@openpalm/lib 0.9.6 → 0.9.7

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.
@@ -16,7 +16,7 @@ import type { ControlPlaneState, CallerType } from "./types.js";
16
16
  import { CORE_SERVICES } from "./types.js";
17
17
  import { resolveConfigHome, resolveStateHome, resolveDataHome } from "./paths.js";
18
18
  import { loadSecretsEnvFile } from "./secrets.js";
19
- import { stageArtifacts, persistArtifacts, discoverStagedChannelYmls, randomHex, isOllamaEnabled } from "./staging.js";
19
+ import { stageArtifacts, persistArtifacts, discoverStagedChannelYmls, randomHex, isOllamaEnabled, isAdminEnabled } from "./staging.js";
20
20
  import { refreshCoreAssets, ensureMemoryDir, ensureCoreAutomations } from "./core-assets.js";
21
21
  import { ensureMemoryConfig } from "./memory-config.js";
22
22
  import { isSetupComplete } from "./setup-status.js";
@@ -222,6 +222,11 @@ export async function applyUpgrade(
222
222
  export function buildComposeFileList(state: ControlPlaneState): string[] {
223
223
  const files = [`${state.stateDir}/artifacts/docker-compose.yml`];
224
224
 
225
+ if (isAdminEnabled(state)) {
226
+ const adminYml = `${state.stateDir}/artifacts/admin.yml`;
227
+ files.push(adminYml);
228
+ }
229
+
225
230
  if (isOllamaEnabled(state)) {
226
231
  const ollamaYml = `${state.stateDir}/artifacts/ollama.yml`;
227
232
  files.push(ollamaYml);
@@ -235,11 +240,15 @@ export function buildComposeFileList(state: ControlPlaneState): string[] {
235
240
 
236
241
  /**
237
242
  * Build the list of services that `docker compose up` should manage.
238
- * Core services only admin/docker-socket-proxy are in the "admin" profile.
243
+ * Core services always; admin/caddy/docker-socket-proxy only when admin is enabled.
239
244
  */
240
245
  export function buildManagedServices(state: ControlPlaneState): string[] {
241
246
  const services: string[] = [...CORE_SERVICES];
242
247
 
248
+ if (isAdminEnabled(state)) {
249
+ services.push("caddy", "admin", "docker-socket-proxy");
250
+ }
251
+
243
252
  if (isOllamaEnabled(state)) {
244
253
  services.push("ollama");
245
254
  }
@@ -17,7 +17,25 @@ export type LocalProviderDetection = {
17
17
 
18
18
  // ── Probe Configuration ──────────────────────────────────────────────────
19
19
 
20
- const LOCAL_PROVIDER_PROBES: { provider: string; probes: { url: string; baseUrl: string }[] }[] = [
20
+ type ProviderProbe = {
21
+ url: string;
22
+ baseUrl: string;
23
+ /** Optional response validator — when present, the probe only succeeds if this returns true. */
24
+ validate?: (res: Response) => Promise<boolean>;
25
+ };
26
+
27
+ /** Ollama's root endpoint returns "Ollama is running" — use this to distinguish from other services on :11434. */
28
+ async function validateOllamaResponse(res: Response): Promise<boolean> {
29
+ try {
30
+ const body = await res.json();
31
+ // Ollama /api/tags returns { models: [...] } — verify shape
32
+ return body != null && Array.isArray(body.models);
33
+ } catch {
34
+ return false;
35
+ }
36
+ }
37
+
38
+ const LOCAL_PROVIDER_PROBES: { provider: string; probes: ProviderProbe[] }[] = [
21
39
  {
22
40
  provider: "model-runner",
23
41
  probes: [
@@ -46,14 +64,17 @@ const LOCAL_PROVIDER_PROBES: { provider: string; probes: { url: string; baseUrl:
46
64
  // In-stack Ollama (compose service on assistant_net)
47
65
  url: "http://ollama:11434/api/tags",
48
66
  baseUrl: "http://ollama:11434",
67
+ validate: validateOllamaResponse,
49
68
  },
50
69
  {
51
70
  url: "http://host.docker.internal:11434/api/tags",
52
71
  baseUrl: "http://host.docker.internal:11434",
72
+ validate: validateOllamaResponse,
53
73
  },
54
74
  {
55
75
  url: "http://localhost:11434/api/tags",
56
76
  baseUrl: "http://localhost:11434",
77
+ validate: validateOllamaResponse,
57
78
  },
58
79
  ],
59
80
  },
@@ -81,12 +102,16 @@ const LOCAL_PROVIDER_PROBES: { provider: string; probes: { url: string; baseUrl:
81
102
  export async function detectLocalProviders(): Promise<LocalProviderDetection[]> {
82
103
  const results = await Promise.all(
83
104
  LOCAL_PROVIDER_PROBES.map(async ({ provider, probes }) => {
84
- for (const { url: probeUrl, baseUrl } of probes) {
105
+ for (const { url: probeUrl, baseUrl, validate } of probes) {
85
106
  try {
86
107
  const res = await fetch(probeUrl, {
87
108
  signal: AbortSignal.timeout(3000),
88
109
  });
89
110
  if (res.ok) {
111
+ if (validate && !(await validate(res))) {
112
+ logger.debug("provider probe response failed validation", { provider, url: baseUrl });
113
+ continue;
114
+ }
90
115
  logger.debug("detected local provider", { provider, url: baseUrl });
91
116
  return { provider, url: baseUrl, available: true };
92
117
  }
@@ -27,5 +27,5 @@ export function isSetupComplete(stateDir: string, configDir: string): boolean {
27
27
  }
28
28
 
29
29
  const keys = readSecretsKeys(configDir);
30
- return keys.ADMIN_TOKEN === true;
30
+ return keys.OPENPALM_ADMIN_TOKEN === true || keys.ADMIN_TOKEN === true;
31
31
  }