Skip to content

feat(manifests): add 8 core-derived ACP agent manifests#17

Open
Yiminnn wants to merge 2 commits into
mainfrom
feat/core-acp-manifests
Open

feat(manifests): add 8 core-derived ACP agent manifests#17
Yiminnn wants to merge 2 commits into
mainfrom
feat/core-acp-manifests

Conversation

@Yiminnn

@Yiminnn Yiminnn commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

What

The 8 core-derived ACP agent manifests that benchflow's manifest loader (load_agent_manifest, merged in #14) consumes — the agents-side half of the decouple "running-through" path. Each manifest.toml is the data-only projection of a core AGENTS entry; benchflow merges it with that entry's host-side shim-only fields (subscription_auth, credential_files, …) so a manifest-loaded agent == the original core agent.

Agents: claude-agent-acp, codex-acp, gemini, mimo, openclaw, opencode, openhands, pi-acp.

How it fits

Verified — e2e citation-check, both docker + daytona

All 8 load from these manifests, and the shim-only merge == orig core entry on every dataclass field. End-to-end via benchflow#825:

agent result
pi-acp / opencode / openhands / mimo reward 1.0 (deepseek)
gemini runs via manifest (GEMINI_API_KEY)
codex-acp (ChatGPT subscription) 1.0 on both backends after the #825 subscription fix (gpt-5.5, 7 tool calls)
claude-agent-acp (subscription) 1.0 daytona
openclaw 1.0 daytona

Test plan

  • manifest load + shim-only merge == orig for all 8 (benchflow loader tests).
  • e2e citation-check on docker + daytona via BENCHFLOW_AGENTS_DIR.

Yiminnn added 2 commits June 22, 2026 13:28
Consolidate the core-compatible agent manifests (claude-agent-acp,
codex-acp, gemini, pi-acp, opencode, openhands, openclaw, mimo) as
data-only manifest.toml files under their core-key directories.

All 8 validate strictly against contract/manifest_schema.json (Draft
2020-12) and parse through the core consumer loader
(benchflow.agents.manifest), each yielding a valid AgentConfig. As a
discovery root these 8 register with 8 unique declared names and no
collision.

Note: a standalone, self-contained mimo manifest already lives at
mimo-acp/manifest.toml and also declares name "mimo". The core-derived
mimo lands at mimo/manifest.toml. The two share the declared name "mimo",
so they must NOT sit under one BENCHFLOW_AGENTS_DIR discovery root
(load_agents_from_dir raises duplicate-name). The core-compatible set is
its own discovery root.
@greptile-apps

greptile-apps Bot commented Jun 23, 2026

Copy link
Copy Markdown

Greptile Summary

Adds eight manifest.toml files — one per ACP agent (claude-agent-acp, codex-acp, gemini, mimo, openclaw, opencode, openhands, pi-acp) — that benchflow's manifest loader consumes when BENCHFLOW_AGENTS_DIR is set, acting as the agents-side data-only projection of the corresponding core AGENTS entries.

  • Each manifest declares install_cmd (bootstraps Node.js and installs the agent package), launch_cmd (starts the ACP server), protocol, requires_env, and an [env_mapping] section that translates BENCHFLOW_PROVIDER_* vars into agent-native env vars.
  • Several manifests embed non-trivial logic as base64-encoded shell/Python proxy scripts baked into install_cmd, handling provider config-file generation at launch time (mimo, opencode, openclaw, pi-acp).
  • opencode/manifest.toml is missing the BENCHFLOW_PROVIDER_API_KEY = "OPENAI_API_KEY" entry in [env_mapping]; the opencode-proxy reads OPENAI_API_KEY to populate the provider JSON, so authentication will silently fail unless the key is already in the environment by another means.

Confidence Score: 4/5

Safe to merge with the caveat that opencode's API key mapping should be verified or fixed before relying on it in key-mapped deployments.

Seven of the eight manifests are structurally sound and consistent with each other. The one concrete concern is opencode's missing BENCHFLOW_PROVIDER_API_KEY = OPENAI_API_KEY env_mapping entry — mimo is structurally identical and has it, and the opencode-proxy reads OPENAI_API_KEY directly; without the mapping the agent config is written without credentials. The e2e tests passed, but likely because the test environment had OPENAI_API_KEY already set in the process environment rather than relying on benchflow's mapping. The remaining findings (unescaped printf in codex-acp and openhands, duplicated bootstrap in pi-acp) are low-risk hardening items.

