ework-aio 0.1.5 → 0.1.7

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/bin/ework-aio CHANGED
@@ -16,16 +16,22 @@ Usage:
16
16
  ework-aio install [options] Install and start ework-web + ework-daemon
17
17
  ework-aio uninstall Stop services and remove units (keeps data)
18
18
  ework-aio status Show service status
19
- ework-aio logs [svc] Tail logs (svc: ework-web | ework-daemon)
19
+ ework-aio logs [svc] Tail logs (svc: web | daemon)
20
20
  ework-aio env Print the .env path and key names (no values)
21
+ ework-aio config <subcommand> Read / change runtime .env keys
22
+ config list List settable keys + current values
23
+ config get <KEY> Print one key's value
24
+ config set <KEY> <VALUE> Set a key, then restart affected service
25
+ (use --no-restart to defer)
26
+ config restart <web|daemon|both>
21
27
  ework-aio --version Print version
22
28
 
23
29
  Install options:
24
30
  --user Use user-level systemd units (default if non-root)
25
31
  --system Use system-level systemd units (default if root)
26
32
  --data-dir <path> Override data directory (default: ~/.local/share/ework-aio)
27
- --port <n> ework-web port (default: 3002)
28
- --daemon-port <n> ework-daemon port (default: 3101)
33
+ --port <n> ework-web port (default 3002)
34
+ --daemon-port <n> ework-daemon port (default 3101)
29
35
  --bot-name <login> Bot username (default: ework-daemon)
30
36
  --no-start Install units but don't start services
31
37
  --yes Skip all prompts (use generated defaults)
@@ -49,7 +55,7 @@ if (!existsSync(installSh)) {
49
55
  process.exit(1);
50
56
  }
51
57
 
52
- const knownSubs = ["install", "uninstall", "status", "logs", "env"];
58
+ const knownSubs = ["install", "uninstall", "status", "logs", "env", "config"];
53
59
  const finalArgs = knownSubs.includes(subcommand) ? args : ["install", ...args];
54
60
 
