Files
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
318 KiB
JSON

{"repo": "buggyblues/shadow", "files": {"apps/cloud/.env.e2e.example": {"c70fa777c96d5a220fd8f1154acc5425cbcb4d63": {"t": 1785745119.7248278, "n": 945, "h": "c0b5329b19b2f97a", "c": "# E2E environment for shadow-cloud CLI tests\n# Copy this to .env.e2e and fill in your values.\n# .env.e2e is gitignored.\n\n# Shadow server URL (docker-compose default)\nE2E_ORIGIN=http://localhost:3000\n\n# Optional: override E2E run ID (used for unique test resource names)\n# E2E_RUN_ID=my-run-001\n\n# Optional: pre-seeded owner credentials (seed script creates these)\n# ADMIN_EMAIL=admin@shadowob.app\n# ADMIN_PASSWORD=admin123456\n\n# DeepSeek API key — used for agent probe E2E tests (test:e2e:probe)\n# DeepSeek is OpenAI-API compatible; models: deepseek-chat, deepseek-reasoner\nDEEPSEEK_API_KEY=sk-59915f72ef4d4c69ace3a9da04ab72ea\n\n# Optional: ANTHROPIC settings for claude-runner tests\n# ANTHROPIC_AUTH_TOKEN=...\n# ANTHROPIC_BASE_URL=...\n# ANTHROPIC_MODEL=claude-3-5-sonnet-20241022\n\n# Optional: override K8s context\n# KUBECONFIG_CONTEXT=rancher-desktop\n\n# Optional: Pulumi backend override\n# PULUMI_BACKEND_URL=file:///tmp/shadow-cloud-e2e-pulumi\n"}, "747eaca2932bc27c2010c49692ff60108e46e1ed": {"t": 1785747939.0331645, "n": 945, "h": "c0b5329b19b2f97a", "c": "# E2E environment for shadow-cloud CLI tests\n# Copy this to .env.e2e and fill in your values.\n# .env.e2e is gitignored.\n\n# Shadow server URL (docker-compose default)\nE2E_ORIGIN=http://localhost:3000\n\n# Optional: override E2E run ID (used for unique test resource names)\n# E2E_RUN_ID=my-run-001\n\n# Optional: pre-seeded owner credentials (seed script creates these)\n# ADMIN_EMAIL=admin@shadowob.app\n# ADMIN_PASSWORD=admin123456\n\n# DeepSeek API key — used for agent probe E2E tests (test:e2e:probe)\n# DeepSeek is OpenAI-API compatible; models: deepseek-chat, deepseek-reasoner\nDEEPSEEK_API_KEY=sk-59915f72ef4d4c69ace3a9da04ab72ea\n\n# Optional: ANTHROPIC settings for claude-runner tests\n# ANTHROPIC_AUTH_TOKEN=...\n# ANTHROPIC_BASE_URL=...\n# ANTHROPIC_MODEL=claude-3-5-sonnet-20241022\n\n# Optional: override K8s context\n# KUBECONFIG_CONTEXT=rancher-desktop\n\n# Optional: Pulumi backend override\n# PULUMI_BACKEND_URL=file:///tmp/shadow-cloud-e2e-pulumi\n"}, "440dff06de27a4715ca39e29813c7e61d620b9d2": {"t": 1786068199.3724012, "n": 945, "h": "c0b5329b19b2f97a", "c": "# E2E environment for shadow-cloud CLI tests\n# Copy this to .env.e2e and fill in your values.\n# .env.e2e is gitignored.\n\n# Shadow server URL (docker-compose default)\nE2E_ORIGIN=http://localhost:3000\n\n# Optional: override E2E run ID (used for unique test resource names)\n# E2E_RUN_ID=my-run-001\n\n# Optional: pre-seeded owner credentials (seed script creates these)\n# ADMIN_EMAIL=admin@shadowob.app\n# ADMIN_PASSWORD=admin123456\n\n# DeepSeek API key — used for agent probe E2E tests (test:e2e:probe)\n# DeepSeek is OpenAI-API compatible; models: deepseek-chat, deepseek-reasoner\nDEEPSEEK_API_KEY=sk-59915f72ef4d4c69ace3a9da04ab72ea\n\n# Optional: ANTHROPIC settings for claude-runner tests\n# ANTHROPIC_AUTH_TOKEN=...\n# ANTHROPIC_BASE_URL=...\n# ANTHROPIC_MODEL=claude-3-5-sonnet-20241022\n\n# Optional: override K8s context\n# KUBECONFIG_CONTEXT=rancher-desktop\n\n# Optional: Pulumi backend override\n# PULUMI_BACKEND_URL=file:///tmp/shadow-cloud-e2e-pulumi\n"}}, "apps/server/src/lib/model-proxy-config.ts": {"c70fa777c96d5a220fd8f1154acc5425cbcb4d63": {"t": 1785745568.2574522, "n": 6578, "h": "ea129f723795137a", "c": "import { signModelProxyToken } from './model-proxy-token'\n\nexport const MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS = new Set([\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_AUTH_TOKEN',\n 'OPENAI_API_KEY',\n 'GEMINI_API_KEY',\n 'GOOGLE_API_KEY',\n 'GOOGLE_AI_API_KEY',\n 'DEEPSEEK_API_KEY',\n 'DASHSCOPE_API_KEY',\n 'ALIBABA_API_KEY',\n 'QWEN_API_KEY',\n 'MINIMAX_API_KEY',\n 'MOONSHOT_API_KEY',\n 'KIMI_API_KEY',\n 'ZAI_API_KEY',\n 'ZHIPUAI_API_KEY',\n 'GLM_API_KEY',\n 'BIGMODEL_API_KEY',\n 'OPENROUTER_API_KEY',\n 'XAI_API_KEY',\n 'GROK_API_KEY',\n 'OPENAI_COMPATIBLE_API_KEY',\n 'ANTHROPIC_COMPATIBLE_API_KEY',\n 'SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY',\n 'SHADOWOB_MODEL_PROXY_UPSTREAM_ANTHROPIC_API_KEY',\n 'MODEL_PROXY_TOKEN_SECRET',\n 'JWT_SECRET',\n])\n\nconst SENSITIVE_SERVER_ENV_PATTERN =\n /(^|_)(API_KEY|AUTH_TOKEN|TOKEN|SECRET|PASSWORD|PRIVATE_KEY|CREDENTIAL|ACCESS_KEY)$/i\n\nconst DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT =\n 'SHADOWOB_AGENT_SERVER_URL (or pod-reachable SHADOWOB_SERVER_URL)'\nconst EXPLICIT_RUNTIME_SERVER_URL_ENV = 'SHADOWOB_MODEL_PROXY_RUNTIME_SERVER_URL'\nconst INTERNAL_ONLY_SHADOWOB_RUNTIME_HOSTS = new Set([\n 'localhost',\n '127.0.0.1',\n '0.0.0.0',\n '::1',\n 'host.docker.internal',\n 'host.lima.internal',\n 'server',\n])\nconst LOOPBACK_RUNTIME_HOSTS = new Set(['localhost', '127.0.0.1', '0.0.0.0', '::1'])\n\nexport function isOfficialModelProxyEnabled() {\n return process.env.SHADOWOB_MODEL_PROXY_ENABLED !== 'false'\n}\n\nfunction firstNonEmptyEnv(...keys: string[]) {\n for (const key of keys) {\n const value = process.env[key]?.trim()\n if (value) return value\n }\n return null\n}\n\nexport function isInternalOnlyShadowRuntimeUrl(rawUrl?: string) {\n if (!rawUrl?.trim()) return false\n\n try {\n const parsed = new URL(rawUrl)\n const hostname = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, '')\n return INTERNAL_ONLY_SHADOWOB_RUNTIME_HOSTS.has(hostname)\n } catch {\n return false\n }\n}\n\nfunction explicitModelProxyRuntimeServerUrl(rawUrl?: string) {\n if (!rawUrl?.trim()) return null\n try {\n const parsed = new URL(rawUrl.trim())\n const hostname = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, '')\n if (\n (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') ||\n LOOPBACK_RUNTIME_HOSTS.has(hostname)\n ) {\n return null\n }\n return parsed.toString().replace(/\\/+$/, '')\n } catch {\n return null\n }\n}\n\nexport function resolveOfficialModelProxyRuntimeServerUrl(input: {\n shadowServerUrl?: string\n modelProxyRuntimeServerUrl?: string\n}): {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement: string\n} {\n const requestedExplicitUrl =\n input.modelProxyRuntimeServerUrl ?? process.env[EXPLICIT_RUNTIME_SERVER_URL_ENV]\n if (requestedExplicitUrl?.trim()) {\n const explicitUrl = explicitModelProxyRuntimeServerUrl(requestedExplicitUrl)\n return explicitUrl\n ? {\n runtimeServerUrl: explicitUrl,\n runtimeServerUrlRequirement: EXPLICIT_RUNTIME_SERVER_URL_ENV,\n }\n : {\n runtimeServerUrl: undefined,\n runtimeServerUrlRequirement: `${EXPLICIT_RUNTIME_SERVER_URL_ENV} (must be a pod-reachable HTTP(S) URL, not loopback)`,\n }\n }\n\n const shadowServerUrl = input.shadowServerUrl?.trim()\n if (shadowServerUrl && !isInternalOnlyShadowRuntimeUrl(shadowServerUrl)) {\n return {\n runtimeServerUrl: shadowServerUrl,\n runtimeServerUrlRequirement: DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n }\n\n return {\n runtimeServerUrl: undefined,\n runtimeServerUrlRequirement: shadowServerUrl\n ? 'SHADOWOB_AGENT_SERVER_URL (current SHADOWOB_SERVER_URL is internal-only)'\n : DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n}\n\nexport function officialModelProxyMissingConfig(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement = DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n): string[] {\n if (!isOfficialModelProxyEnabled()) return ['SHADOWOB_MODEL_PROXY_ENABLED']\n\n const missing: string[] = []\n if (!runtimeServerUrl) missing.push(runtimeServerUrlRequirement)\n if (!firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL')) {\n missing.push('SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL')\n }\n if (!firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY')) {\n missing.push('SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY')\n }\n return missing\n}\n\nexport function assertOfficialModelProxyAvailable(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement?: string,\n) {\n const missing = officialModelProxyMissingConfig(runtimeServerUrl, runtimeServerUrlRequirement)\n if (missing.length === 0) return\n\n throw Object.assign(\n new Error(`Official model provider is unavailable: missing ${missing.join(', ')}`),\n {\n status: 503,\n code: 'OFFICIAL_MODEL_PROVIDER_UNCONFIGURED',\n missing,\n },\n )\n}\n\nexport function officialModelProxyModel() {\n return (\n firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_MODEL', 'SHADOWOB_MODEL_PROXY_DEFAULT_MODEL') ??\n 'deepseek-v4-flash'\n )\n}\n\nexport function officialModelProxyBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/v1`\n}\n\nexport function officialModelProxyAnthropicBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/anthropic`\n}\n\nexport function officialModelProxyEnvVars(input: {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement?: string\n userId: string\n playId?: string\n templateSlug?: string\n namespace?: string\n}) {\n if (\n officialModelProxyMissingConfig(input.runtimeServerUrl, input.runtimeServerUrlRequirement)\n .length > 0\n ) {\n return {}\n }\n const baseUrl = officialModelProxyBaseUrl(input.runtimeServerUrl)\n const anthropicBaseUrl = officialModelProxyAnthropicBaseUrl(input.runtimeServerUrl)\n if (!baseUrl || !anthropicBaseUrl) return {}\n const token = signModelProxyToken({\n userId: input.userId,\n playId: input.playId,\n templateSlug: input.templateSlug,\n namespace: input.namespace,\n })\n const model = officialModelProxyModel()\n\n return {\n SHADOWOB_MODEL_PROVIDER_ID: 'shadow-official',\n OPENAI_COMPATIBLE_BASE_URL: baseUrl,\n OPENAI_COMPATIBLE_API_KEY: token,\n OPENAI_COMPATIBLE_MODEL_ID: model,\n ANTHROPIC_COMPATIBLE_BASE_URL: anthropicBaseUrl,\n ANTHROPIC_COMPATIBLE_API_KEY: token,\n ANTHROPIC_COMPATIBLE_MODEL_ID: model,\n }\n}\n\nexport function shouldCopyServerRuntimeEnvKey(key: string) {\n if (MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS.has(key)) return false\n return !SENSITIVE_SERVER_ENV_PATTERN.test(key)\n}\n"}, "40c0b2f2ce3ba13bb04e27d6b8c29f8c1f15451b": {"t": 1785747939.524698, "n": 6578, "h": "ea129f723795137a", "c": "import { signModelProxyToken } from './model-proxy-token'\n\nexport const MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS = new Set([\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_AUTH_TOKEN',\n 'OPENAI_API_KEY',\n 'GEMINI_API_KEY',\n 'GOOGLE_API_KEY',\n 'GOOGLE_AI_API_KEY',\n 'DEEPSEEK_API_KEY',\n 'DASHSCOPE_API_KEY',\n 'ALIBABA_API_KEY',\n 'QWEN_API_KEY',\n 'MINIMAX_API_KEY',\n 'MOONSHOT_API_KEY',\n 'KIMI_API_KEY',\n 'ZAI_API_KEY',\n 'ZHIPUAI_API_KEY',\n 'GLM_API_KEY',\n 'BIGMODEL_API_KEY',\n 'OPENROUTER_API_KEY',\n 'XAI_API_KEY',\n 'GROK_API_KEY',\n 'OPENAI_COMPATIBLE_API_KEY',\n 'ANTHROPIC_COMPATIBLE_API_KEY',\n 'SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY',\n 'SHADOWOB_MODEL_PROXY_UPSTREAM_ANTHROPIC_API_KEY',\n 'MODEL_PROXY_TOKEN_SECRET',\n 'JWT_SECRET',\n])\n\nconst SENSITIVE_SERVER_ENV_PATTERN =\n /(^|_)(API_KEY|AUTH_TOKEN|TOKEN|SECRET|PASSWORD|PRIVATE_KEY|CREDENTIAL|ACCESS_KEY)$/i\n\nconst DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT =\n 'SHADOWOB_AGENT_SERVER_URL (or pod-reachable SHADOWOB_SERVER_URL)'\nconst EXPLICIT_RUNTIME_SERVER_URL_ENV = 'SHADOWOB_MODEL_PROXY_RUNTIME_SERVER_URL'\nconst INTERNAL_ONLY_SHADOWOB_RUNTIME_HOSTS = new Set([\n 'localhost',\n '127.0.0.1',\n '0.0.0.0',\n '::1',\n 'host.docker.internal',\n 'host.lima.internal',\n 'server',\n])\nconst LOOPBACK_RUNTIME_HOSTS = new Set(['localhost', '127.0.0.1', '0.0.0.0', '::1'])\n\nexport function isOfficialModelProxyEnabled() {\n return process.env.SHADOWOB_MODEL_PROXY_ENABLED !== 'false'\n}\n\nfunction firstNonEmptyEnv(...keys: string[]) {\n for (const key of keys) {\n const value = process.env[key]?.trim()\n if (value) return value\n }\n return null\n}\n\nexport function isInternalOnlyShadowRuntimeUrl(rawUrl?: string) {\n if (!rawUrl?.trim()) return false\n\n try {\n const parsed = new URL(rawUrl)\n const hostname = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, '')\n return INTERNAL_ONLY_SHADOWOB_RUNTIME_HOSTS.has(hostname)\n } catch {\n return false\n }\n}\n\nfunction explicitModelProxyRuntimeServerUrl(rawUrl?: string) {\n if (!rawUrl?.trim()) return null\n try {\n const parsed = new URL(rawUrl.trim())\n const hostname = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, '')\n if (\n (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') ||\n LOOPBACK_RUNTIME_HOSTS.has(hostname)\n ) {\n return null\n }\n return parsed.toString().replace(/\\/+$/, '')\n } catch {\n return null\n }\n}\n\nexport function resolveOfficialModelProxyRuntimeServerUrl(input: {\n shadowServerUrl?: string\n modelProxyRuntimeServerUrl?: string\n}): {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement: string\n} {\n const requestedExplicitUrl =\n input.modelProxyRuntimeServerUrl ?? process.env[EXPLICIT_RUNTIME_SERVER_URL_ENV]\n if (requestedExplicitUrl?.trim()) {\n const explicitUrl = explicitModelProxyRuntimeServerUrl(requestedExplicitUrl)\n return explicitUrl\n ? {\n runtimeServerUrl: explicitUrl,\n runtimeServerUrlRequirement: EXPLICIT_RUNTIME_SERVER_URL_ENV,\n }\n : {\n runtimeServerUrl: undefined,\n runtimeServerUrlRequirement: `${EXPLICIT_RUNTIME_SERVER_URL_ENV} (must be a pod-reachable HTTP(S) URL, not loopback)`,\n }\n }\n\n const shadowServerUrl = input.shadowServerUrl?.trim()\n if (shadowServerUrl && !isInternalOnlyShadowRuntimeUrl(shadowServerUrl)) {\n return {\n runtimeServerUrl: shadowServerUrl,\n runtimeServerUrlRequirement: DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n }\n\n return {\n runtimeServerUrl: undefined,\n runtimeServerUrlRequirement: shadowServerUrl\n ? 'SHADOWOB_AGENT_SERVER_URL (current SHADOWOB_SERVER_URL is internal-only)'\n : DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n}\n\nexport function officialModelProxyMissingConfig(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement = DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n): string[] {\n if (!isOfficialModelProxyEnabled()) return ['SHADOWOB_MODEL_PROXY_ENABLED']\n\n const missing: string[] = []\n if (!runtimeServerUrl) missing.push(runtimeServerUrlRequirement)\n if (!firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL')) {\n missing.push('SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL')\n }\n if (!firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY')) {\n missing.push('SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY')\n }\n return missing\n}\n\nexport function assertOfficialModelProxyAvailable(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement?: string,\n) {\n const missing = officialModelProxyMissingConfig(runtimeServerUrl, runtimeServerUrlRequirement)\n if (missing.length === 0) return\n\n throw Object.assign(\n new Error(`Official model provider is unavailable: missing ${missing.join(', ')}`),\n {\n status: 503,\n code: 'OFFICIAL_MODEL_PROVIDER_UNCONFIGURED',\n missing,\n },\n )\n}\n\nexport function officialModelProxyModel() {\n return (\n firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_MODEL', 'SHADOWOB_MODEL_PROXY_DEFAULT_MODEL') ??\n 'deepseek-v4-flash'\n )\n}\n\nexport function officialModelProxyBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/v1`\n}\n\nexport function officialModelProxyAnthropicBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/anthropic`\n}\n\nexport function officialModelProxyEnvVars(input: {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement?: string\n userId: string\n playId?: string\n templateSlug?: string\n namespace?: string\n}) {\n if (\n officialModelProxyMissingConfig(input.runtimeServerUrl, input.runtimeServerUrlRequirement)\n .length > 0\n ) {\n return {}\n }\n const baseUrl = officialModelProxyBaseUrl(input.runtimeServerUrl)\n const anthropicBaseUrl = officialModelProxyAnthropicBaseUrl(input.runtimeServerUrl)\n if (!baseUrl || !anthropicBaseUrl) return {}\n const token = signModelProxyToken({\n userId: input.userId,\n playId: input.playId,\n templateSlug: input.templateSlug,\n namespace: input.namespace,\n })\n const model = officialModelProxyModel()\n\n return {\n SHADOWOB_MODEL_PROVIDER_ID: 'shadow-official',\n OPENAI_COMPATIBLE_BASE_URL: baseUrl,\n OPENAI_COMPATIBLE_API_KEY: token,\n OPENAI_COMPATIBLE_MODEL_ID: model,\n ANTHROPIC_COMPATIBLE_BASE_URL: anthropicBaseUrl,\n ANTHROPIC_COMPATIBLE_API_KEY: token,\n ANTHROPIC_COMPATIBLE_MODEL_ID: model,\n }\n}\n\nexport function shouldCopyServerRuntimeEnvKey(key: string) {\n if (MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS.has(key)) return false\n return !SENSITIVE_SERVER_ENV_PATTERN.test(key)\n}\n"}, "a8c1ad311f1d030c6f3bd79d7716bbdcbb1d86a8": {"t": 1785747940.6594157, "n": 5325, "h": "a8cf93a8e3324649", "c": "import { signModelProxyToken } from './model-proxy-token'\n\nexport const MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS = new Set([\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_AUTH_TOKEN',\n 'OPENAI_API_KEY',\n 'GEMINI_API_KEY',\n 'GOOGLE_API_KEY',\n 'GOOGLE_AI_API_KEY',\n 'DEEPSEEK_API_KEY',\n 'DASHSCOPE_API_KEY',\n 'ALIBABA_API_KEY',\n 'QWEN_API_KEY',\n 'MINIMAX_API_KEY',\n 'MOONSHOT_API_KEY',\n 'KIMI_API_KEY',\n 'ZAI_API_KEY',\n 'ZHIPUAI_API_KEY',\n 'GLM_API_KEY',\n 'BIGMODEL_API_KEY',\n 'OPENROUTER_API_KEY',\n 'XAI_API_KEY',\n 'GROK_API_KEY',\n 'OPENAI_COMPATIBLE_API_KEY',\n 'ANTHROPIC_COMPATIBLE_API_KEY',\n 'SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY',\n 'SHADOWOB_MODEL_PROXY_UPSTREAM_ANTHROPIC_API_KEY',\n 'MODEL_PROXY_TOKEN_SECRET',\n 'JWT_SECRET',\n])\n\nconst SENSITIVE_SERVER_ENV_PATTERN =\n /(^|_)(API_KEY|AUTH_TOKEN|TOKEN|SECRET|PASSWORD|PRIVATE_KEY|CREDENTIAL|ACCESS_KEY)$/i\n\nconst DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT =\n 'SHADOWOB_AGENT_SERVER_URL (or pod-reachable SHADOWOB_SERVER_URL)'\nconst INTERNAL_ONLY_SHADOWOB_RUNTIME_HOSTS = new Set([\n 'localhost',\n '127.0.0.1',\n '0.0.0.0',\n '::1',\n 'host.docker.internal',\n 'host.lima.internal',\n 'server',\n])\n\nexport function isOfficialModelProxyEnabled() {\n return process.env.SHADOWOB_MODEL_PROXY_ENABLED !== 'false'\n}\n\nfunction firstNonEmptyEnv(...keys: string[]) {\n for (const key of keys) {\n const value = process.env[key]?.trim()\n if (value) return value\n }\n return null\n}\n\nexport function isInternalOnlyShadowRuntimeUrl(rawUrl?: string) {\n if (!rawUrl?.trim()) return false\n\n try {\n const parsed = new URL(rawUrl)\n const hostname = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, '')\n return INTERNAL_ONLY_SHADOWOB_RUNTIME_HOSTS.has(hostname)\n } catch {\n return false\n }\n}\n\nexport function resolveOfficialModelProxyRuntimeServerUrl(input: { shadowServerUrl?: string }): {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement: string\n} {\n const shadowServerUrl = input.shadowServerUrl?.trim()\n if (shadowServerUrl && !isInternalOnlyShadowRuntimeUrl(shadowServerUrl)) {\n return {\n runtimeServerUrl: shadowServerUrl,\n runtimeServerUrlRequirement: DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n }\n\n return {\n runtimeServerUrl: undefined,\n runtimeServerUrlRequirement: shadowServerUrl\n ? 'SHADOWOB_AGENT_SERVER_URL (current SHADOWOB_SERVER_URL is internal-only)'\n : DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n}\n\nexport function officialModelProxyMissingConfig(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement = DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n): string[] {\n if (!isOfficialModelProxyEnabled()) return ['SHADOWOB_MODEL_PROXY_ENABLED']\n\n const missing: string[] = []\n if (!runtimeServerUrl) missing.push(runtimeServerUrlRequirement)\n if (!firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL')) {\n missing.push('SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL')\n }\n if (!firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY')) {\n missing.push('SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY')\n }\n return missing\n}\n\nexport function assertOfficialModelProxyAvailable(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement?: string,\n) {\n const missing = officialModelProxyMissingConfig(runtimeServerUrl, runtimeServerUrlRequirement)\n if (missing.length === 0) return\n\n throw Object.assign(\n new Error(`Official model provider is unavailable: missing ${missing.join(', ')}`),\n {\n status: 503,\n code: 'OFFICIAL_MODEL_PROVIDER_UNCONFIGURED',\n missing,\n },\n )\n}\n\nexport function officialModelProxyModel() {\n return (\n firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_MODEL', 'SHADOWOB_MODEL_PROXY_DEFAULT_MODEL') ??\n 'deepseek-v4-flash'\n )\n}\n\nexport function officialModelProxyBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/v1`\n}\n\nexport function officialModelProxyAnthropicBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/anthropic`\n}\n\nexport function officialModelProxyEnvVars(input: {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement?: string\n userId: string\n playId?: string\n templateSlug?: string\n namespace?: string\n}) {\n if (\n officialModelProxyMissingConfig(input.runtimeServerUrl, input.runtimeServerUrlRequirement)\n .length > 0\n ) {\n return {}\n }\n const baseUrl = officialModelProxyBaseUrl(input.runtimeServerUrl)\n const anthropicBaseUrl = officialModelProxyAnthropicBaseUrl(input.runtimeServerUrl)\n if (!baseUrl || !anthropicBaseUrl) return {}\n const token = signModelProxyToken({\n userId: input.userId,\n playId: input.playId,\n templateSlug: input.templateSlug,\n namespace: input.namespace,\n })\n const model = officialModelProxyModel()\n\n return {\n SHADOWOB_MODEL_PROVIDER_ID: 'shadow-official',\n OPENAI_COMPATIBLE_BASE_URL: baseUrl,\n OPENAI_COMPATIBLE_API_KEY: token,\n OPENAI_COMPATIBLE_MODEL_ID: model,\n ANTHROPIC_COMPATIBLE_BASE_URL: anthropicBaseUrl,\n ANTHROPIC_COMPATIBLE_API_KEY: token,\n ANTHROPIC_COMPATIBLE_MODEL_ID: model,\n }\n}\n\nexport function shouldCopyServerRuntimeEnvKey(key: string) {\n if (MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS.has(key)) return false\n return !SENSITIVE_SERVER_ENV_PATTERN.test(key)\n}\n"}, "b013fd236a220ebc076ec05dc8e51f59e753c583": {"t": 1785747941.8325076, "n": 5291, "h": "aa5e156b42a4eced", "c": "import { signModelProxyToken } from './model-proxy-token'\n\nexport const MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS = new Set([\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_AUTH_TOKEN',\n 'OPENAI_API_KEY',\n 'GEMINI_API_KEY',\n 'GOOGLE_API_KEY',\n 'GOOGLE_AI_API_KEY',\n 'DEEPSEEK_API_KEY',\n 'DASHSCOPE_API_KEY',\n 'ALIBABA_API_KEY',\n 'QWEN_API_KEY',\n 'MINIMAX_API_KEY',\n 'MOONSHOT_API_KEY',\n 'KIMI_API_KEY',\n 'ZAI_API_KEY',\n 'ZHIPUAI_API_KEY',\n 'GLM_API_KEY',\n 'BIGMODEL_API_KEY',\n 'OPENROUTER_API_KEY',\n 'XAI_API_KEY',\n 'GROK_API_KEY',\n 'OPENAI_COMPATIBLE_API_KEY',\n 'ANTHROPIC_COMPATIBLE_API_KEY',\n 'SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY',\n 'SHADOWOB_MODEL_PROXY_UPSTREAM_ANTHROPIC_API_KEY',\n 'MODEL_PROXY_TOKEN_SECRET',\n 'JWT_SECRET',\n])\n\nconst SENSITIVE_SERVER_ENV_PATTERN =\n /(^|_)(API_KEY|AUTH_TOKEN|TOKEN|SECRET|PASSWORD|PRIVATE_KEY|CREDENTIAL|ACCESS_KEY)$/i\n\nconst DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT = 'SHADOWOB_SERVER_URL'\nconst INTERNAL_ONLY_SHADOWOB_RUNTIME_HOSTS = new Set([\n 'localhost',\n '127.0.0.1',\n '0.0.0.0',\n '::1',\n 'host.docker.internal',\n 'host.lima.internal',\n 'server',\n])\n\nexport function isOfficialModelProxyEnabled() {\n return process.env.SHADOWOB_MODEL_PROXY_ENABLED !== 'false'\n}\n\nfunction firstNonEmptyEnv(...keys: string[]) {\n for (const key of keys) {\n const value = process.env[key]?.trim()\n if (value) return value\n }\n return null\n}\n\nexport function isInternalOnlyShadowRuntimeUrl(rawUrl?: string) {\n if (!rawUrl?.trim()) return false\n\n try {\n const parsed = new URL(rawUrl)\n const hostname = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, '')\n return INTERNAL_ONLY_SHADOWOB_RUNTIME_HOSTS.has(hostname)\n } catch {\n return false\n }\n}\n\nexport function resolveOfficialModelProxyRuntimeServerUrl(input: { shadowServerUrl?: string }): {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement: string\n} {\n const shadowServerUrl = input.shadowServerUrl?.trim()\n if (shadowServerUrl && !isInternalOnlyShadowRuntimeUrl(shadowServerUrl)) {\n return {\n runtimeServerUrl: shadowServerUrl,\n runtimeServerUrlRequirement: DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n }\n\n return {\n runtimeServerUrl: undefined,\n runtimeServerUrlRequirement: shadowServerUrl\n ? 'SHADOWOB_SERVER_URL (pod-reachable public Shadow URL; current value is internal-only)'\n : DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n}\n\nexport function officialModelProxyMissingConfig(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement = DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n): string[] {\n if (!isOfficialModelProxyEnabled()) return ['SHADOWOB_MODEL_PROXY_ENABLED']\n\n const missing: string[] = []\n if (!runtimeServerUrl) missing.push(runtimeServerUrlRequirement)\n if (!firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL')) {\n missing.push('SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL')\n }\n if (!firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY')) {\n missing.push('SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY')\n }\n return missing\n}\n\nexport function assertOfficialModelProxyAvailable(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement?: string,\n) {\n const missing = officialModelProxyMissingConfig(runtimeServerUrl, runtimeServerUrlRequirement)\n if (missing.length === 0) return\n\n throw Object.assign(\n new Error(`Official model provider is unavailable: missing ${missing.join(', ')}`),\n {\n status: 503,\n code: 'OFFICIAL_MODEL_PROVIDER_UNCONFIGURED',\n missing,\n },\n )\n}\n\nexport function officialModelProxyModel() {\n return (\n firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_MODEL', 'SHADOWOB_MODEL_PROXY_DEFAULT_MODEL') ??\n 'deepseek-v4-flash'\n )\n}\n\nexport function officialModelProxyBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/v1`\n}\n\nexport function officialModelProxyAnthropicBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/anthropic`\n}\n\nexport function officialModelProxyEnvVars(input: {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement?: string\n userId: string\n playId?: string\n templateSlug?: string\n namespace?: string\n}) {\n if (\n officialModelProxyMissingConfig(input.runtimeServerUrl, input.runtimeServerUrlRequirement)\n .length > 0\n ) {\n return {}\n }\n const baseUrl = officialModelProxyBaseUrl(input.runtimeServerUrl)\n const anthropicBaseUrl = officialModelProxyAnthropicBaseUrl(input.runtimeServerUrl)\n if (!baseUrl || !anthropicBaseUrl) return {}\n const token = signModelProxyToken({\n userId: input.userId,\n playId: input.playId,\n templateSlug: input.templateSlug,\n namespace: input.namespace,\n })\n const model = officialModelProxyModel()\n\n return {\n SHADOWOB_MODEL_PROVIDER_ID: 'shadow-official',\n OPENAI_COMPATIBLE_BASE_URL: baseUrl,\n OPENAI_COMPATIBLE_API_KEY: token,\n OPENAI_COMPATIBLE_MODEL_ID: model,\n ANTHROPIC_COMPATIBLE_BASE_URL: anthropicBaseUrl,\n ANTHROPIC_COMPATIBLE_API_KEY: token,\n ANTHROPIC_COMPATIBLE_MODEL_ID: model,\n }\n}\n\nexport function shouldCopyServerRuntimeEnvKey(key: string) {\n if (MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS.has(key)) return false\n return !SENSITIVE_SERVER_ENV_PATTERN.test(key)\n}\n"}, "e13348ec10ec83787f4219a7212313e3631f26ff": {"t": 1785747943.2097504, "n": 5573, "h": "5ff3f1eded16276f", "c": "import { signModelProxyToken } from './model-proxy-token'\n\nexport const MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS = new Set([\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_AUTH_TOKEN',\n 'OPENAI_API_KEY',\n 'GEMINI_API_KEY',\n 'GOOGLE_API_KEY',\n 'GOOGLE_AI_API_KEY',\n 'DEEPSEEK_API_KEY',\n 'DASHSCOPE_API_KEY',\n 'ALIBABA_API_KEY',\n 'QWEN_API_KEY',\n 'MINIMAX_API_KEY',\n 'MOONSHOT_API_KEY',\n 'KIMI_API_KEY',\n 'ZAI_API_KEY',\n 'ZHIPUAI_API_KEY',\n 'GLM_API_KEY',\n 'BIGMODEL_API_KEY',\n 'OPENROUTER_API_KEY',\n 'XAI_API_KEY',\n 'GROK_API_KEY',\n 'OPENAI_COMPATIBLE_API_KEY',\n 'ANTHROPIC_COMPATIBLE_API_KEY',\n 'SHADOW_MODEL_PROXY_UPSTREAM_API_KEY',\n 'SHADOW_MODEL_PROXY_UPSTREAM_ANTHROPIC_API_KEY',\n 'MODEL_PROXY_TOKEN_SECRET',\n 'JWT_SECRET',\n])\n\nconst SENSITIVE_SERVER_ENV_PATTERN =\n /(^|_)(API_KEY|AUTH_TOKEN|TOKEN|SECRET|PASSWORD|PRIVATE_KEY|CREDENTIAL|ACCESS_KEY)$/i\n\nconst DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT = 'SHADOW_SERVER_URL or SHADOW_AGENT_SERVER_URL'\nconst INTERNAL_ONLY_SHADOW_RUNTIME_HOSTS = new Set([\n 'localhost',\n '127.0.0.1',\n '0.0.0.0',\n '::1',\n 'host.docker.internal',\n 'host.lima.internal',\n 'server',\n])\n\nexport function isOfficialModelProxyEnabled() {\n return process.env.SHADOW_MODEL_PROXY_ENABLED !== 'false'\n}\n\nfunction firstNonEmptyEnv(...keys: string[]) {\n for (const key of keys) {\n const value = process.env[key]?.trim()\n if (value) return value\n }\n return null\n}\n\nexport function isInternalOnlyShadowRuntimeUrl(rawUrl?: string) {\n if (!rawUrl?.trim()) return false\n\n try {\n const parsed = new URL(rawUrl)\n const hostname = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, '')\n return INTERNAL_ONLY_SHADOW_RUNTIME_HOSTS.has(hostname)\n } catch {\n return false\n }\n}\n\nexport function resolveOfficialModelProxyRuntimeServerUrl(input: {\n shadowAgentServerUrl?: string\n shadowServerUrl?: string\n}): {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement: string\n} {\n const shadowAgentServerUrl = input.shadowAgentServerUrl?.trim()\n if (shadowAgentServerUrl) {\n return {\n runtimeServerUrl: shadowAgentServerUrl,\n runtimeServerUrlRequirement: DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n }\n\n const shadowServerUrl = input.shadowServerUrl?.trim()\n if (shadowServerUrl && !isInternalOnlyShadowRuntimeUrl(shadowServerUrl)) {\n return {\n runtimeServerUrl: shadowServerUrl,\n runtimeServerUrlRequirement: DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n }\n\n return {\n runtimeServerUrl: undefined,\n runtimeServerUrlRequirement: shadowServerUrl\n ? 'SHADOW_AGENT_SERVER_URL (pod-reachable public Shadow URL; SHADOW_SERVER_URL is internal-only)'\n : DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n}\n\nexport function officialModelProxyMissingConfig(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement = DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n): string[] {\n if (!isOfficialModelProxyEnabled()) return ['SHADOW_MODEL_PROXY_ENABLED']\n\n const missing: string[] = []\n if (!runtimeServerUrl) missing.push(runtimeServerUrlRequirement)\n if (!firstNonEmptyEnv('SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL')) {\n missing.push('SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL')\n }\n if (!firstNonEmptyEnv('SHADOW_MODEL_PROXY_UPSTREAM_API_KEY')) {\n missing.push('SHADOW_MODEL_PROXY_UPSTREAM_API_KEY')\n }\n return missing\n}\n\nexport function assertOfficialModelProxyAvailable(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement?: string,\n) {\n const missing = officialModelProxyMissingConfig(runtimeServerUrl, runtimeServerUrlRequirement)\n if (missing.length === 0) return\n\n throw Object.assign(\n new Error(`Official model provider is unavailable: missing ${missing.join(', ')}`),\n {\n status: 503,\n code: 'OFFICIAL_MODEL_PROVIDER_UNCONFIGURED',\n missing,\n },\n )\n}\n\nexport function officialModelProxyModel() {\n return (\n firstNonEmptyEnv('SHADOW_MODEL_PROXY_MODEL', 'SHADOW_MODEL_PROXY_DEFAULT_MODEL') ??\n 'deepseek-v4-flash'\n )\n}\n\nexport function officialModelProxyBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/v1`\n}\n\nexport function officialModelProxyAnthropicBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/anthropic`\n}\n\nexport function officialModelProxyEnvVars(input: {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement?: string\n userId: string\n playId?: string\n templateSlug?: string\n namespace?: string\n}) {\n if (\n officialModelProxyMissingConfig(input.runtimeServerUrl, input.runtimeServerUrlRequirement)\n .length > 0\n ) {\n return {}\n }\n const baseUrl = officialModelProxyBaseUrl(input.runtimeServerUrl)\n const anthropicBaseUrl = officialModelProxyAnthropicBaseUrl(input.runtimeServerUrl)\n if (!baseUrl || !anthropicBaseUrl) return {}\n const token = signModelProxyToken({\n userId: input.userId,\n playId: input.playId,\n templateSlug: input.templateSlug,\n namespace: input.namespace,\n })\n const model = officialModelProxyModel()\n\n return {\n SHADOW_MODEL_PROVIDER_ID: 'shadow-official',\n OPENAI_COMPATIBLE_BASE_URL: baseUrl,\n OPENAI_COMPATIBLE_API_KEY: token,\n OPENAI_COMPATIBLE_MODEL_ID: model,\n ANTHROPIC_COMPATIBLE_BASE_URL: anthropicBaseUrl,\n ANTHROPIC_COMPATIBLE_API_KEY: token,\n ANTHROPIC_COMPATIBLE_MODEL_ID: model,\n }\n}\n\nexport function shouldCopyServerRuntimeEnvKey(key: string) {\n if (MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS.has(key)) return false\n return !SENSITIVE_SERVER_ENV_PATTERN.test(key)\n}\n"}, "b8c8b781ec2d529251ee8902c2c98eae51910a5e": {"t": 1785747944.3889246, "n": 4915, "h": "809241510e1f4e4b", "c": "import { signModelProxyToken } from './model-proxy-token'\n\nexport const MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS = new Set([\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_AUTH_TOKEN',\n 'OPENAI_API_KEY',\n 'GEMINI_API_KEY',\n 'GOOGLE_API_KEY',\n 'GOOGLE_AI_API_KEY',\n 'DEEPSEEK_API_KEY',\n 'DASHSCOPE_API_KEY',\n 'ALIBABA_API_KEY',\n 'QWEN_API_KEY',\n 'MINIMAX_API_KEY',\n 'MOONSHOT_API_KEY',\n 'KIMI_API_KEY',\n 'ZAI_API_KEY',\n 'ZHIPUAI_API_KEY',\n 'GLM_API_KEY',\n 'BIGMODEL_API_KEY',\n 'OPENROUTER_API_KEY',\n 'XAI_API_KEY',\n 'GROK_API_KEY',\n 'OPENAI_COMPATIBLE_API_KEY',\n 'SHADOW_MODEL_PROXY_UPSTREAM_API_KEY',\n 'MODEL_PROXY_TOKEN_SECRET',\n 'JWT_SECRET',\n])\n\nconst SENSITIVE_SERVER_ENV_PATTERN =\n /(^|_)(API_KEY|AUTH_TOKEN|TOKEN|SECRET|PASSWORD|PRIVATE_KEY|CREDENTIAL|ACCESS_KEY)$/i\n\nconst DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT = 'SHADOW_SERVER_URL or SHADOW_AGENT_SERVER_URL'\nconst INTERNAL_ONLY_SHADOW_RUNTIME_HOSTS = new Set([\n 'localhost',\n '127.0.0.1',\n '0.0.0.0',\n '::1',\n 'host.docker.internal',\n 'host.lima.internal',\n 'server',\n])\n\nexport function isOfficialModelProxyEnabled() {\n return process.env.SHADOW_MODEL_PROXY_ENABLED !== 'false'\n}\n\nfunction firstNonEmptyEnv(...keys: string[]) {\n for (const key of keys) {\n const value = process.env[key]?.trim()\n if (value) return value\n }\n return null\n}\n\nexport function isInternalOnlyShadowRuntimeUrl(rawUrl?: string) {\n if (!rawUrl?.trim()) return false\n\n try {\n const parsed = new URL(rawUrl)\n const hostname = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, '')\n return INTERNAL_ONLY_SHADOW_RUNTIME_HOSTS.has(hostname)\n } catch {\n return false\n }\n}\n\nexport function resolveOfficialModelProxyRuntimeServerUrl(input: {\n shadowAgentServerUrl?: string\n shadowServerUrl?: string\n}): {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement: string\n} {\n const shadowAgentServerUrl = input.shadowAgentServerUrl?.trim()\n if (shadowAgentServerUrl) {\n return {\n runtimeServerUrl: shadowAgentServerUrl,\n runtimeServerUrlRequirement: DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n }\n\n const shadowServerUrl = input.shadowServerUrl?.trim()\n if (shadowServerUrl && !isInternalOnlyShadowRuntimeUrl(shadowServerUrl)) {\n return {\n runtimeServerUrl: shadowServerUrl,\n runtimeServerUrlRequirement: DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n }\n\n return {\n runtimeServerUrl: undefined,\n runtimeServerUrlRequirement: shadowServerUrl\n ? 'SHADOW_AGENT_SERVER_URL (pod-reachable public Shadow URL; SHADOW_SERVER_URL is internal-only)'\n : DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n}\n\nexport function officialModelProxyMissingConfig(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement = DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n): string[] {\n if (!isOfficialModelProxyEnabled()) return ['SHADOW_MODEL_PROXY_ENABLED']\n\n const missing: string[] = []\n if (!runtimeServerUrl) missing.push(runtimeServerUrlRequirement)\n if (!firstNonEmptyEnv('SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL')) {\n missing.push('SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL')\n }\n if (!firstNonEmptyEnv('SHADOW_MODEL_PROXY_UPSTREAM_API_KEY')) {\n missing.push('SHADOW_MODEL_PROXY_UPSTREAM_API_KEY')\n }\n return missing\n}\n\nexport function assertOfficialModelProxyAvailable(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement?: string,\n) {\n const missing = officialModelProxyMissingConfig(runtimeServerUrl, runtimeServerUrlRequirement)\n if (missing.length === 0) return\n\n throw Object.assign(\n new Error(`Official model provider is unavailable: missing ${missing.join(', ')}`),\n {\n status: 503,\n code: 'OFFICIAL_MODEL_PROVIDER_UNCONFIGURED',\n missing,\n },\n )\n}\n\nexport function officialModelProxyModel() {\n return (\n firstNonEmptyEnv('SHADOW_MODEL_PROXY_MODEL', 'SHADOW_MODEL_PROXY_DEFAULT_MODEL') ??\n 'deepseek-v4-flash'\n )\n}\n\nexport function officialModelProxyBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/v1`\n}\n\nexport function officialModelProxyEnvVars(input: {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement?: string\n userId: string\n playId?: string\n templateSlug?: string\n namespace?: string\n}) {\n if (\n officialModelProxyMissingConfig(input.runtimeServerUrl, input.runtimeServerUrlRequirement)\n .length > 0\n ) {\n return {}\n }\n const baseUrl = officialModelProxyBaseUrl(input.runtimeServerUrl)\n if (!baseUrl) return {}\n\n return {\n OPENAI_COMPATIBLE_API_KEY: signModelProxyToken({\n userId: input.userId,\n playId: input.playId,\n templateSlug: input.templateSlug,\n namespace: input.namespace,\n }),\n OPENAI_COMPATIBLE_BASE_URL: baseUrl,\n }\n}\n\nexport function shouldCopyServerRuntimeEnvKey(key: string) {\n if (MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS.has(key)) return false\n return !SENSITIVE_SERVER_ENV_PATTERN.test(key)\n}\n"}, "b5a77eabbea6cf3afad75aad4ad46e7a11599612": {"t": 1785747945.489822, "n": 3134, "h": "3e71da45b72c6260", "c": "import { signModelProxyToken } from './model-proxy-token'\n\nexport const MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS = new Set([\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_AUTH_TOKEN',\n 'OPENAI_API_KEY',\n 'GEMINI_API_KEY',\n 'GOOGLE_API_KEY',\n 'GOOGLE_AI_API_KEY',\n 'DEEPSEEK_API_KEY',\n 'DASHSCOPE_API_KEY',\n 'ALIBABA_API_KEY',\n 'QWEN_API_KEY',\n 'MINIMAX_API_KEY',\n 'MOONSHOT_API_KEY',\n 'KIMI_API_KEY',\n 'ZAI_API_KEY',\n 'ZHIPUAI_API_KEY',\n 'GLM_API_KEY',\n 'BIGMODEL_API_KEY',\n 'OPENROUTER_API_KEY',\n 'XAI_API_KEY',\n 'GROK_API_KEY',\n 'OPENAI_COMPATIBLE_API_KEY',\n 'SHADOW_MODEL_PROXY_UPSTREAM_API_KEY',\n 'MODEL_PROXY_TOKEN_SECRET',\n 'JWT_SECRET',\n])\n\nconst SENSITIVE_SERVER_ENV_PATTERN =\n /(^|_)(API_KEY|AUTH_TOKEN|TOKEN|SECRET|PASSWORD|PRIVATE_KEY|CREDENTIAL|ACCESS_KEY)$/i\n\nexport function isOfficialModelProxyEnabled() {\n return process.env.SHADOW_MODEL_PROXY_ENABLED !== 'false'\n}\n\nfunction firstNonEmptyEnv(...keys: string[]) {\n for (const key of keys) {\n const value = process.env[key]?.trim()\n if (value) return value\n }\n return null\n}\n\nexport function officialModelProxyMissingConfig(runtimeServerUrl?: string): string[] {\n if (!isOfficialModelProxyEnabled()) return ['SHADOW_MODEL_PROXY_ENABLED']\n\n const missing: string[] = []\n if (!runtimeServerUrl) missing.push('SHADOW_SERVER_URL or SHADOW_AGENT_SERVER_URL')\n if (!firstNonEmptyEnv('SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL')) {\n missing.push('SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL')\n }\n if (!firstNonEmptyEnv('SHADOW_MODEL_PROXY_UPSTREAM_API_KEY')) {\n missing.push('SHADOW_MODEL_PROXY_UPSTREAM_API_KEY')\n }\n return missing\n}\n\nexport function assertOfficialModelProxyAvailable(runtimeServerUrl?: string) {\n const missing = officialModelProxyMissingConfig(runtimeServerUrl)\n if (missing.length === 0) return\n\n throw Object.assign(\n new Error(`Official model provider is unavailable: missing ${missing.join(', ')}`),\n {\n status: 503,\n code: 'OFFICIAL_MODEL_PROVIDER_UNCONFIGURED',\n missing,\n },\n )\n}\n\nexport function officialModelProxyModel() {\n return (\n firstNonEmptyEnv('SHADOW_MODEL_PROXY_MODEL', 'SHADOW_MODEL_PROXY_DEFAULT_MODEL') ??\n 'deepseek-v4-flash'\n )\n}\n\nexport function officialModelProxyBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/v1`\n}\n\nexport function officialModelProxyEnvVars(input: {\n runtimeServerUrl?: string\n userId: string\n playId?: string\n templateSlug?: string\n namespace?: string\n}) {\n if (officialModelProxyMissingConfig(input.runtimeServerUrl).length > 0) return {}\n const baseUrl = officialModelProxyBaseUrl(input.runtimeServerUrl)\n if (!baseUrl) return {}\n\n return {\n OPENAI_COMPATIBLE_API_KEY: signModelProxyToken({\n userId: input.userId,\n playId: input.playId,\n templateSlug: input.templateSlug,\n namespace: input.namespace,\n }),\n OPENAI_COMPATIBLE_BASE_URL: baseUrl,\n }\n}\n\nexport function shouldCopyServerRuntimeEnvKey(key: string) {\n if (MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS.has(key)) return false\n return !SENSITIVE_SERVER_ENV_PATTERN.test(key)\n}\n"}, "7023f4f150219224b3f36e4c0dc0ee979cab3282": {"t": 1785747947.7049258, "n": 2202, "h": "21cfc7a450b96d02", "c": "import { signModelProxyToken } from './model-proxy-token'\n\nexport const MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS = new Set([\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_AUTH_TOKEN',\n 'OPENAI_API_KEY',\n 'GEMINI_API_KEY',\n 'GOOGLE_API_KEY',\n 'GOOGLE_AI_API_KEY',\n 'DEEPSEEK_API_KEY',\n 'DASHSCOPE_API_KEY',\n 'ALIBABA_API_KEY',\n 'QWEN_API_KEY',\n 'MINIMAX_API_KEY',\n 'MOONSHOT_API_KEY',\n 'KIMI_API_KEY',\n 'ZAI_API_KEY',\n 'ZHIPUAI_API_KEY',\n 'GLM_API_KEY',\n 'BIGMODEL_API_KEY',\n 'OPENROUTER_API_KEY',\n 'XAI_API_KEY',\n 'GROK_API_KEY',\n 'OPENAI_COMPATIBLE_API_KEY',\n 'SHADOW_MODEL_PROXY_UPSTREAM_API_KEY',\n 'MODEL_PROXY_TOKEN_SECRET',\n 'JWT_SECRET',\n])\n\nconst SENSITIVE_SERVER_ENV_PATTERN =\n /(^|_)(API_KEY|AUTH_TOKEN|TOKEN|SECRET|PASSWORD|PRIVATE_KEY|CREDENTIAL|ACCESS_KEY)$/i\n\nexport function isOfficialModelProxyEnabled() {\n return process.env.SHADOW_MODEL_PROXY_ENABLED !== 'false'\n}\n\nfunction firstNonEmptyEnv(...keys: string[]) {\n for (const key of keys) {\n const value = process.env[key]?.trim()\n if (value) return value\n }\n return null\n}\n\nexport function officialModelProxyModel() {\n return (\n firstNonEmptyEnv('SHADOW_MODEL_PROXY_MODEL', 'SHADOW_MODEL_PROXY_DEFAULT_MODEL') ??\n 'deepseek-v4-flash'\n )\n}\n\nexport function officialModelProxyBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/v1`\n}\n\nexport function officialModelProxyEnvVars(input: {\n runtimeServerUrl?: string\n userId: string\n playId?: string\n templateSlug?: string\n namespace?: string\n}) {\n if (!isOfficialModelProxyEnabled()) return {}\n const baseUrl = officialModelProxyBaseUrl(input.runtimeServerUrl)\n if (!baseUrl) return {}\n\n return {\n OPENAI_COMPATIBLE_API_KEY: signModelProxyToken({\n userId: input.userId,\n playId: input.playId,\n templateSlug: input.templateSlug,\n namespace: input.namespace,\n }),\n OPENAI_COMPATIBLE_BASE_URL: baseUrl,\n OPENAI_COMPATIBLE_MODEL_ID: officialModelProxyModel(),\n }\n}\n\nexport function shouldCopyServerRuntimeEnvKey(key: string) {\n if (MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS.has(key)) return false\n return !SENSITIVE_SERVER_ENV_PATTERN.test(key)\n}\n"}, "440dff06de27a4715ca39e29813c7e61d620b9d2": {"t": 1786068273.1661644, "n": 6578, "h": "ea129f723795137a", "c": "import { signModelProxyToken } from './model-proxy-token'\n\nexport const MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS = new Set([\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_AUTH_TOKEN',\n 'OPENAI_API_KEY',\n 'GEMINI_API_KEY',\n 'GOOGLE_API_KEY',\n 'GOOGLE_AI_API_KEY',\n 'DEEPSEEK_API_KEY',\n 'DASHSCOPE_API_KEY',\n 'ALIBABA_API_KEY',\n 'QWEN_API_KEY',\n 'MINIMAX_API_KEY',\n 'MOONSHOT_API_KEY',\n 'KIMI_API_KEY',\n 'ZAI_API_KEY',\n 'ZHIPUAI_API_KEY',\n 'GLM_API_KEY',\n 'BIGMODEL_API_KEY',\n 'OPENROUTER_API_KEY',\n 'XAI_API_KEY',\n 'GROK_API_KEY',\n 'OPENAI_COMPATIBLE_API_KEY',\n 'ANTHROPIC_COMPATIBLE_API_KEY',\n 'SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY',\n 'SHADOWOB_MODEL_PROXY_UPSTREAM_ANTHROPIC_API_KEY',\n 'MODEL_PROXY_TOKEN_SECRET',\n 'JWT_SECRET',\n])\n\nconst SENSITIVE_SERVER_ENV_PATTERN =\n /(^|_)(API_KEY|AUTH_TOKEN|TOKEN|SECRET|PASSWORD|PRIVATE_KEY|CREDENTIAL|ACCESS_KEY)$/i\n\nconst DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT =\n 'SHADOWOB_AGENT_SERVER_URL (or pod-reachable SHADOWOB_SERVER_URL)'\nconst EXPLICIT_RUNTIME_SERVER_URL_ENV = 'SHADOWOB_MODEL_PROXY_RUNTIME_SERVER_URL'\nconst INTERNAL_ONLY_SHADOWOB_RUNTIME_HOSTS = new Set([\n 'localhost',\n '127.0.0.1',\n '0.0.0.0',\n '::1',\n 'host.docker.internal',\n 'host.lima.internal',\n 'server',\n])\nconst LOOPBACK_RUNTIME_HOSTS = new Set(['localhost', '127.0.0.1', '0.0.0.0', '::1'])\n\nexport function isOfficialModelProxyEnabled() {\n return process.env.SHADOWOB_MODEL_PROXY_ENABLED !== 'false'\n}\n\nfunction firstNonEmptyEnv(...keys: string[]) {\n for (const key of keys) {\n const value = process.env[key]?.trim()\n if (value) return value\n }\n return null\n}\n\nexport function isInternalOnlyShadowRuntimeUrl(rawUrl?: string) {\n if (!rawUrl?.trim()) return false\n\n try {\n const parsed = new URL(rawUrl)\n const hostname = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, '')\n return INTERNAL_ONLY_SHADOWOB_RUNTIME_HOSTS.has(hostname)\n } catch {\n return false\n }\n}\n\nfunction explicitModelProxyRuntimeServerUrl(rawUrl?: string) {\n if (!rawUrl?.trim()) return null\n try {\n const parsed = new URL(rawUrl.trim())\n const hostname = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, '')\n if (\n (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') ||\n LOOPBACK_RUNTIME_HOSTS.has(hostname)\n ) {\n return null\n }\n return parsed.toString().replace(/\\/+$/, '')\n } catch {\n return null\n }\n}\n\nexport function resolveOfficialModelProxyRuntimeServerUrl(input: {\n shadowServerUrl?: string\n modelProxyRuntimeServerUrl?: string\n}): {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement: string\n} {\n const requestedExplicitUrl =\n input.modelProxyRuntimeServerUrl ?? process.env[EXPLICIT_RUNTIME_SERVER_URL_ENV]\n if (requestedExplicitUrl?.trim()) {\n const explicitUrl = explicitModelProxyRuntimeServerUrl(requestedExplicitUrl)\n return explicitUrl\n ? {\n runtimeServerUrl: explicitUrl,\n runtimeServerUrlRequirement: EXPLICIT_RUNTIME_SERVER_URL_ENV,\n }\n : {\n runtimeServerUrl: undefined,\n runtimeServerUrlRequirement: `${EXPLICIT_RUNTIME_SERVER_URL_ENV} (must be a pod-reachable HTTP(S) URL, not loopback)`,\n }\n }\n\n const shadowServerUrl = input.shadowServerUrl?.trim()\n if (shadowServerUrl && !isInternalOnlyShadowRuntimeUrl(shadowServerUrl)) {\n return {\n runtimeServerUrl: shadowServerUrl,\n runtimeServerUrlRequirement: DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n }\n\n return {\n runtimeServerUrl: undefined,\n runtimeServerUrlRequirement: shadowServerUrl\n ? 'SHADOWOB_AGENT_SERVER_URL (current SHADOWOB_SERVER_URL is internal-only)'\n : DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n }\n}\n\nexport function officialModelProxyMissingConfig(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement = DEFAULT_RUNTIME_SERVER_URL_REQUIREMENT,\n): string[] {\n if (!isOfficialModelProxyEnabled()) return ['SHADOWOB_MODEL_PROXY_ENABLED']\n\n const missing: string[] = []\n if (!runtimeServerUrl) missing.push(runtimeServerUrlRequirement)\n if (!firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL')) {\n missing.push('SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL')\n }\n if (!firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY')) {\n missing.push('SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY')\n }\n return missing\n}\n\nexport function assertOfficialModelProxyAvailable(\n runtimeServerUrl?: string,\n runtimeServerUrlRequirement?: string,\n) {\n const missing = officialModelProxyMissingConfig(runtimeServerUrl, runtimeServerUrlRequirement)\n if (missing.length === 0) return\n\n throw Object.assign(\n new Error(`Official model provider is unavailable: missing ${missing.join(', ')}`),\n {\n status: 503,\n code: 'OFFICIAL_MODEL_PROVIDER_UNCONFIGURED',\n missing,\n },\n )\n}\n\nexport function officialModelProxyModel() {\n return (\n firstNonEmptyEnv('SHADOWOB_MODEL_PROXY_MODEL', 'SHADOWOB_MODEL_PROXY_DEFAULT_MODEL') ??\n 'deepseek-v4-flash'\n )\n}\n\nexport function officialModelProxyBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/v1`\n}\n\nexport function officialModelProxyAnthropicBaseUrl(runtimeServerUrl?: string) {\n if (!runtimeServerUrl) return null\n return `${runtimeServerUrl.replace(/\\/+$/, '')}/api/ai/anthropic`\n}\n\nexport function officialModelProxyEnvVars(input: {\n runtimeServerUrl?: string\n runtimeServerUrlRequirement?: string\n userId: string\n playId?: string\n templateSlug?: string\n namespace?: string\n}) {\n if (\n officialModelProxyMissingConfig(input.runtimeServerUrl, input.runtimeServerUrlRequirement)\n .length > 0\n ) {\n return {}\n }\n const baseUrl = officialModelProxyBaseUrl(input.runtimeServerUrl)\n const anthropicBaseUrl = officialModelProxyAnthropicBaseUrl(input.runtimeServerUrl)\n if (!baseUrl || !anthropicBaseUrl) return {}\n const token = signModelProxyToken({\n userId: input.userId,\n playId: input.playId,\n templateSlug: input.templateSlug,\n namespace: input.namespace,\n })\n const model = officialModelProxyModel()\n\n return {\n SHADOWOB_MODEL_PROVIDER_ID: 'shadow-official',\n OPENAI_COMPATIBLE_BASE_URL: baseUrl,\n OPENAI_COMPATIBLE_API_KEY: token,\n OPENAI_COMPATIBLE_MODEL_ID: model,\n ANTHROPIC_COMPATIBLE_BASE_URL: anthropicBaseUrl,\n ANTHROPIC_COMPATIBLE_API_KEY: token,\n ANTHROPIC_COMPATIBLE_MODEL_ID: model,\n }\n}\n\nexport function shouldCopyServerRuntimeEnvKey(key: string) {\n if (MODEL_PROVIDER_SERVER_SECRET_ENV_KEYS.has(key)) return false\n return !SENSITIVE_SERVER_ENV_PATTERN.test(key)\n}\n"}}, "docker-compose.yml": {"c70fa777c96d5a220fd8f1154acc5425cbcb4d63": {"t": 1785746332.6667573, "n": 7895, "h": "09a393c5dfeb306a", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 20\n start_period: 30s\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOWOB_DISABLE_RATE_LIMITS: ${SHADOWOB_DISABLE_RATE_LIMITS:-false}\n SHADOWOB_DIY_CLOUD_DAILY_LIMIT: ${SHADOWOB_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOWOB_SERVER_URL: ${SHADOWOB_SERVER_URL:-http://host.lima.internal:3002}\n SHADOWOB_PROVISION_URL: ${SHADOWOB_PROVISION_URL:-http://server:3002}\n SHADOWOB_SPACE_APP_ALLOW_PRIVATE_HOSTS: ${SHADOWOB_SPACE_APP_ALLOW_PRIVATE_HOSTS:-host.lima.internal}\n SHADOWOB_SPACE_APP_DEMO_MANIFEST_URL: ${SHADOWOB_SPACE_APP_DEMO_MANIFEST_URL:-}\n SHADOWOB_SPACE_APP_CATALOG_MANIFEST_URLS: ${SHADOWOB_SPACE_APP_CATALOG_MANIFEST_URLS:-}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOWOB_CLAUDE_RUNNER_IMAGE: ${SHADOWOB_CLAUDE_RUNNER_IMAGE:-}\n SHADOWOB_CODEX_RUNNER_IMAGE: ${SHADOWOB_CODEX_RUNNER_IMAGE:-}\n SHADOWOB_GEMINI_RUNNER_IMAGE: ${SHADOWOB_GEMINI_RUNNER_IMAGE:-}\n SHADOWOB_OPENCODE_RUNNER_IMAGE: ${SHADOWOB_OPENCODE_RUNNER_IMAGE:-}\n SHADOWOB_HERMES_RUNNER_IMAGE: ${SHADOWOB_HERMES_RUNNER_IMAGE:-}\n SHADOWOB_MODEL_PROXY_ENABLED: ${SHADOWOB_MODEL_PROXY_ENABLED:-true}\n SHADOWOB_MODEL_PROXY_MODEL: ${SHADOWOB_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOWOB_MODEL_PROXY_BILLING_MODE: ${SHADOWOB_MODEL_PROXY_BILLING_MODE:-}\n SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n AGORA_APP_ID: ${AGORA_APP_ID:-}\n AGORA_APP_CERTIFICATE: ${AGORA_APP_CERTIFICATE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-deployment}\n CLOUD_COMPUTER_BROWSER_IMAGE: ${CLOUD_COMPUTER_BROWSER_IMAGE:-mcr.microsoft.com/playwright:v1.59.1-noble}\n CLOUD_COMPUTER_BROWSER_PROFILE_STORAGE_CLASS: ${CLOUD_COMPUTER_BROWSER_PROFILE_STORAGE_CLASS:-standard}\n CLOUD_COMPUTER_DESKTOP_IMAGE: ${CLOUD_COMPUTER_DESKTOP_IMAGE:-dorowu/ubuntu-desktop-lxde-vnc:latest}\n CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE: ${CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE:-shadow/workspace-mount:dev}\n CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE_PULL_POLICY: ${CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE_PULL_POLICY:-IfNotPresent}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n args:\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "40c0b2f2ce3ba13bb04e27d6b8c29f8c1f15451b": {"t": 1785747939.6267319, "n": 7895, "h": "09a393c5dfeb306a", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 20\n start_period: 30s\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOWOB_DISABLE_RATE_LIMITS: ${SHADOWOB_DISABLE_RATE_LIMITS:-false}\n SHADOWOB_DIY_CLOUD_DAILY_LIMIT: ${SHADOWOB_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOWOB_SERVER_URL: ${SHADOWOB_SERVER_URL:-http://host.lima.internal:3002}\n SHADOWOB_PROVISION_URL: ${SHADOWOB_PROVISION_URL:-http://server:3002}\n SHADOWOB_SPACE_APP_ALLOW_PRIVATE_HOSTS: ${SHADOWOB_SPACE_APP_ALLOW_PRIVATE_HOSTS:-host.lima.internal}\n SHADOWOB_SPACE_APP_DEMO_MANIFEST_URL: ${SHADOWOB_SPACE_APP_DEMO_MANIFEST_URL:-}\n SHADOWOB_SPACE_APP_CATALOG_MANIFEST_URLS: ${SHADOWOB_SPACE_APP_CATALOG_MANIFEST_URLS:-}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOWOB_CLAUDE_RUNNER_IMAGE: ${SHADOWOB_CLAUDE_RUNNER_IMAGE:-}\n SHADOWOB_CODEX_RUNNER_IMAGE: ${SHADOWOB_CODEX_RUNNER_IMAGE:-}\n SHADOWOB_GEMINI_RUNNER_IMAGE: ${SHADOWOB_GEMINI_RUNNER_IMAGE:-}\n SHADOWOB_OPENCODE_RUNNER_IMAGE: ${SHADOWOB_OPENCODE_RUNNER_IMAGE:-}\n SHADOWOB_HERMES_RUNNER_IMAGE: ${SHADOWOB_HERMES_RUNNER_IMAGE:-}\n SHADOWOB_MODEL_PROXY_ENABLED: ${SHADOWOB_MODEL_PROXY_ENABLED:-true}\n SHADOWOB_MODEL_PROXY_MODEL: ${SHADOWOB_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOWOB_MODEL_PROXY_BILLING_MODE: ${SHADOWOB_MODEL_PROXY_BILLING_MODE:-}\n SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n AGORA_APP_ID: ${AGORA_APP_ID:-}\n AGORA_APP_CERTIFICATE: ${AGORA_APP_CERTIFICATE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-deployment}\n CLOUD_COMPUTER_BROWSER_IMAGE: ${CLOUD_COMPUTER_BROWSER_IMAGE:-mcr.microsoft.com/playwright:v1.59.1-noble}\n CLOUD_COMPUTER_BROWSER_PROFILE_STORAGE_CLASS: ${CLOUD_COMPUTER_BROWSER_PROFILE_STORAGE_CLASS:-standard}\n CLOUD_COMPUTER_DESKTOP_IMAGE: ${CLOUD_COMPUTER_DESKTOP_IMAGE:-dorowu/ubuntu-desktop-lxde-vnc:latest}\n CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE: ${CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE:-shadow/workspace-mount:dev}\n CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE_PULL_POLICY: ${CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE_PULL_POLICY:-IfNotPresent}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n args:\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "853b60ae37943663606fa113bdb6c8b7d7b7f1a6": {"t": 1785747940.7302485, "n": 7901, "h": "1a9c2fd4f33f48c1", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 20\n start_period: 30s\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOWOB_DISABLE_RATE_LIMITS: ${SHADOWOB_DISABLE_RATE_LIMITS:-false}\n SHADOWOB_DIY_CLOUD_DAILY_LIMIT: ${SHADOWOB_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOWOB_SERVER_URL: ${SHADOWOB_SERVER_URL:-http://host.lima.internal:3002}\n SHADOWOB_PROVISION_URL: ${SHADOWOB_PROVISION_URL:-http://server:3002}\n SHADOWOB_SERVER_APP_ALLOW_PRIVATE_HOSTS: ${SHADOWOB_SERVER_APP_ALLOW_PRIVATE_HOSTS:-host.lima.internal}\n SHADOWOB_SERVER_APP_DEMO_MANIFEST_URL: ${SHADOWOB_SERVER_APP_DEMO_MANIFEST_URL:-}\n SHADOWOB_SERVER_APP_CATALOG_MANIFEST_URLS: ${SHADOWOB_SERVER_APP_CATALOG_MANIFEST_URLS:-}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOWOB_CLAUDE_RUNNER_IMAGE: ${SHADOWOB_CLAUDE_RUNNER_IMAGE:-}\n SHADOWOB_CODEX_RUNNER_IMAGE: ${SHADOWOB_CODEX_RUNNER_IMAGE:-}\n SHADOWOB_GEMINI_RUNNER_IMAGE: ${SHADOWOB_GEMINI_RUNNER_IMAGE:-}\n SHADOWOB_OPENCODE_RUNNER_IMAGE: ${SHADOWOB_OPENCODE_RUNNER_IMAGE:-}\n SHADOWOB_HERMES_RUNNER_IMAGE: ${SHADOWOB_HERMES_RUNNER_IMAGE:-}\n SHADOWOB_MODEL_PROXY_ENABLED: ${SHADOWOB_MODEL_PROXY_ENABLED:-true}\n SHADOWOB_MODEL_PROXY_MODEL: ${SHADOWOB_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOWOB_MODEL_PROXY_BILLING_MODE: ${SHADOWOB_MODEL_PROXY_BILLING_MODE:-}\n SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n AGORA_APP_ID: ${AGORA_APP_ID:-}\n AGORA_APP_CERTIFICATE: ${AGORA_APP_CERTIFICATE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-deployment}\n CLOUD_COMPUTER_BROWSER_IMAGE: ${CLOUD_COMPUTER_BROWSER_IMAGE:-mcr.microsoft.com/playwright:v1.59.1-noble}\n CLOUD_COMPUTER_BROWSER_PROFILE_STORAGE_CLASS: ${CLOUD_COMPUTER_BROWSER_PROFILE_STORAGE_CLASS:-standard}\n CLOUD_COMPUTER_DESKTOP_IMAGE: ${CLOUD_COMPUTER_DESKTOP_IMAGE:-dorowu/ubuntu-desktop-lxde-vnc:latest}\n CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE: ${CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE:-shadow/workspace-mount:dev}\n CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE_PULL_POLICY: ${CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE_PULL_POLICY:-IfNotPresent}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n args:\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "b013fd236a220ebc076ec05dc8e51f59e753c583": {"t": 1785747941.8501987, "n": 7338, "h": "96cfba50669702c8", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 20\n start_period: 30s\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOWOB_DISABLE_RATE_LIMITS: ${SHADOWOB_DISABLE_RATE_LIMITS:-false}\n SHADOWOB_DIY_CLOUD_DAILY_LIMIT: ${SHADOWOB_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOWOB_SERVER_URL: ${SHADOWOB_SERVER_URL:-http://host.lima.internal:3002}\n SHADOWOB_PROVISION_URL: ${SHADOWOB_PROVISION_URL:-http://server:3002}\n SHADOWOB_SERVER_APP_ALLOW_PRIVATE_HOSTS: ${SHADOWOB_SERVER_APP_ALLOW_PRIVATE_HOSTS:-host.lima.internal}\n SHADOWOB_SERVER_APP_DEMO_MANIFEST_URL: ${SHADOWOB_SERVER_APP_DEMO_MANIFEST_URL:-}\n SHADOWOB_SERVER_APP_CATALOG_MANIFEST_URLS: ${SHADOWOB_SERVER_APP_CATALOG_MANIFEST_URLS:-}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOWOB_CLAUDE_RUNNER_IMAGE: ${SHADOWOB_CLAUDE_RUNNER_IMAGE:-}\n SHADOWOB_CODEX_RUNNER_IMAGE: ${SHADOWOB_CODEX_RUNNER_IMAGE:-}\n SHADOWOB_GEMINI_RUNNER_IMAGE: ${SHADOWOB_GEMINI_RUNNER_IMAGE:-}\n SHADOWOB_OPENCODE_RUNNER_IMAGE: ${SHADOWOB_OPENCODE_RUNNER_IMAGE:-}\n SHADOWOB_HERMES_RUNNER_IMAGE: ${SHADOWOB_HERMES_RUNNER_IMAGE:-}\n SHADOWOB_MODEL_PROXY_ENABLED: ${SHADOWOB_MODEL_PROXY_ENABLED:-true}\n SHADOWOB_MODEL_PROXY_MODEL: ${SHADOWOB_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOWOB_MODEL_PROXY_BILLING_MODE: ${SHADOWOB_MODEL_PROXY_BILLING_MODE:-}\n SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n AGORA_APP_ID: ${AGORA_APP_ID:-}\n AGORA_APP_CERTIFICATE: ${AGORA_APP_CERTIFICATE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-deployment}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n args:\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "89618c0fb17a464ddb26ed613fa6865538fd4de8": {"t": 1785747943.1592035, "n": 7268, "h": "84a5cce749bcea2e", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 20\n start_period: 30s\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOW_DISABLE_RATE_LIMITS: ${SHADOW_DISABLE_RATE_LIMITS:-false}\n SHADOW_DIY_CLOUD_DAILY_LIMIT: ${SHADOW_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS: ${SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS:-host.lima.internal}\n SHADOW_SERVER_APP_DEMO_MANIFEST_URL: ${SHADOW_SERVER_APP_DEMO_MANIFEST_URL:-}\n SHADOW_SERVER_APP_CATALOG_MANIFEST_URLS: ${SHADOW_SERVER_APP_CATALOG_MANIFEST_URLS:-}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOWOB_CLAUDE_RUNNER_IMAGE: ${SHADOWOB_CLAUDE_RUNNER_IMAGE:-}\n SHADOWOB_CODEX_RUNNER_IMAGE: ${SHADOWOB_CODEX_RUNNER_IMAGE:-}\n SHADOWOB_GEMINI_RUNNER_IMAGE: ${SHADOWOB_GEMINI_RUNNER_IMAGE:-}\n SHADOWOB_OPENCODE_RUNNER_IMAGE: ${SHADOWOB_OPENCODE_RUNNER_IMAGE:-}\n SHADOWOB_HERMES_RUNNER_IMAGE: ${SHADOWOB_HERMES_RUNNER_IMAGE:-}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n AGORA_APP_ID: ${AGORA_APP_ID:-}\n AGORA_APP_CERTIFICATE: ${AGORA_APP_CERTIFICATE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-deployment}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n args:\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "e13348ec10ec83787f4219a7212313e3631f26ff": {"t": 1785747944.2273622, "n": 7208, "h": "f523662992eba098", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 20\n start_period: 30s\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOW_DISABLE_RATE_LIMITS: ${SHADOW_DISABLE_RATE_LIMITS:-false}\n SHADOW_DIY_CLOUD_DAILY_LIMIT: ${SHADOW_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS: ${SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS:-host.lima.internal}\n SHADOW_SERVER_APP_DEMO_MANIFEST_URL: ${SHADOW_SERVER_APP_DEMO_MANIFEST_URL:-}\n SHADOW_SERVER_APP_CATALOG_MANIFEST_URLS: ${SHADOW_SERVER_APP_CATALOG_MANIFEST_URLS:-}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOWOB_CLAUDE_RUNNER_IMAGE: ${SHADOWOB_CLAUDE_RUNNER_IMAGE:-}\n SHADOWOB_CODEX_RUNNER_IMAGE: ${SHADOWOB_CODEX_RUNNER_IMAGE:-}\n SHADOWOB_GEMINI_RUNNER_IMAGE: ${SHADOWOB_GEMINI_RUNNER_IMAGE:-}\n SHADOWOB_OPENCODE_RUNNER_IMAGE: ${SHADOWOB_OPENCODE_RUNNER_IMAGE:-}\n SHADOWOB_HERMES_RUNNER_IMAGE: ${SHADOWOB_HERMES_RUNNER_IMAGE:-}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n AGORA_APP_ID: ${AGORA_APP_ID:-}\n AGORA_APP_CERTIFICATE: ${AGORA_APP_CERTIFICATE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-deployment}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "6e98bdd8b6f29c5a3e7e18be2ba64eea3e0d53fb": {"t": 1785747945.3290284, "n": 6856, "h": "0654f11fd2371d26", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 20\n start_period: 30s\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOW_DISABLE_RATE_LIMITS: ${SHADOW_DISABLE_RATE_LIMITS:-false}\n SHADOW_DIY_CLOUD_DAILY_LIMIT: ${SHADOW_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS: ${SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS:-host.lima.internal}\n SHADOW_SERVER_APP_DEMO_MANIFEST_URL: ${SHADOW_SERVER_APP_DEMO_MANIFEST_URL:-}\n SHADOW_SERVER_APP_CATALOG_MANIFEST_URLS: ${SHADOW_SERVER_APP_CATALOG_MANIFEST_URLS:-}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n AGORA_APP_ID: ${AGORA_APP_ID:-}\n AGORA_APP_CERTIFICATE: ${AGORA_APP_CERTIFICATE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-deployment}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "473e6a162c6c84048e806a93fc8d7196f3ecf9e6": {"t": 1785747946.4253366, "n": 7393, "h": "03c249d544e5c8a8", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 20\n start_period: 30s\n\n # ── Application ───────────────────────────────────\n shadow-server-app-demo:\n build:\n context: ./skills/shadow-server-app/example-app\n dockerfile: Dockerfile\n restart: unless-stopped\n ports:\n - \"4199:4199\"\n environment:\n PORT: 4199\n SHADOW_SERVER_URL: ${SHADOW_SERVER_APP_DEMO_SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_APP_PUBLIC_BASE_URL: ${SHADOW_SERVER_APP_DEMO_PUBLIC_BASE_URL:-http://localhost:4199}\n SHADOW_APP_API_BASE_URL: ${SHADOW_SERVER_APP_DEMO_API_BASE_URL:-http://shadow-server-app-demo:4199}\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOW_DISABLE_RATE_LIMITS: ${SHADOW_DISABLE_RATE_LIMITS:-false}\n SHADOW_DIY_CLOUD_DAILY_LIMIT: ${SHADOW_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS: ${SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS:-shadow-server-app-demo}\n SHADOW_SERVER_APP_DEMO_MANIFEST_URL: ${SHADOW_SERVER_APP_DEMO_MANIFEST_URL:-http://shadow-server-app-demo:4199/.well-known/shadow-app.json}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n AGORA_APP_ID: ${AGORA_APP_ID:-}\n AGORA_APP_CERTIFICATE: ${AGORA_APP_CERTIFICATE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-deployment}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "60733c9913567eb2ca63b1ffbfa71f33b707aadc": {"t": 1785747947.5101602, "n": 7368, "h": "9175f1e96c75f61e", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n shadow-server-app-demo:\n build:\n context: ./skills/shadow-server-app/example-app\n dockerfile: Dockerfile\n restart: unless-stopped\n ports:\n - \"4199:4199\"\n environment:\n PORT: 4199\n SHADOW_SERVER_URL: ${SHADOW_SERVER_APP_DEMO_SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_APP_PUBLIC_BASE_URL: ${SHADOW_SERVER_APP_DEMO_PUBLIC_BASE_URL:-http://localhost:4199}\n SHADOW_APP_API_BASE_URL: ${SHADOW_SERVER_APP_DEMO_API_BASE_URL:-http://shadow-server-app-demo:4199}\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOW_DISABLE_RATE_LIMITS: ${SHADOW_DISABLE_RATE_LIMITS:-false}\n SHADOW_DIY_CLOUD_DAILY_LIMIT: ${SHADOW_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS: ${SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS:-shadow-server-app-demo}\n SHADOW_SERVER_APP_DEMO_MANIFEST_URL: ${SHADOW_SERVER_APP_DEMO_MANIFEST_URL:-http://shadow-server-app-demo:4199/.well-known/shadow-app.json}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n AGORA_APP_ID: ${AGORA_APP_ID:-}\n AGORA_APP_CERTIFICATE: ${AGORA_APP_CERTIFICATE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-deployment}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "0ac50fef588ba5db20f9e815ed0fcf17618864d1": {"t": 1785747948.728487, "n": 7274, "h": "95fc1fb714c3868e", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n shadow-server-app-demo:\n build:\n context: ./skills/shadow-server-app/example-app\n dockerfile: Dockerfile\n restart: unless-stopped\n ports:\n - \"4199:4199\"\n environment:\n PORT: 4199\n SHADOW_SERVER_URL: ${SHADOW_SERVER_APP_DEMO_SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_APP_PUBLIC_BASE_URL: ${SHADOW_SERVER_APP_DEMO_PUBLIC_BASE_URL:-http://localhost:4199}\n SHADOW_APP_API_BASE_URL: ${SHADOW_SERVER_APP_DEMO_API_BASE_URL:-http://shadow-server-app-demo:4199}\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOW_DISABLE_RATE_LIMITS: ${SHADOW_DISABLE_RATE_LIMITS:-false}\n SHADOW_DIY_CLOUD_DAILY_LIMIT: ${SHADOW_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS: ${SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS:-shadow-server-app-demo}\n SHADOW_SERVER_APP_DEMO_MANIFEST_URL: ${SHADOW_SERVER_APP_DEMO_MANIFEST_URL:-http://shadow-server-app-demo:4199/.well-known/shadow-app.json}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-deployment}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "4b3d743352a3d93e01af0d60a646f52c12b0fc33": {"t": 1785747949.831767, "n": 6805, "h": "06a90b6df8a409b0", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n shadow-server-app-demo:\n build:\n context: ./skills/shadow-server-app/example-app\n dockerfile: Dockerfile\n restart: unless-stopped\n ports:\n - \"4199:4199\"\n environment:\n PORT: 4199\n SHADOW_SERVER_URL: ${SHADOW_SERVER_APP_DEMO_SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_APP_PUBLIC_BASE_URL: ${SHADOW_SERVER_APP_DEMO_PUBLIC_BASE_URL:-http://localhost:4199}\n SHADOW_APP_API_BASE_URL: ${SHADOW_SERVER_APP_DEMO_API_BASE_URL:-http://shadow-server-app-demo:4199}\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOW_DISABLE_RATE_LIMITS: ${SHADOW_DISABLE_RATE_LIMITS:-false}\n SHADOW_DIY_CLOUD_DAILY_LIMIT: ${SHADOW_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS: ${SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS:-shadow-server-app-demo}\n SHADOW_SERVER_APP_DEMO_MANIFEST_URL: ${SHADOW_SERVER_APP_DEMO_MANIFEST_URL:-http://shadow-server-app-demo:4199/.well-known/shadow-app.json}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "21fb82e46765c01e650c6ec2e9cf2fdf156a4860": {"t": 1785747950.9197187, "n": 6800, "h": "8a56a62d8c3df621", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n shadow-server-app-demo:\n build:\n context: ./examples/shadow-server-app-demo\n dockerfile: Dockerfile\n restart: unless-stopped\n ports:\n - \"4199:4199\"\n environment:\n PORT: 4199\n SHADOW_SERVER_URL: ${SHADOW_SERVER_APP_DEMO_SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_APP_PUBLIC_BASE_URL: ${SHADOW_SERVER_APP_DEMO_PUBLIC_BASE_URL:-http://localhost:4199}\n SHADOW_APP_API_BASE_URL: ${SHADOW_SERVER_APP_DEMO_API_BASE_URL:-http://shadow-server-app-demo:4199}\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOW_DISABLE_RATE_LIMITS: ${SHADOW_DISABLE_RATE_LIMITS:-false}\n SHADOW_DIY_CLOUD_DAILY_LIMIT: ${SHADOW_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS: ${SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS:-shadow-server-app-demo}\n SHADOW_SERVER_APP_DEMO_MANIFEST_URL: ${SHADOW_SERVER_APP_DEMO_MANIFEST_URL:-http://shadow-server-app-demo:4199/.well-known/shadow-app.json}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "333b42e9d8f22c7f1e69dfc48ec58b5e5e7f1731": {"t": 1785747952.122669, "n": 6969, "h": "6aacfd0021b9ff49", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n shadow-server-app-demo:\n build:\n context: ./examples/shadow-server-app-demo\n dockerfile: Dockerfile\n restart: unless-stopped\n ports:\n - \"4199:4199\"\n environment:\n PORT: 4199\n SHADOW_SERVER_URL: ${SHADOW_SERVER_APP_DEMO_SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_APP_PUBLIC_BASE_URL: ${SHADOW_SERVER_APP_DEMO_PUBLIC_BASE_URL:-http://localhost:4199}\n SHADOW_APP_API_BASE_URL: ${SHADOW_SERVER_APP_DEMO_API_BASE_URL:-http://shadow-server-app-demo:4199}\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOW_DISABLE_RATE_LIMITS: ${SHADOW_DISABLE_RATE_LIMITS:-false}\n SHADOW_DIY_CLOUD_DAILY_LIMIT: ${SHADOW_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS: ${SHADOW_SERVER_APP_ALLOW_PRIVATE_HOSTS:-shadow-server-app-demo}\n SHADOW_SERVER_APP_DEMO_MANIFEST_URL: ${SHADOW_SERVER_APP_DEMO_MANIFEST_URL:-http://shadow-server-app-demo:4199/.well-known/shadow-app.json}\n SHADOW_SERVER_APP_DEMO_SECRET: ${SHADOW_SERVER_APP_DEMO_SECRET:-dev-demo-secret-change-me-please}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n shadow-server-app-demo:\n condition: service_started\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "3448360ec4299db5002119323cc8604d38272dd5": {"t": 1785747953.6085365, "n": 6041, "h": "8b203c7adaff2236", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOW_DISABLE_RATE_LIMITS: ${SHADOW_DISABLE_RATE_LIMITS:-false}\n SHADOW_DIY_CLOUD_DAILY_LIMIT: ${SHADOW_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "24b217928195073bce88a0f047aefbf5f80a9a48": {"t": 1785747954.697885, "n": 5926, "h": "9d5f5d26f44097c6", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOW_DISABLE_RATE_LIMITS: ${SHADOW_DISABLE_RATE_LIMITS:-false}\n SHADOW_DIY_CLOUD_DAILY_LIMIT: ${SHADOW_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "b5a77eabbea6cf3afad75aad4ad46e7a11599612": {"t": 1785747955.770051, "n": 5783, "h": "0b1ddb977b8832af", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "7994d40dac171a110caaa46c1d70cf32d61850ee": {"t": 1785747956.9041872, "n": 5449, "h": "35962f9fe129d280", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_PRICE_PER_1K: ${SHADOW_MODEL_PROXY_INPUT_PRICE_PER_1K:-1}\n SHADOW_MODEL_PROXY_OUTPUT_PRICE_PER_1K: ${SHADOW_MODEL_PROXY_OUTPUT_PRICE_PER_1K:-2}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "7e74155a4cf16ea0ac23f72b3a152b5bb11957c0": {"t": 1785747958.1595592, "n": 5543, "h": "3b702776f508954b", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_PRICE_PER_1K: ${SHADOW_MODEL_PROXY_INPUT_PRICE_PER_1K:-1}\n SHADOW_MODEL_PROXY_OUTPUT_PRICE_PER_1K: ${SHADOW_MODEL_PROXY_OUTPUT_PRICE_PER_1K:-2}\n DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:-}\n DEEPSEEK_BASE_URL: ${DEEPSEEK_BASE_URL:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "e365758e1db430ed074b0cc5294318f35ce1e268": {"t": 1785747959.2211418, "n": 5498, "h": "150dc71749c4ee2d", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_PRICE_PER_1K: ${SHADOW_MODEL_PROXY_INPUT_PRICE_PER_1K:-1}\n SHADOW_MODEL_PROXY_OUTPUT_PRICE_PER_1K: ${SHADOW_MODEL_PROXY_OUTPUT_PRICE_PER_1K:-2}\n DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:-}\n DEEPSEEK_BASE_URL: ${DEEPSEEK_BASE_URL:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///root/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG:-/root/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG:-/root/.kube/config}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "78bdbb6347909037e70ce9f89f187c528137024a": {"t": 1785747960.8618135, "n": 5420, "h": "a157509817d34880", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_PRICE_PER_1K: ${SHADOW_MODEL_PROXY_INPUT_PRICE_PER_1K:-1}\n SHADOW_MODEL_PROXY_OUTPUT_PRICE_PER_1K: ${SHADOW_MODEL_PROXY_OUTPUT_PRICE_PER_1K:-2}\n DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:-}\n DEEPSEEK_BASE_URL: ${DEEPSEEK_BASE_URL:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///root/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG:-/root/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG:-/root/.kube/config}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "7023f4f150219224b3f36e4c0dc0ee979cab3282": {"t": 1785747962.9287903, "n": 5152, "h": "dfbbcbdde6d9fba3", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_PRICE_PER_1K: ${SHADOW_MODEL_PROXY_INPUT_PRICE_PER_1K:-1}\n SHADOW_MODEL_PROXY_OUTPUT_PRICE_PER_1K: ${SHADOW_MODEL_PROXY_OUTPUT_PRICE_PER_1K:-2}\n DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:-}\n DEEPSEEK_BASE_URL: ${DEEPSEEK_BASE_URL:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///root/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG:-/root/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG:-/root/.kube/config}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "3a8b8fafbd91332e29258202e4789e9d7880397f": {"t": 1785747964.164295, "n": 4275, "h": "e1e741240503bc25", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:-http://host.lima.internal:3002}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///root/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG:-/root/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG:-/root/.kube/config}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "4c7568a636555d9b88dbcc46c4436bf17cb8e722": {"t": 1785747965.2190437, "n": 3836, "h": "fbe23225520806a9", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\n cloud-worker:\n build:\n context: .\n dockerfile: apps/cloud/Dockerfile.worker\n restart: unless-stopped\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3000}\n KUBECONFIG: ${KUBECONFIG:-}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG:-/dev/null}:ro\n depends_on:\n postgres:\n condition: service_healthy\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "d3edd9863e395a6a80e76c67c10e3c4e0a23da6c": {"t": 1785747966.3459513, "n": 3490, "h": "99b6fcc54fb1d907", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\n cloud-worker:\n build:\n context: .\n dockerfile: apps/cloud/Dockerfile.worker\n restart: unless-stopped\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n depends_on:\n postgres:\n condition: service_healthy\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "3ee771945befa481406f8aaf73d0d543fdf42fc0": {"t": 1785747967.468244, "n": 3384, "h": "00bfafaa80d157d3", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\n cloud-worker:\n build:\n context: .\n dockerfile: apps/cloud/Dockerfile.worker\n restart: unless-stopped\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n depends_on:\n postgres:\n condition: service_healthy\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "7f968087dda0687192baede0f8487ad3984f926e": {"t": 1785747968.541287, "n": 2937, "h": "3cc11fa5354ba4cc", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - '5432:5432'\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U shadow']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - '16379:6379'\n volumes:\n - redis_data:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - '9000:9000'\n - '9001:9001'\n volumes:\n - minio_data:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "235951588aa300548134303150966bebf5e94ee2": {"t": 1785747969.6252787, "n": 2834, "h": "0428d22857fc020d", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - '5432:5432'\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U shadow']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - '16379:6379'\n volumes:\n - redis_data:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - '9000:9000'\n - '9001:9001'\n volumes:\n - minio_data:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "9f28e4915f8d2906528cc4a3e0636a6e311a02ad": {"t": 1785747970.6878734, "n": 2829, "h": "9e249a200e6b3feb", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - '5432:5432'\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U shadow']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - '16379:6379'\n volumes:\n - redis_data:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - '9000:9000'\n - '9001:9001'\n volumes:\n - minio_data:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-secret}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "b6d83285e884d8729fddac8c2d7b8a198bf6e7a4": {"t": 1785747971.8661563, "n": 2667, "h": "bb97cd8862afcc82", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - '5432:5432'\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U shadow']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - '16379:6379'\n volumes:\n - redis_data:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - '9000:9000'\n - '9001:9001'\n volumes:\n - minio_data:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-secret}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "c97c76de7e3f0268d66095e5d06567adb4ac8619": {"t": 1785747972.9457166, "n": 2404, "h": "f7daa602338ecdc0", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - '5432:5432'\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U shadow']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - '16379:6379'\n volumes:\n - redis_data:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - '9000:9000'\n - '9001:9001'\n volumes:\n - minio_data:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-secret}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "533c25e8ac5aac51eb0f0d2b12abf2555f0030de": {"t": 1785747974.3084347, "n": 2402, "h": "8298a3f3633e2aba", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - '5432:5432'\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U shadow']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - '16379:6379'\n volumes:\n - redis_data:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - '9000:9000'\n - '9001:9001'\n volumes:\n - minio_data:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n # ── Application ───────────────────────────────────\n server:\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-secret}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadow.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}, "440dff06de27a4715ca39e29813c7e61d620b9d2": {"t": 1786068427.8325834, "n": 7895, "h": "09a393c5dfeb306a", "c": "services:\n # ── Infrastructure ────────────────────────────────\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n ports:\n - \"5432:5432\"\n volumes:\n - pg_data:/var/lib/postgresql/data\n healthcheck:\n test: [ \"CMD-SHELL\", \"pg_isready -U shadow\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n ports:\n - \"16379:6379\"\n volumes:\n - redis_data:/data\n healthcheck:\n test: [ \"CMD\", \"redis-cli\", \"ping\" ]\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data\n healthcheck:\n test: [ \"CMD\", \"mc\", \"ready\", \"local\" ]\n interval: 5s\n timeout: 3s\n retries: 20\n start_period: 30s\n\n server:\n image: shadow/runtime:dev\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/server\n cache_to:\n - type=local,dest=.docker-cache/server,mode=max\n restart: unless-stopped\n ports:\n - \"3002:3002\"\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n SHADOWOB_DISABLE_RATE_LIMITS: ${SHADOWOB_DISABLE_RATE_LIMITS:-false}\n SHADOWOB_DIY_CLOUD_DAILY_LIMIT: ${SHADOWOB_DIY_CLOUD_DAILY_LIMIT:-24}\n ENABLE_DEV_TOPUP: ${ENABLE_DEV_TOPUP:-0}\n JWT_SECRET: ${JWT_SECRET:-shadow-dev-jwt-secret-do-not-use-in-production}\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: false\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123456}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:-http://localhost:3000}\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}\n GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}\n GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}\n EMAIL_OTP_WEBHOOK_URL: ${EMAIL_OTP_WEBHOOK_URL:-}\n RESEND_API_KEY: ${RESEND_API_KEY:-}\n RESEND_FROM: ${RESEND_FROM:-}\n SMTP_HOST: ${SMTP_HOST:-}\n SMTP_PORT: ${SMTP_PORT:-587}\n SMTP_SECURE: ${SMTP_SECURE:-false}\n SMTP_USER: ${SMTP_USER:-}\n SMTP_PASSWORD: ${SMTP_PASSWORD:-}\n SMTP_FROM: ${SMTP_FROM:-}\n CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000,http://localhost:3001}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:-0000000000000000000000000000000000000000000000000000000000000000}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOWOB_SERVER_URL: ${SHADOWOB_SERVER_URL:-http://host.lima.internal:3002}\n SHADOWOB_PROVISION_URL: ${SHADOWOB_PROVISION_URL:-http://server:3002}\n SHADOWOB_SPACE_APP_ALLOW_PRIVATE_HOSTS: ${SHADOWOB_SPACE_APP_ALLOW_PRIVATE_HOSTS:-host.lima.internal}\n SHADOWOB_SPACE_APP_DEMO_MANIFEST_URL: ${SHADOWOB_SPACE_APP_DEMO_MANIFEST_URL:-}\n SHADOWOB_SPACE_APP_CATALOG_MANIFEST_URLS: ${SHADOWOB_SPACE_APP_CATALOG_MANIFEST_URLS:-}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n SHADOWOB_CLAUDE_RUNNER_IMAGE: ${SHADOWOB_CLAUDE_RUNNER_IMAGE:-}\n SHADOWOB_CODEX_RUNNER_IMAGE: ${SHADOWOB_CODEX_RUNNER_IMAGE:-}\n SHADOWOB_GEMINI_RUNNER_IMAGE: ${SHADOWOB_GEMINI_RUNNER_IMAGE:-}\n SHADOWOB_OPENCODE_RUNNER_IMAGE: ${SHADOWOB_OPENCODE_RUNNER_IMAGE:-}\n SHADOWOB_HERMES_RUNNER_IMAGE: ${SHADOWOB_HERMES_RUNNER_IMAGE:-}\n SHADOWOB_MODEL_PROXY_ENABLED: ${SHADOWOB_MODEL_PROXY_ENABLED:-true}\n SHADOWOB_MODEL_PROXY_MODEL: ${SHADOWOB_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOWOB_MODEL_PROXY_BILLING_MODE: ${SHADOWOB_MODEL_PROXY_BILLING_MODE:-}\n SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n AGORA_APP_ID: ${AGORA_APP_ID:-}\n AGORA_APP_CERTIFICATE: ${AGORA_APP_CERTIFICATE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:-}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-host.lima.internal}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-deployment}\n CLOUD_COMPUTER_BROWSER_IMAGE: ${CLOUD_COMPUTER_BROWSER_IMAGE:-mcr.microsoft.com/playwright:v1.59.1-noble}\n CLOUD_COMPUTER_BROWSER_PROFILE_STORAGE_CLASS: ${CLOUD_COMPUTER_BROWSER_PROFILE_STORAGE_CLASS:-standard}\n CLOUD_COMPUTER_DESKTOP_IMAGE: ${CLOUD_COMPUTER_DESKTOP_IMAGE:-dorowu/ubuntu-desktop-lxde-vnc:latest}\n CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE: ${CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE:-shadow/workspace-mount:dev}\n CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE_PULL_POLICY: ${CLOUD_COMPUTER_WORKSPACE_MOUNT_IMAGE_PULL_POLICY:-IfNotPresent}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n args:\n GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}\n cache_from:\n - type=local,src=.docker-cache/web\n cache_to:\n - type=local,dest=.docker-cache/web,mode=max\n restart: unless-stopped\n ports:\n - \"3000:3000\"\n depends_on:\n - server\n\n admin:\n build:\n context: .\n dockerfile: apps/admin/Dockerfile\n cache_from:\n - type=local,src=.docker-cache/admin\n cache_to:\n - type=local,dest=.docker-cache/admin,mode=max\n restart: unless-stopped\n ports:\n - \"3001:3001\"\n depends_on:\n - server\n\nvolumes:\n pg_data:\n redis_data:\n minio_data:\n"}}, "docker-compose.prod.yml": {"c70fa777c96d5a220fd8f1154acc5425cbcb4d63": {"t": 1785746360.8606863, "n": 6999, "h": "b2c532fe088c9ed6", "c": "# Production docker-compose for public deployment.\n#\n# Runtime hosts should pull CI-built application images instead of building\n# from source. The app image defaults match .github/workflows/publish-prod-images.yml.\n#\n# Usage:\n# docker compose -f docker-compose.prod.yml pull server web admin\n# docker compose -f docker-compose.prod.yml up -d --remove-orphans --no-build\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n image: ${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}/${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}/shadow-server:${SHADOWOB_IMAGE_TAG:-latest}\n pull_policy: always\n env_file:\n - path: .env\n required: false\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n CORS_ORIGIN: ${CORS_ORIGIN:?CORS_ORIGIN is required}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOWOB_MODEL_PROXY_ENABLED: ${SHADOWOB_MODEL_PROXY_ENABLED:-true}\n SHADOWOB_MODEL_PROXY_MODEL: ${SHADOWOB_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOWOB_MODEL_PROXY_BILLING_MODE: ${SHADOWOB_MODEL_PROXY_BILLING_MODE:-}\n SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:?KMS_MASTER_KEY is required}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOWOB_SERVER_URL: ${SHADOWOB_SERVER_URL:?SHADOWOB_SERVER_URL is required}\n SHADOWOB_AGENT_SERVER_URL: ${SHADOWOB_AGENT_SERVER_URL:-}\n SHADOWOB_PROVISION_URL: ${SHADOWOB_PROVISION_URL:-http://server:3002}\n SHADOWOB_RUNNER_IMAGE_REGISTRY: ${SHADOWOB_RUNNER_IMAGE_REGISTRY:-${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}}\n SHADOWOB_RUNNER_IMAGE_NAMESPACE: ${SHADOWOB_RUNNER_IMAGE_NAMESPACE:-${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}}\n SHADOWOB_RUNNER_IMAGE_TAG: ${SHADOWOB_RUNNER_IMAGE_TAG:-${SHADOWOB_IMAGE_TAG:-latest}}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-}\n SHADOWOB_CLAUDE_RUNNER_IMAGE: ${SHADOWOB_CLAUDE_RUNNER_IMAGE:-}\n SHADOWOB_CODEX_RUNNER_IMAGE: ${SHADOWOB_CODEX_RUNNER_IMAGE:-}\n SHADOWOB_OPENCODE_RUNNER_IMAGE: ${SHADOWOB_OPENCODE_RUNNER_IMAGE:-}\n SHADOWOB_HERMES_RUNNER_IMAGE: ${SHADOWOB_HERMES_RUNNER_IMAGE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:?PULUMI_CONFIG_PASSPHRASE is required}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-auto}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n image: ${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}/${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}/shadow-web:${SHADOWOB_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n image: ${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}/${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}/shadow-admin:${SHADOWOB_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n name: ${SHADOWOB_POSTGRES_VOLUME:-shadow_pgdata}\n redisdata:\n name: ${SHADOWOB_REDIS_VOLUME:-shadow_redisdata}\n miniodata:\n name: ${SHADOWOB_MINIO_VOLUME:-shadow_miniodata}\n"}, "a8c1ad311f1d030c6f3bd79d7716bbdcbb1d86a8": {"t": 1785747939.4921014, "n": 6999, "h": "b2c532fe088c9ed6", "c": "# Production docker-compose for public deployment.\n#\n# Runtime hosts should pull CI-built application images instead of building\n# from source. The app image defaults match .github/workflows/publish-prod-images.yml.\n#\n# Usage:\n# docker compose -f docker-compose.prod.yml pull server web admin\n# docker compose -f docker-compose.prod.yml up -d --remove-orphans --no-build\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n image: ${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}/${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}/shadow-server:${SHADOWOB_IMAGE_TAG:-latest}\n pull_policy: always\n env_file:\n - path: .env\n required: false\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n CORS_ORIGIN: ${CORS_ORIGIN:?CORS_ORIGIN is required}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOWOB_MODEL_PROXY_ENABLED: ${SHADOWOB_MODEL_PROXY_ENABLED:-true}\n SHADOWOB_MODEL_PROXY_MODEL: ${SHADOWOB_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOWOB_MODEL_PROXY_BILLING_MODE: ${SHADOWOB_MODEL_PROXY_BILLING_MODE:-}\n SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:?KMS_MASTER_KEY is required}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOWOB_SERVER_URL: ${SHADOWOB_SERVER_URL:?SHADOWOB_SERVER_URL is required}\n SHADOWOB_AGENT_SERVER_URL: ${SHADOWOB_AGENT_SERVER_URL:-}\n SHADOWOB_PROVISION_URL: ${SHADOWOB_PROVISION_URL:-http://server:3002}\n SHADOWOB_RUNNER_IMAGE_REGISTRY: ${SHADOWOB_RUNNER_IMAGE_REGISTRY:-${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}}\n SHADOWOB_RUNNER_IMAGE_NAMESPACE: ${SHADOWOB_RUNNER_IMAGE_NAMESPACE:-${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}}\n SHADOWOB_RUNNER_IMAGE_TAG: ${SHADOWOB_RUNNER_IMAGE_TAG:-${SHADOWOB_IMAGE_TAG:-latest}}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-}\n SHADOWOB_CLAUDE_RUNNER_IMAGE: ${SHADOWOB_CLAUDE_RUNNER_IMAGE:-}\n SHADOWOB_CODEX_RUNNER_IMAGE: ${SHADOWOB_CODEX_RUNNER_IMAGE:-}\n SHADOWOB_OPENCODE_RUNNER_IMAGE: ${SHADOWOB_OPENCODE_RUNNER_IMAGE:-}\n SHADOWOB_HERMES_RUNNER_IMAGE: ${SHADOWOB_HERMES_RUNNER_IMAGE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:?PULUMI_CONFIG_PASSPHRASE is required}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-auto}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n image: ${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}/${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}/shadow-web:${SHADOWOB_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n image: ${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}/${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}/shadow-admin:${SHADOWOB_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n name: ${SHADOWOB_POSTGRES_VOLUME:-shadow_pgdata}\n redisdata:\n name: ${SHADOWOB_REDIS_VOLUME:-shadow_redisdata}\n miniodata:\n name: ${SHADOWOB_MINIO_VOLUME:-shadow_miniodata}\n"}, "b013fd236a220ebc076ec05dc8e51f59e753c583": {"t": 1785747940.694849, "n": 6377, "h": "34f6857bf961ac93", "c": "# Production docker-compose for public deployment.\n#\n# Runtime hosts should pull CI-built application images instead of building\n# from source. The app image defaults match .github/workflows/publish-prod-images.yml.\n#\n# Usage:\n# docker compose -f docker-compose.prod.yml pull server web admin\n# docker compose -f docker-compose.prod.yml up -d --remove-orphans --no-build\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n image: ${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}/${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}/shadow-server:${SHADOWOB_IMAGE_TAG:-latest}\n pull_policy: always\n env_file:\n - path: .env\n required: false\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n CORS_ORIGIN: ${CORS_ORIGIN:?CORS_ORIGIN is required}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOWOB_MODEL_PROXY_ENABLED: ${SHADOWOB_MODEL_PROXY_ENABLED:-true}\n SHADOWOB_MODEL_PROXY_MODEL: ${SHADOWOB_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOWOB_MODEL_PROXY_BILLING_MODE: ${SHADOWOB_MODEL_PROXY_BILLING_MODE:-}\n SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:?KMS_MASTER_KEY is required}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOWOB_SERVER_URL: ${SHADOWOB_SERVER_URL:?SHADOWOB_SERVER_URL is required}\n SHADOWOB_PROVISION_URL: ${SHADOWOB_PROVISION_URL:-http://server:3002}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:?PULUMI_CONFIG_PASSPHRASE is required}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-auto}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n image: ${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}/${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}/shadow-web:${SHADOWOB_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n image: ${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}/${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}/shadow-admin:${SHADOWOB_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n name: ${SHADOWOB_POSTGRES_VOLUME:-shadow_pgdata}\n redisdata:\n name: ${SHADOWOB_REDIS_VOLUME:-shadow_redisdata}\n miniodata:\n name: ${SHADOWOB_MINIO_VOLUME:-shadow_miniodata}\n"}, "af8f70249cc9b7e3a4ec72b88a6efd376ccc3511": {"t": 1785747941.797135, "n": 6307, "h": "a0fd563f688c27dd", "c": "# Production docker-compose for public deployment.\n#\n# Runtime hosts should pull CI-built application images instead of building\n# from source. The app image defaults match .github/workflows/publish-prod-images.yml.\n#\n# Usage:\n# docker compose -f docker-compose.prod.yml pull server web admin\n# docker compose -f docker-compose.prod.yml up -d --remove-orphans --no-build\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-server:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n env_file:\n - path: .env\n required: false\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n CORS_ORIGIN: ${CORS_ORIGIN:?CORS_ORIGIN is required}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:?KMS_MASTER_KEY is required}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:?SHADOW_AGENT_SERVER_URL is required}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:?PULUMI_CONFIG_PASSPHRASE is required}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-auto}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-web:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-admin:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n name: ${SHADOW_POSTGRES_VOLUME:-shadow_pgdata}\n redisdata:\n name: ${SHADOW_REDIS_VOLUME:-shadow_redisdata}\n miniodata:\n name: ${SHADOW_MINIO_VOLUME:-shadow_miniodata}\n"}, "b8c8b781ec2d529251ee8902c2c98eae51910a5e": {"t": 1785747943.3100324, "n": 6279, "h": "8ee6fc332874e1e4", "c": "# Production docker-compose for public deployment.\n#\n# Runtime hosts should pull CI-built application images instead of building\n# from source. The app image defaults match .github/workflows/publish-prod-images.yml.\n#\n# Usage:\n# docker compose -f docker-compose.prod.yml pull server web admin\n# docker compose -f docker-compose.prod.yml up -d\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-server:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n env_file:\n - path: .env\n required: false\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n CORS_ORIGIN: ${CORS_ORIGIN:?CORS_ORIGIN is required}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:?KMS_MASTER_KEY is required}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:?SHADOW_AGENT_SERVER_URL is required}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:?PULUMI_CONFIG_PASSPHRASE is required}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-auto}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-web:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-admin:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n name: ${SHADOW_POSTGRES_VOLUME:-shadow_pgdata}\n redisdata:\n name: ${SHADOW_REDIS_VOLUME:-shadow_redisdata}\n miniodata:\n name: ${SHADOW_MINIO_VOLUME:-shadow_miniodata}\n"}, "0ac50fef588ba5db20f9e815ed0fcf17618864d1": {"t": 1785747944.5441697, "n": 6285, "h": "7434d4e5dd0c5e85", "c": "# Production docker-compose for public deployment.\n#\n# Runtime hosts should pull CI-built application images instead of building\n# from source. The app image defaults match .github/workflows/publish-prod-images.yml.\n#\n# Usage:\n# docker compose -f docker-compose.prod.yml pull server web admin\n# docker compose -f docker-compose.prod.yml up -d\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-server:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n env_file:\n - path: .env\n required: false\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n CORS_ORIGIN: ${CORS_ORIGIN:?CORS_ORIGIN is required}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:?KMS_MASTER_KEY is required}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOW_SERVER_URL: ${SHADOW_SERVER_URL:-http://server:3002}\n SHADOW_AGENT_SERVER_URL: ${SHADOW_AGENT_SERVER_URL:?SHADOW_AGENT_SERVER_URL is required}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-ghcr.io/buggyblues/openclaw-runner:latest}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:?PULUMI_CONFIG_PASSPHRASE is required}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-deployment}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-web:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-admin:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n name: ${SHADOW_POSTGRES_VOLUME:-shadow_pgdata}\n redisdata:\n name: ${SHADOW_REDIS_VOLUME:-shadow_redisdata}\n miniodata:\n name: ${SHADOW_MINIO_VOLUME:-shadow_miniodata}\n"}, "ff2ef5d5007965193129829e9cf74bbd1d85916f": {"t": 1785747945.627144, "n": 4816, "h": "b2a6413637b0b1fe", "c": "# Production docker-compose for public deployment.\n#\n# Runtime hosts should pull CI-built application images instead of building\n# from source. The app image defaults match .github/workflows/publish-prod-images.yml.\n#\n# Usage:\n# docker compose -f docker-compose.prod.yml pull server web admin\n# docker compose -f docker-compose.prod.yml up -d\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-server:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n env_file:\n - path: .env\n required: false\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n CORS_ORIGIN: ${CORS_ORIGIN:?CORS_ORIGIN is required}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-web:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-admin:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n name: ${SHADOW_POSTGRES_VOLUME:-shadow_pgdata}\n redisdata:\n name: ${SHADOW_REDIS_VOLUME:-shadow_redisdata}\n miniodata:\n name: ${SHADOW_MINIO_VOLUME:-shadow_miniodata}\n"}, "fb03fce1d3df21a03cb3f1b452c49466fdbf9aa0": {"t": 1785747946.712107, "n": 4663, "h": "3a5a43fa7fa7b7ff", "c": "# Production docker-compose for public deployment.\n#\n# Runtime hosts should pull CI-built application images instead of building\n# from source. The app image defaults match .github/workflows/publish-prod-images.yml.\n#\n# Usage:\n# docker compose -f docker-compose.prod.yml pull server web admin\n# docker compose -f docker-compose.prod.yml up -d\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-server:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n env_file:\n - path: .env\n required: false\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n CORS_ORIGIN: ${CORS_ORIGIN:?CORS_ORIGIN is required}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-web:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-admin:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n redisdata:\n miniodata:\n"}, "00e6629104970f046ae502f90cb528d8a407c0d9": {"t": 1785747947.8108552, "n": 4409, "h": "df9fcfaf60263292", "c": "# Production docker-compose for public deployment.\n#\n# Runtime hosts should pull CI-built application images instead of building\n# from source. The app image defaults match .github/workflows/publish-prod-images.yml.\n#\n# Usage:\n# docker compose -f docker-compose.prod.yml pull server web\n# docker compose -f docker-compose.prod.yml up -d\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-server:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n env_file:\n - path: .env\n required: false\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n CORS_ORIGIN: ${CORS_ORIGIN:?CORS_ORIGIN is required}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-web:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n redisdata:\n miniodata:\n"}, "a578ab44b27d7efcc8ddcd0f7a904d7515066536": {"t": 1785747948.8988967, "n": 4352, "h": "0d6adbbd4359e94c", "c": "# Production docker-compose for public deployment.\n#\n# Runtime hosts should pull CI-built application images instead of building\n# from source. The app image defaults match .github/workflows/publish-prod-images.yml.\n#\n# Usage:\n# docker compose -f docker-compose.prod.yml pull server web\n# docker compose -f docker-compose.prod.yml up -d\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-server:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n CORS_ORIGIN: ${CORS_ORIGIN:?CORS_ORIGIN is required}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-web:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n redisdata:\n miniodata:\n"}, "f578d7c67f6ca248dd3bd2c54cbb85748d596002": {"t": 1785747949.998231, "n": 4293, "h": "6a1e14eaea811f5d", "c": "# Production docker-compose for public deployment.\n#\n# Runtime hosts should pull CI-built application images instead of building\n# from source. The app image defaults match .github/workflows/publish-prod-images.yml.\n#\n# Usage:\n# docker compose -f docker-compose.prod.yml pull server web\n# docker compose -f docker-compose.prod.yml up -d\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-server:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n image: ${SHADOW_IMAGE_REGISTRY:-ghcr.io}/${SHADOW_IMAGE_NAMESPACE:-buggyblues}/shadow-web:${SHADOW_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n redisdata:\n miniodata:\n"}, "b5a77eabbea6cf3afad75aad4ad46e7a11599612": {"t": 1785747951.0694299, "n": 3984, "h": "64d4248698ee02a2", "c": "# Production docker-compose for public deployment\n# Usage: docker-compose -f docker-compose.prod.yml up -d\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOW_MODEL_PROXY_ENABLED: ${SHADOW_MODEL_PROXY_ENABLED:-true}\n SHADOW_MODEL_PROXY_MODEL: ${SHADOW_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOW_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOW_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOW_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOW_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOW_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOW_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOW_MODEL_PROXY_BILLING_MODE: ${SHADOW_MODEL_PROXY_BILLING_MODE:-}\n SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOW_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n args:\n VITE_API_BASE: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}/api\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n redisdata:\n miniodata:\n"}, "0f30807f5dab2d8066947d69d0aca5ca03187b13": {"t": 1785747952.1420362, "n": 2866, "h": "619faaa859ea162a", "c": "# Production docker-compose for public deployment\n# Usage: docker-compose -f docker-compose.prod.yml up -d\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n args:\n VITE_API_BASE: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}/api\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n redisdata:\n miniodata:"}, "0e4561297793175ffdf912ce3835abf88d696f40": {"t": 1785747953.2702634, "n": 2168, "h": "1b2adaf88e099456", "c": "# Production docker-compose for public deployment\n# Usage: docker-compose -f docker-compose.prod.yml up -d\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: shadow\n POSTGRES_PASSWORD: shadow\n POSTGRES_DB: shadow\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U shadow']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n build:\n context: .\n dockerfile: apps/server/Dockerfile\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://shadow:shadow@postgres:5432/shadow\n REDIS_URL: redis://redis:6379\n JWT_SECRET: shadow-prod-secret-change-me\n JWT_EXPIRES_IN: 7d\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: minioadmin\n MINIO_SECRET_KEY: minioadmin\n MINIO_BUCKET: shadow\n ADMIN_EMAIL: admin@shadowob.app\n ADMIN_PASSWORD: admin123456\n ADMIN_USERNAME: admin\n OAUTH_BASE_URL: http://120.53.105.115:3000\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n build:\n context: .\n dockerfile: apps/web/Dockerfile\n args:\n VITE_API_BASE: http://120.53.105.115:3002\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n redisdata:\n miniodata:"}, "440dff06de27a4715ca39e29813c7e61d620b9d2": {"t": 1786068429.7413251, "n": 6999, "h": "b2c532fe088c9ed6", "c": "# Production docker-compose for public deployment.\n#\n# Runtime hosts should pull CI-built application images instead of building\n# from source. The app image defaults match .github/workflows/publish-prod-images.yml.\n#\n# Usage:\n# docker compose -f docker-compose.prod.yml pull server web admin\n# docker compose -f docker-compose.prod.yml up -d --remove-orphans --no-build\n#\n# ⚠️ All sensitive values MUST be provided via a .env file.\n# See .env.example for required variables.\n\nservices:\n postgres:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}\n POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}\n POSTGRES_DB: ${POSTGRES_DB:-shadow}\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-shadow}']\n interval: 5s\n timeout: 3s\n retries: 5\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n volumes:\n - redisdata:/data\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 5s\n timeout: 3s\n retries: 5\n\n minio:\n image: minio/minio:latest\n restart: unless-stopped\n command: server /data --console-address ':9001'\n environment:\n MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n volumes:\n - miniodata:/data\n healthcheck:\n test: ['CMD', 'mc', 'ready', 'local']\n interval: 5s\n timeout: 3s\n retries: 5\n\n server:\n image: ${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}/${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}/shadow-server:${SHADOWOB_IMAGE_TAG:-latest}\n pull_policy: always\n env_file:\n - path: .env\n required: false\n restart: unless-stopped\n ports:\n - '3002:3002'\n environment:\n DATABASE_URL: postgresql://${POSTGRES_USER:-shadow}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-shadow}\n REDIS_URL: redis://redis:6379\n JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}\n JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}\n PORT: 3002\n HOST: 0.0.0.0\n MINIO_ENDPOINT: minio\n MINIO_PORT: 9000\n MINIO_USE_SSL: 'false'\n MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required}\n MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}\n MINIO_BUCKET: ${MINIO_BUCKET:-shadow}\n ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@shadowob.app}\n ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}\n ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}\n CORS_ORIGIN: ${CORS_ORIGIN:?CORS_ORIGIN is required}\n OAUTH_BASE_URL: ${OAUTH_BASE_URL:?OAUTH_BASE_URL is required}\n STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}\n STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}\n SHADOWOB_MODEL_PROXY_ENABLED: ${SHADOWOB_MODEL_PROXY_ENABLED:-true}\n SHADOWOB_MODEL_PROXY_MODEL: ${SHADOWOB_MODEL_PROXY_MODEL:-deepseek-v4-flash}\n SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL: ${SHADOWOB_MODEL_PROXY_UPSTREAM_BASE_URL:-https://api.deepseek.com}\n SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY: ${SHADOWOB_MODEL_PROXY_UPSTREAM_API_KEY:-}\n SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY: ${SHADOWOB_MODEL_PROXY_SHRIMP_PER_CNY:-20}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_HIT_CNY_PER_MILLION:-0.02}\n SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_INPUT_CACHE_MISS_CNY_PER_MILLION:-1}\n SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION: ${SHADOWOB_MODEL_PROXY_OUTPUT_CNY_PER_MILLION:-2}\n SHADOWOB_MODEL_PROXY_BILLING_MODE: ${SHADOWOB_MODEL_PROXY_BILLING_MODE:-}\n SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_INPUT_TOKENS_PER_SHRIMP:-}\n SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP: ${SHADOWOB_MODEL_PROXY_OUTPUT_TOKENS_PER_SHRIMP:-}\n KMS_MASTER_KEY: ${KMS_MASTER_KEY:?KMS_MASTER_KEY is required}\n CLOUD_TEMPLATES_DIR: /app/apps/cloud/templates\n POLL_INTERVAL_MS: ${CLOUD_WORKER_POLL_INTERVAL_MS:-5000}\n RECONCILE_INTERVAL_MS: ${RECONCILE_INTERVAL_MS:-60000}\n SHADOWOB_SERVER_URL: ${SHADOWOB_SERVER_URL:?SHADOWOB_SERVER_URL is required}\n SHADOWOB_AGENT_SERVER_URL: ${SHADOWOB_AGENT_SERVER_URL:-}\n SHADOWOB_PROVISION_URL: ${SHADOWOB_PROVISION_URL:-http://server:3002}\n SHADOWOB_RUNNER_IMAGE_REGISTRY: ${SHADOWOB_RUNNER_IMAGE_REGISTRY:-${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}}\n SHADOWOB_RUNNER_IMAGE_NAMESPACE: ${SHADOWOB_RUNNER_IMAGE_NAMESPACE:-${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}}\n SHADOWOB_RUNNER_IMAGE_TAG: ${SHADOWOB_RUNNER_IMAGE_TAG:-${SHADOWOB_IMAGE_TAG:-latest}}\n SHADOWOB_OPENCLAW_RUNNER_IMAGE: ${SHADOWOB_OPENCLAW_RUNNER_IMAGE:-}\n SHADOWOB_CLAUDE_RUNNER_IMAGE: ${SHADOWOB_CLAUDE_RUNNER_IMAGE:-}\n SHADOWOB_CODEX_RUNNER_IMAGE: ${SHADOWOB_CODEX_RUNNER_IMAGE:-}\n SHADOWOB_OPENCODE_RUNNER_IMAGE: ${SHADOWOB_OPENCODE_RUNNER_IMAGE:-}\n SHADOWOB_HERMES_RUNNER_IMAGE: ${SHADOWOB_HERMES_RUNNER_IMAGE:-}\n PULUMI_CONFIG_PASSPHRASE: ${PULUMI_CONFIG_PASSPHRASE:?PULUMI_CONFIG_PASSPHRASE is required}\n PULUMI_BACKEND_URL: ${PULUMI_BACKEND_URL:-file:///home/node/.shadowob/pulumi}\n KUBECONFIG: ${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}\n KUBECONFIG_CONTEXT: ${KUBECONFIG_CONTEXT:-}\n KUBECONFIG_LOOPBACK_HOST: ${KUBECONFIG_LOOPBACK_HOST:-}\n CLOUD_SAAS_CLUSTER_CONFIG: ${CLOUD_SAAS_CLUSTER_CONFIG:-}\n CLOUD_SAAS_CLUSTER_KUBECONFIG: ${CLOUD_SAAS_CLUSTER_KUBECONFIG:-}\n CLOUD_SAAS_WORKLOAD_BACKEND: ${CLOUD_SAAS_WORKLOAD_BACKEND:-auto}\n volumes:\n - ${KUBECONFIG_HOST_PATH:-/dev/null}:${KUBECONFIG_CONTAINER_PATH:-/home/node/.kube/config}:ro\n - ${CLOUD_SAAS_CLUSTER_CONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_CONFIG:-/app/cluster.json}:ro\n - ${CLOUD_SAAS_CLUSTER_KUBECONFIG_HOST_PATH:-/dev/null}:${CLOUD_SAAS_CLUSTER_KUBECONFIG:-/home/node/.shadow-cloud/clusters/cluster.yaml}:ro\n depends_on:\n postgres:\n condition: service_healthy\n redis:\n condition: service_healthy\n minio:\n condition: service_healthy\n\n web:\n image: ${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}/${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}/shadow-web:${SHADOWOB_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3000:3000'\n depends_on:\n - server\n\n admin:\n image: ${SHADOWOB_IMAGE_REGISTRY:-ghcr.io}/${SHADOWOB_IMAGE_NAMESPACE:-buggyblues}/shadow-admin:${SHADOWOB_IMAGE_TAG:-latest}\n pull_policy: always\n restart: unless-stopped\n ports:\n - '3001:3001'\n depends_on:\n - server\n\nvolumes:\n pgdata:\n name: ${SHADOWOB_POSTGRES_VOLUME:-shadow_pgdata}\n redisdata:\n name: ${SHADOWOB_REDIS_VOLUME:-shadow_redisdata}\n miniodata:\n name: ${SHADOWOB_MINIO_VOLUME:-shadow_miniodata}\n"}}}}