Compare commits

..

11 Commits

Author SHA1 Message Date
Atif Ali bb128fa077 docs(codex): clarify standalone and AI Bridge usage 2026-02-04 12:45:55 +00:00
Atif Ali 7c5f9b2adc style(codex): remove trailing whitespace in test file 2026-02-04 12:39:29 +00:00
Atif Ali 0a92c5c18f fix(codex): update tests to work with conditional agentapi module
- Only set install_agentapi when explicitly installing real AgentAPI
- Let enable_tasks (defaults to true) control agentapi module in tests
- This fixes tests that were inadvertently triggering standalone mode

All 18 tests now pass 
2026-02-04 11:58:07 +00:00
Atif Ali a443767ef3 chore(codex): apply bun fmt to README 2026-02-04 11:43:32 +00:00
Atif Ali 316269e437 fix(codex): only remove top-level profile key, preserve profiles sections
Use awk to track when we enter a TOML section and only remove 'profile ='
lines that appear at the top level (before any [section] headers). This
ensures user-provided [profiles.*] sections are preserved intact.
2026-02-04 10:32:21 +00:00
Atif Ali 9af62366b7 fix(codex): P2 - override profile when enable_aibridge=true
The previous fix would skip setting profile when one already existed,
breaking enable_aibridge=true with custom base configs. Now when
enable_aibridge=true, we explicitly remove any existing profile line
and set profile="aibridge" (since enable_aibridge=true is an explicit
user intention to use AI Bridge).
2026-02-04 10:29:54 +00:00
Atif Ali 46726a903d style(codex): terraform fmt 2026-02-04 07:24:09 +00:00
Atif Ali 8be5d5e01c fix(codex): address review comments
- P1: Make agentapi module conditional when enable_tasks=false
  - Add standalone coder_script for install when tasks disabled
  - Prevents AgentAPI requirement errors in standalone mode
- P2: Guard against duplicate profile key in config.toml
  - Check if profile already exists before prepending
  - Prevents TOML parsing errors with custom base configs
2026-02-04 07:23:56 +00:00
Atif Ali fa5fb31454 chore(codex): add TODO for removing deprecated install_agentapi in 5.0.0 2026-02-04 07:20:22 +00:00
Atif Ali 52603754cd docs(codex): simplify AI Bridge section in README 2026-02-04 07:19:19 +00:00
Atif Ali e18caa5a46 feat(codex): optimize for standalone usage with optional workdir and default AI Bridge profile
- Add 'enable_tasks' variable (defaults to true) for better discoverability
- Make 'workdir' optional when enable_tasks=false for standalone CLI usage
- Keep 'install_agentapi' as deprecated alias for backward compatibility
- Prepend 'profile = "aibridge"' to config.toml when AI Bridge is enabled
  so users can run 'codex' directly without --profile flag
