openpalm 0.9.10 → 0.10.0-rc9
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 +14 -16
- package/e2e/start-wizard-server.ts +20 -25
- package/package.json +4 -3
- package/src/commands/install-services.test.ts +3 -19
- package/src/commands/install-services.ts +1 -5
- package/src/commands/install.ts +287 -276
- package/src/commands/logs.ts +4 -4
- package/src/commands/restart.ts +7 -9
- package/src/commands/rollback.ts +43 -0
- package/src/commands/scan.ts +8 -9
- package/src/commands/service.ts +8 -9
- package/src/commands/start.ts +7 -9
- package/src/commands/status.ts +4 -4
- package/src/commands/stop.ts +7 -9
- package/src/commands/uninstall.ts +7 -8
- package/src/commands/update.ts +9 -11
- package/src/commands/validate.ts +7 -8
- package/src/install-flow.test.ts +387 -0
- package/src/lib/cli-compose.ts +78 -0
- package/src/lib/cli-state.ts +26 -0
- package/src/lib/docker.ts +135 -15
- package/src/lib/embedded-assets.ts +115 -0
- package/src/lib/env.ts +30 -41
- package/src/lib/opencode-subprocess.ts +113 -0
- package/src/lib/paths.ts +3 -9
- package/src/lib/varlock.ts +8 -14
- package/src/main.test.ts +228 -144
- package/src/main.ts +2 -2
- package/src/setup-wizard/index.html +51 -13
- package/src/setup-wizard/server-errors.test.ts +114 -118
- package/src/setup-wizard/server-integration.test.ts +130 -124
- package/src/setup-wizard/server.test.ts +283 -120
- package/src/setup-wizard/server.ts +63 -38
- package/src/setup-wizard/wizard-renderers.js +1294 -0
- package/src/setup-wizard/wizard-state.js +343 -0
- package/src/setup-wizard/wizard-validators.js +81 -0
- package/src/setup-wizard/wizard.css +72 -6
- package/src/setup-wizard/wizard.js +491 -1607
- package/src/commands/install-file.test.ts +0 -306
- package/src/lib/staging.ts +0 -72
- package/src/setup-wizard/standalone.ts +0 -166
package/README.md
CHANGED
|
@@ -6,17 +6,17 @@ Bun CLI for bootstrapping and managing an OpenPalm installation. The CLI is the
|
|
|
6
6
|
|
|
7
7
|
The CLI operates directly against Docker Compose without requiring an admin container:
|
|
8
8
|
|
|
9
|
-
- **Install** -- creates
|
|
10
|
-
- **All lifecycle commands** --
|
|
9
|
+
- **Install** -- creates the `~/.openpalm/` home layout, downloads assets, serves the setup wizard locally via `Bun.serve()`, writes files to their final locations, and starts core services
|
|
10
|
+
- **All lifecycle commands** -- refresh files in `~/.openpalm/` when needed, then run Docker Compose directly
|
|
11
11
|
- **Admin delegation** -- the `install` command checks for a running admin and delegates if reachable. Other commands operate directly via Docker Compose.
|
|
12
12
|
|
|
13
|
-
The admin container is optional. Use `--with-admin` to
|
|
13
|
+
The admin container is optional. Use `--with-admin` to enable the admin addon overlay in the compose file set.
|
|
14
14
|
|
|
15
15
|
## Commands
|
|
16
16
|
|
|
17
17
|
| Command | Description |
|
|
18
18
|
|---|---|
|
|
19
|
-
| `openpalm install` | Bootstrap
|
|
19
|
+
| `openpalm install` | Bootstrap `~/.openpalm/`, download assets, run setup wizard, start core services |
|
|
20
20
|
| `openpalm uninstall` | Stop and remove the stack (preserves config and data) |
|
|
21
21
|
| `openpalm update` | Pull latest images and recreate containers |
|
|
22
22
|
| `openpalm start [svc...]` | Start all or named services |
|
|
@@ -26,16 +26,16 @@ The admin container is optional. Use `--with-admin` to include the admin UI prof
|
|
|
26
26
|
| `openpalm logs [svc...]` | Tail last 100 log lines |
|
|
27
27
|
| `openpalm status` | Show container status |
|
|
28
28
|
| `openpalm service <sub> [svc...]` | Alias -- subcommands: `start`, `stop`, `restart`, `logs`, `status`, `update` |
|
|
29
|
-
| `openpalm validate` | Validate
|
|
29
|
+
| `openpalm validate` | Validate vault env files against their schemas (requires prior install) |
|
|
30
30
|
| `openpalm scan` | Scan for leaked secrets in config files |
|
|
31
31
|
|
|
32
32
|
### Install options
|
|
33
33
|
|
|
34
34
|
`--force` skip "already installed" check, `--version TAG` install a specific ref (default: current CLI version), `--no-start` prepare files only, `--no-open` skip browser launch.
|
|
35
35
|
|
|
36
|
-
### Admin
|
|
36
|
+
### Admin addon
|
|
37
37
|
|
|
38
|
-
Admin and docker-socket-proxy
|
|
38
|
+
Admin and docker-socket-proxy start only when explicitly requested:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
41
|
openpalm start --with-admin # Start core + admin profile
|
|
@@ -45,23 +45,21 @@ openpalm stop admin # Stop admin service specifically
|
|
|
45
45
|
|
|
46
46
|
## Setup Wizard
|
|
47
47
|
|
|
48
|
-
On first install, the CLI serves a setup wizard on port 8100 via `Bun.serve()`. The wizard runs entirely in the browser (vanilla HTML/JS) and calls `performSetup()` from `@openpalm/lib` to write secrets, connection profiles, memory config, and
|
|
48
|
+
On first install, the CLI serves a setup wizard on port `8100` via `Bun.serve()`. That temporary setup port is separate from the admin container, which defaults to `http://localhost:3880` once installed. The wizard runs entirely in the browser (vanilla HTML/JS) and calls `performSetup()` from `@openpalm/lib` to write secrets, connection profiles, memory config, and other files to their final locations. No admin container is involved.
|
|
49
49
|
|
|
50
50
|
## Environment Variables
|
|
51
51
|
|
|
52
52
|
| Variable | Default | Purpose |
|
|
53
53
|
|---|---|---|
|
|
54
|
-
| `
|
|
55
|
-
| `
|
|
56
|
-
| `
|
|
57
|
-
| `
|
|
58
|
-
| `OPENPALM_ADMIN_API_URL` | `http://localhost:8100` | Admin API endpoint (for optional delegation) |
|
|
59
|
-
| `OPENPALM_ADMIN_TOKEN` | (from `secrets.env`) | Admin API auth token |
|
|
54
|
+
| `OP_HOME` | `~/.openpalm` | Root of all OpenPalm state |
|
|
55
|
+
| `OP_WORK_DIR` | `~/openpalm` | Assistant working directory |
|
|
56
|
+
| `OP_ADMIN_API_URL` | `http://localhost:3880` | Admin API endpoint (for optional delegation) |
|
|
57
|
+
| `OP_ADMIN_TOKEN` | (from `vault/stack/stack.env`) | Admin API auth token |
|
|
60
58
|
|
|
61
59
|
## How It Works
|
|
62
60
|
|
|
63
|
-
1. **Bootstrap** (first install) -- creates
|
|
64
|
-
2. **Running stack** -- commands
|
|
61
|
+
1. **Bootstrap** (first install) -- creates the `~/.openpalm/` tree, downloads core assets from GitHub, seeds `vault/user/user.env` and `vault/stack/stack.env`, materializes the runtime registry catalog under `registry/`, serves the setup wizard, writes `stack/core.compose.yml`, enables requested addons under `stack/addons/`, and starts core services via `docker compose up`
|
|
62
|
+
2. **Running stack** -- commands refresh files in `~/.openpalm/` when needed, then execute Docker Compose directly.
|
|
65
63
|
3. **Admin absent** -- all commands work identically. Admin is never required for any operation.
|
|
66
64
|
|
|
67
65
|
Follows the file-assembly principle: copies whole files, never renders templates. See [`core-principles.md`](../../docs/technical/core-principles.md).
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { createSetupServer } from "../src/setup-wizard/server.ts";
|
|
12
12
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
13
|
-
import type { CoreAssetProvider } from "@openpalm/lib";
|
|
14
13
|
|
|
15
14
|
const port = parseInt(Bun.argv[2] || "18100", 10);
|
|
16
15
|
const tmpBase = `/tmp/openpalm-wizard-test-${port}`;
|
|
@@ -19,36 +18,32 @@ const tmpBase = `/tmp/openpalm-wizard-test-${port}`;
|
|
|
19
18
|
// API endpoints that need real files are mocked at the browser level
|
|
20
19
|
// by Playwright's page.route(), so these dirs just prevent crashes.
|
|
21
20
|
mkdirSync(`${tmpBase}/config`, { recursive: true });
|
|
21
|
+
mkdirSync(`${tmpBase}/config/automations`, { recursive: true });
|
|
22
22
|
mkdirSync(`${tmpBase}/data`, { recursive: true });
|
|
23
|
-
mkdirSync(`${tmpBase}/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
validateConfig: () => "",
|
|
42
|
-
};
|
|
23
|
+
mkdirSync(`${tmpBase}/data/assistant`, { recursive: true });
|
|
24
|
+
mkdirSync(`${tmpBase}/registry/automations`, { recursive: true });
|
|
25
|
+
mkdirSync(`${tmpBase}/stack`, { recursive: true });
|
|
26
|
+
mkdirSync(`${tmpBase}/vault/stack`, { recursive: true });
|
|
27
|
+
mkdirSync(`${tmpBase}/vault/user`, { recursive: true });
|
|
28
|
+
|
|
29
|
+
writeFileSync(`${tmpBase}/vault/stack/stack.env`, "OP_SETUP_COMPLETE=false\n");
|
|
30
|
+
writeFileSync(`${tmpBase}/vault/user/user.env`, "# test\n");
|
|
31
|
+
|
|
32
|
+
// Seed minimal asset files so performSetup() can read them if invoked
|
|
33
|
+
writeFileSync(`${tmpBase}/stack/core.compose.yml`, "services:\n admin:\n image: admin:latest\n");
|
|
34
|
+
writeFileSync(`${tmpBase}/data/assistant/opencode.jsonc`, '{"$schema":"https://opencode.ai/config.json"}\n');
|
|
35
|
+
writeFileSync(`${tmpBase}/data/assistant/AGENTS.md`, "# Agents\n");
|
|
36
|
+
writeFileSync(`${tmpBase}/vault/user/user.env.schema`, "OP_ADMIN_TOKEN=string\n");
|
|
37
|
+
writeFileSync(`${tmpBase}/vault/stack/stack.env.schema`, "OP_IMAGE_TAG=string\n");
|
|
38
|
+
writeFileSync(`${tmpBase}/registry/automations/cleanup-logs.yml`, "name: cleanup-logs\nschedule: daily\n");
|
|
39
|
+
writeFileSync(`${tmpBase}/registry/automations/cleanup-data.yml`, "name: cleanup-data\nschedule: weekly\n");
|
|
40
|
+
writeFileSync(`${tmpBase}/registry/automations/validate-config.yml`, "name: validate-config\nschedule: hourly\n");
|
|
43
41
|
|
|
44
42
|
// Override state/config home so the server doesn't touch real dirs.
|
|
45
|
-
process.env.
|
|
46
|
-
process.env.OPENPALM_STATE_HOME = `${tmpBase}/state`;
|
|
47
|
-
process.env.OPENPALM_DATA_HOME = `${tmpBase}/data`;
|
|
43
|
+
process.env.OP_HOME = tmpBase;
|
|
48
44
|
|
|
49
45
|
const { server } = createSetupServer(port, {
|
|
50
46
|
configDir: `${tmpBase}/config`,
|
|
51
|
-
assetProvider: noopAssetProvider,
|
|
52
47
|
});
|
|
53
48
|
|
|
54
49
|
console.log(`WIZARD_READY:${port}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openpalm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0-rc9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"description": "OpenPalm CLI — install and manage a self-hosted OpenPalm stack",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"start": "bun run src/main.ts",
|
|
17
17
|
"test": "bun test",
|
|
18
18
|
"test:e2e": "npx playwright test",
|
|
19
|
-
"wizard:dev": "bun run src/
|
|
19
|
+
"wizard:dev": "bun run src/main.ts install --no-start --force",
|
|
20
20
|
"build": "bun build src/main.ts --compile --outfile dist/openpalm-cli",
|
|
21
21
|
"build:linux-x64": "bun build src/main.ts --compile --target=bun-linux-x64 --outfile dist/openpalm-cli-linux-x64",
|
|
22
22
|
"build:linux-arm64": "bun build src/main.ts --compile --target=bun-linux-arm64 --outfile dist/openpalm-cli-linux-arm64",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@openpalm/lib": ">=0.9.8 <1.0.0",
|
|
30
|
-
"citty": "^0.2.1"
|
|
30
|
+
"citty": "^0.2.1",
|
|
31
|
+
"yaml": "^2.8.0"
|
|
31
32
|
}
|
|
32
33
|
}
|
|
@@ -1,25 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it } from 'bun:test';
|
|
2
|
-
import { buildDeployStatusEntries
|
|
2
|
+
import { buildDeployStatusEntries } from './install-services.ts';
|
|
3
3
|
|
|
4
4
|
describe('install service helpers', () => {
|
|
5
|
-
it('
|
|
6
|
-
|
|
7
|
-
'memory',
|
|
8
|
-
'assistant',
|
|
9
|
-
]);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('includes admin services when they are in managed list', () => {
|
|
13
|
-
expect(buildInstallServiceNames(['memory', 'caddy', 'admin', 'docker-socket-proxy'])).toEqual([
|
|
14
|
-
'memory',
|
|
15
|
-
'caddy',
|
|
16
|
-
'admin',
|
|
17
|
-
'docker-socket-proxy',
|
|
18
|
-
]);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('builds deploy status entries for the full install service list', () => {
|
|
22
|
-
const services = buildInstallServiceNames(['memory', 'assistant']);
|
|
5
|
+
it('builds deploy status entries for the install service list', () => {
|
|
6
|
+
const services = ['memory', 'assistant'];
|
|
23
7
|
|
|
24
8
|
expect(buildDeployStatusEntries(services, 'pending', 'Waiting...')).toEqual([
|
|
25
9
|
{ service: 'memory', status: 'pending', label: 'Waiting...' },
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
export type DeployStatusState = 'pending' | 'pulling';
|
|
2
|
-
|
|
3
|
-
export function buildInstallServiceNames(managedServices: string[]): string[] {
|
|
4
|
-
return [...managedServices];
|
|
5
|
-
}
|
|
1
|
+
export type DeployStatusState = 'pending' | 'pulling' | 'error';
|
|
6
2
|
|
|
7
3
|
export function buildDeployStatusEntries(
|
|
8
4
|
services: string[],
|