# syntax=docker/dockerfile:1.7
ARG HERMES_IMAGE=nousresearch/hermes-agent@sha256:d597ca1f766ff23ff86437fe5e0f36a6049166ce91df917d9577d7418f0767de
ARG SLACK_PP_GO_IMAGE=golang@sha256:386d475a660466863d9f8c766fec64d7fdad3edac2c6a05020c09534d71edb4b

FROM ${SLACK_PP_GO_IMAGE} AS slack-pp-cli-builder

ARG SLACK_PP_CLI_PACKAGE=github.com/mvanhorn/printing-press-library/library/productivity/slack/cmd/slack-pp-cli@v0.0.0-20260519210111-529e9728df37
ARG SLACK_PP_CLI_SHA256=2d7289d9e0d7f6ab85e2f650dfb95d1841ea6a1e97c31f74b91e9f0b71b39a8e

RUN set -eux; \
    install -d -m 0755 /out; \
    env GOBIN=/out CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
      go install -trimpath "${SLACK_PP_CLI_PACKAGE}"; \
    test "$(sha256sum /out/slack-pp-cli | cut -d ' ' -f 1)" = "${SLACK_PP_CLI_SHA256}"

FROM ${HERMES_IMAGE}

USER root

ENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright

ARG PRODUCT_MCP_PACKAGE
ARG PRODUCT_MCP_INTEGRITY
ARG PRODUCT_INSTALL_PACKAGE
ARG PRODUCT_INSTALL_INTEGRITY
ARG ADMIN_MCP_PACKAGE
ARG ADMIN_MCP_INTEGRITY
ARG ADMIN_INSTALL_PACKAGE
ARG ADMIN_INSTALL_INTEGRITY
ARG ADMIN_INSTALL_SOURCE=registry
ARG ADMIN_INSTALL_LOCAL_SHA256
ARG ADMIN_LOCKED_TREE_DIGEST
ARG ADMIN_ARTIFACT_DIGEST
ARG ADMIN_PACKAGE_LOCK_B64
ARG ADMIN_PROFILE_CONTRACT_TEMPLATE_B64
ARG MCP_TRUST_ROOT_FINGERPRINT
ARG TUS_JS_CLIENT_VERSION=4.3.1
ARG YAML_VERSION=2.9.0
ARG AGENT_BROWSER_VERSION=0.26.0
ARG PLAYWRIGHT_BROWSER_REVISION=1234
ARG STRIPE_CLI_PACKAGE=@stripe/cli-linux-x64@1.45.0
ARG STRIPE_CLI_INTEGRITY=sha512-1ZhoPpoweYfynqsvhCLlTjZ7lPz5IKtxqAMT5MBy6zrwLRTP9x0T6r8h/jLYL8lRH1c7zC/6X6/XUu2V+r9Bog==
ARG DEFAULT_PROFILE_BUNDLE_FIXTURE_VERSION=1
ARG DEFAULT_PROFILE_BUNDLE_VERSION=1
ARG DEFAULT_PROFILE_BUNDLE_DIGEST=e2e306623a85ab6d3fa35409f9324b9cb583a9b8b12f8de1e33bdbdef98fa30f

COPY --from=slack-pp-cli-builder --chmod=0555 /out/slack-pp-cli /usr/local/bin/slack-pp-cli

