@task-handoff/control-plane 0.0.2

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.
Files changed (133) hide show
  1. package/README.md +3 -0
  2. package/bin/task-handoff-control-plane +2 -0
  3. package/bin/task-handoff-install-server +216 -0
  4. package/dist/cli.js +214 -0
  5. package/package.json +37 -0
  6. package/ui/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  7. package/ui/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  8. package/ui/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  9. package/ui/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  10. package/ui/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  11. package/ui/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  12. package/ui/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  13. package/ui/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  14. package/ui/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  15. package/ui/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  16. package/ui/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  17. package/ui/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  18. package/ui/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  19. package/ui/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  20. package/ui/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  21. package/ui/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  22. package/ui/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  23. package/ui/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  24. package/ui/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  25. package/ui/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  26. package/ui/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  27. package/ui/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  28. package/ui/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  29. package/ui/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  30. package/ui/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  31. package/ui/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  32. package/ui/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  33. package/ui/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  34. package/ui/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  35. package/ui/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  36. package/ui/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  37. package/ui/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  38. package/ui/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  39. package/ui/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  40. package/ui/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  41. package/ui/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  42. package/ui/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  43. package/ui/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  44. package/ui/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  45. package/ui/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  46. package/ui/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  47. package/ui/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  48. package/ui/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  49. package/ui/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  50. package/ui/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  51. package/ui/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  52. package/ui/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  53. package/ui/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  54. package/ui/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  55. package/ui/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  56. package/ui/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  57. package/ui/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  58. package/ui/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  59. package/ui/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  60. package/ui/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  61. package/ui/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  62. package/ui/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  63. package/ui/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  64. package/ui/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  65. package/ui/assets/abnfDiagram-VRR7QNED-zpzEGQUU.js +1 -0
  66. package/ui/assets/arc-YlPAcjcA.js +1 -0
  67. package/ui/assets/architectureDiagram-ZJ3FMSHR-gKh1GoJ-.js +36 -0
  68. package/ui/assets/blockDiagram-677ZJIJ3-BPoey46h.js +132 -0
  69. package/ui/assets/c4Diagram-LMCZKHZV-Ba-K1kbG.js +10 -0
  70. package/ui/assets/channel-BMVxpPzT.js +1 -0
  71. package/ui/assets/chunk-2Q5K7J3B-B21lfJN3.js +1 -0
  72. package/ui/assets/chunk-32BRIVSS-4DXGAb-p.js +1 -0
  73. package/ui/assets/chunk-5VM5RSS4-BTJ3QwFs.js +15 -0
  74. package/ui/assets/chunk-EX3LRPZG-BNbiyHtR.js +231 -0
  75. package/ui/assets/chunk-JWPE2WC7-DCyFrqSV.js +1 -0
  76. package/ui/assets/chunk-MOJQB5TN-CpZLzjfV.js +88 -0
  77. package/ui/assets/chunk-RYQCIY6F-C6An87oR.js +1 -0
  78. package/ui/assets/chunk-V7JOEXUC-BUW8J6c_.js +206 -0
  79. package/ui/assets/chunk-VR4S4FIN-rsqRXVtN.js +1 -0
  80. package/ui/assets/chunk-XXDRQBXY-lgeU6p-p.js +1 -0
  81. package/ui/assets/classDiagram-OUVF2IWQ-C1C_N3Xw.js +1 -0
  82. package/ui/assets/classDiagram-v2-EOCWNBFH-C1C_N3Xw.js +1 -0
  83. package/ui/assets/cose-bilkent-JH36ORCC-CI_7H8mu.js +1 -0
  84. package/ui/assets/cynefin-VYW2F7L2-DDtwbU8C.js +166 -0
  85. package/ui/assets/cynefinDiagram-TSTJHNR4-uo6P8HiB.js +62 -0
  86. package/ui/assets/cytoscape.esm-D3_iZ_3b.js +321 -0
  87. package/ui/assets/dagre-VKFMJZFB-uy3bcf3Q.js +4 -0
  88. package/ui/assets/defaultLocale-CrowFXzY.js +1 -0
  89. package/ui/assets/diagram-FQU43EPY-BPo9FUjZ.js +3 -0
  90. package/ui/assets/diagram-G47NLZAW-Bhd3GtJl.js +24 -0
  91. package/ui/assets/diagram-NH7WQ7WH-DU-4-6PW.js +24 -0
  92. package/ui/assets/diagram-OA4YK3LP-DUlbd4mA.js +30 -0
  93. package/ui/assets/diagram-WEI45ONY-B7745Zvo.js +41 -0
  94. package/ui/assets/ebnfDiagram-CCIWWBDH-Czh6tF4d.js +1 -0
  95. package/ui/assets/erDiagram-Q63AITRT-tSICcbbZ.js +85 -0
  96. package/ui/assets/flowDiagram-23GEKE2U-marftwAR.js +156 -0
  97. package/ui/assets/ganttDiagram-NO4QXBWP-BIxUGVA1.js +292 -0
  98. package/ui/assets/gitGraphDiagram-IHSO6WYX-BI2zcSR0.js +106 -0
  99. package/ui/assets/graph-D2o_JWn5.js +1 -0
  100. package/ui/assets/index-D3aR4W1I.js +396 -0
  101. package/ui/assets/index-D5B2b9xz.css +1 -0
  102. package/ui/assets/infoDiagram-FWYZ7A6U-CTmAl0q0.js +2 -0
  103. package/ui/assets/init-Gi6I4Gst.js +1 -0
  104. package/ui/assets/ishikawaDiagram-FXEZZL3T-5s86w_qn.js +70 -0
  105. package/ui/assets/journeyDiagram-5HDEW3XC-DOPMLggG.js +139 -0
  106. package/ui/assets/kanban-definition-HUTT4EX6-CkYQOpOQ.js +89 -0
  107. package/ui/assets/katex-HP8lGamR.js +257 -0
  108. package/ui/assets/layout-1eBIAoSl.js +1 -0
  109. package/ui/assets/linear-CVoQiQC3.js +1 -0
  110. package/ui/assets/map-BdqsVdb3.js +1 -0
  111. package/ui/assets/mermaid.core-DZEhnCSw.js +308 -0
  112. package/ui/assets/mindmap-definition-LN4V7U3C-CQuNaooi.js +96 -0
  113. package/ui/assets/ordinal-Cboi1Yqb.js +1 -0
  114. package/ui/assets/pegDiagram-2B236MQR-n3onBIHl.js +1 -0
  115. package/ui/assets/pieDiagram-ENE6RG2P-J7IBjKOF.js +39 -0
  116. package/ui/assets/quadrantDiagram-ABIIQ3AL-CYkD2nd4.js +7 -0
  117. package/ui/assets/railroadDiagram-RFXS5EU6-Dt4WNh5V.js +1 -0
  118. package/ui/assets/requirementDiagram-TGXJPOKE-BjbHEeRV.js +84 -0
  119. package/ui/assets/sankeyDiagram-HTMAVEWB-CjgeOfZt.js +40 -0
  120. package/ui/assets/sequenceDiagram-DBY2YBRQ-DNTG331x.js +162 -0
  121. package/ui/assets/sizeCapture-X5ZJPWSS-5iQGjbbK.js +1 -0
  122. package/ui/assets/stateDiagram-2N3HPSRC-4BUy2Mph.js +1 -0
  123. package/ui/assets/stateDiagram-v2-6OUMAXLB-BhZ5TT1S.js +1 -0
  124. package/ui/assets/swimlanes-5IMT3BWC-DAxbIAlT.js +2 -0
  125. package/ui/assets/swimlanesDiagram-G3AALYLV-BrfWPmrM.js +8 -0
  126. package/ui/assets/timeline-definition-FHXFAJF6-V7g6gVpe.js +120 -0
  127. package/ui/assets/ui-vendor-D1aTc0NA.js +3 -0
  128. package/ui/assets/vennDiagram-L72KCM5P-76wq4_AF.js +34 -0
  129. package/ui/assets/wardleyDiagram-EHGQE667-BHnijYaJ.js +78 -0
  130. package/ui/assets/xterm-C91wPeZQ.js +16 -0
  131. package/ui/assets/xterm-Dv47L9lv.css +1 -0
  132. package/ui/assets/xychartDiagram-FW5EYKEG-CK8mGMzB.js +7 -0
  133. package/ui/index.html +16 -0
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @task-handoff/control-plane
2
+
3
+ Prebuilt control-plane runtime for TaskHandoff. This package contains compiled JavaScript and built Web UI assets; it does not contain monorepo source code.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("../dist/cli.js");
@@ -0,0 +1,216 @@
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ REPO_DIR="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)"
5
+ TASK_HANDOFF_BIN=""
6
+ TASK_HANDOFF_COMMAND=""
7
+ CONTROL_PLANE_BIN=""
8
+ NODE_AGENT_BIN=""
9
+ CONTROLLED_INSTANCE_BIN=""
10
+ CONTROL_PLANE_COMMAND=""
11
+ NODE_AGENT_COMMAND=""
12
+ CONTROLLED_INSTANCE_COMMAND=""
13
+ SERVICE_USER="task-handoff"
14
+ ENV_DIR="/etc/task-handoff"
15
+ CONTROL_PLANE_DATA_DIR="/var/lib/task-handoff/control-plane"
16
+ NODE_AGENT_DATA_DIR="/var/lib/task-handoff/node-agent"
17
+ CONTROL_PLANE_HOST="0.0.0.0"
18
+ CONTROL_PLANE_PORT="8081"
19
+ NODE_AGENT_HOST="127.0.0.1"
20
+ NODE_AGENT_PORT="8091"
21
+ AUTH_MODE="password"
22
+ STATIC_DIR=""
23
+
24
+ usage() {
25
+ cat <<'USAGE'
26
+ Usage: scripts/install-server-services.sh [options]
27
+
28
+ Installs server-side TaskHandoff services on a systemd host:
29
+ task-handoff-node-agent.service
30
+ task-handoff-control-plane.service
31
+
32
+ Options:
33
+ --repo-dir <path> Repository or unpacked release directory
34
+ --task-handoff-bin <path> Legacy combined task-handoff executable
35
+ --control-plane-bin <path> Control-plane executable
36
+ --node-agent-bin <path> Node-agent executable
37
+ --controlled-instance-bin <path> Controlled-instance executable for local runtimes
38
+ --service-user <user> systemd service user, default task-handoff
39
+ --control-plane-data-dir <path> Control-plane data directory
40
+ --node-agent-data-dir <path> Node-agent data directory
41
+ --control-plane-host <host> Control-plane bind host, default 0.0.0.0
42
+ --control-plane-port <port> Control-plane port, default 8081
43
+ --node-agent-host <host> Local node-agent bind host, default 127.0.0.1
44
+ --node-agent-port <port> Local node-agent port, default 8091
45
+ --auth-mode <mode> Control-plane auth mode: password or disabled
46
+ --static-dir <path> Built control-plane UI directory
47
+ USAGE
48
+ }
49
+
50
+ need_root() {
51
+ if [ "$(id -u)" != "0" ]; then
52
+ echo "This installer must run as root. Re-run with sudo." >&2
53
+ exit 1
54
+ fi
55
+ }
56
+
57
+ while [ "$#" -gt 0 ]; do
58
+ case "$1" in
59
+ --repo-dir) REPO_DIR="${2:-}"; shift 2 ;;
60
+ --task-handoff-bin) TASK_HANDOFF_BIN="${2:-}"; shift 2 ;;
61
+ --control-plane-bin) CONTROL_PLANE_BIN="${2:-}"; shift 2 ;;
62
+ --node-agent-bin) NODE_AGENT_BIN="${2:-}"; shift 2 ;;
63
+ --controlled-instance-bin) CONTROLLED_INSTANCE_BIN="${2:-}"; shift 2 ;;
64
+ --service-user) SERVICE_USER="${2:-}"; shift 2 ;;
65
+ --control-plane-data-dir) CONTROL_PLANE_DATA_DIR="${2:-}"; shift 2 ;;
66
+ --node-agent-data-dir) NODE_AGENT_DATA_DIR="${2:-}"; shift 2 ;;
67
+ --control-plane-host) CONTROL_PLANE_HOST="${2:-}"; shift 2 ;;
68
+ --control-plane-port) CONTROL_PLANE_PORT="${2:-}"; shift 2 ;;
69
+ --node-agent-host) NODE_AGENT_HOST="${2:-}"; shift 2 ;;
70
+ --node-agent-port) NODE_AGENT_PORT="${2:-}"; shift 2 ;;
71
+ --auth-mode) AUTH_MODE="${2:-}"; shift 2 ;;
72
+ --static-dir) STATIC_DIR="${2:-}"; shift 2 ;;
73
+ -h|--help) usage; exit 0 ;;
74
+ *) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
75
+ esac
76
+ done
77
+
78
+ need_root
79
+
80
+ if [ "$AUTH_MODE" != "password" ] && [ "$AUTH_MODE" != "disabled" ]; then
81
+ echo "--auth-mode must be password or disabled." >&2
82
+ exit 1
83
+ fi
84
+
85
+ if ! command -v systemctl >/dev/null 2>&1; then
86
+ echo "systemd is required for this installer." >&2
87
+ exit 1
88
+ fi
89
+ if ! command -v curl >/dev/null 2>&1; then
90
+ echo "curl is required for this installer." >&2
91
+ exit 1
92
+ fi
93
+
94
+ resolve_command() {
95
+ candidate="$1"
96
+ if [ -f "$candidate" ]; then
97
+ if [ -x "$candidate" ]; then
98
+ printf '%s\n' "$candidate"
99
+ else
100
+ if ! command -v node >/dev/null 2>&1; then
101
+ echo "node is required to run $candidate." >&2
102
+ exit 1
103
+ fi
104
+ printf '%s %s\n' "$(command -v node)" "$candidate"
105
+ fi
106
+ elif command -v "$candidate" >/dev/null 2>&1; then
107
+ command -v "$candidate"
108
+ else
109
+ echo "TaskHandoff executable was not found: $candidate" >&2
110
+ exit 1
111
+ fi
112
+ }
113
+
114
+ if [ -n "$TASK_HANDOFF_BIN" ]; then
115
+ TASK_HANDOFF_COMMAND="$(resolve_command "$TASK_HANDOFF_BIN")"
116
+ elif [ -z "$CONTROL_PLANE_BIN" ] && [ -z "$NODE_AGENT_BIN" ] && [ -z "$CONTROLLED_INSTANCE_BIN" ] && [ -f "$REPO_DIR/bin/task-handoff.js" ]; then
117
+ TASK_HANDOFF_COMMAND="$(resolve_command "$REPO_DIR/bin/task-handoff.js")"
118
+ fi
119
+
120
+ if [ -n "$TASK_HANDOFF_COMMAND" ]; then
121
+ CONTROL_PLANE_COMMAND="$TASK_HANDOFF_COMMAND control-plane"
122
+ NODE_AGENT_COMMAND="$TASK_HANDOFF_COMMAND node-agent"
123
+ CONTROLLED_INSTANCE_COMMAND="$TASK_HANDOFF_COMMAND web"
124
+ if [ -z "$STATIC_DIR" ]; then
125
+ STATIC_DIR="$REPO_DIR/packages/control-plane-ui/dist"
126
+ fi
127
+ else
128
+ CONTROL_PLANE_COMMAND="$(resolve_command "${CONTROL_PLANE_BIN:-task-handoff-control-plane}")"
129
+ NODE_AGENT_COMMAND="$(resolve_command "${NODE_AGENT_BIN:-task-handoff-node-agent}")"
130
+ CONTROLLED_INSTANCE_COMMAND="$(resolve_command "${CONTROLLED_INSTANCE_BIN:-task-handoff-controlled-instance}") web"
131
+ fi
132
+
133
+ CONTROL_PLANE_STATIC_OPTION=""
134
+ if [ -n "$STATIC_DIR" ]; then
135
+ CONTROL_PLANE_STATIC_OPTION="--static-dir $STATIC_DIR"
136
+ fi
137
+
138
+ if [ "$SERVICE_USER" != "root" ] && ! id "$SERVICE_USER" >/dev/null 2>&1; then
139
+ useradd --system --create-home --home-dir /var/lib/task-handoff --shell /usr/sbin/nologin "$SERVICE_USER"
140
+ fi
141
+ if [ "$SERVICE_USER" != "root" ] && getent group docker >/dev/null 2>&1; then
142
+ usermod -aG docker "$SERVICE_USER" || true
143
+ fi
144
+
145
+ mkdir -p "$ENV_DIR" "$CONTROL_PLANE_DATA_DIR" "$NODE_AGENT_DATA_DIR"
146
+ chown -R "$SERVICE_USER":"$SERVICE_USER" "$CONTROL_PLANE_DATA_DIR" "$NODE_AGENT_DATA_DIR" 2>/dev/null || true
147
+
148
+ cat > "$ENV_DIR/node-agent.env" <<EOF
149
+ TASK_HANDOFF_NODE_AGENT_HOST=$NODE_AGENT_HOST
150
+ TASK_HANDOFF_NODE_AGENT_PORT=$NODE_AGENT_PORT
151
+ TASK_HANDOFF_NODE_AGENT_DATA_DIR=$NODE_AGENT_DATA_DIR
152
+ TASK_HANDOFF_NODE_AGENT_CONTAINER_URL=http://host.docker.internal:$NODE_AGENT_PORT
153
+ TASK_HANDOFF_LOCAL_CONTROLLED_COMMAND=$CONTROLLED_INSTANCE_COMMAND
154
+ EOF
155
+ chmod 0640 "$ENV_DIR/node-agent.env"
156
+
157
+ cat > "$ENV_DIR/control-plane.env" <<EOF
158
+ TASK_HANDOFF_CONTROL_PLANE_HOST=$CONTROL_PLANE_HOST
159
+ TASK_HANDOFF_CONTROL_PLANE_PORT=$CONTROL_PLANE_PORT
160
+ TASK_HANDOFF_CONTROL_PLANE_DATA_DIR=$CONTROL_PLANE_DATA_DIR
161
+ TASK_HANDOFF_CONTROL_PLANE_STATIC_DIR=$STATIC_DIR
162
+ TASK_HANDOFF_CONTROL_PLANE_AUTH_MODE=$AUTH_MODE
163
+ TASK_HANDOFF_NODE_AGENT_ENDPOINT=http://$NODE_AGENT_HOST:$NODE_AGENT_PORT
164
+ TASK_HANDOFF_NODE_AGENT_CONTROL_ENDPOINT=http://$NODE_AGENT_HOST:$NODE_AGENT_PORT
165
+ TASK_HANDOFF_NODE_AGENT_CONTAINER_URL=http://host.docker.internal:$NODE_AGENT_PORT
166
+ EOF
167
+ chmod 0640 "$ENV_DIR/control-plane.env"
168
+
169
+ cat > /etc/systemd/system/task-handoff-node-agent.service <<EOF
170
+ [Unit]
171
+ Description=TaskHandoff Local Node Agent
172
+ After=network-online.target docker.service
173
+ Wants=network-online.target
174
+
175
+ [Service]
176
+ Type=simple
177
+ User=$SERVICE_USER
178
+ WorkingDirectory=$REPO_DIR
179
+ EnvironmentFile=-$ENV_DIR/node-agent.env
180
+ ExecStart=$NODE_AGENT_COMMAND --host $NODE_AGENT_HOST --port $NODE_AGENT_PORT --data-dir $NODE_AGENT_DATA_DIR
181
+ Restart=always
182
+ RestartSec=3
183
+ KillSignal=SIGTERM
184
+
185
+ [Install]
186
+ WantedBy=multi-user.target
187
+ EOF
188
+
189
+ cat > /etc/systemd/system/task-handoff-control-plane.service <<EOF
190
+ [Unit]
191
+ Description=TaskHandoff Control Plane
192
+ After=network-online.target task-handoff-node-agent.service
193
+ Wants=network-online.target task-handoff-node-agent.service
194
+
195
+ [Service]
196
+ Type=simple
197
+ User=$SERVICE_USER
198
+ WorkingDirectory=$REPO_DIR
199
+ EnvironmentFile=-$ENV_DIR/control-plane.env
200
+ ExecStartPre=/bin/sh -c 'for i in \$(seq 1 30); do curl -fsS http://$NODE_AGENT_HOST:$NODE_AGENT_PORT/api/node-agent/health >/dev/null 2>&1 && exit 0; sleep 1; done; exit 1'
201
+ ExecStart=$CONTROL_PLANE_COMMAND --host $CONTROL_PLANE_HOST --port $CONTROL_PLANE_PORT --data-dir $CONTROL_PLANE_DATA_DIR $CONTROL_PLANE_STATIC_OPTION --auth-mode $AUTH_MODE
202
+ Restart=always
203
+ RestartSec=3
204
+ KillSignal=SIGTERM
205
+
206
+ [Install]
207
+ WantedBy=multi-user.target
208
+ EOF
209
+
210
+ systemctl daemon-reload
211
+ systemctl enable --now task-handoff-node-agent.service
212
+ systemctl enable --now task-handoff-control-plane.service
213
+
214
+ echo "TaskHandoff server services are installed."
215
+ echo "Control plane: task-handoff-control-plane.service on $CONTROL_PLANE_HOST:$CONTROL_PLANE_PORT"
216
+ echo "Local node-agent: task-handoff-node-agent.service on $NODE_AGENT_HOST:$NODE_AGENT_PORT"