@polderlabs/bizar-omp 0.4.2 → 0.4.4

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 CHANGED
@@ -1,122 +1,197 @@
1
- # BizarHarness OMP
1
+ <div align="center">
2
+ <img src="docs/assets/bizar-omp-banner.svg" alt="BizarHarness OMP: autonomous engineering with evidence in the loop" width="100%" />
2
3
 
3
- Release `0.4.2` is the current release target; it will be published on [npm](https://www.npmjs.com/package/@polderlabs/bizar-omp) and available as a [GitHub release](https://github.com/PolderLabsVOF/BizarHarness-OMP/releases/tag/v0.4.2) after the final release gate.
4
+ <p>
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
+ <a href="https://github.com/PolderLabsVOF/BizarHarness-OMP/releases"><img src="https://img.shields.io/github/v/release/PolderLabsVOF/BizarHarness-OMP?style=flat-square&color=2563eb&label=release" alt="latest GitHub release" /></a>
7
+ <img src="https://img.shields.io/badge/OMP-18.2.6-2563eb?style=flat-square" alt="OMP 18.2.6" />
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
+ <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
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-18181b?style=flat-square" alt="MIT license" /></a>
11
+ </p>
4
12
 
5
- BizarHarness OMP is a ground-up, native [oh-my-pi](https://github.com/can1357/oh-my-pi) extension for engineering workflows. It owns workflow intent, acceptance contracts, evidence freshness, and integration admission. OMP owns sessions, models, credentials, tools, workers, isolation, and conversation state.
13
+ <p><strong>Native autonomous engineering workflows for oh-my-pi.</strong><br />
14
+ Plan proportionally, run work in durable sessions, and finish with evidence you can inspect.</p>
15
+ </div>
6
16
 
7
- The package has no Claude Code, AO, Claude Agent SDK, MCP server, second worker runtime, or replacement background daemon. OMP owns native task execution and the live host lifecycle. This release provides workflow tracking, host-observed checks, scoped patch integration, agents, skills, and an autonomous settings installer. Automatic interception and reconciliation of all native task/eval calls are not implemented.
17
+ ---
18
+
19
+ ## What Bizar OMP is
20
+
21
+ BizarHarness OMP is a native [oh-my-pi](https://github.com/can1357/oh-my-pi) extension for engineering work. It adds workflow intent, acceptance criteria, evidence freshness, specialist roles, scoped integration, and a durable session launcher while leaving OMP in charge of sessions, models, credentials, tools, task execution, and conversation state.
22
+
23
+ | You need | Bizar OMP provides |
24
+ | --- | --- |
25
+ | A sensible process | Focused, bounded, and full workflow tiers selected from task scope and risk |
26
+ | Background work | `omb` sessions inside tmux, with reconnect and a cross-project session hub |
27
+ | Useful specialists | Native Bizar roles for orchestration, planning, research, implementation, review, security, verification, and documentation |
28
+ | Stronger completion signals | Host-observed checks, fresh evidence, explicit acceptance, and serialized integration |
29
+ | A readable operator experience | Native Advisor enabled by default, visible active agents, hidden tool trace, and readable chat output |
30
+
31
+ Bizar does not start a second agent runtime, replace OMP's task system, or include a Claude Code, MCP, or background daemon compatibility layer.
8
32
 
9
33
  ## Install
10
34
 
11
- Requires Node 22+, Bun 1.3.14+, and OMP **18.2.6** on PATH (18.2.5 and 18.2.4 remain regression-qualified).
35
+ ### Full installation
36
+
37
+ The supported installation path configures the complete OMP experience in one command.
12
38
 
13
- The recommended installation is through OMP's native plugin manager:
39
+ Requires Node.js 22 or newer, Bun 1.3.14 or newer, and OMP 18.2.6 on `PATH`. OMP 18.2.5 and 18.2.4 remain regression-qualified.
14
40
 
15
41
  ```sh
16
- omp plugin install @polderlabs/bizar-omp
17
- omp
42
+ npx --yes @polderlabs/bizar-omp setup
18
43
  ```
19
44
 
20
- This loads the extension, eight Bizar specialist agents, the default `bizar-omp` orientation skill plus specialized skills, rules, prompts, and the native model-role command. The main OMP session is the Bizar Orchestrator by default. Bizar also enables OMP's native Advisor and configures a visible `bizar_advisor` role for passive independent review. The skill explains Bizar's ownership boundaries, workflow/evidence tools, model-role command, and `omp` versus `omb` launcher contract. On session start, Bizar applies its autonomous OMP preset, enables background task execution, and enables steerable Collab. The ordinary `omp` command remains untouched; use `omb` when you want a durable tmux-backed host.
45
+ The installer:
46
+
47
+ 1. Installs the exact Bizar version globally, providing `omb` and `bizar-omp`.
48
+ 2. Registers and enables the package through `omp plugin install`.
49
+ 3. Installs the extension, eight specialist agents, skills, rules, prompts, tools, and model roles.
50
+ 4. Makes the Bizar Orchestrator the default conversation and enables OMP's native Advisor.
51
+ 5. Applies the autonomous preset for background tasks, steerable Collab, visible agents, and readable output.
52
+ 6. Writes a recoverable receipt and preserves credentials, provider choices, approval policies, and project overrides.
21
53
 
22
- OMP's plugin manager owns the extension and all OMP-discoverable assets. It cannot place npm executables into your shell `PATH`, so `omb` and `bizar-omp` need the explicit all-in-one setup fallback:
54
+ Interactive terminals show a phase dashboard with detected versions, applied settings, the recovery receipt, and the next commands. Preview or script the same operation with:
23
55
 
24
56
  ```sh
25
- npx --yes @polderlabs/bizar-omp@0.4.2 setup
57
+ npx --yes @polderlabs/bizar-omp setup --dry-run
58
+ npx --yes @polderlabs/bizar-omp setup --json
26
59
  ```
27
60
 
28
- `setup` installs the exact package version globally for both commands, installs that same version through `omp plugin install`, applies the autonomous settings with a recoverable receipt, and leaves credentials and explicit user policies intact. If you only need the OMP extension, `omp plugin install @polderlabs/bizar-omp` remains the primary path.
29
-
30
- The companion CLI is optional for diagnostics and repair:
61
+ ### Start OMP
31
62
 
32
63
  ```sh
33
- npm install --global @polderlabs/bizar-omp
34
- bizar-omp install-doctor
35
- omb
64
+ omp # normal direct OMP session
65
+ omb # durable tmux-backed session
66
+ omb agents # session hub and new-session selector
36
67
  ```
37
68
 
38
- `bizar-omp install` remains available when a host-level repair is needed; `bizar-omp setup` is the one-command fallback when you need both the plugin and shell commands. The plugin path is the normal path and applies the same autonomous settings from the loaded extension. Worker patches are retained for explicit parent integration rather than automatically applied. Credentials, selected providers/models, explicit deny/prompt policies, and project overrides are preserved.
69
+ `omp` remains untouched. `omb` is the explicit durable mode. Plain `omb` reconnects to the most recently active live session in the current directory, or creates that directory's default session when none exists.
39
70
 
40
- Use only in trusted projects. OMP extensions and shell commands are not an OS security sandbox. Review changes with `bizar-omp install --dry-run`; isolate configuration with `bizar-omp install --profile bizar`, then launch `omp --profile bizar`. A new profile needs its own OMP login/model configuration.
71
+ ### Verify, repair, or remove
41
72
 
42
- Restart OMP after plugin installation. `bizar-omp uninstall` removes the plugin installation created by the CLI installer and restores settings it changed, preserving later user edits. Add the same `--profile` for profile-scoped commands. The global package install supplies the `omb` and `bizar-omp` shell commands; the plugin itself is still installed and updated through `omp plugin install`.
73
+ ```sh
74
+ bizar-omp install-doctor
75
+ omp plugin list
76
+ omp plugin doctor
77
+ ```
43
78
 
44
- ## Development
79
+ For a profile-scoped installation:
45
80
 
46
81
  ```sh
47
- npm install
48
- npm test
49
- npm run typecheck
50
- npm run verify:package
82
+ npx --yes @polderlabs/bizar-omp setup --profile bizar
83
+ omp --profile bizar
84
+ bizar-omp install-doctor --profile bizar
51
85
  ```
52
86
 
53
- Try the extension from the checkout with `omp --extension ./dist/extension.js`. For an installed package use `omp plugin link /path/to/bizaromp`; the `omp.extensions` manifest points at `dist/extension.js`.
87
+ Each profile has its own OMP login and model configuration. Remove Bizar's plugin configuration with `bizar-omp uninstall`. The command restores settings only when they still contain the values Bizar applied, preserving later edits. Remove the global shell commands separately if needed:
54
88
 
55
- The development contract is documented in `CONTRIBUTING.md`: work from feature branches, pass CI before merging to `main`, use Conventional Commits, and cut exact SemVer tags. CI runs on Node 22/24 and Bun 1.3.14, including packed-package and registry-plugin installation against OMP 18.2.6. Repository-plan limitations currently prevent enforced GitHub branch protection. Tagged builds publish to npm through trusted publishing and create a GitHub release artifact; see [release setup](docs/releases/npm-publishing.md).
89
+ ```sh
90
+ npm uninstall --global @polderlabs/bizar-omp
91
+ ```
56
92
 
57
- ## Commands and tools
93
+ ### Extension-only installation
58
94
 
59
- The extension registers `/bizar` with `init`, `run`, `status`, `next`, `cancel`, `evidence`, and legacy `model-roles` subcommands, plus the simpler `/bizar-models` command. LLM tools are `bizar_workflow`, `bizar_verify`, `bizar_evidence`, and `bizar_integrate`. Start with `/bizar run <objective>`; the model uses tools to advance the workflow, record checks, accept work, and complete it. For unattended continuation, explicitly ask OMP to pursue a native goal; Bizar does not create a second execution loop.
95
+ Use the native plugin command only when you already manage the shell commands yourself or only need the OMP extension:
60
96
 
61
- The core is deliberately deterministic where it can be: transitions, route classification, evidence invalidation, ownership, idempotency, and integration eligibility are pure or journaled contracts. Provider output and native worker execution remain observable external effects and are never treated as complete merely because a call was accepted.
97
+ ```sh
98
+ omp plugin install @polderlabs/bizar-omp
99
+ ```
62
100
 
63
- ### Automatic Bizar method tiers
101
+ This does not install `omb` or `bizar-omp` on `PATH`. For checkout development, use `omp plugin link /path/to/bizaromp`.
64
102
 
65
- The main Orchestrator chooses the method tier automatically. Focused fixes use direct edits and targeted proof; bounded features use lightweight Bizar acceptance and checks; full-risk work uses planning, isolation, fresh evidence, independent review, and serialized integration. Security, architecture, ambiguity, unknown-cause regressions, cross-cutting scope, and integration risk always escalate to the full tier. A focused task is still validated proportionally, and a task escalates if its scope or risk changes.
103
+ ## How to work with Bizar
66
104
 
67
- ## Persistent agent sessions and the Agent Hub
105
+ The main OMP conversation is the Bizar Orchestrator. It chooses the smallest method that fits the work:
68
106
 
69
- OMP's native Agent Hub is the control surface for Bizar's background agents. With `async.enabled` enabled, task agents run in the background and can be inspected from the hub. Bizar sets `display.pinnedAgents=full`, so every active task agent is visible in the live session as well as the hub. Open the hub with `Alt+A` or `Ctrl+S`; it can inspect live agents, open their transcripts, interrupt them, send follow-up instructions, and revive parked agents. Agent definitions and model roles are not running sessions: they appear in the hub only after the orchestrator actually spawns them, so installation does not waste model calls by starting every specialist.
107
+ | Tier | Use it for | Typical proof |
108
+ | --- | --- | --- |
109
+ | Focused | A local bug fix, styling change, typo, or narrow documentation edit | Targeted check, diff review, or smoke test |
110
+ | Bounded | A contained behavior change or small feature | Acceptance criteria and focused tests |
111
+ | Full | Security, architecture, migrations, concurrency, unknown regressions, or cross-cutting work | Planning, isolation, fresh evidence, review, and serialized integration |
70
112
 
71
- For a session that must keep running after its visible terminal closes, start OMP with `omb`. `omb` starts the interactive OMP host inside a persistent tmux session from the first process. A terminal window is only the client; the host process is what owns the model turn and workers:
113
+ The route can escalate when scope or risk changes. A focused task is still validated; it simply avoids ceremony that does not improve the result.
72
114
 
73
- ```sh
74
- # The primary durable launcher. Re-running it reconnects to this project host.
75
- omb
115
+ ### Useful commands inside OMP
116
+
117
+ ```text
118
+ /bizar run <objective> start a bounded workflow
119
+ /bizar status inspect the active workflow
120
+ /bizar evidence inspect current proof
121
+ /bizar cancel cancel the active workflow
122
+ /bizar-models map available OMP models to Bizar roles
123
+ /bizar-models health validate Bizar role selectors without changing them
76
124
  ```
77
125
 
78
- `omp` remains the normal direct launcher and never starts, attaches to, or hands off to tmux. This separation keeps terminal ownership deterministic and prevents raw-mode probe responses from leaking between OMP processes. Plain `omb` reconnects to the most recently active live Bizar session in the current directory; if none exists, it creates the stable default session for that directory. The launcher enables tmux mouse mode before attaching, so wheel scrolling stays pane scrolling instead of becoming OMP prompt-history input. Inside an existing tmux session, `omb` runs OMP directly to avoid nested tmux clients. Noninteractive invocations such as `omb --print` also run directly.
126
+ `/bizar-models` reads OMP's authenticated model catalog locally, assigns the best available selectors to Bizar roles, validates native resolution, and preserves unrelated roles.
127
+
128
+ ## Durable sessions and the agents hub
79
129
 
80
- Run multiple durable OMP conversations in the same project with a session id, or create a fresh generated session:
130
+ Use `omb` when a session must keep running after the terminal client closes. OMP runs inside a Bizar-owned tmux host from the first process. The client can detach without stopping the host or its background agents.
81
131
 
82
132
  ```sh
83
133
  omb new "Investigate the API timeout"
84
134
  omb --session api-retries
85
- omb --new
135
+ omb agents
86
136
  ```
87
137
 
88
- `omb new` always creates a fresh session. `omb --session <id>` creates or reconnects to a named session, while plain `omb` returns to the latest active session for the current directory.
138
+ The `omb agents` hub provides:
89
139
 
90
- Use the cross-project session switcher to see every Bizar-owned host, attach to one, or dispatch a new host from an interactive prompt:
140
+ - A workspace rail and grouped session list across projects.
141
+ - A global registry of every Bizar session, including sessions running outside the directory where `omb agents` was opened.
142
+ - Session attach, rename, delete, refresh, settings, help, and reconnect controls.
143
+ - A new-session selector opened with `n`.
144
+ - Fuzzy directory search, parent and child navigation, recent project shortcuts, and direct absolute paths.
145
+ - A configurable Projects folder in Settings; its child directories are indexed for quick new-session dispatch from anywhere.
146
+ - Optional initial task text and session naming without leaving the TUI.
147
+ - Native OMP session titles with deterministic project/task fallbacks.
91
148
 
92
- ```sh
93
- omb agents
94
- ```
149
+ Key controls are `Enter` attach, `n` new session, `e` rename, `d` delete, `s` settings, `r` refresh, `?` help, and `q` exit. Inside a session, `Ctrl-d` or `Ctrl-c` returns to the hub without sending EOF or interrupt input to OMP. Mouse scrolling is enabled by default and can be changed in Settings.
95
150
 
96
- The hub is a full-screen Ink TUI with a workspace rail, grouped live-session list, selected-session inspector, status counts, and modal Settings, Help, and Delete views. It remains keyboard-first: use Up/Down (or `j`/`k`) to select, Enter to attach, `n` to choose a project directory, task, and session name, `e` to rename, `d` to delete after confirmation, `s` to open Settings, `r` to refresh, `?` for help, and `q` to leave the hub. Settings persist the latest-session reconnect preference, mouse scrolling, and whether stopped sessions are shown. Each Bizar host gets an isolated native OMP session journal, so the hub shows OMP's configured or auto-generated session title. Before OMP has generated a title, it derives a stable label from the first task; the project/id remains visible as secondary identity. Sessions are identified by their project path and Bizar session id, so several sessions in one project remain independent. The hub only reads and controls tmux sessions created by Bizar; unrelated tmux sessions are not displayed or changed.
151
+ To configure fast project picking, open `s`, select `Projects folder`, press `Enter`, enter a path such as `~/projects`, and press `s` to save. The new-session selector keeps direct absolute paths and parent navigation, while also showing the configured folder and its immediate child directories.
97
152
 
98
- Run the objective in that host, then use `Ctrl-d` or `Ctrl-c` to leave the client and return to the Bizar agents hub. Both keys are private to the Bizar tmux client, so they detach the view without sending EOF or interrupt input into OMP; the host and background work continue. The standard tmux sequence `Ctrl-b d` remains available too. Mouse scrolling is enabled by default and can be changed from Settings. If the host pane is already dead, the next `omb` detects it, respawns the host, and reconnects to the same project session. Closing the terminal window or detaching does not stop the tmux host. Bizar automatically enables `collab.autoStart=control` so the host is discoverable and steerable. Later, discover and reconnect to the live host:
153
+ ## Model roles and native assets
99
154
 
100
- ```sh
101
- omp collab list
102
- omp collab link <instance-id-or-pid> # prints a control link
103
- omp join "<control-link>"
104
- ```
155
+ Bizar registers visible `bizar_*` roles without replacing operator-owned mappings. The Orchestrator and Advisor are enabled by default; specialist definitions are available to OMP when the orchestrator delegates work. Installation also provides the `bizar-omp` orientation skill, workflow skills, native rules, prompts, tools, and the OMP-native development reference skill.
156
+
157
+ ## Security boundaries
105
158
 
106
- The joined OMP client receives the live transcript and Agent Hub roster. Press `Alt+A` or `Ctrl+S` to steer the running agents. Closing the joined client is safe; it only disconnects that guest. Use the project-specific session shown by `tmux ls` to return to the original host, or kill that session when the work should stop. `omb` is the supported way to start or reconnect; no extension callback performs a process handoff.
159
+ - Bizar is trusted in-process extension code. OMP extensions and shell commands are not an OS sandbox.
160
+ - API keys, tokens, `.env` contents, and private control links are never written to source, logs, commits, or evidence.
161
+ - Credentials, providers, explicit tool policies, model selections, and project overrides remain owned by OMP.
162
+ - Managed worker changes remain isolated and are retained for explicit parent integration. Bizar does not silently apply worker patches.
163
+ - Install only in projects and environments you trust. Review changes with `setup --dry-run` and `bizar-omp install-doctor`.
107
164
 
108
- `collab.autoStart=control` publishes a capability-bearing control link through the configured Collab relay. Treat the link like a credential and share it only with intended operators. Use `collab.autoStart=view` for monitoring without steering. The install preset hides thinking blocks and model tool activity while preserving the reasoning itself, keeping the chat readable; use OMP's display settings when you need the detailed trace. If the host process itself is killed, its live task agents cannot continue; OMP persists the session transcript for later resume, but it does not turn a terminated model process into a running background job. OMP's native `hub` tool can also launch a persistent host with `persist: true` and `pty: true`; `omp ps` then lists and controls that supervised process.
165
+ ## Compatibility
109
166
 
110
- ## Support boundary
167
+ | Component | Qualified baseline |
168
+ | --- | --- |
169
+ | OMP | 18.2.6, with 18.2.5 and 18.2.4 regression-qualified |
170
+ | Node.js | 22.x and 24.x in CI |
171
+ | Bun | 1.3.14 compatibility job |
172
+ | Package | `@polderlabs/bizar-omp@0.4.4` |
111
173
 
112
- The supported native baseline is OMP 18.2.6 (release commit `78b753124d11f8dd3ae73e2524125890ff7c977e`) and Bun >=1.3.14; OMP 18.2.5 and 18.2.4 remain separately tested compatibility versions. The extension API is trusted in-process code; OMP task isolation protects the child workspace/settings but is not an OS sandbox for extension code. See `docs/compatibility/` and `docs/security/` for the qualified matrix.
174
+ Upstream OMP changes require a new compatibility baseline and contract run. The package does not widen a version range to hide an unqualified runtime.
113
175
 
114
- ## Model roles
176
+ ## Development
115
177
 
116
- Bizar ships semantic native roles for orchestration, advisory review, coordination, research, planning, architecture, implementation, review, security, verification, and documentation. Installing the plugin registers visible, namespaced `bizar_*` roles in OMP's model menu and preserves operator-owned role mappings. To have Bizar inspect the authenticated models currently available to OMP, assign the best selectors using its bounded local scorer, validate every assignment, and report unresolved roles, run:
178
+ ```sh
179
+ npm install
180
+ make verify
181
+ ```
117
182
 
118
- ```text
119
- /bizar-models
183
+ The verification gate runs typecheck, tests, package checks, generated documentation checks, and secret scanning. A native OMP qualification run is also available when the OMP source package is installed:
184
+
185
+ ```sh
186
+ npm run verify:omp
120
187
  ```
121
188
 
122
- `/bizar model-roles` remains a compatibility alias, and `/bizar-models health` validates the configured selectors without changing settings. The assignment command uses OMP 18.2.6's native authenticated model catalog directly in the extension, normalizes irregular thinking metadata safely, chooses assignments using actual capability metadata, preserves non-Bizar roles, validates native resolution, and reports any role it could not assign. It is intentionally bounded and does not start a long planning or research turn. The plugin registers safe Bizar defaults so the roles are visible immediately; `/bizar-models` can replace those defaults with concrete available selectors.
189
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for branches, Conventional Commits, release tags, and trusted publishing. Release notes live in [`docs/releases/`](docs/releases/).
190
+
191
+ ## License
192
+
193
+ MIT. See [LICENSE](LICENSE).
194
+
195
+ <div align="center">
196
+ <a href="https://polderlabs.io/"><img src="docs/assets/sponsored-by-polderlabs.svg" alt="Sponsored by PolderLabs" width="100%" /></a>
197
+ </div>
@@ -7,7 +7,9 @@ export type AgentsHubAction = {
7
7
  session: OmbSessionInfo;
8
8
  } | {
9
9
  type: "new";
10
- selected?: OmbSessionInfo;
10
+ projectCwd: string;
11
+ task: string;
12
+ sessionId: string;
11
13
  } | {
12
14
  type: "rename";
13
15
  session: OmbSessionInfo;
@@ -1 +1 @@
1
- {"version":3,"file":"agents-ink.d.ts","sourceRoot":"","sources":["../../src/cli/agents-ink.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA0C,KAAK,cAAc,EAAwB,MAAM,wBAAwB,CAAC;AAC3H,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,cAAc,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,WAAW,CAAA;CAAE,CAAC;AA6ThD,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAOtJ"}
1
+ {"version":3,"file":"agents-ink.d.ts","sourceRoot":"","sources":["../../src/cli/agents-ink.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA0C,KAAK,cAAc,EAAwB,MAAM,wBAAwB,CAAC;AAC3H,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG1D,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC3C;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,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,WAAW,CAAA;CAAE,CAAC;AAsfhD,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAOtJ"}
@@ -1,7 +1,8 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from "react";
3
3
  import { Box, Text, useApp, useInput, useWindowSize, render } from "ink";
4
4
  import { listOmbSessions, ombSessionDisplayName } from "../omp/omb-sessions.js";
5
+ import { filterDirectoryOptions, readDirectoryOptions } from "./directory-selector.js";
5
6
  const statusLabel = (state) => state === "attached" ? "CONNECTED" : state === "detached" ? "DISCONNECTED" : "STOPPED";
6
7
  const statusColor = (state) => state === "attached" ? "green" : state === "detached" ? "yellow" : "gray";
7
8
  const statusMark = (state) => state === "attached" ? "●" : state === "detached" ? "◌" : "○";
@@ -32,7 +33,7 @@ function Header({ cwd, sessions }) {
32
33
  const connected = sessions.filter(session => session.state === "attached").length;
33
34
  const disconnected = sessions.filter(session => session.state === "detached").length;
34
35
  const stopped = sessions.filter(session => session.state === "dead").length;
35
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { bold: true, color: "cyan", children: "\u25C6 BIZAR / AGENTS HUB" }), _jsx(Text, { dimColor: true, children: short(cwd, 44) })] }), _jsxs(Box, { marginTop: 1, gap: 2, children: [_jsxs(Text, { color: "green", children: ["\u25CF ", connected, " connected"] }), _jsxs(Text, { color: "yellow", children: ["\u25CC ", disconnected, " disconnected"] }), _jsxs(Text, { color: "gray", children: ["\u25CB ", stopped, " stopped"] })] })] }));
36
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { bold: true, color: "cyan", children: "\u25C6 BIZAR / AGENTS HUB" }), _jsxs(Text, { dimColor: true, children: ["GLOBAL \u00B7 launched from ", short(cwd, 34)] })] }), _jsxs(Box, { marginTop: 1, gap: 2, children: [_jsxs(Text, { color: "green", children: ["\u25CF ", connected, " connected"] }), _jsxs(Text, { color: "yellow", children: ["\u25CC ", disconnected, " disconnected"] }), _jsxs(Text, { color: "gray", children: ["\u25CB ", stopped, " stopped"] })] })] }));
36
37
  }
