openpalm 0.9.6 → 0.9.8

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.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env bun
2
+ import { runMain } from 'citty';
3
+ import { mainCommand } from '../src/main.ts';
4
+
5
+ runMain(mainCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openpalm",
3
- "version": "0.9.6",
3
+ "version": "0.9.8",
4
4
  "type": "module",
5
5
  "license": "MPL-2.0",
6
6
  "description": "OpenPalm CLI — install and manage a self-hosted OpenPalm stack",
@@ -10,7 +10,7 @@
10
10
  "directory": "packages/cli"
11
11
  },
12
12
  "bin": {
13
- "openpalm": "./src/main.ts"
13
+ "openpalm": "./bin/openpalm.js"
14
14
  },
15
15
  "scripts": {
16
16
  "start": "bun run src/main.ts",
@@ -24,7 +24,7 @@
24
24
  "build:windows-arm64": "bun build src/main.ts --compile --target=bun-windows-arm64 --outfile dist/openpalm-cli-windows-arm64.exe"
25
25
  },
26
26
  "dependencies": {
27
- "@openpalm/lib": "workspace:*",
27
+ "@openpalm/lib": "0.9.6",
28
28
  "citty": "^0.2.1"
29
29
  }
30
30
  }
@@ -0,0 +1,24 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import { buildDeployStatusEntries, buildInstallServiceNames } from './install-services.ts';
3
+
4
+ describe('install service helpers', () => {
5
+ it('appends admin services to managed services', () => {
6
+ expect(buildInstallServiceNames(['caddy', 'memory'])).toEqual([
7
+ 'caddy',
8
+ 'memory',
9
+ 'admin',
10
+ 'docker-socket-proxy',
11
+ ]);
12
+ });
13
+
14
+ it('builds deploy status entries for the full install service list', () => {
15
+ const services = buildInstallServiceNames(['caddy', 'memory']);
16
+
17
+ expect(buildDeployStatusEntries(services, 'pending', 'Waiting...')).toEqual([
18
+ { service: 'caddy', status: 'pending', label: 'Waiting...' },
19
+ { service: 'memory', status: 'pending', label: 'Waiting...' },
20
+ { service: 'admin', status: 'pending', label: 'Waiting...' },
21
+ { service: 'docker-socket-proxy', status: 'pending', label: 'Waiting...' },
22
+ ]);
23
+ });
24
+ });
@@ -0,0 +1,13 @@
1
+ export type DeployStatusState = 'pending' | 'pulling';
2
+
3
+ export function buildInstallServiceNames(managedServices: string[]): string[] {
4
+ return [...managedServices, 'admin', 'docker-socket-proxy'];
5
+ }
6
+
7
+ export function buildDeployStatusEntries(
8
+ services: string[],
9
+ status: DeployStatusState,
10
+ label: string,
11
+ ): Array<{ service: string; status: DeployStatusState; label: string }> {
12
+ return services.map(service => ({ service, status, label }));
13
+ }
@@ -12,6 +12,7 @@ import { detectHostInfo } from '../lib/host-info.ts';
12
12
  import { loadAdminToken } from '../lib/env.ts';
13
13
  import { ensureStagedState, fullComposeArgs, buildManagedServiceNames } from '../lib/staging.ts';
14
14
  import { createSetupServer } from '../setup-wizard/server.ts';
15
+ import { buildInstallServiceNames, buildDeployStatusEntries } from './install-services.ts';
15
16
 
16
17
  const DEFAULT_INSTALL_REF = cliPkg.version ? `v${cliPkg.version}` : 'main';
17
18
  const SETUP_WIZARD_PORT = 8100;
