@task-handoff/server 0.0.46 → 0.0.48
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.
|
@@ -24,6 +24,9 @@ AUTH_MODE="password"
|
|
|
24
24
|
NPM_REGISTRY=""
|
|
25
25
|
STATIC_DIR=""
|
|
26
26
|
MATERIALIZE_ONLY="0"
|
|
27
|
+
JS_RUNTIME="${TASK_HANDOFF_JS_RUNTIME:-}"
|
|
28
|
+
JS_RUNTIME_COMMAND=""
|
|
29
|
+
MIN_BUN_VERSION="1.4.4"
|
|
27
30
|
|
|
28
31
|
usage() {
|
|
29
32
|
cat <<'USAGE'
|
|
@@ -48,6 +51,7 @@ Options:
|
|
|
48
51
|
--node-agent-port <port> Local node-agent port, default 8091
|
|
49
52
|
--node-agent-ipc-path <path> Local control socket, default /run/task-handoff/node-agent.sock
|
|
50
53
|
--auth-mode <mode> Control-plane auth mode: password or disabled
|
|
54
|
+
--js-runtime <runtime> Override the JavaScript runtime: node or bun; auto-detected by default
|
|
51
55
|
--npm-registry <url> npm registry inherited by managed updates
|
|
52
56
|
--static-dir <path> Built control-plane UI directory
|
|
53
57
|
--materialize-only Rewrite env and systemd units without starting services
|
|
@@ -77,6 +81,7 @@ while [ "$#" -gt 0 ]; do
|
|
|
77
81
|
--node-agent-port) NODE_AGENT_PORT="${2:-}"; shift 2 ;;
|
|
78
82
|
--node-agent-ipc-path) NODE_AGENT_IPC_PATH="${2:-}"; shift 2 ;;
|
|
79
83
|
--auth-mode) AUTH_MODE="${2:-}"; shift 2 ;;
|
|
84
|
+
--js-runtime) JS_RUNTIME="${2:-}"; shift 2 ;;
|
|
80
85
|
--npm-registry) NPM_REGISTRY="${2:-}"; shift 2 ;;
|
|
81
86
|
--static-dir) STATIC_DIR="${2:-}"; shift 2 ;;
|
|
82
87
|
--materialize-only) MATERIALIZE_ONLY="1"; shift ;;
|
|
@@ -91,6 +96,11 @@ if [ "$AUTH_MODE" != "password" ] && [ "$AUTH_MODE" != "disabled" ]; then
|
|
|
91
96
|
echo "--auth-mode must be password or disabled." >&2
|
|
92
97
|
exit 1
|
|
93
98
|
fi
|
|
99
|
+
case "$JS_RUNTIME" in
|
|
100
|
+
""|auto) JS_RUNTIME="" ;;
|
|
101
|
+
node|bun) ;;
|
|
102
|
+
*) echo "--js-runtime must be auto, node, or bun." >&2; exit 1 ;;
|
|
103
|
+
esac
|
|
94
104
|
|
|
95
105
|
if ! command -v systemctl >/dev/null 2>&1; then
|
|
96
106
|
echo "systemd is required for this installer." >&2
|
|
@@ -106,20 +116,59 @@ if ! command -v npm >/dev/null 2>&1; then
|
|
|
106
116
|
fi
|
|
107
117
|
NPM_COMMAND="$(command -v npm)"
|
|
108
118
|
|
|
119
|
+
version_is_at_least() {
|
|
120
|
+
awk -v current="$1" -v minimum="$2" 'BEGIN {
|
|
121
|
+
if (current !~ /^[0-9]+\.[0-9]+([.][0-9]+)?([-+][0-9A-Za-z.-]+)?$/) exit 1;
|
|
122
|
+
split(current, left, "."); split(minimum, right, ".");
|
|
123
|
+
for (i = 1; i <= 3; i++) {
|
|
124
|
+
if ((left[i] + 0) > (right[i] + 0)) exit 0;
|
|
125
|
+
if ((left[i] + 0) < (right[i] + 0)) exit 1;
|
|
126
|
+
}
|
|
127
|
+
exit 0;
|
|
128
|
+
}'
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
resolve_js_runtime() {
|
|
132
|
+
selected=""
|
|
133
|
+
case "$JS_RUNTIME" in
|
|
134
|
+
"")
|
|
135
|
+
if command -v node >/dev/null 2>&1; then selected="$(command -v node)"
|
|
136
|
+
elif command -v bun >/dev/null 2>&1; then selected="$(command -v bun)"
|
|
137
|
+
else echo "node or bun is required to run TaskHandoff." >&2; exit 1
|
|
138
|
+
fi
|
|
139
|
+
;;
|
|
140
|
+
node)
|
|
141
|
+
selected="$(command -v node 2>/dev/null || true)"
|
|
142
|
+
;;
|
|
143
|
+
bun)
|
|
144
|
+
selected="$(command -v bun 2>/dev/null || true)"
|
|
145
|
+
;;
|
|
146
|
+
esac
|
|
147
|
+
if [ -z "$selected" ]; then
|
|
148
|
+
echo "${JS_RUNTIME:-node or bun} is required to run TaskHandoff." >&2
|
|
149
|
+
exit 1
|
|
150
|
+
fi
|
|
151
|
+
if [ "$(basename "$selected")" = "bun" ]; then
|
|
152
|
+
bun_version="$("$selected" --version 2>/dev/null || true)"
|
|
153
|
+
version_is_at_least "$bun_version" "$MIN_BUN_VERSION" || {
|
|
154
|
+
echo "Bun.js $MIN_BUN_VERSION or newer is required; found ${bun_version:-unknown}." >&2
|
|
155
|
+
exit 1
|
|
156
|
+
}
|
|
157
|
+
fi
|
|
158
|
+
printf '%s\n' "$selected"
|
|
159
|
+
}
|
|
160
|
+
JS_RUNTIME_COMMAND="$(resolve_js_runtime)"
|
|
161
|
+
|
|
109
162
|
resolve_command() {
|
|
110
163
|
candidate="$1"
|
|
111
164
|
if [ -f "$candidate" ]; then
|
|
112
|
-
if [ -
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if ! command -v node >/dev/null 2>&1; then
|
|
116
|
-
echo "node is required to run $candidate." >&2
|
|
117
|
-
exit 1
|
|
118
|
-
fi
|
|
119
|
-
printf '%s %s\n' "$(command -v node)" "$candidate"
|
|
165
|
+
if [ ! -r "$candidate" ]; then
|
|
166
|
+
echo "TaskHandoff executable is not readable: $candidate" >&2
|
|
167
|
+
exit 1
|
|
120
168
|
fi
|
|
169
|
+
printf '%s %s\n' "$JS_RUNTIME_COMMAND" "$candidate"
|
|
121
170
|
elif command -v "$candidate" >/dev/null 2>&1; then
|
|
122
|
-
command -v "$candidate"
|
|
171
|
+
printf '%s %s\n' "$JS_RUNTIME_COMMAND" "$(command -v "$candidate")"
|
|
123
172
|
else
|
|
124
173
|
echo "TaskHandoff executable was not found: $candidate" >&2
|
|
125
174
|
exit 1
|
|
@@ -159,7 +208,7 @@ if [ -n "$STATIC_DIR" ]; then
|
|
|
159
208
|
CONTROL_PLANE_STATIC_OPTION="--static-dir $STATIC_DIR"
|
|
160
209
|
fi
|
|
161
210
|
|
|
162
|
-
NODE_AGENT_IPC_ENDPOINT="$(
|
|
211
|
+
NODE_AGENT_IPC_ENDPOINT="$("$JS_RUNTIME_COMMAND" -e 'process.stdout.write(`ipc://${encodeURIComponent(process.argv[1])}`)' "$NODE_AGENT_IPC_PATH")"
|
|
163
212
|
|
|
164
213
|
if [ "$SERVICE_USER" != "root" ] && ! id "$SERVICE_USER" >/dev/null 2>&1; then
|
|
165
214
|
useradd --system --create-home --home-dir /var/lib/task-handoff --shell /usr/sbin/nologin "$SERVICE_USER"
|
|
@@ -208,8 +257,8 @@ if [ "$AUTH_MODE" = "password" ]; then
|
|
|
208
257
|
# The auth store is the sole authority: file existence cannot distinguish a
|
|
209
258
|
# valid administrator from a corrupt record that sanitation will isolate.
|
|
210
259
|
systemctl stop task-handoff-control-plane.service 2>/dev/null || true
|
|
211
|
-
ADMIN_USERNAME="$(
|
|
212
|
-
ADMIN_PASSWORD="$(
|
|
260
|
+
ADMIN_USERNAME="$("$JS_RUNTIME_COMMAND" -e 'process.stdout.write(`admin-${require("node:crypto").randomBytes(6).toString("hex")}`)')"
|
|
261
|
+
ADMIN_PASSWORD="$("$JS_RUNTIME_COMMAND" -e 'process.stdout.write(require("node:crypto").randomBytes(24).toString("base64url"))')"
|
|
213
262
|
ADMIN_INITIALIZATION_RESULT="$(printf '%s\n' "$ADMIN_PASSWORD" | initialize_control_plane_admin "$ADMIN_USERNAME")"
|
|
214
263
|
if [ "$ADMIN_INITIALIZATION_RESULT" != "created" ]; then
|
|
215
264
|
ADMIN_USERNAME=""
|
|
@@ -225,6 +274,7 @@ TASK_HANDOFF_NODE_AGENT_CONNECTION_MODE=local-ipc
|
|
|
225
274
|
TASK_HANDOFF_NODE_AGENT_IPC_PATH=$NODE_AGENT_IPC_PATH
|
|
226
275
|
TASK_HANDOFF_NODE_AGENT_CONTAINER_URL=http://host.docker.internal:$NODE_AGENT_PORT
|
|
227
276
|
TASK_HANDOFF_LOCAL_CONTROLLED_COMMAND=$CONTROLLED_INSTANCE_COMMAND
|
|
277
|
+
${JS_RUNTIME:+TASK_HANDOFF_JS_RUNTIME=$JS_RUNTIME}
|
|
228
278
|
TASK_HANDOFF_NPM_COMMAND=$NPM_COMMAND
|
|
229
279
|
${NPM_REGISTRY:+NPM_CONFIG_REGISTRY=$NPM_REGISTRY}
|
|
230
280
|
TASK_HANDOFF_CONTROL_PLANE_HEALTH_URL=http://127.0.0.1:$CONTROL_PLANE_PORT/api/health
|