37
38
  function WorkspaceRail({ sessions, selected }) {
38
39
  const projects = projectCounts(sessions);
@@ -59,36 +60,178 @@ function Inspector({ session }) {
59
60
  return (_jsxs(Box, { width: "29%", minWidth: 25, flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "SELECTED SESSION" }), !session ? _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Select a session to inspect it." }) }) : (_jsxs(Box, { marginTop: 1, flexDirection: "column", gap: 1, children: [_jsxs(Text, { bold: true, color: statusColor(session.state), children: [statusMark(session.state), " ", statusLabel(session.state)] }), _jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "NAME" }), _jsx(Text, { children: ombSessionDisplayName(session) }), _jsx(Text, { dimColor: true, children: session.nativeName ? "OMP session title" : "Generated from task or project" })] }), _jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "PROJECT" }), _jsx(Text, { children: short(session.cwd, 30) })] }), _jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "COMMAND" }), _jsx(Text, { children: short(session.command || "omp", 30) })] }), _jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "LAST ACTIVITY" }), _jsx(Text, { children: age(session) })] })] }))] }));
60
61
  }
61
62
  function Footer() {
62
- return (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, justifyContent: "space-between", children: [_jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "Enter" }), " attach ", _jsx(Text, { color: "cyan", children: "n" }), " new ", _jsx(Text, { color: "cyan", children: "e" }), " rename ", _jsx(Text, { color: "cyan", children: "d" }), " delete"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "s" }), " settings ", _jsx(Text, { color: "cyan", children: "r" }), " refresh ", _jsx(Text, { color: "cyan", children: "?" }), " help ", _jsx(Text, { color: "cyan", children: "q" }), " quit"] })] }));
63
+ return (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, justifyContent: "space-between", children: [_jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "Enter" }), " attach ", _jsx(Text, { color: "cyan", children: "n" }), " new selector ", _jsx(Text, { color: "cyan", children: "e" }), " rename ", _jsx(Text, { color: "cyan", children: "d" }), " delete"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "s" }), " settings ", _jsx(Text, { color: "cyan", children: "r" }), " refresh ", _jsx(Text, { color: "cyan", children: "?" }), " help ", _jsx(Text, { color: "cyan", children: "q" }), " quit"] })] }));
63
64
  }
