From f252d7680b04138a3230fe2ca62e578917dd806b Mon Sep 17 00:00:00 2001 From: librelad Date: Wed, 27 May 2026 14:51:13 +0100 Subject: [PATCH] fix(cli): camelCase task fields match WebUI shape (createdAt, not created_at) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WebUI-created tasks emit camelCase initial fields (createdAt, startedAt, completedAt, heartbeatAt, exitCode, errorMessage) per tasks-manager.js / task-manager.js conventions, with createdAt in ISO-UTC-with-ms (`2026-05-27T13:01:26.345Z`). The processor then layers snake_case status fields (started_at, heartbeat_at, …) on top as the task runs. The CLI's cliTaskRun was writing snake_case only — `created_at` with local-tz offset. The task panel's renderer reads `task.createdAt` directly (no alias), so CLI-queued tasks showed blank Created/Started columns until the processor wrote its own snake_case overlay (which doesn't include createdAt at all). Visible symptom: dates "broken" on CLI-queued tasks. Now the initial JSON cliTaskRun writes matches what the WebUI's "Install" button writes: { id, command, status: queued, createdAt: "", startedAt: null, completedAt: null, heartbeatAt: null, exitCode: null, errorMessage: null, type, app } Processor side is unchanged (still adds snake_case overlay on status transitions — that's how WebUI tasks already work). No JSON shape change for in-flight tasks. ALSO (out-of-repo): /home/user/Documents/Scripts/update.sh now restarts the systemd `libreportal.service` task processor after the docker `libreportal-service` container restart. Same reason — both pre-load code at startup, both need a restart to pick up changes. Without this, deploys silently kept a stale processor running old code while the disk reflected the new code; the install task-routing recursion I just saw was a direct consequence. Signed-off-by: librelad --- scripts/cli/task/cli_task_run.sh | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/scripts/cli/task/cli_task_run.sh b/scripts/cli/task/cli_task_run.sh index 1284a56..191e0d6 100644 --- a/scripts/cli/task/cli_task_run.sh +++ b/scripts/cli/task/cli_task_run.sh @@ -37,28 +37,41 @@ _writeTaskFile() { local task_id="$1" command="$2" task_type="$3" app_name="$4" local task_dir; task_dir=$(_taskDir) local task_file="$task_dir/${task_id}.json" - local created_at; created_at=$(date -Iseconds 2>/dev/null || date '+%Y-%m-%dT%H:%M:%S') + # ISO-8601 UTC with milliseconds. Matches the format the WebUI's + # tasks-manager.js emits (Date.now() → toISOString()), so the tasks + # panel's `new Date(task.createdAt).toLocaleString()` renders correctly. + # Falls back to seconds-precision if %3N isn't supported (busybox). + local created_at + created_at=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ" 2>/dev/null) \ + || created_at=$(date -u +"%Y-%m-%dT%H:%M:%SZ") [[ -d "$task_dir" ]] || runFileOp mkdir -p "$task_dir" + # CamelCase initial fields match the WebUI's task shape; processor adds + # snake_case status fields on top as it runs. Both task-manager.js and + # tasks-manager.js read camelCase directly (no alias needed for createdAt). local task_json if command -v jq >/dev/null 2>&1; then task_json=$(jq -n \ --arg id "$task_id" \ --arg command "$command" \ --arg status queued \ - --arg created_at "$created_at" \ + --arg createdAt "$created_at" \ --arg type "${task_type:-}" \ --arg app "${app_name:-}" \ - '{id:$id, command:$command, status:$status, created_at:$created_at} + '{id:$id, command:$command, status:$status, createdAt:$createdAt, + startedAt:null, completedAt:null, heartbeatAt:null, + exitCode:null, errorMessage:null} + (if $type != "" then {type:$type} else {} end) + (if $app != "" then {app:$app} else {} end)') else # Plain string interpolation — command is the only field that needs - # escaping. Strip control chars; the install dispatcher uses ascii - # only so this is sufficient without pulling jq in. + # escaping. Strip control chars; the dispatcher uses ascii only so + # this is sufficient without pulling jq in. local esc="${command//\\/\\\\}"; esc="${esc//\"/\\\"}" - task_json="{\"id\":\"$task_id\",\"command\":\"$esc\",\"status\":\"queued\",\"created_at\":\"$created_at\"" + task_json="{\"id\":\"$task_id\",\"command\":\"$esc\",\"status\":\"queued\",\"createdAt\":\"$created_at\"" + task_json+=",\"startedAt\":null,\"completedAt\":null,\"heartbeatAt\":null" + task_json+=",\"exitCode\":null,\"errorMessage\":null" [[ -n "$task_type" ]] && task_json+=",\"type\":\"$task_type\"" [[ -n "$app_name" ]] && task_json+=",\"app\":\"$app_name\"" task_json+="}"