RUN --mount=type=secret,id=admin_install_tarball,required=false \
    set -eux; \
    test "${ADMIN_INSTALL_SOURCE}" = "registry" -o "${ADMIN_INSTALL_SOURCE}" = "local-tarball"; \
    test -n "${ADMIN_PACKAGE_LOCK_B64}"; \
    test -n "${ADMIN_PROFILE_CONTRACT_TEMPLATE_B64}"; \
    test "$(npm view "${PRODUCT_MCP_PACKAGE}" dist.integrity)" = "${PRODUCT_MCP_INTEGRITY}"; \
    test "$(npm view "${PRODUCT_INSTALL_PACKAGE}" dist.integrity)" = "${PRODUCT_INSTALL_INTEGRITY}"; \
    test "$(npm view "${ADMIN_MCP_PACKAGE}" dist.integrity)" = "${ADMIN_MCP_INTEGRITY}"; \
    if test "${ADMIN_INSTALL_SOURCE}" = "registry"; then \
      test "$(npm view "${ADMIN_INSTALL_PACKAGE}" dist.integrity)" = "${ADMIN_INSTALL_INTEGRITY}"; \
    else \
      test -s /run/secrets/admin_install_tarball; \
      test -n "${ADMIN_INSTALL_LOCAL_SHA256}"; \
      test "$(sha256sum /run/secrets/admin_install_tarball | cut -d ' ' -f 1)" = "${ADMIN_INSTALL_LOCAL_SHA256}"; \
      test "$(node -e 'const c=require("crypto"),f=require("fs"); process.stdout.write(`sha512-${c.createHash("sha512").update(f.readFileSync(process.argv[1])).digest("base64")}`)' /run/secrets/admin_install_tarball)" = "${ADMIN_INSTALL_INTEGRITY}"; \
    fi; \
    test "$(npm view "${STRIPE_CLI_PACKAGE}" dist.integrity)" = "${STRIPE_CLI_INTEGRITY}"; \
    mkdir -p /usr/local/lib/sellable-agent/admin-artifact; \
    node -e 'const fs=require("fs"); const specs=process.argv.slice(1); fs.writeFileSync("/usr/local/lib/sellable-agent/admin-artifact/package.json", JSON.stringify({name:"sellable-admin-runtime-artifact",private:true,version:"1.0.0",dependencies:Object.fromEntries(specs.map((spec)=>{const at=spec.lastIndexOf("@"); return [spec.slice(0,at),spec.slice(at+1)];}))},null,2)+"\n");' \
      "${PRODUCT_MCP_PACKAGE}" \
      "${PRODUCT_INSTALL_PACKAGE}" \
      "${ADMIN_MCP_PACKAGE}" \
      "${ADMIN_INSTALL_PACKAGE}"; \
    printf '%s' "${ADMIN_PACKAGE_LOCK_B64}" | base64 -d \
      > /usr/local/lib/sellable-agent/admin-artifact/package-lock.json; \
    printf '%s' "${ADMIN_PROFILE_CONTRACT_TEMPLATE_B64}" | base64 -d \
      > /usr/local/lib/sellable-agent/admin-artifact/profile-contract-template.json; \
    test "$(sha256sum /usr/local/lib/sellable-agent/admin-artifact/package-lock.json | cut -d ' ' -f 1)" = "${ADMIN_LOCKED_TREE_DIGEST}"; \
    if test "${ADMIN_INSTALL_SOURCE}" = "local-tarball"; then \
      node -e 'const fs=require("fs"); const packagePath=process.argv[1],lockPath=process.argv[2]; const p=JSON.parse(fs.readFileSync(packagePath)); delete p.dependencies["@sellable/admin-install"]; fs.writeFileSync(packagePath,JSON.stringify(p,null,2)+"\n"); const l=JSON.parse(fs.readFileSync(lockPath)); delete l.packages[""].dependencies["@sellable/admin-install"]; delete l.packages["node_modules/@sellable/admin-install"]; fs.writeFileSync(lockPath,JSON.stringify(l,null,2)+"\n");' \
        /usr/local/lib/sellable-agent/admin-artifact/package.json \
        /usr/local/lib/sellable-agent/admin-artifact/package-lock.json; \
    fi; \
    npm ci \
      --prefix /usr/local/lib/sellable-agent/admin-artifact \
      --ignore-scripts \
      --omit=dev \
      --no-audit \
      --no-fund; \
    if test "${ADMIN_INSTALL_SOURCE}" = "local-tarball"; then \
      npm install \
        --prefix /usr/local/lib/sellable-agent/admin-artifact \
        --ignore-scripts \
        --omit=dev \
        --no-audit \
        --no-fund \
        --no-save \
        --package-lock=false \
        /run/secrets/admin_install_tarball; \
    fi; \
    npm install \
      --prefix /usr/local/lib/sellable-agent \
      --omit=dev \
      --ignore-scripts \
      --no-audit \
      --no-fund \
      "agent-browser@${AGENT_BROWSER_VERSION}" \
      "tus-js-client@${TUS_JS_CLIENT_VERSION}" \
      "yaml@${YAML_VERSION}"; \
    npm install \
      --prefix /usr/local/lib/sellable-agent/stripe-cli \
      --omit=dev \
      --ignore-scripts \
      --no-audit \
      --no-fund \
      "${STRIPE_CLI_PACKAGE}"; \
    install -m 0755 \
      /usr/local/lib/sellable-agent/stripe-cli/node_modules/@stripe/cli-linux-x64/bin/stripe \
      /usr/local/bin/stripe; \
    stripe_cli_version="$(node -p "require('/usr/local/lib/sellable-agent/stripe-cli/node_modules/@stripe/cli-linux-x64/package.json').version")"; \
    test "$(stripe version | head -n 1)" = "stripe version ${stripe_cli_version}"; \
    test "$(node -p "require('/usr/local/lib/sellable-agent/node_modules/tus-js-client/package.json').version")" = "${TUS_JS_CLIENT_VERSION}"; \
    test "$(node -p "require('/usr/local/lib/sellable-agent/node_modules/yaml/package.json').version")" = "${YAML_VERSION}"; \
    test "$(node -p "require('/usr/local/lib/sellable-agent/node_modules/agent-browser/package.json').version")" = "${AGENT_BROWSER_VERSION}"; \
    test -d "/opt/hermes/.playwright/chromium_headless_shell-${PLAYWRIGHT_BROWSER_REVISION}"; \
    ln -sf /usr/local/lib/sellable-agent/node_modules/.bin/agent-browser /usr/local/bin/agent-browser; \
    command -v agent-browser >/dev/null; \
    agent-browser --version | grep -F "${AGENT_BROWSER_VERSION}"; \
    slack-pp-cli --help >/dev/null; \
    test -f /usr/local/lib/sellable-agent/admin-artifact/node_modules/@sellable/install/lib/sellable-agent/admin-runtime-reconciler.mjs; \
    test -f /usr/local/lib/sellable-agent/admin-artifact/node_modules/@sellable/admin-mcp/dist/index.js; \
    node -e 'const p=require("/usr/local/lib/sellable-agent/admin-artifact/node_modules/@sellable/admin-mcp/package.json"); if(p.main!=="dist/index.js" || p.bin?.["sellable-admin-mcp"]!=="dist/index.js") process.exit(1);'; \
    test -f /usr/local/lib/sellable-agent/admin-artifact/node_modules/@sellable/admin-install/lib/hermes-admin-profile-factory.mjs; \
    test -f /usr/local/lib/sellable-agent/admin-artifact/node_modules/@sellable/admin-install/default-profile-bundles/admin/manifest.fragment.json; \
    test "$(node -p "require('/usr/local/lib/sellable-agent/admin-artifact/node_modules/@sellable/admin-install/package.json').version")" = "${ADMIN_INSTALL_PACKAGE##*@}"; \
    node -e 'const fs=require("fs"),c=require("crypto"); const p="/usr/local/lib/sellable-agent/admin-artifact/profile-contract-template.json"; const stable=(v)=>Array.isArray(v)?`[${v.map(stable).join(",")}]`:v&&typeof v==="object"?`{${Object.keys(v).sort().map((k)=>`${JSON.stringify(k)}:${stable(v[k])}`).join(",")}}`:JSON.stringify(v); const t=JSON.parse(fs.readFileSync(p)); const {contentDigest,...body}=t; if(t.schemaVersion!=="sellable-admin-profile-contract-template/v1" || c.createHash("sha256").update(stable(body)).digest("hex")!==contentDigest) process.exit(1);'; \
    rm -f /etc/s6-overlay/s6-rc.d/user/contents.d/dashboard \
          /etc/s6-overlay/s6-rc.d/user/contents.d/main-hermes \
          /etc/cont-init.d/01-hermes-setup \
          /etc/cont-init.d/015-supervise-perms \
          /etc/cont-init.d/02-reconcile-profiles; \
    npm cache clean --force