64
65
  function Modal({ title, children, width, columns }) {
65
66
  return (_jsxs(Box, { position: "absolute", top: 2, left: Math.max(0, Math.floor((columns - width) / 2)), width: width, flexDirection: "column", borderStyle: "double", borderColor: "cyan", backgroundColor: "black", paddingX: 2, paddingY: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: title }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: children })] }));
66
67
  }
67
- function SettingsModal({ settings, selected, columns, onToggle, onSave, onClose }) {
68
+ function NewSessionModal({ cwd, sessions, projectsFolder, selected, columns, rows, onSubmit, onClose, }) {
69
+ const initialDirectory = selected?.cwd && selected.cwd !== "?" ? selected.cwd : cwd;
70
+ const [mode, setMode] = useState("directory");
71
+ const [directoryPath, setDirectoryPath] = useState(initialDirectory);
72
+ const [directoryQuery, setDirectoryQuery] = useState("");
73
+ const [directoryOptions, setDirectoryOptions] = useState([]);
74
+ const [directorySelected, setDirectorySelected] = useState(0);
75
+ const [projectCwd, setProjectCwd] = useState(initialDirectory);
76
+ const [task, setTask] = useState("");
77
+ const [sessionId, setSessionId] = useState("");
78
+ const [loading, setLoading] = useState(true);
79
+ const recentPaths = useMemo(() => [...new Set(sessions.map(session => session.cwd).filter(path => path && path !== "?"))], [sessions]);
80
+ const filteredDirectories = useMemo(() => filterDirectoryOptions(directoryOptions, directoryQuery), [directoryOptions, directoryQuery]);
81
+ const visibleCount = Math.max(4, Math.min(9, rows - 14));
82
+ const directoryStart = Math.max(0, Math.min(Math.max(0, filteredDirectories.length - visibleCount), directorySelected - Math.floor(visibleCount / 2)));
83
+ const visibleDirectories = filteredDirectories.slice(directoryStart, directoryStart + visibleCount);
84
+ const selectedDirectory = filteredDirectories[directorySelected];
85
+ useEffect(() => {
86
+ let active = true;
87
+ setLoading(true);
88
+ void readDirectoryOptions(directoryPath, recentPaths, directoryQuery, projectsFolder).then(options => {
89
+ if (!active)
90
+ return;
91
+ setDirectoryOptions(options);
92
+ setDirectorySelected(0);
93
+ setLoading(false);
94
+ });
95
+ return () => { active = false; };
96
+ }, [directoryPath, directoryQuery, projectsFolder, recentPaths]);
97
+ useEffect(() => {
98
+ setDirectorySelected(value => Math.min(value, Math.max(0, filteredDirectories.length - 1)));
99
+ }, [filteredDirectories.length]);
100
+ const selectDirectory = (option) => {
101
+ if (!option)
102
+ return;
103
+ if (option.kind === "parent") {
104
+ setDirectoryPath(option.path);
105
+ setDirectoryQuery("");
106
+ return;
107
+ }
108
+ setProjectCwd(option.path);
109
+ setMode("task");
110
+ };
111
+ const openDirectory = (option) => {
112
+ if (!option || option.kind === "current")
113
+ return;
114
+ setDirectoryPath(option.path);
115
+ setDirectoryQuery("");
116
+ };
117
+ const goToParent = () => {
118
+ const parent = directoryPath.replace(/[\\/]$/, "").split(/[\\/]/).slice(0, -1).join("/") || "/";
119
+ if (parent !== directoryPath) {
120
+ setDirectoryPath(parent);
121
+ setDirectoryQuery("");
122
+ }
123
+ };
124
+ useInput((input, key) => {
125
+ if (key.escape) {
126
+ if (mode === "name")
127
+ setMode("task");
128
+ else if (mode === "task")
129
+ setMode("directory");
130
+ else
131
+ onClose();
132
+ return;
133
+ }
134
+ if (mode === "directory") {
135
+ if (key.upArrow || input === "k")
136
+ setDirectorySelected(value => Math.max(0, value - 1));
137
+ else if (key.downArrow || input === "j")
138
+ setDirectorySelected(value => Math.min(Math.max(0, filteredDirectories.length - 1), value + 1));
139
+ else if (key.return)
140
+ selectDirectory(selectedDirectory);
141
+ else if (key.rightArrow || input === "l")
142
+ openDirectory(selectedDirectory);
143
+ else if (key.leftArrow || input === "h")
144
+ goToParent();
145
+ else if (key.backspace || (key.ctrl && input === "h")) {
146
+ setDirectoryQuery(value => value.slice(0, -1));
147
+ setDirectorySelected(0);
148
+ }
149
+ else if (key.ctrl && input === "u") {
150
+ setDirectoryQuery("");
151
+ setDirectorySelected(0);
152
+ }
153
+ else if (input && !key.ctrl && !key.meta && input >= " ") {
154
+ setDirectoryQuery(value => `${value}${input}`);
155
+ setDirectorySelected(0);
156
+ }
157
+ return;
158
+ }
159
+ const updateText = (setter) => {
160
+ if (key.backspace || (key.ctrl && input === "h"))
161
+ setter(value => value.slice(0, -1));
162
+ else if (key.ctrl && input === "u")
163
+ setter("");
164
+ else if (input && !key.ctrl && !key.meta && input >= " ")
165
+ setter(value => `${value}${input}`);
166
+ };
167
+ if (mode === "task") {
168
+ if (key.return)
169
+ setMode("name");
170
+ else
171
+ updateText(setTask);
172
+ }
173
+ else if (key.return) {
174
+ onSubmit({ projectCwd, task: task.trim(), sessionId: sessionId.trim() });
175
+ }
176
+ else {
177
+ updateText(setSessionId);
178
+ }
179
+ });
180
+ const width = Math.min(92, Math.max(54, columns - 6));
181
+ return (_jsx(Modal, { title: "NEW BIZAR SESSION", width: width, columns: columns, children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: mode === "directory" ? "cyan" : undefined, bold: mode === "directory", children: "1 Project directory" }), mode === "directory" ? (_jsxs(_Fragment, { children: [_jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginTop: 1, children: [_jsx(Text, { color: "cyan", children: "\u2315 " }), _jsx(Text, { children: directoryQuery || "Type to fuzzy-search directories" })] }), _jsx(Text, { dimColor: true, children: directoryPath }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: loading ? _jsx(Text, { color: "yellow", children: "Scanning directories\u2026" }) : visibleDirectories.length === 0 ? _jsx(Text, { color: "yellow", children: "No matching directories. Type an absolute path to jump." }) : visibleDirectories.map((option, offset) => {
182
+ const index = directoryStart + offset;
183
+ const isSelected = index === directorySelected;
184
+ return (_jsxs(Box, { flexDirection: "column", backgroundColor: isSelected ? "blue" : undefined, children: [_jsxs(Text, { color: isSelected ? "white" : option.kind === "recent" ? "green" : "cyan", bold: isSelected, children: [isSelected ? "›" : " ", " ", option.kind === "parent" ? "↰" : option.kind === "recent" ? "●" : option.kind === "current" ? "◆" : option.kind === "projects-root" ? "▣" : option.kind === "project" ? "◇" : "□", " ", option.label] }), isSelected && _jsxs(Text, { dimColor: true, children: [" ", option.detail ?? option.path] })] }, `${option.kind}:${option.path}`));
185
+ }) }), _jsxs(Text, { dimColor: true, children: [filteredDirectories.length ? `${directoryStart + 1}-${Math.min(directoryStart + visibleCount, filteredDirectories.length)} of ${filteredDirectories.length}` : "0 directories", " \u00B7 Enter choose \u2192 open \u2190 parent"] })] })) : (_jsxs(Text, { dimColor: true, children: [" ", projectCwd] })), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: mode === "task" ? "cyan" : undefined, bold: mode === "task", children: "2 Initial task" }), mode === "task" ? _jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, children: [_jsx(Text, { color: "cyan", children: "\u203A " }), _jsx(Text, { children: task || "Optional task description" })] }) : _jsxs(Text, { dimColor: true, children: [" ", task || "Optional"] })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: mode === "name" ? "cyan" : undefined, bold: mode === "name", children: "3 Session name" }), mode === "name" ? _jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, children: [_jsx(Text, { color: "cyan", children: "\u203A " }), _jsx(Text, { children: sessionId || "Blank generates a name" })] }) : _jsxs(Text, { dimColor: true, children: [" ", sessionId || "Generated automatically"] })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Type to search or edit \u00B7 Up/Down select \u00B7 Enter continue \u00B7 Esc back" }), _jsx(Text, { color: "yellow", children: mode === "directory" ? projectsFolder ? `Global sessions are listed below; ${projectsFolder} is indexed here.` : "Global sessions are listed below; configure a projects folder in settings for faster picking." : mode === "name" ? "Enter starts the durable OMB host." : "Enter moves to the session name." })] })] }) }));
186
+ }
187
+ function SettingsModal({ settings, selected, columns, onToggle, onMove, onSetProjectsFolder, onSave, onClose }) {
68
188
  const options = [
69
189
  ["Attach plain omb to latest live session", settings.autoAttachLatest],
70
190
  ["Enable mouse scrolling in OMB sessions", settings.mouseScrolling],
71
191
  ["Show stopped sessions in this view", settings.showStoppedSessions],
192
+ ["Projects folder", settings.projectsFolder || "not set"],
72
193
  ];
73
- return (_jsxs(Modal, { title: "OMB SETTINGS", width: Math.min(70, Math.max(46, columns - 6)), columns: columns, children: [options.map(([label, enabled], index) => (_jsxs(Text, { color: index === selected ? "white" : undefined, backgroundColor: index === selected ? "blue" : undefined, children: [index === selected ? "›" : " ", " [", enabled ? "on " : "off", "] ", label] }, label))), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Up/Down select Space/Enter toggle s save Esc cancel" }), _jsx(Text, { color: "yellow", children: selected === 1 ? "Mouse mode applies to existing OMB sessions when saved." : "" }), _jsx(Text, { children: selected >= 0 ? "" : "" }), _jsx(SettingsKeyHandler, { onToggle: onToggle, onSave: onSave, onClose: onClose })] }));
74
- }
75
- function SettingsKeyHandler({ onToggle, onSave, onClose }) {
194
+ const [editingFolder, setEditingFolder] = useState(false);
195
+ const [folderInput, setFolderInput] = useState(settings.projectsFolder);
76
196
  useInput((input, key) => {
77
- if (key.upArrow || key.downArrow)
197
+ if (editingFolder) {
198
+ if (key.escape) {
199
+ setFolderInput(settings.projectsFolder);
200
+ setEditingFolder(false);
201
+ }
202
+ else if (key.return) {
203
+ onSetProjectsFolder(folderInput.trim());
204
+ setEditingFolder(false);
205
+ }
206
+ else if (key.backspace || (key.ctrl && input === "h"))
207
+ setFolderInput(value => value.slice(0, -1));
208
+ else if (key.ctrl && input === "u")
209
+ setFolderInput("");
210
+ else if (input && !key.ctrl && !key.meta && input >= " ")
211
+ setFolderInput(value => `${value}${input}`);
78
212
  return;
79
- if (key.escape)
213
+ }
214
+ if (key.upArrow)
215
+ onMove(Math.max(0, selected - 1));
216
+ else if (key.downArrow)
217
+ onMove(Math.min(options.length - 1, selected + 1));
218
+ else if (key.escape || input === "q")
80
219
  onClose();
81
- else if (input === " " || key.return)
82
- onToggle();
83
220
  else if (input === "s")
84
221
  onSave();
222
+ else if (input === " " || key.return) {
223
+ if (selected === 3)
224
+ setEditingFolder(true);
225
+ else
226
+ onToggle();
227
+ }
85
228
  });
86
- return null;
229
+ return (_jsxs(Modal, { title: "OMB SETTINGS", width: Math.min(70, Math.max(46, columns - 6)), columns: columns, children: [options.map(([label, enabled], index) => (_jsxs(Text, { color: index === selected ? "white" : undefined, backgroundColor: index === selected ? "blue" : undefined, children: [index === selected ? "›" : " ", " ", typeof enabled === "boolean" ? `[${enabled ? "on " : "off"}]` : enabled, " ", label] }, label))), selected === 3 && (_jsxs(Box, { marginTop: 1, borderStyle: "single", borderColor: editingFolder ? "cyan" : "gray", paddingX: 1, children: [_jsx(Text, { color: "cyan", children: "\u2315 " }), _jsx(Text, { children: editingFolder ? folderInput || "Type ~/projects or an absolute path" : settings.projectsFolder || "Press Enter to set a projects folder" })] })), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: editingFolder ? "Type path Enter apply Ctrl-U clear Esc cancel" : "Up/Down select Space/Enter edit s save Esc cancel" }), _jsx(Text, { color: "yellow", children: selected === 1 ? "Mouse mode applies to existing OMB sessions when saved." : selected === 3 ? "Child directories from this folder appear in the new-session picker." : "The hub always shows every Bizar session across projects." })] }));
87
230
  }
88
231
  function HelpModal({ columns, onClose }) {
89
232
  useInput((input, key) => { if (key.escape || key.return || input === "q")
90
233
  onClose(); });
91
- 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: "cyan", children: "Enter" }), " attach to the selected session"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "n" }), " create a new session"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "e" }), " rename the selected session"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "d" }), " delete after confirmation"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "s" }), " open launcher settings"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "r" }), " refresh the session list"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "q / Esc" }), " leave this view"] }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Only tmux sessions with the bizar- prefix are managed." }), _jsx(Text, { dimColor: true, children: "Press Enter or Esc to return." })] }));
234
+ 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: "cyan", children: "Enter" }), " attach to the selected session"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "n" }), " open the fuzzy directory session selector"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "e" }), " rename the selected session"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "d" }), " delete after confirmation"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "s" }), " open launcher settings"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "r" }), " refresh the session list"] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "q / Esc" }), " leave this view"] }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Global view: every tmux session with the bizar- prefix is shown." }), _jsx(Text, { dimColor: true, children: "Press Enter or Esc to return." })] }));
92
235
  }