- Update README with standalone usage examples and version 4.2.0
- Add tests for aibridge profile at config top and standalone mode
2026-02-04 07:12:00 +00:00
10 changed files with 213 additions and 131 deletions
+31 -28
View File
@@ -1,19 +1,19 @@
---
display_name: Codex CLI
icon: ../../../../.icons/openai.svg
description: Run Codex CLI in your workspace with AgentAPI integration
description: Run Codex CLI in your workspace with optional Tasks integration
verified: true
tags: [agent, codex, ai, openai, tasks, aibridge]
---
# Codex CLI
Run Codex CLI in your workspace to access OpenAI's models through the Codex interface, with custom pre/post install scripts. This module integrates with [AgentAPI](https://github.com/coder/agentapi) for Coder Tasks compatibility.
Install Codex CLI in your workspace with optional Coder Tasks integration via [AgentAPI](https://github.com/coder/agentapi). The module supports AI Bridge, custom install scripts, and MCP server configuration.
```tf
module "codex" {
source = "registry.coder.com/coder-labs/codex/coder"
version = "4.1.0"
version = "4.2.0"
agent_id = coder_agent.example.id
openai_api_key = var.openai_api_key
workdir = "/home/coder/project"
@@ -22,47 +22,51 @@ module "codex" {
## Prerequisites
- OpenAI API key for Codex access
- OpenAI API key for Codex access (not required when `enable_aibridge = true`)
## Examples
### Run standalone
### Standalone (no Tasks UI)
Use `enable_tasks = false` to install Codex without AgentAPI/Tasks. `workdir` is optional in this mode.
```tf
module "codex" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder-labs/codex/coder"
version = "4.1.0"
version = "4.2.0"
agent_id = coder_agent.example.id
openai_api_key = "..."
workdir = "/home/coder/project"
report_tasks = false
enable_tasks = false
# workdir not required in standalone mode
}
```
### Usage with AI Bridge
[AI Bridge](https://coder.com/docs/ai-coder/ai-bridge) is a Premium Coder feature that provides centralized LLM proxy management. To use AI Bridge, set `enable_aibridge = true`. Requires Coder version 2.30+
For tasks integration with AI Bridge, add `enable_aibridge = true` to the [Usage with Tasks](#usage-with-tasks) example below.
#### Standalone usage with AI Bridge
[AI Bridge](https://coder.com/docs/ai-coder/ai-bridge) is a Premium Coder feature that provides centralized LLM proxy management. Set `enable_aibridge = true` to use it (requires Coder 2.30+). When AI Bridge is enabled, authentication uses the workspace owner session token, so `openai_api_key` should be omitted.
```tf
module "codex" {
source = "registry.coder.com/coder-labs/codex/coder"
version = "4.1.0"
version = "4.2.0"
agent_id = coder_agent.example.id
workdir = "/home/coder/project"
enable_aibridge = true
enable_tasks = false # Standalone mode - just CLI, no Tasks UI
# workdir not required in standalone mode
}
```
For Tasks integration, add `enable_aibridge = true` to the [Usage with Tasks](#usage-with-tasks) example below.
When `enable_aibridge = true`, the module:
- Configures Codex to use the AI Bridge profile with `base_url` pointing to `${data.coder_workspace.me.access_url}/api/v2/aibridge/openai/v1` and `env_key` pointing to the workspace owner's session token
- Sets `profile = "aibridge"` at the top of `config.toml` so Codex uses AI Bridge by default
```toml
profile = "aibridge"
[model_providers.aibridge]
name = "AI Bridge"
base_url = "https://example.coder.com/api/v2/aibridge/openai/v1"
@@ -75,9 +79,7 @@ model = "<model>" # as configured in the module input
model_reasoning_effort = "<model_reasoning_effort>" # as configured in the module input
```
Codex then runs with `--profile aibridge`
This allows Codex to route API requests through Coder's AI Bridge instead of directly to OpenAI's API.
Codex uses the AI Bridge profile by default, so running `codex` manually does not require `--profile aibridge`.
Template build will fail if `openai_api_key` is provided alongside `enable_aibridge = true`.
### Usage with Tasks
@@ -94,7 +96,7 @@ data "coder_task" "me" {}
module "codex" {
source = "registry.coder.com/coder-labs/codex/coder"
version = "4.1.0"
version = "4.2.0"
agent_id = coder_agent.example.id
openai_api_key = "..."
ai_prompt = data.coder_task.me.prompt
@@ -112,7 +114,7 @@ This example shows additional configuration options for custom models, MCP serve
```tf
module "codex" {
source = "registry.coder.com/coder-labs/codex/coder"
version = "4.1.0"
version = "4.2.0"
agent_id = coder_agent.example.id
openai_api_key = "..."
workdir = "/home/coder/project"
@@ -142,11 +144,11 @@ module "codex" {
## How it Works
- **Install**: The module installs Codex CLI and sets up the environment
- **System Prompt**: If `codex_system_prompt` is set, writes the prompt to `AGENTS.md` in the `~/.codex/` directory
- **Start**: Launches Codex CLI in the specified directory, wrapped by AgentAPI
- **Configuration**: Sets `OPENAI_API_KEY` environment variable and passes `--model` flag to Codex CLI (if variables provided)
- **Session Continuity**: When `continue = true` (default), the module automatically tracks task sessions in `~/.codex-module/.codex-task-session`. On workspace restart, it resumes the existing session with full conversation history. Set `continue = false` to always start fresh sessions.
- **Install**: Installs Codex CLI and prepares configuration.
- **System Prompt**: If `codex_system_prompt` is set, writes it to `~/.codex/AGENTS.md`.
- **Start**: When `enable_tasks = true`, launches Codex via AgentAPI in the selected `workdir`. When `enable_tasks = false`, only the install script runs.
- **Configuration**: Writes `OPENAI_API_KEY` when provided, and sets the AI Bridge profile when `enable_aibridge = true`.
- **Session Continuity**: When `continue = true` (default), task sessions are tracked in `~/.codex-module/.codex-task-session` for resume on restart. Set `continue = false` to always start fresh sessions.
## Configuration
@@ -168,13 +170,14 @@ network_access = true
## Troubleshooting
- Check installation and startup logs in `~/.codex-module/`
- Ensure your OpenAI API key has access to the specified model
- Tasks mode: check installation/startup logs in `~/.codex-module/`.
- Standalone mode: review the workspace script output for the "Install Codex" script.
- Ensure your OpenAI API key has access to the specified model (unless using AI Bridge).
> [!IMPORTANT]
> To use tasks with Codex CLI, ensure you have the `openai_api_key` variable set. [Tasks Template Example](https://registry.coder.com/templates/coder-labs/tasks-docker).
> The module automatically configures Codex with your API key and model preferences.
> workdir is a required variable for the module to function correctly.
> `workdir` is required when `enable_tasks = true` (default). For standalone CLI usage, set `enable_tasks = false` and `workdir` becomes optional.
## References
+40 -7
View File
@@ -41,15 +41,25 @@ interface SetupProps {
const setup = async (props?: SetupProps): Promise<{ id: string }> => {
const projectDir = "/home/coder/project";
const moduleVars: Record<string, string> = {
install_codex: props?.skipCodexMock ? "true" : "false",
codex_model: "gpt-4-turbo",
workdir: "/home/coder",
...props?.moduleVariables,
};
// For backward compatibility: install_agentapi takes precedence over enable_tasks
// Only set install_agentapi when explicitly installing real AgentAPI
if (props?.skipAgentAPIMock) {
moduleVars.install_agentapi = "true";
}
// Otherwise, let enable_tasks control whether agentapi module runs
// (defaults to true unless explicitly disabled in moduleVariables)
const { id } = await setupUtil({
moduleDir: import.meta.dir,
moduleVariables: {
install_codex: props?.skipCodexMock ? "true" : "false",
install_agentapi: props?.skipAgentAPIMock ? "true" : "false",
codex_model: "gpt-4-turbo",
workdir: "/home/coder",
...props?.moduleVariables,
},
moduleVariables: moduleVars,
registerCleanup,
projectDir,
skipAgentAPIMock: props?.skipAgentAPIMock,
@@ -481,5 +491,28 @@ describe("codex", async () => {
expect(configToml).toContain(
"[profiles.aibridge]\n" + 'model_provider = "aibridge"',
);
// Verify profile = "aibridge" is set at the top of the config
expect(configToml.startsWith('profile = "aibridge"')).toBe(true);
});
test("codex-standalone-mode", async () => {
// Test standalone mode without tasks (enable_tasks = false)
// workdir should default to /home/coder when not explicitly provided
const { id } = await setup({
moduleVariables: {
enable_tasks: "false",
enable_aibridge: "true",
},
});
await execModuleScript(id);
const configToml = await readFileContainer(
id,
"/home/coder/.codex/config.toml",
);
// In standalone mode, config should still have aibridge profile set as default
expect(configToml.startsWith('profile = "aibridge"')).toBe(true);
expect(configToml).toContain("[profiles.aibridge]");
});
});
+54 -7
View File
@@ -38,7 +38,19 @@ variable "icon" {
variable "workdir" {
type = string
description = "The folder to run Codex in."
description = "The folder to run Codex in. Required when enable_tasks is true."
default = null
validation {
condition = var.workdir != null || !local.tasks_enabled
error_message = "workdir is required when enable_tasks is true. Set workdir or set enable_tasks = false for standalone CLI usage."
}
}
variable "enable_tasks" {
type = bool
description = "Enable Tasks UI for Codex (requires workdir). When false, only installs Codex CLI with config for standalone usage."
default = true
}
variable "report_tasks" {
@@ -122,10 +134,11 @@ variable "openai_api_key" {
default = ""
}
# TODO: Remove install_agentapi in next major version (5.0.0)
variable "install_agentapi" {
type = bool
description = "Whether to install AgentAPI."
default = true
description = "DEPRECATED: Use enable_tasks instead. Whether to install AgentAPI."
default = null
}
variable "agentapi_version" {
@@ -184,7 +197,9 @@ resource "coder_env" "coder_aibridge_session_token" {
}
locals {
workdir = trimsuffix(var.workdir, "/")
# Use enable_tasks, but fall back to install_agentapi if explicitly set (for backward compat)
tasks_enabled = var.install_agentapi != null ? var.install_agentapi : var.enable_tasks
workdir = var.workdir != null ? trimsuffix(var.workdir, "/") : "/home/coder"
app_slug = "codex"
install_script = file("${path.module}/scripts/install.sh")
start_script = file("${path.module}/scripts/start.sh")
@@ -204,6 +219,7 @@ locals {
}
module "agentapi" {
count = local.tasks_enabled ? 1 : 0
source = "registry.coder.com/coder/agentapi/coder"
version = "2.0.0"
@@ -218,7 +234,7 @@ module "agentapi" {
cli_app_slug = var.cli_app ? "${local.app_slug}-cli" : null
cli_app_display_name = var.cli_app ? var.cli_app_display_name : null
module_dir_name = local.module_dir_name
install_agentapi = var.install_agentapi
install_agentapi = true
agentapi_subdomain = var.subdomain
agentapi_version = var.agentapi_version
pre_install_script = var.pre_install_script
@@ -262,6 +278,37 @@ module "agentapi" {
EOT
}
output "task_app_id" {
value = module.agentapi.task_app_id
# Standalone installation (when tasks are disabled)
resource "coder_script" "standalone_install" {
count = local.tasks_enabled ? 0 : 1
agent_id = var.agent_id
display_name = "Install Codex"
icon = var.icon
run_on_start = true
start_blocks_login = false
script = <<-EOT
#!/bin/bash
set -o errexit
set -o pipefail
echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh
chmod +x /tmp/install.sh
ARG_OPENAI_API_KEY='${var.openai_api_key}' \
ARG_REPORT_TASKS='false' \
ARG_INSTALL='${var.install_codex}' \
ARG_CODEX_VERSION='${var.codex_version}' \
ARG_BASE_CONFIG_TOML='${base64encode(var.base_config_toml)}' \
ARG_ENABLE_AIBRIDGE='${var.enable_aibridge}' \
ARG_AIBRIDGE_CONFIG='${base64encode(var.enable_aibridge ? local.aibridge_config : "")}' \
ARG_ADDITIONAL_MCP_SERVERS='${base64encode(var.additional_mcp_servers)}' \
ARG_CODER_MCP_APP_STATUS_SLUG='' \
ARG_CODEX_START_DIRECTORY='${local.workdir}' \
ARG_CODEX_INSTRUCTION_PROMPT='${base64encode(var.codex_system_prompt)}' \
/tmp/install.sh
EOT
}
output "task_app_id" {
value = local.tasks_enabled ? module.agentapi[0].task_app_id : null
}
@@ -151,6 +151,25 @@ function populate_config_toml() {
write_minimal_default_config "$CONFIG_PATH"
fi
# Set aibridge as default profile when AI Bridge is enabled
# This allows users to run `codex` without --profile flag
if [ "$ARG_ENABLE_AIBRIDGE" = "true" ]; then
printf "Setting aibridge as default profile\n"
# Remove any existing top-level profile line (before first section header)
# This only removes profile = ... at top level, not inside [profiles.*] sections
awk '
BEGIN { in_top_level = 1 }
/^\[/ { in_top_level = 0 }
in_top_level && /^profile[ \t]*=/ { next }
{ print }
' "$CONFIG_PATH" > "${CONFIG_PATH}.tmp"
mv "${CONFIG_PATH}.tmp" "$CONFIG_PATH"
# Prepend profile = "aibridge" to the config
local temp_config
temp_config=$(cat "$CONFIG_PATH")
echo -e "profile = \"aibridge\"\n\n$temp_config" > "$CONFIG_PATH"
fi
append_mcp_servers_section "$CONFIG_PATH"
if [ "$ARG_ENABLE_AIBRIDGE" = "true" ]; then
+9 -9
View File
@@ -13,7 +13,7 @@ Run the [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.7.5"
version = "4.7.4"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
claude_api_key = "xxxx-xxxxx-xxxx"
@@ -47,7 +47,7 @@ By default, when `enable_boundary = true`, the module uses `coder boundary` subc
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.7.5"
version = "4.7.4"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
enable_boundary = true
@@ -68,7 +68,7 @@ For tasks integration with AI Bridge, add `enable_aibridge = true` to the [Usage
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.7.5"
version = "4.7.4"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
enable_aibridge = true
@@ -97,7 +97,7 @@ data "coder_task" "me" {}
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.7.5"
version = "4.7.4"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
ai_prompt = data.coder_task.me.prompt
@@ -120,7 +120,7 @@ This example shows additional configuration options for version pinning, custom
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.7.5"
version = "4.7.4"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
@@ -176,7 +176,7 @@ Run and configure Claude Code as a standalone CLI in your workspace.
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.7.5"
version = "4.7.4"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
install_claude_code = true
@@ -198,7 +198,7 @@ variable "claude_code_oauth_token" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.7.5"
version = "4.7.4"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
claude_code_oauth_token = var.claude_code_oauth_token
@@ -271,7 +271,7 @@ resource "coder_env" "bedrock_api_key" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.7.5"
version = "4.7.4"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
@@ -328,7 +328,7 @@ resource "coder_env" "google_application_credentials" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.7.5"
version = "4.7.4"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
model = "claude-sonnet-4@20250514"
+31 -25
View File
@@ -208,11 +208,6 @@ variable "claude_binary_path" {
type = string
description = "Directory where the Claude Code binary is located. Use this if Claude is pre-installed or installed outside the module to a non-default location."
default = "$HOME/.local/bin"
validation {
condition = var.claude_binary_path == "$HOME/.local/bin" || !var.install_claude_code
error_message = "Custom claude_binary_path can only be used when install_claude_code is false. The official installer always installs to $HOME/.local/bin and does not support custom paths."
}
}
variable "install_via_npm" {
@@ -295,6 +290,18 @@ resource "coder_env" "disable_autoupdater" {
value = "1"
}
resource "coder_env" "claude_binary_path" {
agent_id = var.agent_id
name = "PATH"
value = "${var.claude_binary_path}:$PATH"
lifecycle {
precondition {
condition = var.claude_binary_path == "$HOME/.local/bin" || !var.install_claude_code
error_message = "Custom claude_binary_path can only be used when install_claude_code is false. The official installer and npm both install to fixed locations."
}
}
}
resource "coder_env" "anthropic_model" {
count = var.model != "" ? 1 : 0
@@ -375,27 +382,26 @@ module "agentapi" {
pre_install_script = var.pre_install_script
post_install_script = var.post_install_script
start_script = <<-EOT
#!/bin/bash
set -o errexit
set -o pipefail
echo -n '${base64encode(local.start_script)}' | base64 -d > /tmp/start.sh
chmod +x /tmp/start.sh
#!/bin/bash
set -o errexit
set -o pipefail
echo -n '${base64encode(local.start_script)}' | base64 -d > /tmp/start.sh
chmod +x /tmp/start.sh
ARG_RESUME_SESSION_ID='${var.resume_session_id}' \
ARG_CONTINUE='${var.continue}' \
ARG_DANGEROUSLY_SKIP_PERMISSIONS='${var.dangerously_skip_permissions}' \
ARG_PERMISSION_MODE='${var.permission_mode}' \
ARG_WORKDIR='${local.workdir}' \
ARG_AI_PROMPT='${base64encode(var.ai_prompt)}' \
ARG_REPORT_TASKS='${var.report_tasks}' \
ARG_ENABLE_BOUNDARY='${var.enable_boundary}' \
ARG_BOUNDARY_VERSION='${var.boundary_version}' \
ARG_COMPILE_FROM_SOURCE='${var.compile_boundary_from_source}' \
ARG_USE_BOUNDARY_DIRECTLY='${var.use_boundary_directly}' \
ARG_CODER_HOST='${local.coder_host}' \
ARG_CLAUDE_BINARY_PATH='${var.claude_binary_path}' \
/tmp/start.sh
EOT
ARG_RESUME_SESSION_ID='${var.resume_session_id}' \
ARG_CONTINUE='${var.continue}' \
ARG_DANGEROUSLY_SKIP_PERMISSIONS='${var.dangerously_skip_permissions}' \
ARG_PERMISSION_MODE='${var.permission_mode}' \
ARG_WORKDIR='${local.workdir}' \
ARG_AI_PROMPT='${base64encode(var.ai_prompt)}' \
ARG_REPORT_TASKS='${var.report_tasks}' \
ARG_ENABLE_BOUNDARY='${var.enable_boundary}' \
ARG_BOUNDARY_VERSION='${var.boundary_version}' \
ARG_COMPILE_FROM_SOURCE='${var.compile_boundary_from_source}' \
ARG_USE_BOUNDARY_DIRECTLY='${var.use_boundary_directly}' \
ARG_CODER_HOST='${local.coder_host}' \
/tmp/start.sh
EOT
install_script = <<-EOT
#!/bin/bash
@@ -12,7 +12,6 @@ ARG_CLAUDE_CODE_VERSION=${ARG_CLAUDE_CODE_VERSION:-}
ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"}
ARG_INSTALL_CLAUDE_CODE=${ARG_INSTALL_CLAUDE_CODE:-}
ARG_CLAUDE_BINARY_PATH=${ARG_CLAUDE_BINARY_PATH:-"$HOME/.local/bin"}
ARG_CLAUDE_BINARY_PATH=$(eval echo "$ARG_CLAUDE_BINARY_PATH")
ARG_INSTALL_VIA_NPM=${ARG_INSTALL_VIA_NPM:-false}
ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true}
ARG_MCP_APP_STATUS_SLUG=${ARG_MCP_APP_STATUS_SLUG:-}
@@ -22,8 +21,6 @@ ARG_ALLOWED_TOOLS=${ARG_ALLOWED_TOOLS:-}
ARG_DISALLOWED_TOOLS=${ARG_DISALLOWED_TOOLS:-}
ARG_ENABLE_AIBRIDGE=${ARG_ENABLE_AIBRIDGE:-false}
export PATH="$ARG_CLAUDE_BINARY_PATH:$PATH"
echo "--------------------------------"
printf "ARG_CLAUDE_CODE_VERSION: %s\n" "$ARG_CLAUDE_CODE_VERSION"
@@ -54,51 +51,39 @@ function add_mcp_servers() {
done < <(echo "$mcp_json" | jq -r '.mcpServers | to_entries[] | .key, (.value | @json)')
}
function add_path_to_shell_profiles() {
local path_dir="$1"
for profile in "$HOME/.profile" "$HOME/.bash_profile" "$HOME/.bashrc" "$HOME/.zprofile" "$HOME/.zshrc"; do
if [ -f "$profile" ]; then
if ! grep -q "$path_dir" "$profile" 2> /dev/null; then
echo "export PATH=\"\$PATH:$path_dir\"" >> "$profile"
echo "Added $path_dir to $profile"
fi
fi
done
local fish_config="$HOME/.config/fish/config.fish"
if [ -f "$fish_config" ]; then
if ! grep -q "$path_dir" "$fish_config" 2> /dev/null; then
echo "fish_add_path $path_dir" >> "$fish_config"
echo "Added $path_dir to $fish_config"
fi
fi
}
function ensure_claude_in_path() {
local CLAUDE_BIN=""
if command -v claude > /dev/null 2>&1; then
CLAUDE_BIN=$(command -v claude)
elif [ -x "$ARG_CLAUDE_BINARY_PATH/claude" ]; then
CLAUDE_BIN="$ARG_CLAUDE_BINARY_PATH/claude"
elif [ -x "$HOME/.local/bin/claude" ]; then
CLAUDE_BIN="$HOME/.local/bin/claude"
fi
if [ -z "$CLAUDE_BIN" ] || [ ! -x "$CLAUDE_BIN" ]; then
echo "Warning: Could not find claude binary"
if [ -z "${CODER_SCRIPT_BIN_DIR:-}" ]; then
echo "CODER_SCRIPT_BIN_DIR not set, skipping PATH setup"
return
fi
local CLAUDE_DIR
CLAUDE_DIR=$(dirname "$CLAUDE_BIN")
if [ ! -e "$CODER_SCRIPT_BIN_DIR/claude" ]; then
local CLAUDE_BIN=""
if command -v claude > /dev/null 2>&1; then
CLAUDE_BIN=$(command -v claude)
elif [ -x "$ARG_CLAUDE_BINARY_PATH/claude" ]; then
CLAUDE_BIN="$ARG_CLAUDE_BINARY_PATH/claude"
elif [ -x "$HOME/.local/bin/claude" ]; then
CLAUDE_BIN="$HOME/.local/bin/claude"
fi
if [ -n "${CODER_SCRIPT_BIN_DIR:-}" ] && [ ! -e "$CODER_SCRIPT_BIN_DIR/claude" ]; then
ln -s "$CLAUDE_BIN" "$CODER_SCRIPT_BIN_DIR/claude"
echo "Created symlink: $CODER_SCRIPT_BIN_DIR/claude -> $CLAUDE_BIN"
if [ -n "$CLAUDE_BIN" ] && [ -x "$CLAUDE_BIN" ]; then
ln -s "$CLAUDE_BIN" "$CODER_SCRIPT_BIN_DIR/claude"
echo "Created symlink: $CODER_SCRIPT_BIN_DIR/claude -> $CLAUDE_BIN"
else
echo "Warning: Could not find claude binary to symlink"
fi
else
echo "Claude already available in CODER_SCRIPT_BIN_DIR"
fi
add_path_to_shell_profiles "$CLAUDE_DIR"
local marker="# Added by claude-code module"
for profile in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.profile"; do
if [ -f "$profile" ] && ! grep -q "$marker" "$profile" 2> /dev/null; then
printf "\n%s\nexport PATH=\"%s:\$PATH\"\n" "$marker" "$CODER_SCRIPT_BIN_DIR" >> "$profile"
echo "Added $CODER_SCRIPT_BIN_DIR to PATH in $profile"
fi
done
}
function install_claude_code_cli() {
@@ -2,11 +2,6 @@
set -euo pipefail
ARG_CLAUDE_BINARY_PATH=${ARG_CLAUDE_BINARY_PATH:-"$HOME/.local/bin"}
ARG_CLAUDE_BINARY_PATH=$(eval echo "$ARG_CLAUDE_BINARY_PATH")
export PATH="$ARG_CLAUDE_BINARY_PATH:$PATH"
command_exists() {
command -v "$1" > /dev/null 2>&1
}
+3 -3
View File
@@ -14,7 +14,7 @@ Runs a script that updates git credentials in the workspace to match the user's
module "git-config" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-config/coder"
version = "1.0.33"
version = "1.0.32"
agent_id = coder_agent.main.id
}
```
@@ -29,7 +29,7 @@ TODO: Add screenshot
module "git-config" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-config/coder"
version = "1.0.33"
version = "1.0.32"
agent_id = coder_agent.main.id
allow_email_change = true
}
@@ -43,7 +43,7 @@ TODO: Add screenshot
module "git-config" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-config/coder"
version = "1.0.33"
version = "1.0.32"
agent_id = coder_agent.main.id
allow_username_change = false
allow_email_change = false
@@ -44,9 +44,6 @@ data "coder_parameter" "user_email" {
description = "Git user.email to be used for commits. Leave empty to default to Coder user's email."
display_name = "Git config user.email"
mutable = true
styling = jsonencode({
placeholder = data.coder_workspace_owner.me.email
})
}
data "coder_parameter" "username" {
@@ -58,9 +55,6 @@ data "coder_parameter" "username" {
description = "Git user.name to be used for commits. Leave empty to default to Coder user's Full Name."
display_name = "Full Name for Git config"
mutable = true
styling = jsonencode({
placeholder = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)
})
}
resource "coder_env" "git_author_name" {