@@ -220,22 +221,15 @@ export async function bootstrapInstall(options: InstallOptions): Promise<void> {
220
221
  const state = await ensureStagedState();
221
222
  const composeArgs = fullComposeArgs(state);
222
223
  const managedServices = buildManagedServiceNames(state);
224
+ const allServices = buildInstallServiceNames(managedServices);
223
225
 
224
- wizard.updateDeployStatus(
225
- allServices.map(s => ({ service: s, status: 'pending', label: 'Waiting...' })),
226
- );
227
-
228
- // Include admin profile so admin + docker-socket-proxy start by default
229
- const adminServices = ['admin', 'docker-socket-proxy'];
230
- const allServices = [...managedServices, ...adminServices];
226
+ wizard.updateDeployStatus(buildDeployStatusEntries(allServices, 'pending', 'Waiting...'));
231
227
 
232
228
  await runDockerCompose([...composeArgs, '--profile', 'admin', 'pull', ...allServices]).catch(() => {
233
229
  // Pull failure is non-fatal — images may already be cached
234
230
  });
235
231
 
236
- wizard.updateDeployStatus(
237
- allServices.map(s => ({ service: s, status: 'pulling', label: 'Starting...' })),
238
- );
232
+ wizard.updateDeployStatus(buildDeployStatusEntries(allServices, 'pulling', 'Starting...'));
239
233
 
240
234
  await runDockerCompose([...composeArgs, '--profile', 'admin', 'up', '-d', ...allServices]);
241
235
 
@@ -268,7 +262,7 @@ export async function bootstrapInstall(options: InstallOptions): Promise<void> {
268
262
  const state = await ensureStagedState();
269
263
  const composeArgs = fullComposeArgs(state);
270
264
  const managedServices = buildManagedServiceNames(state);
271
- const allServices = [...managedServices, 'admin', 'docker-socket-proxy'];
265
+ const allServices = buildInstallServiceNames(managedServices);
272
266
 
273
267
  await runDockerCompose([...composeArgs, '--profile', 'admin', 'up', '-d', ...allServices]);
274
268
 
package/src/main.test.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { afterEach, describe, expect, it, mock } from 'bun:test';
2
- import { existsSync, mkdirSync, writeFileSync, chmodSync, mkdtempSync, rmSync } from 'node:fs';
2
+ import { existsSync, mkdirSync, writeFileSync, chmodSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
3
3
  import { tmpdir } from 'node:os';
4
4
  import { join } from 'node:path';
5
5
  import { detectHostInfo, main, reconcileStackEnvImageTag, resolveRequestedImageTag, upsertEnvValue } from './main.ts';
@@ -237,6 +237,22 @@ describe('cli main', () => {
237
237
  });
238
238
  });
239
239
 
240
+ describe('npm bin launcher', () => {
241
+ it('points the published bin to a Bun launcher script instead of a TypeScript source file', () => {
242
+ const cliPkg = JSON.parse(
243
+ readFileSync(new URL('../package.json', import.meta.url), 'utf8'),
244
+ ) as {
245
+ bin?: Record<string, string>;
246
+ };
247
+
248
+ expect(cliPkg.bin?.openpalm).toBe('./bin/openpalm.js');
249
+
250
+ const launcher = readFileSync(new URL('../bin/openpalm.js', import.meta.url), 'utf8');
251
+
252
+ expect(launcher.startsWith('#!/usr/bin/env bun\n')).toBe(true);
253
+ });
254
+ });
255
+
240
256
  describe('validate command', () => {
241
257
  it('is a recognized command (does not throw Unknown command)', async () => {
242
258
  const tempStateHome = mkdtempSync(join(tmpdir(), 'openpalm-test-'));
package/src/main.ts CHANGED
@@ -8,7 +8,7 @@ export type { HostInfo } from './lib/host-info.ts';
8
8
  export { upsertEnvValue, resolveRequestedImageTag, reconcileStackEnvImageTag } from './lib/env.ts';
9
9
  export { bootstrapInstall } from './commands/install.ts';
10
10
 
11
- const mainCommand = defineCommand({
11
+ export const mainCommand = defineCommand({
12
12
  meta: {
13
13
  name: 'openpalm',
14
14
  version: cliPkg.version,