55
61
  const result = spawnSync(["bash", installSh, ...finalArgs], {
package/bin/install.sh CHANGED
@@ -100,6 +100,39 @@ if [[ "$SCOPENAME" == "--user" && "${EUID:-$(id -u)}" == "0" ]]; then
100
100
  SCOPENAME="--system"
101
101
  fi
102
102
 
103
+ # ─── Ensure --user mode can actually talk to systemd ─────────────────────────
104
+ # When invoked from ssh/cron/non-PAM-login shells, XDG_RUNTIME_DIR is often
105
+ # empty and systemctl --user fails with "Failed to connect to bus" or — worse —
106
+ # "Unit not found" (when a stale bus from another session responds but doesn't
107
+ # know about installed units). Auto-export the runtime dir + bus socket if we
108
+ # can find them. No-op for --system scope.
109
+ ensure_user_session() {
110
+ [[ "$SCOPENAME" == "--user" ]] || return 0
111
+ local uid
112
+ uid="$(id -u)"
113
+ local rundir="/run/user/$uid"
114
+
115
+ if [[ -z "${XDG_RUNTIME_DIR:-}" && -d "$rundir" ]]; then
116
+ export XDG_RUNTIME_DIR="$rundir"
117
+ fi
118
+ if [[ -z "${DBUS_SESSION_BUS_ADDRESS:-}" && -S "${XDG_RUNTIME_DIR}/bus" ]]; then
119
+ export DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"
120
+ fi
121
+
122
+ # Final sanity: can we reach systemd --user at all?
123
+ if ! systemctl --user is-system-running >/dev/null 2>&1 \
124
+ && ! systemctl --user list-units >/dev/null 2>&1; then
125
+ warn "systemctl --user cannot reach the user session bus."
126
+ warn " XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-<empty>}"
127
+ warn " DBUS_SESSION_BUS_ADDRESS=${DBUS_SESSION_BUS_ADDRESS:-<empty>}"
128
+ warn "Likely causes: ssh without PAM, no linger, or session never started."
129
+ warn "Fix: 'sudo loginctl enable-linger \$USER' then relogin; or reinstall with --system."
130
+ return 1
131
+ fi
132
+ return 0
133
+ }
134
+ ensure_user_session || true # warn but don't hard-fail — let later steps report specifics
135
+
103
136
  # ─── Pre-flight: command dependencies ───────────────────────────────────────
104
137
  need_cmd() {
105
138
  command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1. $2"
@@ -260,7 +293,45 @@ EOF
260
293
  fi
261
294
  }
262
295
 
263
- ctl() { systemctl "$SCOPENAME" "$@"; }
296
+ # ctl wraps `systemctl $SCOPENAME` with two hardenings over the bare command:
297
+ # 1. If output contains "Unit ... not found", retry once after daemon-reload
298
+ # — fresh user sessions (no linger, post-ssh-reconnect) often have a stale
299
+ # unit cache and this is the standard fix.
300
+ # 2. If output mentions bus connection failure, print an actionable hint
301
+ # instead of letting the raw "No medium found" / "Failed to connect to
302
+ # bus" message through unchanged.
303
+ ctl() {
304
+ local out rc
305
+ out="$(systemctl "$SCOPENAME" "$@" 2>&1)"
306
+ rc=$?
307
+ if [[ $rc -ne 0 ]]; then
308
+ if [[ "$out" == *"Failed to connect to bus"* || "$out" == *"No medium found"* ]]; then
309
+ cat >&2 <<EOF
310
+ ${c_red}systemctl $SCOPENAME failed to reach the user bus.${c_reset}
311
+ $out
312
+ Hint: run from a logged-in session, or:
313
+ export XDG_RUNTIME_DIR=/run/user/$(id -u)
314
+ export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus
315
+ or reinstall with: sudo ework-aio install --system
316
+ EOF
317
+ return $rc
318
+ fi
319
+ if [[ "$out" == *"not found"* ]]; then
320
+ systemctl "$SCOPENAME" daemon-reload >/dev/null 2>&1 || true
321
+ out="$(systemctl "$SCOPENAME" "$@" 2>&1)"
322
+ rc=$?
323
+ if [[ $rc -ne 0 ]]; then
324
+ cat >&2 <<EOF
325
+ ${c_red}systemctl $SCOPENAME $*: unit not found after daemon-reload.${c_reset}
326
+ The unit file may be missing from $UNIT_DIR. Re-run:
327
+ ework-aio install --no-start # rewrites units, preserves .env/data
328
+ EOF
329
+ return $rc
330
+ fi
331
+ fi
332
+ fi
333
+ printf '%s\n' "$out"
334
+ }
264
335
 
265
336
  # ─── Config mode: read/change runtime .env keys ─────────────────────────────
266
337
  # Each entry: KEY|SERVICE|DESCRIPTION. Only keys in this list are settable via
@@ -343,14 +414,24 @@ service_for_key() {
343
414
 
344
415
  restart_service() {
345
416
  local svc="$1"
417
+ local rc=0
346
418
  case "$svc" in
347
- web) ctl restart ework-web.service && ok "Restarted ework-web" ;;
348
- daemon) ctl restart ework-daemon.service && ok "Restarted ework-daemon" ;;
419
+ web) ctl restart ework-web.service && ok "Restarted ework-web" || rc=$? ;;
420
+ daemon) ctl restart ework-daemon.service && ok "Restarted ework-daemon" || rc=$? ;;
349
421
  both)
350
- ctl restart ework-web.service ework-daemon.service && ok "Restarted ework-web + ework-daemon"
422
+ ctl restart ework-web.service ework-daemon.service \
423
+ && ok "Restarted ework-web + ework-daemon" || rc=$?
351
424
  ;;
352
425
  *) return 1 ;;
353
426
  esac
427
+ if [[ $rc -ne 0 ]]; then
428
+ warn "restart of '$svc' failed (exit $rc)."
429
+ warn "The .env changes are saved; services still need to be reloaded."
430
+ warn "Recovery: 'ework-aio config restart $svc' from a logged-in shell,"
431
+ warn "or 'sudo ework-aio install --system' to escape user-bus limitations."
432
+ return $rc
433
+ fi
434
+ return 0
354
435
  }
355
436
 
356
437
  config_help() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ework-aio",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
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",