Skip to content

Commit 9e89f04

Browse files
fix: session resumption fix, and bug fixes for arg path logic (#522)
## Description Fix issue with commands being injected through prompt. Bug fix for logic in arg paths. <!-- Briefly describe what this PR does and why --> ## Type of Change - [ ] New module - [ ] New template - [X] Bug fix - [ ] Feature/enhancement - [ ] Documentation - [ ] Other ## Module Information <!-- Delete this section if not applicable --> **Path:** `registry/coder/modules/claude-code` **New version:** `v4.0.1` **Breaking change:** [ ] Yes [X] No ## Testing & Validation - [X] Tests pass (`bun test`) - [X] Code formatted (`bun fmt`) - [ ] Changes tested locally ## Related Issues <!-- Link related issues or write "None" if not applicable --> --------- Co-authored-by: DevelopmentCats <christofer@coder.com> Co-authored-by: DevelopmentCats <chris@dualriver.com>
1 parent 4edfdae commit 9e89f04

File tree

6 files changed

+112
-30
lines changed

6 files changed

+112
-30
lines changed

registry/coder/modules/claude-code/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Run the [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude
1313
```tf
1414
module "claude-code" {
1515
source = "registry.coder.com/coder/claude-code/coder"
16-
version = "4.0.0"
16+
version = "4.0.1"
1717
agent_id = coder_agent.example.id
1818
workdir = "/home/coder/project"
1919
claude_api_key = "xxxx-xxxxx-xxxx"
@@ -70,7 +70,7 @@ data "coder_parameter" "ai_prompt" {
7070
7171
module "claude-code" {
7272
source = "registry.coder.com/coder/claude-code/coder"
73-
version = "4.0.0"
73+
version = "4.0.1"
7474
agent_id = coder_agent.example.id
7575
workdir = "/home/coder/project"
7676
@@ -106,7 +106,7 @@ Run and configure Claude Code as a standalone CLI in your workspace.
106106
```tf
107107
module "claude-code" {
108108
source = "registry.coder.com/coder/claude-code/coder"
109-
version = "4.0.0"
109+
version = "4.0.1"
110110
agent_id = coder_agent.example.id
111111
workdir = "/home/coder"
112112
install_claude_code = true
@@ -129,7 +129,7 @@ variable "claude_code_oauth_token" {
129129
130130
module "claude-code" {
131131
source = "registry.coder.com/coder/claude-code/coder"
132-
version = "4.0.0"
132+
version = "4.0.1"
133133
agent_id = coder_agent.example.id
134134
workdir = "/home/coder/project"
135135
claude_code_oauth_token = var.claude_code_oauth_token
@@ -202,7 +202,7 @@ resource "coder_env" "bedrock_api_key" {
202202
203203
module "claude-code" {
204204
source = "registry.coder.com/coder/claude-code/coder"
205-
version = "4.0.0"
205+
version = "4.0.1"
206206
agent_id = coder_agent.example.id
207207
workdir = "/home/coder/project"
208208
model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
@@ -259,7 +259,7 @@ resource "coder_env" "google_application_credentials" {
259259
260260
module "claude-code" {
261261
source = "registry.coder.com/coder/claude-code/coder"
262-
version = "4.0.0"
262+
version = "4.0.1"
263263
agent_id = coder_agent.example.id
264264
workdir = "/home/coder/project"
265265
model = "claude-sonnet-4@20250514"

registry/coder/modules/claude-code/main.test.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,16 @@ describe("claude-code", async () => {
198198
expect(startLog.stdout).toContain(`--model ${model}`);
199199
});
200200

201-
test("claude-continue-resume-existing-session", async () => {
201+
test("claude-continue-resume-task-session", async () => {
202202
const { id } = await setup({
203203
moduleVariables: {
204204
continue: "true",
205+
report_tasks: "true",
205206
ai_prompt: "test prompt",
206207
},
207208
});
208209

209-
// Create a mock session file with the predefined task session ID
210+
// Create a mock task session file with the hardcoded task session ID
210211
const taskSessionId = "cd32e253-ca16-4fd3-9825-d837e74ae3c2";
211212
const sessionDir = `/home/coder/.claude/projects/-home-coder-project`;
212213
await execContainer(id, ["mkdir", "-p", sessionDir]);
@@ -226,6 +227,43 @@ describe("claude-code", async () => {
226227
expect(startLog.stdout).toContain("--resume");
227228
expect(startLog.stdout).toContain(taskSessionId);
228229
expect(startLog.stdout).toContain("Resuming existing task session");
230+
expect(startLog.stdout).toContain("--dangerously-skip-permissions");
231+
});
232+
233+
test("claude-continue-resume-standalone-session", async () => {
234+
const { id } = await setup({
235+
moduleVariables: {
236+
continue: "true",
237+
report_tasks: "false",
238+
ai_prompt: "test prompt",
239+
},
240+
});
241+
242+
const sessionId = "some-random-session-id";
243+
const workdir = "/home/coder/project";
244+
const claudeJson = {
245+
projects: {
246+
[workdir]: {
247+
lastSessionId: sessionId,
248+
},
249+
},
250+
};
251+
252+
await execContainer(id, [
253+
"bash",
254+
"-c",
255+
`echo '${JSON.stringify(claudeJson)}' > /home/coder/.claude.json`,
256+
]);
257+
258+
await execModuleScript(id);
259+
260+
const startLog = await execContainer(id, [
261+
"bash",
262+
"-c",
263+
"cat /home/coder/.claude-module/agentapi-start.log",
264+
]);
265+
expect(startLog.stdout).toContain("--continue");
266+
expect(startLog.stdout).toContain("Resuming existing session");
229267
});
230268

231269
test("pre-post-install-scripts", async () => {

registry/coder/modules/claude-code/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ module "agentapi" {
348348
ARG_PERMISSION_MODE='${var.permission_mode}' \
349349
ARG_WORKDIR='${local.workdir}' \
350350
ARG_AI_PROMPT='${base64encode(var.ai_prompt)}' \
351+
ARG_REPORT_TASKS='${var.report_tasks}' \
351352
ARG_ENABLE_BOUNDARY='${var.enable_boundary}' \
352353
ARG_BOUNDARY_VERSION='${var.boundary_version}' \
353354
ARG_BOUNDARY_LOG_DIR='${var.boundary_log_dir}' \

registry/coder/modules/claude-code/main.tftest.hcl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ run "test_claude_code_with_custom_options" {
5757
group = "development"
5858
icon = "/icon/custom.svg"
5959
model = "opus"
60-
task_prompt = "Help me write better code"
60+
ai_prompt = "Help me write better code"
6161
permission_mode = "plan"
6262
continue = true
6363
install_claude_code = false
@@ -88,8 +88,8 @@ run "test_claude_code_with_custom_options" {
8888
}
8989

9090
assert {
91-
condition = var.task_prompt == "Help me write better code"
92-
error_message = "Task prompt variable should be set correctly"
91+
condition = var.ai_prompt == "Help me write better code"
92+
error_message = "AI prompt variable should be set correctly"
9393
}
9494

9595
assert {

registry/coder/modules/claude-code/scripts/remove-last-session-id.sh

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,19 @@ echo ".claude.json path $claude_json_path"
2626
# Check if .claude.json exists
2727
if [ ! -f "$claude_json_path" ]; then
2828
echo "No .claude.json file found"
29-
exit 0
29+
exit 1
3030
fi
3131

3232
# Use jq to check if lastSessionId exists for the working directory and remove it
3333

3434
if jq -e ".projects[\"$working_dir\"].lastSessionId" "$claude_json_path" > /dev/null 2>&1; then
3535
# Remove lastSessionId and update the file
36-
jq "del(.projects[\"$working_dir\"].lastSessionId)" "$claude_json_path" > "${claude_json_path}.tmp" && mv "${claude_json_path}.tmp" "$claude_json_path"
37-
echo "Removed lastSessionId from .claude.json"
36+
if jq "del(.projects[\"$working_dir\"].lastSessionId)" "$claude_json_path" > "${claude_json_path}.tmp" && mv "${claude_json_path}.tmp" "$claude_json_path"; then
37+
echo "Removed lastSessionId from .claude.json"
38+
exit 0
39+
else
40+
echo "Failed to remove lastSessionId from .claude.json"
41+
fi
3842
else
3943
echo "No lastSessionId found in .claude.json - nothing to do"
4044
fi

registry/coder/modules/claude-code/scripts/start.sh

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ ARG_DANGEROUSLY_SKIP_PERMISSIONS=${ARG_DANGEROUSLY_SKIP_PERMISSIONS:-}
2020
ARG_PERMISSION_MODE=${ARG_PERMISSION_MODE:-}
2121
ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"}
2222
ARG_AI_PROMPT=$(echo -n "${ARG_AI_PROMPT:-}" | base64 -d)
23+
ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true}
2324
ARG_ENABLE_BOUNDARY=${ARG_ENABLE_BOUNDARY:-false}
2425
ARG_BOUNDARY_VERSION=${ARG_BOUNDARY_VERSION:-"main"}
2526
ARG_BOUNDARY_LOG_DIR=${ARG_BOUNDARY_LOG_DIR:-"/tmp/boundary_logs"}
@@ -38,6 +39,7 @@ printf "ARG_DANGEROUSLY_SKIP_PERMISSIONS: %s\n" "$ARG_DANGEROUSLY_SKIP_PERMISSIO
3839
printf "ARG_PERMISSION_MODE: %s\n" "$ARG_PERMISSION_MODE"
3940
printf "ARG_AI_PROMPT: %s\n" "$ARG_AI_PROMPT"
4041
printf "ARG_WORKDIR: %s\n" "$ARG_WORKDIR"
42+
printf "ARG_REPORT_TASKS: %s\n" "$ARG_REPORT_TASKS"
4143
printf "ARG_ENABLE_BOUNDARY: %s\n" "$ARG_ENABLE_BOUNDARY"
4244
printf "ARG_BOUNDARY_VERSION: %s\n" "$ARG_BOUNDARY_VERSION"
4345
printf "ARG_BOUNDARY_LOG_DIR: %s\n" "$ARG_BOUNDARY_LOG_DIR"
@@ -47,10 +49,18 @@ printf "ARG_CODER_HOST: %s\n" "$ARG_CODER_HOST"
4749

4850
echo "--------------------------------"
4951

50-
# see the remove-last-session-id.sh script for details
51-
# about why we need it
52-
# avoid exiting if the script fails
53-
bash "/tmp/remove-last-session-id.sh" "$(pwd)" 2> /dev/null || true
52+
# Clean up stale session data (see remove-last-session-id.sh for details)
53+
CAN_CONTINUE_CONVERSATION=false
54+
set +e
55+
bash "/tmp/remove-last-session-id.sh" "$(pwd)" 2> /dev/null
56+
session_cleanup_exit_code=$?
57+
set -e
58+
59+
case $session_cleanup_exit_code in
60+
0)
61+
CAN_CONTINUE_CONVERSATION=true
62+
;;
63+
esac
5464

5565
function install_boundary() {
5666
# Install boundary from public github repo
@@ -69,10 +79,15 @@ function validate_claude_installation() {
6979
fi
7080
}
7181

82+
# Hardcoded task session ID for Coder task reporting
83+
# This ensures all task sessions use a consistent, predictable ID
7284
TASK_SESSION_ID="cd32e253-ca16-4fd3-9825-d837e74ae3c2"
7385

7486
task_session_exists() {
75-
if find "$HOME/.claude" -type f -name "*${TASK_SESSION_ID}*" 2> /dev/null | grep -q .; then
87+
local workdir_normalized=$(echo "$ARG_WORKDIR" | tr '/' '-')
88+
local project_dir="$HOME/.claude/projects/${workdir_normalized}"
89+
90+
if [ -d "$project_dir" ] && find "$project_dir" -type f -name "*${TASK_SESSION_ID}*" 2> /dev/null | grep -q .; then
7691
return 0
7792
else
7893
return 1
@@ -97,39 +112,63 @@ function start_agentapi() {
97112
fi
98113

99114
if [ -n "$ARG_RESUME_SESSION_ID" ]; then
100-
echo "Using explicit resume_session_id: $ARG_RESUME_SESSION_ID"
115+
echo "Resuming task session by ID: $ARG_RESUME_SESSION_ID"
101116
ARGS+=(--resume "$ARG_RESUME_SESSION_ID")
102117
if [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ]; then
103118
ARGS+=(--dangerously-skip-permissions)
104119
fi
105120
elif [ "$ARG_CONTINUE" = "true" ]; then
106-
if task_session_exists; then
121+
if [ "$ARG_REPORT_TASKS" = "true" ] && task_session_exists; then
107122
echo "Task session detected (ID: $TASK_SESSION_ID)"
108123
ARGS+=(--resume "$TASK_SESSION_ID")
124+
ARGS+=(--dangerously-skip-permissions)
125+
echo "Resuming existing task session"
126+
elif [ "$ARG_REPORT_TASKS" = "false" ] && [ "$CAN_CONTINUE_CONVERSATION" = true ]; then
127+
echo "Previous session exists"
128+
ARGS+=(--continue)
109129
if [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ]; then
110130
ARGS+=(--dangerously-skip-permissions)
111131
fi
112-
echo "Resuming existing task session"
132+
echo "Resuming existing session"
113133
else
114-
echo "No existing task session found"
115-
ARGS+=(--session-id "$TASK_SESSION_ID")
134+
echo "No existing session found"
135+
if [ "$ARG_REPORT_TASKS" = "true" ]; then
136+
ARGS+=(--session-id "$TASK_SESSION_ID")
137+
fi
116138
if [ -n "$ARG_AI_PROMPT" ]; then
117-
ARGS+=(--dangerously-skip-permissions "$ARG_AI_PROMPT")
118-
echo "Starting new task session with prompt"
139+
if [ "$ARG_REPORT_TASKS" = "true" ]; then
140+
ARGS+=(--dangerously-skip-permissions -- "$ARG_AI_PROMPT")
141+
else
142+
if [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ]; then
143+
ARGS+=(--dangerously-skip-permissions)
144+
fi
145+
ARGS+=(-- "$ARG_AI_PROMPT")
146+
fi
147+
echo "Starting new session with prompt"
119148
else
120-
if [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ]; then
149+
if [ "$ARG_REPORT_TASKS" = "true" ] || [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ]; then
121150
ARGS+=(--dangerously-skip-permissions)
122151
fi
123-
echo "Starting new task session"
152+
echo "Starting new session"
124153
fi
125154
fi
126155
else
127156
echo "Continue disabled, starting fresh session"
157+
if [ "$ARG_REPORT_TASKS" = "true" ]; then
158+
ARGS+=(--session-id "$TASK_SESSION_ID")
159+
fi
128160
if [ -n "$ARG_AI_PROMPT" ]; then
129-
ARGS+=(--dangerously-skip-permissions "$ARG_AI_PROMPT")
161+
if [ "$ARG_REPORT_TASKS" = "true" ]; then
162+
ARGS+=(--dangerously-skip-permissions -- "$ARG_AI_PROMPT")
163+
else
164+
if [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ]; then
165+
ARGS+=(--dangerously-skip-permissions)
166+
fi
167+
ARGS+=(-- "$ARG_AI_PROMPT")
168+
fi
130169
echo "Starting new session with prompt"
131170
else
132-
if [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ]; then
171+
if [ "$ARG_REPORT_TASKS" = "true" ] || [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ]; then
133172
ARGS+=(--dangerously-skip-permissions)
134173
fi
135174
echo "Starting claude code session"

0 commit comments

Comments
 (0)