Add session resuming

This commit is contained in:
Samuel Aubertin
2025-11-14 11:21:14 +01:00
parent 67fd0cd9c9
commit 698ca67677
5 changed files with 71 additions and 6 deletions

View File

@@ -107,6 +107,7 @@ Targets are supplied after the code directory (or via `default_targets` in the m
| `build-if-missing` | No-op when the image already exists; otherwise delegates to `build`. |
| `rebuild` | Rebuild the image from scratch (`--no-cache`). |
| `run` | Default goal. Runs the container with Codex as entrypoint and passes `codex_args`. |
| `resume <session-id>` | Continues a Codex session by running `codex resume <session-id>` inside the container (builds if needed). |
| `login` | Starts Codex in login mode to bootstrap `${HOME}/.codex`. |
| `shell` | Launches `/bin/bash` inside the container for debugging. |
| `stop` | Best-effort stop of the running container (if any). |

View File

@@ -30,6 +30,8 @@ print_styled() {
for arg in "$@"; do
colored_args+=("$COLOR_HIGHLIGHT$arg$color")
done
# Format strings are defined within sloptrap, not user input.
# shellcheck disable=SC2059
printf "$fmt" "${colored_args[@]}"
else
printf '%b' "$fmt"
@@ -50,6 +52,8 @@ print_styled_err() {
for arg in "$@"; do
colored_args+=("$COLOR_HIGHLIGHT$arg$color")
done
# Format strings are defined within sloptrap, not user input.
# shellcheck disable=SC2059
printf "$fmt" "${colored_args[@]}" >&2
else
printf '%b' "$fmt" >&2
@@ -121,6 +125,7 @@ usage() {
info_line "\n"
info_line "Example targets:\n"
comment_line " run Build if needed, then launch Codex\n"
comment_line " resume <id> Build if needed, then run 'codex resume <id>'\n"
comment_line " shell Drop into an interactive /bin/bash session\n"
comment_line " clean Remove the project container/image cache\n"
comment_line " prune Remove dangling/unused sloptrap images\n"
@@ -1026,17 +1031,25 @@ prune_sloptrap_images() {
run_or_print "${cmd[@]}"
}
run_codex() {
if ! $DRY_RUN; then
status_line "Running %s\n" "$SLOPTRAP_IMAGE_NAME"
fi
run_codex_command() {
local -a extra_args=("$@")
local -a cmd=("${BASE_CONTAINER_CMD[@]}" "$SLOPTRAP_IMAGE_NAME")
if [[ ${#CODEX_ARGS_ARRAY[@]} -gt 0 ]]; then
cmd+=("${CODEX_ARGS_ARRAY[@]}")
fi
if [[ ${#extra_args[@]} -gt 0 ]]; then
cmd+=("${extra_args[@]}")
fi
run_or_print "${cmd[@]}"
}
run_codex() {
if ! $DRY_RUN; then
status_line "Running %s\n" "$SLOPTRAP_IMAGE_NAME"
fi
run_codex_command
}
run_login_target() {
if ! $DRY_RUN; then
status_line "Login %s\n" "$SLOPTRAP_IMAGE_NAME"
@@ -1053,6 +1066,23 @@ run_shell_target() {
run_or_print "${cmd[@]}"
}
run_resume_target() {
local session_id=$1
if ! $DRY_RUN; then
status_line "Resume %s (%s)\n" "$SLOPTRAP_IMAGE_NAME" "$session_id"
fi
run_codex_command resume "$session_id"
}
process_resume_target() {
local session_id=$1
if [[ -z $session_id ]]; then
error "target 'resume' requires a session identifier"
fi
build_if_missing
run_resume_target "$session_id"
}
dispatch_target() {
local target=$1
case "$target" in
@@ -1267,6 +1297,17 @@ if $AUTO_LOGIN; then
dispatch_target login
fi
for target in "${TARGETS[@]}"; do
dispatch_target "$target"
target_index=0
while (( target_index < ${#TARGETS[@]} )); do
current_target="${TARGETS[$target_index]}"
if [[ $current_target == "resume" ]]; then
if (( target_index + 1 >= ${#TARGETS[@]} )); then
error "target 'resume' requires a session identifier"
fi
process_resume_target "${TARGETS[$((target_index + 1))]}"
((target_index+=2))
continue
fi
dispatch_target "$current_target"
((target_index+=1))
done

View File

@@ -10,3 +10,4 @@ Current scenarios:
- `manifest_injection/` — ensures disallowed `make.*` overrides abort parsing.
- `helper_symlink/` — ensures `.sloptrap-ignores` cannot be a symlink to directories outside the project.
- `secret_mask/` — verifies masked files remain hidden even when sloptrap remaps the workspace mount.
- `resume_target/` — verifies the resume target passes the requested session identifier to Codex.

View File

@@ -0,0 +1,4 @@
# Resume Target Scenario
Empty project used by the regression suite to ensure the `resume` target
invokes `codex resume <session-id>` inside the container.

View File

@@ -289,6 +289,23 @@ run_secret_mask() {
teardown_stub_env
}
run_resume_target() {
local scenario_dir="$TEST_ROOT/resume_target"
printf '==> resume_target\n'
setup_stub_env
local session_id="019a81b7-32d2-7622-8639-6698c6579625"
if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" \
"$SLOPTRAP_BIN" "$scenario_dir" resume "$session_id" >/dev/null 2>&1; then
record_failure "resume_target: sloptrap exited non-zero"
teardown_stub_env
return
fi
if ! grep -q -- "resume $session_id" "$STUB_LOG"; then
record_failure "resume_target: resume invocation missing"
fi
teardown_stub_env
}
run_shellcheck
run_mount_injection
run_root_target
@@ -296,6 +313,7 @@ run_symlink_escape
run_manifest_injection
run_helper_symlink
run_secret_mask
run_resume_target
if [[ ${#failures[@]} -gt 0 ]]; then
printf '\nTest failures:\n'