ework-aio 0.1.14 → 0.1.16

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 (3) hide show
  1. package/README.md +28 -12
  2. package/bin/install.sh +142 -88
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -13,11 +13,21 @@ All-in-one installer for the **ework** self-hosted AI development stack:
13
13
  ## Quick start
14
14
 
15
15
  ```bash
16
- # Recommended: user-level install (no sudo needed)
16
+ # Recommended: user-level install (no sudo needed, no systemd needed)
17
17
  npm install -g ework-aio --prefix ~/.local && ework-aio install
18
18
  ```
19
19
 
20
- That's the whole install. When it finishes it prints your login URL, operator login, and token.
20
+ That's the whole install. It runs in **PID-file mode** (services via `nohup`, no `systemctl` calls, no linger prompt) and prints your login URL, operator login, and token when done.
21
+
22
+ ### When to use `install systemd`
23
+
24
+ If you want systemd to supervise the services (auto-restart on crash, start on boot, journal logging), add the `systemd` subcommand:
25
+
26
+ ```bash
27
+ ework-aio install systemd # writes units, daemon-reload, enable, restart
28
+ ```
29
+
30
+ This is **opt-in**. Without `systemd`, install never touches `systemctl`, works on hosts without systemd (containers, macOS, WSL without systemd), and doesn't prompt for linger.
21
31
 
22
32
  > **PATH heads-up:** `--prefix ~/.local` puts bin shims at `~/.local/bin/`.
