@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.
- package/README.md +8 -4
- package/dist/cli/agents-ink.d.ts.map +1 -1
- package/dist/cli/agents-ink.js +5 -3
- package/dist/cli/agents-ink.js.map +1 -1
- package/dist/cli/agents.d.ts.map +1 -1
- package/dist/cli/agents.js +27 -9
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/doctor.d.ts +4 -4
- package/dist/cli/main.js +0 -0
- package/dist/cli/omb.js +0 -0
- package/dist/core/recovery.d.ts.map +1 -1
- package/dist/core/recovery.js +10 -5
- package/dist/core/recovery.js.map +1 -1
- package/dist/core/transitions.d.ts +4 -0
- package/dist/core/transitions.d.ts.map +1 -1
- package/dist/core/transitions.js +12 -2
- package/dist/core/transitions.js.map +1 -1
- package/dist/core/types.d.ts +46 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/extension.d.ts +4 -0
- package/dist/extension.d.ts.map +1 -1
- package/dist/extension.js +308 -23
- package/dist/extension.js.map +1 -1
- package/dist/omp/compatibility.d.ts +5 -5
- package/dist/omp/compatibility.d.ts.map +1 -1
- package/dist/omp/compatibility.js +2 -2
- package/dist/omp/compatibility.js.map +1 -1
- package/dist/omp/daemon-service.d.ts.map +1 -1
- package/dist/omp/daemon-service.js +54 -21
- package/dist/omp/daemon-service.js.map +1 -1
- package/dist/omp/daemon.d.ts.map +1 -1
- package/dist/omp/daemon.js +109 -21
- package/dist/omp/daemon.js.map +1 -1
- package/dist/omp/dashboard-html.js +5 -5
- package/dist/omp/dispatch-admission.js +1 -1
- package/dist/omp/dispatch-admission.js.map +1 -1
- package/dist/omp/model-role-assignment.d.ts +4 -0
- package/dist/omp/model-role-assignment.d.ts.map +1 -1
- package/dist/omp/model-role-assignment.js +52 -7
- package/dist/omp/model-role-assignment.js.map +1 -1
- package/dist/omp/omb-sessions.d.ts +65 -7
- package/dist/omp/omb-sessions.d.ts.map +1 -1
- package/dist/omp/omb-sessions.js +329 -34
- package/dist/omp/omb-sessions.js.map +1 -1
- package/dist/omp/omb-settings.d.ts +15 -1
- package/dist/omp/omb-settings.d.ts.map +1 -1
- package/dist/omp/omb-settings.js +107 -31
- package/dist/omp/omb-settings.js.map +1 -1
- package/dist/omp/rpc.d.ts +8 -0
- package/dist/omp/rpc.d.ts.map +1 -1
- package/dist/omp/session-activity.d.ts +5 -0
- package/dist/omp/session-activity.d.ts.map +1 -1
- package/dist/omp/session-activity.js +17 -0
- package/dist/omp/session-activity.js.map +1 -1
- package/dist/omp/tmux.d.ts +3 -1
- package/dist/omp/tmux.d.ts.map +1 -1
- package/dist/omp/tmux.js +195 -31
- package/dist/omp/tmux.js.map +1 -1
- package/dist/services/candidate-verify.d.ts.map +1 -1
- package/dist/services/candidate-verify.js +44 -1
- package/dist/services/candidate-verify.js.map +1 -1
- package/dist/services/inspector.d.ts +5 -1
- package/dist/services/inspector.d.ts.map +1 -1
- package/dist/services/inspector.js +11 -2
- package/dist/services/inspector.js.map +1 -1
- package/dist/services/native-review-ingest.d.ts +35 -0
- package/dist/services/native-review-ingest.d.ts.map +1 -0
- package/dist/services/native-review-ingest.js +14 -0
- package/dist/services/native-review-ingest.js.map +1 -0
- package/dist/storage/journal-recovery.js +1 -1
- package/dist/storage/journal-recovery.js.map +1 -1
- package/dist/storage/resources.js +1 -1
- package/dist/storage/resources.js.map +1 -1
- package/dist/tools/integrate.d.ts.map +1 -1
- package/dist/tools/integrate.js +13 -0
- package/dist/tools/integrate.js.map +1 -1
- package/dist/tools/workflow.d.ts +9 -0
- package/dist/tools/workflow.d.ts.map +1 -1
- package/dist/tools/workflow.js +25 -2
- package/dist/tools/workflow.js.map +1 -1
- package/docs/compatibility/baseline.json +8 -7
- package/docs/compatibility/supported-surfaces.json +2 -1
- package/docs/development/ci-release-implementation-guide.md +1261 -0
- package/docs/development/contributing-and-releasing.md +117 -0
- package/docs/development/omp-compatibility-update-guide.md +117 -0
- package/docs/releases/0.7.1.md +15 -0
- package/docs/releases/0.7.2.md +32 -0
- package/docs/releases/native-stable.md +11 -1
- package/docs/releases/npm-publishing.md +31 -4
- package/docs/releases/support-matrix.md +1 -1
- package/package.json +2 -1
- package/rules/oflow-gitlab.md +6 -0
- package/skills/oflow-gitlab-context/SKILL.md +49 -0
- package/skills/omp-native-development/SKILL.md +1 -1
- package/skills/omp-native-development/references/accuracy-and-versioning.md +1 -1
- package/skills/omp-native-development/references/source-manifest.json +3 -3
- package/dist/src/cli/agents-ink.d.ts +0 -25
- package/dist/src/cli/agents-ink.js +0 -517
- package/dist/src/cli/agents-ink.js.map +0 -1
- package/dist/src/cli/agents.d.ts +0 -14
- package/dist/src/cli/agents.js +0 -197
- package/dist/src/cli/agents.js.map +0 -1
- package/dist/src/cli/directory-selector.d.ts +0 -60
- package/dist/src/cli/directory-selector.js +0 -208
- package/dist/src/cli/directory-selector.js.map +0 -1
- package/dist/src/cli/doctor.d.ts +0 -41
- package/dist/src/cli/doctor.js +0 -31
- package/dist/src/cli/doctor.js.map +0 -1
- package/dist/src/cli/install.d.ts +0 -129
- package/dist/src/cli/install.js +0 -164
- package/dist/src/cli/install.js.map +0 -1
- package/dist/src/cli/main.d.ts +0 -2
- package/dist/src/cli/main.js +0 -117
- package/dist/src/cli/main.js.map +0 -1
- package/dist/src/cli/migrate.d.ts +0 -18
- package/dist/src/cli/migrate.js +0 -14
- package/dist/src/cli/migrate.js.map +0 -1
- package/dist/src/cli/omb-commands.d.ts +0 -29
- package/dist/src/cli/omb-commands.js +0 -107
- package/dist/src/cli/omb-commands.js.map +0 -1
- package/dist/src/cli/omb-daemon.d.ts +0 -2
- package/dist/src/cli/omb-daemon.js +0 -135
- package/dist/src/cli/omb-daemon.js.map +0 -1
- package/dist/src/cli/omb-dashboard.d.ts +0 -12
- package/dist/src/cli/omb-dashboard.js +0 -113
- package/dist/src/cli/omb-dashboard.js.map +0 -1
- package/dist/src/cli/omb-invocation.d.ts +0 -8
- package/dist/src/cli/omb-invocation.js +0 -41
- package/dist/src/cli/omb-invocation.js.map +0 -1
- package/dist/src/cli/omb-runtime.d.ts +0 -41
- package/dist/src/cli/omb-runtime.js +0 -371
- package/dist/src/cli/omb-runtime.js.map +0 -1
- package/dist/src/cli/omb-tray.d.ts +0 -2
- package/dist/src/cli/omb-tray.js +0 -38
- package/dist/src/cli/omb-tray.js.map +0 -1
- package/dist/src/cli/omb.d.ts +0 -2
- package/dist/src/cli/omb.js +0 -31
- package/dist/src/cli/omb.js.map +0 -1
- package/dist/src/cli/omp-theme.d.ts +0 -17
- package/dist/src/cli/omp-theme.js +0 -22
- package/dist/src/cli/omp-theme.js.map +0 -1
- package/dist/src/cli/process.d.ts +0 -6
- package/dist/src/cli/process.js +0 -54
- package/dist/src/cli/process.js.map +0 -1
- package/dist/src/cli/run.d.ts +0 -2
- package/dist/src/cli/run.js +0 -5
- package/dist/src/cli/run.js.map +0 -1
- package/dist/src/cli/setup-ui.d.ts +0 -37
- package/dist/src/cli/setup-ui.js +0 -90
- package/dist/src/cli/setup-ui.js.map +0 -1
- package/dist/src/core/acceptance.d.ts +0 -32
- package/dist/src/core/acceptance.js +0 -87
- package/dist/src/core/acceptance.js.map +0 -1
- package/dist/src/core/errors.d.ts +0 -20
- package/dist/src/core/errors.js +0 -30
- package/dist/src/core/errors.js.map +0 -1
- package/dist/src/core/evidence.d.ts +0 -10
- package/dist/src/core/evidence.js +0 -35
- package/dist/src/core/evidence.js.map +0 -1
- package/dist/src/core/policies.d.ts +0 -10
- package/dist/src/core/policies.js +0 -60
- package/dist/src/core/policies.js.map +0 -1
- package/dist/src/core/recovery.d.ts +0 -6
- package/dist/src/core/recovery.js +0 -56
- package/dist/src/core/recovery.js.map +0 -1
- package/dist/src/core/transitions.d.ts +0 -13
- package/dist/src/core/transitions.js +0 -59
- package/dist/src/core/transitions.js.map +0 -1
- package/dist/src/core/types.d.ts +0 -256
- package/dist/src/core/types.js +0 -2
- package/dist/src/core/types.js.map +0 -1
- package/dist/src/extension.d.ts +0 -60
- package/dist/src/extension.js +0 -538
- package/dist/src/extension.js.map +0 -1
- package/dist/src/index.d.ts +0 -29
- package/dist/src/index.js +0 -30
- package/dist/src/index.js.map +0 -1
- package/dist/src/omp/autonomous-settings.d.ts +0 -14
- package/dist/src/omp/autonomous-settings.js +0 -65
- package/dist/src/omp/autonomous-settings.js.map +0 -1
- package/dist/src/omp/capabilities.d.ts +0 -23
- package/dist/src/omp/capabilities.js +0 -6
- package/dist/src/omp/capabilities.js.map +0 -1
- package/dist/src/omp/compatibility.d.ts +0 -30
- package/dist/src/omp/compatibility.js +0 -34
- package/dist/src/omp/compatibility.js.map +0 -1
- package/dist/src/omp/completion.d.ts +0 -7
- package/dist/src/omp/completion.js +0 -10
- package/dist/src/omp/completion.js.map +0 -1
- package/dist/src/omp/config.d.ts +0 -10
- package/dist/src/omp/config.js +0 -14
- package/dist/src/omp/config.js.map +0 -1
- package/dist/src/omp/context.d.ts +0 -15
- package/dist/src/omp/context.js +0 -3
- package/dist/src/omp/context.js.map +0 -1
- package/dist/src/omp/daemon-service.d.ts +0 -25
- package/dist/src/omp/daemon-service.js +0 -483
- package/dist/src/omp/daemon-service.js.map +0 -1
- package/dist/src/omp/daemon.d.ts +0 -48
- package/dist/src/omp/daemon.js +0 -194
- package/dist/src/omp/daemon.js.map +0 -1
- package/dist/src/omp/dashboard-html.d.ts +0 -3
- package/dist/src/omp/dashboard-html.js +0 -419
- package/dist/src/omp/dashboard-html.js.map +0 -1
- package/dist/src/omp/dispatch-admission.d.ts +0 -2
- package/dist/src/omp/dispatch-admission.js +0 -12
- package/dist/src/omp/dispatch-admission.js.map +0 -1
- package/dist/src/omp/integration-recovery.d.ts +0 -10
- package/dist/src/omp/integration-recovery.js +0 -18
- package/dist/src/omp/integration-recovery.js.map +0 -1
- package/dist/src/omp/isolation-policy.d.ts +0 -14
- package/dist/src/omp/isolation-policy.js +0 -9
- package/dist/src/omp/isolation-policy.js.map +0 -1
- package/dist/src/omp/lifecycle.d.ts +0 -14
- package/dist/src/omp/lifecycle.js +0 -14
- package/dist/src/omp/lifecycle.js.map +0 -1
- package/dist/src/omp/memory.d.ts +0 -16
- package/dist/src/omp/memory.js +0 -4
- package/dist/src/omp/memory.js.map +0 -1
- package/dist/src/omp/model-role-assignment.d.ts +0 -296
- package/dist/src/omp/model-role-assignment.js +0 -559
- package/dist/src/omp/model-role-assignment.js.map +0 -1
- package/dist/src/omp/model-roles.d.ts +0 -19
- package/dist/src/omp/model-roles.js +0 -6
- package/dist/src/omp/model-roles.js.map +0 -1
- package/dist/src/omp/omb-sessions.d.ts +0 -122
- package/dist/src/omp/omb-sessions.js +0 -512
- package/dist/src/omp/omb-sessions.js.map +0 -1
- package/dist/src/omp/omb-settings.d.ts +0 -35
- package/dist/src/omp/omb-settings.js +0 -104
- package/dist/src/omp/omb-settings.js.map +0 -1
- package/dist/src/omp/result-reconciliation.d.ts +0 -2
- package/dist/src/omp/result-reconciliation.js +0 -9
- package/dist/src/omp/result-reconciliation.js.map +0 -1
- package/dist/src/omp/rpc.d.ts +0 -67
- package/dist/src/omp/rpc.js +0 -4
- package/dist/src/omp/rpc.js.map +0 -1
- package/dist/src/omp/run-log.d.ts +0 -25
- package/dist/src/omp/run-log.js +0 -24
- package/dist/src/omp/run-log.js.map +0 -1
- package/dist/src/omp/session-activity.d.ts +0 -70
- package/dist/src/omp/session-activity.js +0 -361
- package/dist/src/omp/session-activity.js.map +0 -1
- package/dist/src/omp/session-controls.d.ts +0 -17
- package/dist/src/omp/session-controls.js +0 -14
- package/dist/src/omp/session-controls.js.map +0 -1
- package/dist/src/omp/tmux.d.ts +0 -89
- package/dist/src/omp/tmux.js +0 -445
- package/dist/src/omp/tmux.js.map +0 -1
- package/dist/src/omp/tray-icons.d.ts +0 -5
- package/dist/src/omp/tray-icons.js +0 -78
- package/dist/src/omp/tray-icons.js.map +0 -1
- package/dist/src/omp/tray.d.ts +0 -23
- package/dist/src/omp/tray.js +0 -167
- package/dist/src/omp/tray.js.map +0 -1
- package/dist/src/services/budget.d.ts +0 -19
- package/dist/src/services/budget.js +0 -10
- package/dist/src/services/budget.js.map +0 -1
- package/dist/src/services/candidate-local.d.ts +0 -13
- package/dist/src/services/candidate-local.js +0 -15
- package/dist/src/services/candidate-local.js.map +0 -1
- package/dist/src/services/candidates.d.ts +0 -20
- package/dist/src/services/candidates.js +0 -100
- package/dist/src/services/candidates.js.map +0 -1
- package/dist/src/services/evidence-bundle.d.ts +0 -17
- package/dist/src/services/evidence-bundle.js +0 -21
- package/dist/src/services/evidence-bundle.js.map +0 -1
- package/dist/src/services/inspector.d.ts +0 -11
- package/dist/src/services/inspector.js +0 -6
- package/dist/src/services/inspector.js.map +0 -1
- package/dist/src/services/lessons.d.ts +0 -13
- package/dist/src/services/lessons.js +0 -11
- package/dist/src/services/lessons.js.map +0 -1
- package/dist/src/services/projection.d.ts +0 -21
- package/dist/src/services/projection.js +0 -10
- package/dist/src/services/projection.js.map +0 -1
- package/dist/src/services/readiness.d.ts +0 -4
- package/dist/src/services/readiness.js +0 -35
- package/dist/src/services/readiness.js.map +0 -1
- package/dist/src/services/recipes.d.ts +0 -15
- package/dist/src/services/recipes.js +0 -42
- package/dist/src/services/recipes.js.map +0 -1
- package/dist/src/services/recovery.d.ts +0 -19
- package/dist/src/services/recovery.js +0 -9
- package/dist/src/services/recovery.js.map +0 -1
- package/dist/src/services/review.d.ts +0 -15
- package/dist/src/services/review.js +0 -9
- package/dist/src/services/review.js.map +0 -1
- package/dist/src/storage/journal-recovery.d.ts +0 -10
- package/dist/src/storage/journal-recovery.js +0 -33
- package/dist/src/storage/journal-recovery.js.map +0 -1
- package/dist/src/storage/journal.d.ts +0 -12
- package/dist/src/storage/journal.js +0 -82
- package/dist/src/storage/journal.js.map +0 -1
- package/dist/src/storage/migrations.d.ts +0 -22
- package/dist/src/storage/migrations.js +0 -107
- package/dist/src/storage/migrations.js.map +0 -1
- package/dist/src/storage/repository-identity.d.ts +0 -11
- package/dist/src/storage/repository-identity.js +0 -67
- package/dist/src/storage/repository-identity.js.map +0 -1
- package/dist/src/storage/resources.d.ts +0 -66
- package/dist/src/storage/resources.js +0 -148
- package/dist/src/storage/resources.js.map +0 -1
- package/dist/src/tools/evidence.d.ts +0 -8
- package/dist/src/tools/evidence.js +0 -9
- package/dist/src/tools/evidence.js.map +0 -1
- package/dist/src/tools/integrate.d.ts +0 -13
- package/dist/src/tools/integrate.js +0 -90
- package/dist/src/tools/integrate.js.map +0 -1
- package/dist/src/tools/result.d.ts +0 -9
- package/dist/src/tools/result.js +0 -2
- package/dist/src/tools/result.js.map +0 -1
- package/dist/src/tools/verify.d.ts +0 -13
- package/dist/src/tools/verify.js +0 -61
- package/dist/src/tools/verify.js.map +0 -1
- package/dist/src/tools/workflow.d.ts +0 -8
- package/dist/src/tools/workflow.js +0 -65
- package/dist/src/tools/workflow.js.map +0 -1
- package/dist/src/workflows/direct.d.ts +0 -9
- package/dist/src/workflows/direct.js +0 -2
- package/dist/src/workflows/direct.js.map +0 -1
- package/dist/src/workflows/implement.d.ts +0 -2
- package/dist/src/workflows/implement.js +0 -4
- package/dist/src/workflows/implement.js.map +0 -1
- package/dist/src/workflows/plan.d.ts +0 -17
- package/dist/src/workflows/plan.js +0 -6
- package/dist/src/workflows/plan.js.map +0 -1
- package/dist/src/workflows/research.d.ts +0 -15
- package/dist/src/workflows/research.js +0 -2
- package/dist/src/workflows/research.js.map +0 -1
- package/dist/src/workflows/review.d.ts +0 -15
- package/dist/src/workflows/review.js +0 -2
- package/dist/src/workflows/review.js.map +0 -1
- package/dist/src/workflows/verify.d.ts +0 -9
- package/dist/src/workflows/verify.js +0 -2
- package/dist/src/workflows/verify.js.map +0 -1
- package/dist/tests/acceptance.test.d.ts +0 -1
- package/dist/tests/acceptance.test.js +0 -27
- package/dist/tests/acceptance.test.js.map +0 -1
- package/dist/tests/agents.test.d.ts +0 -1
- package/dist/tests/agents.test.js +0 -369
- package/dist/tests/agents.test.js.map +0 -1
- package/dist/tests/candidates.test.d.ts +0 -1
- package/dist/tests/candidates.test.js +0 -60
- package/dist/tests/candidates.test.js.map +0 -1
- package/dist/tests/core.test.d.ts +0 -1
- package/dist/tests/core.test.js +0 -39
- package/dist/tests/core.test.js.map +0 -1
- package/dist/tests/daemon.test.d.ts +0 -1
- package/dist/tests/daemon.test.js +0 -157
- package/dist/tests/daemon.test.js.map +0 -1
- package/dist/tests/dashboard.test.d.ts +0 -1
- package/dist/tests/dashboard.test.js +0 -414
- package/dist/tests/dashboard.test.js.map +0 -1
- package/dist/tests/directory-selector.test.d.ts +0 -1
- package/dist/tests/directory-selector.test.js +0 -93
- package/dist/tests/directory-selector.test.js.map +0 -1
- package/dist/tests/doctor.test.d.ts +0 -1
- package/dist/tests/doctor.test.js +0 -32
- package/dist/tests/doctor.test.js.map +0 -1
- package/dist/tests/install.test.d.ts +0 -1
- package/dist/tests/install.test.js +0 -101
- package/dist/tests/install.test.js.map +0 -1
- package/dist/tests/integration.test.d.ts +0 -1
- package/dist/tests/integration.test.js +0 -49
- package/dist/tests/integration.test.js.map +0 -1
- package/dist/tests/journal.test.d.ts +0 -1
- package/dist/tests/journal.test.js +0 -50
- package/dist/tests/journal.test.js.map +0 -1
- package/dist/tests/model-role-assignment.test.d.ts +0 -1
- package/dist/tests/model-role-assignment.test.js +0 -294
- package/dist/tests/model-role-assignment.test.js.map +0 -1
- package/dist/tests/omb-runtime.test.d.ts +0 -1
- package/dist/tests/omb-runtime.test.js +0 -554
- package/dist/tests/omb-runtime.test.js.map +0 -1
- package/dist/tests/omb-session-actions.test.d.ts +0 -1
- package/dist/tests/omb-session-actions.test.js +0 -191
- package/dist/tests/omb-session-actions.test.js.map +0 -1
- package/dist/tests/omb-settings.test.d.ts +0 -1
- package/dist/tests/omb-settings.test.js +0 -82
- package/dist/tests/omb-settings.test.js.map +0 -1
- package/dist/tests/omp-contract.test.d.ts +0 -1
- package/dist/tests/omp-contract.test.js +0 -362
- package/dist/tests/omp-contract.test.js.map +0 -1
- package/dist/tests/process.test.d.ts +0 -1
- package/dist/tests/process.test.js +0 -12
- package/dist/tests/process.test.js.map +0 -1
- package/dist/tests/psmux-windows.test.d.ts +0 -1
- package/dist/tests/psmux-windows.test.js +0 -105
- package/dist/tests/psmux-windows.test.js.map +0 -1
- package/dist/tests/recovery.test.d.ts +0 -1
- package/dist/tests/recovery.test.js +0 -9
- package/dist/tests/recovery.test.js.map +0 -1
- package/dist/tests/resources.test.d.ts +0 -1
- package/dist/tests/resources.test.js +0 -55
- package/dist/tests/resources.test.js.map +0 -1
- package/dist/tests/session-activity.test.d.ts +0 -1
- package/dist/tests/session-activity.test.js +0 -159
- package/dist/tests/session-activity.test.js.map +0 -1
- package/dist/tests/setup-ui.test.d.ts +0 -1
- package/dist/tests/setup-ui.test.js +0 -37
- package/dist/tests/setup-ui.test.js.map +0 -1
- package/dist/tests/storage-integrity.test.d.ts +0 -1
- package/dist/tests/storage-integrity.test.js +0 -88
- package/dist/tests/storage-integrity.test.js.map +0 -1
- package/dist/tests/tmux.test.d.ts +0 -1
- package/dist/tests/tmux.test.js +0 -239
- package/dist/tests/tmux.test.js.map +0 -1
- package/dist/tests/tray.test.d.ts +0 -1
- package/dist/tests/tray.test.js +0 -37
- package/dist/tests/tray.test.js.map +0 -1
- package/dist/tests/verification.test.d.ts +0 -1
- package/dist/tests/verification.test.js +0 -61
- package/dist/tests/verification.test.js.map +0 -1
- package/dist/tests/workflow-features.test.d.ts +0 -1
- package/dist/tests/workflow-features.test.js +0 -82
- package/dist/tests/workflow-features.test.js.map +0 -1
- package/dist/tests/workflow-safety.test.d.ts +0 -1
- package/dist/tests/workflow-safety.test.js +0 -57
- 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":"
|
|
1
|
+
{"version":3,"file":"omb-sessions.d.ts","sourceRoot":"","sources":["../../src/omp/omb-sessions.ts"],"names":[],"mappings":"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"}
|
package/dist/omp/omb-sessions.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
228
|
+
function ompSessionsRoot(env) {
|
|
60
229
|
if (env.PI_CODING_AGENT_DIR)
|
|
61
|
-
return resolve(env.PI_CODING_AGENT_DIR);
|
|
62
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
|
556
|
-
return [...
|
|
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
|
-
|
|
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);
|