# The MCP turn trust root is the same build secret the customer image bakes.
# The Admin runtime hands the Product MCP context proxy this exact file plus
# its fingerprint, so the baked bytes must match the pinned signing contract.
RUN --mount=type=secret,id=mcp_trust_root,required=true \
    set -eux; \
    test -s /run/secrets/mcp_trust_root; \
    test -n "${MCP_TRUST_ROOT_FINGERPRINT}"; \
    install -d -m 0755 /usr/local/share/sellable-agent; \
    install -o root -g root -m 0444 /run/secrets/mcp_trust_root \
      /usr/local/share/sellable-agent/mcp-turn-trust-root.pem; \
    test "$(sha256sum /usr/local/share/sellable-agent/mcp-turn-trust-root.pem | cut -d ' ' -f 1)" = "${MCP_TRUST_ROOT_FINGERPRINT}"

COPY fly-admin-image/admin-runtime.mjs /usr/local/lib/sellable-agent/admin-runtime/admin-runtime.mjs
COPY fly-admin-image/admin-runtime-phase-telemetry.mjs /usr/local/lib/sellable-agent/admin-runtime/admin-runtime-phase-telemetry.mjs
COPY fly-admin-image/admin-state-generation.mjs /usr/local/lib/sellable-agent/admin-runtime/admin-state-generation.mjs
COPY fly-admin-image/start-admin-runtime /usr/local/lib/sellable-agent/admin-runtime/start-admin-runtime
COPY fly-customer-image/customer-runtime.mjs /usr/local/lib/sellable-agent/fly-customer-image/customer-runtime.mjs
COPY fly-customer-image/hermes-runs-client.mjs /usr/local/lib/sellable-agent/fly-customer-image/hermes-runs-client.mjs
COPY fly-customer-image/endpoint-uat-completion-gate.mjs /usr/local/lib/sellable-agent/fly-customer-image/endpoint-uat-completion-gate.mjs
COPY admin-native-gateway-supervisor.mjs /usr/local/lib/sellable-agent/admin-native-gateway-supervisor.mjs
COPY admin-endpoint-runtime.mjs /usr/local/lib/sellable-agent/admin-endpoint-runtime.mjs
COPY abandoned-runtime-scratch.mjs /usr/local/lib/sellable-agent/abandoned-runtime-scratch.mjs
COPY fly-customer-model.mjs /usr/local/lib/sellable-agent/fly-customer-model.mjs
COPY fly-customer-worker.mjs /usr/local/lib/sellable-agent/fly-customer-worker.mjs
COPY profile-materializer.mjs /usr/local/lib/sellable-agent/profile-materializer.mjs
COPY mcp-context-proxy.mjs /usr/local/lib/sellable-agent/mcp-context-proxy.mjs
COPY mcp-runtime-binding.mjs /usr/local/lib/sellable-agent/mcp-runtime-binding.mjs
COPY fly-runtime-identity.mjs /usr/local/lib/sellable-agent/fly-runtime-identity.mjs
COPY model-auth-reconciler.mjs /usr/local/lib/sellable-agent/model-auth-reconciler.mjs
COPY model-auth-canary-reseed.mjs /usr/local/lib/sellable-agent/model-auth-canary-reseed.mjs
COPY model-health-reporter.mjs /usr/local/lib/sellable-agent/model-health-reporter.mjs
COPY hermes-bridge.mjs /usr/local/lib/sellable-agent/hermes-bridge.mjs
COPY hermes-memory-snapshot.mjs /usr/local/lib/sellable-agent/hermes-memory-snapshot.mjs
COPY fly-soul-bridge.mjs /usr/local/lib/sellable-agent/fly-soul-bridge.mjs
COPY fly-soul-bridge-exec.mjs /usr/local/lib/sellable-agent/fly-soul-bridge-exec.mjs
COPY fly-skills-bridge.mjs /usr/local/lib/sellable-agent/fly-skills-bridge.mjs
COPY fly-skills-bridge-exec.mjs /usr/local/lib/sellable-agent/fly-skills-bridge-exec.mjs
COPY fly-capabilities-bridge.mjs /usr/local/lib/sellable-agent/fly-capabilities-bridge.mjs
COPY fly-capabilities-bridge-exec.mjs /usr/local/lib/sellable-agent/fly-capabilities-bridge-exec.mjs
COPY soul-artifact-validator.mjs /usr/local/lib/sellable-agent/soul-artifact-validator.mjs
COPY default-profile-bundle.mjs /usr/local/lib/sellable-agent/default-profile-bundle.mjs
COPY default-profile-reconciler.mjs /usr/local/lib/sellable-agent/default-profile-reconciler.mjs
COPY fly-cron-proof-exec.mjs /usr/local/lib/sellable-agent/fly-cron-proof-exec.mjs
COPY default-profile-bundles/shared/ /usr/local/lib/sellable-agent/default-profile-bundles/shared/
COPY default-profile-bundles/fixtures/ /usr/local/lib/sellable-agent/default-profile-bundles/fixtures/
COPY hermes-memory-dirty.mjs /opt/sellable/bin/hermes-memory-dirty
COPY hermes-memory-reconcile.sh /opt/sellable/share/hermes-memory-reconcile.sh
COPY hermes-endpoint-cron.mjs /opt/sellable/bin/hermes-endpoint-cron
COPY fly-admin-image/rootfs/ /

