ework-aio 0.1.15 → 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 +136 -87
  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)"
@@ -227,17 +239,33 @@ ensure_user_session() {
227
239
  }
228
240
  ensure_user_session || true # warn but don't hard-fail — let later steps report specifics
229
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
+
230
259
  # ─── Pre-flight: command dependencies ───────────────────────────────────────
231
260
  need_cmd() {
232
261
  command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1. $2"
233
262
  }
234
263
  need_cmd awk "Should be present on any Linux."
235
264
 
236
- # install needs systemctl (to write unit files + reload). Other modes
237
- # (status/logs/env/config/uninstall) can fall back to PID-file mode via
238
- # 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.
239
267
  if [[ "$MODE" == "install" ]]; then
240
- 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."
241
269
  need_cmd bun "Install from https://bun.sh"
242
270
  need_cmd npm "Install Node.js or Bun (ships npm)"
243
271
  need_cmd opencode "Install from https://opencode.ai"
@@ -809,14 +837,14 @@ esac
809
837
  # ─── Install mode ───────────────────────────────────────────────────────────
810
838
  hr
811
839
  log "ework-aio install"
812
- log " scope : $SCOPENAME"
840
+ log " mode : $([[ "$USE_SYSTEMD" == "1" ]] && echo "systemd" || echo "PID-file (no systemd)")"
813
841
  log " data dir : $DATA_DIR"
814
842
  log " web bin : $EWORK_WEB_BIN"
815
843
  log " daemon bin : $EWORK_DAEMON_BIN"
816
844
  log " opencode : $(command -v opencode) ($($(command -v opencode) --version 2>&1 | head -1))"
817
845
  hr
818
846
 
819
- 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
820
848
  warn "User-level systemd requires lingering to keep services alive after logout."
821
849
  if [[ "$ASSUME_YES" == "1" ]]; then
822
850
  warn "Run this manually: sudo loginctl enable-linger $USER"
@@ -832,56 +860,57 @@ mkdir -p "$WEB_DATA_DIR" "$DAEMON_DATA_DIR" "$DATA_DIR/opencode-workdir"
832
860
 
833
861
  write_web_env
834
862
 
835
- # ─── Write ework-web systemd unit ──────────────────────────────────────────
836
- WEB_UNIT="$UNIT_DIR/ework-web.service"
837
- write_unit_file \
838
- "ework-web" \
839
- "ework — multi-project issue tracker" \
840
- "$EWORK_WEB_BIN" \
841
- "$WEB_DATA_DIR" \
842
- "$WEB_ENV" \
843
- "$WEB_UNIT"
844
- ok "Wrote $WEB_UNIT"
845
-
846
- # ─── Reload + start ework-web ──────────────────────────────────────────────
847
- # systemd calls here are best-effort. If systemd isn't functional on this host
848
- # (containers without systemd PID 1, polkit redirects under sudo, missing
849
- # /etc/systemd/system) we still want install to complete so the user can run
850
- # `ework-aio start` (PID-file mode) against the scaffolded .env.
851
- SYSTEMD_OK=1
852
- if ! ctl daemon-reload; then
853
- warn "systemctl daemon-reload failed — systemd may be unavailable on this host."
854
- SYSTEMD_OK=0
855
- fi
856
-
857
- if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "1" ]]; then
858
- log "Starting ework-web..."
859
- ctl enable ework-web.service || { warn "systemctl enable failed"; SYSTEMD_OK=0; }
860
- if [[ "$SYSTEMD_OK" == "1" ]]; then
861
- 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
862
884
  fi
863
- if [[ "$SYSTEMD_OK" == "1" ]]; then
864
- for i in $(seq 1 60); do
865
- if curl -sf -o /dev/null "http://127.0.0.1:$WORK_PORT/login"; then
866
- ok "ework-web listening on :$WORK_PORT (after ${i} half-seconds)"
867
- break
868
- fi
869
- sleep 0.5
870
- [[ $i -eq 60 ]] && { warn "ework-web did not come up via systemd in 30s. Falling back to PID-file mode."; SYSTEMD_OK=0; }
871
- 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
872
905
  fi
