Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,9 @@ jobs:
- name: Validate wrangler binding consistency
run: pnpm quality:wrangler-bindings

- name: Validate agent install manifest consistency
run: pnpm quality:agent-install-manifest

code-quality:
name: Code Quality Checks
if: github.event_name == 'pull_request' || github.repository == 'raphaeltm/simple-agent-manager'
Expand Down
20 changes: 17 additions & 3 deletions apps/api/Dockerfile.vm-agent-container
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
FROM docker.io/library/node:20-bookworm-slim
FROM docker.io/library/node:22-bookworm-slim

COPY container-entrypoints/patch-acp-amp.py /tmp/patch-acp-amp.py

RUN set -eux; \
apt-get update; \
Expand All @@ -9,13 +11,25 @@
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list; \
apt-get update; \
apt-get install -y --no-install-recommends gh; \
npm install -g @zed-industries/claude-agent-acp @anthropic-ai/claude-code; \
npm install -g @agentclientprotocol/claude-agent-acp@0.58.1 @anthropic-ai/claude-code@2.1.207 @agentclientprotocol/codex-acp@1.1.2 @google/gemini-cli@0.50.0 opencode-ai@1.17.18 @ampcode/cli@0.0.1783785389-g0da70d; \

Check warning on line 14 in apps/api/Dockerfile.vm-agent-container

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Line is too long. Split it into multiple lines using backslash continuations.

See more on https://sonarcloud.io/project/issues?id=raphaeltm_simple-agent-manager&issues=AZ9SDDrJOsIJlDz0awSO&open=AZ9SDDrJOsIJlDz0awSO&pullRequest=1565
curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh; \
UV_TOOL_DIR=/opt/uv-tools UV_PYTHON_INSTALL_DIR=/opt/uv-python UV_TOOL_BIN_DIR=/usr/local/bin uv tool install mistral-vibe==2.19.1 --python 3.12 --quiet; \

Check warning on line 16 in apps/api/Dockerfile.vm-agent-container

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Line is too long. Split it into multiple lines using backslash continuations.

See more on https://sonarcloud.io/project/issues?id=raphaeltm_simple-agent-manager&issues=AZ9SDDrJOsIJlDz0awSM&open=AZ9SDDrJOsIJlDz0awSM&pullRequest=1565
UV_TOOL_DIR=/opt/uv-tools UV_PYTHON_INSTALL_DIR=/opt/uv-python UV_TOOL_BIN_DIR=/usr/local/bin uv tool install acp-amp==0.1.3 --with agent-client-protocol==0.7.1 --with amp-sdk==0.1.2 --with pydantic==2.12.5 --with pydantic-core==2.41.5 --with annotated-types==0.7.0 --with typing-inspection==0.4.2 --with typing-extensions==4.15.0 --python 3.12 --quiet; \

Check warning on line 17 in apps/api/Dockerfile.vm-agent-container

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Line is too long. Split it into multiple lines using backslash continuations.

