ework-aio 0.1.15 → 0.1.17
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.
- package/README.md +28 -12
- package/bin/install.sh +190 -87
- 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.
|
|
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
|
-
#
|
|
47
|
-
|
|
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
|
-
-
|
|
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
|
|
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]
|
|
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
|
-
|
|
65
|
-
|
|
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
|
|
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
|
-
#
|
|
237
|
-
#
|
|
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
|
|
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"
|
|
@@ -367,6 +395,11 @@ write_web_env() {
|
|
|
367
395
|
mkdir -p "$(dirname "$WEB_ENV")"
|
|
368
396
|
if [[ -f "$WEB_ENV" ]]; then
|
|
369
397
|
log "Preserving existing $WEB_ENV"
|
|
398
|
+
# Older installs (pre-0.1.16) may have a .env that predates some keys
|
|
399
|
+
# ework-web's Zod schema now requires (WORK_COOKIE_SECRET in particular).
|
|
400
|
+
# Fill any missing required keys with fresh defaults so the preserved
|
|
401
|
+
# .env doesn't crash the next start. User-set keys are never overwritten.
|
|
402
|
+
ensure_web_env_keys
|
|
370
403
|
return
|
|
371
404
|
fi
|
|
372
405
|
local tok secret webhook
|
|
@@ -392,6 +425,39 @@ EOF
|
|
|
392
425
|
ok "Wrote $WEB_ENV"
|
|
393
426
|
}
|
|
394
427
|
|
|
428
|
+
# ensure_env_key: append KEY=value to $file iff KEY is not already present.
|
|
429
|
+
# Used to forward-fill schema-required keys on preserved .env files without
|
|
430
|
+
# clobbering any user-set values.
|
|
431
|
+
ensure_env_key() {
|
|
432
|
+
local file="$1" key="$2" val="$3"
|
|
433
|
+
if ! grep -qE "^${key}=" "$file" 2>/dev/null; then
|
|
434
|
+
printf '%s=%s\n' "$key" "$val" >> "$file"
|
|
435
|
+
log " + added missing key: $key"
|
|
436
|
+
fi
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
ensure_web_env_keys() {
|
|
440
|
+
# Only fills keys that are missing; never overwrites existing values.
|
|
441
|
+
# Tokens / secrets get fresh random values (safe because if they were
|
|
442
|
+
# missing, web couldn't have started, so nothing depends on them yet).
|
|
443
|
+
local tok secret webhook
|
|
444
|
+
tok=$(gen_token 20)
|
|
445
|
+
secret=$(gen_token 24)
|
|
446
|
+
webhook=$(gen_token 20)
|
|
447
|
+
ensure_env_key "$WEB_ENV" WORK_PORT "$WORK_PORT"
|
|
448
|
+
ensure_env_key "$WEB_ENV" WORK_HOST "127.0.0.1"
|
|
449
|
+
ensure_env_key "$WEB_ENV" WORK_TOKEN "$tok"
|
|
450
|
+
ensure_env_key "$WEB_ENV" WORK_COOKIE_SECRET "$secret"
|
|
451
|
+
ensure_env_key "$WEB_ENV" WORK_OPERATOR_LOGIN "$USER"
|
|
452
|
+
ensure_env_key "$WEB_ENV" WORK_WRITES_ENABLED "true"
|
|
453
|
+
ensure_env_key "$WEB_ENV" WORK_DB_PATH "$WEB_DATA_DIR/ework.db"
|
|
454
|
+
ensure_env_key "$WEB_ENV" WORK_ATTACHMENT_ROOT "$WEB_DATA_DIR/attachments"
|
|
455
|
+
ensure_env_key "$WEB_ENV" WORK_FILE_ROOTS "/tmp,$DATA_DIR"
|
|
456
|
+
ensure_env_key "$WEB_ENV" WORK_DAEMON_BOT_LOGIN "$BOT_NAME"
|
|
457
|
+
ensure_env_key "$WEB_ENV" WORK_DAEMON_WEBHOOK_URL "http://127.0.0.1:$DAEMON_PORT"
|
|
458
|
+
ensure_env_key "$WEB_ENV" WORK_DAEMON_WEBHOOK_SECRET "$webhook"
|
|
459
|
+
}
|
|
460
|
+
|
|
395
461
|
write_daemon_env() {
|
|
396
462
|
mkdir -p "$(dirname "$DAEMON_ENV")"
|
|
397
463
|
local bot_token="$1"
|
|
@@ -399,6 +465,22 @@ write_daemon_env() {
|
|
|
399
465
|
# Reuse webhook secret from web env so daemon's signature matches web's verify
|
|
400
466
|
webhook=$(awk -F= '/^WORK_DAEMON_WEBHOOK_SECRET=/{print $2}' "$WEB_ENV" 2>/dev/null || true)
|
|
401
467
|
[[ -n "$webhook" ]] || webhook=$(gen_token 20)
|
|
468
|
+
if [[ -f "$DAEMON_ENV" ]]; then
|
|
469
|
+
log "Preserving existing $DAEMON_ENV"
|
|
470
|
+
# Same forward-fill pattern as web: required keys get filled if missing.
|
|
471
|
+
ensure_env_key "$DAEMON_ENV" DAEMON_ENV "production"
|
|
472
|
+
ensure_env_key "$DAEMON_ENV" DAEMON_PORT "$DAEMON_PORT"
|
|
473
|
+
ensure_env_key "$DAEMON_ENV" DAEMON_HOST "127.0.0.1"
|
|
474
|
+
ensure_env_key "$DAEMON_ENV" DAEMON_DB_PATH "$DAEMON_DATA_DIR/ework-daemon.db"
|
|
475
|
+
ensure_env_key "$DAEMON_ENV" GITEA_URL "http://127.0.0.1:$WORK_PORT"
|
|
476
|
+
ensure_env_key "$DAEMON_ENV" GITEA_TOKEN "$bot_token"
|
|
477
|
+
ensure_env_key "$DAEMON_ENV" GITEA_WEBHOOK_SECRET "$webhook"
|
|
478
|
+
ensure_env_key "$DAEMON_ENV" BOT_USERNAME "$BOT_NAME"
|
|
479
|
+
ensure_env_key "$DAEMON_ENV" BOT_TOKEN "$bot_token"
|
|
480
|
+
ensure_env_key "$DAEMON_ENV" OPENCODE_BINARY "$(command -v opencode)"
|
|
481
|
+
ensure_env_key "$DAEMON_ENV" OPENCODE_BASE_WORKDIR "$DATA_DIR/opencode-workdir"
|
|
482
|
+
return
|
|
483
|
+
fi
|
|
402
484
|
cat > "$DAEMON_ENV" <<EOF
|
|
403
485
|
# Generated by ework-aio at $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
404
486
|
DAEMON_ENV=production
|
|
@@ -809,14 +891,14 @@ esac
|
|
|
809
891
|
# ─── Install mode ───────────────────────────────────────────────────────────
|
|
810
892
|
hr
|
|
811
893
|
log "ework-aio install"
|
|
812
|
-
log "
|
|
894
|
+
log " mode : $([[ "$USE_SYSTEMD" == "1" ]] && echo "systemd" || echo "PID-file (no systemd)")"
|
|
813
895
|
log " data dir : $DATA_DIR"
|
|
814
896
|
log " web bin : $EWORK_WEB_BIN"
|
|
815
897
|
log " daemon bin : $EWORK_DAEMON_BIN"
|
|
816
898
|
log " opencode : $(command -v opencode) ($($(command -v opencode) --version 2>&1 | head -1))"
|
|
817
899
|
hr
|
|
818
900
|
|
|
819
|
-
if [[ "$SCOPENAME" == "--user" ]] && ! loginctl show-user "$USER" 2>/dev/null | grep -q '^Linger=yes'; then
|
|
901
|
+
if [[ "$USE_SYSTEMD" == "1" && "$SCOPENAME" == "--user" ]] && ! loginctl show-user "$USER" 2>/dev/null | grep -q '^Linger=yes'; then
|
|
820
902
|
warn "User-level systemd requires lingering to keep services alive after logout."
|
|
821
903
|
if [[ "$ASSUME_YES" == "1" ]]; then
|
|
822
904
|
warn "Run this manually: sudo loginctl enable-linger $USER"
|
|
@@ -832,56 +914,57 @@ mkdir -p "$WEB_DATA_DIR" "$DAEMON_DATA_DIR" "$DATA_DIR/opencode-workdir"
|
|
|
832
914
|
|
|
833
915
|
write_web_env
|
|
834
916
|
|
|
835
|
-
# ─── Write ework-web systemd unit
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
"ework-web"
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
#
|
|
849
|
-
#
|
|
850
|
-
#
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
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; }
|
|
917
|
+
# ─── Write ework-web systemd unit (only with `install systemd`) ────────────
|
|
918
|
+
SYSTEMD_OK=0
|
|
919
|
+
if [[ "$USE_SYSTEMD" == "1" ]]; then
|
|
920
|
+
WEB_UNIT="$UNIT_DIR/ework-web.service"
|
|
921
|
+
write_unit_file \
|
|
922
|
+
"ework-web" \
|
|
923
|
+
"ework — multi-project issue tracker" \
|
|
924
|
+
"$EWORK_WEB_BIN" \
|
|
925
|
+
"$WEB_DATA_DIR" \
|
|
926
|
+
"$WEB_ENV" \
|
|
927
|
+
"$WEB_UNIT"
|
|
928
|
+
ok "Wrote $WEB_UNIT"
|
|
929
|
+
|
|
930
|
+
# systemd calls here are best-effort. If systemd isn't functional on this host
|
|
931
|
+
# (containers without systemd PID 1, polkit redirects under sudo, missing
|
|
932
|
+
# /etc/systemd/system) we still want install to complete so the user can run
|
|
933
|
+
# `ework-aio start` (PID-file mode) against the scaffolded .env.
|
|
934
|
+
SYSTEMD_OK=1
|
|
935
|
+
if ! ctl daemon-reload; then
|
|
936
|
+
warn "systemctl daemon-reload failed — systemd may be unavailable on this host."
|
|
937
|
+
SYSTEMD_OK=0
|
|
862
938
|
fi
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
939
|
+
|
|
940
|
+
if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "1" ]]; then
|
|
941
|
+
log "Starting ework-web (systemd)..."
|
|
942
|
+
ctl enable ework-web.service || { warn "systemctl enable failed"; SYSTEMD_OK=0; }
|
|
943
|
+
if [[ "$SYSTEMD_OK" == "1" ]]; then
|
|
944
|
+
ctl restart ework-web.service || { warn "systemctl restart failed"; SYSTEMD_OK=0; }
|
|
945
|
+
fi
|
|
946
|
+
if [[ "$SYSTEMD_OK" == "1" ]]; then
|
|
947
|
+
for i in $(seq 1 60); do
|
|
948
|
+
if curl -sf -o /dev/null "http://127.0.0.1:$WORK_PORT/login"; then
|
|
949
|
+
ok "ework-web listening on :$WORK_PORT (after ${i} half-seconds)"
|
|
950
|
+
break
|
|
951
|
+
fi
|
|
952
|
+
sleep 0.5
|
|
953
|
+
[[ $i -eq 60 ]] && { warn "ework-web did not come up via systemd in 30s. Falling back to PID-file mode."; SYSTEMD_OK=0; }
|
|
954
|
+
done
|
|
955
|
+
fi
|
|
956
|
+
else
|
|
957
|
+
warn "--no-start: unit enabled but not started"
|
|
958
|
+
ctl enable ework-web.service 2>/dev/null || true
|
|
872
959
|
fi
|
|
873
|
-
else
|
|
874
|
-
warn "--no-start: unit enabled but not started"
|
|
875
|
-
ctl enable ework-web.service 2>/dev/null || true
|
|
876
960
|
fi
|
|
877
961
|
|
|
878
|
-
# ─── PID-file mode
|
|
879
|
-
#
|
|
880
|
-
#
|
|
881
|
-
#
|
|
882
|
-
# calls to :WORK_PORT succeed.
|
|
962
|
+
# ─── Start ework-web in PID-file mode ──────────────────────────────────────
|
|
963
|
+
# Default path (no `systemd` arg) OR systemd fallback. We bring web up via
|
|
964
|
+
# setsid+nohup so the bot bootstrap below can HTTP-probe it. Web stays
|
|
965
|
+
# running in PID-file mode after install — use `ework-aio stop` to kill it.
|
|
883
966
|
if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "0" ]]; then
|
|
884
|
-
log "Starting ework-web
|
|
967
|
+
log "Starting ework-web (PID-file mode)..."
|
|
885
968
|
WEB_LOG_FILE="$DATA_DIR/run/web.log"
|
|
886
969
|
mkdir -p "$(dirname "$WEB_LOG_FILE")"
|
|
887
970
|
setsid nohup "$EWORK_WEB_BIN" >>"$WEB_LOG_FILE" 2>&1 </dev/null &
|
|
@@ -975,42 +1058,55 @@ fi
|
|
|
975
1058
|
# ─── Write ework-daemon .env ───────────────────────────────────────────────
|
|
976
1059
|
write_daemon_env "$BOT_TOKEN"
|
|
977
1060
|
|
|
978
|
-
# ─── Write ework-daemon systemd
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1061
|
+
# ─── Write + start ework-daemon (systemd path, only with `install systemd`) ─
|
|
1062
|
+
if [[ "$USE_SYSTEMD" == "1" ]]; then
|
|
1063
|
+
DAEMON_UNIT="$UNIT_DIR/ework-daemon.service"
|
|
1064
|
+
write_unit_file \
|
|
1065
|
+
"ework-daemon" \
|
|
1066
|
+
"ework-daemon — issue-driven AI dev daemon" \
|
|
1067
|
+
"$EWORK_DAEMON_BIN" \
|
|
1068
|
+
"$DAEMON_DATA_DIR" \
|
|
1069
|
+
"$DAEMON_ENV" \
|
|
1070
|
+
"$DAEMON_UNIT" \
|
|
1071
|
+
" \"\""
|
|
1072
|
+
# (trailing " \"\"" is a no-op separator; kept for future extra env injection)
|
|
1073
|
+
ok "Wrote $DAEMON_UNIT"
|
|
1074
|
+
|
|
1075
|
+
ctl daemon-reload 2>/dev/null || true
|
|
1076
|
+
if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "1" ]]; then
|
|
1077
|
+
log "Starting ework-daemon (systemd)..."
|
|
1078
|
+
ctl enable ework-daemon.service 2>/dev/null || true
|
|
1079
|
+
ctl restart ework-daemon.service 2>/dev/null || warn "ework-daemon restart via systemd failed; falling back to PID-file mode"
|
|
1080
|
+
sleep 1
|
|
1081
|
+
if ctl is-active --quiet ework-daemon.service 2>/dev/null; then
|
|
1082
|
+
ok "ework-daemon active (systemd)"
|
|
1083
|
+
else
|
|
1084
|
+
warn "ework-daemon not active via systemd — falling back to PID-file mode"
|
|
1085
|
+
SYSTEMD_OK=0
|
|
1086
|
+
fi
|
|
999
1087
|
else
|
|
1000
|
-
|
|
1088
|
+
ctl enable ework-daemon.service 2>/dev/null || true
|
|
1001
1089
|
fi
|
|
1002
|
-
else
|
|
1003
|
-
ctl enable ework-daemon.service 2>/dev/null || true
|
|
1004
1090
|
fi
|
|
1005
1091
|
|
|
1006
|
-
|
|
1092
|
+
# ─── Start ework-daemon in PID-file mode (default path) ────────────────────
|
|
1093
|
+
# Mirrors the web PID-file start. Skipped if systemd already brought it up.
|
|
1094
|
+
if [[ "$NO_START" == "0" && "$SYSTEMD_OK" == "0" ]]; then
|
|
1095
|
+
log "Starting ework-daemon (PID-file mode)..."
|
|
1096
|
+
DAEMON_LOG_FILE="$DATA_DIR/run/daemon.log"
|
|
1097
|
+
mkdir -p "$(dirname "$DAEMON_LOG_FILE")"
|
|
1098
|
+
setsid nohup "$EWORK_DAEMON_BIN" >>"$DAEMON_LOG_FILE" 2>&1 </dev/null &
|
|
1099
|
+
DAEMON_PID=$!
|
|
1100
|
+
disown "$DAEMON_PID" 2>/dev/null || true
|
|
1101
|
+
printf '%s\n' "$DAEMON_PID" > "$DATA_DIR/run/daemon.pid"
|
|
1102
|
+
ok "ework-daemon started in PID-file mode (pid $DAEMON_PID, log $DAEMON_LOG_FILE)"
|
|
1103
|
+
fi
|
|
1104
|
+
|
|
1105
|
+
if [[ "$USE_SYSTEMD" == "1" && "$SYSTEMD_OK" == "0" ]]; then
|
|
1007
1106
|
hr
|
|
1008
1107
|
warn "systemd mode did not come up cleanly on this host."
|
|
1009
|
-
warn "Services
|
|
1010
|
-
warn "
|
|
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"
|
|
1108
|
+
warn "Services started in PID-file mode instead. systemd unit files were"
|
|
1109
|
+
warn "written but are not active. To clean them up: ework-aio uninstall"
|
|
1014
1110
|
hr
|
|
1015
1111
|
fi
|
|
1016
1112
|
|
|
@@ -1071,7 +1167,7 @@ fi
|
|
|
1071
1167
|
|
|
1072
1168
|
# ─── Done ──────────────────────────────────────────────────────────────────
|
|
1073
1169
|
hr
|
|
1074
|
-
ok "Install complete."
|
|
1170
|
+
ok "Install complete ($([[ "$USE_SYSTEMD" == "1" ]] && echo "systemd mode" || echo "PID-file mode"))."
|
|
1075
1171
|
hr
|
|
1076
1172
|
printf '\n%s→%s Open %shttp://127.0.0.1:%s/login%s\n' \
|
|
1077
1173
|
"$c_bold" "$c_reset" "$c_dim" "$WORK_PORT" "$c_reset"
|
|
@@ -1083,7 +1179,14 @@ printf ' Bot user: %s%s%s (auto-created, used by ework-daemon)\n' \
|
|
|
1083
1179
|
printf ' Data dir: %s%s%s\n' "$c_dim" "$DATA_DIR" "$c_reset"
|
|
1084
1180
|
printf ' Logs: ework-aio logs web | ework-aio logs daemon\n'
|
|
1085
1181
|
printf ' Status: ework-aio status\n'
|
|
1182
|
+
printf ' Stop: ework-aio stop\n'
|
|
1086
1183
|
printf ' Uninstall: ework-aio uninstall\n'
|
|
1184
|
+
if [[ "$USE_SYSTEMD" != "1" ]]; then
|
|
1185
|
+
hr
|
|
1186
|
+
printf '\n%sPID-file mode note%s (services run via nohup, not systemd)\n' "$c_bold" "$c_reset"
|
|
1187
|
+
printf ' • To enable auto-restart on boot, re-run with: ework-aio install systemd\n'
|
|
1188
|
+
printf ' • Services stop when you kill them (no supervisor). Use ework-aio stop to stop cleanly.\n'
|
|
1189
|
+
fi
|
|
1087
1190
|
hr
|
|
1088
1191
|
printf '\n%sNext steps (optional config)%s\n' "$c_bold" "$c_reset"
|
|
1089
1192
|
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.
|
|
3
|
+
"version": "0.1.17",
|
|
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",
|