@polderlabs/bizar-omp 0.7.0 → 0.7.2

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 (420) hide show
  1. package/README.md +8 -4
  2. package/dist/cli/agents-ink.d.ts.map +1 -1
  3. package/dist/cli/agents-ink.js +5 -3
  4. package/dist/cli/agents-ink.js.map +1 -1
  5. package/dist/cli/agents.d.ts.map +1 -1
  6. package/dist/cli/agents.js +27 -9
  7. package/dist/cli/agents.js.map +1 -1
  8. package/dist/cli/doctor.d.ts +4 -4
  9. package/dist/cli/main.js +0 -0
  10. package/dist/cli/omb.js +0 -0
  11. package/dist/core/recovery.d.ts.map +1 -1
  12. package/dist/core/recovery.js +10 -5
  13. package/dist/core/recovery.js.map +1 -1
  14. package/dist/core/transitions.d.ts +4 -0
  15. package/dist/core/transitions.d.ts.map +1 -1
  16. package/dist/core/transitions.js +12 -2
  17. package/dist/core/transitions.js.map +1 -1
  18. package/dist/core/types.d.ts +46 -0
  19. package/dist/core/types.d.ts.map +1 -1
  20. package/dist/extension.d.ts +4 -0
  21. package/dist/extension.d.ts.map +1 -1
  22. package/dist/extension.js +308 -23
  23. package/dist/extension.js.map +1 -1
  24. package/dist/omp/compatibility.d.ts +5 -5
  25. package/dist/omp/compatibility.d.ts.map +1 -1
  26. package/dist/omp/compatibility.js +2 -2
  27. package/dist/omp/compatibility.js.map +1 -1
  28. package/dist/omp/daemon-service.d.ts.map +1 -1
  29. package/dist/omp/daemon-service.js +54 -21
  30. package/dist/omp/daemon-service.js.map +1 -1
  31. package/dist/omp/daemon.d.ts.map +1 -1
  32. package/dist/omp/daemon.js +109 -21
  33. package/dist/omp/daemon.js.map +1 -1
  34. package/dist/omp/dashboard-html.js +5 -5
  35. package/dist/omp/dispatch-admission.js +1 -1
  36. package/dist/omp/dispatch-admission.js.map +1 -1
  37. package/dist/omp/model-role-assignment.d.ts +4 -0
  38. package/dist/omp/model-role-assignment.d.ts.map +1 -1
  39. package/dist/omp/model-role-assignment.js +52 -7
  40. package/dist/omp/model-role-assignment.js.map +1 -1
  41. package/dist/omp/omb-sessions.d.ts +65 -7
  42. package/dist/omp/omb-sessions.d.ts.map +1 -1
  43. package/dist/omp/omb-sessions.js +329 -34
  44. package/dist/omp/omb-sessions.js.map +1 -1
  45. package/dist/omp/omb-settings.d.ts +15 -1
  46. package/dist/omp/omb-settings.d.ts.map +1 -1
  47. package/dist/omp/omb-settings.js +107 -31
  48. package/dist/omp/omb-settings.js.map +1 -1
  49. package/dist/omp/rpc.d.ts +8 -0
  50. package/dist/omp/rpc.d.ts.map +1 -1
  51. package/dist/omp/session-activity.d.ts +5 -0
  52. package/dist/omp/session-activity.d.ts.map +1 -1
  53. package/dist/omp/session-activity.js +17 -0
  54. package/dist/omp/session-activity.js.map +1 -1
  55. package/dist/omp/tmux.d.ts +3 -1
  56. package/dist/omp/tmux.d.ts.map +1 -1
  57. package/dist/omp/tmux.js +195 -31
  58. package/dist/omp/tmux.js.map +1 -1
  59. package/dist/services/candidate-verify.d.ts.map +1 -1
  60. package/dist/services/candidate-verify.js +44 -1
  61. package/dist/services/candidate-verify.js.map +1 -1
  62. package/dist/services/inspector.d.ts +5 -1
  63. package/dist/services/inspector.d.ts.map +1 -1
  64. package/dist/services/inspector.js +11 -2
  65. package/dist/services/inspector.js.map +1 -1
  66. package/dist/services/native-review-ingest.d.ts +35 -0
  67. package/dist/services/native-review-ingest.d.ts.map +1 -0
  68. package/dist/services/native-review-ingest.js +14 -0
  69. package/dist/services/native-review-ingest.js.map +1 -0
  70. package/dist/storage/journal-recovery.js +1 -1
  71. package/dist/storage/journal-recovery.js.map +1 -1
  72. package/dist/storage/resources.js +1 -1
  73. package/dist/storage/resources.js.map +1 -1
  74. package/dist/tools/integrate.d.ts.map +1 -1
  75. package/dist/tools/integrate.js +13 -0
  76. package/dist/tools/integrate.js.map +1 -1
  77. package/dist/tools/workflow.d.ts +9 -0
  78. package/dist/tools/workflow.d.ts.map +1 -1
  79. package/dist/tools/workflow.js +25 -2
  80. package/dist/tools/workflow.js.map +1 -1
  81. package/docs/compatibility/baseline.json +8 -7
  82. package/docs/compatibility/supported-surfaces.json +2 -1
  83. package/docs/development/ci-release-implementation-guide.md +1261 -0
  84. package/docs/development/contributing-and-releasing.md +117 -0
  85. package/docs/development/omp-compatibility-update-guide.md +117 -0
  86. package/docs/releases/0.7.1.md +15 -0
  87. package/docs/releases/0.7.2.md +32 -0
  88. package/docs/releases/native-stable.md +11 -1
  89. package/docs/releases/npm-publishing.md +31 -4
  90. package/docs/releases/support-matrix.md +1 -1
  91. package/package.json +2 -1
  92. package/rules/oflow-gitlab.md +6 -0
  93. package/skills/oflow-gitlab-context/SKILL.md +49 -0
  94. package/skills/omp-native-development/SKILL.md +1 -1
  95. package/skills/omp-native-development/references/accuracy-and-versioning.md +1 -1
  96. package/skills/omp-native-development/references/source-manifest.json +3 -3
  97. package/dist/src/cli/agents-ink.d.ts +0 -25
  98. package/dist/src/cli/agents-ink.js +0 -517
  99. package/dist/src/cli/agents-ink.js.map +0 -1
  100. package/dist/src/cli/agents.d.ts +0 -14
  101. package/dist/src/cli/agents.js +0 -197
  102. package/dist/src/cli/agents.js.map +0 -1
  103. package/dist/src/cli/directory-selector.d.ts +0 -60
  104. package/dist/src/cli/directory-selector.js +0 -208
  105. package/dist/src/cli/directory-selector.js.map +0 -1
  106. package/dist/src/cli/doctor.d.ts +0 -41
  107. package/dist/src/cli/doctor.js +0 -31
  108. package/dist/src/cli/doctor.js.map +0 -1
  109. package/dist/src/cli/install.d.ts +0 -129
  110. package/dist/src/cli/install.js +0 -164
  111. package/dist/src/cli/install.js.map +0 -1
  112. package/dist/src/cli/main.d.ts +0 -2
  113. package/dist/src/cli/main.js +0 -117
  114. package/dist/src/cli/main.js.map +0 -1
  115. package/dist/src/cli/migrate.d.ts +0 -18
  116. package/dist/src/cli/migrate.js +0 -14
  117. package/dist/src/cli/migrate.js.map +0 -1
  118. package/dist/src/cli/omb-commands.d.ts +0 -29
  119. package/dist/src/cli/omb-commands.js +0 -107
  120. package/dist/src/cli/omb-commands.js.map +0 -1
  121. package/dist/src/cli/omb-daemon.d.ts +0 -2
  122. package/dist/src/cli/omb-daemon.js +0 -135
  123. package/dist/src/cli/omb-daemon.js.map +0 -1
  124. package/dist/src/cli/omb-dashboard.d.ts +0 -12
  125. package/dist/src/cli/omb-dashboard.js +0 -113
  126. package/dist/src/cli/omb-dashboard.js.map +0 -1
  127. package/dist/src/cli/omb-invocation.d.ts +0 -8
  128. package/dist/src/cli/omb-invocation.js +0 -41
  129. package/dist/src/cli/omb-invocation.js.map +0 -1
  130. package/dist/src/cli/omb-runtime.d.ts +0 -41
  131. package/dist/src/cli/omb-runtime.js +0 -371
  132. package/dist/src/cli/omb-runtime.js.map +0 -1
  133. package/dist/src/cli/omb-tray.d.ts +0 -2
  134. package/dist/src/cli/omb-tray.js +0 -38
  135. package/dist/src/cli/omb-tray.js.map +0 -1
  136. package/dist/src/cli/omb.d.ts +0 -2
  137. package/dist/src/cli/omb.js +0 -31
  138. package/dist/src/cli/omb.js.map +0 -1
  139. package/dist/src/cli/omp-theme.d.ts +0 -17
  140. package/dist/src/cli/omp-theme.js +0 -22
  141. package/dist/src/cli/omp-theme.js.map +0 -1
  142. package/dist/src/cli/process.d.ts +0 -6
  143. package/dist/src/cli/process.js +0 -54
  144. package/dist/src/cli/process.js.map +0 -1
  145. package/dist/src/cli/run.d.ts +0 -2
  146. package/dist/src/cli/run.js +0 -5
  147. package/dist/src/cli/run.js.map +0 -1
  148. package/dist/src/cli/setup-ui.d.ts +0 -37
  149. package/dist/src/cli/setup-ui.js +0 -90
  150. package/dist/src/cli/setup-ui.js.map +0 -1
  151. package/dist/src/core/acceptance.d.ts +0 -32
  152. package/dist/src/core/acceptance.js +0 -87
  153. package/dist/src/core/acceptance.js.map +0 -1
  154. package/dist/src/core/errors.d.ts +0 -20
  155. package/dist/src/core/errors.js +0 -30
  156. package/dist/src/core/errors.js.map +0 -1
  157. package/dist/src/core/evidence.d.ts +0 -10
  158. package/dist/src/core/evidence.js +0 -35
  159. package/dist/src/core/evidence.js.map +0 -1
  160. package/dist/src/core/policies.d.ts +0 -10
  161. package/dist/src/core/policies.js +0 -60
  162. package/dist/src/core/policies.js.map +0 -1
  163. package/dist/src/core/recovery.d.ts +0 -6
  164. package/dist/src/core/recovery.js +0 -56
  165. package/dist/src/core/recovery.js.map +0 -1
  166. package/dist/src/core/transitions.d.ts +0 -13
  167. package/dist/src/core/transitions.js +0 -59
  168. package/dist/src/core/transitions.js.map +0 -1
  169. package/dist/src/core/types.d.ts +0 -256
  170. package/dist/src/core/types.js +0 -2
  171. package/dist/src/core/types.js.map +0 -1
  172. package/dist/src/extension.d.ts +0 -60
  173. package/dist/src/extension.js +0 -538
  174. package/dist/src/extension.js.map +0 -1
  175. package/dist/src/index.d.ts +0 -29
  176. package/dist/src/index.js +0 -30
  177. package/dist/src/index.js.map +0 -1
  178. package/dist/src/omp/autonomous-settings.d.ts +0 -14
  179. package/dist/src/omp/autonomous-settings.js +0 -65
  180. package/dist/src/omp/autonomous-settings.js.map +0 -1
  181. package/dist/src/omp/capabilities.d.ts +0 -23
  182. package/dist/src/omp/capabilities.js +0 -6
  183. package/dist/src/omp/capabilities.js.map +0 -1
  184. package/dist/src/omp/compatibility.d.ts +0 -30
  185. package/dist/src/omp/compatibility.js +0 -34
  186. package/dist/src/omp/compatibility.js.map +0 -1
  187. package/dist/src/omp/completion.d.ts +0 -7
  188. package/dist/src/omp/completion.js +0 -10
  189. package/dist/src/omp/completion.js.map +0 -1
  190. package/dist/src/omp/config.d.ts +0 -10
  191. package/dist/src/omp/config.js +0 -14
  192. package/dist/src/omp/config.js.map +0 -1
  193. package/dist/src/omp/context.d.ts +0 -15
  194. package/dist/src/omp/context.js +0 -3
  195. package/dist/src/omp/context.js.map +0 -1
  196. package/dist/src/omp/daemon-service.d.ts +0 -25
  197. package/dist/src/omp/daemon-service.js +0 -483
  198. package/dist/src/omp/daemon-service.js.map +0 -1
  199. package/dist/src/omp/daemon.d.ts +0 -48
  200. package/dist/src/omp/daemon.js +0 -194
  201. package/dist/src/omp/daemon.js.map +0 -1
  202. package/dist/src/omp/dashboard-html.d.ts +0 -3
  203. package/dist/src/omp/dashboard-html.js +0 -419
  204. package/dist/src/omp/dashboard-html.js.map +0 -1
  205. package/dist/src/omp/dispatch-admission.d.ts +0 -2
  206. package/dist/src/omp/dispatch-admission.js +0 -12
  207. package/dist/src/omp/dispatch-admission.js.map +0 -1
  208. package/dist/src/omp/integration-recovery.d.ts +0 -10
  209. package/dist/src/omp/integration-recovery.js +0 -18
  210. package/dist/src/omp/integration-recovery.js.map +0 -1
  211. package/dist/src/omp/isolation-policy.d.ts +0 -14
  212. package/dist/src/omp/isolation-policy.js +0 -9
  213. package/dist/src/omp/isolation-policy.js.map +0 -1
  214. package/dist/src/omp/lifecycle.d.ts +0 -14
  215. package/dist/src/omp/lifecycle.js +0 -14
  216. package/dist/src/omp/lifecycle.js.map +0 -1
  217. package/dist/src/omp/memory.d.ts +0 -16
  218. package/dist/src/omp/memory.js +0 -4
  219. package/dist/src/omp/memory.js.map +0 -1
  220. package/dist/src/omp/model-role-assignment.d.ts +0 -296
  221. package/dist/src/omp/model-role-assignment.js +0 -559
  222. package/dist/src/omp/model-role-assignment.js.map +0 -1
  223. package/dist/src/omp/model-roles.d.ts +0 -19
  224. package/dist/src/omp/model-roles.js +0 -6
  225. package/dist/src/omp/model-roles.js.map +0 -1
  226. package/dist/src/omp/omb-sessions.d.ts +0 -122
  227. package/dist/src/omp/omb-sessions.js +0 -512
  228. package/dist/src/omp/omb-sessions.js.map +0 -1
  229. package/dist/src/omp/omb-settings.d.ts +0 -35
  230. package/dist/src/omp/omb-settings.js +0 -104
  231. package/dist/src/omp/omb-settings.js.map +0 -1
  232. package/dist/src/omp/result-reconciliation.d.ts +0 -2
  233. package/dist/src/omp/result-reconciliation.js +0 -9
  234. package/dist/src/omp/result-reconciliation.js.map +0 -1
  235. package/dist/src/omp/rpc.d.ts +0 -67
  236. package/dist/src/omp/rpc.js +0 -4
  237. package/dist/src/omp/rpc.js.map +0 -1
  238. package/dist/src/omp/run-log.d.ts +0 -25
  239. package/dist/src/omp/run-log.js +0 -24
  240. package/dist/src/omp/run-log.js.map +0 -1
  241. package/dist/src/omp/session-activity.d.ts +0 -70
  242. package/dist/src/omp/session-activity.js +0 -361
  243. package/dist/src/omp/session-activity.js.map +0 -1
  244. package/dist/src/omp/session-controls.d.ts +0 -17
  245. package/dist/src/omp/session-controls.js +0 -14
  246. package/dist/src/omp/session-controls.js.map +0 -1
  247. package/dist/src/omp/tmux.d.ts +0 -89
  248. package/dist/src/omp/tmux.js +0 -445
  249. package/dist/src/omp/tmux.js.map +0 -1
  250. package/dist/src/omp/tray-icons.d.ts +0 -5
  251. package/dist/src/omp/tray-icons.js +0 -78
  252. package/dist/src/omp/tray-icons.js.map +0 -1
  253. package/dist/src/omp/tray.d.ts +0 -23
  254. package/dist/src/omp/tray.js +0 -167
  255. package/dist/src/omp/tray.js.map +0 -1
  256. package/dist/src/services/budget.d.ts +0 -19
  257. package/dist/src/services/budget.js +0 -10
  258. package/dist/src/services/budget.js.map +0 -1
  259. package/dist/src/services/candidate-local.d.ts +0 -13
  260. package/dist/src/services/candidate-local.js +0 -15
  261. package/dist/src/services/candidate-local.js.map +0 -1
  262. package/dist/src/services/candidates.d.ts +0 -20
  263. package/dist/src/services/candidates.js +0 -100
  264. package/dist/src/services/candidates.js.map +0 -1
  265. package/dist/src/services/evidence-bundle.d.ts +0 -17
  266. package/dist/src/services/evidence-bundle.js +0 -21
  267. package/dist/src/services/evidence-bundle.js.map +0 -1
  268. package/dist/src/services/inspector.d.ts +0 -11
  269. package/dist/src/services/inspector.js +0 -6
  270. package/dist/src/services/inspector.js.map +0 -1
  271. package/dist/src/services/lessons.d.ts +0 -13
  272. package/dist/src/services/lessons.js +0 -11
  273. package/dist/src/services/lessons.js.map +0 -1
  274. package/dist/src/services/projection.d.ts +0 -21
  275. package/dist/src/services/projection.js +0 -10
  276. package/dist/src/services/projection.js.map +0 -1
  277. package/dist/src/services/readiness.d.ts +0 -4
  278. package/dist/src/services/readiness.js +0 -35
  279. package/dist/src/services/readiness.js.map +0 -1
  280. package/dist/src/services/recipes.d.ts +0 -15
  281. package/dist/src/services/recipes.js +0 -42
  282. package/dist/src/services/recipes.js.map +0 -1
  283. package/dist/src/services/recovery.d.ts +0 -19
  284. package/dist/src/services/recovery.js +0 -9
  285. package/dist/src/services/recovery.js.map +0 -1
  286. package/dist/src/services/review.d.ts +0 -15
  287. package/dist/src/services/review.js +0 -9
  288. package/dist/src/services/review.js.map +0 -1
  289. package/dist/src/storage/journal-recovery.d.ts +0 -10
  290. package/dist/src/storage/journal-recovery.js +0 -33
  291. package/dist/src/storage/journal-recovery.js.map +0 -1
  292. package/dist/src/storage/journal.d.ts +0 -12
  293. package/dist/src/storage/journal.js +0 -82
  294. package/dist/src/storage/journal.js.map +0 -1
  295. package/dist/src/storage/migrations.d.ts +0 -22
  296. package/dist/src/storage/migrations.js +0 -107
  297. package/dist/src/storage/migrations.js.map +0 -1
  298. package/dist/src/storage/repository-identity.d.ts +0 -11
  299. package/dist/src/storage/repository-identity.js +0 -67
  300. package/dist/src/storage/repository-identity.js.map +0 -1
  301. package/dist/src/storage/resources.d.ts +0 -66
  302. package/dist/src/storage/resources.js +0 -148
  303. package/dist/src/storage/resources.js.map +0 -1
  304. package/dist/src/tools/evidence.d.ts +0 -8
  305. package/dist/src/tools/evidence.js +0 -9
  306. package/dist/src/tools/evidence.js.map +0 -1
  307. package/dist/src/tools/integrate.d.ts +0 -13
  308. package/dist/src/tools/integrate.js +0 -90
  309. package/dist/src/tools/integrate.js.map +0 -1
  310. package/dist/src/tools/result.d.ts +0 -9
  311. package/dist/src/tools/result.js +0 -2
  312. package/dist/src/tools/result.js.map +0 -1
  313. package/dist/src/tools/verify.d.ts +0 -13
  314. package/dist/src/tools/verify.js +0 -61
  315. package/dist/src/tools/verify.js.map +0 -1
  316. package/dist/src/tools/workflow.d.ts +0 -8
  317. package/dist/src/tools/workflow.js +0 -65
  318. package/dist/src/tools/workflow.js.map +0 -1
  319. package/dist/src/workflows/direct.d.ts +0 -9
  320. package/dist/src/workflows/direct.js +0 -2
  321. package/dist/src/workflows/direct.js.map +0 -1
  322. package/dist/src/workflows/implement.d.ts +0 -2
  323. package/dist/src/workflows/implement.js +0 -4
  324. package/dist/src/workflows/implement.js.map +0 -1
  325. package/dist/src/workflows/plan.d.ts +0 -17
  326. package/dist/src/workflows/plan.js +0 -6
  327. package/dist/src/workflows/plan.js.map +0 -1
  328. package/dist/src/workflows/research.d.ts +0 -15
  329. package/dist/src/workflows/research.js +0 -2
  330. package/dist/src/workflows/research.js.map +0 -1
  331. package/dist/src/workflows/review.d.ts +0 -15
  332. package/dist/src/workflows/review.js +0 -2
  333. package/dist/src/workflows/review.js.map +0 -1
  334. package/dist/src/workflows/verify.d.ts +0 -9
  335. package/dist/src/workflows/verify.js +0 -2
  336. package/dist/src/workflows/verify.js.map +0 -1
  337. package/dist/tests/acceptance.test.d.ts +0 -1
  338. package/dist/tests/acceptance.test.js +0 -27
  339. package/dist/tests/acceptance.test.js.map +0 -1
  340. package/dist/tests/agents.test.d.ts +0 -1
  341. package/dist/tests/agents.test.js +0 -369
  342. package/dist/tests/agents.test.js.map +0 -1
  343. package/dist/tests/candidates.test.d.ts +0 -1
  344. package/dist/tests/candidates.test.js +0 -60
  345. package/dist/tests/candidates.test.js.map +0 -1
  346. package/dist/tests/core.test.d.ts +0 -1
  347. package/dist/tests/core.test.js +0 -39
  348. package/dist/tests/core.test.js.map +0 -1
  349. package/dist/tests/daemon.test.d.ts +0 -1
  350. package/dist/tests/daemon.test.js +0 -157
  351. package/dist/tests/daemon.test.js.map +0 -1
  352. package/dist/tests/dashboard.test.d.ts +0 -1
  353. package/dist/tests/dashboard.test.js +0 -414
  354. package/dist/tests/dashboard.test.js.map +0 -1
  355. package/dist/tests/directory-selector.test.d.ts +0 -1
  356. package/dist/tests/directory-selector.test.js +0 -93
  357. package/dist/tests/directory-selector.test.js.map +0 -1
  358. package/dist/tests/doctor.test.d.ts +0 -1
  359. package/dist/tests/doctor.test.js +0 -32
  360. package/dist/tests/doctor.test.js.map +0 -1
  361. package/dist/tests/install.test.d.ts +0 -1
  362. package/dist/tests/install.test.js +0 -101
  363. package/dist/tests/install.test.js.map +0 -1
  364. package/dist/tests/integration.test.d.ts +0 -1
  365. package/dist/tests/integration.test.js +0 -49
  366. package/dist/tests/integration.test.js.map +0 -1
  367. package/dist/tests/journal.test.d.ts +0 -1
  368. package/dist/tests/journal.test.js +0 -50
  369. package/dist/tests/journal.test.js.map +0 -1
  370. package/dist/tests/model-role-assignment.test.d.ts +0 -1
  371. package/dist/tests/model-role-assignment.test.js +0 -294
  372. package/dist/tests/model-role-assignment.test.js.map +0 -1
  373. package/dist/tests/omb-runtime.test.d.ts +0 -1
  374. package/dist/tests/omb-runtime.test.js +0 -554
  375. package/dist/tests/omb-runtime.test.js.map +0 -1
  376. package/dist/tests/omb-session-actions.test.d.ts +0 -1
  377. package/dist/tests/omb-session-actions.test.js +0 -191
  378. package/dist/tests/omb-session-actions.test.js.map +0 -1
  379. package/dist/tests/omb-settings.test.d.ts +0 -1
  380. package/dist/tests/omb-settings.test.js +0 -82
  381. package/dist/tests/omb-settings.test.js.map +0 -1
  382. package/dist/tests/omp-contract.test.d.ts +0 -1
  383. package/dist/tests/omp-contract.test.js +0 -362
  384. package/dist/tests/omp-contract.test.js.map +0 -1
  385. package/dist/tests/process.test.d.ts +0 -1
  386. package/dist/tests/process.test.js +0 -12
  387. package/dist/tests/process.test.js.map +0 -1
  388. package/dist/tests/psmux-windows.test.d.ts +0 -1
  389. package/dist/tests/psmux-windows.test.js +0 -105
  390. package/dist/tests/psmux-windows.test.js.map +0 -1
  391. package/dist/tests/recovery.test.d.ts +0 -1
  392. package/dist/tests/recovery.test.js +0 -9
  393. package/dist/tests/recovery.test.js.map +0 -1
  394. package/dist/tests/resources.test.d.ts +0 -1
  395. package/dist/tests/resources.test.js +0 -55
  396. package/dist/tests/resources.test.js.map +0 -1
  397. package/dist/tests/session-activity.test.d.ts +0 -1
  398. package/dist/tests/session-activity.test.js +0 -159
  399. package/dist/tests/session-activity.test.js.map +0 -1
  400. package/dist/tests/setup-ui.test.d.ts +0 -1
  401. package/dist/tests/setup-ui.test.js +0 -37
  402. package/dist/tests/setup-ui.test.js.map +0 -1
  403. package/dist/tests/storage-integrity.test.d.ts +0 -1
  404. package/dist/tests/storage-integrity.test.js +0 -88
  405. package/dist/tests/storage-integrity.test.js.map +0 -1
  406. package/dist/tests/tmux.test.d.ts +0 -1
  407. package/dist/tests/tmux.test.js +0 -239
  408. package/dist/tests/tmux.test.js.map +0 -1
  409. package/dist/tests/tray.test.d.ts +0 -1
  410. package/dist/tests/tray.test.js +0 -37
  411. package/dist/tests/tray.test.js.map +0 -1
  412. package/dist/tests/verification.test.d.ts +0 -1
  413. package/dist/tests/verification.test.js +0 -61
  414. package/dist/tests/verification.test.js.map +0 -1
  415. package/dist/tests/workflow-features.test.d.ts +0 -1
  416. package/dist/tests/workflow-features.test.js +0 -82
  417. package/dist/tests/workflow-features.test.js.map +0 -1
  418. package/dist/tests/workflow-safety.test.d.ts +0 -1
  419. package/dist/tests/workflow-safety.test.js +0 -57
  420. package/dist/tests/workflow-safety.test.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"omb-sessions.d.ts","sourceRoot":"","sources":["../../src/omp/omb-sessions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"omb-sessions.d.ts","sourceRoot":"","sources":["../../src/omp/omb-sessions.ts"],"names":[],"mappings":"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"}
@@ -1,22 +1,33 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { createHash } from "node:crypto";
2
3
  import { parseTmuxSessionRecords } from "./tmux.js";
3
4
  import { access, readdir, stat } from "node:fs/promises";
4
- import { mkdirSync, rmSync, writeFileSync } from "node:fs";
5
- import { basename, join, relative, resolve } from "node:path";
5
+ import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
6
+ import { basename, join, relative, resolve, sep } from "node:path";
6
7
  import { homedir, tmpdir } from "node:os";
8
+ import { ContractError } from "../core/errors.js";
9
+ import { acquireLease } from "../storage/lease.js";
7
10
  import { describeToolActivity, deriveSessionActivity, listSessionJournals, readJournalHead, readJournalTail, } from "./session-activity.js";
8
11
  export const BIZAR_SESSION_PREFIX = "bizar-";
9
12
  /** Most recent stopped sessions to surface when stopped sessions are enabled. */
10
13
  const STOPPED_SESSION_LIMIT = 6;
11
14
  const DELETED_SESSION_MARKER = ".bizar-deleted";
15
+ const OMP_LINK_MANIFEST = ".bizar-omp-link.json";
12
16
  function nativeSessionRoot(env) {
13
17
  const stateHome = env.XDG_STATE_HOME || join(env.HOME || homedir(), ".local", "state");
14
- return join(stateHome, "bizar-omp", "native-sessions");
18
+ return join(stateHome, "bizar-omp", ...(env.PI_PROFILE ? ["profiles", env.PI_PROFILE] : []), "native-sessions");
15
19
  }
16
20
  /** Keep native OMP journals separate so each durable `omb` host has one exact session. */
17
21
  export function ombSessionDir(session, env = process.env) {
18
22
  return join(nativeSessionRoot(env), session);
19
23
  }
24
+ /** Recognize private journals written by older versions, including unscoped profiles. */
25
+ export function isLegacyOmbSessionDir(directory, session, env = process.env) {
26
+ const root = resolve(env.XDG_STATE_HOME || join(env.HOME || homedir(), ".local", "state"), "bizar-omp");
27
+ const candidate = resolve(directory);
28
+ const rel = relative(root, candidate);
29
+ return rel !== "" && rel !== ".." && !rel.startsWith(`..${sep}`) && basename(candidate) === session && rel.split(sep).includes("native-sessions");
30
+ }
20
31
  /**
21
32
  * Whether a name is one of the sessions Bizar owns, and may therefore kill,
22
33
  * rename, tombstone, or adopt as its own native journal.
@@ -34,9 +45,60 @@ function markDirectoryDeleted(directory) {
34
45
  return false;
35
46
  }
36
47
  }
48
+ function readOmpLinkManifest(session, env) {
49
+ try {
50
+ const parsed = JSON.parse(readFileSync(join(ombSessionDir(session, env), OMP_LINK_MANIFEST), "utf8"));
51
+ return typeof parsed.source === "string" && typeof parsed.id === "string"
52
+ ? parsed
53
+ : undefined;
54
+ }
55
+ catch {
56
+ return undefined;
57
+ }
58
+ }
59
+ function removeOmpSessionFile(session, env) {
60
+ const manifest = readOmpLinkManifest(session, env);
61
+ if (!manifest)
62
+ return true;
63
+ try {
64
+ statSync(manifest.source);
65
+ }
66
+ catch (error) {
67
+ if (error.code === "ENOENT")
68
+ return true;
69
+ return false;
70
+ }
71
+ let lease;
72
+ try {
73
+ lease = acquireOmpSessionLease(manifest.source, env);
74
+ }
75
+ catch {
76
+ return false;
77
+ }
78
+ try {
79
+ unlinkSync(manifest.source);
80
+ rmSync(manifest.source.slice(0, -".jsonl".length), { recursive: true, force: true });
81
+ const base = basename(manifest.source);
82
+ for (const entry of readdirSync(join(manifest.source, ".."))) {
83
+ if (entry.startsWith(`${base}.`) && entry.endsWith(".bak"))
84
+ rmSync(join(manifest.source, "..", entry), { force: true });
85
+ }
86
+ return true;
87
+ }
88
+ catch (error) {
89
+ return error.code === "ENOENT";
90
+ }
91
+ finally {
92
+ lease.release();
93
+ }
94
+ }
37
95
  /** Keep an intentionally removed session out of journal-based discovery. */
38
96
  export function markOmbSessionDeleted(session, env = process.env) {
39
- return isOmbSessionName(session) && markDirectoryDeleted(ombSessionDir(session, env));
97
+ if (!isOmbSessionName(session))
98
+ return false;
99
+ if (!removeOmpSessionFile(session, env))
100
+ return false;
101
+ return markDirectoryDeleted(ombSessionDir(session, env));
40
102
  }
41
103
  /** Reusing a session name makes its native journal discoverable again. */
42
104
  export function clearOmbSessionDeleted(session, env = process.env) {
@@ -47,6 +109,113 @@ export function clearOmbSessionDeleted(session, env = process.env) {
47
109
  }
48
110
  catch { /* discovery remains conservative */ }
49
111
  }
112
+ /**
113
+ * Record the exact OMP-owned journal for Bizar. OMP writes directly into its
114
+ * normal project/profile session directory, keeping the native file
115
+ * authoritative through atomic rewrites.
116
+ */
117
+ export function indexOmbSessionJournal(session, journal, cwd, nativeId, env = process.env) {
118
+ if (!isOmbSessionName(session) || !nativeId.trim())
119
+ return { ok: false, reason: "Bizar session identity is incomplete" };
120
+ const indexedDir = resolve(defaultOmpSessionDir(cwd, env));
121
+ const path = resolve(journal);
122
+ const inProjectBucket = relative(indexedDir, path);
123
+ if (!inProjectBucket || inProjectBucket.startsWith("..") || inProjectBucket.includes("/") || !path.endsWith(".jsonl")) {
124
+ return { ok: false, reason: "journal is outside OMP's normal project/profile session directory" };
125
+ }
126
+ try {
127
+ statSync(path);
128
+ mkdirSync(ombSessionDir(session, env), { recursive: true, mode: 0o700 });
129
+ writeFileSync(join(ombSessionDir(session, env), OMP_LINK_MANIFEST), JSON.stringify({ source: path, id: nativeId }), { mode: 0o600 });
130
+ return { ok: true, path };
131
+ }
132
+ catch (error) {
133
+ const code = error.code;
134
+ return { ok: false, reason: `could not record the OMP journal (${code ?? "filesystem error"})` };
135
+ }
136
+ }
137
+ /** Move one stopped legacy OMB journal into OMP's native project picker. */
138
+ export async function migrateLegacyOmbSessionJournal(session, legacyDir, cwd, env = process.env) {
139
+ const journalFiles = readdirSync(legacyDir).filter(name => name.endsWith(".jsonl"));
140
+ if (journalFiles.length !== 1)
141
+ return { ok: false, reason: "legacy session directory does not contain exactly one journal" };
142
+ const source = join(legacyDir, journalFiles[0]);
143
+ const metadata = await readNativeSessionFile(source);
144
+ if (!metadata?.id)
145
+ return { ok: false, reason: "legacy journal has no readable OMP session identity" };
146
+ let sourceLease;
147
+ try {
148
+ sourceLease = acquireOmpSessionLease(source, env);
149
+ }
150
+ catch {
151
+ return { ok: false, reason: "legacy journal is currently owned by another OMP process" };
152
+ }
153
+ const targetDir = defaultOmpSessionDir(cwd, env);
154
+ const safeId = metadata.id.replace(/[^A-Za-z0-9_.-]/g, "-");
155
+ const target = join(targetDir, `${safeId}.jsonl`);
156
+ const temporary = `${target}.${process.pid}.migration`;
157
+ const sourceArtifacts = source.slice(0, -".jsonl".length);
158
+ const targetArtifacts = target.slice(0, -".jsonl".length);
159
+ const temporaryArtifacts = `${targetArtifacts}.${process.pid}.migration`;
160
+ let targetLease;
161
+ try {
162
+ mkdirSync(targetDir, { recursive: true, mode: 0o700 });
163
+ if (existsSync(target)) {
164
+ targetLease = acquireOmpSessionLease(target, env);
165
+ const current = await readNativeSessionFile(target);
166
+ if (current?.id !== metadata.id || createHash("sha256").update(readFileSync(target)).digest("hex") !== createHash("sha256").update(readFileSync(source)).digest("hex")) {
167
+ return { ok: false, reason: "OMP already has a different journal with this native session identity" };
168
+ }
169
+ }
170
+ else {
171
+ copyFileSync(source, temporary);
172
+ targetLease = acquireOmpSessionLease(temporary, env);
173
+ if (createHash("sha256").update(readFileSync(temporary)).digest("hex") !== createHash("sha256").update(readFileSync(source)).digest("hex")) {
174
+ return { ok: false, reason: "copied journal did not verify against its source" };
175
+ }
176
+ renameSync(temporary, target);
177
+ }
178
+ if (existsSync(sourceArtifacts)) {
179
+ if (existsSync(targetArtifacts))
180
+ return { ok: false, reason: "OMP artifact directory already exists for this session" };
181
+ cpSync(sourceArtifacts, temporaryArtifacts, { recursive: true, errorOnExist: true });
182
+ renameSync(temporaryArtifacts, targetArtifacts);
183
+ }
184
+ const recorded = indexOmbSessionJournal(session, target, cwd, metadata.id, env);
185
+ if (!recorded.ok)
186
+ return recorded;
187
+ unlinkSync(source);
188
+ rmSync(sourceArtifacts, { recursive: true, force: true });
189
+ return { ok: true, path: target, id: metadata.id };
190
+ }
191
+ catch (error) {
192
+ const code = error.code;
193
+ return { ok: false, reason: `could not safely migrate the legacy journal (${code ?? "filesystem error"})` };
194
+ }
195
+ finally {
196
+ try {
197
+ targetLease?.release();
198
+ }
199
+ catch { /* preserve the migration result */ }
200
+ try {
201
+ sourceLease.release();
202
+ }
203
+ catch { /* preserve the migration result */ }
204
+ rmSync(temporary, { force: true });
205
+ rmSync(temporaryArtifacts, { recursive: true, force: true });
206
+ }
207
+ }
208
+ /** Share one recoverable lease across hard-link names for the same journal. */
209
+ export function acquireOmpSessionLease(journal, env = process.env) {
210
+ const identity = statSync(journal);
211
+ const lockName = createHash("sha256").update(`${identity.dev}:${identity.ino}`).digest("hex");
212
+ const root = join(env.XDG_STATE_HOME || join(env.HOME || homedir(), ".local", "state"), "bizar-omp", "session-leases");
213
+ mkdirSync(root, { recursive: true, mode: 0o700 });
214
+ return acquireLease(join(root, `${lockName}.lock`), "This OMP session is already open in another OMP or OMB process; close it there before resuming.");
215
+ }
216
+ export function ombNativeSessionReference(session, env = process.env) {
217
+ return isOmbSessionName(session) ? readOmpLinkManifest(session, env) : undefined;
218
+ }
50
219
  async function isOmbSessionDeleted(session, env) {
51
220
  try {
52
221
  await access(join(ombSessionDir(session, env), DELETED_SESSION_MARKER));
@@ -56,25 +225,56 @@ async function isOmbSessionDeleted(session, env) {
56
225
  return false;
57
226
  }
58
227
  }
59
- function ompAgentDir(env) {
228
+ function ompSessionsRoot(env) {
60
229
  if (env.PI_CODING_AGENT_DIR)
61
- return resolve(env.PI_CODING_AGENT_DIR);
62
- return join(env.HOME || homedir(), env.PI_CONFIG_DIR || ".omp", "agent");
230
+ return join(resolve(env.PI_CODING_AGENT_DIR), "sessions");
231
+ const home = env.HOME || homedir();
232
+ const config = env.PI_CONFIG_DIR || ".omp";
233
+ const profile = env.PI_PROFILE;
234
+ const profileParts = profile ? ["profiles", profile] : [];
235
+ if (process.platform === "linux" || process.platform === "darwin") {
236
+ const xdgRoot = env.XDG_DATA_HOME ? join(env.XDG_DATA_HOME, "omp", ...profileParts) : undefined;
237
+ if (xdgRoot && existsSync(xdgRoot))
238
+ return join(xdgRoot, "sessions");
239
+ }
240
+ return join(home, config, ...profileParts, "agent", "sessions");
63
241
  }
64
- function defaultOmpSessionDir(cwd, env) {
65
- const resolvedCwd = resolve(cwd);
242
+ export function defaultOmpSessionDir(cwd, env = process.env) {
243
+ let resolvedCwd = resolve(cwd);
244
+ try {
245
+ resolvedCwd = realpathSync(resolvedCwd);
246
+ }
247
+ catch { /* cwd may not exist yet */ }
66
248
  const home = resolve(env.HOME || homedir());
67
249
  const temp = resolve(tmpdir());
68
250
  const encode = (value) => value.replace(/[\\/:]/g, "-");
69
251
  const homeRelative = relative(home, resolvedCwd);
70
252
  if (homeRelative === "" || (!homeRelative.startsWith("..") && !homeRelative.startsWith("/"))) {
71
- return join(ompAgentDir(env), "sessions", homeRelative ? `-${encode(homeRelative)}` : "-");
253
+ return join(ompSessionsRoot(env), homeRelative ? `-${encode(homeRelative)}` : "-");
72
254
  }
73
255
  const tempRelative = relative(temp, resolvedCwd);
74
256
  if (tempRelative === "" || (!tempRelative.startsWith("..") && !tempRelative.startsWith("/"))) {
75
- return join(ompAgentDir(env), "sessions", tempRelative ? `-tmp-${encode(tempRelative)}` : "-tmp");
257
+ return join(ompSessionsRoot(env), tempRelative ? `-tmp-${encode(tempRelative)}` : "-tmp");
258
+ }
259
+ return join(ompSessionsRoot(env), `--${encode(resolvedCwd).replace(/^-/, "")}--`);
260
+ }
261
+ /** Index a live OMB journal after OMP has committed its session header. */
262
+ export async function indexOmbSessionFile(session, journal, cwd, env = process.env) {
263
+ const metadata = await readNativeSessionFile(journal);
264
+ if (!metadata?.id)
265
+ return { ok: false, reason: "OMP has not written a readable session header yet" };
266
+ return indexOmbSessionJournal(session, journal, cwd, metadata.id, env);
267
+ }
268
+ /** Compare session paths by file identity, including OMP picker hard links. */
269
+ export function sameOmpSessionFile(left, right) {
270
+ try {
271
+ const a = statSync(left);
272
+ const b = statSync(right);
273
+ return a.dev === b.dev && a.ino === b.ino;
274
+ }
275
+ catch {
276
+ return resolve(left) === resolve(right);
76
277
  }
77
- return join(ompAgentDir(env), "sessions", `--${encode(resolvedCwd).replace(/^-/, "")}--`);
78
278
  }
79
279
  function cleanText(value) {
80
280
  if (typeof value !== "string")
@@ -154,8 +354,12 @@ async function readNativeSessionFile(journal) {
154
354
  }
155
355
  }
156
356
  const timestamp = typeof header.timestamp === "string" ? Date.parse(header.timestamp) : NaN;
357
+ // OMP 18.2.11's SessionHeader has no pid; honor an optional host-specific pid
358
+ // without treating ordinary journal freshness as proof that a process lives.
359
+ const pid = typeof header.pid === "number" && Number.isSafeInteger(header.pid) && header.pid > 0 ? header.pid : undefined;
157
360
  return {
158
361
  id: cleanText(header.id),
362
+ pid,
159
363
  title: latestTitle,
160
364
  cwd: cleanText(header.cwd),
161
365
  firstMessage,
@@ -163,8 +367,17 @@ async function readNativeSessionFile(journal) {
163
367
  };
164
368
  }
165
369
  /** Metadata plus live activity for a Bizar-owned native session directory. */
166
- async function readNativeSessionSnapshot(sessionDir, now) {
167
- const journals = await listSessionJournals(sessionDir);
370
+ async function readNativeSessionSnapshot(sessionDir, now, env = process.env) {
371
+ let journals = await listSessionJournals(sessionDir);
372
+ const sessionName = basename(sessionDir);
373
+ const reference = isOmbSessionName(sessionName) ? readOmpLinkManifest(sessionName, env) : undefined;
374
+ if (reference) {
375
+ try {
376
+ await access(reference.source);
377
+ journals = [reference.source];
378
+ }
379
+ catch { /* keep a legacy private journal available if the pointer went stale */ }
380
+ }
168
381
  const newest = journals.at(-1);
169
382
  if (!newest)
170
383
  return {};
@@ -180,9 +393,12 @@ async function readNativeSessionSnapshot(sessionDir, now) {
180
393
  break;
181
394
  }
182
395
  }
396
+ const activity = entries.length > 0 ? deriveSessionActivity(entries, { now, fallbackUpdatedAt: modifiedAt }) : undefined;
397
+ if (activity && metadata?.pid)
398
+ activity.pid = metadata.pid;
183
399
  return {
184
400
  metadata,
185
- activity: entries.length > 0 ? deriveSessionActivity(entries, { now, fallbackUpdatedAt: modifiedAt }) : undefined,
401
+ activity,
186
402
  };
187
403
  }
188
404
  async function readLegacyNativeSessionMetadata(cwd, sessionCreatedAt, env) {
@@ -272,12 +488,25 @@ const STATE_RANK = {
272
488
  connected: 2,
273
489
  disconnected: 3,
274
490
  stopped: 4,
491
+ unknown: 5,
275
492
  };
276
493
  function exitCode(code, signal) {
277
494
  if (code !== null)
278
495
  return code;
279
496
  return signal ? 1 : 1;
280
497
  }
498
+ /** Probe whether a native session process still exists without signaling it. */
499
+ export function processAliveCheck(pid) {
500
+ if (!Number.isSafeInteger(pid) || pid <= 0)
501
+ return false;
502
+ try {
503
+ process.kill(pid, 0);
504
+ return true;
505
+ }
506
+ catch (error) {
507
+ return error.code === "EPERM";
508
+ }
509
+ }
281
510
  function readTmux(command, args, cwd, env) {
282
511
  const child = spawn(command, args, { cwd, env, stdio: ["ignore", "pipe", "ignore"] });
283
512
  let output = "";
@@ -310,7 +539,7 @@ function sessionProject(name) {
310
539
  * every host as `omp --session-dir <native root>/<session>`, so that command is
311
540
  * the only exact record of which journal a live row owns.
312
541
  */
313
- const PANE_FORMAT = "#{pane_dead}\t#{pane_current_path}\t#{pane_current_command}\t#{pane_pid}\t#{pane_start_command}";
542
+ const PANE_FORMAT = "#{pane_dead}\t#{pane_current_path}\t#{pane_current_command}\t#{pane_pid}\t#{pane_start_command}\t#{@bizar-session-owner}";
314
543
  /**
315
544
  * Session whose native directory a pane command declares.
316
545
  *
@@ -319,7 +548,9 @@ const PANE_FORMAT = "#{pane_dead}\t#{pane_current_path}\t#{pane_current_command}
319
548
  * matches the session name. Paths outside the Bizar native root, or names
320
549
  * Bizar does not own, are ignored so unrelated OMP hosts are never adopted.
321
550
  */
322
- function paneBoundSession(startCommand, env) {
551
+ function paneBoundSession(startCommand, env, owner) {
552
+ if (owner && isOmbSessionName(owner))
553
+ return owner;
323
554
  const declared = startCommand?.match(/--session-dir(?:=|\s+)(?:"([^"]*)"|'([^']*)'|(\S+))/);
324
555
  const value = declared?.[1] ?? declared?.[2] ?? declared?.[3];
325
556
  if (!value)
@@ -329,17 +560,22 @@ function paneBoundSession(startCommand, env) {
329
560
  return undefined;
330
561
  return directory;
331
562
  }
332
- function parsePane(output, env) {
563
+ function parsePane(output, env, ownerOverride) {
333
564
  const [line = ""] = output.trim().split("\n");
334
- const [dead, cwd, command, pid, startCommand] = line.split("\t");
565
+ const [dead, cwd, command, pid, startCommand, owner] = line.split("\t");
335
566
  return {
336
567
  dead: dead === "1",
337
568
  cwd: cwd || "?",
338
569
  command: command || "?",
339
570
  pid: pid || "?",
340
- bound: paneBoundSession(startCommand, env),
571
+ bound: paneBoundSession(startCommand, env, ownerOverride || owner),
341
572
  };
342
573
  }
574
+ async function sessionOwner(tmux, name, cwd, childEnv) {
575
+ const result = await readTmux(tmux, ["show-options", "-t", name, "-v", "@bizar-session-owner"], cwd, childEnv);
576
+ const owner = result.output.trim();
577
+ return result.code === 0 && isOmbSessionName(owner) ? owner : undefined;
578
+ }
343
579
  /**
344
580
  * Live tmux records that Bizar may own.
345
581
  *
@@ -350,35 +586,57 @@ function parseSessionList(output) {
350
586
  return parseTmuxSessionRecords(output).filter(session => session.name.startsWith(BIZAR_SESSION_PREFIX));
351
587
  }
352
588
  function sessionRecord(name, fields) {
589
+ const hosted = fields.hosted ?? false;
590
+ const attached = fields.attached ?? false;
591
+ const activity = fields.activity;
592
+ const generation = createHash("sha256").update(JSON.stringify([
593
+ name,
594
+ fields.createdAt ?? null,
595
+ fields.nativeId ?? null,
596
+ fields.pid && fields.pid !== "?" ? fields.pid : null,
597
+ ])).digest("hex").slice(0, 32);
353
598
  const record = {
354
599
  name,
355
600
  project: fields.cwd === "?" ? sessionProject(name) : basename(fields.cwd),
356
601
  id: sessionId(name),
357
602
  ...fields,
603
+ hosted,
604
+ attached,
605
+ generation,
606
+ authorityKnown: fields.authorityKnown ?? false,
607
+ nativeOutcome: activity?.nativeOutcome ?? "unknown",
608
+ uncertainLiveness: fields.uncertainLiveness ?? false,
609
+ processObserved: fields.processObserved ?? false,
358
610
  };
359
611
  return { ...record, displayName: ombSessionDisplayName(record) };
360
612
  }
361
613
  async function describeLiveSession(tmux, session, cwd, childEnv, env, now) {
614
+ // S007: a failed list-panes (e.g. multiplexer refused) cannot prove liveness;
615
+ // mark the pane as dead so the session row reports an unknown/stopped state
616
+ // instead of appearing live.
362
617
  const pane = await readTmux(tmux, ["list-panes", "-t", session.name, "-F", PANE_FORMAT], cwd, childEnv);
363
- const details = parsePane(pane.output, env);
618
+ const details = pane.code === 0 ? parsePane(pane.output, env) : { dead: true, cwd: "", command: "", pid: "", bound: session.name };
619
+ const authorityKnown = pane.code === 0 && /^\d+$/.test(details.pid) && details.command !== "?";
364
620
  // Prefer the journal the pane command names: after a rename the tmux session
365
621
  // and its native directory differ, and the host keeps writing the directory
366
622
  // it was started with.
367
623
  const declared = details.bound && details.bound !== session.name
368
- ? await readNativeSessionSnapshot(ombSessionDir(details.bound, env), now)
624
+ ? await readNativeSessionSnapshot(ombSessionDir(details.bound, env), now, env)
369
625
  : undefined;
370
- const snapshot = declared?.metadata ? declared : await readNativeSessionSnapshot(ombSessionDir(session.name, env), now);
371
- const native = snapshot.metadata ?? await readLegacyNativeSessionMetadata(details.cwd, session.createdAt, env);
626
+ const snapshot = declared?.metadata ? declared : await readNativeSessionSnapshot(ombSessionDir(session.name, env), now, env);
627
+ const hasReference = Boolean(readOmpLinkManifest(details.bound ?? session.name, env));
628
+ const native = snapshot.metadata ?? (hasReference ? undefined : await readLegacyNativeSessionMetadata(details.cwd, session.createdAt, env));
372
629
  return {
373
630
  // A live session owns the directory its pane declared, so it must not also
374
631
  // be listed from that directory as a second, unopenable session.
375
632
  binding: declared?.metadata ? details.bound : undefined,
376
633
  session: sessionRecord(session.name, {
377
634
  cwd: details.cwd,
378
- state: ombSessionState({ dead: details.dead, attached: session.attached, activity: snapshot.activity }),
379
- attached: session.attached,
635
+ state: authorityKnown ? ombSessionState({ dead: details.dead, attached: session.attached, activity: snapshot.activity }) : "unknown",
636
+ attached: authorityKnown && session.attached,
380
637
  activity: snapshot.activity,
381
- hosted: true,
638
+ hosted: authorityKnown,
639
+ authorityKnown,
382
640
  command: details.command,
383
641
  pid: details.pid,
384
642
  nativeId: native?.id,
@@ -435,6 +693,14 @@ function journalMessageText(content) {
435
693
  * the lookup.
436
694
  */
437
695
  export async function ombSessionJournalPath(session, env = process.env) {
696
+ const reference = readOmpLinkManifest(session.name, env);
697
+ if (reference) {
698
+ try {
699
+ await access(reference.source);
700
+ return reference.source;
701
+ }
702
+ catch { /* fall through to a legacy per-host journal */ }
703
+ }
438
704
  const bound = session.hosted === false ? [] : await ombSessionBoundNames(session.name, session.cwd === "?" ? process.cwd() : session.cwd, env);
439
705
  for (const name of [...new Set([...bound, session.name])]) {
440
706
  const journals = await listSessionJournals(ombSessionDir(name, env));
@@ -527,7 +793,7 @@ async function listUnhostedSessions(env, claimed, now) {
527
793
  const unhosted = (await Promise.all(entries.map(async (entry) => {
528
794
  if (!entry.isDirectory() || !entry.name.startsWith(BIZAR_SESSION_PREFIX) || claimed.has(entry.name) || await isOmbSessionDeleted(entry.name, env))
529
795
  return undefined;
530
- const snapshot = await readNativeSessionSnapshot(join(nativeSessionRoot(env), entry.name), now);
796
+ const snapshot = await readNativeSessionSnapshot(join(nativeSessionRoot(env), entry.name), now, env);
531
797
  const metadata = snapshot.metadata;
532
798
  // A directory with no readable session header holds no session: it is an
533
799
  // emptied tombstone or a directory created before OMP journaled anything.
@@ -535,14 +801,20 @@ async function listUnhostedSessions(env, claimed, now) {
535
801
  if (!metadata)
536
802
  return undefined;
537
803
  const activity = snapshot.activity;
538
- const alive = Boolean(activity && !activity.stale);
804
+ const recent = Boolean(activity && !activity.stale);
805
+ const processObserved = Boolean(activity?.pid && processAliveCheck(activity.pid));
539
806
  return sessionRecord(entry.name, {
540
807
  cwd: metadata.cwd ?? "?",
541
- state: alive ? ombSessionState({ dead: false, attached: false, activity }) : "stopped",
808
+ state: processObserved
809
+ ? recent ? ombSessionState({ dead: false, attached: false, activity }) : "disconnected"
810
+ : recent ? "unknown" : "stopped",
542
811
  attached: false,
543
812
  activity,
544
813
  hosted: false,
545
- command: alive ? "unattached" : "exited",
814
+ authorityKnown: true,
815
+ uncertainLiveness: !processObserved,
816
+ processObserved,
817
+ command: processObserved ? "unattached" : recent ? "unhosted" : "exited",
546
818
  pid: "?",
547
819
  nativeId: metadata.id,
548
820
  nativeName: metadata.title,
@@ -552,8 +824,8 @@ async function listUnhostedSessions(env, claimed, now) {
552
824
  });
553
825
  }))).filter((session) => Boolean(session));
554
826
  unhosted.sort((a, b) => (b.activity?.updatedAt ?? 0) - (a.activity?.updatedAt ?? 0));
555
- const live = unhosted.filter(session => session.state !== "stopped");
556
- return [...live, ...unhosted.filter(session => session.state === "stopped").slice(0, STOPPED_SESSION_LIMIT)];
827
+ const uncertain = unhosted.filter(session => session.state === "unknown");
828
+ return [...uncertain, ...unhosted.filter(session => session.state === "stopped").slice(0, STOPPED_SESSION_LIMIT)];
557
829
  }
558
830
  export async function currentOmbHostSession(cwd = process.cwd(), env = process.env) {
559
831
  if (!env.TMUX)
@@ -581,6 +853,9 @@ export async function listOmbSessions(cwd = process.cwd(), env = process.env, op
581
853
  const childEnv = { ...env, BIZAR_OMP_NO_TMUX: "1" };
582
854
  const now = Date.now();
583
855
  const sessions = await readTmux(tmux, ["list-sessions", "-F", "#{session_name}\t#{session_created}\t#{session_last_attached}\t#{session_attached}"], cwd, childEnv);
856
+ if (options.requireMultiplexer && sessions.code !== 0) {
857
+ throw new ContractError("session authority is unavailable");
858
+ }
584
859
  const live = sessions.code === 0 ? parseSessionList(sessions.output) : [];
585
860
  const described = await Promise.all(live.map(session => describeLiveSession(tmux, session, cwd, childEnv, env, now)));
586
861
  // Every live session claims the directory its pane writes (its own, or the one
@@ -589,12 +864,32 @@ export async function listOmbSessions(cwd = process.cwd(), env = process.env, op
589
864
  ...live.map(session => session.name),
590
865
  ...described.map(item => item.binding).filter((name) => Boolean(name)),
591
866
  ]);
592
- const unhosted = await listUnhostedSessions(env, claimed, now);
867
+ // S001: when the multiplexer is unavailable (code !== 0), do NOT scan
868
+ // directories as "unhosted" — a transient refusal can make a still-hosted
869
+ // session appear unhosted, and `forgetOmbSession` would then tombstone its
870
+ // live journal. Return only the confirmed-live sessions in that case.
871
+ // S001: when the multiplexer binary is missing (exit 127 from ENOENT/EINVAL),
872
+ // skip unhosted scanning — a missing binary means no tmux sessions exist,
873
+ // so unhosted directories could incorrectly override tmux-discovered sessions.
874
+ // For other nonzero codes (e.g. fake test multiplexers, transient errors),
875
+ // the unhosted scan is safe and correct.
876
+ const unhosted = sessions.code === 127 ? [] : await listUnhostedSessions(env, claimed, now);
593
877
  const stopped = options.includeStopped ? unhosted.filter(session => session.state === "stopped") : [];
594
878
  return [...described.map(item => item.session), ...unhosted.filter(session => session.state !== "stopped"), ...stopped].sort((a, b) => STATE_RANK[a.state] - STATE_RANK[b.state] ||
595
879
  a.project.localeCompare(b.project) ||
596
880
  a.name.localeCompare(b.name));
597
881
  }
882
+ /** Re-resolve a selected row immediately before a mutating action. */
883
+ export async function assertOmbSessionGeneration(expected, cwd = process.cwd(), env = process.env) {
884
+ const current = (await listOmbSessions(cwd, env, { includeStopped: true, requireMultiplexer: true }))
885
+ .find(session => session.name === expected.name);
886
+ if (!current || current.generation !== expected.generation) {
887
+ throw new ContractError("session changed externally");
888
+ }
889
+ if (!current.authorityKnown)
890
+ throw new ContractError("session authority is unavailable");
891
+ return current;
892
+ }
598
893
  /** Return the most recently attached live session for one exact project path. */
599
894
  export async function findLastOmbSession(cwd, env = process.env) {
600
895
  const sessions = await listOmbSessions(cwd, env);