RUN set -eux; \
    fixture_args=""; \
    if test -n "${DEFAULT_PROFILE_BUNDLE_FIXTURE_VERSION}"; then \
      fixture_args="--fixture-version ${DEFAULT_PROFILE_BUNDLE_FIXTURE_VERSION}"; \
    fi; \
    node /usr/local/lib/sellable-agent/default-profile-bundle.mjs \
      --kind ADMIN ${fixture_args} \
      --admin-fragment /usr/local/lib/sellable-agent/admin-artifact/node_modules/@sellable/admin-install/default-profile-bundles/admin/manifest.fragment.json \
      --output /usr/local/share/sellable-agent/default-profile-bundle \
    && node -e \
      'const fs=require("fs"); const manifest=JSON.parse(fs.readFileSync("/usr/local/share/sellable-agent/default-profile-bundle/manifest.json")); if(String(manifest.bundleVersion)!==process.argv[1] || manifest.bundleDigest!==process.argv[2]) process.exit(1);' \
      "${DEFAULT_PROFILE_BUNDLE_VERSION}" "${DEFAULT_PROFILE_BUNDLE_DIGEST}" \
    && node --input-type=module -e \
      'import { installHermesAgentBridge, HERMES_AGENT_BRIDGE_DEDICATED_V020_CONTRACT } from "/usr/local/lib/sellable-agent/hermes-bridge.mjs"; installHermesAgentBridge({ sourceRoot: "/opt/hermes", contract: HERMES_AGENT_BRIDGE_DEDICATED_V020_CONTRACT });' \
    && node --input-type=module -e \
      'await import("/usr/local/lib/sellable-agent/fly-runtime-identity.mjs");' \
    && node --input-type=module -e \
      'await import("/usr/local/lib/sellable-agent/mcp-context-proxy.mjs");' \
    && node --input-type=module -e \
      'await import("/usr/local/lib/sellable-agent/admin-runtime/admin-runtime.mjs");' \
    && install -d -m 0755 /usr/local/share/sellable-agent \
    && printf '%s\n' \
      '#!/usr/bin/env node' \
      'import("file:///usr/local/lib/sellable-agent/fly-soul-bridge.mjs").then(({ runSoulBridgeCli }) => runSoulBridgeCli());' \
      > /usr/local/bin/sellable-soul-bridge \
    && chmod 0555 /usr/local/bin/sellable-soul-bridge \
    && printf '%s\n' \
      '#!/usr/bin/env node' \
      'import("file:///usr/local/lib/sellable-agent/fly-soul-bridge-exec.mjs").then(({ runFlySoulBridgeExecCli }) => runFlySoulBridgeExecCli());' \
      > /usr/local/bin/sellable-soul-bridge-exec \
    && chmod 0555 /usr/local/bin/sellable-soul-bridge-exec \
    && printf '%s\n' \
      '#!/usr/bin/env node' \
      'import("file:///usr/local/lib/sellable-agent/fly-skills-bridge-exec.mjs").then(({ runFlySkillsBridgeExecCli }) => runFlySkillsBridgeExecCli());' \
      > /usr/local/bin/sellable-skills-bridge-exec \
    && chmod 0555 /usr/local/bin/sellable-skills-bridge-exec \
    && printf '%s\n' \
      '#!/usr/bin/env node' \
      'import("file:///usr/local/lib/sellable-agent/fly-capabilities-bridge-exec.mjs").then(({ runFlyCapabilitiesBridgeExecCli }) => runFlyCapabilitiesBridgeExecCli());' \
      > /usr/local/bin/sellable-capabilities-bridge-exec \
    && chmod 0555 /usr/local/bin/sellable-capabilities-bridge-exec \
    && sha256sum /usr/local/lib/sellable-agent/fly-soul-bridge.mjs \
      > /usr/local/share/sellable-agent/soul-bridge-source.sha256 \
    && sha256sum /usr/local/lib/sellable-agent/fly-skills-bridge.mjs \
      /usr/local/lib/sellable-agent/fly-skills-bridge-exec.mjs \
      > /usr/local/share/sellable-agent/skills-bridge-source.sha256 \
    && sha256sum /usr/local/lib/sellable-agent/default-profile-reconciler.mjs \
      /usr/local/lib/sellable-agent/fly-cron-proof-exec.mjs \
      > /usr/local/share/sellable-agent/default-profile-reconcile-source.sha256 \
    && sha256sum /usr/local/lib/sellable-agent/fly-capabilities-bridge.mjs \
      /usr/local/lib/sellable-agent/fly-capabilities-bridge-exec.mjs \
      > /usr/local/share/sellable-agent/capabilities-bridge-source.sha256 \
    && chmod 0444 /usr/local/share/sellable-agent/soul-bridge-source.sha256 \
      /usr/local/share/sellable-agent/skills-bridge-source.sha256 \
      /usr/local/share/sellable-agent/default-profile-reconcile-source.sha256 \
      /usr/local/share/sellable-agent/capabilities-bridge-source.sha256 \
    && chmod 0755 /etc \
    && chmod 0555 \
      /usr/local/lib/sellable-agent/admin-runtime/admin-runtime.mjs \
      /usr/local/lib/sellable-agent/admin-runtime/admin-state-generation.mjs \
      /usr/local/lib/sellable-agent/admin-runtime/start-admin-runtime \
      /usr/local/lib/sellable-agent/fly-customer-image/customer-runtime.mjs \
      /usr/local/lib/sellable-agent/fly-customer-image/hermes-runs-client.mjs \
      /usr/local/lib/sellable-agent/fly-customer-image/endpoint-uat-completion-gate.mjs \
      /usr/local/lib/sellable-agent/admin-native-gateway-supervisor.mjs \
      /usr/local/lib/sellable-agent/admin-endpoint-runtime.mjs \
      /usr/local/lib/sellable-agent/abandoned-runtime-scratch.mjs \
      /usr/local/lib/sellable-agent/fly-customer-model.mjs \
      /usr/local/lib/sellable-agent/fly-customer-worker.mjs \
      /usr/local/lib/sellable-agent/profile-materializer.mjs \
      /usr/local/lib/sellable-agent/mcp-context-proxy.mjs \
      /usr/local/lib/sellable-agent/mcp-runtime-binding.mjs \
      /usr/local/lib/sellable-agent/fly-runtime-identity.mjs \
      /usr/local/lib/sellable-agent/model-auth-reconciler.mjs \
      /usr/local/lib/sellable-agent/model-auth-canary-reseed.mjs \
      /usr/local/lib/sellable-agent/model-health-reporter.mjs \
      /usr/local/lib/sellable-agent/hermes-bridge.mjs \
      /usr/local/lib/sellable-agent/hermes-memory-snapshot.mjs \
      /usr/local/lib/sellable-agent/fly-soul-bridge.mjs \
      /usr/local/lib/sellable-agent/fly-soul-bridge-exec.mjs \
      /usr/local/lib/sellable-agent/fly-skills-bridge.mjs \
      /usr/local/lib/sellable-agent/fly-skills-bridge-exec.mjs \
      /usr/local/lib/sellable-agent/default-profile-reconciler.mjs \
      /usr/local/lib/sellable-agent/fly-cron-proof-exec.mjs \
      /usr/local/lib/sellable-agent/soul-artifact-validator.mjs \
      /opt/sellable/bin/hermes-memory-dirty \
      /opt/sellable/bin/hermes-endpoint-cron \
      /etc/s6-overlay/s6-rc.d/admin-runtime/run \
    && chmod 0444 \
      /opt/sellable/share/hermes-memory-reconcile.sh \
      /etc/s6-overlay/s6-rc.d/admin-runtime/type \
      /etc/s6-overlay/s6-rc.d/user/contents.d/admin-runtime

