@task-handoff/server 0.0.45 → 0.0.47

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 [ -x "$candidate" ]; then
113
- printf '%s\n' "$candidate"
114
- else
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="$(node -e 'process.stdout.write(`ipc://${encodeURIComponent(process.argv[1])}`)' "$NODE_AGENT_IPC_PATH")"
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="$(node -e 'process.stdout.write(`admin-${require("node:crypto").randomBytes(6).toString("hex")}`)')"
212
- ADMIN_PASSWORD="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(24).toString("base64url"))')"
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