23
33
  > Most distros already have `~/.local/bin` on PATH (via `systemd-user-sessions`
@@ -32,19 +42,24 @@ That's the whole install. When it finishes it prints your login URL, operator lo
32
42
 
33
43
  The install command checks for these and aborts with a hint if any are missing:
34
44
 
35
- | Tool | Min ver | Install from |
36
- | ----------- | ------- | ------------------------------------ |
37
- | `bun` | 1.1.0 | https://bun.sh |
38
- | `opencode` | 1.14 | https://opencode.ai |
39
- | `npm` | any | ships with bun or node |
40
- | `systemctl` | any | systemd-based Linux |
41
- | `openssl`/`curl`/`jq`/`awk` | any | your distro package manager |
45
+ | Tool | Min ver | When required | Install from |
46
+ | ----------- | ------- | ----------------------------------------- | ------------------------------------ |
47
+ | `bun` | 1.1.0 | always | https://bun.sh |
48
+ | `opencode` | 1.14 | always | https://opencode.ai |
49
+ | `npm` | any | always | ships with bun or node |
50
+ | `systemctl` | any | only `install systemd` (not default) | systemd-based Linux |
51
+ | `openssl`/`curl`/`jq`/`awk` | any | always | your distro package manager |
42
52
 
43
53
  ### Install variants
44
54
 
45
55
  ```bash
46
- # System-level install (needs sudo; services run as root, units in /etc/systemd/system)
47
- sudo npm install -g ework-aio && sudo ework-aio install --system
56
+ # PID-file mode (default): no systemctl, works anywhere
57
+ ework-aio install
58
+
59
+ # systemd mode: writes units + enables + starts via systemd
60
+ ework-aio install systemd
61
+ # (system-level variant: services run as root, units in /etc/systemd/system)
62
+ sudo npm install -g ework-aio && sudo ework-aio install systemd --system
48
63
 
49
64
  # Run without installing globally (downloads + runs once)
50
65
  npx ework-aio install
@@ -58,7 +73,8 @@ User-level (default in this README) keeps everything under your home directory:
58
73
  - bins: `~/.local/bin/`
59
74
  - npm package files: `~/.local/lib/node/`
60
75
  - data: `~/.local/share/ework-aio/`
61
- - systemd units: `~/.config/systemd/user/`
76
+ - PID files + logs: `~/.local/share/ework-aio/run/{web,daemon}.{pid,log}`
77
+ - systemd units (only with `install systemd`): `~/.config/systemd/user/`
62
78
 
63
79
  `sudo` is never required; uninstall is `rm -rf ~/.local/share/ework-aio && npm uninstall -g ework-aio --prefix ~/.local`.
64
80
 
package/bin/install.sh CHANGED
@@ -17,7 +17,7 @@ set -euo pipefail
17
17
  # scope + polkit redirect, missing systemd PID 1, journalctl-as-root) all
18
18
  # manifest as silent exit at a systemctl call — without this trace, the user
19
19
  # just sees the prompt return and assumes install succeeded.
20
- trap 'rc=$?; if [[ $rc -ne 0 ]]; then echo "${c_red}✗${c_reset} install.sh exited with code $rc at line $LINENO (most recent command: ${BASH_COMMAND})" >&2; echo " If systemd is unavailable on this host, retry with: ework-aio install --no-start" >&2; echo " Then start services with: ework-aio start" >&2; fi' ERR
20
+ trap 'rc=$?; if [[ $rc -ne 0 ]]; then echo "${c_red}✗${c_reset} install.sh exited with code $rc at line $LINENO (most recent command: ${BASH_COMMAND})" >&2; echo " If running in PID-file mode (default), this is a real bug please report." >&2; echo " If running with '\''systemd'\'' subcommand and systemd is unavailable, retry without it." >&2; fi' ERR
21
21
 
22
22
  # ─── Pretty output ──────────────────────────────────────────────────────────
23
23
  c_reset=$'\033[0m'; c_bold=$'\033[1m'; c_dim=$'\033[2m'
@@ -42,13 +42,22 @@ AS_USER=""
42
42
  ALLOW_ROOT=0
43
43
  CFG_ARGS=()
44
44
  MODE_ARGS=()
45
+ # USE_SYSTEMD=1 only when user runs `install systemd`. Default install is
46
+ # pure PID-file mode (no systemctl calls, no unit files, no linger prompt).
47
+ # This is the inverse of v0.1.x behavior where install always tried systemd
48
+ # first. PID-file mode is simpler, works on hosts without systemd, and
49
+ # matches the dominant failure mode we've seen in the wild.
50
+ USE_SYSTEMD=0
45
51
 
46
52
  usage() {
47
53
  cat <<'EOF'
48
54
  ework-aio <command> [options]
49
55
 
50
56
  Commands:
51
- install [options] Install or upgrade the ework stack (default)
57
+ install [systemd] [options] Install or upgrade the ework stack (default)
58
+ Add 'systemd' to also write+enable systemd
59
+ units. Without 'systemd', runs in pure
60
+ PID-file mode (no systemctl calls).
52
61
  uninstall Stop services and remove units (data preserved)
53
62
  status Show service status
54
63
  logs [web|daemon] Tail logs
@@ -61,13 +70,15 @@ Commands:
61
70
  config restart <web|daemon> Restart one or both services
62
71
 
63
72
  Install options:
64
- --user Use user-level systemd units (default if non-root)
65
- --system Use system-level systemd units (default if root)
73
+ systemd Also install systemd units + enable them.
74
+ Without this flag, install is PID-file only.
75
+ --user (with systemd) user-level units (default)
76
+ --system (with systemd) system-level units (needs sudo)
66
77
  --data-dir <path> Override data directory (default: ~/.local/share/ework-aio)
67
78
  --port <n> ework-web port (default: 3002)
68
79
  --daemon-port <n> ework-daemon port (default: 3101)
69
80
  --bot-name <login> Bot username (default: ework-daemon)
70
- --no-start Install units but don't start services
81
+ --no-start Install but don't start services
71
82
  --yes Skip all prompts (use generated defaults)
72
83
  --as-user <login> (sudo only) drop priv: re-exec install as <login>
73
84
  after enabling linger. Data + opencode + npm
@@ -196,6 +207,7 @@ fi
196
207
  # know about installed units). Auto-export the runtime dir + bus socket if we
197
208
  # can find them. No-op for --system scope.
198
209
  ensure_user_session() {
210
+ [[ "$USE_SYSTEMD" == "1" ]] || return 0
199
211
  [[ "$SCOPENAME" == "--user" ]] || return 0
200
212
  local uid
201
213
  uid="$(id -u)"
@@ -204,7 +216,12 @@ ensure_user_session() {
204
216
  if [[ -z "${XDG_RUNTIME_DIR:-}" && -d "$rundir" ]]; then
205
217
  export XDG_RUNTIME_DIR="$rundir"
206
218
  fi
207
- if [[ -z "${DBUS_SESSION_BUS_ADDRESS:-}" && -S "${XDG_RUNTIME_DIR}/bus" ]]; then
219
+ # ${XDG_RUNTIME_DIR:-} not bare ${XDG_RUNTIME_DIR}: the first if above only
220
+ # exports when /run/user/$uid exists. On hosts without linger / without any
221
+ # login session, /run/user/$uid is absent, XDG_RUNTIME_DIR stays unset, and
222
+ # `set -u` would kill install here before the systemd_reachable() fallback
223
+ # can route to PID-file mode.
224
+ if [[ -z "${DBUS_SESSION_BUS_ADDRESS:-}" && -S "${XDG_RUNTIME_DIR:-}/bus" ]]; then
208
225
  export DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"
209
226
  fi
210
227
 
@@ -222,17 +239,33 @@ ensure_user_session() {
222
239
  }
223
240
  ensure_user_session || true # warn but don't hard-fail — let later steps report specifics
224
241
 
242
+ # ─── Post-parse: detect `install systemd` sub-variant ──────────────────────
243
+ # `install systemd` (or `systemd install`, or `install ... systemd`) opts in
244
+ # to writing+enabling systemd units. Without this token, install is pure
245
+ # PID-file mode (no systemctl calls, no unit files, no linger prompt).
246
+ if [[ "$MODE" == "install" ]]; then
247
+ new_mode_args=()
248
+ for a in "${MODE_ARGS[@]:-}"; do
249
+ [[ -z "$a" ]] && continue
250
+ if [[ "$a" == "systemd" ]]; then
251
+ USE_SYSTEMD=1
252
+ else
253
+ new_mode_args+=("$a")
254
+ fi
255
+ done
256
+ MODE_ARGS=("${new_mode_args[@]:-}")
257
+ fi
258
+
225
259
  # ─── Pre-flight: command dependencies ───────────────────────────────────────
226
260
  need_cmd() {
227
261
  command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1. $2"
228
262
  }
229
263
  need_cmd awk "Should be present on any Linux."
230
264
 
231
- # install needs systemctl (to write unit files + reload). Other modes
232
- # (status/logs/env/config/uninstall) can fall back to PID-file mode via
233
- # the 'ework-aio' dispatcher if systemd is unreachable on this host.
265
+ # systemctl only required when user opts into systemd variant. Default
266
+ # install path is PID-file only and works on hosts without systemd.
234
267
  if [[ "$MODE" == "install" ]]; then
235
- need_cmd systemctl "Install requires systemd. For hosts without systemd, run 'npm install -g ework-aio' and use 'ework-aio start' directly (PID-file mode)."
268
+ [[ "$USE_SYSTEMD" == "1" ]] && need_cmd systemctl "Install with 'systemd' subcommand requires systemctl. Drop 'systemd' to install in PID-file mode."
236
269
  need_cmd bun "Install from https://bun.sh"
237
270
  need_cmd npm "Install Node.js or Bun (ships npm)"
238
271
  need_cmd opencode "Install from https://opencode.ai"
@@ -804,14 +837,14 @@ esac
804
837
  # ─── Install mode ───────────────────────────────────────────────────────────
805
838
  hr
806
839
  log "ework-aio install"
807
- log " scope : $SCOPENAME"
840
+ log " mode : $([[ "$USE_SYSTEMD" == "1" ]] && echo "systemd" || echo "PID-file (no systemd)")"
808
841
  log " data dir : $DATA_DIR"
809
842
  log " web bin : $EWORK_WEB_BIN"
810
843
  log " daemon bin : $EWORK_DAEMON_BIN"
811
844
  log " opencode : $(command -v opencode) ($($(command -v opencode) --version 2>&1 | head -1))"
812
845
  hr
813
846
 
814
- if [[ "$SCOPENAME" == "--user" ]] && ! loginctl show-user "$USER" 2>/dev/null | grep -q '^Linger=yes'; then
847
+ if [[ "$USE_SYSTEMD" == "1" && "$SCOPENAME" == "--user" ]] && ! loginctl show-user "$USER" 2>/dev/null | grep -q '^Linger=yes'; then
815
848
  warn "User-level systemd requires lingering to keep services alive after logout."
816
849
  if [[ "$ASSUME_YES" == "1" ]]; then
817
850
  warn "Run this manually: sudo loginctl enable-linger $USER"
@@ -827,56 +860,57 @@ mkdir -p "$WEB_DATA_DIR" "$DAEMON_DATA_DIR" "$DATA_DIR/opencode-workdir"
827
860
 
828
861
  write_web_env
829
862
 
830
- # ─── Write ework-web systemd unit ──────────────────────────────────────────
831
- WEB_UNIT="$UNIT_DIR/ework-web.service"
832
- write_unit_file \
833
- "ework-web" \
834
- "ework — multi-project issue tracker" \
835
- "$EWORK_WEB_BIN" \
836
- "$WEB_DATA_DIR" \
837
- "$WEB_ENV" \
838
- "$WEB_UNIT"
839
- ok "Wrote $WEB_UNIT"
840
-
841
- # ─── Reload + start ework-web ──────────────────────────────────────────────
842
- # systemd calls here are best-effort. If systemd isn't functional on this host
843
- # (containers without systemd PID 1, polkit redirects under sudo, missing
844
- # /etc/systemd/system) we still want install to complete so the user can run
845
- # `ework-aio start` (PID-file mode) against the scaffolded .env.
846
- SYSTEMD_OK=1
847
- if ! ctl daemon-reload; then
848
- warn "systemctl daemon-reload failed — systemd may be unavailable on this host."
849
- SYSTEMD_OK=0
850
- fi
851
-
852
- if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "1" ]]; then
853
- log "Starting ework-web..."
854
- ctl enable ework-web.service || { warn "systemctl enable failed"; SYSTEMD_OK=0; }
855
- if [[ "$SYSTEMD_OK" == "1" ]]; then
856
- ctl restart ework-web.service || { warn "systemctl restart failed"; SYSTEMD_OK=0; }
863
+ # ─── Write ework-web systemd unit (only with `install systemd`) ────────────
864
+ SYSTEMD_OK=0
865
+ if [[ "$USE_SYSTEMD" == "1" ]]; then
866
+ WEB_UNIT="$UNIT_DIR/ework-web.service"
867
+ write_unit_file \
868
+ "ework-web" \
869
+ "ework — multi-project issue tracker" \
870
+ "$EWORK_WEB_BIN" \
871
+ "$WEB_DATA_DIR" \
872
+ "$WEB_ENV" \
873
+ "$WEB_UNIT"
874
+ ok "Wrote $WEB_UNIT"
875
+
876
+ # systemd calls here are best-effort. If systemd isn't functional on this host
877
+ # (containers without systemd PID 1, polkit redirects under sudo, missing
878
+ # /etc/systemd/system) we still want install to complete so the user can run
879
+ # `ework-aio start` (PID-file mode) against the scaffolded .env.
880
+ SYSTEMD_OK=1
881
+ if ! ctl daemon-reload; then
882
+ warn "systemctl daemon-reload failed — systemd may be unavailable on this host."
883
+ SYSTEMD_OK=0
857
884
  fi
858
- if [[ "$SYSTEMD_OK" == "1" ]]; then
859
- for i in $(seq 1 60); do
860
- if curl -sf -o /dev/null "http://127.0.0.1:$WORK_PORT/login"; then
861
- ok "ework-web listening on :$WORK_PORT (after ${i} half-seconds)"
862
- break
863
- fi
864
- sleep 0.5
865
- [[ $i -eq 60 ]] && { warn "ework-web did not come up via systemd in 30s. Falling back to PID-file mode."; SYSTEMD_OK=0; }
866
- done
885
+
886
+ if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "1" ]]; then
887
+ log "Starting ework-web (systemd)..."
888
+ ctl enable ework-web.service || { warn "systemctl enable failed"; SYSTEMD_OK=0; }
889
+ if [[ "$SYSTEMD_OK" == "1" ]]; then
890
+ ctl restart ework-web.service || { warn "systemctl restart failed"; SYSTEMD_OK=0; }
891
+ fi
892
+ if [[ "$SYSTEMD_OK" == "1" ]]; then
893
+ for i in $(seq 1 60); do
894
+ if curl -sf -o /dev/null "http://127.0.0.1:$WORK_PORT/login"; then
895
+ ok "ework-web listening on :$WORK_PORT (after ${i} half-seconds)"
896
+ break
897
+ fi
898
+ sleep 0.5
899
+ [[ $i -eq 60 ]] && { warn "ework-web did not come up via systemd in 30s. Falling back to PID-file mode."; SYSTEMD_OK=0; }
900
+ done
901
+ fi
902
+ else
903
+ warn "--no-start: unit enabled but not started"
904
+ ctl enable ework-web.service 2>/dev/null || true
867
905
  fi
868
- else
869
- warn "--no-start: unit enabled but not started"
870
- ctl enable ework-web.service 2>/dev/null || true
871
906
  fi
872
907
 
873
- # ─── PID-file mode fallback for bot bootstrap ──────────────────────────────
874
- # If systemd couldn't start web (or we're on a host without systemd), bring
875
- # web up briefly via the PID-file path so the bot user + PAT bootstrap can
876
- # still complete. We leave web running in PID-file mode so subsequent curl
877
- # calls to :WORK_PORT succeed.
908
+ # ─── Start ework-web in PID-file mode ──────────────────────────────────────
909
+ # Default path (no `systemd` arg) OR systemd fallback. We bring web up via
910
+ # setsid+nohup so the bot bootstrap below can HTTP-probe it. Web stays
911
+ # running in PID-file mode after install — use `ework-aio stop` to kill it.
878
912
  if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "0" ]]; then
879
- log "Starting ework-web via PID-file mode (nohup) for bot bootstrap..."
913
+ log "Starting ework-web (PID-file mode)..."
880
914
  WEB_LOG_FILE="$DATA_DIR/run/web.log"
881
915
  mkdir -p "$(dirname "$WEB_LOG_FILE")"
882
916
  setsid nohup "$EWORK_WEB_BIN" >>"$WEB_LOG_FILE" 2>&1 </dev/null &
@@ -970,42 +1004,55 @@ fi
970
1004
  # ─── Write ework-daemon .env ───────────────────────────────────────────────
971
1005
  write_daemon_env "$BOT_TOKEN"
972
1006
 
973
- # ─── Write ework-daemon systemd unit ───────────────────────────────────────
974
- DAEMON_UNIT="$UNIT_DIR/ework-daemon.service"
975
- write_unit_file \
976
- "ework-daemon" \
977
- "ework-daemon — issue-driven AI dev daemon" \
978
- "$EWORK_DAEMON_BIN" \
979
- "$DAEMON_DATA_DIR" \
980
- "$DAEMON_ENV" \
981
- "$DAEMON_UNIT" \
982
- " \"\""
983
- # (trailing " \"\"" is a no-op separator; kept for future extra env injection)
984
- ok "Wrote $DAEMON_UNIT"
985
-
986
- ctl daemon-reload 2>/dev/null || true
987
- if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "1" ]]; then
988
- log "Starting ework-daemon..."
989
- ctl enable ework-daemon.service 2>/dev/null || true
990
- ctl restart ework-daemon.service 2>/dev/null || warn "ework-daemon restart via systemd failed; use 'ework-aio start daemon' for PID-file mode"
991
- sleep 1
992
- if ctl is-active --quiet ework-daemon.service 2>/dev/null; then
993
- ok "ework-daemon active"
1007
+ # ─── Write + start ework-daemon (systemd path, only with `install systemd`) ─
1008
+ if [[ "$USE_SYSTEMD" == "1" ]]; then
1009
+ DAEMON_UNIT="$UNIT_DIR/ework-daemon.service"
1010
+ write_unit_file \
1011
+ "ework-daemon" \
1012
+ "ework-daemon — issue-driven AI dev daemon" \
1013
+ "$EWORK_DAEMON_BIN" \
1014
+ "$DAEMON_DATA_DIR" \
1015
+ "$DAEMON_ENV" \
1016
+ "$DAEMON_UNIT" \
1017
+ " \"\""
1018
+ # (trailing " \"\"" is a no-op separator; kept for future extra env injection)
1019
+ ok "Wrote $DAEMON_UNIT"
1020
+
1021
+ ctl daemon-reload 2>/dev/null || true
1022
+ if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "1" ]]; then
1023
+ log "Starting ework-daemon (systemd)..."
1024
+ ctl enable ework-daemon.service 2>/dev/null || true
1025
+ ctl restart ework-daemon.service 2>/dev/null || warn "ework-daemon restart via systemd failed; falling back to PID-file mode"
1026
+ sleep 1
1027
+ if ctl is-active --quiet ework-daemon.service 2>/dev/null; then
1028
+ ok "ework-daemon active (systemd)"
1029
+ else
1030
+ warn "ework-daemon not active via systemd — falling back to PID-file mode"
1031
+ SYSTEMD_OK=0
1032
+ fi
994
1033
  else
995
- warn "ework-daemon did not report active; run 'ework-aio start daemon' for PID-file mode"
1034
+ ctl enable ework-daemon.service 2>/dev/null || true
996
1035
  fi
997
- else
998
- ctl enable ework-daemon.service 2>/dev/null || true
999
1036
  fi
1000
1037
 
1001
- if [[ "$SYSTEMD_OK" == "0" ]]; then
1038
+ # ─── Start ework-daemon in PID-file mode (default path) ────────────────────
1039
+ # Mirrors the web PID-file start. Skipped if systemd already brought it up.
1040
+ if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "0" ]]; then
1041
+ log "Starting ework-daemon (PID-file mode)..."
1042
+ DAEMON_LOG_FILE="$DATA_DIR/run/daemon.log"
1043
+ mkdir -p "$(dirname "$DAEMON_LOG_FILE")"
1044
+ setsid nohup "$EWORK_DAEMON_BIN" >>"$DAEMON_LOG_FILE" 2>&1 </dev/null &
1045
+ DAEMON_PID=$!
1046
+ disown "$DAEMON_PID" 2>/dev/null || true
1047
+ printf '%s\n' "$DAEMON_PID" > "$DATA_DIR/run/daemon.pid"
1048
+ ok "ework-daemon started in PID-file mode (pid $DAEMON_PID, log $DAEMON_LOG_FILE)"
1049
+ fi
1050
+
1051
+ if [[ "$USE_SYSTEMD" == "1" && "$SYSTEMD_OK" == "0" ]]; then
1002
1052
  hr
1003
1053
  warn "systemd mode did not come up cleanly on this host."
1004
- warn "Services are scaffolded but not auto-started under systemd."
1005
- warn "Use PID-file mode instead:"
1006
- echo " ework-aio start # start web + daemon in background"
1007
- echo " ework-aio ps # check status"
1008
- echo " ework-aio logs web # tail web log"
1054
+ warn "Services started in PID-file mode instead. systemd unit files were"
1055
+ warn "written but are not active. To clean them up: ework-aio uninstall"
1009
1056
  hr
1010
1057
  fi
1011
1058
 
@@ -1066,7 +1113,7 @@ fi
1066
1113
 
1067
1114
  # ─── Done ──────────────────────────────────────────────────────────────────
1068
1115
  hr
1069
- ok "Install complete."
1116
+ ok "Install complete ($([[ "$USE_SYSTEMD" == "1" ]] && echo "systemd mode" || echo "PID-file mode"))."
1070
1117
  hr
1071
1118
  printf '\n%s→%s Open %shttp://127.0.0.1:%s/login%s\n' \
1072
1119
  "$c_bold" "$c_reset" "$c_dim" "$WORK_PORT" "$c_reset"
@@ -1078,7 +1125,14 @@ printf ' Bot user: %s%s%s (auto-created, used by ework-daemon)\n' \
1078
1125
  printf ' Data dir: %s%s%s\n' "$c_dim" "$DATA_DIR" "$c_reset"
1079
1126
  printf ' Logs: ework-aio logs web | ework-aio logs daemon\n'
1080
1127
  printf ' Status: ework-aio status\n'
1128
+ printf ' Stop: ework-aio stop\n'
1081
1129
  printf ' Uninstall: ework-aio uninstall\n'
1130
+ if [[ "$USE_SYSTEMD" != "1" ]]; then
1131
+ hr
1132
+ printf '\n%sPID-file mode note%s (services run via nohup, not systemd)\n' "$c_bold" "$c_reset"
1133
+ printf ' • To enable auto-restart on boot, re-run with: ework-aio install systemd\n'
1134
+ printf ' • Services stop when you kill them (no supervisor). Use ework-aio stop to stop cleanly.\n'
1135
+ fi
1082
1136
  hr
1083
1137
  printf '\n%sNext steps (optional config)%s\n' "$c_bold" "$c_reset"
1084
1138
  printf ' • 朗读 (TTS): %shttp://127.0.0.1:%s/admin/tts%s — needs an OpenAI-compat /audio/speech endpoint\n' \
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ework-aio",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "All-in-one installer for ework (issue tracker) + ework-daemon (AI bridge) + opencode-ework (plugin). One command: npm i -g ework-aio && ework-aio install.",
5
5
  "type": "module",
6
6
  "license": "MIT",