LABEL io.sellable.runtime.kind="admin" \
      io.sellable.runtime.listener="native-dedicated-slack" \
      io.sellable.runtime.api-server="authenticated-loopback-127.0.0.1:8642" \
      io.sellable.runtime.installers="build-only" \
      io.sellable.runtime.default-profile-bundle-version="${DEFAULT_PROFILE_BUNDLE_VERSION}" \
      io.sellable.runtime.default-profile-bundle-digest="${DEFAULT_PROFILE_BUNDLE_DIGEST}"

ENV SELLABLE_AGENT_ADMIN_RUNTIME=/usr/local/lib/sellable-agent/admin-runtime/admin-runtime.mjs
ENV SELLABLE_AGENT_PRODUCT_MCP_PACKAGE=${PRODUCT_MCP_PACKAGE}
ENV SELLABLE_AGENT_PRODUCT_INSTALL_PACKAGE=${PRODUCT_INSTALL_PACKAGE}
ENV SELLABLE_AGENT_ADMIN_MCP_PACKAGE=${ADMIN_MCP_PACKAGE}
ENV SELLABLE_AGENT_ADMIN_INSTALL_PACKAGE=${ADMIN_INSTALL_PACKAGE}
ENV SELLABLE_AGENT_ADMIN_LOCKED_TREE_DIGEST=${ADMIN_LOCKED_TREE_DIGEST}
ENV SELLABLE_AGENT_ADMIN_ARTIFACT_DIGEST=${ADMIN_ARTIFACT_DIGEST}
ENV SELLABLE_AGENT_DEFAULT_PROFILE_BUNDLE_VERSION=${DEFAULT_PROFILE_BUNDLE_VERSION}
ENV SELLABLE_AGENT_DEFAULT_PROFILE_BUNDLE_DIGEST=${DEFAULT_PROFILE_BUNDLE_DIGEST}
ENV SELLABLE_AGENT_DEFAULT_PROFILE_FIXTURE_TEST_ONLY=1
ENV SELLABLE_AGENT_DEFAULT_PROFILE_FIXTURE_WORKSPACE_ID=cmrz87l040019ih0452rdtq5s
ENV SELLABLE_AGENT_DEFAULT_PROFILE_FIXTURE_AGENT_ID=agent_665e5f64ca144b12f7f6b3ce6fa9f5a1
ENV HOME=/opt/data
ENV HERMES_HOME=/opt/data
ENV HERMES_WRITE_SAFE_ROOT=/opt/data
ENV NODE_ENV=production
ENV SELLABLE_AGENT_RUNTIME=1
ENTRYPOINT ["/init"]