93
236
  function DeleteModal({ session, columns, onConfirm, onClose }) {
94
237
  useInput((input, key) => {
@@ -135,7 +278,7 @@ function AgentsApp({ cwd, env, sessions: initialSessions, settings: initialSetti
135
278
  else if (key.return && selectedSession)
136
279
  finish({ type: "attach", session: selectedSession });
137
280
  else if (input === "n")
138
- finish({ type: "new", selected: selectedSession });
281
+ setOverlay("new");
139
282
  else if (input === "e" && selectedSession)
140
283
  finish({ type: "rename", session: selectedSession });
141
284
  else if (input === "d" && selectedSession) {
@@ -152,19 +295,12 @@ function AgentsApp({ cwd, env, sessions: initialSessions, settings: initialSetti
152
295
  setOverlay("settings");
153
296
  }
154
297
  });
155
- return (_jsxs(Box, { flexDirection: "column", width: "100%", minHeight: Math.max(12, rows - 1), paddingX: 1, children: [_jsx(Header, { cwd: cwd, sessions: sessions }), _jsxs(Box, { flexGrow: 1, marginTop: 1, gap: 1, children: [_jsx(WorkspaceRail, { sessions: sessions, selected: selectedSession }), _jsx(SessionList, { sessions: sessions, selected: selected, rows: rows, width: Math.max(34, Math.floor(columns * 0.42)) }), _jsx(Inspector, { session: selectedSession })] }), _jsx(Footer, {}), overlay === "help" && _jsx(HelpModal, { columns: columns, onClose: () => setOverlay(undefined) }), overlay === "delete" && selectedSession && _jsx(DeleteModal, { session: selectedSession, columns: columns, onConfirm: () => finish({ type: "delete", session: selectedSession }), onClose: () => setOverlay(undefined) }), overlay === "settings" && (_jsx(SettingsModal, { settings: draftSettings, selected: overlaySelected, columns: columns, onToggle: () => {
298
+ return (_jsxs(Box, { flexDirection: "column", width: "100%", minHeight: Math.max(12, rows - 1), paddingX: 1, children: [_jsx(Header, { cwd: cwd, sessions: sessions }), _jsxs(Box, { flexGrow: 1, marginTop: 1, gap: 1, children: [_jsx(WorkspaceRail, { sessions: sessions, selected: selectedSession }), _jsx(SessionList, { sessions: sessions, selected: selected, rows: rows, width: Math.max(34, Math.floor(columns * 0.42)) }), _jsx(Inspector, { session: selectedSession })] }), _jsx(Footer, {}), overlay === "new" && (_jsx(NewSessionModal, { cwd: cwd, sessions: allSessions, projectsFolder: settings.projectsFolder, 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 }), onClose: () => setOverlay(undefined) }), overlay === "settings" && (_jsx(SettingsModal, { settings: draftSettings, selected: overlaySelected, onMove: setOverlaySelected, columns: columns, onToggle: () => {
299
+ if (overlaySelected === 3)
300
+ return;
156
301
  const field = overlaySelected === 0 ? "autoAttachLatest" : overlaySelected === 1 ? "mouseScrolling" : "showStoppedSessions";
157
302
  setDraftSettings(value => ({ ...value, [field]: !value[field] }));
158
- }, onSave: () => finish({ type: "settings", settings: draftSettings }), onClose: () => setOverlay(undefined) })), overlay === "settings" && _jsx(SettingsNavigation, { selected: overlaySelected, onChange: setOverlaySelected })] }));
159
- }
160
- function SettingsNavigation({ selected, onChange }) {
161
- useInput((_input, key) => {
162
- if (key.upArrow)
163
- onChange(Math.max(0, selected - 1));
164
- else if (key.downArrow)
165
- onChange(Math.min(2, selected + 1));
166
- });
167
- return null;
303
+ }, onSetProjectsFolder: value => setDraftSettings(current => ({ ...current, projectsFolder: value })), onSave: () => finish({ type: "settings", settings: draftSettings }), onClose: () => setOverlay(undefined) }))] }));
168
304
  }
169
305
  export async function runInkAgentsHub(cwd, env, sessions, settings) {
170
306
  let action = { type: "quit" };