@runuai/host 0.9.140 → 0.9.141
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/scripts/agent/task-up.sh +37 -1
package/package.json
CHANGED
package/scripts/agent/task-up.sh
CHANGED
|
@@ -141,6 +141,42 @@ reject_workspace_runtime_shadow() {
|
|
|
141
141
|
fi
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
# The first check of a task-up used to be the refusal above. A fresh task
|
|
145
|
+
# never trips it (the workspace is empty), but a RESUMED one can: the
|
|
146
|
+
# workspace persists across an idle park, agents' shells start in /workspace,
|
|
147
|
+
# and `asdf local nodejs 22` from there writes exactly this file — after
|
|
148
|
+
# which the task could never wake again without someone deleting the file on
|
|
149
|
+
# the host (client runner, 2026-09-14). The entry is the task's own
|
|
150
|
+
# container-writable content, so move it aside instead: a rename is
|
|
151
|
+
# metadata-only (never opens a FIFO/device/socket), the runtime proof is
|
|
152
|
+
# unchanged because nothing is left at the root, and the content survives
|
|
153
|
+
# under .uai/refused/ where the agent can re-pin it in a project. The
|
|
154
|
+
# post-materialization recheck below keeps refusing — by then the root must
|
|
155
|
+
# be empty by construction, so an entry there is a bug, not a user file.
|
|
156
|
+
quarantine_workspace_runtime_shadow() {
|
|
157
|
+
local path="$task_workspace/.tool-versions" aside_dir aside
|
|
158
|
+
if [ -L "$path" ] || [ -e "$path" ]; then
|
|
159
|
+
aside_dir="$task_workspace/.uai/refused"
|
|
160
|
+
reject_unsafe_host_directory "$task_workspace/.uai" "the task control directory"
|
|
161
|
+
reject_unsafe_host_directory "$aside_dir" "the refused-files directory"
|
|
162
|
+
mkdir -p "$aside_dir"
|
|
163
|
+
aside="$aside_dir/tool-versions.$(date +%s)"
|
|
164
|
+
if ! mv -f "$path" "$aside" 2>/dev/null || [ -L "$path" ] || [ -e "$path" ]; then
|
|
165
|
+
reject_workspace_runtime_shadow
|
|
166
|
+
fi
|
|
167
|
+
cat > "$aside_dir/README.txt" <<'NOTE'
|
|
168
|
+
Uai moved a /workspace/.tool-versions aside before starting this task.
|
|
169
|
+
|
|
170
|
+
A .tool-versions at the workspace root is outside the runtime proof and would
|
|
171
|
+
override the runtimes proved for every project in the task, so the host refuses
|
|
172
|
+
to start a container while one exists. The file is kept here, untouched, under
|
|
173
|
+
its original content. Pin runtimes in a project's own .tool-versions instead
|
|
174
|
+
(/workspace/<project>/.tool-versions), which the materializer proves.
|
|
175
|
+
NOTE
|
|
176
|
+
log "moved a workspace-root .tool-versions aside to ${aside#"$task_workspace"/} (it would override the runtimes proved for this task; pin per project instead)"
|
|
177
|
+
fi
|
|
178
|
+
}
|
|
179
|
+
|
|
144
180
|
mapped_host_port() {
|
|
145
181
|
local container="$1" container_port="$2"
|
|
146
182
|
docker port "$container" "$container_port" 2>/dev/null \
|
|
@@ -555,7 +591,7 @@ else
|
|
|
555
591
|
fi
|
|
556
592
|
reject_unsafe_host_directory "$task_workspace" "the task workspace"
|
|
557
593
|
mkdir -p "$task_workspace"
|
|
558
|
-
|
|
594
|
+
quarantine_workspace_runtime_shadow
|
|
559
595
|
|
|
560
596
|
# Git resolves symlinked ancestors when it writes a linked worktree's absolute
|
|
561
597
|
# `.git` pointer. Keep the configured (lexical) task paths as Uai's stable host
|