873
- else
874
- warn "--no-start: unit enabled but not started"
875
- ctl enable ework-web.service 2>/dev/null || true
876
906
  fi
877
907
 
878
- # ─── PID-file mode fallback for bot bootstrap ──────────────────────────────
879
- # If systemd couldn't start web (or we're on a host without systemd), bring
880
- # web up briefly via the PID-file path so the bot user + PAT bootstrap can
881
- # still complete. We leave web running in PID-file mode so subsequent curl
882
- # 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.
883
912
  if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "0" ]]; then
884
- log "Starting ework-web via PID-file mode (nohup) for bot bootstrap..."
913
+ log "Starting ework-web (PID-file mode)..."
885
914
  WEB_LOG_FILE="$DATA_DIR/run/web.log"
886
915
  mkdir -p "$(dirname "$WEB_LOG_FILE")"
887
916
  setsid nohup "$EWORK_WEB_BIN" >>"$WEB_LOG_FILE" 2>&1 </dev/null &
@@ -975,42 +1004,55 @@ fi
975
1004
  # ─── Write ework-daemon .env ───────────────────────────────────────────────
976
1005
  write_daemon_env "$BOT_TOKEN"
977
1006
 
978
- # ─── Write ework-daemon systemd unit ───────────────────────────────────────
979
- DAEMON_UNIT="$UNIT_DIR/ework-daemon.service"
980
- write_unit_file \
981
- "ework-daemon" \
982
- "ework-daemon — issue-driven AI dev daemon" \
983
- "$EWORK_DAEMON_BIN" \
984
- "$DAEMON_DATA_DIR" \
985
- "$DAEMON_ENV" \
986
- "$DAEMON_UNIT" \
987
- " \"\""
988
- # (trailing " \"\"" is a no-op separator; kept for future extra env injection)
989
- ok "Wrote $DAEMON_UNIT"
990
-
991
- ctl daemon-reload 2>/dev/null || true
992
- if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "1" ]]; then
993
- log "Starting ework-daemon..."
994
- ctl enable ework-daemon.service 2>/dev/null || true
995
- ctl restart ework-daemon.service 2>/dev/null || warn "ework-daemon restart via systemd failed; use 'ework-aio start daemon' for PID-file mode"
996
- sleep 1
997
- if ctl is-active --quiet ework-daemon.service 2>/dev/null; then
998
- 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
999
1033
  else
1000
- 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
1001
1035
  fi
1002
- else
1003
- ctl enable ework-daemon.service 2>/dev/null || true
1004
1036
  fi
1005
1037
 
1006
- 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
1007
1052
  hr
1008
1053
  warn "systemd mode did not come up cleanly on this host."
1009
- warn "Services are scaffolded but not auto-started under systemd."
1010
- warn "Use PID-file mode instead:"
1011
- echo " ework-aio start # start web + daemon in background"
1012
- echo " ework-aio ps # check status"
1013
- 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"
1014
1056
  hr
1015
1057
  fi
1016
1058
 
@@ -1071,7 +1113,7 @@ fi
1071
1113
 
1072
1114
  # ─── Done ──────────────────────────────────────────────────────────────────
1073
1115
  hr
1074
- ok "Install complete."
1116
+ ok "Install complete ($([[ "$USE_SYSTEMD" == "1" ]] && echo "systemd mode" || echo "PID-file mode"))."
1075
1117
  hr
1076
1118
  printf '\n%s→%s Open %shttp://127.0.0.1:%s/login%s\n' \
1077
1119
  "$c_bold" "$c_reset" "$c_dim" "$WORK_PORT" "$c_reset"
@@ -1083,7 +1125,14 @@ printf ' Bot user: %s%s%s (auto-created, used by ework-daemon)\n' \
1083
1125
  printf ' Data dir: %s%s%s\n' "$c_dim" "$DATA_DIR" "$c_reset"
1084
1126
  printf ' Logs: ework-aio logs web | ework-aio logs daemon\n'
1085
1127
  printf ' Status: ework-aio status\n'
1128
+ printf ' Stop: ework-aio stop\n'
1086
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
1087
1136
  hr
1088
1137
  printf '\n%sNext steps (optional config)%s\n' "$c_bold" "$c_reset"
1089
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.15",
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",