opencode/manifest.toml — verify or add the missing BENCHFLOW_PROVIDER_API_KEY mapping. codex-acp/manifest.toml and openhands/manifest.toml — the printf-based JSON construction is worth hardening against unusual key values.

Important Files Changed

Filename Overview
opencode/manifest.toml Missing BENCHFLOW_PROVIDER_API_KEY → OPENAI_API_KEY env_mapping entry; the opencode-proxy reads OPENAI_API_KEY to populate the provider JSON, so without this mapping the agent will launch without an API key.
codex-acp/manifest.toml launch_cmd writes auth.json via unescaped printf string interpolation; API keys with JSON special chars would produce malformed output, though standard OpenAI keys are alphanumeric.
openhands/manifest.toml launch_cmd builds agent_settings.json via shell printf string interpolation; LLM_MODEL or LLM_API_KEY with embedded quotes would produce malformed JSON, but real-world values are unlikely to trigger this.
pi-acp/manifest.toml Duplicate Node.js bootstrap block in install_cmd inflates manifest size; uses @latest for pi-related packages (unpinned). Python launcher handles env_mapping internally so no env_mapping section needed.
openclaw/manifest.toml Ships a large (~50 KB) base64-encoded Python ACP shim; uses openclaw@latest (unpinned), but the conditional skip-if-present install mitigates reproducibility concerns.
mimo/manifest.toml Ships embedded base64 shell/Python proxy script for provider config; has complete env_mapping with both BASE_URL and API_KEY entries; no issues found.
claude-agent-acp/manifest.toml Clean manifest with pinned npm version, proper requires_env, and complete env_mapping; no issues found.
gemini/manifest.toml Standard manifest with pinned @google/gemini-cli@0.42.0, requires_env, and env_mapping; no issues found.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant BF as benchflow
    participant ML as manifest loader
    participant MF as manifest.toml
    participant AG as agent process

    BF->>ML: load_agent_manifest(BENCHFLOW_AGENTS_DIR)
    ML->>MF: read contract_version, name, install_cmd, launch_cmd, env_mapping
    ML-->>BF: manifest dataclass

    BF->>BF: additive merge(manifest, core AGENTS entry)
    note over BF: shim-only fields added from core

    BF->>AG: run install_cmd
    BF->>BF: "apply env_mapping BENCHFLOW_PROVIDER_* to agent-native vars"
    BF->>AG: exec launch_cmd with mapped env vars
    AG-->>BF: ACP stdio session
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant BF as benchflow
    participant ML as manifest loader
    participant MF as manifest.toml
    participant AG as agent process

    BF->>ML: load_agent_manifest(BENCHFLOW_AGENTS_DIR)
    ML->>MF: read contract_version, name, install_cmd, launch_cmd, env_mapping
    ML-->>BF: manifest dataclass

    BF->>BF: additive merge(manifest, core AGENTS entry)
    note over BF: shim-only fields added from core

    BF->>AG: run install_cmd
    BF->>BF: "apply env_mapping BENCHFLOW_PROVIDER_* to agent-native vars"
    BF->>AG: exec launch_cmd with mapped env vars
    AG-->>BF: ACP stdio session
Loading

Comments Outside Diff (1)

  1. opencode/manifest.toml, line 15-17 (link)

    P1 Missing API key mapping in env_mapping

    The [env_mapping] section only maps BENCHFLOW_PROVIDER_BASE_URL → OPENAI_BASE_URL, but is missing BENCHFLOW_PROVIDER_API_KEY = "OPENAI_API_KEY". The opencode-proxy script (decoded from the base64 blob in install_cmd) reads OPENAI_API_KEY directly to populate opts["apiKey"] in the provider JSON config — if OPENAI_API_KEY is never injected via env_mapping, the config is written without an API key and authentication will silently fail at runtime. The structurally identical mimo/manifest.toml has both mappings and serves as the reference.

Reviews (1): Last reviewed commit: "fix(codex-acp): manifest launch_cmd self..." | Re-trigger Greptile

