From 4b2808521d151e03a03980bf66181c28a7461b5a Mon Sep 17 00:00:00 2001 From: Morgan Westlee Lunt Date: Wed, 22 Apr 2026 20:26:52 +0000 Subject: [PATCH 1/2] fix(claude-code): derive task session ID from workspace; add transcript_retention_days; emit Stop-hook idle sentinel The hardcoded TASK_SESSION_ID caused 'Session ID already in use' collisions whenever a home directory was templated or shared across workspaces. Derive a per-workspace UUIDv5 from data.coder_workspace.me.id instead so the session is stable across restarts of the same workspace but unique across workspaces. While here: - Quarantine invalid session files to .bak instead of silently deleting them so transcripts are recoverable. - Add transcript_retention_days input that maps to Claude Code's cleanupPeriodDays setting via /etc/claude-code/managed-settings.d/. - Register a Stop hook that touches ~/.claude-module/last-stop so template authors can wire workspace autostop or activity tracking off the file mtime. Fixes #726 --- registry/coder/modules/claude-code/README.md | 19 ++++ .../coder/modules/claude-code/main.test.ts | 98 ++++++++++++++++++- registry/coder/modules/claude-code/main.tf | 14 +++ .../modules/claude-code/scripts/install.sh | 46 +++++++++ .../modules/claude-code/scripts/start.sh | 42 +++++--- 5 files changed, 204 insertions(+), 15 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index 48b291bb0..bab851d32 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -36,6 +36,25 @@ module "claude-code" { By default, Claude Code automatically resumes existing conversations when your workspace restarts. Sessions are tracked per workspace directory, so conversations continue where you left off. If no session exists (first start), your `ai_prompt` will run normally. To disable this behavior and always start fresh, set `continue = false` +### Session lifecycle + +When task reporting is enabled the module pins Claude Code to a session ID derived from `data.coder_workspace.me.id` (UUIDv5). This keeps the conversation stable across restarts of the same workspace while remaining unique per workspace, avoiding the "Session ID already in use" error that can occur when home directories are templated or shared. + +The module also writes a managed settings drop-in at `/etc/claude-code/managed-settings.d/30-coder-lifecycle.json` that: + +- registers a `Stop` hook which touches `~/.claude-module/last-stop` whenever Claude finishes a turn, so template authors can wire workspace autostop or activity tracking off that file's modification time +- sets `cleanupPeriodDays` when `transcript_retention_days` is provided, so session JSONL transcripts are pruned automatically + +```tf +module "claude-code" { + source = "registry.coder.com/coder/claude-code/coder" + version = "4.9.2" + agent_id = coder_agent.main.id + workdir = "/home/coder/project" + transcript_retention_days = 7 +} +``` + ## State Persistence AgentAPI can save and restore its conversation state to disk across workspace restarts. This complements `continue` (which resumes the Claude CLI session) by also preserving the AgentAPI-level context. Enabled by default, requires agentapi >= v0.12.0 (older versions skip it with a warning). diff --git a/registry/coder/modules/claude-code/main.test.ts b/registry/coder/modules/claude-code/main.test.ts index b01e88327..46fa2e459 100644 --- a/registry/coder/modules/claude-code/main.test.ts +++ b/registry/coder/modules/claude-code/main.test.ts @@ -66,6 +66,26 @@ const setup = async ( return { id, coderEnvVars }; }; +// start.sh derives TASK_SESSION_ID as uuid5(NAMESPACE_URL, "coder-workspace://" + workspace_id). +// The workspace_id comes from data.coder_workspace.me.id which the coder +// provider resolves from the host environment, so we recompute it here from +// the rendered script rather than hardcoding a value that varies by host. +const deriveTaskSessionId = async (id: string): Promise => { + const script = await readFileContainer(id, "/home/coder/script.sh"); + const m = script.match(/ARG_WORKSPACE_ID='([^']*)'/); + const workspaceId = m?.[1] ?? ""; + if (workspaceId === "") { + return "cd32e253-ca16-4fd3-9825-d837e74ae3c2"; + } + const resp = await execContainer(id, [ + "python3", + "-c", + 'import uuid,sys; print(uuid.uuid5(uuid.NAMESPACE_URL, "coder-workspace://" + sys.argv[1]))', + workspaceId, + ]); + return resp.stdout.trim(); +}; + setDefaultTimeout(60 * 1000); describe("claude-code", async () => { @@ -222,9 +242,8 @@ describe("claude-code", async () => { }, }); - // Create a mock task session file with the hardcoded task session ID // Note: Claude CLI creates files without "session-" prefix when using --session-id - const taskSessionId = "cd32e253-ca16-4fd3-9825-d837e74ae3c2"; + const taskSessionId = await deriveTaskSessionId(id); const sessionDir = `/home/coder/.claude/projects/-home-coder-project`; await execContainer(id, ["mkdir", "-p", sessionDir]); await execContainer(id, [ @@ -353,7 +372,7 @@ SESSIONEOF`, }, }); - const taskSessionId = "cd32e253-ca16-4fd3-9825-d837e74ae3c2"; + const taskSessionId = await deriveTaskSessionId(id); const sessionDir = `/home/coder/.claude/projects/-home-coder-project`; await execContainer(id, ["mkdir", "-p", sessionDir]); @@ -374,6 +393,10 @@ SESSIONEOF`, // Should start new session, not try to resume invalid one expect(startLog.stdout).toContain("Starting new task session"); expect(startLog.stdout).toContain("--session-id"); + + // Invalid session file should be quarantined, not deleted + const ls = await execContainer(id, ["ls", sessionDir]); + expect(ls.stdout).toContain(`${taskSessionId}.jsonl.bak`); }); test("standalone-first-build-no-sessions", async () => { @@ -442,7 +465,7 @@ EOF`, }, }); - const taskSessionId = "cd32e253-ca16-4fd3-9825-d837e74ae3c2"; + const taskSessionId = await deriveTaskSessionId(id); const sessionDir = `/home/coder/.claude/projects/-home-coder-project`; await execContainer(id, ["mkdir", "-p", sessionDir]); @@ -529,4 +552,71 @@ EOF`, expect(claudeConfig).toContain("typescript-language-server"); expect(claudeConfig).toContain("go-language-server"); }); + + test("task-session-id-derived-from-workspace", async () => { + const { id } = await setup({ + moduleVariables: { + continue: "true", + report_tasks: "true", + ai_prompt: "test prompt", + }, + }); + const expected = await deriveTaskSessionId(id); + + await execModuleScript(id); + + const startLog = await readFileContainer( + id, + "/home/coder/.claude-module/agentapi-start.log", + ); + expect(startLog).toContain(`TASK_SESSION_ID: ${expected}`); + expect(startLog).toContain(`--session-id ${expected}`); + // The legacy hardcoded ID must not be used when a workspace ID is available + if (expected !== "cd32e253-ca16-4fd3-9825-d837e74ae3c2") { + expect(startLog).not.toContain( + "--session-id cd32e253-ca16-4fd3-9825-d837e74ae3c2", + ); + } + }); + + test("lifecycle-settings-written", async () => { + const { id } = await setup({ + moduleVariables: { + transcript_retention_days: "7", + }, + }); + await execModuleScript(id); + + const installLog = await readFileContainer( + id, + "/home/coder/.claude-module/install.log", + ); + expect(installLog).toContain("Wrote lifecycle settings to"); + + const settings = await readFileContainer( + id, + "/etc/claude-code/managed-settings.d/30-coder-lifecycle.json", + ); + const parsed = JSON.parse(settings); + expect(parsed.cleanupPeriodDays).toBe(7); + expect(parsed.hooks.Stop[0].hooks[0].type).toBe("command"); + expect(parsed.hooks.Stop[0].hooks[0].command).toContain("touch"); + expect(parsed.hooks.Stop[0].hooks[0].command).toContain( + "/home/coder/.claude-module/last-stop", + ); + }); + + test("lifecycle-settings-default-retention", async () => { + const { id } = await setup({}); + await execModuleScript(id); + + const settings = await readFileContainer( + id, + "/etc/claude-code/managed-settings.d/30-coder-lifecycle.json", + ); + const parsed = JSON.parse(settings); + // Stop hook is always present; cleanupPeriodDays only when explicitly set + expect(parsed.hooks.Stop).toBeDefined(); + expect(parsed.cleanupPeriodDays).toBeUndefined(); + }); }); diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index db234c052..62d961d49 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -273,6 +273,17 @@ variable "enable_state_persistence" { default = true } +variable "transcript_retention_days" { + type = number + description = "Days to keep Claude Code session transcripts before automatic cleanup. Maps to Claude Code's cleanupPeriodDays setting. Defaults to Claude Code's built-in retention (30 days) when unset." + default = null + + validation { + condition = var.transcript_retention_days == null ? true : var.transcript_retention_days >= 1 + error_message = "transcript_retention_days must be at least 1." + } +} + resource "coder_env" "claude_code_md_path" { count = var.claude_md_path == "" ? 0 : 1 agent_id = var.agent_id @@ -407,6 +418,7 @@ module "agentapi" { ARG_COMPILE_FROM_SOURCE='${var.compile_boundary_from_source}' \ ARG_USE_BOUNDARY_DIRECTLY='${var.use_boundary_directly}' \ ARG_CODER_HOST='${local.coder_host}' \ + ARG_WORKSPACE_ID='${data.coder_workspace.me.id}' \ ARG_CLAUDE_BINARY_PATH='${var.claude_binary_path}' \ /tmp/start.sh EOT @@ -431,6 +443,8 @@ module "agentapi" { ARG_MCP_CONFIG_REMOTE_PATH='${base64encode(jsonencode(var.mcp_config_remote_path))}' \ ARG_ENABLE_AIBRIDGE='${var.enable_aibridge}' \ ARG_PERMISSION_MODE='${var.permission_mode}' \ + ARG_WORKSPACE_ID='${data.coder_workspace.me.id}' \ + ARG_TRANSCRIPT_RETENTION_DAYS='${var.transcript_retention_days != null ? var.transcript_retention_days : ""}' \ /tmp/install.sh EOT } diff --git a/registry/coder/modules/claude-code/scripts/install.sh b/registry/coder/modules/claude-code/scripts/install.sh index c00773b5e..ffe971d77 100644 --- a/registry/coder/modules/claude-code/scripts/install.sh +++ b/registry/coder/modules/claude-code/scripts/install.sh @@ -23,6 +23,8 @@ ARG_ALLOWED_TOOLS=${ARG_ALLOWED_TOOLS:-} ARG_DISALLOWED_TOOLS=${ARG_DISALLOWED_TOOLS:-} ARG_ENABLE_AIBRIDGE=${ARG_ENABLE_AIBRIDGE:-false} ARG_PERMISSION_MODE=${ARG_PERMISSION_MODE:-} +ARG_WORKSPACE_ID=${ARG_WORKSPACE_ID:-} +ARG_TRANSCRIPT_RETENTION_DAYS=${ARG_TRANSCRIPT_RETENTION_DAYS:-} export PATH="$ARG_CLAUDE_BINARY_PATH:$PATH" @@ -40,6 +42,8 @@ printf "ARG_MCP_CONFIG_REMOTE_PATH: %s\n" "$ARG_MCP_CONFIG_REMOTE_PATH" printf "ARG_ALLOWED_TOOLS: %s\n" "$ARG_ALLOWED_TOOLS" printf "ARG_DISALLOWED_TOOLS: %s\n" "$ARG_DISALLOWED_TOOLS" printf "ARG_ENABLE_AIBRIDGE: %s\n" "$ARG_ENABLE_AIBRIDGE" +printf "ARG_WORKSPACE_ID: %s\n" "$ARG_WORKSPACE_ID" +printf "ARG_TRANSCRIPT_RETENTION_DAYS: %s\n" "$ARG_TRANSCRIPT_RETENTION_DAYS" echo "--------------------------------" @@ -238,6 +242,47 @@ function report_tasks() { fi } +function configure_lifecycle_settings() { + # Write a managed-settings drop-in that: + # - registers a Stop hook touching a sentinel file whose mtime can be + # polled by Coder autostop logic to detect when the agent went idle + # - optionally sets cleanupPeriodDays so transcripts age out + # Managed settings live at /etc/claude-code on Linux and are read by the + # Claude CLI on every backend (Anthropic API, Bedrock, Vertex, gateway). + local module_path="$HOME/.claude-module" + mkdir -p "$module_path" + + local settings_dir="/etc/claude-code/managed-settings.d" + local settings_file="$settings_dir/30-coder-lifecycle.json" + local sentinel="$module_path/last-stop" + + if command_exists sudo; then + SUDO="sudo" + else + SUDO="" + fi + + if ! $SUDO mkdir -p "$settings_dir" 2> /dev/null; then + echo "Warning: cannot create $settings_dir (no write access); skipping lifecycle settings" + return + fi + + local hook_json + hook_json=$( + jq -n --arg sentinel "$sentinel" \ + '{hooks: {Stop: [{hooks: [{type: "command", command: ("touch " + ($sentinel | @sh))}]}]}}' + ) + + local payload="$hook_json" + if [ -n "$ARG_TRANSCRIPT_RETENTION_DAYS" ]; then + payload=$(echo "$hook_json" | jq --argjson days "$ARG_TRANSCRIPT_RETENTION_DAYS" '. + {cleanupPeriodDays: $days}') + fi + + echo "$payload" | $SUDO tee "$settings_file" > /dev/null + $SUDO chmod 0644 "$settings_file" + echo "Wrote lifecycle settings to $settings_file" +} + function accept_auto_mode() { # Pre-accept the auto mode TOS prompt so it doesn't appear interactively. # Claude Code shows a confirmation dialog for auto mode that blocks @@ -259,6 +304,7 @@ function accept_auto_mode() { install_claude_code_cli setup_claude_configurations report_tasks +configure_lifecycle_settings if [ "$ARG_PERMISSION_MODE" = "auto" ]; then accept_auto_mode diff --git a/registry/coder/modules/claude-code/scripts/start.sh b/registry/coder/modules/claude-code/scripts/start.sh index 5ccbc8fa1..b46c40df2 100644 --- a/registry/coder/modules/claude-code/scripts/start.sh +++ b/registry/coder/modules/claude-code/scripts/start.sh @@ -24,6 +24,7 @@ ARG_BOUNDARY_VERSION=${ARG_BOUNDARY_VERSION:-"latest"} ARG_COMPILE_FROM_SOURCE=${ARG_COMPILE_FROM_SOURCE:-false} ARG_USE_BOUNDARY_DIRECTLY=${ARG_USE_BOUNDARY_DIRECTLY:-false} ARG_CODER_HOST=${ARG_CODER_HOST:-} +ARG_WORKSPACE_ID=${ARG_WORKSPACE_ID:-} echo "--------------------------------" @@ -39,6 +40,7 @@ printf "ARG_BOUNDARY_VERSION: %s\n" "$ARG_BOUNDARY_VERSION" printf "ARG_COMPILE_FROM_SOURCE: %s\n" "$ARG_COMPILE_FROM_SOURCE" printf "ARG_USE_BOUNDARY_DIRECTLY: %s\n" "$ARG_USE_BOUNDARY_DIRECTLY" printf "ARG_CODER_HOST: %s\n" "$ARG_CODER_HOST" +printf "ARG_WORKSPACE_ID: %s\n" "$ARG_WORKSPACE_ID" echo "--------------------------------" @@ -82,9 +84,27 @@ function validate_claude_installation() { fi } -# Hardcoded task session ID for Coder task reporting -# This ensures all task sessions use a consistent, predictable ID -TASK_SESSION_ID="cd32e253-ca16-4fd3-9825-d837e74ae3c2" +# Derive a stable task session ID from the workspace ID so that the Claude +# session is consistent across restarts of the same workspace but unique +# across different workspaces. A globally hardcoded ID causes "Session ID +# already in use" collisions when a home directory is shared or templated +# across workspaces (https://github.com/coder/registry/issues/726). +LEGACY_TASK_SESSION_ID="cd32e253-ca16-4fd3-9825-d837e74ae3c2" +derive_task_session_id() { + if [ -z "$ARG_WORKSPACE_ID" ]; then + printf '%s' "$LEGACY_TASK_SESSION_ID" + return + fi + if command_exists python3; then + python3 -c 'import uuid,sys; print(uuid.uuid5(uuid.NAMESPACE_URL, "coder-workspace://" + sys.argv[1]))' "$ARG_WORKSPACE_ID" + return + fi + # Coder workspace IDs are already RFC 4122 UUIDs, so fall back to using the + # workspace ID directly when python3 is unavailable. + printf '%s' "$ARG_WORKSPACE_ID" +} +TASK_SESSION_ID=$(derive_task_session_id) +printf "TASK_SESSION_ID: %s\n" "$TASK_SESSION_ID" get_project_dir() { local workdir_normalized @@ -120,8 +140,8 @@ is_valid_session() { fi if [ ! -s "$session_file" ]; then - printf "Session validation failed: file is empty, removing stale file\n" - rm -f "$session_file" + printf "Session validation failed: file is empty, quarantining stale file\n" + mv -f "$session_file" "$session_file.bak" return 1 fi @@ -130,16 +150,16 @@ is_valid_session() { local line_count line_count=$(wc -l < "$session_file") if [ "$line_count" -lt 2 ]; then - printf "Session validation failed: incomplete (only %s lines), removing incomplete file\n" "$line_count" - rm -f "$session_file" + printf "Session validation failed: incomplete (only %s lines), quarantining incomplete file\n" "$line_count" + mv -f "$session_file" "$session_file.bak" return 1 fi # Validate JSONL format by checking first 3 lines # Claude session files use JSONL (JSON Lines) format where each line is valid JSON if ! head -3 "$session_file" | jq empty 2> /dev/null; then - printf "Session validation failed: invalid JSONL format, removing corrupt file\n" - rm -f "$session_file" + printf "Session validation failed: invalid JSONL format, quarantining corrupt file\n" + mv -f "$session_file" "$session_file.bak" return 1 fi @@ -147,8 +167,8 @@ is_valid_session() { # This ensures the file structure matches Claude's session format if ! grep -q '"sessionId"' "$session_file" \ || ! grep -m 1 '"sessionId"' "$session_file" | jq -e '.sessionId' > /dev/null 2>&1; then - printf "Session validation failed: no valid sessionId found, removing malformed file\n" - rm -f "$session_file" + printf "Session validation failed: no valid sessionId found, quarantining malformed file\n" + mv -f "$session_file" "$session_file.bak" return 1 fi From 11925ea71ecd0e83f84f71703a0631fa106ca96b Mon Sep 17 00:00:00 2001 From: Morgan Westlee Lunt Date: Thu, 23 Apr 2026 23:59:18 +0000 Subject: [PATCH 2/2] address review: bump version to 4.9.3; fix bun tests - Pin CODER_WORKSPACE_ID in tests so the derived session UUID is deterministic across hosts and runs. The previous helper tried to parse the workspace ID out of script.sh, but the install/start scripts are base64-encoded inside the agentapi wrapper so the regex never matched and the helper silently fell back to the legacy hardcoded value. - Call configure_lifecycle_settings before report_tasks in install.sh. report_tasks invokes the coder CLI which is absent in the test container, and set -e was aborting before the lifecycle settings file was written. - Bump README example version 4.9.2 -> 4.9.3. --- registry/coder/modules/claude-code/README.md | 20 +++++++------- .../coder/modules/claude-code/main.test.ts | 27 +++++++------------ .../modules/claude-code/scripts/install.sh | 2 +- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index bab851d32..7107347ef 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -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.9.2" + version = "4.9.3" agent_id = coder_agent.main.id workdir = "/home/coder/project" claude_api_key = "xxxx-xxxxx-xxxx" @@ -48,7 +48,7 @@ The module also writes a managed settings drop-in at `/etc/claude-code/managed-s ```tf module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.9.2" + version = "4.9.3" agent_id = coder_agent.main.id workdir = "/home/coder/project" transcript_retention_days = 7 @@ -79,7 +79,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.9.2" + version = "4.9.3" agent_id = coder_agent.main.id workdir = "/home/coder/project" enable_boundary = true @@ -100,7 +100,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.9.2" + version = "4.9.3" agent_id = coder_agent.main.id workdir = "/home/coder/project" enable_aibridge = true @@ -129,7 +129,7 @@ data "coder_task" "me" {} module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.9.2" + version = "4.9.3" agent_id = coder_agent.main.id workdir = "/home/coder/project" ai_prompt = data.coder_task.me.prompt @@ -152,7 +152,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.9.2" + version = "4.9.3" agent_id = coder_agent.main.id workdir = "/home/coder/project" @@ -208,7 +208,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.9.2" + version = "4.9.3" agent_id = coder_agent.main.id workdir = "/home/coder/project" install_claude_code = true @@ -230,7 +230,7 @@ variable "claude_code_oauth_token" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.9.2" + version = "4.9.3" agent_id = coder_agent.main.id workdir = "/home/coder/project" claude_code_oauth_token = var.claude_code_oauth_token @@ -303,7 +303,7 @@ resource "coder_env" "bedrock_api_key" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.9.2" + version = "4.9.3" agent_id = coder_agent.main.id workdir = "/home/coder/project" model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0" @@ -360,7 +360,7 @@ resource "coder_env" "google_application_credentials" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.9.2" + version = "4.9.3" agent_id = coder_agent.main.id workdir = "/home/coder/project" model = "claude-sonnet-4@20250514" diff --git a/registry/coder/modules/claude-code/main.test.ts b/registry/coder/modules/claude-code/main.test.ts index 46fa2e459..7f14ba9de 100644 --- a/registry/coder/modules/claude-code/main.test.ts +++ b/registry/coder/modules/claude-code/main.test.ts @@ -67,23 +67,16 @@ const setup = async ( }; // start.sh derives TASK_SESSION_ID as uuid5(NAMESPACE_URL, "coder-workspace://" + workspace_id). -// The workspace_id comes from data.coder_workspace.me.id which the coder -// provider resolves from the host environment, so we recompute it here from -// the rendered script rather than hardcoding a value that varies by host. -const deriveTaskSessionId = async (id: string): Promise => { - const script = await readFileContainer(id, "/home/coder/script.sh"); - const m = script.match(/ARG_WORKSPACE_ID='([^']*)'/); - const workspaceId = m?.[1] ?? ""; - if (workspaceId === "") { - return "cd32e253-ca16-4fd3-9825-d837e74ae3c2"; - } - const resp = await execContainer(id, [ - "python3", - "-c", - 'import uuid,sys; print(uuid.uuid5(uuid.NAMESPACE_URL, "coder-workspace://" + sys.argv[1]))', - workspaceId, - ]); - return resp.stdout.trim(); +// The coder provider populates data.coder_workspace.me.id from CODER_WORKSPACE_ID, +// generating a random value per terraform-apply when unset. Pin it so the +// expected session ID is stable across hosts and runs. +const TEST_CODER_WORKSPACE_ID = "e3aee544-5dbb-4c97-846c-ee9e50a6a06f"; +process.env.CODER_WORKSPACE_ID = TEST_CODER_WORKSPACE_ID; +// uuid5(NAMESPACE_URL, "coder-workspace://" + TEST_CODER_WORKSPACE_ID) +const TEST_TASK_SESSION_ID = "feac99e4-b036-54e7-8ecb-b12e95960344"; + +const deriveTaskSessionId = async (_id: string): Promise => { + return TEST_TASK_SESSION_ID; }; setDefaultTimeout(60 * 1000); diff --git a/registry/coder/modules/claude-code/scripts/install.sh b/registry/coder/modules/claude-code/scripts/install.sh index ffe971d77..32041a0bc 100644 --- a/registry/coder/modules/claude-code/scripts/install.sh +++ b/registry/coder/modules/claude-code/scripts/install.sh @@ -303,8 +303,8 @@ function accept_auto_mode() { install_claude_code_cli setup_claude_configurations -report_tasks configure_lifecycle_settings +report_tasks if [ "$ARG_PERMISSION_MODE" = "auto" ]; then accept_auto_mode