Compare commits

..

1 Commits

Author SHA1 Message Date
Ben Potter
1601ab3e8b
feat(.icons): add Lucide SVG icons for skill cards (#880) 2026-05-20 13:18:52 +00:00
7 changed files with 14 additions and 158 deletions

4
.icons/coder-modules.svg Normal file
View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="7" height="7" x="14" y="3" rx="1"/>
<path d="M10 21V8a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1H3"/>
</svg>

After

Width:  |  Height:  |  Size: 339 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="18" height="7" x="3" y="3" rx="1"/>
<rect width="9" height="7" x="3" y="14" rx="1"/>
<rect width="5" height="7" x="16" y="14" rx="1"/>
</svg>

After

Width:  |  Height:  |  Size: 336 B

View File

@ -13,7 +13,7 @@ Install and configure the [Codex CLI](https://github.com/openai/codex) in your w
```tf ```tf
module "codex" { module "codex" {
source = "registry.coder.com/coder-labs/codex/coder" source = "registry.coder.com/coder-labs/codex/coder"
version = "5.1.0" version = "5.0.0"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
openai_api_key = var.openai_api_key openai_api_key = var.openai_api_key
} }
@ -33,7 +33,7 @@ locals {
module "codex" { module "codex" {
source = "registry.coder.com/coder-labs/codex/coder" source = "registry.coder.com/coder-labs/codex/coder"
version = "5.1.0" version = "5.0.0"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
workdir = local.codex_workdir workdir = local.codex_workdir
openai_api_key = var.openai_api_key openai_api_key = var.openai_api_key
@ -64,7 +64,7 @@ resource "coder_app" "codex" {
```tf ```tf
module "codex" { module "codex" {
source = "registry.coder.com/coder-labs/codex/coder" source = "registry.coder.com/coder-labs/codex/coder"
version = "5.1.0" version = "5.0.0"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
workdir = "/home/coder/project" workdir = "/home/coder/project"
enable_ai_gateway = true enable_ai_gateway = true
@ -88,7 +88,7 @@ When `enable_ai_gateway = true`, the module configures Codex to use the `aigatew
```tf ```tf
module "codex" { module "codex" {
source = "registry.coder.com/coder-labs/codex/coder" source = "registry.coder.com/coder-labs/codex/coder"
version = "5.1.0" version = "5.0.0"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
workdir = "/home/coder/project" workdir = "/home/coder/project"
openai_api_key = var.openai_api_key openai_api_key = var.openai_api_key
@ -107,26 +107,9 @@ module "codex" {
args = ["-y", "@modelcontextprotocol/server-github"] args = ["-y", "@modelcontextprotocol/server-github"]
type = "stdio" type = "stdio"
EOT EOT
mcp_config_remote_path = [
"https://example.com/team-mcp-servers.toml",
"https://raw.githubusercontent.com/your-org/your-repo/main/.codex/mcp.toml",
]
} }
``` ```
> [!NOTE]
> Servers configured through `mcp` or `mcp_config_remote_path` are appended to `~/.codex/config.toml`, so they apply to every Codex session in the workspace. Each remote URL should return a body in Codex's native TOML format, e.g.:
>
> ```toml
> [mcp_servers.my-tool]
> command = "my-tool-server"
> args = ["--port", "8080"]
> type = "stdio"
> ```
>
> Fetch failures (network errors or non-2xx responses) log a warning and the install continues with the remaining URLs. Bodies are appended verbatim without further validation, so make sure the URL returns valid Codex TOML.
### Serialize a downstream `coder_script` after the install pipeline ### Serialize a downstream `coder_script` after the install pipeline
The module exposes the `scripts` output: an ordered list of `coder exp sync` names for the scripts this module creates (pre_install, install, post_install). Scripts that were not configured are absent. The module exposes the `scripts` output: an ordered list of `coder exp sync` names for the scripts this module creates (pre_install, install, post_install). Scripts that were not configured are absent.
@ -134,7 +117,7 @@ The module exposes the `scripts` output: an ordered list of `coder exp sync` nam
```tf ```tf
module "codex" { module "codex" {
source = "registry.coder.com/coder-labs/codex/coder" source = "registry.coder.com/coder-labs/codex/coder"
version = "5.1.0" version = "5.0.0"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
openai_api_key = var.openai_api_key openai_api_key = var.openai_api_key
} }

View File

@ -425,86 +425,6 @@ describe("codex", async () => {
expect(installLog).toContain("Installed Codex CLI"); expect(installLog).toContain("Installed Codex CLI");
}); });
test("mcp-config-remote-path", async () => {
const remoteToml = [
"[mcp_servers.remote-fetched]",
'command = "remote-mcp-cmd"',
'args = ["--from-url"]',
'type = "stdio"',
].join("\n");
const projectDir = "/home/coder/project";
const moduleDir = path.resolve(import.meta.dir);
const state = await runTerraformApply(moduleDir, {
agent_id: "foo",
workdir: projectDir,
install_codex: "false",
mcp_config_remote_path: JSON.stringify([
"http://localhost:19999/mcp.toml",
"file:///tmp/remote-mcp.toml",
]),
});
const scripts = collectScripts(state);
const coderEnvVars = extractCoderEnvVars(state);
const id = await runContainer("codercom/enterprise-node:latest");
registerCleanup(async () => {
if (process.env["DEBUG"] === "true" || process.env["DEBUG"] === "1") {
console.log(`Not removing container ${id} in debug mode`);
return;
}
await removeContainer(id);
});
await execContainer(id, ["bash", "-c", `mkdir -p '${projectDir}'`]);
await writeExecutable({
containerId: id,
filePath: "/usr/bin/coder",
content: "#!/bin/bash\nexit 0\n",
});
await writeExecutable({
containerId: id,
filePath: "/usr/bin/codex",
content: await Bun.file(
path.join(moduleDir, "testdata", "codex-mock.sh"),
).text(),
});
// Drop the remote TOML payload at a path the install script will fetch
// via file://. Keeps the test self-contained (no external network).
await execContainer(id, [
"bash",
"-c",
`cat > /tmp/remote-mcp.toml <<'EOF'\n${remoteToml}\nEOF`,
]);
await runScripts(id, scripts, coderEnvVars);
const installLog = await readFileContainer(
id,
"/home/coder/.coder-modules/coder-labs/codex/logs/install.log",
);
// Both URLs were attempted.
expect(installLog).toContain("http://localhost:19999/mcp.toml");
expect(installLog).toContain("file:///tmp/remote-mcp.toml");
// First URL fails gracefully.
expect(installLog).toContain(
"Warning: Failed to fetch MCP configuration from 'http://localhost:19999/mcp.toml'",
);
// Second URL succeeds.
expect(installLog).not.toContain(
"Warning: Failed to fetch MCP configuration from 'file:///tmp/remote-mcp.toml'",
);
expect(installLog).toContain(
"Appending MCP servers from file:///tmp/remote-mcp.toml",
);
const configToml = await readFileContainer(
id,
"/home/coder/.codex/config.toml",
);
expect(configToml).toContain("[mcp_servers.remote-fetched]");
expect(configToml).toContain('command = "remote-mcp-cmd"');
});
test("custom-config-drops-reasoning-effort", async () => { test("custom-config-drops-reasoning-effort", async () => {
const baseConfig = [ const baseConfig = [
'sandbox_mode = "danger-full-access"', 'sandbox_mode = "danger-full-access"',

View File

@ -88,12 +88,6 @@ variable "mcp" {
default = "" default = ""
} }
variable "mcp_config_remote_path" {
type = list(string)
description = "List of URLs that return MCP server configurations in TOML format (matching Codex's native config format). Fetched at install time and appended to config.toml."
default = []
}
variable "model_reasoning_effort" { variable "model_reasoning_effort" {
type = string type = string
description = "The reasoning effort for the model. One of: none, minimal, low, medium, high, xhigh. See https://platform.openai.com/docs/guides/latest-model#lower-reasoning-effort" description = "The reasoning effort for the model. One of: none, minimal, low, medium, high, xhigh. See https://platform.openai.com/docs/guides/latest-model#lower-reasoning-effort"
@ -147,7 +141,6 @@ locals {
ARG_WORKDIR = local.workdir != "" ? base64encode(local.workdir) : "" ARG_WORKDIR = local.workdir != "" ? base64encode(local.workdir) : ""
ARG_BASE_CONFIG_TOML = var.base_config_toml != "" ? base64encode(var.base_config_toml) : "" ARG_BASE_CONFIG_TOML = var.base_config_toml != "" ? base64encode(var.base_config_toml) : ""
ARG_MCP = var.mcp != "" ? base64encode(var.mcp) : "" ARG_MCP = var.mcp != "" ? base64encode(var.mcp) : ""
ARG_MCP_CONFIG_REMOTE_PATH = base64encode(jsonencode(var.mcp_config_remote_path))
ARG_ENABLE_AI_GATEWAY = tostring(var.enable_ai_gateway) ARG_ENABLE_AI_GATEWAY = tostring(var.enable_ai_gateway)
ARG_AIBRIDGE_CONFIG = var.enable_ai_gateway ? base64encode(local.aibridge_config) : "" ARG_AIBRIDGE_CONFIG = var.enable_ai_gateway ? base64encode(local.aibridge_config) : ""
ARG_MODEL_REASONING_EFFORT = var.model_reasoning_effort ARG_MODEL_REASONING_EFFORT = var.model_reasoning_effort

View File

@ -183,34 +183,3 @@ run "test_workdir_optional" {
error_message = "scripts output should have install script even without workdir" error_message = "scripts output should have install script even without workdir"
} }
} }
run "test_mcp_config_remote_path" {
command = plan
variables {
agent_id = "test-agent"
workdir = "/home/coder"
mcp_config_remote_path = [
"https://example.com/mcp-one.toml",
"https://example.com/mcp-two.toml",
]
}
assert {
condition = strcontains(local.install_script, base64encode(jsonencode(var.mcp_config_remote_path)))
error_message = "install script should embed the base64-encoded mcp_config_remote_path JSON"
}
}
run "test_mcp_config_remote_path_default" {
command = plan
variables {
agent_id = "test-agent"
}
assert {
condition = length(var.mcp_config_remote_path) == 0
error_message = "mcp_config_remote_path should default to an empty list"
}
}

View File

@ -13,7 +13,6 @@ ARG_CODEX_VERSION=$(echo -n '${ARG_CODEX_VERSION}' | base64 -d)
ARG_WORKDIR=$(echo -n '${ARG_WORKDIR}' | base64 -d) ARG_WORKDIR=$(echo -n '${ARG_WORKDIR}' | base64 -d)
ARG_BASE_CONFIG_TOML=$(echo -n '${ARG_BASE_CONFIG_TOML}' | base64 -d) ARG_BASE_CONFIG_TOML=$(echo -n '${ARG_BASE_CONFIG_TOML}' | base64 -d)
ARG_MCP=$(echo -n '${ARG_MCP}' | base64 -d) ARG_MCP=$(echo -n '${ARG_MCP}' | base64 -d)
ARG_MCP_CONFIG_REMOTE_PATH=$(echo -n '${ARG_MCP_CONFIG_REMOTE_PATH}' | base64 -d)
ARG_ENABLE_AI_GATEWAY='${ARG_ENABLE_AI_GATEWAY}' ARG_ENABLE_AI_GATEWAY='${ARG_ENABLE_AI_GATEWAY}'
ARG_AIBRIDGE_CONFIG=$(echo -n '${ARG_AIBRIDGE_CONFIG}' | base64 -d) ARG_AIBRIDGE_CONFIG=$(echo -n '${ARG_AIBRIDGE_CONFIG}' | base64 -d)
ARG_MODEL_REASONING_EFFORT='${ARG_MODEL_REASONING_EFFORT}' ARG_MODEL_REASONING_EFFORT='${ARG_MODEL_REASONING_EFFORT}'
@ -25,7 +24,6 @@ printf "workdir: %s\n" "$${ARG_WORKDIR}"
printf "enable_ai_gateway: %s\n" "$${ARG_ENABLE_AI_GATEWAY}" printf "enable_ai_gateway: %s\n" "$${ARG_ENABLE_AI_GATEWAY}"
printf "install_codex: %s\n" "$${ARG_INSTALL}" printf "install_codex: %s\n" "$${ARG_INSTALL}"
printf "model_reasoning_effort: %s\n" "$${ARG_MODEL_REASONING_EFFORT}" printf "model_reasoning_effort: %s\n" "$${ARG_MODEL_REASONING_EFFORT}"
printf "mcp_config_remote_path: %s\n" "$${ARG_MCP_CONFIG_REMOTE_PATH}"
echo "--------------------------------" echo "--------------------------------"
function add_path_to_shell_profiles() { function add_path_to_shell_profiles() {
@ -157,22 +155,6 @@ function populate_config_toml() {
echo "$${ARG_MCP}" >> "$${config_path}" echo "$${ARG_MCP}" >> "$${config_path}"
fi fi
if [ -n "$${ARG_MCP_CONFIG_REMOTE_PATH}" ] && [ "$${ARG_MCP_CONFIG_REMOTE_PATH}" != "[]" ]; then
if ! command -v jq > /dev/null 2>&1; then
printf "Error: 'jq' is required to process mcp_config_remote_path but was not found. Skipping remote MCP config fetch.\n" >&2
else
for url in $(echo "$${ARG_MCP_CONFIG_REMOTE_PATH}" | jq -r '.[]'); do
echo "Fetching MCP configuration from: $${url}"
mcp_toml=$(curl -fsSL "$${url}") || {
echo "Warning: Failed to fetch MCP configuration from '$${url}', continuing..."
continue
}
printf "Appending MCP servers from %s\n" "$${url}"
printf '\n%s\n' "$${mcp_toml}" >> "$${config_path}"
done
fi
fi
if [ "$${ARG_ENABLE_AI_GATEWAY}" = "true" ] && [ -n "$${ARG_AIBRIDGE_CONFIG}" ]; then if [ "$${ARG_ENABLE_AI_GATEWAY}" = "true" ] && [ -n "$${ARG_AIBRIDGE_CONFIG}" ]; then
if ! grep -q '\[model_providers\.aigateway\]' "$${config_path}" 2>/dev/null; then if ! grep -q '\[model_providers\.aigateway\]' "$${config_path}" 2>/dev/null; then
printf "Adding AI Gateway configuration\n" printf "Adding AI Gateway configuration\n"