Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
bash -n .opencode_web_yolo.sh
bash -n .opencode_web_yolo_config.sh
bash -n .opencode_web_yolo_entrypoint.sh
bash -n .opencode_web_yolo_runtime.sh
bash -n install.sh
bash -n tests/test_helpers.sh
bash -n tests/test_dry_run.sh
Expand All @@ -37,13 +38,15 @@ jobs:
bash -n tests/test_source_of_truth_refs.sh
bash -n tests/test_docs_required_sections.sh
bash -n tests/test_technical_required_sections.sh
bash -n tests/test_session_retention.sh
bash -n tests/run.sh
bash -n tests/version_guard.sh
- name: Shellcheck
run: |
shellcheck -x .opencode_web_yolo.sh
shellcheck .opencode_web_yolo_config.sh
shellcheck .opencode_web_yolo_entrypoint.sh
shellcheck .opencode_web_yolo_runtime.sh
shellcheck install.sh
shellcheck -x tests/test_helpers.sh
shellcheck -x tests/test_dry_run.sh
Expand All @@ -66,8 +69,11 @@ jobs:
shellcheck -x tests/test_source_of_truth_refs.sh
shellcheck -x tests/test_docs_required_sections.sh
shellcheck -x tests/test_technical_required_sections.sh
shellcheck -x tests/test_session_retention.sh
shellcheck -x tests/run.sh
shellcheck -x tests/version_guard.sh
- name: JavaScript syntax check
run: node --check .opencode_web_yolo_retention.js

