@rubytech/create-realagent 1.0.684 → 1.0.686

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 (36) hide show
  1. package/dist/index.js +49 -203
  2. package/dist/pinned-binaries.js +10 -41
  3. package/dist/uninstall.js +47 -19
  4. package/package.json +1 -1
  5. package/payload/platform/config/brand.json +1 -0
  6. package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +35 -9
  7. package/payload/platform/plugins/docs/PLUGIN.md +2 -0
  8. package/payload/platform/plugins/docs/references/cloudflare.md +1 -1
  9. package/payload/platform/plugins/docs/references/deployment.md +19 -6
  10. package/payload/platform/plugins/docs/references/graph.md +38 -0
  11. package/payload/platform/plugins/docs/references/platform.md +10 -7
  12. package/payload/platform/plugins/docs/references/troubleshooting.md +23 -13
  13. package/payload/platform/scripts/vnc.sh +7 -7
  14. package/payload/platform/templates/systemd/{maxy-edge.service → edge.service.template} +9 -6
  15. package/payload/server/maxy-edge.js +7 -369
  16. package/payload/server/public/assets/admin-BqLtaMVu.js +352 -0
  17. package/payload/server/public/assets/{data-DUSyrydY.js → data-BZ7v-zug.js} +1 -1
  18. package/payload/server/public/assets/{file-CDJ6dUV3.js → file-CScYkZq5.js} +1 -1
  19. package/payload/server/public/assets/graph-tjXdtwk-.js +50 -0
  20. package/payload/server/public/assets/{house-CNP_bwvT.js → house-CdFRNujU.js} +1 -1
  21. package/payload/server/public/assets/{jsx-runtime-BFFQvkdQ.css → jsx-runtime-Og0q7dXg.css} +1 -1
  22. package/payload/server/public/assets/{public-sHoAccvb.js → public-CrkQJek6.js} +2 -2
  23. package/payload/server/public/assets/{share-2-DBcb9j6E.js → share-2-Ev-D4Lm9.js} +1 -1
  24. package/payload/server/public/assets/{useVoiceRecorder-CtSgpc95.js → useVoiceRecorder-DyDXH7EA.js} +2 -2
  25. package/payload/server/public/assets/{x-CTVJaC_u.js → x-D5W7ddgP.js} +1 -1
  26. package/payload/server/public/data.html +6 -6
  27. package/payload/server/public/graph.html +6 -6
  28. package/payload/server/public/index.html +7 -8
  29. package/payload/server/public/public.html +4 -4
  30. package/payload/server/server.js +830 -258
  31. package/payload/platform/templates/dotfiles/.tmux.conf +0 -1
  32. package/payload/platform/templates/systemd/maxy-ttyd.service +0 -25
  33. package/payload/server/public/assets/admin-WQxJgaus.js +0 -362
  34. package/payload/server/public/assets/admin-kHJ-D0s7.css +0 -1
  35. package/payload/server/public/assets/graph-CWcYp5bE.js +0 -50
  36. /package/payload/server/public/assets/{jsx-runtime-BVKWELH6.js → jsx-runtime-CHqDsKlc.js} +0 -0
@@ -68,19 +68,32 @@ The logs will show which service failed to start and why. Common causes:
68
68
 
69
69
  ## Systemd units on each device
70
70
 
