@polderlabs/bizar-omp 0.7.6 → 0.7.8
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 +16 -10
- package/dist/cli/agents-ink.d.ts +34 -0
- package/dist/cli/agents-ink.d.ts.map +1 -1
- package/dist/cli/agents-ink.js +120 -30
- package/dist/cli/agents-ink.js.map +1 -1
- package/dist/cli/agents.d.ts +1 -0
- package/dist/cli/agents.d.ts.map +1 -1
- package/dist/cli/agents.js +37 -13
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/doctor.d.ts +4 -4
- package/dist/core/types.d.ts +13 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +15 -1
- package/dist/core/types.js.map +1 -1
- package/dist/extension.d.ts +2 -0
- package/dist/extension.d.ts.map +1 -1
- package/dist/extension.js +161 -59
- 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 +4 -1
- package/dist/omp/daemon-service.js.map +1 -1
- package/dist/omp/lifecycle.d.ts +1 -1
- package/dist/omp/lifecycle.d.ts.map +1 -1
- package/dist/omp/lifecycle.js +2 -1
- package/dist/omp/lifecycle.js.map +1 -1
- package/dist/omp/omb-sessions.d.ts +60 -3
- package/dist/omp/omb-sessions.d.ts.map +1 -1
- package/dist/omp/omb-sessions.js +183 -19
- package/dist/omp/omb-sessions.js.map +1 -1
- package/dist/omp/omb-settings.d.ts +17 -0
- package/dist/omp/omb-settings.d.ts.map +1 -1
- package/dist/omp/omb-settings.js +10 -0
- package/dist/omp/omb-settings.js.map +1 -1
- package/dist/omp/terminal-title.d.ts +70 -0
- package/dist/omp/terminal-title.d.ts.map +1 -0
- package/dist/omp/terminal-title.js +123 -0
- package/dist/omp/terminal-title.js.map +1 -0
- package/dist/omp/tmux.d.ts +58 -0
- package/dist/omp/tmux.d.ts.map +1 -1
- package/dist/omp/tmux.js +153 -7
- package/dist/omp/tmux.js.map +1 -1
- package/dist/storage/journal.d.ts +1 -1
- package/dist/storage/journal.d.ts.map +1 -1
- package/dist/storage/journal.js +2 -1
- package/dist/storage/journal.js.map +1 -1
- package/docs/compatibility/baseline.json +8 -7
- package/docs/compatibility/supported-surfaces.json +2 -1
- package/docs/releases/0.7.7.md +3 -0
- package/docs/releases/0.7.8.md +21 -0
- package/docs/releases/support-matrix.md +1 -1
- package/package.json +1 -1
- package/skills/bizar-omp/SKILL.md +24 -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/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<p>
|
|
5
5
|
<a href="https://www.npmjs.com/package/@polderlabs/bizar-omp"><img src="https://img.shields.io/npm/v/%40polderlabs%2Fbizar-omp?style=flat-square&color=0f766e&label=npm" alt="npm version" /></a>
|
|
6
6
|
<a href="https://github.com/PolderLabs/BizarHarness-OMP/releases"><img src="https://img.shields.io/github/v/release/PolderLabs/BizarHarness-OMP?style=flat-square&color=2563eb&label=release" alt="latest GitHub release" /></a>
|
|
7
|
-
<img src="https://img.shields.io/badge/OMP-18.4.
|
|
7
|
+
<img src="https://img.shields.io/badge/OMP-18.4.2-2563eb?style=flat-square" alt="OMP 18.4.2" />
|
|
8
8
|
<img src="https://img.shields.io/badge/Node.js-22%2B-18181b?style=flat-square&logo=nodedotjs&logoColor=5fa04e" alt="Node.js 22 or newer" />
|
|
9
9
|
<img src="https://img.shields.io/badge/Bun-1.3.14%2B-18181b?style=flat-square&logo=bun&logoColor=fbf0df" alt="Bun 1.3.14 or newer" />
|
|
10
10
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-18181b?style=flat-square" alt="MIT license" /></a>
|
|
@@ -69,8 +69,8 @@ Bizar does not replace OMP's task system, add a parallel scheduler, or provide a
|
|
|
69
69
|
|
|
70
70
|
- Node.js 22 or newer
|
|
71
71
|
- Bun 1.3.14 or newer
|
|
72
|
-
- OMP 18.4.
|
|
73
|
-
- OMP 18.3.2, 18.3.0, 18.2.11, 18.2.8, 18.2.7, 18.2.6, 18.2.5, 18.2.4 remain regression-qualified
|
|
72
|
+
- OMP 18.4.2 on `PATH`
|
|
73
|
+
- OMP 18.4.1, 18.3.2, 18.3.0, 18.2.11, 18.2.8, 18.2.7, 18.2.6, 18.2.5, 18.2.4 remain regression-qualified
|
|
74
74
|
- tmux on Linux and macOS, or [psmux](https://github.com/psmux/psmux) on Windows for durable sessions
|
|
75
75
|
|
|
76
76
|
Check the host before installing:
|
|
@@ -238,10 +238,11 @@ omb agents --new # open the new-session picker immediately
|
|
|
238
238
|
omb hub # alias for omb agents
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
-
|
|
241
|
+
By default the hub shows the sessions of the current directory, including sessions whose host has stopped. Press `Tab` to switch to every project, and again to return. Press `f` to cycle the state filter between `Active`, `Stopped`, and `Both`. It includes:
|
|
242
242
|
|
|
243
|
+
- A `Cwd`/`All` scope row and an `Active`/`Stopped`/`Both` state row in the header, and matching filters in the plain-text view.
|
|
243
244
|
- One full-width, workspace-grouped session list with a compact selected-session strip.
|
|
244
|
-
- Attach, rename, delete, refresh, settings, help, and reconnect controls.
|
|
245
|
+
- Attach, continue, rename, delete, refresh, settings, help, and reconnect controls.
|
|
245
246
|
- A new-session selector opened with `n`.
|
|
246
247
|
- Recursive search inside the configured Project directory root, parent navigation, recent paths, autocomplete, and direct absolute paths.
|
|
247
248
|
- Optional task text and an explicit session name.
|
|
@@ -252,7 +253,9 @@ The hub shows every Bizar-owned session across projects. It includes:
|
|
|
252
253
|
|
|
253
254
|
| Key | Action |
|
|
254
255
|
| --- | --- |
|
|
255
|
-
| `
|
|
256
|
+
| `Tab` | Switch the list between this directory (`Cwd`) and every project (`All`) |
|
|
257
|
+
| `f` | Cycle the state filter between `Active`, `Stopped`, and `Both` |
|
|
258
|
+
| `Enter` | Attach to the selected live session, or continue a stopped one by restarting its host |
|
|
256
259
|
| `n` | Open the full new-session menu |
|
|
257
260
|
| `e` | Rename the selected session inline |
|
|
258
261
|
| `d` | Delete the selected Bizar session |
|
|
@@ -263,16 +266,16 @@ The hub shows every Bizar-owned session across projects. It includes:
|
|
|
263
266
|
|
|
264
267
|
Mouse clicks select sessions and a second click opens a live one. Mouse scrolling moves through the session list while the hub is open. The hub enables terminal SGR mouse reporting only for its own lifetime. Mouse behavior inside an attached OMP session follows the session's OMP and multiplexer settings.
|
|
265
268
|
|
|
266
|
-
To configure project discovery, open `s`, select `Project directory root`, press `Enter`, enter a path such as `~/projects`, and save. Use `
|
|
269
|
+
To configure project discovery, open `s`, select `Project directory root`, press `Enter`, enter a path such as `~/projects`, and save. Use `Agents view scope` to make `Cwd` or `All` the opening view; the choice is shared by every hub window. Use `Sessions shown` to keep only active sessions, only stopped ones, or both; stopped sessions are shown by default so a conversation whose host exited stays reachable. Pressing `Enter` on a stopped session restarts a host bound to that exact conversation and attaches to it. Deleting a session also tombstones its native journal so a recent history entry cannot reappear as an unopenable session; deleting an already unhosted row removes that stale history entry.
|
|
267
270
|
|
|
268
271
|
### Session states
|
|
269
272
|
|
|
270
273
|
| State | Meaning |
|
|
271
274
|
| --- | --- |
|
|
272
275
|
| `working` | The journal shows unfinished work. |
|
|
273
|
-
| `waiting` | The agent finished its turn and is waiting for input. |
|
|
276
|
+
| `waiting` | The agent finished its turn and is waiting for input, whether or not a client is attached. |
|
|
274
277
|
| `connected` | A client is attached and no structured activity has been journaled yet. |
|
|
275
|
-
| `disconnected` | The host is live and unattached,
|
|
278
|
+
| `disconnected` | The host is live and unattached, and the journal gives no evidence either way. |
|
|
276
279
|
| `stopped` | No host is observed and the journal is silent. |
|
|
277
280
|
|
|
278
281
|
State follows journal activity and host liveness, not tmux attachment alone. A detached session can remain `working`. Activity that stops advancing is marked `stalled`; old journal data is marked `stale`.
|
|
@@ -386,6 +389,9 @@ The role names are selectors, not guarantees of speed, cost, provider, or model
|
|
|
386
389
|
- OMP keeps ownership of credentials, providers, model selections, approval policies, tool policies, and project overrides.
|
|
387
390
|
- Managed worker changes stay isolated and require explicit parent integration. Bizar never silently applies worker patches.
|
|
388
391
|
- Git worktree cleanup is preview-first, ownership-aware, and non-forced. Ignored or uncertain content blocks cleanup.
|
|
392
|
+
- A journal has at most one writer. A host that resumes a different conversation probes the target for a competing writer, then moves its own generation binding and journal manifest together; if either cannot be written, the host is left deliberately unrecoverable rather than still bound to the conversation it left, and a dead pane refuses to respawn instead of resuming the wrong one. The probe is point-in-time — OMP emits no cancellation event for a switch that does not commit, so ownership is re-established on the confirmed switch rather than held across that gap.
|
|
393
|
+
- The agents hub never presents an unanswered multiplexer scan as an empty session list. A refused scan keeps the last confirmed rows and marks the view degraded; a refused scan at startup is reported rather than opening an empty hub.
|
|
394
|
+
- Managed-workflow refusals name the run, its phase, and the cancel that releases it. A run left mid-flight otherwise blocks every `task` call and every non-allowlisted tool for the rest of the session with no in-band way out.
|
|
389
395
|
- Install only in projects and environments you trust. Review `setup --dry-run` and `bizar-omp install-doctor` before making changes.
|
|
390
396
|
|
|
391
397
|
### Qualification boundary
|
|
@@ -398,7 +404,7 @@ The release does not claim OS sandboxing, provider model quality, universal nati
|
|
|
398
404
|
|
|
399
405
|
| Component | Qualified baseline |
|
|
400
406
|
| --- | --- |
|
|
401
|
-
| OMP | 18.4.
|
|
407
|
+
| OMP | 18.4.2 at release commit `4620bb8338e0ecace7ea237da9d5088d16068617`; 18.3.0, 18.2.11, 18.2.8, 18.2.7, 18.2.6, 18.2.5, and 18.2.4 remain regression-qualified |
|
|
402
408
|
| Node.js | 22.x and 24.x |
|
|
403
409
|
| Bun | 1.3.14 compatibility job |
|
|
404
410
|
| Package | `@polderlabs/bizar-omp@0.7.3` |
|
package/dist/cli/agents-ink.d.ts
CHANGED
|
@@ -5,6 +5,15 @@ export type AgentsHubAction = {
|
|
|
5
5
|
} | {
|
|
6
6
|
type: "attach";
|
|
7
7
|
session: OmbSessionInfo;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Restart a host for a session whose tmux session exited, so its journal can
|
|
11
|
+
* be picked up again. Attaching is impossible while nothing hosts it, so
|
|
12
|
+
* this is the only way back into a stopped conversation.
|
|
13
|
+
*/
|
|
14
|
+
| {
|
|
15
|
+
type: "continue";
|
|
16
|
+
session: OmbSessionInfo;
|
|
8
17
|
} | {
|
|
9
18
|
type: "new";
|
|
10
19
|
projectCwd: string;
|
|
@@ -22,5 +31,30 @@ export type AgentsHubAction = {
|
|
|
22
31
|
type: "settings";
|
|
23
32
|
settings: OmbSettings;
|
|
24
33
|
};
|
|
34
|
+
/** Terminal lines consumed by the hub chrome above the first workspace heading. */
|
|
35
|
+
export declare const FIRST_ROW_LINE = 12;
|
|
36
|
+
/**
|
|
37
|
+
* Slice the window of rows that fits beside the hub's fixed chrome.
|
|
38
|
+
*
|
|
39
|
+
* The chrome (header with scope toolbar, list frame, selected strip, footer)
|
|
40
|
+
* costs `CHROME_ROWS`; the remainder is the row budget, where every session
|
|
41
|
+
* also spends a line on a workspace heading. Exported because both this and the
|
|
42
|
+
* mouse hit-test below must agree on where the first row lands, and both are
|
|
43
|
+
* easy to break by changing the header without changing a constant.
|
|
44
|
+
*/
|
|
45
|
+
export declare function sessionWindow(sessions: OmbSessionInfo[], selected: number, rows: number): {
|
|
46
|
+
start: number;
|
|
47
|
+
visible: OmbSessionInfo[];
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Map a terminal row to the session rendered there, or `undefined` for chrome.
|
|
51
|
+
*
|
|
52
|
+
* `FIRST_ROW_LINE` counts the fixed chrome above the first workspace heading:
|
|
53
|
+
* outer padding, header border, title, scope filter row, header border, a
|
|
54
|
+
* one-row gap, list border, list title, and a one-row gap. Measured against a
|
|
55
|
+
* live pane; a stale value silently breaks row clicks without failing any
|
|
56
|
+
* rendering test, so it is pinned by `tests/agents-ink.test.ts`.
|
|
57
|
+
*/
|
|
58
|
+
export declare function sessionMouseIndex(sessions: OmbSessionInfo[], selected: number, rows: number, y: number): number | undefined;
|
|
25
59
|
export declare function runInkAgentsHub(cwd: string, env: NodeJS.ProcessEnv, sessions: OmbSessionInfo[], settings: OmbSettings, initialSelectedName?: string, openNewSession?: boolean): Promise<AgentsHubAction>;
|
|
26
60
|
//# sourceMappingURL=agents-ink.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents-ink.d.ts","sourceRoot":"","sources":["../../src/cli/agents-ink.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"agents-ink.d.ts","sourceRoot":"","sources":["../../src/cli/agents-ink.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA+E,KAAK,cAAc,EAAwB,MAAM,wBAAwB,CAAC;AAEhK,OAAO,EAAiF,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAIzI,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE;AAC7C;;;;GAIG;GACD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,cAAc,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,WAAW,CAAA;CAAE,CAAC;AA4HhD,mFAAmF;AACnF,eAAO,MAAM,cAAc,KAAK,CAAC;AAKjC;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,cAAc,EAAE,CAAA;CAAE,CActI;AAybD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAU3H;AA8KD,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,mBAAmB,CAAC,EAAE,MAAM,EAAE,cAAc,UAAQ,GAAG,OAAO,CAAC,eAAe,CAAC,CAO5M"}
|
package/dist/cli/agents-ink.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { Box, Text, useApp, useInput, useStdin, useStdout, useWindowSize, render } from "ink";
|
|
4
|
-
import { listOmbSessions, ombSessionDisplayName } from "../omp/omb-sessions.js";
|
|
4
|
+
import { filterOmbSessions, listOmbSessions, ombScanAuthority, ombSessionDisplayName } from "../omp/omb-sessions.js";
|
|
5
5
|
import { activitySummary, compactAge } from "../omp/session-activity.js";
|
|
6
|
-
import { watchOmbSettings } from "../omp/omb-settings.js";
|
|
6
|
+
import { saveOmbSettings, watchOmbSettings } from "../omp/omb-settings.js";
|
|
7
7
|
import { directoryKeyAction, expandDirectoryPath, filterDirectoryOptions, readDirectoryCompletions, readDirectoryOptions } from "./directory-selector.js";
|
|
8
8
|
import { OMP_THEME } from "./omp-theme.js";
|
|
9
9
|
const STATUS_STYLE = {
|
|
@@ -19,9 +19,9 @@ const HUB_STATES = ["working", "waiting", "connected", "disconnected", "stopped"
|
|
|
19
19
|
/** One-line meaning of each state, used by the help overlay. */
|
|
20
20
|
const STATUS_HINT = {
|
|
21
21
|
working: "the journal shows unfinished work",
|
|
22
|
-
waiting: "
|
|
23
|
-
connected: "attached with
|
|
24
|
-
disconnected: "no client attached and
|
|
22
|
+
waiting: "finished its turn and is waiting for your input",
|
|
23
|
+
connected: "attached, with no journal evidence of a phase",
|
|
24
|
+
disconnected: "live, with no client attached and no journal evidence either way",
|
|
25
25
|
stopped: "no host observed and the journal went silent",
|
|
26
26
|
unknown: "recent journal exists, but no live host or process was observed",
|
|
27
27
|
};
|
|
@@ -49,14 +49,24 @@ function age(session) {
|
|
|
49
49
|
function workspacePath(session) {
|
|
50
50
|
return session.cwd === "?" ? session.project : session.cwd;
|
|
51
51
|
}
|
|
52
|
-
function visibleSessions(allSessions, settings) {
|
|
53
|
-
return
|
|
54
|
-
.
|
|
52
|
+
function visibleSessions(allSessions, settings, cwd) {
|
|
53
|
+
return filterOmbSessions(allSessions, cwd, {
|
|
54
|
+
scope: settings.agentsScope,
|
|
55
|
+
includeStopped: settings.showStoppedSessions,
|
|
56
|
+
sessionFilter: settings.sessionFilter,
|
|
57
|
+
}).sort((a, b) => workspacePath(a).localeCompare(workspacePath(b)) || HUB_STATES.indexOf(a.state) - HUB_STATES.indexOf(b.state) || a.name.localeCompare(b.name));
|
|
55
58
|
}
|
|
56
|
-
function
|
|
59
|
+
function FilterTabs({ active, color, background }) {
|
|
60
|
+
return _jsxs(Text, { bold: true, color: active ? OMP_THEME.text : OMP_THEME.muted, backgroundColor: active ? background : undefined, children: [" ", color, " "] });
|
|
61
|
+
}
|
|
62
|
+
function Header({ sessions, scope, filter, cwd, scanIssue }) {
|
|
57
63
|
const working = sessions.filter(session => session.state === "working").length;
|
|
58
64
|
const waiting = sessions.filter(session => session.state === "waiting").length;
|
|
59
|
-
|
|
65
|
+
const connected = sessions.filter(session => session.state === "connected").length;
|
|
66
|
+
const disconnected = sessions.filter(session => session.state === "disconnected").length;
|
|
67
|
+
const stopped = sessions.filter(session => session.state === "stopped").length;
|
|
68
|
+
const cwdLabel = scope === "cwd" ? short(cwd, 32) : "every project";
|
|
69
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: OMP_THEME.accent, backgroundColor: OMP_THEME.surface, paddingX: 2, paddingY: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Text, { bold: true, color: OMP_THEME.accent, children: ["\u03C0 ", _jsx(Text, { color: OMP_THEME.text, children: "BIZAR SESSIONS" })] }), _jsxs(Text, { color: OMP_THEME.muted, children: [sessions.length, " shown ", _jsxs(Text, { color: OMP_THEME.success, children: ["\u00B7 ", working, " working"] }), " ", _jsxs(Text, { color: OMP_THEME.warning, children: ["\u00B7 ", waiting, " waiting"] }), stopped > 0 && _jsxs(Text, { color: OMP_THEME.muted, children: [" \u00B7 ", stopped, " stopped"] })] })] }), _jsxs(Box, { marginTop: 1, justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { color: OMP_THEME.muted, children: "Scope:" }), _jsx(FilterTabs, { active: scope === "cwd", color: `Cwd (${cwdLabel})`, background: OMP_THEME.selectedBackground }), _jsx(FilterTabs, { active: scope === "all", color: "All", background: OMP_THEME.selectedBackground }), _jsx(Text, { children: " " }), _jsx(Text, { color: OMP_THEME.muted, children: "State:" }), _jsx(FilterTabs, { active: filter === "active", color: "Active", background: OMP_THEME.selectedBackground }), _jsx(FilterTabs, { active: filter === "stopped", color: "Stopped", background: OMP_THEME.selectedBackground }), _jsx(FilterTabs, { active: filter === "all", color: "Both", background: OMP_THEME.selectedBackground })] }), _jsxs(Text, { color: OMP_THEME.muted, children: [working + waiting + connected + disconnected, " live \u00B7 ", stopped, " stopped"] })] }), scanIssue && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: OMP_THEME.warning, children: ["! Showing the last confirmed session list \u2014 ", scanIssue, "."] }) }))] }));
|
|
60
70
|
}
|
|
61
71
|
function SessionRow({ session, selected, width }) {
|
|
62
72
|
const status = STATUS_STYLE[session.state];
|
|
@@ -64,10 +74,23 @@ function SessionRow({ session, selected, width }) {
|
|
|
64
74
|
const displayName = ombSessionDisplayName(session);
|
|
65
75
|
return (_jsxs(Box, { width: "100%", paddingX: 1, backgroundColor: selected ? OMP_THEME.selectedBackground : undefined, justifyContent: "space-between", children: [_jsx(Box, { justifyContent: "space-between", children: _jsxs(Text, { color: selected ? OMP_THEME.text : status.color, bold: selected, children: [selected ? _jsx(Text, { color: OMP_THEME.accent, children: "\u203A" }) : " ", " ", status.mark, " ", short(displayName, Math.max(18, width - (width >= 100 ? 58 : 24)))] }) }), _jsxs(Text, { color: selected ? OMP_THEME.accent : status.color, children: [" ", status.label] }), width >= 100 && _jsxs(Text, { color: activityColor(activity), children: [" \u00B7 ", short(activitySummary(activity), 24), " ", _jsxs(Text, { color: OMP_THEME.muted, children: ["\u00B7 ", activity ? compactAge(activity.ageSeconds) : age(session), " \u00B7 ", session.nativeOutcome, session.uncertainLiveness ? " · liveness unknown" : ""] })] })] }));
|
|
66
76
|
}
|
|
67
|
-
|
|
77
|
+
/** Terminal lines consumed by the hub chrome above the first workspace heading. */
|
|
78
|
+
export const FIRST_ROW_LINE = 12;
|
|
79
|
+
/** Terminal lines the hub chrome consumes in total, leaving the row budget. */
|
|
80
|
+
const CHROME_ROWS = 16;
|
|
81
|
+
/**
|
|
82
|
+
* Slice the window of rows that fits beside the hub's fixed chrome.
|
|
83
|
+
*
|
|
84
|
+
* The chrome (header with scope toolbar, list frame, selected strip, footer)
|
|
85
|
+
* costs `CHROME_ROWS`; the remainder is the row budget, where every session
|
|
86
|
+
* also spends a line on a workspace heading. Exported because both this and the
|
|
87
|
+
* mouse hit-test below must agree on where the first row lands, and both are
|
|
88
|
+
* easy to break by changing the header without changing a constant.
|
|
89
|
+
*/
|
|
90
|
+
export function sessionWindow(sessions, selected, rows) {
|
|
68
91
|
if (!sessions.length)
|
|
69
92
|
return { start: 0, visible: [] };
|
|
70
|
-
const budget = Math.max(3, rows -
|
|
93
|
+
const budget = Math.max(3, rows - CHROME_ROWS);
|
|
71
94
|
const lineCost = (items) => items.reduce((cost, session, index) => cost + 1 + (index === 0 || workspacePath(items[index - 1]) !== workspacePath(session) ? 1 : 0), 0);
|
|
72
95
|
let start = Math.max(0, Math.min(selected, sessions.length - 1));
|
|
73
96
|
let end = start + 1;
|
|
@@ -106,7 +129,7 @@ function SelectedSummary({ session, width }) {
|
|
|
106
129
|
return (_jsxs(Box, { borderStyle: "round", borderColor: OMP_THEME.border, paddingX: 1, justifyContent: "space-between", children: [_jsxs(Text, { children: [_jsx(Text, { bold: true, children: short(ombSessionDisplayName(session), Math.max(16, Math.floor(width * .3))) }), " ", _jsxs(Text, { color: status.color, children: [status.mark, " ", status.label] })] }), _jsx(Text, { color: activityColor(activity), children: short(activitySummary(activity), Math.max(16, Math.floor(width * .3))) }), _jsxs(Text, { color: OMP_THEME.muted, children: [session.hosted ? short(session.cwd, Math.max(18, Math.floor(width * .28))) : session.processObserved ? "process observed; no host" : "liveness unknown", " \u00B7 ", session.attached ? "attached" : "detached", " \u00B7 ", session.nativeOutcome] })] }));
|
|
107
130
|
}
|
|
108
131
|
function Footer() {
|
|
109
|
-
return (_jsx(Box, {
|
|
132
|
+
return (_jsx(Box, { paddingX: 1, children: _jsxs(Text, { color: OMP_THEME.muted, children: [_jsx(Text, { color: OMP_THEME.accent, children: "Tab" }), " scope ", _jsx(Text, { color: OMP_THEME.accent, children: "Enter" }), " open ", _jsx(Text, { color: OMP_THEME.accent, children: "n" }), " new ", _jsx(Text, { color: OMP_THEME.accent, children: "e" }), " rename ", _jsx(Text, { color: OMP_THEME.accent, children: "d" }), " delete ", _jsx(Text, { color: OMP_THEME.accent, children: "s" }), " settings ", _jsx(Text, { color: OMP_THEME.accent, children: "?" }), " help ", _jsx(Text, { color: OMP_THEME.accent, children: "q" }), " quit"] }) }));
|
|
110
133
|
}
|
|
111
134
|
function Modal({ title, children, width, columns }) {
|
|
112
135
|
return (_jsxs(Box, { position: "absolute", top: 2, left: Math.max(0, Math.floor((columns - width) / 2)), width: width, flexDirection: "column", borderStyle: "round", borderColor: OMP_THEME.accent, backgroundColor: OMP_THEME.surface, paddingX: 2, paddingY: 1, children: [_jsxs(Text, { bold: true, color: OMP_THEME.accent, children: ["\u03C0 \u203A ", title] }), _jsx(Box, { marginTop: 1, width: "100%", flexDirection: "column", backgroundColor: OMP_THEME.surface, children: children })] }));
|
|
@@ -253,9 +276,10 @@ function NewSessionModal({ cwd, sessions, projectsFolder, initialDirectory: work
|
|
|
253
276
|
function SettingsModal({ cwd, settings, selected, columns, onToggle, onMove, onSetProjectsFolder, onSave, onClose }) {
|
|
254
277
|
const options = [
|
|
255
278
|
["Project directory root", settings.projectsFolder || "not set"],
|
|
279
|
+
["Agents view scope", settings.agentsScope === "cwd" ? "Cwd" : "All"],
|
|
256
280
|
["Attach plain omb to latest live session", settings.autoAttachLatest],
|
|
257
281
|
["Enable mouse scrolling in OMB sessions", settings.mouseScrolling],
|
|
258
|
-
["
|
|
282
|
+
["Sessions shown (active/stopped/both)", settings.sessionFilter],
|
|
259
283
|
["Enable system tray icon", settings.trayEnabled],
|
|
260
284
|
];
|
|
261
285
|
const [editingFolder, setEditingFolder] = useState(false);
|
|
@@ -318,12 +342,12 @@ function SettingsModal({ cwd, settings, selected, columns, onToggle, onMove, onS
|
|
|
318
342
|
onToggle();
|
|
319
343
|
}
|
|
320
344
|
});
|
|
321
|
-
return (_jsxs(Modal, { title: "OMB SETTINGS", width: Math.min(70, Math.max(46, columns - 6)), columns: columns, children: [options.map(([label, enabled], index) => (_jsx(Box, { width: "100%", backgroundColor: index === selected ? OMP_THEME.selectedBackground : OMP_THEME.surface, children: _jsxs(Text, { color: index === selected ? OMP_THEME.text : OMP_THEME.muted, children: [index === selected ? _jsx(Text, { color: OMP_THEME.accent, children: "\u203A" }) : " ", " ", typeof enabled === "boolean" ? `[${enabled ? "on " : "off"}]` : enabled, " ", label] }) }, label))), selected === 0 && (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: editingFolder ? OMP_THEME.accent : OMP_THEME.border, backgroundColor: OMP_THEME.surface, paddingX: 1, children: [_jsx(Text, { color: OMP_THEME.accent, children: "\u2315 " }), _jsx(Text, { children: editingFolder ? folderInput || "Type ~/projects or an absolute path" : settings.projectsFolder || "Press Enter to set a projects folder" })] })), selected === 0 && editingFolder && folderSuggestions.length > 0 && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: OMP_THEME.muted, children: "Autocomplete" }), folderSuggestions.slice(0, 5).map((suggestion, index) => (_jsx(Box, { width: "100%", backgroundColor: index === folderSuggestionSelected ? OMP_THEME.selectedBackground : OMP_THEME.surface, children: _jsxs(Text, { color: index === folderSuggestionSelected ? OMP_THEME.text : OMP_THEME.muted, children: [index === folderSuggestionSelected ? _jsx(Text, { color: OMP_THEME.accent, children: "\u203A" }) : " ", " ", suggestion.path] }) }, suggestion.path)))] })), _jsx(Text, { children: " " }), _jsx(Text, { color: OMP_THEME.muted, children: editingFolder ? "Type path Enter apply Ctrl-U clear Esc cancel" : "Up/Down select Space/Enter edit s save Esc cancel" }), _jsx(Text, { color: OMP_THEME.warning, children: selected === 0 ? "Child directories from this folder appear in the new-session picker." : selected ===
|
|
345
|
+
return (_jsxs(Modal, { title: "OMB SETTINGS", width: Math.min(70, Math.max(46, columns - 6)), columns: columns, children: [options.map(([label, enabled], index) => (_jsx(Box, { width: "100%", backgroundColor: index === selected ? OMP_THEME.selectedBackground : OMP_THEME.surface, children: _jsxs(Text, { color: index === selected ? OMP_THEME.text : OMP_THEME.muted, children: [index === selected ? _jsx(Text, { color: OMP_THEME.accent, children: "\u203A" }) : " ", " ", typeof enabled === "boolean" ? `[${enabled ? "on " : "off"}]` : enabled, " ", label] }) }, label))), selected === 0 && (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: editingFolder ? OMP_THEME.accent : OMP_THEME.border, backgroundColor: OMP_THEME.surface, paddingX: 1, children: [_jsx(Text, { color: OMP_THEME.accent, children: "\u2315 " }), _jsx(Text, { children: editingFolder ? folderInput || "Type ~/projects or an absolute path" : settings.projectsFolder || "Press Enter to set a projects folder" })] })), selected === 0 && editingFolder && folderSuggestions.length > 0 && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: OMP_THEME.muted, children: "Autocomplete" }), folderSuggestions.slice(0, 5).map((suggestion, index) => (_jsx(Box, { width: "100%", backgroundColor: index === folderSuggestionSelected ? OMP_THEME.selectedBackground : OMP_THEME.surface, children: _jsxs(Text, { color: index === folderSuggestionSelected ? OMP_THEME.text : OMP_THEME.muted, children: [index === folderSuggestionSelected ? _jsx(Text, { color: OMP_THEME.accent, children: "\u203A" }) : " ", " ", suggestion.path] }) }, suggestion.path)))] })), _jsx(Text, { children: " " }), _jsx(Text, { color: OMP_THEME.muted, children: editingFolder ? "Type path Enter apply Ctrl-U clear Esc cancel" : "Up/Down select Space/Enter edit s save Esc cancel" }), _jsx(Text, { color: OMP_THEME.warning, children: selected === 0 ? "Child directories from this folder appear in the new-session picker." : selected === 1 ? "Cwd shows this directory by default; All shows sessions from every project." : selected === 3 ? "Mouse mode applies to existing OMB sessions when saved." : selected === 5 ? "The tray starts a native menu for supported Linux, macOS, and Windows hosts." : "Settings apply to this shared agents hub." })] }));
|
|
322
346
|
}
|
|
323
347
|
function HelpModal({ columns, onClose }) {
|
|
324
348
|
useInput((input, key) => { if (key.escape || key.return || input === "q")
|
|
325
349
|
onClose(); });
|
|
326
|
-
return (_jsxs(Modal, { title: "OMB AGENTS SHORTCUTS", width: Math.min(64, Math.max(42, columns - 6)), columns: columns, children: [_jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "Enter" }), " open the selected live session"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "n" }), " create a session"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "Mouse" }), " click rows and scroll the list"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "e" }), " rename the selected session"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "d" }), " delete after confirmation"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "s" }), " open launcher settings"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "r" }), " refresh the session list"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "q / Esc" }), " leave this view"] }), _jsx(Text, { children: " " }), _jsx(Text, { color: OMP_THEME.muted, children: "STATES" }), HUB_STATES.map(state => (_jsxs(Text, { color: OMP_THEME.muted, children: [_jsxs(Text, { color: STATUS_STYLE[state].color, children: [STATUS_STYLE[state].mark, " ", state] }), " ", STATUS_HINT[state]] }, state))), _jsx(Text, { color: OMP_THEME.muted, children: "Enter or Esc returns." })] }));
|
|
350
|
+
return (_jsxs(Modal, { title: "OMB AGENTS SHORTCUTS", width: Math.min(64, Math.max(42, columns - 6)), columns: columns, children: [_jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "Enter" }), " open the selected live session"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "Tab / Shift-Tab" }), " switch between Cwd and All sessions"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "n" }), " create a session"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "Mouse" }), " click rows and scroll the list"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "e" }), " rename the selected session"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "d" }), " delete after confirmation"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "s" }), " open launcher settings"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "r" }), " refresh the session list"] }), _jsxs(Text, { children: [_jsx(Text, { color: OMP_THEME.accent, children: "q / Esc" }), " leave this view"] }), _jsx(Text, { children: " " }), _jsx(Text, { color: OMP_THEME.muted, children: "STATES" }), HUB_STATES.map(state => (_jsxs(Text, { color: OMP_THEME.muted, children: [_jsxs(Text, { color: STATUS_STYLE[state].color, children: [STATUS_STYLE[state].mark, " ", state] }), " ", STATUS_HINT[state]] }, state))), _jsx(Text, { color: OMP_THEME.muted, children: "Enter or Esc returns." })] }));
|
|
327
351
|
}
|
|
328
352
|
function DeleteModal({ session, columns, onConfirm, onClose }) {
|
|
329
353
|
useInput((input, key) => {
|
|
@@ -386,10 +410,18 @@ function useTerminalMouse(onMouse) {
|
|
|
386
410
|
};
|
|
387
411
|
}, [stdin, stdout]);
|
|
388
412
|
}
|
|
389
|
-
|
|
413
|
+
/**
|
|
414
|
+
* Map a terminal row to the session rendered there, or `undefined` for chrome.
|
|
415
|
+
*
|
|
416
|
+
* `FIRST_ROW_LINE` counts the fixed chrome above the first workspace heading:
|
|
417
|
+
* outer padding, header border, title, scope filter row, header border, a
|
|
418
|
+
* one-row gap, list border, list title, and a one-row gap. Measured against a
|
|
419
|
+
* live pane; a stale value silently breaks row clicks without failing any
|
|
420
|
+
* rendering test, so it is pinned by `tests/agents-ink.test.ts`.
|
|
421
|
+
*/
|
|
422
|
+
export function sessionMouseIndex(sessions, selected, rows, y) {
|
|
390
423
|
const { start, visible } = sessionWindow(sessions, selected, rows);
|
|
391
|
-
|
|
392
|
-
let line = 7;
|
|
424
|
+
let line = FIRST_ROW_LINE;
|
|
393
425
|
let previousWorkspace;
|
|
394
426
|
for (const [offset, session] of visible.entries()) {
|
|
395
427
|
if (workspacePath(session) !== previousWorkspace) {
|
|
@@ -411,21 +443,31 @@ function AgentsApp({ cwd, env, sessions: initialSessions, settings: initialSetti
|
|
|
411
443
|
const [overlay, setOverlay] = useState(openNewSessionOnStart ? "new" : undefined);
|
|
412
444
|
const [overlaySelected, setOverlaySelected] = useState(0);
|
|
413
445
|
const [draftSettings, setDraftSettings] = useState(initialSettings);
|
|
446
|
+
const [scanIssue, setScanIssue] = useState();
|
|
414
447
|
const refreshSequence = useRef(0);
|
|
415
448
|
const { exit } = useApp();
|
|
416
|
-
const sessions = useMemo(() => visibleSessions(allSessions, settings), [allSessions, settings]);
|
|
449
|
+
const sessions = useMemo(() => visibleSessions(allSessions, settings, cwd), [allSessions, settings, cwd]);
|
|
417
450
|
const selected = Math.max(0, sessions.findIndex(session => session.name === selectedName));
|
|
418
451
|
const selectedSession = sessions[selected];
|
|
419
|
-
const refresh = async (
|
|
452
|
+
const refresh = async () => {
|
|
420
453
|
const sequence = ++refreshSequence.current;
|
|
421
|
-
|
|
454
|
+
// A scan the multiplexer could not answer is not evidence that no sessions
|
|
455
|
+
// exist. Applying it would blank every row on a transient tmux restart, so
|
|
456
|
+
// the last good list is kept and the hub is marked degraded instead.
|
|
457
|
+
const authority = await ombScanAuthority(cwd, env);
|
|
458
|
+
if (sequence !== refreshSequence.current)
|
|
459
|
+
return;
|
|
460
|
+
setScanIssue(authority.known ? undefined : authority.reason);
|
|
461
|
+
if (!authority.known)
|
|
462
|
+
return;
|
|
463
|
+
const next = await listOmbSessions(cwd, env, { includeStopped: true });
|
|
422
464
|
if (sequence === refreshSequence.current)
|
|
423
465
|
setAllSessions(next);
|
|
424
466
|
};
|
|
425
467
|
useEffect(() => {
|
|
426
468
|
const timer = setInterval(() => { void refresh(); }, 3000);
|
|
427
469
|
return () => clearInterval(timer);
|
|
428
|
-
}, [cwd, env
|
|
470
|
+
}, [cwd, env]);
|
|
429
471
|
useEffect(() => {
|
|
430
472
|
// Reload settings when another process (the dashboard, another `omb agents`
|
|
431
473
|
// window, or `omp config set`) rewrites the shared `omb.json`. The watch
|
|
@@ -452,6 +494,37 @@ function AgentsApp({ cwd, env, sessions: initialSessions, settings: initialSetti
|
|
|
452
494
|
return;
|
|
453
495
|
setSelectedName(session.name);
|
|
454
496
|
};
|
|
497
|
+
const toggleScope = () => {
|
|
498
|
+
const next = { ...settings, agentsScope: settings.agentsScope === "cwd" ? "all" : "cwd" };
|
|
499
|
+
try {
|
|
500
|
+
setSettings(saveOmbSettings(next, env));
|
|
501
|
+
}
|
|
502
|
+
catch (error) {
|
|
503
|
+
if (error instanceof Error && error.name === "OmbSettingsConflictError")
|
|
504
|
+
return;
|
|
505
|
+
throw error;
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
const toggleFilter = () => {
|
|
509
|
+
const order = ["all", "active", "stopped"];
|
|
510
|
+
const next = { ...settings, sessionFilter: order[(order.indexOf(settings.sessionFilter) + 1) % order.length] ?? "all" };
|
|
511
|
+
try {
|
|
512
|
+
setSettings(saveOmbSettings(next, env));
|
|
513
|
+
}
|
|
514
|
+
catch (error) {
|
|
515
|
+
if (error instanceof Error && error.name === "OmbSettingsConflictError")
|
|
516
|
+
return;
|
|
517
|
+
throw error;
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
/**
|
|
521
|
+
* Enter on a stopped session restarts a host for it instead of attaching:
|
|
522
|
+
* nothing is attached to a session tmux no longer hosts, so attaching is
|
|
523
|
+
* the one action guaranteed not to work.
|
|
524
|
+
*/
|
|
525
|
+
const sessionAction = (session) => session.state === "stopped" || session.hosted === false
|
|
526
|
+
? { type: "continue", session }
|
|
527
|
+
: { type: "attach", session };
|
|
455
528
|
useTerminalMouse(event => {
|
|
456
529
|
if (overlay || event.release)
|
|
457
530
|
return;
|
|
@@ -465,14 +538,22 @@ function AgentsApp({ cwd, env, sessions: initialSessions, settings: initialSetti
|
|
|
465
538
|
if (index === undefined)
|
|
466
539
|
return;
|
|
467
540
|
const session = sessions[index];
|
|
468
|
-
if (session?.name === selectedName
|
|
469
|
-
finish(
|
|
541
|
+
if (session?.name === selectedName)
|
|
542
|
+
finish(sessionAction(session));
|
|
470
543
|
else
|
|
471
544
|
selectSession(index);
|
|
472
545
|
});
|
|
473
546
|
useInput((input, key) => {
|
|
474
547
|
if (overlay)
|
|
475
548
|
return;
|
|
549
|
+
if (key.tab) {
|
|
550
|
+
toggleScope();
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
if (input === "f") {
|
|
554
|
+
toggleFilter();
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
476
557
|
if (key.ctrl && input === "c") {
|
|
477
558
|
finish({ type: "quit" });
|
|
478
559
|
return;
|
|
@@ -485,8 +566,8 @@ function AgentsApp({ cwd, env, sessions: initialSessions, settings: initialSetti
|
|
|
485
566
|
selectSession(Math.max(0, selected - 1));
|
|
486
567
|
else if (key.downArrow || input === "j")
|
|
487
568
|
selectSession(Math.min(Math.max(0, sessions.length - 1), selected + 1));
|
|
488
|
-
else if (key.return && selectedSession
|
|
489
|
-
finish(
|
|
569
|
+
else if (key.return && selectedSession)
|
|
570
|
+
finish(sessionAction(selectedSession));
|
|
490
571
|
else if (input === "n")
|
|
491
572
|
openNewSession(selectedSession?.cwd === "?" ? undefined : selectedSession?.cwd);
|
|
492
573
|
else if (input === "e" && selectedSession && selectedSession.hosted !== false && selectedSession.state !== "stopped")
|
|
@@ -505,14 +586,23 @@ function AgentsApp({ cwd, env, sessions: initialSessions, settings: initialSetti
|
|
|
505
586
|
setOverlay("settings");
|
|
506
587
|
}
|
|
507
588
|
});
|
|
508
|
-
return (_jsxs(Box, { flexDirection: "column", width: "100%", minHeight: Math.max(12, rows - 1), paddingX: 1, children: [_jsx(Header, { sessions: sessions }), _jsx(Box, { flexGrow: 1, marginTop: 1, children: _jsx(SessionList, { sessions: sessions, selected: selected, rows: rows, width: Math.max(34, columns - 4) }) }), _jsx(SelectedSummary, { session: selectedSession, width: Math.max(34, columns - 4) }), _jsx(Footer, {}), overlay === "new" && (_jsx(NewSessionModal, { cwd: cwd, sessions: allSessions, projectsFolder: settings.projectsFolder, initialDirectory: newSessionDirectory, selected: selectedSession, columns: columns, rows: rows, onSubmit: value => finish({ type: "new", ...value }), onClose: () => setOverlay(undefined) })), overlay === "help" && _jsx(HelpModal, { columns: columns, onClose: () => setOverlay(undefined) }), overlay === "delete" && selectedSession && _jsx(DeleteModal, { session: selectedSession, columns: columns, onConfirm: () => finish({ type: "delete", session: selectedSession, nextSessionName: sessions[selected - 1]?.name ?? sessions[selected + 1]?.name }), onClose: () => setOverlay(undefined) }), overlay === "rename" && selectedSession && _jsx(RenameModal, { session: selectedSession, columns: columns, onConfirm: value => finish({ type: "rename", session: selectedSession, nextId: value }), onClose: () => setOverlay(undefined) }), overlay === "settings" && (_jsx(SettingsModal, { cwd: cwd, settings: draftSettings, selected: overlaySelected, onMove: setOverlaySelected, columns: columns, onToggle: () => {
|
|
589
|
+
return (_jsxs(Box, { flexDirection: "column", width: "100%", minHeight: Math.max(12, rows - 1), paddingX: 1, children: [_jsx(Header, { sessions: sessions, scope: settings.agentsScope, filter: settings.sessionFilter, cwd: cwd, scanIssue: scanIssue }), _jsx(Box, { flexGrow: 1, marginTop: 1, children: _jsx(SessionList, { sessions: sessions, selected: selected, rows: rows, width: Math.max(34, columns - 4) }) }), _jsx(SelectedSummary, { session: selectedSession, width: Math.max(34, columns - 4) }), _jsx(Footer, {}), overlay === "new" && (_jsx(NewSessionModal, { cwd: cwd, sessions: allSessions, projectsFolder: settings.projectsFolder, initialDirectory: newSessionDirectory, selected: selectedSession, columns: columns, rows: rows, onSubmit: value => finish({ type: "new", ...value }), onClose: () => setOverlay(undefined) })), overlay === "help" && _jsx(HelpModal, { columns: columns, onClose: () => setOverlay(undefined) }), overlay === "delete" && selectedSession && _jsx(DeleteModal, { session: selectedSession, columns: columns, onConfirm: () => finish({ type: "delete", session: selectedSession, nextSessionName: sessions[selected - 1]?.name ?? sessions[selected + 1]?.name }), onClose: () => setOverlay(undefined) }), overlay === "rename" && selectedSession && _jsx(RenameModal, { session: selectedSession, columns: columns, onConfirm: value => finish({ type: "rename", session: selectedSession, nextId: value }), onClose: () => setOverlay(undefined) }), overlay === "settings" && (_jsx(SettingsModal, { cwd: cwd, settings: draftSettings, selected: overlaySelected, onMove: setOverlaySelected, columns: columns, onToggle: () => {
|
|
509
590
|
if (overlaySelected === 0)
|
|
510
591
|
return;
|
|
511
|
-
|
|
592
|
+
if (overlaySelected === 1) {
|
|
593
|
+
setDraftSettings(value => ({ ...value, agentsScope: value.agentsScope === "cwd" ? "all" : "cwd" }));
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
if (overlaySelected === 4) {
|
|
597
|
+
const order = ["all", "active", "stopped"];
|
|
598
|
+
setDraftSettings(value => ({ ...value, sessionFilter: order[(order.indexOf(value.sessionFilter) + 1) % order.length] ?? "all" }));
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
const field = overlaySelected === 2 ? "autoAttachLatest" : overlaySelected === 3 ? "mouseScrolling" : "trayEnabled";
|
|
512
602
|
setDraftSettings(value => ({ ...value, [field]: !value[field] }));
|
|
513
603
|
}, onSetProjectsFolder: value => setDraftSettings(current => ({ ...current, projectsFolder: value })), onSave: () => {
|
|
514
604
|
setSettings(draftSettings);
|
|
515
|
-
void refresh(
|
|
605
|
+
void refresh();
|
|
516
606
|
finish({ type: "settings", settings: draftSettings });
|
|
517
607
|
}, onClose: () => setOverlay(undefined) }))] }));
|
|
518
608
|
}
|