openpalm 0.9.9 → 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.
Files changed (41) hide show
  1. package/README.md +14 -16
  2. package/e2e/start-wizard-server.ts +20 -25
  3. package/package.json +5 -4
  4. package/src/commands/install-services.test.ts +3 -19
  5. package/src/commands/install-services.ts +1 -5
  6. package/src/commands/install.ts +294 -258
  7. package/src/commands/logs.ts +4 -4
  8. package/src/commands/restart.ts +7 -9
  9. package/src/commands/rollback.ts +43 -0
  10. package/src/commands/scan.ts +8 -9
  11. package/src/commands/service.ts +8 -9
  12. package/src/commands/start.ts +7 -9
  13. package/src/commands/status.ts +4 -4
  14. package/src/commands/stop.ts +7 -9
  15. package/src/commands/uninstall.ts +7 -8
  16. package/src/commands/update.ts +9 -11
  17. package/src/commands/validate.ts +7 -8
  18. package/src/install-flow.test.ts +387 -0
  19. package/src/lib/cli-compose.ts +78 -0
  20. package/src/lib/cli-state.ts +26 -0
  21. package/src/lib/docker.ts +135 -15
  22. package/src/lib/embedded-assets.ts +115 -0
  23. package/src/lib/env.ts +35 -40
  24. package/src/lib/opencode-subprocess.ts +113 -0
  25. package/src/lib/paths.ts +3 -9
  26. package/src/lib/varlock.ts +8 -14
  27. package/src/main.test.ts +280 -126
  28. package/src/main.ts +2 -2
  29. package/src/setup-wizard/index.html +51 -13
  30. package/src/setup-wizard/server-errors.test.ts +114 -118
  31. package/src/setup-wizard/server-integration.test.ts +130 -124
  32. package/src/setup-wizard/server.test.ts +283 -120
  33. package/src/setup-wizard/server.ts +63 -38
  34. package/src/setup-wizard/wizard-renderers.js +1294 -0
  35. package/src/setup-wizard/wizard-state.js +343 -0
  36. package/src/setup-wizard/wizard-validators.js +81 -0
  37. package/src/setup-wizard/wizard.css +72 -6
  38. package/src/setup-wizard/wizard.js +491 -1607
  39. package/src/commands/install-file.test.ts +0 -306
  40. package/src/lib/staging.ts +0 -72
  41. 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 XDG dirs, downloads assets, serves the setup wizard locally via `Bun.serve()`, stages artifacts, starts core services
10
- - **All lifecycle commands** -- stage artifacts from `@openpalm/lib` using `FilesystemAssetProvider`, then run Docker Compose directly
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 include the admin UI profile.
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 XDG dirs, download assets, run setup wizard, start core services |
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 `secrets.env` against the schema (requires prior install) |
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 profile
36
+ ### Admin addon
37
37
 
38
- Admin and docker-socket-proxy use Docker Compose profiles. They start only when explicitly requested:
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 stage artifacts. No admin container is involved.
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
- | `OPENPALM_CONFIG_HOME` | `~/.config/openpalm` | User config + secrets |
55
- | `OPENPALM_DATA_HOME` | `~/.local/share/openpalm` | Persistent service data |
56
- | `OPENPALM_STATE_HOME` | `~/.local/state/openpalm` | Assembled runtime |
57
- | `OPENPALM_WORK_DIR` | `~/openpalm` | Assistant working directory |
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 XDG directory tree, downloads core assets from GitHub, seeds `secrets.env` and `stack.env`, serves setup wizard, stages artifacts via `@openpalm/lib`, starts core services via `docker compose up`
64
- 2. **Running stack** -- commands stage artifacts locally using `FilesystemAssetProvider`, then execute Docker Compose directly.
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}/state/artifacts`, { recursive: true });
24
-
25
- writeFileSync(`${tmpBase}/config/secrets.env`, "# test\n");
26
- writeFileSync(`${tmpBase}/state/artifacts/stack.env`, "OPENPALM_SETUP_COMPLETE=false\n");
27
-
28
- // No-op asset provider — mocked tests intercept API calls before they
29
- // reach performSetup(), so these methods are never invoked.
30
- const noopAssetProvider: CoreAssetProvider = {
31
- coreCompose: () => "",
32
- caddyfile: () => "",
33
- ollamaCompose: () => "",
34
- agentsMd: () => "",
35
- opencodeConfig: () => "",
36
- adminOpencodeConfig: () => "",
37
- secretsSchema: () => "",
38
- stackSchema: () => "",
39
- cleanupLogs: () => "",
40
- cleanupData: () => "",
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.OPENPALM_CONFIG_HOME = `${tmpBase}/config`;
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.9.9",
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/setup-wizard/standalone.ts",
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",
@@ -26,7 +26,8 @@
26
26
  "build:windows-arm64": "bun build src/main.ts --compile --target=bun-windows-arm64 --outfile dist/openpalm-cli-windows-arm64.exe"
27
27
  },
28
28
  "dependencies": {
29
- "@openpalm/lib": "0.9.6",
30
- "citty": "^0.2.1"
29
+ "@openpalm/lib": ">=0.9.8 <1.0.0",
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, buildInstallServiceNames } from './install-services.ts';
2
+ import { buildDeployStatusEntries } from './install-services.ts';
3
3
 
4
4
  describe('install service helpers', () => {
5
- it('passes managed services through unchanged', () => {
6
- expect(buildInstallServiceNames(['memory', 'assistant'])).toEqual([
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[],