71
- Each Maxy device runs one `--user` systemd unit:
71
+ Each installed brand runs two per-brand `--user` systemd units (Task 662 + Task 664 — unit filenames are prefixed with the brand's `hostname` so two brands on the same device never share a unit file):
72
72
 
73
- - `maxy-ui.service` — the admin + public HTTP server on `127.0.0.1:19199`. Restarted by the upgrade flow; short downtime is expected during steps 8→12 of an upgrade.
74
- - `maxy-edge.service` — the always-on public listener on the configured port (default 19200). Reverse-proxies HTTP to `maxy-ui`, handles `/websockify` (VNC) and `/ttyd` (admin terminal) WebSocket upgrades locally. Does NOT restart during an upgrade — the browser WebSocket stays connected by construction.
75
- - `maxy-ttyd.service` — `ttyd` bound to `127.0.0.1:7681`, running `tmux new-session -A -s maxy-pty`. Owns the byte-stream admin terminal rendered by xterm.js in the header overlay and the Software Update modal (Task 657). Independent of `maxy-ui` and `maxy-edge`; outlives service restarts so scrollback is preserved.
73
+ - `{hostname}.service` — the admin + public HTTP server on `127.0.0.1:19199`. Restarted by the upgrade flow; short downtime is expected during steps 8→11 of an upgrade.
74
+ - `{hostname}-edge.service` — the always-on public listener on the configured port (default 19200). Reverse-proxies HTTP to the main brand service and handles `/websockify` (VNC) WebSocket upgrades locally. Does NOT restart during an upgrade — the browser WebSocket stays connected by construction.
76
75
 
77
- If the admin terminal fails to open, check `sudo tail -n 50 ~/.maxy/logs/edge-boot.log` the `ttyd-ws-upgrade` / `ttyd-proxy-open` / `ttyd-proxy-close` lines carry a `corrId` that ties the full session lifecycle together. For unit health, `systemctl --user status maxy-ttyd` + `journalctl --user -u maxy-ttyd`.
76
+ Upgrade and Cloudflare setup (Task 664) run as detached actions: `systemd-run --user` transient units per invocation with stdout+stderr persisted to `~/.maxy/logs/actions/<actionId>.log` and streamed to the UI via SSE. No boot-time service file exists for these.
77
+
78
+ If an action looks stuck, read `~/.maxy/logs/actions/<actionId>.log` directly for the full output, or `journalctl --user --identifier=maxy-action-<actionId>` for systemd's record.
79
+
80
+ **Pre-Task-662 / pre-Task-664 upgrade** — devices that ran an installer before Task 662 have legacy shared `maxy-edge.service` / `maxy-ttyd.service` units; devices that ran before Task 664 have per-brand `{hostname}-ttyd.service` units plus a pinned `/usr/local/bin/ttyd` binary. Neither is removed automatically — do this cleanup once per device before re-running any installer:
81
+
82
+ ```bash
83
+ systemctl --user stop maxy-edge maxy-ttyd realagent-ttyd 2>/dev/null || true
84
+ systemctl --user disable maxy-edge maxy-ttyd realagent-ttyd 2>/dev/null || true
85
+ rm -f ~/.config/systemd/user/maxy-edge.service \
86
+ ~/.config/systemd/user/maxy-ttyd.service \
87
+ ~/.config/systemd/user/realagent-ttyd.service
88
+ sudo rm -f /usr/local/bin/ttyd
89
+ systemctl --user daemon-reload
90
+ ```
78
91
 
79
92
  ## Running multiple brands on one device
80
93
 
81
94
  A single Pi or laptop can host more than one brand (for example Maxy and Real Agent) side by side. Each brand runs as its own service on its own port, with its own install directory and its own data. Installing one brand does not touch the other.
82
95
 
83
- - **Separate:** each brand has its own install folder (`~/maxy/`, `~/realagent/`), its own config folder (`~/.maxy/`, `~/.realagent/`), its own web port, its own Cloudflare tunnel state, and by default its own Neo4j database (Maxy on bolt port 7687, Real Agent on 7688).
96
+ - **Separate:** each brand has its own install folder (`~/maxy/`, `~/realagent/`), its own config folder (`~/.maxy/`, `~/.realagent/`), its own web port, its own Cloudflare tunnel state, its own edge systemd unit (`maxy-edge.service` vs `realagent-edge.service`), and by default its own Neo4j database (Maxy on bolt port 7687, Real Agent on 7688). Action runner units are transient and per-invocation, not per-brand, so no naming conflict is possible.
84
97
  - **Shared:** both brands share the system Chromium/VNC stack, the Ollama model server, and the `cloudflared` command itself. Browser automation is serialised — one admin session at a time across both brands.
85
98
 
86
99
  To install a second brand on a device that already runs the first, just run the other installer. No flags needed for isolation:
@@ -0,0 +1,38 @@
1
+ # Graph View
2
+
3
+ The **Graph** admin page (`/graph`) renders a force-directed view of your
4
+ account's Neo4j subgraph. Labels on the canvas follow the zoom level, so you
5
+ see the most useful identity at every scale.
6
+
7
+ ## Conversation label tiers
8
+
9
+ Conversation nodes carry the most operator-meaningful identity in the
10
+ subgraph (the conversation name or summary, the date it started, the message
11
+ count). They render in one of three tiers, switched by canvas scale:
12
+
13
+ | Zoom | Label shape | Example |
14
+ |------|-------------|---------|
15
+ | Zoomed out (< 0.7×) | Compact — one line, capped at 24 characters. Preserves the no-overlap contract that matters when nodes are tightly packed. | `Maxyfi branding conflict…` |
16
+ | Mid zoom (0.7× to 1.3×) | Wrapped — up to two lines of 24 characters each, soft-ellipsis on overflow. Full name is visible without hover. | `Maxyfi branding conflict` / `with Rubytech` |
17
+ | Zoomed in (≥ 1.3×) | Detailed — wrapped name plus a metadata line reading `YYYY-MM-DD · N msgs`. | `Maxyfi branding conflict` / `with Rubytech` / `2026-04-23 · 7 msgs` |
18
+
19
+ Non-Conversation nodes (People, Messages, Tasks, WorkflowRuns, etc.) keep
20
+ their concise single-line labels at every zoom level — the canvas stays
21
+ readable when you zoom out to see a large subgraph.
22
+
23
+ Tier transitions are debounced so spinning the scroll wheel does not cause
24
+ label flicker; labels only rewrite once zoom settles on a new tier.
25
+
26
+ ## Tooltips and side panel
27
+
28
+ Hovering a node still shows the full 5-line tooltip (display name, labels,
29
+ id, created at, updated at). Clicking a Conversation opens the side panel
30
+ with the full property table — zoom-tier changes never alter these paths.
31
+
32
+ ## Trashed conversations
33
+
34
+ Trashed Conversation nodes are hidden by default. Toggle **Show trashed** in
35
+ the filter popover to surface them; they render with a faded fill and dashed
36
+ border, with their zoom-tier labels intact. The `N msgs` count excludes
37
+ trashed Messages, so the detailed-tier label reflects only live turns in the
38
+ conversation.
@@ -62,19 +62,22 @@ There is no dashboard, no settings panel, no menus. Everything is done through c
62
62
 
63
63
  The chat input auto-grows as you type — it expands to fit your message and shrinks back when you delete text. You can also drag the resize handle above the input to set a custom height.
64
64
 
65
- ## Admin Terminal
65
+ ## Software Update and Cloudflare Setup
66
66
 
67
- The admin UI has a single terminal surface one pipeline (a real GUI terminal emulator running on the Pi's VNC display `:99`, rendered inside an `iframe` of `/vnc-viewer.html`) with two entry points: the burger menu's **Terminal** button (opens a plain operator shell) and the Software Update modal's **Upgrade** button (opens the same iframe with `npx -y @rubytech/create-maxy@latest` already running in the spawned shell).
67
+ There is no free-form terminal surface in the admin UI ad-hoc shell access stays on SSH. The two flows that used to need a terminal (upgrade, Cloudflare tunnel setup) run as **detached actions** instead.
68
68
 
69
- The binary is chosen by target display. For the VNC virtual display `:99`, **xterm** is preferred because it honours `DISPLAY` directly with no IPC layer. For the native loopback display, **gnome-terminal** is preferred because the login session's `gnome-terminal-server` owns that display. (gnome-terminal cannot be used for the VNC display — it's a D-Bus launcher that delegates window creation to the session's server, and the window would appear on the physical screen instead of inside the admin iframe.) Post-spawn, the launch pipeline asserts the window actually landed on the target display via `xdotool search --onlyvisible --class '.'` if anything went wrong (gnome-terminal D-Bus delegation, missing `xdotool`, broken X server), the 502 response body carries the exact diagnostic string inline in the UI instead of showing a black rectangle.
69
+ **Software Update flow.** Click Upgrade in the modal the modal asks for your sudo password once the admin server validates it and launches a transient `systemd-run --user` unit running `npx -y @rubytech/create-maxy@latest`. The action unit is a peer of the brand service (not a child), so the installer's mid-run `systemctl --user restart maxy` does not kill the upgrade itself it finishes running, then the web UI reloads on the new version. The modal shows a live log panel with three event types:
70
+ - every stdout/stderr line the installer emits, timestamped server-side;
71
+ - a heartbeat every 5 seconds carrying `state=active` + `last_phase` so you can see the installer is alive even during silent phases (tarball download, dep install);
72
+ - a final banner on exit with the return code and elapsed time.
70
73
 
71
- **Software Update flow.** Click Upgrade in the modal the admin server kills any pre-existing terminal on `:99` (the upgrade must run in a fresh shell) and spawns the chosen binary with a command dispatcher: `xterm -e bash -c "npx …; exec bash"` or `gnome-terminal -- bash -c "npx …; exec bash"`. The trailing `exec bash` replaces the shell process after `npx` exits so the window stays open — you can scroll through the full installer output and read the final "Open in your browser:" line at your own pace. The modal mounts the fullscreen VNC terminal overlay (the same surface the burger menu's Terminal button uses) and the operator watches the installer run at viewport height. A background poll of `GET /api/admin/version` every 5 seconds detects completion: the moment `installed === latest`, the modal flips to success and the page reloads two seconds later. Password-protected `sudo` prompts appear natively inside the terminal — the password you type never leaves the Pi.
74
+ If the browser drops the SSE connection mid-upgrade (typical during the maxy restart window), the panel reconnects within two seconds and replays any lines you missed from the persisted log.
72
75
 
73
- **Operator Terminal flow.** The burger menu's Terminal button uses the exact same pipeline, minus the pre-loaded command. Click Terminal the admin server spawns the same binary (no `-e`/`--` dispatcher, no `bash -c` wrapper) the iframe shows an empty shell. Closing the overlay with Esc or × kills the spawned PID on the Pi via `POST /api/admin/terminal/close`; reopening launches a fresh shell.
76
+ **Cloudflare setup flow.** Same pattern POST to `/api/admin/cloudflare/setup` launches a `cloudflare-setup` action that runs `~/setup-tunnel.sh <brand> <port> <hostname...>`. When the script emits the OAuth consent URL on stdout, the log panel surfaces an **"Authorise in Cloudflare"** button; clicking it opens the consent page in a new tab. After you approve, the script's callback receives `cert.pem` and the setup continues through `tunnel create`/`route`/`run`. On devices where a VNC Chromium is also running, the script can drive the click via CDP automatically (same button remains a harmless safety net).
74
77
 
75
- **If you click Upgrade while an operator Terminal is open** (or vice versa), the pre-existing shell is killed and the iframe refreshes with the new shell. The upgrade is disruptive by design you cannot graft an installer onto a shell that already has your env, cwd, and aliases.
78
+ **Sudo password** is prompted once per upgrade. The admin server pipes it to `sudo -S -v` to validate + cache, then forwards it to the action unit via `systemd-run --setenv=SUDO_PASSWORD` so the installer's in-unit `sudo -S` reads it directlyper-TTY sudoers configurations where the user-level cache does not cover a fresh systemd-run unit still work. The password is never written to any log, SSE frame, or persisted file.
76
79
 
77
- **Error surface.** If the terminal emulator fails to spawn on `:99` (missing xterm, gnome-terminal broken, X server down), the UpdateModal renders the verbatim server-side diagnostic — e.g. `[terminal-launch] failed err="window absent from target display after spawn" pid=... display=:99 observed_windows=0 transport=vnc reason=upgrade` — and the Upgrade button re-labels to "Try again". The same string lands in `~/.maxy/logs/vnc-boot.log` under `action=launch-upgrade-failed err="..."`, so what you see in the modal and what your operator-visible diagnostic grep finds are identical.
80
+ **Log files.** Each action writes its full output to `~/.maxy/logs/actions/<actionId>.log` for seven days. `journalctl --user --identifier=maxy-action-<actionId>` gives the systemd-level view.
78
81
 
79
82
  **Authorisation** is inherited from the same `canAccessAdmin()` gate that wraps every `/api/admin/*` route.
80
83
 
@@ -93,26 +93,36 @@ If the initial Cloudflare login fails during setup, Maxy will fall back to askin
93
93
 
94
94
  ---
95
95
 
96
- ## Admin terminal renders leading `0`, `1`, or `2` characters (wire-format decoder not running)
96
+ ## Action runner upgrade or Cloudflare setup appears stuck
97
97
 
98
- **Symptom:** The header-menu Terminal or Software Update modal connects, but the xterm.js buffer shows literal digits where the tmux prompt should be — e.g. `1tmux new-session -A -s maxy-pty -x 200 -y 50 (neo)2{"..."}`. Typing keystrokes does nothing (the terminal looks alive but nothing echoes).
98
+ Task 664 replaced the ttyd/xterm admin terminal with a detached action runner. Upgrades and Cloudflare setup now run under transient `systemd-run --user` units whose stdout+stderr land in a persisted per-action log, streamed to the browser via SSE.
99
99
 
100
- **What it means:** ttyd 1.7.7 frames every WebSocket message with a 1-byte command prefix (`'0'` for output, `'1'` for window title, `'2'` for preferences). The React terminal needs the [ttyd-protocol.ts](../../../../platform/ui/app/lib/ttyd-protocol.ts) decoder to split the prefix and route accordingly. If the decoder isn't wired up — typically because an older bundle was installed or a hotfix reverted the wiring — xterm.js receives the raw bytes and renders the prefix as a literal digit. Outbound keystrokes have the mirror problem: ttyd discards any frame that doesn't start with `'0'` INPUT.
100
+ **Heartbeat stalled** (log panel header shows rising `silent Ns` amber badge).
101
101
 
102
- **Check (browser DevTools console on admin.maxy.bot):**
102
+ - Open the log panel header: `state: <systemd_state>` tells you the unit's current state.
103
+ - `systemd_state: active` + silent >30s → the child is running but emitting nothing. Expected for `npx` while it downloads the tarball, or `cloudflared tunnel login` waiting for an operator click.
104
+ - `systemd_state: inactive` + no `exit` event → the exit event was missed; the server-side heartbeat timer will emit it on the next 5 s tick.
105
+ - `systemd_state: failed` → see the next symptom.
103
106
 
104
- ```
105
- [terminal] connected
106
- [ttyd-client] protocol negotiated cmd=0 payloadBytes=<n> ← expected within 3s of connect
107
- ```
107
+ **`ActiveState=failed`** (log panel's exit banner shows a non-zero code).
108
+
109
+ - Read the persisted log directly: `~/.maxy/logs/actions/<actionId>.log` (or `.realagent/...`) has every stdout+stderr line the unit emitted.
110
+ - `journalctl --user --identifier=maxy-action-<actionId>` shows systemd's own record including ExecStartPre/ExecStopPost if any.
111
+ - Common cases:
112
+ - Wrong sudo password → `sudo: 1 incorrect password attempt` near the top of the log; re-open the upgrade modal, enter the correct password.
113
+ - Network failure during `npx` → `npm ERR! network` lines; re-open the modal and retry when network is restored.
114
+ - `cloudflared tunnel login` timed out waiting for OAuth → action exits non-zero with `Timed out after Ns waiting for cert.pem`; re-trigger from the Cloudflare setup form.
115
+
116
+ **"Authorise in Cloudflare" button never appears** (cloudflare-setup action).
117
+
118
+ The setup script emits either the raw `https://dash.cloudflare.com/argotunnel?...` URL in cloudflared's own stderr OR an explicit `OAUTH_URL: <url>` stdout line once URL extraction succeeds. The log panel's regex matches either. If neither appears within ~15 s of launch:
108
119
 
109
- - `[terminal] connected` present but `[ttyd-client] protocol negotiated` absent → the decoder is not running. Re-install: `npx -y @rubytech/create-maxy@latest` (or Software Update from the admin header when reachable).
110
- - `[ttyd-client] unknown cmd prefix=<hex> bytes=<n>` cluster ttyd version drift. The 1.7.7 pin is expected; a newer ttyd may have added command classes. Safe-ignore on 1.7.7.
111
- - Neither line appears → the WebSocket itself isn't connecting; see the "Admin terminal blank / flashing cursor" section below (pre-Task-657 sections are historical, not applicable).
120
+ - The action log file (`~/.maxy/logs/actions/<actionId>.log`) should show `[script:setup-tunnel:cloudflared]` lines. No such lines cloudflared isn't spawning (check whether the binary is on PATH in the transient unit; `systemctl --user show maxy-action-<actionId>` reveals the environment).
121
+ - Lines present but no URLcloudflared output-format drift; file a task with the last 20 lines of the action log.
112
122
 
113
- **Correlate with server side.** `grep corrId=<id> ~/.maxy/logs/edge-boot.log` reveals whether bytes are flowing end-to-end — `ttyd-proxy-chunk dir=upstream→client` lines prove ttyd is sending output. If those lines exist but the browser shows leading digits, the decode listener isn't wired to the live socket; if those lines are absent, the failure is upstream of the client (maxy-ttyd service, tmux attach).
123
+ **Log file missing (action stream returns 404).**
114
124
 
115
- **Regression boundary:** `platform/ui/app/RemoteTerminal.tsx` must import `decodeFrame`, `encodeInput`, and `encodeResize` from `./lib/ttyd-protocol`. `@xterm/addon-attach` is not a dependency it pipes WS bytes to `term.write` raw and cannot satisfy the ttyd framing contract.
125
+ The transient unit was auto-collected by systemd before the client subscribed. Race condition: action finished in <1 s. The per-action log file is retained for 7 days; look for it by name under `~/.maxy/logs/actions/`. If it isn't there, the unit failed before any output (check `journalctl --user -u maxy-action-<id>`).
116
126
 
117
127
  ---
118
128
 
@@ -10,9 +10,10 @@
10
10
  # Chromium :9222 — headed browser with CDP enabled
11
11
  # (Playwright MCP connects via --cdp-endpoint)
12
12
  #
13
- # Task 657: the admin Terminal overlay and upgrade modal now use the
14
- # byte-stream xterm.js surface over /ttyd on maxy-edge, not VNC. This
15
- # script no longer spawns GUI terminal emulators.
13
+ # Task 664 retired the admin-UI terminal surface entirely. This script
14
+ # no longer spawns GUI terminal emulators of any kind; upgrades and
15
+ # cloudflare-setup actions run via the detached action runner
16
+ # (/api/admin/actions/*) rather than an in-browser terminal.
16
17
  #
17
18
  # Display modes (DISPLAY_MODE env var, set by installer --display flag):
18
19
  # virtual (default) — Chromium runs on :99 (VNC virtual display)
@@ -185,10 +186,9 @@ start_chrome() {
185
186
  }
186
187
 
187
188
  # ---------------------------------------------------------------------------
188
- # Task 657 retired the VNC-as-terminal path (Task 627/643): the header
189
- # TerminalOverlay and UpdateModal now mount xterm.js against /ttyd on
190
- # maxy-edge. The GUI-terminal spawn pipeline that lived here is gone.
191
- # Only the Chromium surface remains for BrowserOverlay.
189
+ # Task 664 retired the admin-UI terminal surface entirely: the header
190
+ # TerminalOverlay + UpdateModal embedded terminal stack is gone. Only
191
+ # the Chromium surface remains for BrowserOverlay.
192
192
  # ---------------------------------------------------------------------------
193
193
 
194
194
  start_chrome_native() {
@@ -1,14 +1,17 @@
1
1
  [Unit]
2
- Description=Maxy Edge (public port + VNC transport — independent of maxy-ui)
3
- # No ordering dependency on maxy-ui: the edge is the long-running front door.
4
- # maxy-ui.service declares Wants/After this unit so maxy-ui only starts once
5
- # the edge is listening, but this unit has no such reciprocal dependency.
2
+ Description=Edge service (public port + VNC transport — independent of the main brand service)
3
+ # No ordering dependency on the main brand service: the edge is the long-running
4
+ # front door. The main brand unit declares Wants/After this unit so it only
5
+ # starts once the edge is listening, but this unit has no such reciprocal
6
+ # dependency.
6
7
 
7
8
  [Service]
8
9
  Type=simple
9
10
  # ExecStartPre owns the VNC stack so an `npx -y @rubytech/create-maxy@latest`
10
- # run from the admin terminal can restart maxy-ui without taking Xtigervnc,
11
- # websockify, or the upgrade shell down with it. Task 647.
11
+ # run from the admin UI can restart the main brand service without taking
12
+ # Xtigervnc or websockify down with it. Task 647. Task 664 removed the ttyd
13
+ # transport — upgrades now run via systemd-run --user transient units that
14
+ # are peers of maxy-ui and survive its restart structurally.
12
15
  ExecStartPre=/bin/bash __INSTALL_DIR__/platform/scripts/vnc.sh start
13
16
  ExecStart=/usr/bin/node __INSTALL_DIR__/server/maxy-edge.js
14
17
  ExecStopPost=/bin/bash __INSTALL_DIR__/platform/scripts/vnc.sh stop