Comment thread codex-acp/manifest.toml
name = "codex-acp"
description = "OpenAI Codex agent via ACP"
install_cmd = "export DEBIAN_FRONTEND=noninteractive; BF_NODE_DIR=/opt/benchflow/node; BF_NODE_VERSION=22.20.0; if [ ! -x \"$BF_NODE_DIR/bin/node\" ]; then if ! command -v curl >/dev/null 2>&1 || ! command -v tar >/dev/null 2>&1 || ! command -v xz >/dev/null 2>&1; then if command -v apt-get >/dev/null 2>&1; then apt-get update -qq && apt-get install -y -qq curl ca-certificates tar xz-utils; elif command -v dnf >/dev/null 2>&1; then dnf -y install curl ca-certificates tar xz; elif command -v apk >/dev/null 2>&1; then apk add --no-cache curl ca-certificates tar xz; else echo 'BenchFlow JS agent bootstrap requires curl, tar, and xz' >&2; exit 127; fi; fi; arch=\"$(uname -m)\"; case \"$arch\" in x86_64|amd64) node_arch=x64 ;; aarch64|arm64) node_arch=arm64 ;; *) echo \"Unsupported architecture for Node.js: $arch\" >&2; exit 1 ;; esac; tmp=\"$(mktemp -d)\"; mkdir -p /opt/benchflow; curl -fsSLo \"$tmp/node.tar.xz\" \"https://nodejs.org/dist/v${BF_NODE_VERSION}/node-v${BF_NODE_VERSION}-linux-${node_arch}.tar.xz\"; rm -rf \"$BF_NODE_DIR\"; mkdir -p \"$BF_NODE_DIR\"; tar -xJf \"$tmp/node.tar.xz\" -C \"$BF_NODE_DIR\" --strip-components=1 --no-same-owner; rm -rf \"$tmp\"; fi; export PATH=\"/opt/benchflow/node/bin:$PATH\"; \"$BF_NODE_DIR/bin/node\" --version; \"$BF_NODE_DIR/bin/npm\" --version && mkdir -p /opt/benchflow/js-agents /opt/benchflow/bin && export PATH=\"/opt/benchflow/bin:/opt/benchflow/js-agents/bin:/opt/benchflow/node/bin:$PATH\" && ( /opt/benchflow/node/bin/npm install -g --prefix /opt/benchflow/js-agents @agentclientprotocol/codex-acp@0.0.45 ) && printf '%s\\n' '#!/bin/sh' 'exec /opt/benchflow/node/bin/node /opt/benchflow/js-agents/bin/codex-acp \"$@\"' > /opt/benchflow/bin/codex-acp && chmod +x /opt/benchflow/bin/codex-acp && chmod -R a+rX /opt/benchflow && [ -x /opt/benchflow/js-agents/bin/codex-acp ] && [ -x /opt/benchflow/bin/codex-acp ]"
launch_cmd = "h=\"${BENCHFLOW_AGENT_HOME:-$HOME}\"; if [ -n \"$OPENAI_API_KEY\" ]; then mkdir -p \"$h/.codex\" && printf '{\"OPENAI_API_KEY\": \"%s\"}' \"$OPENAI_API_KEY\" > \"$h/.codex/auth.json\"; fi; exec /opt/benchflow/bin/codex-acp ${OPENAI_BASE_URL:+-c openai_base_url=$OPENAI_BASE_URL}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Unescaped API key in printf JSON construction

launch_cmd uses printf '{"OPENAI_API_KEY": "%s"}' "$OPENAI_API_KEY" to write auth.json. If OPENAI_API_KEY ever contains ", \, or a newline (e.g., a key passed in from a CI secret with trailing whitespace or embedded quotes), the resulting file is malformed JSON and codex will fail to authenticate. The same pattern appears in openhands/manifest.toml with LLM_MODEL and LLM_API_KEY. Consider piping through python3 -c "import json,sys,os; print(json.dumps({...}))" or similar for safe serialization.