behavior-checks:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -100,7 +106,7 @@ jobs:
run: docker build -f .opencode_web_yolo.Dockerfile -t opencode_web_yolo:ci .
- name: Validate required binaries
run: |
docker run --rm --entrypoint sh opencode_web_yolo:ci -lc 'command -v gh && command -v git && command -v ssh'
docker run --rm --entrypoint sh opencode_web_yolo:ci -lc 'command -v gh && command -v git && command -v ssh && command -v tini'
- name: Build Playwright-enabled runtime image
run: |
docker build \
Expand Down
9 changes: 7 additions & 2 deletions .opencode_web_yolo.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ RUN apt-get update \
openssh-client \
passwd \
sudo \
tini \
&& rm -rf /var/lib/apt/lists/*

ARG OPENCODE_NPM_PACKAGE=opencode-ai
Expand Down Expand Up @@ -61,7 +62,11 @@ This is a built-in fallback instruction file used when no host AGENTS.md is moun
EOF

COPY .opencode_web_yolo_entrypoint.sh /usr/local/bin/opencode_web_yolo_entrypoint.sh
RUN chmod +x /usr/local/bin/opencode_web_yolo_entrypoint.sh
COPY .opencode_web_yolo_runtime.sh /usr/local/bin/opencode_web_yolo_runtime.sh
COPY .opencode_web_yolo_retention.js /usr/local/bin/opencode_web_yolo_retention.js
RUN chmod +x /usr/local/bin/opencode_web_yolo_entrypoint.sh \
/usr/local/bin/opencode_web_yolo_runtime.sh \
/usr/local/bin/opencode_web_yolo_retention.js

WORKDIR /workspace
ENTRYPOINT ["/usr/local/bin/opencode_web_yolo_entrypoint.sh"]
ENTRYPOINT ["/usr/bin/tini", "-s", "-g", "--", "/usr/local/bin/opencode_web_yolo_entrypoint.sh"]
71 changes: 70 additions & 1 deletion .opencode_web_yolo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,28 @@ normalize_bool() {
fi
}

validate_retention_days() {
local value
case "${OPENCODE_WEB_RETENTION_DAYS}" in
''|*[!0-9]*)
die "OPENCODE_WEB_RETENTION_DAYS must be a non-negative integer (received '${OPENCODE_WEB_RETENTION_DAYS:-unset}')."
;;
esac
value="${OPENCODE_WEB_RETENTION_DAYS}"
while [ "${value#0}" != "$value" ]; do value="${value#0}"; done
OPENCODE_WEB_RETENTION_DAYS="${value:-0}"
}

validate_positive_integer() {
local name="$1" value="$2"
if ! [[ "$value" =~ ^[1-9][0-9]*$ ]]; then
die "${name} must be a positive integer (received '${value:-unset}')."
fi
if [ "${#value}" -gt 10 ] || { [ "${#value}" -eq 10 ] && (( value > 2147483647 )); }; then
die "${name} is outside the supported positive integer range (received '${value}')."
fi
}

log() {
printf '%s\n' "[opencode_web_yolo] $*"
}
Expand Down Expand Up @@ -116,6 +138,8 @@ managed_files() {
.opencode_web_yolo_config.sh
.opencode_web_yolo.Dockerfile
.opencode_web_yolo_entrypoint.sh
.opencode_web_yolo_runtime.sh
.opencode_web_yolo_retention.js
.opencode_web_yolo_completion.bash
.opencode_web_yolo_completion.zsh
install.sh
Expand Down Expand Up @@ -214,6 +238,8 @@ Wrapper flags:
--no-pull Skip default pull-on-start behavior for this run.
--playwright Build runtime image with Playwright Chromium.
--wrangler Build Wrangler and mount host Wrangler config read-write.
--retention-days N Delete inactive root sessions older than N days (0 disables).
--retention-days=N Same as above, using an equals-form value.
--agents-file PATH Mount a host AGENTS.md file read-only.
--no-host-agents Skip mounting host AGENTS.md.
--dry-run Print docker command and exit.
Expand All @@ -238,6 +264,7 @@ Lifecycle defaults:
Restart policy: ${OPENCODE_WEB_RESTART_POLICY}
Background mode: ${OPENCODE_WEB_RUN_DETACHED}
Pull-on-start: ${OPENCODE_WEB_AUTO_PULL}
Session retention: ${OPENCODE_WEB_RETENTION_DAYS} days (0 disables)

First-time setup:
1) Create config file:
Expand Down Expand Up @@ -289,6 +316,12 @@ export OPENCODE_WEB_BUILD_PLAYWRIGHT=0
# This explicit pin remains effective even when version checks are skipped.
# export OPENCODE_WEB_EXPECTED_PLAYWRIGHT_VERSION=1.62.1
export OPENCODE_WEB_BUILD_WRANGLER=0
export OPENCODE_WEB_RETENTION_DAYS=0
# Set OPENCODE_WEB_RETENTION_DAYS to a non-negative integer to enable weekly cleanup.
# export OPENCODE_WEB_RETENTION_DRY_RUN=1
export OPENCODE_WEB_RETENTION_POLL_SECONDS=3600
export OPENCODE_WEB_RETENTION_FETCH_TIMEOUT_MS=10000
export OPENCODE_WEB_RETENTION_VERIFY_TIMEOUT_MS=10000
export OPENCODE_WEB_SKIP_UPDATE_CHECK=0
export OPENCODE_WEB_SKIP_VERSION_CHECK=0
# Required: set a non-empty password before running the server.
Expand Down Expand Up @@ -329,6 +362,13 @@ show_health() {
printf '%s\n' " build_pull=${OPENCODE_WEB_BUILD_PULL}"
printf '%s\n' " build_playwright=${OPENCODE_WEB_BUILD_PLAYWRIGHT}"
printf '%s\n' " build_wrangler=${OPENCODE_WEB_BUILD_WRANGLER}"
printf '%s\n' " retention_days=${OPENCODE_WEB_RETENTION_DAYS}"
printf '%s\n' " retention_dry_run=${OPENCODE_WEB_RETENTION_DRY_RUN}"
printf '%s\n' " retention_poll_seconds=${OPENCODE_WEB_RETENTION_POLL_SECONDS}"
printf '%s\n' " retention_fetch_timeout_ms=${OPENCODE_WEB_RETENTION_FETCH_TIMEOUT_MS}"
printf '%s\n' " retention_verify_timeout_ms=${OPENCODE_WEB_RETENTION_VERIFY_TIMEOUT_MS}"
printf '%s\n' " retention_schedule=after-health-at-most-weekly"
printf '%s\n' " retention_marker=${runtime_xdg_state}/session-retention.last-success"
printf '%s\n' " runtime_env_home=${runtime_home}"
printf '%s\n' " runtime_env_xdg_config_home=${runtime_xdg_config}"
printf '%s\n' " runtime_env_xdg_data_home=${runtime_xdg_data}"
Expand Down Expand Up @@ -659,6 +699,14 @@ main() {
OPENCODE_WEB_BUILD_WRANGLER=1
use_wrangler=1
;;
--retention-days=*)
OPENCODE_WEB_RETENTION_DAYS="${1#*=}"
;;
--retention-days)
shift
[ "$#" -gt 0 ] || die "--retention-days requires a non-negative integer value."
OPENCODE_WEB_RETENTION_DAYS="$1"
;;
--agents-file=*)
host_agents_enabled=1
host_agents_source="flag"
Expand Down Expand Up @@ -723,6 +771,13 @@ main() {
OPENCODE_WEB_RUN_DETACHED="$(normalize_bool "${OPENCODE_WEB_RUN_DETACHED}")"
OPENCODE_WEB_SKIP_UPDATE_CHECK="$(normalize_bool "${OPENCODE_WEB_SKIP_UPDATE_CHECK}")"
OPENCODE_WEB_SKIP_VERSION_CHECK="$(normalize_bool "${OPENCODE_WEB_SKIP_VERSION_CHECK}")"
OPENCODE_WEB_RETENTION_DRY_RUN="$(normalize_bool "${OPENCODE_WEB_RETENTION_DRY_RUN}")"
validate_retention_days
if [ "$OPENCODE_WEB_RETENTION_DAYS" != "0" ]; then
validate_positive_integer OPENCODE_WEB_RETENTION_POLL_SECONDS "${OPENCODE_WEB_RETENTION_POLL_SECONDS}"
validate_positive_integer OPENCODE_WEB_RETENTION_FETCH_TIMEOUT_MS "${OPENCODE_WEB_RETENTION_FETCH_TIMEOUT_MS}"
validate_positive_integer OPENCODE_WEB_RETENTION_VERIFY_TIMEOUT_MS "${OPENCODE_WEB_RETENTION_VERIFY_TIMEOUT_MS}"
fi

case "$mode" in
version)
Expand Down Expand Up @@ -750,6 +805,7 @@ main() {
fi

require_password
export OPENCODE_SERVER_PASSWORD
require_command docker
docker info >/dev/null 2>&1 || die "Docker daemon is not available."
[ -n "${OPENCODE_WEB_CONTAINER_NAME}" ] || die "OPENCODE_WEB_CONTAINER_NAME must be non-empty."
Expand All @@ -773,8 +829,14 @@ main() {
-e "LOCAL_USER=$(id -un)"
-e "OPENCODE_WEB_YOLO_CLEANUP=${OPENCODE_WEB_YOLO_CLEANUP}"
-e "OPENCODE_WEB_YOLO_HOME=${OPENCODE_WEB_YOLO_HOME}"
-e "OPENCODE_SERVER_PASSWORD=${OPENCODE_SERVER_PASSWORD}"
-e OPENCODE_SERVER_PASSWORD
-e "OPENCODE_SERVER_USERNAME=${OPENCODE_SERVER_USERNAME}"
-e "OPENCODE_WEB_PORT=${OPENCODE_WEB_PORT}"
-e "OPENCODE_WEB_RETENTION_DAYS=${OPENCODE_WEB_RETENTION_DAYS}"
-e "OPENCODE_WEB_RETENTION_DRY_RUN=${OPENCODE_WEB_RETENTION_DRY_RUN}"
-e "OPENCODE_WEB_RETENTION_POLL_SECONDS=${OPENCODE_WEB_RETENTION_POLL_SECONDS}"
-e "OPENCODE_WEB_RETENTION_FETCH_TIMEOUT_MS=${OPENCODE_WEB_RETENTION_FETCH_TIMEOUT_MS}"
-e "OPENCODE_WEB_RETENTION_VERIFY_TIMEOUT_MS=${OPENCODE_WEB_RETENTION_VERIFY_TIMEOUT_MS}"
-e "HOME=${runtime_home}"
-e "XDG_CONFIG_HOME=${runtime_xdg_config}"
-e "XDG_DATA_HOME=${runtime_xdg_data}"
Expand Down Expand Up @@ -883,6 +945,13 @@ main() {
printf '%s\n' "build_pull=${OPENCODE_WEB_BUILD_PULL}"
printf '%s\n' "build_playwright=${OPENCODE_WEB_BUILD_PLAYWRIGHT}"
printf '%s\n' "build_wrangler=${OPENCODE_WEB_BUILD_WRANGLER}"
printf '%s\n' "retention_days=${OPENCODE_WEB_RETENTION_DAYS}"
printf '%s\n' "retention_dry_run=${OPENCODE_WEB_RETENTION_DRY_RUN}"
printf '%s\n' "retention_poll_seconds=${OPENCODE_WEB_RETENTION_POLL_SECONDS}"
printf '%s\n' "retention_fetch_timeout_ms=${OPENCODE_WEB_RETENTION_FETCH_TIMEOUT_MS}"
printf '%s\n' "retention_verify_timeout_ms=${OPENCODE_WEB_RETENTION_VERIFY_TIMEOUT_MS}"
printf '%s\n' "retention_schedule=after-health-at-most-weekly"
printf '%s\n' "retention_marker=${runtime_xdg_state}/session-retention.last-success"
printf '%s\n' "opencode_config_dir=${OPENCODE_WEB_CONFIG_DIR}"
printf '%s\n' "opencode_data_dir=${OPENCODE_WEB_DATA_DIR}"
printf '%s\n' "runtime_env_home=${runtime_home}"
Expand Down
2 changes: 1 addition & 1 deletion .opencode_web_yolo_completion.bash
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ _opencode_web_yolo_completion() {
cur="${COMP_WORDS[COMP_CWORD]}"

local opts
opts="--pull --no-pull --playwright --wrangler --detach -d --foreground -f --mount-ssh -gh --gh --health diagnostics health config --version version --verbose -v --help -h help --"
opts="--pull --no-pull --playwright --wrangler --retention-days --retention-days= --detach -d --foreground -f --mount-ssh -gh --gh --health diagnostics health config --version version --verbose -v --help -h help --"

COMPREPLY=($(compgen -W "${opts}" -- "${cur}"))
}
Expand Down
1 change: 1 addition & 0 deletions .opencode_web_yolo_completion.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ _opencode_web_yolo_completion() {
'--no-pull:Skip default pull-on-start for this run'
'--playwright:Build runtime image with Playwright Chromium'
'--wrangler:Build Wrangler and mount host config read-write'
'--retention-days[Delete inactive root sessions older than N days]:days'
'--detach:Run in background mode'
'-d:Run in background mode'
'--foreground:Run attached in current terminal'
Expand Down
13 changes: 13 additions & 0 deletions .opencode_web_yolo_config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ OPENCODE_WEB_CONFIG_FILE="${OPENCODE_WEB_YOLO_CONFIG_FILE:-$OPENCODE_WEB_YOLO_CO
: "${OPENCODE_WEB_YOLO_BRANCH:=main}"
: "${OPENCODE_WEB_NPM_PACKAGE:=opencode-ai}"
: "${OPENCODE_SERVER_USERNAME:=opencode}"
if [ "${OPENCODE_WEB_RETENTION_DAYS+x}" != x ]; then
OPENCODE_WEB_RETENTION_DAYS=0
fi
: "${OPENCODE_WEB_RETENTION_DRY_RUN:=0}"
if [ "${OPENCODE_WEB_RETENTION_POLL_SECONDS+x}" != x ]; then
OPENCODE_WEB_RETENTION_POLL_SECONDS=3600
fi
if [ "${OPENCODE_WEB_RETENTION_FETCH_TIMEOUT_MS+x}" != x ]; then
OPENCODE_WEB_RETENTION_FETCH_TIMEOUT_MS=10000
fi
if [ "${OPENCODE_WEB_RETENTION_VERIFY_TIMEOUT_MS+x}" != x ]; then
OPENCODE_WEB_RETENTION_VERIFY_TIMEOUT_MS=10000
fi

if [ -f "$OPENCODE_WEB_CONFIG_FILE" ]; then
# shellcheck disable=SC1090
Expand Down
18 changes: 17 additions & 1 deletion .opencode_web_yolo_entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ OPENCODE_WEB_YOLO_CLEANUP="${OPENCODE_WEB_YOLO_CLEANUP:-1}"
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-${OPENCODE_WEB_YOLO_HOME}/.config}"
XDG_DATA_HOME="${XDG_DATA_HOME:-${OPENCODE_WEB_YOLO_HOME}/.local/share}"
XDG_STATE_HOME="${XDG_STATE_HOME:-${XDG_DATA_HOME}/opencode/state}"
OPENCODE_WEB_RETENTION_DAYS="${OPENCODE_WEB_RETENTION_DAYS-0}"

case "$OPENCODE_WEB_RETENTION_DAYS" in
''|*[!0-9]*)
printf '%s\n' "[opencode_web_yolo] ERROR: OPENCODE_WEB_RETENTION_DAYS must be a non-negative integer." >&2
exit 1
;;
esac
while [ "${OPENCODE_WEB_RETENTION_DAYS#0}" != "$OPENCODE_WEB_RETENTION_DAYS" ]; do
OPENCODE_WEB_RETENTION_DAYS="${OPENCODE_WEB_RETENTION_DAYS#0}"
done
OPENCODE_WEB_RETENTION_DAYS="${OPENCODE_WEB_RETENTION_DAYS:-0}"

if [ -z "${OPENCODE_SERVER_PASSWORD:-}" ]; then
printf '%s\n' "[opencode_web_yolo] ERROR: OPENCODE_SERVER_PASSWORD must be set and non-empty." >&2
Expand Down Expand Up @@ -68,4 +80,8 @@ export XDG_CONFIG_HOME="${XDG_CONFIG_HOME}"
export XDG_DATA_HOME="${XDG_DATA_HOME}"
export XDG_STATE_HOME="${XDG_STATE_HOME}"

exec env HOME="${HOME}" XDG_CONFIG_HOME="${XDG_CONFIG_HOME}" XDG_DATA_HOME="${XDG_DATA_HOME}" XDG_STATE_HOME="${XDG_STATE_HOME}" gosu "${runtime_user}" "$@"
if [ "$OPENCODE_WEB_RETENTION_DAYS" = "0" ]; then
exec env HOME="${HOME}" XDG_CONFIG_HOME="${XDG_CONFIG_HOME}" XDG_DATA_HOME="${XDG_DATA_HOME}" XDG_STATE_HOME="${XDG_STATE_HOME}" gosu "${runtime_user}" "$@"
fi

exec env HOME="${HOME}" XDG_CONFIG_HOME="${XDG_CONFIG_HOME}" XDG_DATA_HOME="${XDG_DATA_HOME}" XDG_STATE_HOME="${XDG_STATE_HOME}" OPENCODE_WEB_RETENTION_DAYS="${OPENCODE_WEB_RETENTION_DAYS}" OPENCODE_WEB_RETENTION_DRY_RUN="${OPENCODE_WEB_RETENTION_DRY_RUN:-0}" gosu "${runtime_user}" /usr/local/bin/opencode_web_yolo_runtime.sh "$@"
Loading
Loading