opencode-docker-panel 0.5.0 → 0.5.1

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/CHANGELOG.md CHANGED
@@ -1,70 +1,77 @@
1
- # Changelog
2
-
3
- All notable changes to this plugin, by version and date. The version is the one in `package.json` at
4
- that commit.
5
-
6
- ## 0.5.0 - 2026-10-07
7
-
8
- - The panel can start and stop Docker Desktop: `Start Docker Desktop` is a clickable line in the
9
- sidebar, `Stop Docker Desktop` is the last entry of the container list and is available even with no
10
- containers at all
11
- - `Stop` confirms first and names the running containers it can see, because an app-level stop ends
12
- every container of every project
13
- - Engine state comes from a `docker desktop status` probe rather than from `docker ps`, which reports a
14
- stopped engine as an unavailable socket and cannot tell it apart from a missing CLI
15
- - The probe waits up to nine seconds: measured, the CLI plugin takes 3.5 to 4.5 seconds to answer when
16
- Docker is stopped, and a shorter timeout turned a provable `stopped` into an unknown state with no
17
- buttons at all
18
- - Log polling stops while the engine is down instead of spawning a doomed `docker logs` every two
19
- seconds; the window keeps its last lines and does not resume by itself
20
- - Readme trimmed to install and verification, with the behaviour, the demos and the limits moved to
21
- `docs/features.md` and `docs/features.ru.md`
22
- - Compose project names derived from a directory are normalized the way compose normalizes them, so an
23
- uppercase directory like `CarManufacturersMVC` starts as `carmanufacturersmvc` instead of being
24
- rejected as an invalid project name
25
- - A compose project name that compose would reject, or one that normalizes to nothing, no longer
26
- offers a button at all
27
- - A stopped engine is read from `docker ps` failing on a missing `dockerDesktopLinuxEngine` pipe, which
28
- takes a quarter of a second instead of the four seconds `docker desktop status` needs, so the
29
- `Start Docker Desktop` line shows up right away
30
-
31
- ## 0.4.8 - 2026-10-04
32
-
33
- - The package now ships precompiled ESM: `npm run build` transpiles the sources with the same
34
- Solid options OpenTUI's own transform uses, and `exports["./tui"]` points at `dist/tui.js`
35
- - `react` dropped: the panel never imported it, and the host rewrites `@opentui/solid` and
36
- `solid-js` to its own runtime when a package under `node_modules` ships JavaScript
37
- - Peer dependencies stay optional, so npm never writes a second Solid or OpenTUI copy next to
38
- the plugin
39
- - `check-build` verifies the built entry imports, claims `sidebar.content`, and releases it on
40
- cleanup
41
-
42
- ## 0.4.1 — 2026-10-04
43
-
44
- - `react` added to peer dependencies, so the panel loads from npm
45
-
46
- ## 0.4.0 — 2026-10-04
47
-
48
- - Sidebar draws running containers only, at most five, with the header opening the full list
49
- - `Pin` and `Unpin` per container, stored by the host and surviving a TUI restart
50
- - `Up stack` starts a compose project from the agent directory, only when the file provably declares
51
- the clicked container's project
52
- - An unstarted stack in the agent directory gets its own line under the rows
53
- - Packaged for npm: `files` allowlist, peer dependencies, repository metadata, npm install docs
54
- - Readme trimmed to what a user needs, with the working install path first
55
-
56
- ## 0.3.0 — 2026-09-30
57
-
58
- - `Start`, `Restart`, `Stop` and `Down compose project` per container, with `Down` confirming first
59
- - Log view in the same dialog, `docker logs --timestamps --tail 200`, streams merged by timestamp
60
- - Terminal recording added to the readme
61
- - CI running typecheck and parser checks on both Linux and Windows
62
-
63
- ## 0.2.0 — 2026-09-29
64
-
65
- - Loads as a CLI-only plugin, no `@opencode/plugin` import at runtime
66
- - A poll that reports no containers clears the panel instead of keeping stale rows
67
-
68
- ## 0.1.0 — 2026-09-29
69
-
70
- - First version: Docker containers in the `sidebar.content` slot, polled from `docker ps`
1
+ # Changelog
2
+
3
+ All notable changes to this plugin, by version and date. The version is the one in `package.json` at
4
+ that commit.
5
+
6
+ ## 0.5.1 - 2026-10-08
7
+
8
+ - The repository is formatted with prettier, with a config that matches the existing style: no semicolons,
9
+ a 120 column width, trailing commas everywhere
10
+ - `npm run format` writes, `npm run format:check` only reports
11
+ - Version is bumped because the formatting changes every module and the rebuilt `dist` differs from 0.5.0
12
+
13
+ ## 0.5.0 - 2026-10-07
14
+
15
+ - The panel can start and stop Docker Desktop: `Start Docker Desktop` is a clickable line in the
16
+ sidebar, `Stop Docker Desktop` is the last entry of the container list and is available even with no
17
+ containers at all
18
+ - `Stop` confirms first and names the running containers it can see, because an app-level stop ends
19
+ every container of every project
20
+ - Engine state comes from a `docker desktop status` probe rather than from `docker ps`, which reports a
21
+ stopped engine as an unavailable socket and cannot tell it apart from a missing CLI
22
+ - The probe waits up to nine seconds: measured, the CLI plugin takes 3.5 to 4.5 seconds to answer when
23
+ Docker is stopped, and a shorter timeout turned a provable `stopped` into an unknown state with no
24
+ buttons at all
25
+ - Log polling stops while the engine is down instead of spawning a doomed `docker logs` every two
26
+ seconds; the window keeps its last lines and does not resume by itself
27
+ - Readme trimmed to install and verification, with the behaviour, the demos and the limits moved to
28
+ `docs/features.md` and `docs/features.ru.md`
29
+ - Compose project names derived from a directory are normalized the way compose normalizes them, so an
30
+ uppercase directory like `CarManufacturersMVC` starts as `carmanufacturersmvc` instead of being
31
+ rejected as an invalid project name
32
+ - A compose project name that compose would reject, or one that normalizes to nothing, no longer
33
+ offers a button at all
34
+ - A stopped engine is read from `docker ps` failing on a missing `dockerDesktopLinuxEngine` pipe, which
35
+ takes a quarter of a second instead of the four seconds `docker desktop status` needs, so the
36
+ `Start Docker Desktop` line shows up right away
37
+
38
+ ## 0.4.8 - 2026-10-04
39
+
40
+ - The package now ships precompiled ESM: `npm run build` transpiles the sources with the same
41
+ Solid options OpenTUI's own transform uses, and `exports["./tui"]` points at `dist/tui.js`
42
+ - `react` dropped: the panel never imported it, and the host rewrites `@opentui/solid` and
43
+ `solid-js` to its own runtime when a package under `node_modules` ships JavaScript
44
+ - Peer dependencies stay optional, so npm never writes a second Solid or OpenTUI copy next to
45
+ the plugin
46
+ - `check-build` verifies the built entry imports, claims `sidebar.content`, and releases it on
47
+ cleanup
48
+
49
+ ## 0.4.1 — 2026-10-04
50
+
51
+ - `react` added to peer dependencies, so the panel loads from npm
52
+
53
+ ## 0.4.0 — 2026-10-04
54
+
55
+ - Sidebar draws running containers only, at most five, with the header opening the full list
56
+ - `Pin` and `Unpin` per container, stored by the host and surviving a TUI restart
57
+ - `Up stack` starts a compose project from the agent directory, only when the file provably declares
58
+ the clicked container's project
59
+ - An unstarted stack in the agent directory gets its own line under the rows
60
+ - Packaged for npm: `files` allowlist, peer dependencies, repository metadata, npm install docs
61
+ - Readme trimmed to what a user needs, with the working install path first
62
+
63
+ ## 0.3.0 — 2026-09-30
64
+
65
+ - `Start`, `Restart`, `Stop` and `Down compose project` per container, with `Down` confirming first
66
+ - Log view in the same dialog, `docker logs --timestamps --tail 200`, streams merged by timestamp
67
+ - Terminal recording added to the readme
68
+ - CI running typecheck and parser checks on both Linux and Windows
69
+
70
+ ## 0.2.0 — 2026-09-29
71
+
72
+ - Loads as a CLI-only plugin, no `@opencode/plugin` import at runtime
73
+ - A poll that reports no containers clears the panel instead of keeping stale rows
74
+
75
+ ## 0.1.0 — 2026-09-29
76
+
77
+ - First version: Docker containers in the `sidebar.content` slot, polled from `docker ps`
package/README.md CHANGED
@@ -1,87 +1,86 @@
1
- # opencode-docker-panel
2
-
3
- [![CI](https://github.com/victor-ochenin/opencodeDockerPlugin/actions/workflows/ci.yml/badge.svg)](https://github.com/victor-ochenin/opencodeDockerPlugin/actions/workflows/ci.yml)
4
- [![npm](https://img.shields.io/npm/v/opencode-docker-panel.svg)](https://www.npmjs.com/package/opencode-docker-panel)
5
-
6
- A Docker container panel for the OpenCode 2 TUI sidebar, with Docker Desktop control.
7
-
8
- ![The Docker panel in a session sidebar](docs/demo2.gif)
9
-
10
- What it does, with demos: [docs/features.md](docs/features.md). Русская версия этого файла:
11
- [README.ru.md](README.ru.md), демонстрации на русском — [docs/features.ru.md](docs/features.ru.md).
12
-
13
- ## Requirements
14
-
15
- - OpenCode 2 runtime with plugin slots (`opencode2`)
16
- - `docker` on `PATH`. Starting and stopping Docker Desktop needs its `docker desktop` CLI plugin
17
- and works on Windows only
18
-
19
- ## Install
20
-
21
- ### Option A: let an LLM do it
22
-
23
- Paste this into any agent (Claude Code, OpenCode, Cursor, and so on):
24
-
25
- ```text
26
- Install the opencode-docker-panel Docker sidebar plugin by following
27
- https://github.com/victor-ochenin/opencodeDockerPlugin#installation
28
- ```
29
-
30
- ### Option B: manual setup
31
-
32
- Add the plugin to `~/.config/opencode/cli.json`. Create the file if it does not exist and keep
33
- whatever is already in it.
34
-
35
- ```jsonc
36
- {
37
- "$schema": "https://opencode.ai/v2/cli.json",
38
- "plugins": [{ "package": "opencode-docker-panel", "options": { "intervalMs": 3000 } }]
39
- }
40
- ```
41
-
42
- Two things trip people up here, so they are worth stating plainly:
43
-
44
- - **It goes in `cli.json`, not `opencode.json`.** This is a terminal-only plugin: it draws in the
45
- sidebar, and `cli.json` is the file the terminal client reads.
46
- - **There is no login step and no provider to configure.** It talks to the local `docker` CLI and
47
- nothing else.
48
-
49
- Restart the TUI afterwards. The host installs the package on the next start; nothing to copy and
50
- nothing to build.
51
-
52
- Pin a version when you want a known state: `{ "package": "opencode-docker-panel@0.5.0" }`.
53
-
54
- ### Verification
55
-
56
- There is no CLI check for this one: the plugin draws in the terminal UI, so `opencode run` will
57
- never show it. Verify in the TUI.
58
-
59
- 1. `docker ps` returns at least one container. If it fails, the panel has nothing to draw and says
60
- so.
61
- 2. Restart the TUI and open a session.
62
- 3. The sidebar gets a `Docker` header with a container count. Running containers appear as rows, at
63
- most five of them, with a `N more, click for all` line under them when something is still hidden.
64
- 4. Click `Docker` to collapse the list, then click it again to open the full list. Pick a container
65
- to get its actions menu, and the last entry there is `Stop Docker Desktop`.
66
-
67
- Stop Docker Desktop and the sidebar gets a clickable `Start Docker Desktop` line instead of a line of text.
68
-
69
- If the header never appears, the plugin did not load: check that the entry is in `cli.json` under
70
- `plugins`, and check `~/.local/share/opencode/log/opencode.log` for a load error.
71
-
72
- ## Options
73
-
74
- | Option | Default | Notes |
75
- |---|---|---|
76
- | `intervalMs` | `3000` | Poll interval, clamped to 1000..60000 |
77
-
78
-
79
- Everything else lives in [docs/features.md](docs/features.md).
80
-
81
- ## Changelog
82
-
83
- Versions and dates are in [CHANGELOG.md](CHANGELOG.md).
84
-
85
- ## License
86
-
87
- MIT
1
+ # opencode-docker-panel
2
+
3
+ [![CI](https://github.com/victor-ochenin/opencodeDockerPlugin/actions/workflows/ci.yml/badge.svg)](https://github.com/victor-ochenin/opencodeDockerPlugin/actions/workflows/ci.yml)
4
+ [![npm](https://img.shields.io/npm/v/opencode-docker-panel.svg)](https://www.npmjs.com/package/opencode-docker-panel)
5
+
6
+ A Docker container panel for the OpenCode 2 TUI sidebar, with Docker Desktop control.
7
+
8
+ ![The Docker panel in a session sidebar](docs/demo2.gif)
9
+
10
+ What it does, with demos: [docs/features.md](docs/features.md). Русская версия этого файла:
11
+ [README.ru.md](README.ru.md), демонстрации на русском — [docs/features.ru.md](docs/features.ru.md).
12
+
13
+ ## Requirements
14
+
15
+ - OpenCode 2 runtime with plugin slots (`opencode2`)
16
+ - `docker` on `PATH`. Starting and stopping Docker Desktop needs its `docker desktop` CLI plugin
17
+ and works on Windows only
18
+
19
+ ## Install
20
+
21
+ ### Option A: let an LLM do it
22
+
23
+ Paste this into any agent (Claude Code, OpenCode, Cursor, and so on):
24
+
25
+ ```text
26
+ Install the opencode-docker-panel Docker sidebar plugin by following
27
+ https://github.com/victor-ochenin/opencodeDockerPlugin#installation
28
+ ```
29
+
30
+ ### Option B: manual setup
31
+
32
+ Add the plugin to `~/.config/opencode/cli.json`. Create the file if it does not exist and keep
33
+ whatever is already in it.
34
+
35
+ ```jsonc
36
+ {
37
+ "$schema": "https://opencode.ai/v2/cli.json",
38
+ "plugins": [{ "package": "opencode-docker-panel", "options": { "intervalMs": 3000 } }],
39
+ }
40
+ ```
41
+
42
+ Two things trip people up here, so they are worth stating plainly:
43
+
44
+ - **It goes in `cli.json`, not `opencode.json`.** This is a terminal-only plugin: it draws in the
45
+ sidebar, and `cli.json` is the file the terminal client reads.
46
+ - **There is no login step and no provider to configure.** It talks to the local `docker` CLI and
47
+ nothing else.
48
+
49
+ Restart the TUI afterwards. The host installs the package on the next start; nothing to copy and
50
+ nothing to build.
51
+
52
+ Pin a version when you want a known state: `{ "package": "opencode-docker-panel@0.5.0" }`.
53
+
54
+ ### Verification
55
+
56
+ There is no CLI check for this one: the plugin draws in the terminal UI, so `opencode run` will
57
+ never show it. Verify in the TUI.
58
+
59
+ 1. `docker ps` returns at least one container. If it fails, the panel has nothing to draw and says
60
+ so.
61
+ 2. Restart the TUI and open a session.
62
+ 3. The sidebar gets a `Docker` header with a container count. Running containers appear as rows, at
63
+ most five of them, with a `N more, click for all` line under them when something is still hidden.
64
+ 4. Click `Docker` to collapse the list, then click it again to open the full list. Pick a container
65
+ to get its actions menu, and the last entry there is `Stop Docker Desktop`.
66
+
67
+ Stop Docker Desktop and the sidebar gets a clickable `Start Docker Desktop` line instead of a line of text.
68
+
69
+ If the header never appears, the plugin did not load: check that the entry is in `cli.json` under
70
+ `plugins`, and check `~/.local/share/opencode/log/opencode.log` for a load error.
71
+
72
+ ## Options
73
+
74
+ | Option | Default | Notes |
75
+ | ------------ | ------- | ------------------------------------- |
76
+ | `intervalMs` | `3000` | Poll interval, clamped to 1000..60000 |
77
+
78
+ Everything else lives in [docs/features.md](docs/features.md).
79
+
80
+ ## Changelog
81
+
82
+ Versions and dates are in [CHANGELOG.md](CHANGELOG.md).
83
+
84
+ ## License
85
+
86
+ MIT
package/README.ru.md CHANGED
@@ -1,77 +1,76 @@
1
- # opencode-docker-panel
2
-
3
- [![CI](https://github.com/victor-ochenin/opencodeDockerPlugin/actions/workflows/ci.yml/badge.svg)](https://github.com/victor-ochenin/opencodeDockerPlugin/actions/workflows/ci.yml)
4
- [![npm](https://img.shields.io/npm/v/opencode-docker-panel.svg)](https://www.npmjs.com/package/opencode-docker-panel)
5
-
6
- Панель контейнеров Docker для бокового сайдбара OpenCode 2, с управлением Docker Desktop.
7
-
8
- ![Панель Docker в сайдбаре сессии с незапущенным compose-стеком из каталога агента](docs/demo2.gif)
9
-
10
- Что она умеет, с демонстрациями: [docs/features.ru.md](docs/features.ru.md). English version of this file:
11
- [README.md](README.md), demos in English — [docs/features.md](docs/features.md).
12
-
13
- ## Требования
14
-
15
- - Рантайм OpenCode 2 со слотами плагинов (`opencode2`)
16
- - `docker` в `PATH`. Запуск и остановка Docker Desktop требуют CLI-плагина `docker desktop` и работают только на Windows
17
-
18
- ## Установка
19
-
20
- ### Вариант A: пусть сделает LLM
21
-
22
- Вставь это в любого агента (Claude Code, OpenCode, Cursor и так далее):
23
-
24
- ```text
25
- Установи плагин панели Docker opencode-docker-panel по инструкции
26
- https://github.com/victor-ochenin/opencodeDockerPlugin#installation
27
- ```
28
-
29
- ### Вариант B: вручную
30
-
31
- Добавь плагин в `~/.config/opencode/cli.json`. Если файла нет, создай его, и всё, что в нём уже есть, сохрани.
32
-
33
- ```jsonc
34
- {
35
- "$schema": "https://opencode.ai/v2/cli.json",
36
- "plugins": [{ "package": "opencode-docker-panel", "options": { "intervalMs": 3000 } }]
37
- }
38
- ```
39
-
40
- Два места, на которых обычно спотыкаются, поэтому скажу прямо:
41
-
42
- - **Запись идёт в `cli.json`, а не в `opencode.json`.** Плагин только терминальный: он рисуется в сайдбаре, а `cli.json` читает терминальный клиент.
43
- - **Логиниться не нужно, провайдера настраивать не нужно.** Плагин говорит только с локальным `docker` и больше ни с чем.
44
-
45
- После этого перезапусти TUI: хост сам поставит пакет при следующем старте, копировать и собирать ничего не нужно.
46
-
47
- Если нужна зафиксированная версия, укажи её явно: `{ "package": "opencode-docker-panel@0.5.0" }`.
48
-
49
- ### Проверка
50
-
51
- CLI-проверки у этого плагина нет: он рисуется в терминальном интерфейсе, поэтому `opencode run` его не покажет никогда. Проверяй в TUI.
52
-
53
- 1. `docker ps` возвращает хотя бы один контейнер. Если команда падает, панели нечего рисовать, и она так и скажет.
54
- 2. Перезапусти TUI и открой сессию.
55
- 3. В сайдбаре появится заголовок `Docker` со счётчиком контейнеров. Запущенные контейнеры станут строками, не больше пяти, а под ними — строка `N more, click for all`, если что-то ещё скрыто. Если Docker остановлен, под заголовком будет кликабельная строка `Start Docker Desktop` вместо текста.
56
- 4. Кликни по `Docker`, чтобы свернуть список, и ещё раз, чтобы открыть полный. Выбери контейнер — откроется меню его действий, а последней позицией в том же списке будет `Stop Docker Desktop`.
57
-
58
- Останови Docker Desktop — вместо текста в сайдбаре появится кликабельная строка `Start Docker Desktop`.
59
-
60
- Если заголовок так и не появился, плагин не загрузился: проверь, что запись лежит в `cli.json` в секции `plugins`, и посмотри `~/.local/share/opencode/log/opencode.log` на предмет ошибки загрузки.
61
-
62
- ## Опции
63
-
64
- | Опция | По умолчанию | Примечания |
65
- |---|---|---|
66
- | `intervalMs` | `3000` | Интервал опроса, ограничивается диапазоном 1000..60000 |
67
-
68
-
69
- Всё остальное — в [docs/features.ru.md](docs/features.ru.md).
70
-
71
- ## Изменения
72
-
73
- Версии и даты в [CHANGELOG.md](CHANGELOG.md).
74
-
75
- ## Лицензия
76
-
77
- MIT
1
+ # opencode-docker-panel
2
+
3
+ [![CI](https://github.com/victor-ochenin/opencodeDockerPlugin/actions/workflows/ci.yml/badge.svg)](https://github.com/victor-ochenin/opencodeDockerPlugin/actions/workflows/ci.yml)
4
+ [![npm](https://img.shields.io/npm/v/opencode-docker-panel.svg)](https://www.npmjs.com/package/opencode-docker-panel)
5
+
6
+ Панель контейнеров Docker для бокового сайдбара OpenCode 2, с управлением Docker Desktop.
7
+
8
+ ![Панель Docker в сайдбаре сессии с незапущенным compose-стеком из каталога агента](docs/demo2.gif)
9
+
10
+ Что она умеет, с демонстрациями: [docs/features.ru.md](docs/features.ru.md). English version of this file:
11
+ [README.md](README.md), demos in English — [docs/features.md](docs/features.md).
12
+
13
+ ## Требования
14
+
15
+ - Рантайм OpenCode 2 со слотами плагинов (`opencode2`)
16
+ - `docker` в `PATH`. Запуск и остановка Docker Desktop требуют CLI-плагина `docker desktop` и работают только на Windows
17
+
18
+ ## Установка
19
+
20
+ ### Вариант A: пусть сделает LLM
21
+
22
+ Вставь это в любого агента (Claude Code, OpenCode, Cursor и так далее):
23
+
24
+ ```text
25
+ Установи плагин панели Docker opencode-docker-panel по инструкции
26
+ https://github.com/victor-ochenin/opencodeDockerPlugin#installation
27
+ ```
28
+
29
+ ### Вариант B: вручную
30
+
31
+ Добавь плагин в `~/.config/opencode/cli.json`. Если файла нет, создай его, и всё, что в нём уже есть, сохрани.
32
+
33
+ ```jsonc
34
+ {
35
+ "$schema": "https://opencode.ai/v2/cli.json",
36
+ "plugins": [{ "package": "opencode-docker-panel", "options": { "intervalMs": 3000 } }],
37
+ }
38
+ ```
39
+
40
+ Два места, на которых обычно спотыкаются, поэтому скажу прямо:
41
+
42
+ - **Запись идёт в `cli.json`, а не в `opencode.json`.** Плагин только терминальный: он рисуется в сайдбаре, а `cli.json` читает терминальный клиент.
43
+ - **Логиниться не нужно, провайдера настраивать не нужно.** Плагин говорит только с локальным `docker` и больше ни с чем.
44
+
45
+ После этого перезапусти TUI: хост сам поставит пакет при следующем старте, копировать и собирать ничего не нужно.
46
+
47
+ Если нужна зафиксированная версия, укажи её явно: `{ "package": "opencode-docker-panel@0.5.0" }`.
48
+
49
+ ### Проверка
50
+
51
+ CLI-проверки у этого плагина нет: он рисуется в терминальном интерфейсе, поэтому `opencode run` его не покажет никогда. Проверяй в TUI.
52
+
53
+ 1. `docker ps` возвращает хотя бы один контейнер. Если команда падает, панели нечего рисовать, и она так и скажет.
54
+ 2. Перезапусти TUI и открой сессию.
55
+ 3. В сайдбаре появится заголовок `Docker` со счётчиком контейнеров. Запущенные контейнеры станут строками, не больше пяти, а под ними — строка `N more, click for all`, если что-то ещё скрыто. Если Docker остановлен, под заголовком будет кликабельная строка `Start Docker Desktop` вместо текста.
56
+ 4. Кликни по `Docker`, чтобы свернуть список, и ещё раз, чтобы открыть полный. Выбери контейнер — откроется меню его действий, а последней позицией в том же списке будет `Stop Docker Desktop`.
57
+
58
+ Останови Docker Desktop — вместо текста в сайдбаре появится кликабельная строка `Start Docker Desktop`.
59
+
60
+ Если заголовок так и не появился, плагин не загрузился: проверь, что запись лежит в `cli.json` в секции `plugins`, и посмотри `~/.local/share/opencode/log/opencode.log` на предмет ошибки загрузки.
61
+
62
+ ## Опции
63
+
64
+ | Опция | По умолчанию | Примечания |
65
+ | ------------ | ------------ | ------------------------------------------------------ |
66
+ | `intervalMs` | `3000` | Интервал опроса, ограничивается диапазоном 1000..60000 |
67
+
68
+ Всё остальное — в [docs/features.ru.md](docs/features.ru.md).
69
+
70
+ ## Изменения
71
+
72
+ Версии и даты в [CHANGELOG.md](CHANGELOG.md).
73
+
74
+ ## Лицензия
75
+
76
+ MIT
package/dist/commands.js CHANGED
@@ -48,11 +48,11 @@ function firstLine(text) {
48
48
  if (!line) return "";
49
49
  return line.length > 80 ? `${line.slice(0, 77)}...` : line;
50
50
  }
51
- /**
52
- * Runs an already-built argument list.
53
- *
54
- * `up` has no container behind it, so the boundary takes the argv rather than a container the caller
55
- * would have to invent to satisfy the type.
51
+ /**
52
+ * Runs an already-built argument list.
53
+ *
54
+ * `up` has no container behind it, so the boundary takes the argv rather than a container the caller
55
+ * would have to invent to satisfy the type.
56
56
  */
57
57
  export function runDockerArgs(args) {
58
58
  return new Promise(resolve => {
package/dist/compose.js CHANGED
@@ -4,14 +4,14 @@ import { basename, dirname, join } from "node:path";
4
4
  /** compose v2's own search order, so the resolver sees the file the CLI would pick */
5
5
  const CANDIDATES = ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"];
6
6
 
7
- /**
8
- * Compose derives a project name from the directory by lowercasing it, dropping everything outside
9
- * `[a-z0-9_-]` and then dropping whatever is left before the first alphanumeric. Measured against
10
- * compose v2: `My.Stack 2` becomes `mystack2`, `A+B` becomes `ab`, `--Lead` becomes `lead`,
11
- * `Ünïcode` becomes `ncode`, and a directory named `---` fails with "project name must not be empty".
12
- *
13
- * The panel passes the name explicitly as `-p`, which replaces that derivation, so the same
14
- * normalization has to happen here or compose rejects what it would have accepted on its own.
7
+ /**
8
+ * Compose derives a project name from the directory by lowercasing it, dropping everything outside
9
+ * `[a-z0-9_-]` and then dropping whatever is left before the first alphanumeric. Measured against
10
+ * compose v2: `My.Stack 2` becomes `mystack2`, `A+B` becomes `ab`, `--Lead` becomes `lead`,
11
+ * `Ünïcode` becomes `ncode`, and a directory named `---` fails with "project name must not be empty".
12
+ *
13
+ * The panel passes the name explicitly as `-p`, which replaces that derivation, so the same
14
+ * normalization has to happen here or compose rejects what it would have accepted on its own.
15
15
  */
16
16
  export function normalizeProject(name) {
17
17
  return name.toLowerCase().replace(/[^a-z0-9_-]/g, "").replace(/^[^a-z0-9]+/, "");
@@ -25,10 +25,10 @@ function declaredProject(body) {
25
25
  return match?.[1]?.replace(/^["']|["']$/g, "") ?? "";
26
26
  }
27
27
 
28
- /**
29
- * Finds the agent directory's compose file and reports the project it declares, if any.
30
- *
31
- * Read on every call because the caller opens a menu, not the poll loop.
28
+ /**
29
+ * Finds the agent directory's compose file and reports the project it declares, if any.
30
+ *
31
+ * Read on every call because the caller opens a menu, not the poll loop.
32
32
  */
33
33
  export function findComposeFile(agentDir) {
34
34
  if (!agentDir) return null;
@@ -56,12 +56,12 @@ export function findComposeFile(agentDir) {
56
56
  return null;
57
57
  }
58
58
 
59
- /**
60
- * The compose target for a container already part of the project, or null when the agent directory's
61
- * file belongs to somebody else.
62
- *
63
- * `up` runs build and command lines from that file, so an uncertain match has to hide the button
64
- * rather than point it at the wrong stack.
59
+ /**
60
+ * The compose target for a container already part of the project, or null when the agent directory's
61
+ * file belongs to somebody else.
62
+ *
63
+ * `up` runs build and command lines from that file, so an uncertain match has to hide the button
64
+ * rather than point it at the wrong stack.
65
65
  */
66
66
  export function resolveComposeTarget(agentDir, project) {
67
67
  const target = findComposeFile(agentDir);
package/dist/panel.js CHANGED
@@ -275,12 +275,12 @@ export function DockerPanel(props) {
275
275
  });
276
276
  await polling.refreshAfterAction();
277
277
  };
278
- /**
279
- * Opens the same actions for a container the sidebar does not show, and carries the one engine
280
- * action last.
281
- *
282
- * The engine entry stays available with no containers at all, because that is exactly when Docker is
283
- * down and it is the only way to turn it back on.
278
+ /**
279
+ * Opens the same actions for a container the sidebar does not show, and carries the one engine
280
+ * action last.
281
+ *
282
+ * The engine entry stays available with no containers at all, because that is exactly when Docker is
283
+ * down and it is the only way to turn it back on.
284
284
  */
285
285
  const pickContainer = async all => {
286
286
  const action = engine.state() === "running" ? "engine-stop" : undefined;
@@ -325,11 +325,11 @@ export function DockerPanel(props) {
325
325
  await pickContainer(polling.state().containers);
326
326
  };
327
327
 
328
- /**
329
- * Both engine actions ask first, and Stop names what it is about to end.
330
- *
331
- * Start confirms too: it brings up a virtual machine and starts consuming memory, so a misclick is
332
- * not free even though nothing is running that it would interrupt.
328
+ /**
329
+ * Both engine actions ask first, and Stop names what it is about to end.
330
+ *
331
+ * Start confirms too: it brings up a virtual machine and starts consuming memory, so a misclick is
332
+ * not free even though nothing is running that it would interrupt.
333
333
  */
334
334
  const runRuntime = async action => {
335
335
  if (busy()) return;
@@ -536,8 +536,9 @@ export function DockerPanel(props) {
536
536
  return _$memo(() => !!(!stopping() && !hasRows()))() && polling.state().containers.length > 0;
537
537
  },
538
538
  get children() {
539
- var _el$30 = _$createElement("text");
540
- _$insertNode(_el$30, _$createTextNode(` click for the list`));
539
+ var _el$30 = _$createElement("text"),
540
+ _el$31 = _$createTextNode(` click for the list`);
541
+ _$insertNode(_el$30, _el$31);
541
542
  _$setProp(_el$30, "onMouseUp", event => arm(openBrowse, event));
542
543
  _$effect(_$p => _$setProp(_el$30, "fg", theme().text.muted, _$p));
543
544
  return _el$30;
@@ -548,27 +549,27 @@ export function DockerPanel(props) {
548
549
  return _$memo(() => !!engineDown())() && !busy();
549
550
  },
550
551
  get children() {
551
- var _el$32 = _$createElement("text"),
552
- _el$33 = _$createElement("b"),
553
- _el$35 = _$createElement("span");
554
- _$insertNode(_el$32, _el$33);
555
- _$insertNode(_el$32, _el$35);
556
- _$setProp(_el$32, "onMouseUp", event => arm(() => void runRuntime("engine-start"), event));
557
- _$insertNode(_el$33, _$createTextNode(`Start Docker Desktop`));
558
- _$insertNode(_el$35, _$createTextNode(` · click to start`));
552
+ var _el$33 = _$createElement("text"),
553
+ _el$34 = _$createElement("b"),
554
+ _el$36 = _$createElement("span");
555
+ _$insertNode(_el$33, _el$34);
556
+ _$insertNode(_el$33, _el$36);
557
+ _$setProp(_el$33, "onMouseUp", event => arm(() => void runRuntime("engine-start"), event));
558
+ _$insertNode(_el$34, _$createTextNode(`Start Docker Desktop`));
559
+ _$insertNode(_el$36, _$createTextNode(` · click to start`));
559
560
  _$effect(_p$ => {
560
561
  var _v$6 = theme().text.base,
561
562
  _v$7 = {
562
563
  fg: theme().text.muted
563
564
  };
564
- _v$6 !== _p$.e && (_p$.e = _$setProp(_el$32, "fg", _v$6, _p$.e));
565
- _v$7 !== _p$.t && (_p$.t = _$setProp(_el$35, "style", _v$7, _p$.t));
565
+ _v$6 !== _p$.e && (_p$.e = _$setProp(_el$33, "fg", _v$6, _p$.e));
566
+ _v$7 !== _p$.t && (_p$.t = _$setProp(_el$36, "style", _v$7, _p$.t));
566
567
  return _p$;
567
568
  }, {
568
569
  e: undefined,
569
570
  t: undefined
570
571
  });
571
- return _el$32;
572
+ return _el$33;
572
573
  }
573
574
  }), null);
574
575
  _$insert(_el$18, _$createComponent(Show, {
@@ -576,12 +577,12 @@ export function DockerPanel(props) {
576
577
  return _$memo(() => !!(!engineDown() && polling.state().containers.length === 0))() && polling.state().detail.length > 0;
577
578
  },
578
579
  get children() {
579
- var _el$37 = _$createElement("text"),
580
- _el$38 = _$createTextNode(` `);
581
- _$insertNode(_el$37, _el$38);
582
- _$insert(_el$37, () => polling.state().detail, null);
583
- _$effect(_$p => _$setProp(_el$37, "fg", theme().text.muted, _$p));
584
- return _el$37;
580
+ var _el$38 = _$createElement("text"),
581
+ _el$39 = _$createTextNode(` `);
582
+ _$insertNode(_el$38, _el$39);
583
+ _$insert(_el$38, () => polling.state().detail, null);
584
+ _$effect(_$p => _$setProp(_el$38, "fg", theme().text.muted, _$p));
585
+ return _el$38;
585
586
  }
586
587
  }), null);
587
588
  _$insert(_el$18, _$createComponent(Show, {
@@ -594,52 +595,52 @@ export function DockerPanel(props) {
594
595
  return visible();
595
596
  },
596
597
  children: container => (() => {
597
- var _el$47 = _$createElement("box"),
598
- _el$48 = _$createElement("text"),
599
- _el$50 = _$createElement("text"),
600
- _el$51 = _$createTextNode(` `),
601
- _el$52 = _$createElement("span");
602
- _$insertNode(_el$47, _el$48);
603
- _$insertNode(_el$47, _el$50);
604
- _$setProp(_el$47, "flexDirection", "row");
605
- _$setProp(_el$47, "gap", 1);
606
- _$setProp(_el$47, "onMouseUp", event => arm(() => openMenu(container()), event));
607
- _$insertNode(_el$48, _$createTextNode(`•`));
608
- _$setProp(_el$48, "flexShrink", 0);
609
- _$insertNode(_el$50, _el$51);
610
- _$insertNode(_el$50, _el$52);
611
- _$setProp(_el$50, "wrapMode", "word");
612
- _$insert(_el$50, () => container().name, _el$51);
613
- _$insert(_el$52, () => detailLabel(container(), props.pinned));
598
+ var _el$48 = _$createElement("box"),
599
+ _el$49 = _$createElement("text"),
600
+ _el$51 = _$createElement("text"),
601
+ _el$52 = _$createTextNode(` `),
602
+ _el$53 = _$createElement("span");
603
+ _$insertNode(_el$48, _el$49);
604
+ _$insertNode(_el$48, _el$51);
605
+ _$setProp(_el$48, "flexDirection", "row");
606
+ _$setProp(_el$48, "gap", 1);
607
+ _$setProp(_el$48, "onMouseUp", event => arm(() => openMenu(container()), event));
608
+ _$insertNode(_el$49, _$createTextNode(`•`));
609
+ _$setProp(_el$49, "flexShrink", 0);
610
+ _$insertNode(_el$51, _el$52);
611
+ _$insertNode(_el$51, _el$53);
612
+ _$setProp(_el$51, "wrapMode", "word");
613
+ _$insert(_el$51, () => container().name, _el$52);
614
+ _$insert(_el$53, () => detailLabel(container(), props.pinned));
614
615
  _$effect(_p$ => {
615
616
  var _v$0 = dotColor(theme(), container().state),
616
617
  _v$1 = theme().text.base,
617
618
  _v$10 = {
618
619
  fg: theme().text.muted
619
620
  };
620
- _v$0 !== _p$.e && (_p$.e = _$setProp(_el$48, "fg", _v$0, _p$.e));
621
- _v$1 !== _p$.t && (_p$.t = _$setProp(_el$50, "fg", _v$1, _p$.t));
622
- _v$10 !== _p$.a && (_p$.a = _$setProp(_el$52, "style", _v$10, _p$.a));
621
+ _v$0 !== _p$.e && (_p$.e = _$setProp(_el$49, "fg", _v$0, _p$.e));
622
+ _v$1 !== _p$.t && (_p$.t = _$setProp(_el$51, "fg", _v$1, _p$.t));
623
+ _v$10 !== _p$.a && (_p$.a = _$setProp(_el$53, "style", _v$10, _p$.a));
623
624
  return _p$;
624
625
  }, {
625
626
  e: undefined,
626
627
  t: undefined,
627
628
  a: undefined
628
629
  });
629
- return _el$47;
630
+ return _el$48;
630
631
  })()
631
632
  }), _$createComponent(Show, {
632
633
  get when() {
633
634
  return hasRows();
634
635
  },
635
636
  get children() {
636
- var _el$39 = _$createElement("text"),
637
- _el$40 = _$createTextNode(` `);
638
- _$insertNode(_el$39, _el$40);
639
- _$setProp(_el$39, "onMouseUp", event => arm(openBrowse, event));
640
- _$insert(_el$39, browseLabel, null);
641
- _$effect(_$p => _$setProp(_el$39, "fg", theme().text.muted, _$p));
642
- return _el$39;
637
+ var _el$40 = _$createElement("text"),
638
+ _el$41 = _$createTextNode(` `);
639
+ _$insertNode(_el$40, _el$41);
640
+ _$setProp(_el$40, "onMouseUp", event => arm(openBrowse, event));
641
+ _$insert(_el$40, browseLabel, null);
642
+ _$effect(_$p => _$setProp(_el$40, "fg", theme().text.muted, _$p));
643
+ return _el$40;
643
644
  }
644
645
  })];
645
646
  }
@@ -649,31 +650,31 @@ export function DockerPanel(props) {
649
650
  return _$memo(() => !!pendingStack())() && !engineDown();
650
651
  },
651
652
  get children() {
652
- var _el$41 = _$createElement("text"),
653
- _el$42 = _$createElement("b"),
654
- _el$44 = _$createElement("span"),
655
- _el$45 = _$createTextNode(` · `),
656
- _el$46 = _$createTextNode(` is not running here`);
657
- _$insertNode(_el$41, _el$42);
658
- _$insertNode(_el$41, _el$44);
659
- _$setProp(_el$41, "onMouseUp", event => arm(() => void openStack(), event));
660
- _$insertNode(_el$42, _$createTextNode(`Up stack`));
661
- _$insertNode(_el$44, _el$45);
662
- _$insertNode(_el$44, _el$46);
663
- _$insert(_el$44, () => pendingStack()?.project, _el$46);
653
+ var _el$42 = _$createElement("text"),
654
+ _el$43 = _$createElement("b"),
655
+ _el$45 = _$createElement("span"),
656
+ _el$46 = _$createTextNode(` · `),
657
+ _el$47 = _$createTextNode(` is not running here`);
658
+ _$insertNode(_el$42, _el$43);
659
+ _$insertNode(_el$42, _el$45);
660
+ _$setProp(_el$42, "onMouseUp", event => arm(() => void openStack(), event));
661
+ _$insertNode(_el$43, _$createTextNode(`Up stack`));
662
+ _$insertNode(_el$45, _el$46);
663
+ _$insertNode(_el$45, _el$47);
664
+ _$insert(_el$45, () => pendingStack()?.project, _el$47);
664
665
  _$effect(_p$ => {
665
666
  var _v$8 = theme().text.base,
666
667
  _v$9 = {
667
668
  fg: theme().text.muted
668
669
  };
669
- _v$8 !== _p$.e && (_p$.e = _$setProp(_el$41, "fg", _v$8, _p$.e));
670
- _v$9 !== _p$.t && (_p$.t = _$setProp(_el$44, "style", _v$9, _p$.t));
670
+ _v$8 !== _p$.e && (_p$.e = _$setProp(_el$42, "fg", _v$8, _p$.e));
671
+ _v$9 !== _p$.t && (_p$.t = _$setProp(_el$45, "style", _v$9, _p$.t));
671
672
  return _p$;
672
673
  }, {
673
674
  e: undefined,
674
675
  t: undefined
675
676
  });
676
- return _el$41;
677
+ return _el$42;
677
678
  }
678
679
  }), null);
679
680
  _$effect(_$p => _$setProp(_el$20, "fg", theme().text.base, _$p));
package/dist/poll.js CHANGED
@@ -10,10 +10,10 @@ const INITIAL = {
10
10
  /** docker reports the old state for a moment after start or stop, so an action is polled twice */
11
11
  const SETTLE_MS = 1200;
12
12
 
13
- /**
14
- * A Docker Desktop cold start boots a virtual machine, which takes a minute and answers `unknown` while
15
- * it goes. Polling faster than the container loop is what makes the panel notice it came up at all,
16
- * and the deadline is what stops a dead engine from holding `working` forever.
13
+ /**
14
+ * A Docker Desktop cold start boots a virtual machine, which takes a minute and answers `unknown` while
15
+ * it goes. Polling faster than the container loop is what makes the panel notice it came up at all,
16
+ * and the deadline is what stops a dead engine from holding `working` forever.
17
17
  */
18
18
  export const ENGINE_TRANSITION_MS = 2000;
19
19
  export const ENGINE_DEADLINE_MS = 120000;
@@ -27,11 +27,11 @@ export function keepContainers(previous, next) {
27
27
  /** The sidebar belongs to what runs right now, not to every container that exists */
28
28
  export const MAX_RUNNING = 5;
29
29
 
30
- /**
31
- * A pinned container is shown whatever its state and spends the running budget when it happens to
32
- * run, so pinning everything shows everything.
33
- *
34
- * Stopped containers get no row, the dialog is their only door.
30
+ /**
31
+ * A pinned container is shown whatever its state and spends the running budget when it happens to
32
+ * run, so pinning everything shows everything.
33
+ *
34
+ * Stopped containers get no row, the dialog is their only door.
35
35
  */
36
36
  export function selectRows(all, pinned) {
37
37
  const isPinned = item => pinned.includes(item.name);
@@ -39,20 +39,20 @@ export function selectRows(all, pinned) {
39
39
  const running = all.filter(item => !isPinned(item) && item.state === "running");
40
40
  return [...fixed, ...running.slice(0, Math.max(0, MAX_RUNNING - fixed.length))];
41
41
  }
42
- /**
43
- * The engine has its own probe because `docker ps` cannot report it: on a stopped engine the ps call
44
- * fails to connect and says only `unavailable`, which is also what a missing CLI or a locked socket
45
- * produces. `docker desktop status` is the only thing that tells those apart.
42
+ /**
43
+ * The engine has its own probe because `docker ps` cannot report it: on a stopped engine the ps call
44
+ * fails to connect and says only `unavailable`, which is also what a missing CLI or a locked socket
45
+ * produces. `docker desktop status` is the only thing that tells those apart.
46
46
  */
47
47
  export function createEngineProbe() {
48
48
  const [state, setState] = createSignal("unknown");
49
49
  let disposed = false;
50
50
  let probing = false;
51
51
 
52
- /**
53
- * A stopped engine takes over four seconds to answer, which is longer than the container poll, so a
54
- * probe per poll would leave several of them waiting on the same pipe at once. One at a time is the
55
- * whole guard: a call that arrives while one is in flight reads the last known state instead.
52
+ /**
53
+ * A stopped engine takes over four seconds to answer, which is longer than the container poll, so a
54
+ * probe per poll would leave several of them waiting on the same pipe at once. One at a time is the
55
+ * whole guard: a call that arrives while one is in flight reads the last known state instead.
56
56
  */
57
57
  const refresh = async () => {
58
58
  if (probing) return state();
package/package.json CHANGED
@@ -1,76 +1,79 @@
1
- {
2
- "name": "opencode-docker-panel",
3
- "version": "0.5.0",
4
- "description": "Docker container panel for the OpenCode 2 TUI sidebar",
5
- "keywords": [
6
- "opencode",
7
- "opencode-plugin",
8
- "opencode-tui",
9
- "docker",
10
- "docker-compose",
11
- "sidebar",
12
- "tui"
13
- ],
14
- "homepage": "https://github.com/victor-ochenin/opencodeDockerPlugin#readme",
15
- "bugs": {
16
- "url": "https://github.com/victor-ochenin/opencodeDockerPlugin/issues"
17
- },
18
- "repository": {
19
- "type": "git",
20
- "url": "git+https://github.com/victor-ochenin/opencodeDockerPlugin.git",
21
- "directory": "."
22
- },
23
- "type": "module",
24
- "license": "MIT",
25
- "exports": {
26
- "./tui": "./dist/tui.js"
27
- },
28
- "files": [
29
- "dist",
30
- "README.md",
31
- "CHANGELOG.md",
32
- "LICENSE"
33
- ],
34
- "scripts": {
35
- "build": "node --experimental-strip-types scripts/build.ts",
36
- "check": "node --experimental-strip-types scripts/check-parser.ts",
37
- "typecheck": "tsc --noEmit",
38
- "check-build": "node --experimental-strip-types scripts/check-build.ts"
39
- },
40
- "peerDependencies": {
41
- "@opencode/plugin": "^2.0.20",
42
- "@opencode/theme": "^2.0.20",
43
- "@opentui/core": ">=0.5.8",
44
- "@opentui/solid": ">=0.5.8",
45
- "solid-js": "^1.9.0"
46
- },
47
- "peerDependenciesMeta": {
48
- "@opencode/plugin": {
49
- "optional": true
50
- },
51
- "@opencode/theme": {
52
- "optional": true
53
- },
54
- "@opentui/core": {
55
- "optional": true
56
- },
57
- "@opentui/solid": {
58
- "optional": true
59
- },
60
- "solid-js": {
61
- "optional": true
62
- }
63
- },
64
- "devDependencies": {
65
- "@babel/core": "^7.28.0",
66
- "@babel/preset-typescript": "^7.27.1",
67
- "@opencode/plugin": "^2.0.20",
68
- "@opencode/theme": "^2.0.20",
69
- "@opentui/core": "0.5.12",
70
- "@opentui/solid": "0.5.12",
71
- "@types/babel__core": "^7.20.5",
72
- "babel-preset-solid": "^1.9.12",
73
- "solid-js": "1.9.12",
74
- "typescript": "^5.9.2"
75
- }
76
- }
1
+ {
2
+ "name": "opencode-docker-panel",
3
+ "version": "0.5.1",
4
+ "description": "Docker container panel for the OpenCode 2 TUI sidebar",
5
+ "keywords": [
6
+ "opencode",
7
+ "opencode-plugin",
8
+ "opencode-tui",
9
+ "docker",
10
+ "docker-compose",
11
+ "sidebar",
12
+ "tui"
13
+ ],
14
+ "homepage": "https://github.com/victor-ochenin/opencodeDockerPlugin#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/victor-ochenin/opencodeDockerPlugin/issues"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/victor-ochenin/opencodeDockerPlugin.git",
21
+ "directory": "."
22
+ },
23
+ "type": "module",
24
+ "license": "MIT",
25
+ "exports": {
26
+ "./tui": "./dist/tui.js"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "README.md",
31
+ "CHANGELOG.md",
32
+ "LICENSE"
33
+ ],
34
+ "scripts": {
35
+ "build": "node --experimental-strip-types scripts/build.ts",
36
+ "check": "node --experimental-strip-types scripts/check-parser.ts",
37
+ "typecheck": "tsc --noEmit",
38
+ "check-build": "node --experimental-strip-types scripts/check-build.ts",
39
+ "format": "prettier --write .",
40
+ "format:check": "prettier --check ."
41
+ },
42
+ "peerDependencies": {
43
+ "@opencode/plugin": "^2.0.20",
44
+ "@opencode/theme": "^2.0.20",
45
+ "@opentui/core": ">=0.5.8",
46
+ "@opentui/solid": ">=0.5.8",
47
+ "solid-js": "^1.9.0"
48
+ },
49
+ "peerDependenciesMeta": {
50
+ "@opencode/plugin": {
51
+ "optional": true
52
+ },
53
+ "@opencode/theme": {
54
+ "optional": true
55
+ },
56
+ "@opentui/core": {
57
+ "optional": true
58
+ },
59
+ "@opentui/solid": {
60
+ "optional": true
61
+ },
62
+ "solid-js": {
63
+ "optional": true
64
+ }
65
+ },
66
+ "devDependencies": {
67
+ "@babel/core": "^7.28.0",
68
+ "@babel/preset-typescript": "^7.27.1",
69
+ "@opencode/plugin": "^2.0.20",
70
+ "@opencode/theme": "^2.0.20",
71
+ "@opentui/core": "0.5.12",
72
+ "@opentui/solid": "0.5.12",
73
+ "@types/babel__core": "^7.20.5",
74
+ "babel-preset-solid": "^1.9.12",
75
+ "prettier": "^3.9.9",
76
+ "solid-js": "1.9.12",
77
+ "typescript": "^5.9.2"
78
+ }
79
+ }