@p10i/create-nestbox 0.4.0 → 0.6.0
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/.dockerignore +18 -18
- package/.env.example +0 -4
- package/CHANGELOG.md +16 -0
- package/INSTALL.md +32 -24
- package/README.md +22 -4
- package/bin/create-nestbox.js +4 -85
- package/docker/control/Dockerfile +2 -2
- package/docker/control/server.py +4 -383
- package/docker/nginx/Dockerfile +11 -11
- package/docker/opencode/Dockerfile +6 -2
- package/docker/php-fpm/Dockerfile +22 -22
- package/docker-compose.yaml +1 -29
- package/home/code/__includes/footer.php +2 -2
- package/home/code/__includes/header.php +5 -5
- package/home/configs/nginx/nginx.conf +17 -34
- package/home/configs/opencode/control-mcp.js +1 -21
- package/home/configs/opencode/instructions.md +11 -12
- package/home/configs/opencode/opencode.json +1 -1
- package/home/configs/php/composer.json +8 -8
- package/home/configs/php/init.php +2 -2
- package/home/configs/php/preload.php +4 -4
- package/package.json +2 -6
- package/scripts/check-package.js +0 -7
- package/tests/control.mjs +56 -23
- package/tests/creator.mjs +14 -19
- package/tests/nestbox.ps1 +6 -11
- package/tests/nestbox.sh +8 -9
- package/host-runner.mjs +0 -292
- package/package.host.json +0 -8
- package/tests/host-runner.mjs +0 -143
package/.dockerignore
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
# Build context hygiene — keep image builds small and reproducible.
|
|
2
|
-
|
|
3
|
-
# VCS / IDE
|
|
1
|
+
# Build context hygiene — keep image builds small and reproducible.
|
|
2
|
+
|
|
3
|
+
# VCS / IDE
|
|
4
4
|
.git
|
|
5
5
|
**/.git
|
|
6
|
-
.gitignore
|
|
7
|
-
.vscode
|
|
8
|
-
.idea
|
|
9
|
-
|
|
10
|
-
# Local environment
|
|
6
|
+
.gitignore
|
|
7
|
+
.vscode
|
|
8
|
+
.idea
|
|
9
|
+
|
|
10
|
+
# Local environment
|
|
11
11
|
.env
|
|
12
12
|
.env.*
|
|
13
13
|
!.env.example
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
# npm / Composer caches that may live in the working tree
|
|
16
16
|
node_modules
|
|
17
17
|
vendor
|
|
@@ -22,15 +22,15 @@ vendor
|
|
|
22
22
|
# Page state is local by default and must not leak into image layers. A page
|
|
23
23
|
# that deliberately ships durable data must explicitly revise this policy.
|
|
24
24
|
home/code/**/__data/**
|
|
25
|
-
|
|
26
|
-
# OS junk
|
|
27
|
-
.DS_Store
|
|
28
|
-
Thumbs.db
|
|
29
|
-
|
|
30
|
-
# Bundles are produced inside the build, not pulled from the host.
|
|
31
|
-
home/code/scripts-bundle.js
|
|
32
|
-
home/code/scripts-bundle.css
|
|
33
|
-
|
|
25
|
+
|
|
26
|
+
# OS junk
|
|
27
|
+
.DS_Store
|
|
28
|
+
Thumbs.db
|
|
29
|
+
|
|
30
|
+
# Bundles are produced inside the build, not pulled from the host.
|
|
31
|
+
home/code/scripts-bundle.js
|
|
32
|
+
home/code/scripts-bundle.css
|
|
33
|
+
|
|
34
34
|
# Docs and metadata not needed at build time
|
|
35
35
|
README.md
|
|
36
36
|
LICENSE
|
package/.env.example
CHANGED
|
@@ -8,10 +8,6 @@ COMPOSE_PROJECT_NAME=nestbox-change-me
|
|
|
8
8
|
# directory, or .. when this installation is <workspace>/.nestbox.
|
|
9
9
|
WORKSPACE_PATH=.
|
|
10
10
|
|
|
11
|
-
# The native runner uses the shared WEB_PORT gateway. The creator generates a
|
|
12
|
-
# private token file outside the workspace and mounts it only into control.
|
|
13
|
-
NESTBOX_HOST_TOKEN_FILE=
|
|
14
|
-
|
|
15
11
|
# Override for rootless or nonstandard Docker Engine installations.
|
|
16
12
|
DOCKER_SOCKET_PATH=/var/run/docker.sock
|
|
17
13
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
- Consistently track latest-stable runtime images, dynamically select Alpine's newest PHP CLI branch, and document fresh builds with `--pull --no-cache`.
|
|
6
|
+
- Remove native host npm execution, npm script confirmation tools, the host runner, its stdio bridge, and the loopback job API. Keep label-gated container execution and structured control logs.
|
|
7
|
+
- Stop creating or modifying workspace package manifests during installation. Remove package.json-specific bind mounts and the control service's workspace mount.
|
|
8
|
+
- Run the installed runtime entirely in Docker; host Node.js is needed only when using the npm creator.
|
|
9
|
+
- Load OpenCode instructions and instance policy by absolute `/etc/opencode` paths, incorporating Gitea fix `4d53e89`.
|
|
10
|
+
- See `INSTALL.md` for existing-installation cleanup and activation steps.
|
|
11
|
+
|
|
12
|
+
## 0.5.0
|
|
13
|
+
|
|
14
|
+
- Replace the public token-authenticated host API with a persistent `docker compose exec -T control` stdio bridge.
|
|
15
|
+
- Bind the bridge API to container loopback and add reconnect-safe runner sessions with idempotent result replay.
|
|
16
|
+
- Remove host tokens, the Nginx host proxy, and all `4089` exposure while retaining one Nginx-published host port.
|
|
17
|
+
- Existing `0.3.x` and `0.4.x` installations may remove `NESTBOX_HOST_TOKEN_FILE` and its referenced token file after upgrading.
|
|
18
|
+
|
|
3
19
|
## 0.4.0
|
|
4
20
|
|
|
5
21
|
- Route the authenticated host runner through `/_nestbox/host/` on the existing Nginx gateway.
|
package/INSTALL.md
CHANGED
|
@@ -12,15 +12,14 @@ npm create @p10i/nestbox@latest
|
|
|
12
12
|
|
|
13
13
|
The published npm package is `@p10i/create-nestbox`; npm maps `npm create @p10i/nestbox` to that package. The creator explains and previews one of the two default layouts before writing files. The recommended layout installs at `<workspace>/.nestbox` so Nestbox stays separate from project files. The direct layout writes Nestbox files into an empty selected directory. The creator copies `.env.example` to `.env`, copies `home/configs/opencode/instance.example.md` to `instance.md`, records npm package provenance in the instance policy, and initializes fresh installation Git history when Git is available.
|
|
14
14
|
|
|
15
|
-
The creator does not start Docker
|
|
15
|
+
The creator does not start Docker or collect secrets. Node.js and npm are needed only to run the creator, not the installed runtime. After it finishes, edit `.env`, then run from the installation directory:
|
|
16
16
|
|
|
17
17
|
```sh
|
|
18
18
|
docker compose config --quiet
|
|
19
|
-
docker compose
|
|
19
|
+
docker compose build --pull --no-cache
|
|
20
|
+
docker compose up -d
|
|
20
21
|
```
|
|
21
22
|
|
|
22
|
-
After `control` is healthy, run `npm run host --` from the workspace in a separate terminal.
|
|
23
|
-
|
|
24
23
|
Then run the host test suite documented in section 7.
|
|
25
24
|
|
|
26
25
|
## 1. Choose Language
|
|
@@ -56,7 +55,7 @@ docker version
|
|
|
56
55
|
docker compose version
|
|
57
56
|
```
|
|
58
57
|
|
|
59
|
-
Nestbox requires Git,
|
|
58
|
+
Nestbox requires Git, a running Docker Engine, and Docker Compose v2. The npm creator additionally requires Node.js with npm; installation from Git does not. If something is missing, explain the platform-specific requirement and pause. Do not install system software without approval.
|
|
60
59
|
|
|
61
60
|
Inspect Git status for the selected directory and installation target before changing files. Preserve unrelated changes. The fresh Nestbox repository remains independent in both default layouts, including when `.nestbox` is nested inside another Git workspace.
|
|
62
61
|
|
|
@@ -96,14 +95,7 @@ Copy `.env.example` to `.env` and `home/configs/opencode/instance.example.md` to
|
|
|
96
95
|
|
|
97
96
|
Relative bind paths resolve from the installation directory. The page tree is mounted as `/home/code` in runtime services and as the writable `/nestbox/home/code` agent path. `WORKSPACE_PATH` is mounted as `/workspace` in PHP and OpenCode. `NESTBOX_PAGE_PATH` remains an optional advanced override for a user-requested external page tree.
|
|
98
97
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
- For `.nestbox` layout, create `package.json` from `.nestbox/package.host.json` when absent, or merge only its `host` and `test:host` scripts into the existing manifest.
|
|
102
|
-
- For direct layout, use `node host-runner.mjs` and `node tests/host-runner.mjs` for those scripts. A source clone's publisher-oriented `package.json` may be replaced by this installation manifest after preserving any intentional project metadata.
|
|
103
|
-
- Never overwrite a conflicting script. Stop and ask for a different script name.
|
|
104
|
-
- Set `NESTBOX_HOST_TOKEN_FILE` to a private file outside every container-mounted workspace. The npm creator writes a 64-character token there with owner-only permissions. Only `control` mounts the file; never paste the token into chat or expose it through a page.
|
|
105
|
-
- Start `npm run host --` after `control` is healthy. The runner authenticates through `/_nestbox/host/` on the existing `WEB_PORT`, long-polls for work, sends heartbeats, and posts results without opening a host listener, publishing a second port, or sharing queue files.
|
|
106
|
-
- The workspace manifest is mounted read-only in runtime containers. Confirmed changes are written only by the native host runner.
|
|
98
|
+
The runtime does not require a workspace `package.json`. Project manifests are accessed through the ordinary workspace mounts in PHP-FPM and OpenCode. The control service mounts only the Docker socket and provides label-gated container execution.
|
|
107
99
|
|
|
108
100
|
Update the new `home/configs/opencode/instance.md` with:
|
|
109
101
|
|
|
@@ -126,7 +118,7 @@ Then ask about:
|
|
|
126
118
|
- Linux UID and GID when bind-mount ownership matters;
|
|
127
119
|
- additional directories required by PHP and OpenCode;
|
|
128
120
|
- an optional reverse-proxy URL prefix;
|
|
129
|
-
-
|
|
121
|
+
- the default latest-stable image policy, with pinning only as an explicitly requested adaptation;
|
|
130
122
|
- `NESTBOX_OPENCODE_PUBLIC_URL` when `agent.<nestbox-host>` cannot be derived.
|
|
131
123
|
|
|
132
124
|
Open `.env` in a local editor for runtime settings and secrets. Never ask the user to paste provider keys into chat or print the completed file.
|
|
@@ -135,7 +127,9 @@ Before startup, query existing Docker containers with the proposed Compose proje
|
|
|
135
127
|
|
|
136
128
|
For additional directories, mount the same host path at the same container path in PHP and OpenCode. Extend OpenCode's `external_directory` permission when unattended access is intended. Prefer read-only mounts unless writing is required.
|
|
137
129
|
|
|
138
|
-
|
|
130
|
+
Nestbox defaults to rolling latest-stable image tags and the latest system packages available in their configured repositories. OpenCode selects the newest PHP branch available from Alpine; PHP-FPM follows the official rolling PHP image. Verify both runtime versions after each build because Alpine packaging can lag upstream PHP. Resolve any incompatible branch mismatch before handoff. Use `docker compose build --pull --no-cache` to refresh base images and cached package-install layers. Application library lockfiles remain authoritative and are updated separately.
|
|
131
|
+
|
|
132
|
+
For a path-prefixed reverse proxy, the outer proxy removes the prefix before forwarding and configures `NESTBOX_URL_PREFIX`. Set `NESTBOX_OPENCODE_PUBLIC_URL` explicitly whenever the public OpenCode scheme or host differs from direct Nestbox access.
|
|
139
133
|
|
|
140
134
|
## 6. Keep The Public Page Tree Empty
|
|
141
135
|
|
|
@@ -149,17 +143,12 @@ Run from the installation directory:
|
|
|
149
143
|
|
|
150
144
|
```sh
|
|
151
145
|
docker compose config --quiet
|
|
152
|
-
docker compose
|
|
146
|
+
docker compose build --pull --no-cache
|
|
147
|
+
docker compose up -d
|
|
153
148
|
docker compose ps
|
|
154
149
|
docker compose port nginx 80
|
|
155
150
|
```
|
|
156
151
|
|
|
157
|
-
In a separate terminal, keep the bridge running from the workspace root:
|
|
158
|
-
|
|
159
|
-
```sh
|
|
160
|
-
npm run host --
|
|
161
|
-
```
|
|
162
|
-
|
|
163
152
|
Verify:
|
|
164
153
|
|
|
165
154
|
- `/` retains HTTP 404 and renders the OpenCode implementation form;
|
|
@@ -167,7 +156,7 @@ Verify:
|
|
|
167
156
|
- `php /sources/php/cli.php __templates/super-document` is rejected;
|
|
168
157
|
- `/Agent` redirects to OpenCode on the same published port;
|
|
169
158
|
- the actual OpenCode URL works in the user's client;
|
|
170
|
-
- `
|
|
159
|
+
- `control` is healthy and its API is not published on the host;
|
|
171
160
|
- a provider and model are available for agent work, without printing credentials or sending a billable prompt unless the user approves it;
|
|
172
161
|
- `/_nestbox/health` returns HTTP 200;
|
|
173
162
|
- a transient PHP event reaches an EventSource subscriber through Nchan;
|
|
@@ -245,7 +234,7 @@ Send this work to the internal OpenCode agent. A useful prompt is:
|
|
|
245
234
|
Extend this Nestbox installation for the following requirement: <request>. Inspect /workspace and /nestbox, follow the internal Nestbox manual, implement and verify all file changes you can, and report the exact host-side activation command for any container or infrastructure change.
|
|
246
235
|
```
|
|
247
236
|
|
|
248
|
-
The internal agent edits pages and infrastructure definitions. It has no Docker socket. It
|
|
237
|
+
The internal agent edits pages and infrastructure definitions. It has no Docker socket. It uses the label-gated control MCP for approved container commands; host-side activation remains an external-maintainer task.
|
|
249
238
|
|
|
250
239
|
## 10. Git And Generated State
|
|
251
240
|
|
|
@@ -274,3 +263,22 @@ When a super-document intentionally changes files in `/workspace`, follow that w
|
|
|
274
263
|
## 11. Optional Adaptations
|
|
275
264
|
|
|
276
265
|
Retaining upstream Git history, adding an upstream remote, external page trees, parent-owned engines, submodules, vendoring, shared repositories, alternate Compose layouts, and operating-system shortcuts are optional. Explain their ownership consequences and obtain explicit confirmation before creating them. They must not obscure the two default installation paths.
|
|
266
|
+
|
|
267
|
+
## Upgrading From Host-Runner Versions
|
|
268
|
+
|
|
269
|
+
Host npm execution and npm script confirmation tools have been removed. Container execution through `docker_exec` and `nestbox_control_exec()` remains available.
|
|
270
|
+
|
|
271
|
+
1. Stop the old `npm run host --` terminal or any service configured to launch it.
|
|
272
|
+
2. Apply the source update while preserving installation-specific Compose overrides, `.env`, pages, and `instance.md`. Remove obsolete `host-runner.mjs`, `package.host.json`, `docker/control/host_bridge.py`, and `tests/host-runner.mjs` if the update mechanism leaves deleted files behind.
|
|
273
|
+
3. Remove only the Nestbox-generated `host` and `test:host` scripts from the workspace `package.json`, after checking that they still point to the removed runner and test. Preserve project scripts and metadata. If the manifest was generated solely for the runner, it may be removed after confirming nothing else uses it.
|
|
274
|
+
4. Remove `nestbox.npm.allow`, package.json-specific read-only mounts, and the control service's workspace mount from any local overrides. Keep the ordinary workspace mounts in PHP-FPM and OpenCode. Older installations may also remove obsolete host-token settings and mounts described in the changelog.
|
|
275
|
+
5. From the installation directory, validate and activate the affected services:
|
|
276
|
+
|
|
277
|
+
```sh
|
|
278
|
+
docker compose config --quiet
|
|
279
|
+
docker compose build --pull --no-cache control opencode
|
|
280
|
+
docker compose up -d control php-fpm opencode
|
|
281
|
+
bash tests/nestbox.sh
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
On Windows, run `.\tests\nestbox.ps1` instead of the Bash test. Reconnect to OpenCode after recreation so it loads the updated MCP tools and instructions. Inspect `docker compose ps` and `docker compose logs control` to confirm health. Project workloads formerly executed on the host must use an appropriate project container or be run manually by the host maintainer.
|
package/README.md
CHANGED
|
@@ -8,13 +8,29 @@ Its core design is the **super-document**: one cohesive PHP and Markdown documen
|
|
|
8
8
|
|
|
9
9
|
Nestbox runs with Docker Compose using Nginx, PHP-FPM, Rollup, OpenCode, and a private control service. A fresh installation opens with a prompt for creating its first screen instead of shipping a predefined application.
|
|
10
10
|
|
|
11
|
-
## Container
|
|
11
|
+
## Container Control
|
|
12
12
|
|
|
13
13
|
The `control` service is the only container with `/var/run/docker.sock`. Its internal-only API permits exec only when caller, target, project, and root-user labels allow it. OpenCode reaches the API through the bundled control MCP and can target PHP-FPM and Rollup by default. Trusted PHP pages can use `nestbox_control_exec()` and are restricted to PHP-FPM self-exec.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Project commands run inside the appropriate container through `docker_exec`. Host-side Docker Compose activation is performed by the user or external maintainer. Nestbox needs no background process on the host and no workspace `package.json`.
|
|
16
16
|
|
|
17
|
-
Control emits bounded structured events to ordinary container logs. Use `docker compose logs control`; no telemetry collector, database, or observability dependency is installed. Docker socket access is root-equivalent on the host,
|
|
17
|
+
Control emits bounded structured events to ordinary container logs. Use `docker compose logs control`; no telemetry collector, database, or observability dependency is installed. Docker socket access is root-equivalent on the host, so this is a controlled capability, not a sandbox.
|
|
18
|
+
|
|
19
|
+
## Runtime Versions And Updates
|
|
20
|
+
|
|
21
|
+
Nestbox tracks the latest stable container images by default: OpenCode and Composer use `latest`, Alpine uses `latest`, and Node, Python, and PHP use their rolling Alpine variants. Alpine-installed tools use the newest packages available in the base image's configured repositories; OpenCode's PHP CLI selects the newest available PHP branch. These repositories can lag upstream releases, so verify the resulting PHP CLI and FPM versions after a refresh.
|
|
22
|
+
|
|
23
|
+
Refresh images and installed system packages from the installation directory:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
docker compose config --quiet
|
|
27
|
+
docker compose build --pull --no-cache
|
|
28
|
+
docker compose up -d
|
|
29
|
+
docker compose exec -T php-fpm php --version
|
|
30
|
+
docker compose exec -T opencode php --version
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Reconnect to OpenCode after recreation, then run `bash tests/nestbox.sh` or `.\tests\nestbox.ps1`. Existing containers do not update automatically. JavaScript and PHP library dependencies continue to use their committed lockfiles; runtime refreshes do not rewrite those dependencies.
|
|
18
34
|
|
|
19
35
|
## Learn More
|
|
20
36
|
|
|
@@ -32,7 +48,9 @@ Create a new Nestbox project with npm:
|
|
|
32
48
|
npm create @p10i/nestbox@latest
|
|
33
49
|
```
|
|
34
50
|
|
|
35
|
-
The creator previews the exact paths before it writes files. The recommended layout installs Nestbox at `<workspace>/.nestbox` so Nestbox stays separate from your project files. You can also choose a direct install into an empty directory.
|
|
51
|
+
The creator previews the exact paths before it writes files. The recommended layout installs Nestbox at `<workspace>/.nestbox` so Nestbox stays separate from your project files. You can also choose a direct install into an empty directory. The workspace's package manifest is left untouched. After creation, edit `.env`, then run the Docker Compose validation and startup commands printed by the creator. Node.js and npm are needed only to use the creator; the installed runtime runs entirely in Docker.
|
|
52
|
+
|
|
53
|
+
For upgrades from versions with host npm execution, see the migration notes in [INSTALL.md](INSTALL.md#upgrading-from-host-runner-versions).
|
|
36
54
|
|
|
37
55
|
For agent-guided installation or repair work, copy and send this to an agent with filesystem, Git, Docker, and terminal access:
|
|
38
56
|
|
package/bin/create-nestbox.js
CHANGED
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
|
-
import { randomBytes, randomUUID } from 'node:crypto';
|
|
4
|
-
import { homedir } from 'node:os';
|
|
5
3
|
import { createInterface } from 'node:readline/promises';
|
|
6
4
|
import { stdin as input, stdout as output } from 'node:process';
|
|
7
|
-
import { dirname,
|
|
5
|
+
import { dirname, join, resolve } from 'node:path';
|
|
8
6
|
import { fileURLToPath } from 'node:url';
|
|
9
|
-
import { cp, mkdir, readdir, readFile,
|
|
7
|
+
import { cp, mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';
|
|
10
8
|
import { constants } from 'node:fs';
|
|
11
9
|
|
|
12
10
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
13
11
|
const packageJson = JSON.parse(await readFile(join(packageRoot, 'package.json'), 'utf8'));
|
|
14
12
|
|
|
15
|
-
function containsPath(root, target) {
|
|
16
|
-
const child = relative(resolve(root), resolve(target));
|
|
17
|
-
return child === '' || (!child.startsWith(`..${sep}`) && child !== '..' && !isAbsolute(child));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
13
|
const copyEntries = [
|
|
21
14
|
'docker',
|
|
22
15
|
'home',
|
|
23
16
|
'tests',
|
|
24
|
-
'host-runner.mjs',
|
|
25
|
-
'package.host.json',
|
|
26
17
|
'docker-compose.yaml',
|
|
27
18
|
'.dockerignore',
|
|
28
19
|
'.env.example',
|
|
@@ -178,73 +169,6 @@ async function configureInstance(installDir, workspaceDir, layout) {
|
|
|
178
169
|
await writeFile(instancePath, instance, 'utf8');
|
|
179
170
|
}
|
|
180
171
|
|
|
181
|
-
function hostScripts(layout) {
|
|
182
|
-
const prefix = layout === 'nestbox' ? '.nestbox/' : '';
|
|
183
|
-
return {
|
|
184
|
-
host: `node ${prefix}host-runner.mjs`,
|
|
185
|
-
'test:host': `node ${prefix}tests/host-runner.mjs`
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
async function readWorkspacePackage(workspaceDir) {
|
|
190
|
-
const path = join(workspaceDir, 'package.json');
|
|
191
|
-
if (!(await pathExists(path))) return null;
|
|
192
|
-
let document;
|
|
193
|
-
try {
|
|
194
|
-
document = JSON.parse(await readFile(path, 'utf8'));
|
|
195
|
-
} catch (error) {
|
|
196
|
-
throw new Error(`Cannot use workspace package.json: ${error.message}`);
|
|
197
|
-
}
|
|
198
|
-
if (!document || typeof document !== 'object' || Array.isArray(document)) {
|
|
199
|
-
throw new Error('Workspace package.json must contain a JSON object.');
|
|
200
|
-
}
|
|
201
|
-
if (document.scripts !== undefined && (!document.scripts || typeof document.scripts !== 'object' || Array.isArray(document.scripts))) {
|
|
202
|
-
throw new Error('Workspace package.json scripts must be an object.');
|
|
203
|
-
}
|
|
204
|
-
return document;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
async function preflightHostPackage(workspaceDir, layout) {
|
|
208
|
-
const document = await readWorkspacePackage(workspaceDir);
|
|
209
|
-
if (!document) return;
|
|
210
|
-
for (const [name, command] of Object.entries(hostScripts(layout))) {
|
|
211
|
-
if (document.scripts?.[name] !== undefined && document.scripts[name] !== command) {
|
|
212
|
-
throw new Error(`Refusing to overwrite existing workspace npm script: ${name}`);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
async function configureHostPackage(installDir, workspaceDir, layout) {
|
|
218
|
-
const scripts = hostScripts(layout);
|
|
219
|
-
const document = await readWorkspacePackage(workspaceDir) || {
|
|
220
|
-
name: 'nestbox-workspace',
|
|
221
|
-
private: true
|
|
222
|
-
};
|
|
223
|
-
document.scripts = { ...(document.scripts || {}), ...scripts };
|
|
224
|
-
await writeFile(join(workspaceDir, 'package.json'), `${JSON.stringify(document, null, 2)}\n`, 'utf8');
|
|
225
|
-
await writeFile(join(installDir, 'package.host.json'), `${JSON.stringify({
|
|
226
|
-
name: 'nestbox-workspace',
|
|
227
|
-
private: true,
|
|
228
|
-
scripts
|
|
229
|
-
}, null, 2)}\n`, 'utf8');
|
|
230
|
-
const envPath = join(installDir, '.env');
|
|
231
|
-
const token = randomBytes(32).toString('hex');
|
|
232
|
-
const stateBase = process.env.NESTBOX_CREATOR_STATE_ROOT
|
|
233
|
-
|| process.env.LOCALAPPDATA
|
|
234
|
-
|| process.env.XDG_STATE_HOME
|
|
235
|
-
|| (process.platform === 'darwin' ? join(homedir(), 'Library', 'Application Support') : join(homedir(), '.local', 'state'));
|
|
236
|
-
const tokenDirectory = join(stateBase, 'nestbox', 'host-control');
|
|
237
|
-
await mkdir(tokenDirectory, { recursive: true });
|
|
238
|
-
const tokenPath = join(await realpath(tokenDirectory), `${randomUUID()}.token`);
|
|
239
|
-
const canonicalWorkspace = await realpath(workspaceDir);
|
|
240
|
-
const canonicalInstall = await realpath(installDir);
|
|
241
|
-
if (containsPath(canonicalWorkspace, tokenPath) || containsPath(canonicalInstall, tokenPath)) throw new Error('Host token state directory must be outside the workspace and Nestbox installation.');
|
|
242
|
-
await writeFile(tokenPath, `${token}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
243
|
-
const composeTokenPath = tokenPath.replaceAll('\\', '/');
|
|
244
|
-
const configuredEnv = (await readFile(envPath, 'utf8')).replace(/^NESTBOX_HOST_TOKEN_FILE=.*\r?$/m, () => `NESTBOX_HOST_TOKEN_FILE=${composeTokenPath}`);
|
|
245
|
-
await writeFile(envPath, configuredEnv, 'utf8');
|
|
246
|
-
}
|
|
247
|
-
|
|
248
172
|
function commandExists(command) {
|
|
249
173
|
const result = spawnSync(command, ['--version'], { stdio: 'ignore' });
|
|
250
174
|
return result.status === 0;
|
|
@@ -281,12 +205,9 @@ async function main() {
|
|
|
281
205
|
throw new Error(`Refusing to overwrite non-empty installation target: ${installDir}`);
|
|
282
206
|
}
|
|
283
207
|
|
|
284
|
-
await preflightHostPackage(workspaceDir, layoutInput);
|
|
285
|
-
|
|
286
208
|
await mkdir(installDir, { recursive: true });
|
|
287
209
|
await copyTemplate(installDir);
|
|
288
210
|
await configureInstance(installDir, workspaceDir, layoutInput);
|
|
289
|
-
await configureHostPackage(installDir, workspaceDir, layoutInput);
|
|
290
211
|
const gitInitialized = options.git ? initGit(installDir) : false;
|
|
291
212
|
|
|
292
213
|
console.log('\nNestbox project created.');
|
|
@@ -297,10 +218,8 @@ async function main() {
|
|
|
297
218
|
console.log(` cd ${installDir}`);
|
|
298
219
|
console.log(' Edit .env and set COMPOSE_PROJECT_NAME, WEB_PORT, OpenCode credentials, and provider keys.');
|
|
299
220
|
console.log(' docker compose config --quiet');
|
|
300
|
-
console.log(' docker compose
|
|
301
|
-
console.log(
|
|
302
|
-
console.log(' npm run host --');
|
|
303
|
-
console.log(` cd ${installDir}`);
|
|
221
|
+
console.log(' docker compose build --pull --no-cache');
|
|
222
|
+
console.log(' docker compose up -d');
|
|
304
223
|
console.log(process.platform === 'win32' ? ' .\\tests\\nestbox.ps1' : ' bash tests/nestbox.sh');
|
|
305
224
|
} finally {
|
|
306
225
|
rl.close();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
FROM python:
|
|
1
|
+
FROM python:alpine
|
|
2
2
|
|
|
3
3
|
COPY ./docker/control/server.py /usr/local/bin/nestbox-control
|
|
4
4
|
|
|
5
5
|
RUN python -m py_compile /usr/local/bin/nestbox-control && \
|
|
6
6
|
chmod 0755 /usr/local/bin/nestbox-control
|
|
7
7
|
|
|
8
|
-
WORKDIR /
|
|
8
|
+
WORKDIR /
|
|
9
9
|
|
|
10
10
|
EXPOSE 4088
|
|
11
11
|
|