See more on https://sonarcloud.io/project/issues?id=raphaeltm_simple-agent-manager&issues=AZ9SDDrJOsIJlDz0awSN&open=AZ9SDDrJOsIJlDz0awSN&pullRequest=1565
UV_PYTHON_INSTALL_DIR=/opt/uv-python uv run --python 3.12 python /tmp/patch-acp-amp.py; \
rm /tmp/patch-acp-amp.py; \
npm cache clean --force; \
rm -rf /var/lib/apt/lists/*

ENV SAM_AGENT_HOME=/var/lib/vm-agent/agents \
NPM_CONFIG_PREFIX=/var/lib/vm-agent/agents/npm \
UV_TOOL_DIR=/var/lib/vm-agent/agents/uv-tools \
UV_PYTHON_INSTALL_DIR=/var/lib/vm-agent/agents/uv-python \
UV_TOOL_BIN_DIR=/var/lib/vm-agent/agents/bin \
PATH=/var/lib/vm-agent/agents/bin:/var/lib/vm-agent/agents/npm/bin:/usr/local/bin:/usr/bin:/bin

COPY container-entrypoints/vm-agent-bootstrap.sh /usr/local/bin/vm-agent-bootstrap
RUN chmod +x /usr/local/bin/vm-agent-bootstrap && \
mkdir -p /workspaces /var/lib/vm-agent && \
mkdir -p /workspaces /var/lib/vm-agent/agents/bin /var/lib/vm-agent/agents/npm /var/lib/vm-agent/agents/uv-tools /var/lib/vm-agent/agents/uv-python && \

Check warning on line 32 in apps/api/Dockerfile.vm-agent-container

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Line is too long. Split it into multiple lines using backslash continuations.

See more on https://sonarcloud.io/project/issues?id=raphaeltm_simple-agent-manager&issues=AZ9SDDrJOsIJlDz0awSP&open=AZ9SDDrJOsIJlDz0awSP&pullRequest=1565
chown -R node:node /workspaces /var/lib/vm-agent

USER node
Expand Down
28 changes: 28 additions & 0 deletions apps/api/container-entrypoints/patch-acp-amp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from pathlib import Path

base = Path('/opt/uv-tools/acp-amp/lib/python3.12/site-packages')
p = base / 'acp_amp/driver/python_sdk.py'
t = p.read_text()
t = t.replace('"message": str(exc)', '"message": str(exc) + (" stderr: " + exc.stderr if hasattr(exc, "stderr") and exc.stderr else "")')
old = ''' if mcp_config:
base["mcp_config"] = mcp_config
base["mcpConfig"] = mcp_config'''
new = ''' if mcp_config:
from amp_sdk.types import MCPConfig
cleaned = {}
for _n, _c in mcp_config.items():
if isinstance(_c, dict):
_cc = dict(_c)
if _cc.get("env") is None:
_cc["env"] = {}
cleaned[_n] = _cc
else:
cleaned[_n] = _c
_wrapped = MCPConfig(servers=cleaned)
base["mcp_config"] = _wrapped
base["mcpConfig"] = _wrapped'''
t = t.replace(old, new)
p.write_text(t)

Check failure on line 25 in apps/api/container-entrypoints/patch-acp-amp.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Change this code to not construct the path from user-controlled data.

See more on https://sonarcloud.io/project/issues?id=raphaeltm_simple-agent-manager&issues=AZ9SDDi_OsIJlDz0awSK&open=AZ9SDDi_OsIJlDz0awSK&pullRequest=1565
v = base / 'amp_sdk/types.py'
vt = v.read_text().replace('visibility: Optional[Literal["private", "public", "workspace", "group"]] = "workspace"', 'visibility: Optional[Literal["private", "public", "workspace", "group"]] = "private"')
v.write_text(vt)

Check failure on line 28 in apps/api/container-entrypoints/patch-acp-amp.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Change this code to not construct the path from user-controlled data.

See more on https://sonarcloud.io/project/issues?id=raphaeltm_simple-agent-manager&issues=AZ9SDDi_OsIJlDz0awSL&open=AZ9SDDi_OsIJlDz0awSL&pullRequest=1565
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"setup:local": "tsx scripts/deploy/setup-local-dev.ts",
"quality:preflight": "tsx scripts/quality/check-preflight-evidence.ts",
"quality:wrangler-bindings": "tsx scripts/quality/check-wrangler-bindings.ts",
"quality:agent-install-manifest": "tsx scripts/quality/check-agent-install-manifest.ts",
"quality:ast-checks": "tsx scripts/quality/ast-checks.ts",
"quality:file-sizes": "tsx scripts/quality/check-file-sizes.ts",
"quality:migration-safety": "tsx scripts/quality/check-migration-safety.ts",
Expand Down
57 changes: 57 additions & 0 deletions packages/shared/src/agent-install-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[
{
"agentType": "claude-code",
"method": "npm",
"package": "@agentclientprotocol/claude-agent-acp",
"version": "0.58.1",
"bin": "claude-agent-acp"
},
{
"agentType": "openai-codex",
"method": "npm",
"package": "@agentclientprotocol/codex-acp",
"version": "1.1.2",
"bin": "codex-acp"
},
{
"agentType": "google-gemini",
"method": "npm",
"package": "@google/gemini-cli",
"version": "0.50.0",
"bin": "gemini"
},
{
"agentType": "mistral-vibe",
"method": "uv-tool",
"package": "mistral-vibe",
"version": "2.19.1",
"bin": "vibe-acp",
"python": "3.12"
},
{
"agentType": "opencode",
"method": "npm",
"package": "opencode-ai",
"version": "1.17.18",
"bin": "opencode"
},
{
"agentType": "amp",
"method": "uv-tool",
"package": "acp-amp",
"version": "0.1.3",
"bin": "acp-amp",
"python": "3.12",
"extraPackages": [
"agent-client-protocol==0.7.1",
"amp-sdk==0.1.2",
"pydantic==2.12.5",
"pydantic-core==2.41.5",
"annotated-types==0.7.0",
"typing-inspection==0.4.2",
"typing-extensions==4.15.0"
],
"npmCompanion": { "package": "@ampcode/cli", "version": "0.0.1783785389-g0da70d" },
"postInstallHook": "amp-sdk-patch"
}
]
21 changes: 6 additions & 15 deletions packages/shared/src/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const AGENT_TYPE_VALUES = [
'amp',
] as const;

export type AgentType = typeof AGENT_TYPE_VALUES[number];
export type AgentType = (typeof AGENT_TYPE_VALUES)[number];

/** API key provider identifiers */
export const AGENT_PROVIDER_VALUES = [
Expand All @@ -26,7 +26,7 @@ export const AGENT_PROVIDER_VALUES = [
'amp',
] as const;

export type AgentProvider = typeof AGENT_PROVIDER_VALUES[number];
export type AgentProvider = (typeof AGENT_PROVIDER_VALUES)[number];

// =============================================================================
// Agent Definition (Configuration Registry)
Expand All @@ -52,8 +52,6 @@ export interface AgentDefinition {
supportsAcp: boolean;
/** URL where users can obtain an API key */
credentialHelpUrl: string;
/** npm global install command */
installCommand: string;
/** Cloud provider whose credential can be used as a fallback when no dedicated agent key exists */
fallbackCloudProvider?: string;
/** OAuth-specific metadata */
Expand All @@ -67,7 +65,6 @@ export interface AgentDefinition {
};
}


// =============================================================================
// Agent Catalog
// =============================================================================
Expand All @@ -84,10 +81,10 @@ export const AGENT_CATALOG: readonly AgentDefinition[] = [
acpArgs: [],
supportsAcp: true,
credentialHelpUrl: 'https://console.anthropic.com/settings/keys',
installCommand: 'npm install -g @zed-industries/claude-agent-acp',
oauthSupport: {
envVarName: 'CLAUDE_CODE_OAUTH_TOKEN',
setupInstructions: 'Generate a token using "claude setup-token" or "claude login" in your terminal',
setupInstructions:
'Generate a token using "claude setup-token" or "claude login" in your terminal',
subscriptionUrl: 'https://claude.ai/settings/plan',
},
},
Expand All @@ -101,10 +98,10 @@ export const AGENT_CATALOG: readonly AgentDefinition[] = [
acpArgs: [],
supportsAcp: true,
credentialHelpUrl: 'https://platform.openai.com/api-keys',
installCommand: 'npx --yes @agentclientprotocol/codex-acp --version',
oauthSupport: {
envVarName: 'CODEX_AUTH_JSON',
setupInstructions: 'Run "codex login" on your local machine and sign in with your ChatGPT account, then paste the contents of ~/.codex/auth.json',
setupInstructions:
'Run "codex login" on your local machine and sign in with your ChatGPT account, then paste the contents of ~/.codex/auth.json',
subscriptionUrl: 'https://openai.com/chatgpt/pricing/',
},
},
Expand All @@ -118,7 +115,6 @@ export const AGENT_CATALOG: readonly AgentDefinition[] = [
acpArgs: ['--acp'],
supportsAcp: true,
credentialHelpUrl: 'https://aistudio.google.com/apikey',
installCommand: 'npm install -g @google/gemini-cli',
},
{
id: 'mistral-vibe',
Expand All @@ -130,8 +126,6 @@ export const AGENT_CATALOG: readonly AgentDefinition[] = [
acpArgs: [],
supportsAcp: true,
credentialHelpUrl: 'https://console.mistral.ai/api-keys',
installCommand:
'curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh && UV_TOOL_DIR=/opt/uv-tools UV_PYTHON_INSTALL_DIR=/opt/uv-python UV_TOOL_BIN_DIR=/usr/local/bin uv tool install mistral-vibe==2.7.0 --python 3.12 --quiet',
},
{
id: 'opencode',
Expand All @@ -143,7 +137,6 @@ export const AGENT_CATALOG: readonly AgentDefinition[] = [
acpArgs: ['acp'],
supportsAcp: true,
credentialHelpUrl: 'https://opencode.ai/auth',
installCommand: 'npm install -g opencode-ai@1.17.8',
},
{
id: 'amp',
Expand All @@ -155,8 +148,6 @@ export const AGENT_CATALOG: readonly AgentDefinition[] = [
acpArgs: ['run'],
supportsAcp: true,
credentialHelpUrl: 'https://ampcode.com/settings',
installCommand:
'curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh && UV_TOOL_DIR=/opt/uv-tools UV_PYTHON_INSTALL_DIR=/opt/uv-python UV_TOOL_BIN_DIR=/usr/local/bin uv tool install acp-amp==0.1.3 --with agent-client-protocol==0.7.1 --with amp-sdk==0.1.2 --with pydantic==2.12.5 --with pydantic-core==2.41.5 --with annotated-types==0.7.0 --with typing-inspection==0.4.2 --with typing-extensions==4.15.0 --python 3.12 --quiet && npm install -g @sourcegraph/amp',
},
] as const;

Expand Down
19 changes: 2 additions & 17 deletions packages/shared/tests/unit/agents.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { describe, expect, it } from 'vitest';

import {
AGENT_CATALOG,
getAgentDefinition,
isValidAgentType,
} from '../../src/agents';
import { AGENT_CATALOG, getAgentDefinition, isValidAgentType } from '../../src/agents';

describe('AGENT_CATALOG', () => {
it('includes mistral-vibe as a supported agent', () => {
Expand All @@ -17,12 +13,7 @@ describe('AGENT_CATALOG', () => {
expect(mistral!.acpCommand).toBe('vibe-acp');
expect(mistral!.acpArgs).toEqual([]);
expect(mistral!.supportsAcp).toBe(true);
expect(mistral!.credentialHelpUrl).toBe(
'https://console.mistral.ai/api-keys'
);
expect(mistral!.installCommand).toBe(
'curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh && UV_TOOL_DIR=/opt/uv-tools UV_PYTHON_INSTALL_DIR=/opt/uv-python UV_TOOL_BIN_DIR=/usr/local/bin uv tool install mistral-vibe==2.7.0 --python 3.12 --quiet'
);
expect(mistral!.credentialHelpUrl).toBe('https://console.mistral.ai/api-keys');
});

it('includes opencode as a supported agent', () => {
Expand All @@ -39,7 +30,6 @@ describe('AGENT_CATALOG', () => {
expect(opencode!.supportsAcp).toBe(true);
expect(opencode!.credentialHelpUrl).toBe('https://opencode.ai/auth');
expect(opencode!.fallbackCloudProvider).toBeUndefined();
expect(opencode!.installCommand).toBe('npm install -g opencode-ai@1.17.8');
});

it('includes Gemini CLI as a supported ACP agent', () => {
Expand All @@ -51,15 +41,13 @@ describe('AGENT_CATALOG', () => {
expect(gemini!.acpCommand).toBe('gemini');
expect(gemini!.acpArgs).toEqual(['--acp']);
expect(gemini!.supportsAcp).toBe(true);
expect(gemini!.installCommand).toBe('npm install -g @google/gemini-cli');
expect(gemini!.oauthSupport).toBeUndefined();
});

it('uses the maintained Codex ACP wrapper for OpenAI Codex', () => {
const codex = AGENT_CATALOG.find((a) => a.id === 'openai-codex');
expect(codex).toMatchObject({
acpCommand: 'codex-acp',
installCommand: 'npx --yes @agentclientprotocol/codex-acp --version',
supportsAcp: true,
});
expect(codex?.oauthSupport?.envVarName).toBe('CODEX_AUTH_JSON');
Expand All @@ -81,9 +69,6 @@ describe('AGENT_CATALOG', () => {
expect(amp!.acpArgs).toEqual(['run']);
expect(amp!.supportsAcp).toBe(true);
expect(amp!.credentialHelpUrl).toBe('https://ampcode.com/settings');
expect(amp!.installCommand).toBe(
'curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh && UV_TOOL_DIR=/opt/uv-tools UV_PYTHON_INSTALL_DIR=/opt/uv-python UV_TOOL_BIN_DIR=/usr/local/bin uv tool install acp-amp==0.1.3 --with agent-client-protocol==0.7.1 --with amp-sdk==0.1.2 --with pydantic==2.12.5 --with pydantic-core==2.41.5 --with annotated-types==0.7.0 --with typing-inspection==0.4.2 --with typing-extensions==4.15.0 --python 3.12 --quiet && npm install -g @sourcegraph/amp'
);
expect(amp!.fallbackCloudProvider).toBeUndefined();
expect(amp!.oauthSupport).toBeUndefined();
});
Expand Down
24 changes: 12 additions & 12 deletions packages/vm-agent/internal/acp/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -783,8 +783,8 @@ func installAgentBinary(ctx context.Context, containerID string, info agentComma
// directories can block subsequent installs with ENOTEMPTY.
if info.isNpmBased {
cleanupScript := fmt.Sprintf(
`rm -rf /usr/local/lib/node_modules/@zed-industries/.%s-* /usr/local/share/nvm/versions/node/*/lib/node_modules/@zed-industries/.%s-* 2>/dev/null; true`,
info.command, info.command,
`rm -rf /usr/local/lib/node_modules/.%s-* /usr/local/lib/node_modules/*/.%s-* /usr/local/share/nvm/versions/node/*/lib/node_modules/.%s-* /usr/local/share/nvm/versions/node/*/lib/node_modules/*/.%s-* 2>/dev/null; true`,
info.command, info.command, info.command, info.command,
)
cleanupArgs := []string{"exec", "-u", "root", containerID, "sh", "-c", cleanupScript}
cleanupCmd := exec.CommandContext(ctx, "docker", cleanupArgs...)
Expand Down Expand Up @@ -842,8 +842,8 @@ func installAgentBinaryLocal(ctx context.Context, info agentCommandInfo) error {
// by previous failed npm installs (same rationale as the docker path).
if info.isNpmBased {
cleanupScript := fmt.Sprintf(
`rm -rf /usr/local/lib/node_modules/@zed-industries/.%s-* /usr/local/share/nvm/versions/node/*/lib/node_modules/@zed-industries/.%s-* 2>/dev/null; true`,
info.command, info.command,
`rm -rf /usr/local/lib/node_modules/.%s-* /usr/local/lib/node_modules/*/.%s-* /usr/local/share/nvm/versions/node/*/lib/node_modules/.%s-* /usr/local/share/nvm/versions/node/*/lib/node_modules/*/.%s-* 2>/dev/null; true`,
info.command, info.command, info.command, info.command,
)
cleanupCmd := exec.CommandContext(ctx, localShellPath, "-c", cleanupScript)
_ = cleanupCmd.Run() // best-effort cleanup
Expand Down Expand Up @@ -883,7 +883,7 @@ type agentCommandInfo struct {
authFilePath string // relative to home dir, e.g. ".codex/auth.json" (only when injectionMode == "auth-file")
}

const codexACPInstallCommand = "npm install -g @agentclientprotocol/codex-acp"
const codexACPInstallCommand = "npm install -g @agentclientprotocol/codex-acp@1.1.2"

// getAgentCommandInfo returns the ACP command, args, env var name, and install command for a given agent type.
// These match the agent catalog defined in packages/shared/src/agents.ts.
Expand All @@ -892,9 +892,9 @@ func getAgentCommandInfo(agentType string, credentialKind string) agentCommandIn
switch agentType {
case "claude-code":
if credentialKind == "oauth-token" {
return agentCommandInfo{"claude-agent-acp", nil, "CLAUDE_CODE_OAUTH_TOKEN", "npm install -g @zed-industries/claude-agent-acp", true, "", ""}
return agentCommandInfo{"claude-agent-acp", nil, "CLAUDE_CODE_OAUTH_TOKEN", "npm install -g @agentclientprotocol/claude-agent-acp@0.58.1", true, "", ""}
}
return agentCommandInfo{"claude-agent-acp", nil, "ANTHROPIC_API_KEY", "npm install -g @zed-industries/claude-agent-acp", true, "", ""}
return agentCommandInfo{"claude-agent-acp", nil, "ANTHROPIC_API_KEY", "npm install -g @agentclientprotocol/claude-agent-acp@0.58.1", true, "", ""}
case "openai-codex":
// Use -c to override sandbox_mode via codex-acp's config override flag.
// This takes the highest priority in the Codex config hierarchy,
Expand All @@ -918,15 +918,15 @@ func getAgentCommandInfo(agentType string, credentialKind string) agentCommandIn
}
return agentCommandInfo{"codex-acp", codexSandboxArgs, "OPENAI_API_KEY", codexACPInstallCommand, true, "", ""}
case "google-gemini":
return agentCommandInfo{"gemini", []string{"--acp"}, "GEMINI_API_KEY", "npm install -g @google/gemini-cli", true, "", ""}
return agentCommandInfo{"gemini", []string{"--acp"}, "GEMINI_API_KEY", "npm install -g @google/gemini-cli@0.50.0", true, "", ""}
case "mistral-vibe":
return agentCommandInfo{"vibe-acp", nil, "MISTRAL_API_KEY", `curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh && UV_TOOL_DIR=/opt/uv-tools UV_PYTHON_INSTALL_DIR=/opt/uv-python UV_TOOL_BIN_DIR=/usr/local/bin uv tool install mistral-vibe==2.7.0 --python 3.12 --quiet`, false, "", ""}
return agentCommandInfo{"vibe-acp", nil, "MISTRAL_API_KEY", `curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh && UV_TOOL_DIR=/opt/uv-tools UV_PYTHON_INSTALL_DIR=/opt/uv-python UV_TOOL_BIN_DIR=/usr/local/bin uv tool install mistral-vibe==2.19.1 --python 3.12 --quiet`, false, "", ""}
case "opencode":
return agentCommandInfo{
command: "opencode",
args: []string{"acp"},
envVarName: "OPENCODE_API_KEY",
installCmd: "npm install -g opencode-ai@1.17.8",
installCmd: "npm install -g opencode-ai@1.17.18",
isNpmBased: true,
injectionMode: "",
authFilePath: "",
Expand All @@ -936,7 +936,7 @@ func getAgentCommandInfo(agentType string, credentialKind string) agentCommandIn
command: "acp-amp",
args: []string{"run"},
envVarName: "AMP_API_KEY",
installCmd: `curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh && UV_TOOL_DIR=/opt/uv-tools UV_PYTHON_INSTALL_DIR=/opt/uv-python UV_TOOL_BIN_DIR=/usr/local/bin uv tool install acp-amp==0.1.3 --with agent-client-protocol==0.7.1 --with amp-sdk==0.1.2 --with pydantic==2.12.5 --with pydantic-core==2.41.5 --with annotated-types==0.7.0 --with typing-inspection==0.4.2 --with typing-extensions==4.15.0 --python 3.12 --quiet && npm install -g @sourcegraph/amp && UV_PYTHON_INSTALL_DIR=/opt/uv-python uv run --python 3.12 python -c "
installCmd: `curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh && UV_TOOL_DIR=/opt/uv-tools UV_PYTHON_INSTALL_DIR=/opt/uv-python UV_TOOL_BIN_DIR=/usr/local/bin uv tool install acp-amp==0.1.3 --with agent-client-protocol==0.7.1 --with amp-sdk==0.1.2 --with pydantic==2.12.5 --with pydantic-core==2.41.5 --with annotated-types==0.7.0 --with typing-inspection==0.4.2 --with typing-extensions==4.15.0 --python 3.12 --quiet && npm install -g @ampcode/cli@0.0.1783785389-g0da70d && UV_PYTHON_INSTALL_DIR=/opt/uv-python uv run --python 3.12 python -c "
import pathlib
base = '/opt/uv-tools/acp-amp/lib/python3.12/site-packages'

Expand Down Expand Up @@ -976,7 +976,7 @@ vt = vt.replace('visibility: Optional[Literal[\"private\", \"public\", \"workspa
v.write_text(vt)
print('Patched amp_sdk: visibility default to private')
"`,
// isNpmBased must be true because installCmd chains `npm install -g @sourcegraph/amp`
// isNpmBased must be true because installCmd chains `npm install -g @ampcode/cli@0.0.1783785389-g0da70d`
// after the uv install. The Node.js bootstrap preamble ensures npm is available
// inside devcontainers that don't ship with Node.js pre-installed.
isNpmBased: true,
Expand Down
Loading
Loading