Comment thread pi-acp/manifest.toml
contract_version = "1.0"
name = "pi-acp"
description = "Pi agent via ACP"
install_cmd = "export DEBIAN_FRONTEND=noninteractive; BF_NODE_DIR=/opt/benchflow/node; BF_NODE_VERSION=22.20.0; if [ ! -x \"$BF_NODE_DIR/bin/node\" ]; then if ! command -v curl >/dev/null 2>&1 || ! command -v tar >/dev/null 2>&1 || ! command -v xz >/dev/null 2>&1; then if command -v apt-get >/dev/null 2>&1; then apt-get update -qq && apt-get install -y -qq curl ca-certificates tar xz-utils; elif command -v dnf >/dev/null 2>&1; then dnf -y install curl ca-certificates tar xz; elif command -v apk >/dev/null 2>&1; then apk add --no-cache curl ca-certificates tar xz; else echo 'BenchFlow JS agent bootstrap requires curl, tar, and xz' >&2; exit 127; fi; fi; arch=\"$(uname -m)\"; case \"$arch\" in x86_64|amd64) node_arch=x64 ;; aarch64|arm64) node_arch=arm64 ;; *) echo \"Unsupported architecture for Node.js: $arch\" >&2; exit 1 ;; esac; tmp=\"$(mktemp -d)\"; mkdir -p /opt/benchflow; curl -fsSLo \"$tmp/node.tar.xz\" \"https://nodejs.org/dist/v${BF_NODE_VERSION}/node-v${BF_NODE_VERSION}-linux-${node_arch}.tar.xz\"; rm -rf \"$BF_NODE_DIR\"; mkdir -p \"$BF_NODE_DIR\"; tar -xJf \"$tmp/node.tar.xz\" -C \"$BF_NODE_DIR\" --strip-components=1 --no-same-owner; rm -rf \"$tmp\"; fi; export PATH=\"/opt/benchflow/node/bin:$PATH\"; \"$BF_NODE_DIR/bin/node\" --version; \"$BF_NODE_DIR/bin/npm\" --version && mkdir -p /opt/benchflow/js-agents /opt/benchflow/bin && export PATH=\"/opt/benchflow/bin:/opt/benchflow/js-agents/bin:/opt/benchflow/node/bin:$PATH\" && ( [ -x /opt/benchflow/js-agents/bin/pi ] || /opt/benchflow/node/bin/npm install -g --prefix /opt/benchflow/js-agents @mariozechner/pi-coding-agent@latest ) && printf '%s\\n' '#!/bin/sh' 'exec /opt/benchflow/node/bin/node /opt/benchflow/js-agents/bin/pi \"$@\"' > /opt/benchflow/bin/pi && chmod +x /opt/benchflow/bin/pi && chmod -R a+rX /opt/benchflow && [ -x /opt/benchflow/js-agents/bin/pi ] && [ -x /opt/benchflow/bin/pi ] && export DEBIAN_FRONTEND=noninteractive; BF_NODE_DIR=/opt/benchflow/node; BF_NODE_VERSION=22.20.0; if [ ! -x \"$BF_NODE_DIR/bin/node\" ]; then if ! command -v curl >/dev/null 2>&1 || ! command -v tar >/dev/null 2>&1 || ! command -v xz >/dev/null 2>&1; then if command -v apt-get >/dev/null 2>&1; then apt-get update -qq && apt-get install -y -qq curl ca-certificates tar xz-utils; elif command -v dnf >/dev/null 2>&1; then dnf -y install curl ca-certificates tar xz; elif command -v apk >/dev/null 2>&1; then apk add --no-cache curl ca-certificates tar xz; else echo 'BenchFlow JS agent bootstrap requires curl, tar, and xz' >&2; exit 127; fi; fi; arch=\"$(uname -m)\"; case \"$arch\" in x86_64|amd64) node_arch=x64 ;; aarch64|arm64) node_arch=arm64 ;; *) echo \"Unsupported architecture for Node.js: $arch\" >&2; exit 1 ;; esac; tmp=\"$(mktemp -d)\"; mkdir -p /opt/benchflow; curl -fsSLo \"$tmp/node.tar.xz\" \"https://nodejs.org/dist/v${BF_NODE_VERSION}/node-v${BF_NODE_VERSION}-linux-${node_arch}.tar.xz\"; rm -rf \"$BF_NODE_DIR\"; mkdir -p \"$BF_NODE_DIR\"; tar -xJf \"$tmp/node.tar.xz\" -C \"$BF_NODE_DIR\" --strip-components=1 --no-same-owner; rm -rf \"$tmp\"; fi; export PATH=\"/opt/benchflow/node/bin:$PATH\"; \"$BF_NODE_DIR/bin/node\" --version; \"$BF_NODE_DIR/bin/npm\" --version && mkdir -p /opt/benchflow/js-agents /opt/benchflow/bin && export PATH=\"/opt/benchflow/bin:/opt/benchflow/js-agents/bin:/opt/benchflow/node/bin:$PATH\" && ( [ -x /opt/benchflow/js-agents/bin/pi-acp ] || /opt/benchflow/node/bin/npm install -g --prefix /opt/benchflow/js-agents pi-acp@latest ) && printf '%s\\n' '#!/bin/sh' 'exec /opt/benchflow/node/bin/node /opt/benchflow/js-agents/bin/pi-acp \"$@\"' > /opt/benchflow/bin/pi-acp && chmod +x /opt/benchflow/bin/pi-acp && chmod -R a+rX /opt/benchflow && [ -x /opt/benchflow/js-agents/bin/pi-acp ] && [ -x /opt/benchflow/bin/pi-acp ] && ( command -v python3 >/dev/null 2>&1 || (apt-get update -qq && apt-get install -y -qq python3 >/dev/null 2>&1) ) && mkdir -p /opt/benchflow/bin && echo IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoiIiJMYXVuY2ggd3JhcHBlciBmb3IgcGktYWNwIOKAlCBicmlkZ2VzIEJFTkNIRkxPV19QUk9WSURFUl8qIHRvIFBpIGNvbmZpZy4KClBpIG5hdGl2ZWx5IHJlYWRzIEFOVEhST1BJQ18qIGVudiB2YXJzIGZvciBBbnRocm9waWMgcHJvdmlkZXJzLiBGb3IKT3BlbkFJLWNvbXBhdGlibGUgcHJvdmlkZXJzICh2TExNLCBldGMuKSwgUGkgcmVxdWlyZXMgYSBgYG1vZGVscy5qc29uYGAKY29uZmlnIGZpbGUgYXQgYGB+Ly5waS9hZ2VudC9tb2RlbHMuanNvbmBgIHRoYXQgZGVjbGFyZXMgdGhlIHByb3ZpZGVyJ3MKd2lyZSBwcm90b2NvbC4gIFRoaXMgd3JhcHBlciBnZW5lcmF0ZXMgaXQgZnJvbSBCRU5DSEZMT1dfUFJPVklERVJfKiBlbnYKdmFycyBpbmplY3RlZCBieSB0aGUgU0RLLCB0aGVuIGV4ZWNzIGBgcGktYWNwYGAuCgpTZWUgaHR0cHM6Ly9naXRodWIuY29tL2JhZGxvZ2ljL3BpLW1vbm8vYmxvYi9tYWluL3BhY2thZ2VzL2NvZGluZy1hZ2VudC9kb2NzL21vZGVscy5tZAoiIiIKCmltcG9ydCBqc29uCmltcG9ydCBvcwppbXBvcnQgc3lzCmZyb20gcGF0aGxpYiBpbXBvcnQgUGF0aAoKIyBQaSBtb2RlbC1tZXRhZGF0YSBkZWZhdWx0cyBpZiBuZWl0aGVyIHRoZSBwcm92aWRlciByZWdpc3RyeSBub3IgcGVyLXJ1bgojIG92ZXJyaWRlcyBzdXBwbHkgdmFsdWVzLiBDb25zZXJ2YXRpdmUg4oCUIG1vc3QgbW9kZXJuIG1vZGVscyBleGNlZWQgdGhlc2UuCl9ERUZBVUxUX0NPTlRFWFRfV0lORE9XID0gMTI4MDAwCl9ERUZBVUxUX01BWF9UT0tFTlMgPSAxNjM4NApfQkVOQ0hGTE9XX0JJTl9ESVIgPSAiL29wdC9iZW5jaGZsb3cvYmluIgpfUElfQUNQX0JJTiA9ICIvb3B0L2JlbmNoZmxvdy9iaW4vcGktYWNwIgoKCmRlZiBfbG9va3VwX21vZGVsX21ldGFkYXRhKG1vZGVsOiBzdHIpIC0+IGRpY3Q6CiAgICAiIiJSZXR1cm4gdGhlIHJlZ2lzdHJ5IGVudHJ5IGZvciBgbW9kZWxgIGZyb20gQkVOQ0hGTE9XX1BST1ZJREVSX01PREVMUywgb3Ige30uIiIiCiAgICByYXcgPSBvcy5lbnZpcm9uLmdldCgiQkVOQ0hGTE9XX1BST1ZJREVSX01PREVMUyIsICIiKQogICAgaWYgbm90IHJhdzoKICAgICAgICByZXR1cm4ge30KICAgIHRyeToKICAgICAgICBlbnRyaWVzID0ganNvbi5sb2FkcyhyYXcpCiAgICBleGNlcHQganNvbi5KU09ORGVjb2RlRXJyb3I6CiAgICAgICAgcmV0dXJuIHt9CiAgICBmb3IgZW50cnkgaW4gZW50cmllczoKICAgICAgICBpZiBpc2luc3RhbmNlKGVudHJ5LCBkaWN0KSBhbmQgZW50cnkuZ2V0KCJpZCIpID09IG1vZGVsOgogICAgICAgICAgICByZXR1cm4gZW50cnkKICAgIHJldHVybiB7fQoKCmRlZiBfZGVyaXZlX3Byb3ZpZGVyX25hbWUobW9kZWw6IHN0cikgLT4gc3RyOgogICAgIiIiRGVyaXZlIGEgdW5pcXVlIHByb3ZpZGVyIGtleSBzbyBjb25jdXJyZW50IHJ1bnMgZG9uJ3QgY29sbGlkZSBvbiAiY3VzdG9tIi4iIiIKICAgIGlmICIvIiBpbiBtb2RlbDoKICAgICAgICByZXR1cm4gZiJiZW5jaGZsb3cte21vZGVsLnNwbGl0KCcvJylbMF19IgogICAgcmV0dXJuIGYiYmVuY2hmbG93LXttb2RlbH0iIGlmIG1vZGVsIGVsc2UgImJlbmNoZmxvdy1jdXN0b20iCgoKZGVmIHNldHVwX3Byb3ZpZGVyKCkgLT4gTm9uZToKICAgICIiIkNvbmZpZ3VyZSBQaSBmb3IgdGhlIGRldGVjdGVkIHByb3ZpZGVyIHByb3RvY29sLiIiIgogICAgcHJvdG9jb2wgPSBvcy5lbnZpcm9uLmdldCgiQkVOQ0hGTE9XX1BST1ZJREVSX1BST1RPQ09MIiwgIiIpCiAgICBiYXNlX3VybCA9IG9zLmVudmlyb24uZ2V0KCJCRU5DSEZMT1dfUFJPVklERVJfQkFTRV9VUkwiLCAiIikKICAgIGFwaV9rZXkgPSBvcy5lbnZpcm9uLmdldCgiQkVOQ0hGTE9XX1BST1ZJREVSX0FQSV9LRVkiLCAiIikKICAgIG1vZGVsID0gb3MuZW52aXJvbi5nZXQoIkJFTkNIRkxPV19QUk9WSURFUl9NT0RFTCIsICIiKQogICAgcHJvdmlkZXJfbmFtZSA9IG9zLmVudmlyb24uZ2V0KCJCRU5DSEZMT1dfUFJPVklERVJfTkFNRSIpIG9yIF9kZXJpdmVfcHJvdmlkZXJfbmFtZSgKICAgICAgICBtb2RlbAogICAgKQoKICAgIGlmIHByb3RvY29sID09ICJvcGVuYWktY29tcGxldGlvbnMiOgogICAgICAgIGlmIG5vdCBiYXNlX3VybDoKICAgICAgICAgICAgcmFpc2UgU3lzdGVtRXhpdCgKICAgICAgICAgICAgICAgICJwaS1hY3A6IEJFTkNIRkxPV19QUk9WSURFUl9QUk9UT0NPTD1vcGVuYWktY29tcGxldGlvbnMgcmVxdWlyZXMgIgogICAgICAgICAgICAgICAgIkJFTkNIRkxPV19QUk9WSURFUl9CQVNFX1VSTCwgYnV0IGl0IGlzIGVtcHR5LiBDaGVjayBwcm92aWRlciAiCiAgICAgICAgICAgICAgICAicmVnaXN0cnkgdXJsX3BhcmFtcyAoZS5nLiBtaXNzaW5nIEdPT0dMRV9DTE9VRF9QUk9KRUNUKS4iCiAgICAgICAgICAgICkKICAgICAgICAjIFBpIHVzZXMgfi8ucGkvYWdlbnQvbW9kZWxzLmpzb24gdG8gZGlzY292ZXIgbm9uLUFudGhyb3BpYyBwcm92aWRlcnMuCiAgICAgICAgIyBSZWdpc3RlciB0aGUgcHJvdmlkZXIgc28gUGkgcm91dGVzIEFQSSBjYWxscyB0aHJvdWdoIHRoZSBPcGVuQUkKICAgICAgICAjIENoYXQgQ29tcGxldGlvbnMgd2lyZSBmb3JtYXQgaW5zdGVhZCBvZiBBbnRocm9waWMgTWVzc2FnZXMuCiAgICAgICAgbWV0YSA9IF9sb29rdXBfbW9kZWxfbWV0YWRhdGEobW9kZWwpCiAgICAgICAgY29uZmlnID0gewogICAgICAgICAgICAicHJvdmlkZXJzIjogewogICAgICAgICAgICAgICAgcHJvdmlkZXJfbmFtZTogewogICAgICAgICAgICAgICAgICAgICJiYXNlVXJsIjogYmFzZV91cmwsCiAgICAgICAgICAgICAgICAgICAgImFwaSI6ICJvcGVuYWktY29tcGxldGlvbnMiLAogICAgICAgICAgICAgICAgICAgICJhcGlLZXkiOiBhcGlfa2V5IG9yICJ1bnVzZWQiLAogICAgICAgICAgICAgICAgICAgICJtb2RlbHMiOiBbCiAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJpZCI6IG1vZGVsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiBtZXRhLmdldCgibmFtZSIsIG1vZGVsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJyZWFzb25pbmciOiBtZXRhLmdldCgicmVhc29uaW5nIiwgRmFsc2UpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImlucHV0IjogbWV0YS5nZXQoImlucHV0IiwgWyJ0ZXh0Il0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbnRleHRXaW5kb3ciOiBtZXRhLmdldCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29udGV4dFdpbmRvdyIsIF9ERUZBVUxUX0NPTlRFWFRfV0lORE9XCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1heFRva2VucyI6IG1ldGEuZ2V0KCJtYXhUb2tlbnMiLCBfREVGQVVMVF9NQVhfVE9LRU5TKSwKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgY29uZmlnX2RpciA9IFBhdGguaG9tZSgpIC8gIi5waSIgLyAiYWdlbnQiCiAgICAgICAgY29uZmlnX2Rpci5ta2RpcihwYXJlbnRzPVRydWUsIGV4aXN0X29rPVRydWUpCiAgICAgICAgbW9kZWxzX3BhdGggPSBjb25maWdfZGlyIC8gIm1vZGVscy5qc29uIgogICAgICAgICMgTWVyZ2Ugd2l0aCBleGlzdGluZyBjb25maWcgc28gbWFudWFsbHktYWRkZWQgcHJvdmlkZXJzIHN1cnZpdmUKICAgICAgICBpZiBtb2RlbHNfcGF0aC5leGlzdHMoKToKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgZXhpc3RpbmcgPSBqc29uLmxvYWRzKG1vZGVsc19wYXRoLnJlYWRfdGV4dCgpKQogICAgICAgICAgICAgICAgZXhpc3Rpbmcuc2V0ZGVmYXVsdCgicHJvdmlkZXJzIiwge30pLnVwZGF0ZShjb25maWdbInByb3ZpZGVycyJdKQogICAgICAgICAgICAgICAgY29uZmlnID0gZXhpc3RpbmcKICAgICAgICAgICAgZXhjZXB0IChqc29uLkpTT05EZWNvZGVFcnJvciwgT1NFcnJvcik6CiAgICAgICAgICAgICAgICBwcmludCgKICAgICAgICAgICAgICAgICAgICBmIldhcm5pbmc6IGNvdWxkIG5vdCBwYXJzZSB7bW9kZWxzX3BhdGh9LCBvdmVyd3JpdGluZy4iLAogICAgICAgICAgICAgICAgICAgIGZpbGU9c3lzLnN0ZGVyciwKICAgICAgICAgICAgICAgICkKICAgICAgICBtb2RlbHNfcGF0aC53cml0ZV90ZXh0KGpzb24uZHVtcHMoY29uZmlnLCBpbmRlbnQ9MikpCiAgICBlbHNlOgogICAgICAgICMgQW50aHJvcGljIG1vZGUg4oCUIHNldCBuYXRpdmUgZW52IHZhcnMgdGhhdCBQaSByZWFkcyBkaXJlY3RseS4KICAgICAgICAjIERPIE5PVCBjaGFuZ2Ugc2V0ZGVmYXVsdCB0byBhc3NpZ25tZW50LiBVc2VycyByb3V0ZSB0aHJvdWdoIHByb3hpZXMKICAgICAgICAjIHdpdGggLS1hZ2VudC1lbnYgQU5USFJPUElDX0JBU0VfVVJMPTxwcm94eT47IG92ZXJ3cml0aW5nIGJyZWFrcyB0aGF0IHBhdGguCiAgICAgICAgIyBXaHk6IEJFTkNIRkxPV19QUk9WSURFUl9CQVNFX1VSTCBpcyB0aGUgcmVnaXN0cnkgZGVmYXVsdDsgdGhlIHVzZXIncwogICAgICAgICMgLS1hZ2VudC1lbnYgb3ZlcnJpZGUgbXVzdCB3aW4uIFBpbm5lZCBieSB0ZXN0cy90ZXN0X3BpX2FjcF9sYXVuY2hlci5weTo6CiAgICAgICAgIyB0ZXN0X3NldGRlZmF1bHRfZG9lc19ub3Rfb3ZlcndyaXRlLgogICAgICAgIGlmIGJhc2VfdXJsOgogICAgICAgICAgICBvcy5lbnZpcm9uLnNldGRlZmF1bHQoIkFOVEhST1BJQ19CQVNFX1VSTCIsIGJhc2VfdXJsKQogICAgICAgIGlmIGFwaV9rZXk6CiAgICAgICAgICAgIG9zLmVudmlyb24uc2V0ZGVmYXVsdCgiQU5USFJPUElDX0FVVEhfVE9LRU4iLCBhcGlfa2V5KQogICAgICAgIGlmIG1vZGVsOgogICAgICAgICAgICBvcy5lbnZpcm9uLnNldGRlZmF1bHQoIkFOVEhST1BJQ19NT0RFTCIsIG1vZGVsKQoKCmRlZiBfcHJlcGVuZF9iZW5jaGZsb3dfYmluX3BhdGgoKSAtPiBOb25lOgogICAgIiIiTGV0IHBpLWFjcCBmaW5kIHRoZSBwYWlyZWQgcGkgd3JhcHBlciB3aXRob3V0IGV4cG9zaW5nIE5vZGUvbnBtLiIiIgogICAgY3VycmVudCA9IG9zLmVudmlyb24uZ2V0KCJQQVRIIiwgIiIpCiAgICBwYXJ0cyA9IGN1cnJlbnQuc3BsaXQoIjoiKSBpZiBjdXJyZW50IGVsc2UgW10KICAgIGlmIF9CRU5DSEZMT1dfQklOX0RJUiBub3QgaW4gcGFydHM6CiAgICAgICAgb3MuZW52aXJvblsiUEFUSCJdID0gKAogICAgICAgICAgICBmIntfQkVOQ0hGTE9XX0JJTl9ESVJ9OntjdXJyZW50fSIgaWYgY3VycmVudCBlbHNlIF9CRU5DSEZMT1dfQklOX0RJUgogICAgICAgICkKCgpkZWYgbWFpbigpIC0+IE5vbmU6CiAgICBzZXR1cF9wcm92aWRlcigpCiAgICBfcHJlcGVuZF9iZW5jaGZsb3dfYmluX3BhdGgoKQogICAgdHJ5OgogICAgICAgIG9zLmV4ZWN2KF9QSV9BQ1BfQklOLCBbX1BJX0FDUF9CSU4sICpzeXMuYXJndlsxOl1dKQogICAgZXhjZXB0IEZpbGVOb3RGb3VuZEVycm9yIGFzIGU6CiAgICAgICAgcmFpc2UgU3lzdGVtRXhpdCgKICAgICAgICAgICAgZiJwaS1hY3A6IHtfUElfQUNQX0JJTiFyfSBub3QgZm91bmQuIEl0IHNob3VsZCBoYXZlIGJlZW4gIgogICAgICAgICAgICAiaW5zdGFsbGVkIGJ5IHRoZSByZWdpc3RyeSdzIGluc3RhbGxfY21kIHZpYSAiCiAgICAgICAgICAgICInbnBtIGluc3RhbGwgLWcgcGktYWNwJy4gQ2hlY2sgdGhlIGNvbnRhaW5lcidzIGluc3RhbGwgbG9nLiIKICAgICAgICApIGZyb20gZQoKCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICBtYWluKCkK | base64 -d > /opt/benchflow/bin/pi-acp-launcher && chmod +x /opt/benchflow/bin/pi-acp-launcher"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Entire Node.js bootstrap block duplicated in install_cmd

The install_cmd contains the full Node.js download-and-install bootstrap (the if [ ! -x "$BF_NODE_DIR/bin/node" ]; then … fi block) twice — once before installing @mariozechner/pi-coding-agent and again verbatim before installing pi-acp. The second occurrence is a no-op at runtime (the node binary is already present), but it roughly doubles the manifest size and makes the command harder to audit. Consider factoring the bootstrap into a shared variable or a helper, or omitting the repeated copy.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant