@rubytech/create-maxy 1.0.648 → 1.0.649

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 (142) hide show
  1. package/dist/index.js +65 -2
  2. package/package.json +1 -1
  3. package/payload/platform/plugins/docs/references/deployment.md +11 -0
  4. package/payload/platform/plugins/docs/references/getting-started.md +2 -0
  5. package/payload/platform/plugins/docs/references/memory-guide.md +2 -2
  6. package/payload/platform/plugins/docs/references/platform.md +6 -0
  7. package/payload/platform/plugins/docs/references/troubleshooting.md +16 -0
  8. package/payload/platform/plugins/memory/references/graph-primitives.md +5 -5
  9. package/payload/platform/templates/dotfiles/.tmux.conf +1 -0
  10. package/payload/platform/templates/systemd/maxy-ttyd.service +20 -0
  11. package/payload/server/public/assets/admin-BtjYSo0M.js +362 -0
  12. package/payload/server/public/assets/admin-kHJ-D0s7.css +1 -0
  13. package/payload/server/public/assets/{arc-DcrodP5U.js → arc-BMhgytDB.js} +1 -1
  14. package/payload/server/public/assets/architecture-YZFGNWBL-S9-oeq_x.js +1 -0
  15. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Cvo_8X6C.js → architectureDiagram-Q4EWVU46-BePoi8XC.js} +1 -1
  16. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-CEK06TEn.js → blockDiagram-DXYQGD6D-BkiwLTtq.js} +1 -1
  17. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-QjYUSwTU.js → c4Diagram-AHTNJAMY-bpjPj2Ln.js} +1 -1
  18. package/payload/server/public/assets/channel-D3U0_a1j.js +1 -0
  19. package/payload/server/public/assets/{chunk-2KRD3SAO-BBifNfFc.js → chunk-2KRD3SAO-ZcHg_orY.js} +1 -1
  20. package/payload/server/public/assets/{chunk-336JU56O-B-N_zWuf.js → chunk-336JU56O-BpATJiGl.js} +2 -2
  21. package/payload/server/public/assets/chunk-426QAEUC-Wz6Bpsil.js +1 -0
  22. package/payload/server/public/assets/{chunk-4BX2VUAB-CtDQKj9B.js → chunk-4BX2VUAB-zJekz2NU.js} +1 -1
  23. package/payload/server/public/assets/{chunk-4TB4RGXK-Dnu9n3p1.js → chunk-4TB4RGXK-CLXL19Wd.js} +1 -1
  24. package/payload/server/public/assets/{chunk-55IACEB6-DSLoJJSj.js → chunk-55IACEB6-CzqB8aoU.js} +1 -1
  25. package/payload/server/public/assets/{chunk-5FUZZQ4R-rx-IvMNE.js → chunk-5FUZZQ4R-BoTfWHuW.js} +1 -1
  26. package/payload/server/public/assets/{chunk-5PVQY5BW-B9w9AKCS.js → chunk-5PVQY5BW-RhIfPCRB.js} +1 -1
  27. package/payload/server/public/assets/{chunk-67CJDMHE-C1yEjtiu.js → chunk-67CJDMHE-mM1sFmlz.js} +1 -1
  28. package/payload/server/public/assets/{chunk-7N4EOEYR-C2f3zeVH.js → chunk-7N4EOEYR-GUck0jv1.js} +1 -1
  29. package/payload/server/public/assets/{chunk-AA7GKIK3-B_U-NsDK.js → chunk-AA7GKIK3-BYhfUc1V.js} +1 -1
  30. package/payload/server/public/assets/{chunk-BSJP7CBP-DM6_wafW.js → chunk-BSJP7CBP-CTsYuARh.js} +1 -1
  31. package/payload/server/public/assets/{chunk-CIAEETIT-DG7WkfNj.js → chunk-CIAEETIT-CGsGmUze.js} +1 -1
  32. package/payload/server/public/assets/{chunk-EDXVE4YY-aS3_rdwQ.js → chunk-EDXVE4YY-utELKGQK.js} +1 -1
  33. package/payload/server/public/assets/{chunk-ENJZ2VHE-r1I0uoCf.js → chunk-ENJZ2VHE-CNHjq5xK.js} +1 -1
  34. package/payload/server/public/assets/{chunk-FMBD7UC4-CTm3YRE5.js → chunk-FMBD7UC4-DaRrfk3s.js} +1 -1
  35. package/payload/server/public/assets/{chunk-FOC6F5B3-CAIttx3K.js → chunk-FOC6F5B3-BaeLcJVt.js} +1 -1
  36. package/payload/server/public/assets/{chunk-ICPOFSXX-DQFV4c1l.js → chunk-ICPOFSXX-Di63NBur.js} +2 -2
  37. package/payload/server/public/assets/{chunk-K5T4RW27-B2WCPQBa.js → chunk-K5T4RW27-CTTOezMH.js} +1 -1
  38. package/payload/server/public/assets/{chunk-KGLVRYIC-C6w2sUOF.js → chunk-KGLVRYIC-DCkohKP2.js} +1 -1
  39. package/payload/server/public/assets/{chunk-LIHQZDEY-BT1hcDTK.js → chunk-LIHQZDEY-osQO30uB.js} +1 -1
  40. package/payload/server/public/assets/{chunk-ORNJ4GCN-Brl32BSe.js → chunk-ORNJ4GCN-DoLajOOe.js} +1 -1
  41. package/payload/server/public/assets/{chunk-OYMX7WX6-BCO6n1CX.js → chunk-OYMX7WX6-BSPzqyxs.js} +1 -1
  42. package/payload/server/public/assets/chunk-QZHKN3VN-BAQp1OEl.js +1 -0
  43. package/payload/server/public/assets/{chunk-U2HBQHQK-BvgC0fpb.js → chunk-U2HBQHQK-BZnA7c4T.js} +1 -1
  44. package/payload/server/public/assets/{chunk-X2U36JSP-3yLdcqYf.js → chunk-X2U36JSP-DpQ2OA_c.js} +1 -1
  45. package/payload/server/public/assets/{chunk-XPW4576I-D876RWxK.js → chunk-XPW4576I-BccP1mlQ.js} +1 -1
  46. package/payload/server/public/assets/{chunk-YZCP3GAM-CiuA4hOC.js → chunk-YZCP3GAM-BAkNXu0G.js} +1 -1
  47. package/payload/server/public/assets/{chunk-ZZ45TVLE-COjEBPzv.js → chunk-ZZ45TVLE-DBSm41oP.js} +1 -1
  48. package/payload/server/public/assets/classDiagram-6PBFFD2Q-6EGGLDD_.js +1 -0
  49. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DfAV4tgE.js +1 -0
  50. package/payload/server/public/assets/clone-BoV8noAi.js +1 -0
  51. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-Dap0yL0o.js → cose-bilkent-S5V4N54A-Boeb8aWs.js} +1 -1
  52. package/payload/server/public/assets/{dagre-KV5264BT-DEia9UJj.js → dagre-KV5264BT-BkvWofSp.js} +1 -1
  53. package/payload/server/public/assets/{dagre-DBbjK-Cf.js → dagre-nvPNAunb.js} +1 -1
  54. package/payload/server/public/assets/data-gtcFdXVv.js +1 -0
  55. package/payload/server/public/assets/{diagram-5BDNPKRD-CWSP9MzJ.js → diagram-5BDNPKRD-CMEgyt4E.js} +1 -1
  56. package/payload/server/public/assets/{diagram-G4DWMVQ6-DWRsfitL.js → diagram-G4DWMVQ6-ChorrAF0.js} +1 -1
  57. package/payload/server/public/assets/{diagram-MMDJMWI5-n-jyzS4D.js → diagram-MMDJMWI5-D_iD27po.js} +1 -1
  58. package/payload/server/public/assets/{diagram-TYMM5635-CLPTbfLq.js → diagram-TYMM5635-8qXI1ioG.js} +1 -1
  59. package/payload/server/public/assets/{dist-Tkw8EOuG.js → dist-CrzV1W3-.js} +1 -1
  60. package/payload/server/public/assets/{erDiagram-SMLLAGMA-CmPC9Cnc.js → erDiagram-SMLLAGMA-BFjtKDSB.js} +1 -1
  61. package/payload/server/public/assets/file-DRa7iPfT.js +1 -0
  62. package/payload/server/public/assets/{flatten-Db2kUB5j.js → flatten-ya0TqRLc.js} +1 -1
  63. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-DKMNmUbX.js → flowDiagram-DWJPFMVM-Bpd7IL9l.js} +1 -1
  64. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-C5-y3w-l.js → ganttDiagram-T4ZO3ILL-CwOozU85.js} +1 -1
  65. package/payload/server/public/assets/gitGraph-7Q5UKJZL-BOC4CldZ.js +1 -0
  66. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-D9hG5kTg.js → gitGraphDiagram-UUTBAWPF-CcPILiC9.js} +1 -1
  67. package/payload/server/public/assets/graph-ydtwufZX.js +49 -0
  68. package/payload/server/public/assets/{graphlib-StP6GUhM.js → graphlib-B_mcXEVr.js} +1 -1
  69. package/payload/server/public/assets/house-DEu5yOIQ.js +1 -0
  70. package/payload/server/public/assets/info-OMHHGYJF-BSCPTUIx.js +1 -0
  71. package/payload/server/public/assets/infoDiagram-42DDH7IO-T2sn--WJ.js +2 -0
  72. package/payload/server/public/assets/{isEmpty-CXH_nKTs.js → isEmpty-h-wRi_o9.js} +1 -1
  73. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A--K4KOS61.js → ishikawaDiagram-UXIWVN3A-DOP9-Q8H.js} +1 -1
  74. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DE-28YrW.js → journeyDiagram-VCZTEJTY-DGATg0WC.js} +1 -1
  75. package/payload/server/public/assets/{jsx-runtime-DwoXvzmf.js → jsx-runtime-BrB6Lw5Y.js} +1 -1
  76. package/payload/server/public/assets/{jsx-runtime-BQmd8XDE.css → jsx-runtime-C8kAju5f.css} +1 -1
  77. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-CxSHjau2.js → kanban-definition-6JOO6SKY-C5PigmKg.js} +1 -1
  78. package/payload/server/public/assets/{line-DbcqYIG0.js → line-DlKKhwkO.js} +1 -1
  79. package/payload/server/public/assets/{linear-DXHoZSN3.js → linear-DD4JiB1l.js} +1 -1
  80. package/payload/server/public/assets/{mermaid-parser.core-CNGUA13J.js → mermaid-parser.core-C8xGCa9p.js} +2 -2
  81. package/payload/server/public/assets/{mermaid.core-IQgx_upQ.js → mermaid.core-CCUSwZB_.js} +3 -3
  82. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-BT9Up6-C.js → mindmap-definition-QFDTVHPH-75k-IVhC.js} +1 -1
  83. package/payload/server/public/assets/{ordinal-CN3oz6oW.js → ordinal-Dwxksj1B.js} +1 -1
  84. package/payload/server/public/assets/packet-4T2RLAQJ-pBa_ZhNI.js +1 -0
  85. package/payload/server/public/assets/pie-ZZUOXDRM-BzYOyiMb.js +1 -0
  86. package/payload/server/public/assets/{pieDiagram-DEJITSTG-BuewQTi6.js → pieDiagram-DEJITSTG-DN5RsDwZ.js} +1 -1
  87. package/payload/server/public/assets/public-D0ymcICW.js +5 -0
  88. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-Cu8y2zQL.js → quadrantDiagram-34T5L4WZ-Sd9x6pNe.js} +1 -1
  89. package/payload/server/public/assets/radar-PYXPWWZC-CTVOaAq6.js +1 -0
  90. package/payload/server/public/assets/{reduce-SDh8_UdG.js → reduce-BUuWaDl2.js} +1 -1
  91. package/payload/server/public/assets/{requirementDiagram-MS252O5E-DiT9bo27.js → requirementDiagram-MS252O5E-BDgifYzj.js} +1 -1
  92. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-EkRnGTxM.js → sankeyDiagram-XADWPNL6-BX9VULNJ.js} +1 -1
  93. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BUiQA3SI.js → sequenceDiagram-FGHM5R23-z3vMxhgE.js} +1 -1
  94. package/payload/server/public/assets/share-2-Cnd_9DYU.js +1 -0
  95. package/payload/server/public/assets/{src-DQQCRlaQ.js → src-Bo15iQ7w.js} +1 -1
  96. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-Fij35Tic.js → stateDiagram-FHFEXIEX-DlP0hBxF.js} +1 -1
  97. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DSddQStC.js +1 -0
  98. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BMsyr7wU.js → timeline-definition-GMOUNBTQ-DwQbhKCo.js} +1 -1
  99. package/payload/server/public/assets/treeView-SZITEDCU-OTnF4Qzw.js +1 -0
  100. package/payload/server/public/assets/treemap-W4RFUUIX-DlIRmHFb.js +1 -0
  101. package/payload/server/public/assets/{useVoiceRecorder-C0Fvv_Bt.js → useVoiceRecorder-CFIpzGaB.js} +3 -3
  102. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-6fegYFB3.js → vennDiagram-DHZGUBPP-WTqmZWWa.js} +1 -1
  103. package/payload/server/public/assets/wardley-RL74JXVD-DwMXAC4U.js +1 -0
  104. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BtJ_B35h.js → wardleyDiagram-NUSXRM2D-BUY50x5T.js} +1 -1
  105. package/payload/server/public/assets/x-DitohdYO.js +1 -0
  106. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-DJ20B4NY.js → xychartDiagram-5P7HB3ND-Btdq-fDj.js} +1 -1
  107. package/payload/server/public/data.html +7 -5
  108. package/payload/server/public/graph.html +19 -0
  109. package/payload/server/public/index.html +10 -7
  110. package/payload/server/public/public.html +6 -6
  111. package/payload/server/server.js +866 -733
  112. package/payload/server/public/assets/admin-uiqCo17I.js +0 -352
  113. package/payload/server/public/assets/architecture-YZFGNWBL-C38eyeNF.js +0 -1
  114. package/payload/server/public/assets/channel-D0dIwjlN.js +0 -1
  115. package/payload/server/public/assets/chunk-426QAEUC-C8oXXITm.js +0 -1
  116. package/payload/server/public/assets/chunk-QZHKN3VN-BE_lylks.js +0 -1
  117. package/payload/server/public/assets/classDiagram-6PBFFD2Q-DH37CWIF.js +0 -1
  118. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DNJ7bv8r.js +0 -1
  119. package/payload/server/public/assets/clone-rrGuX3ZR.js +0 -1
  120. package/payload/server/public/assets/data-D8kol1ed.js +0 -1
  121. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CCjgA3FG.js +0 -1
  122. package/payload/server/public/assets/info-OMHHGYJF-B65K6dQJ.js +0 -1
  123. package/payload/server/public/assets/infoDiagram-42DDH7IO-DUJfTICr.js +0 -2
  124. package/payload/server/public/assets/packet-4T2RLAQJ-fp5ishAK.js +0 -1
  125. package/payload/server/public/assets/pie-ZZUOXDRM-Bc3VMuuU.js +0 -1
  126. package/payload/server/public/assets/public-CWuf8cLU.js +0 -5
  127. package/payload/server/public/assets/radar-PYXPWWZC-D9jy5QAa.js +0 -1
  128. package/payload/server/public/assets/share-2-wGga_ldi.js +0 -1
  129. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DQzhSd8K.js +0 -1
  130. package/payload/server/public/assets/treeView-SZITEDCU-CHyRL9e4.js +0 -1
  131. package/payload/server/public/assets/treemap-W4RFUUIX-DpQ_FOO6.js +0 -1
  132. package/payload/server/public/assets/wardley-RL74JXVD-CWBIAatW.js +0 -1
  133. /package/payload/server/public/assets/{_baseFor-D71p92tl.js → _baseFor-Dn4GSmI6.js} +0 -0
  134. /package/payload/server/public/assets/{array-Bs_owIvv.js → array-DJN9YAVf.js} +0 -0
  135. /package/payload/server/public/assets/{chunk-lgnzUk6H.js → chunk-DD-I1_y5.js} +0 -0
  136. /package/payload/server/public/assets/{cytoscape.esm-DLG5qhup.js → cytoscape.esm-BcJTl1re.js} +0 -0
  137. /package/payload/server/public/assets/{defaultLocale-Du_2bjyv.js → defaultLocale-B4F_XsBB.js} +0 -0
  138. /package/payload/server/public/assets/{init-BYLBkHX_.js → init-DX0Y1qU4.js} +0 -0
  139. /package/payload/server/public/assets/{katex-lkho_UhZ.js → katex-CjHJ1D7d.js} +0 -0
  140. /package/payload/server/public/assets/{path-BO54iFkf.js → path-7vUsG-o2.js} +0 -0
  141. /package/payload/server/public/assets/{preload-helper-DWTEM3RW.js → preload-helper-qlgyTAkD.js} +0 -0
  142. /package/payload/server/public/assets/{rough.esm-BCiZEpQC.js → rough.esm-NLRoWnq-.js} +0 -0
package/dist/index.js CHANGED
@@ -208,7 +208,7 @@ function canSudo() {
208
208
  // ---------------------------------------------------------------------------
209
209
  // Installation steps
210
210
  // ---------------------------------------------------------------------------
211
- const TOTAL = "11";
211
+ const TOTAL = "12";
212
212
  function installSystemDeps() {
213
213
  log("1", TOTAL, "System dependencies and network...");
214
214
  if (!isLinux()) {
@@ -220,6 +220,11 @@ function installSystemDeps() {
220
220
  shell("apt-get", ["install", "-y", "curl", "git", "unzip", "jq", "avahi-daemon", "avahi-utils", "poppler-utils", "ffmpeg"], { sudo: true });
221
221
  shell("apt-get", ["install", "-y", "tigervnc-standalone-server", "python3-websockify", "novnc", "xdg-utils", "chromium"], { sudo: true });
222
222
  shell("apt-get", ["install", "-y", "hostapd", "dnsmasq"], { sudo: true });
223
+ // ttyd + tmux power the admin terminal surface (Task 591) — ttyd serves a
224
+ // WebSocket PTY on 127.0.0.1:7681, tmux provides the persistent named
225
+ // session that outlives admin-server restarts. Both are in Debian/Raspbian
226
+ // repos; no third-party source needed.
227
+ shell("apt-get", ["install", "-y", "ttyd", "tmux"], { sudo: true });
223
228
  }
224
229
  else {
225
230
  console.log(" Skipping apt-get (sudo unavailable non-interactively — deps assumed present from prior install)");
@@ -1499,8 +1504,65 @@ function installCrons() {
1499
1504
  logFile(` crontab write failed: ${write.stderr}`);
1500
1505
  }
1501
1506
  }
1507
+ function installTerminalService() {
1508
+ log("11", TOTAL, "Installing admin terminal service (ttyd + tmux)...");
1509
+ if (!isLinux()) {
1510
+ console.log(" Skipping admin terminal service (not Linux). On macOS start manually:");
1511
+ console.log(" brew install ttyd tmux && ttyd -p 7681 -i 127.0.0.1 -W tmux new-session -A -s maxy-pty");
1512
+ return;
1513
+ }
1514
+ // Default ~/.tmux.conf — only written if the operator doesn't already have
1515
+ // one. `history-limit 50000` is load-bearing: a closed-tab + reopen during
1516
+ // an upgrade must show every line the operator missed in scrollback.
1517
+ const homeDir = process.env.HOME ?? "/root";
1518
+ const tmuxConfDest = resolve(homeDir, ".tmux.conf");
1519
+ if (!existsSync(tmuxConfDest)) {
1520
+ const tmuxConfTemplate = resolve(INSTALL_DIR, "platform/templates/dotfiles/.tmux.conf");
1521
+ try {
1522
+ if (existsSync(tmuxConfTemplate)) {
1523
+ writeFileSync(tmuxConfDest, readFileSync(tmuxConfTemplate, "utf-8"));
1524
+ console.log(` Wrote default ~/.tmux.conf (history-limit 50000)`);
1525
+ }
1526
+ else {
1527
+ // Fallback if the template was not in the payload for any reason —
1528
+ // preserves the load-bearing scrollback-size guarantee.
1529
+ writeFileSync(tmuxConfDest, "set -g history-limit 50000\n");
1530
+ console.log(` Wrote default ~/.tmux.conf (fallback — template missing)`);
1531
+ }
1532
+ }
1533
+ catch (err) {
1534
+ console.error(` WARNING: failed to write ~/.tmux.conf: ${err instanceof Error ? err.message : String(err)}`);
1535
+ }
1536
+ }
1537
+ // Install and enable the maxy-ttyd.service --user unit. Independent of
1538
+ // BRAND.serviceName — a single device runs one admin terminal regardless of
1539
+ // brand, because the unit binds to 127.0.0.1:7681 which only one process can
1540
+ // hold anyway. On a multi-brand device, the first brand's install writes the
1541
+ // unit and every subsequent install is a no-op (idempotent overwrite).
1542
+ const systemdUserDir = resolve(homeDir, ".config/systemd/user");
1543
+ mkdirSync(systemdUserDir, { recursive: true });
1544
+ const ttydUnitTemplate = resolve(INSTALL_DIR, "platform/templates/systemd/maxy-ttyd.service");
1545
+ const ttydUnitDest = join(systemdUserDir, "maxy-ttyd.service");
1546
+ try {
1547
+ if (existsSync(ttydUnitTemplate)) {
1548
+ writeFileSync(ttydUnitDest, readFileSync(ttydUnitTemplate, "utf-8"));
1549
+ }
1550
+ else {
1551
+ console.error(` WARNING: maxy-ttyd.service template missing at ${ttydUnitTemplate} — admin terminal will not work`);
1552
+ return;
1553
+ }
1554
+ }
1555
+ catch (err) {
1556
+ console.error(` WARNING: failed to write ${ttydUnitDest}: ${err instanceof Error ? err.message : String(err)}`);
1557
+ return;
1558
+ }
1559
+ spawnSync("systemctl", ["--user", "daemon-reload"], { stdio: "inherit" });
1560
+ spawnSync("systemctl", ["--user", "enable", "maxy-ttyd"], { stdio: "inherit" });
1561
+ spawnSync("systemctl", ["--user", "restart", "maxy-ttyd"], { stdio: "inherit" });
1562
+ console.log(" maxy-ttyd.service enabled — admin terminal available on 127.0.0.1:7681");
1563
+ }
1502
1564
  function installService() {
1503
- log("11", TOTAL, `Starting ${BRAND.productName}...`);
1565
+ log("12", TOTAL, `Starting ${BRAND.productName}...`);
1504
1566
  if (!isLinux()) {
1505
1567
  console.log(" Skipping systemd service (not Linux). Start manually with:");
1506
1568
  console.log(` cd ${INSTALL_DIR}/server && MAXY_PLATFORM_ROOT=${INSTALL_DIR}/platform PORT=${PORT} HOSTNAME=0.0.0.0 KEEP_ALIVE_TIMEOUT=61000 node --require ./server-init.cjs server.js`);
@@ -2042,6 +2104,7 @@ try {
2042
2104
  setupVncViewer();
2043
2105
  setupAccount();
2044
2106
  installTunnelScripts(); // ~/setup-tunnel.sh, ~/reset-tunnel.sh — the SKILL contract
2107
+ installTerminalService(); // Task 591: ttyd + tmux systemd --user unit (sibling of maxy-ui)
2045
2108
  installService();
2046
2109
  console.log("");
2047
2110
  console.log("================================================================");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy",
3
- "version": "1.0.648",
3
+ "version": "1.0.649",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy": "./dist/index.js"
@@ -66,6 +66,15 @@ The logs will show which service failed to start and why. Common causes:
66
66
  - **Port 19200 already in use** — check for another process: `lsof -i :19200`
67
67
  - **Claude OAuth expired** — the next admin session will prompt you to re-authenticate
68
68
 
69
+ ## Systemd units on each device
70
+
71
+ Each Maxy device runs two independent `--user` systemd units:
72
+
73
+ - `maxy-ui.service` — the admin + public HTTP server (default port 19200). Restarted by the upgrade flow; short downtime is expected during steps 8→12 of an upgrade.
74
+ - `maxy-ttyd.service` — a persistent PTY over WebSocket on `127.0.0.1:7681` attached to a tmux session named `maxy-pty`. Independent of `maxy-ui` — restarting the UI does not interrupt shell work, which is exactly the property the upgrade flow relies on to survive its own admin-server restart.
75
+
76
+ If the Software Update window's terminal goes blank and does not reconnect, `sudo systemctl --user status maxy-ttyd` is the first thing to check. Restarting the unit (`sudo systemctl --user restart maxy-ttyd`) is safe: the tmux session survives because `tmux new-session -A -s maxy-pty` is idempotent.
77
+
69
78
  ## Upgrading
70
79
 
71
80
  To upgrade Maxy to the latest version, ask Maxy: "Upgrade Maxy." The platform checks the current device identity (hostname and port via `system-status`), then re-runs the installer with explicit `--hostname` and `--port` flags to preserve them across the upgrade.
@@ -76,4 +85,6 @@ The docs plugin (this plugin) is upgraded in the same step — you always have t
76
85
 
77
86
  Maxy checks for new releases on every admin session start — whenever you log in, reload the page, or return to the admin chat. When a newer version is available, the Software Update window opens automatically showing your current and the latest version, with a one-click Upgrade button. Dismissing the window (click outside or the close button) defers the alert until your next login or reload; no alert is shown when you are already on the latest version.
78
87
 
88
+ The upgrade runs inside a live terminal embedded in the Software Update window — you see each installation step stream as it happens, and any password prompts from `sudo` appear directly in the terminal for you to answer. Closing the window does not cancel the upgrade; re-opening it reattaches to the same shell so you can see what happened while disconnected.
89
+
79
90
  The header menu's version indicator still reflects real-time status: a green dot means you are up to date, and an accent-coloured dot means an upgrade is available. Opening the menu refreshes the version check, so a long-lived session can still surface an upgrade that became available after login without reloading the page.
@@ -40,6 +40,8 @@ When you first open the admin interface:
40
40
 
41
41
  This setup is resumable — if you close the browser mid-setup, Maxy picks up where you left off next time.
42
42
 
43
+ After install, a live admin terminal is available inside the Software Update window — your Pi's shell, accessible through the admin UI, for upgrades and any other shell work without needing to SSH.
44
+
43
45
  ## How to Use Maxy
44
46
 
45
47
  Conversation is the only interface. Type or speak what you need:
@@ -84,9 +84,9 @@ Ask naturally:
84
84
 
85
85
  Maxy answers relational questions — "list all my people", "how many tasks do I have", "find the person with email X", "show me the 20 most recently created nodes" — via direct read-only Cypher against your Neo4j. This is faster and more precise than semantic search when the question is "the exact set where", not "things similar to".
86
86
 
87
- You can also open the Neo4j Browser at any time from the burger menu → **Graph**. Sign in with your Neo4j username (`neo4j`) and password (stored in `config/.neo4j-password` on the device). Run `MATCH (n) RETURN n LIMIT 25` for a visual overview of your graph, or write your own Cypher for ad-hoc exploration.
87
+ You can also open a visual view of your graph at any time from the burger menu → **Graph**. It renders up to 200 of your most recently updated nodes as a force-directed map, coloured by label (Person, Service, KnowledgeDocument, Task, …). Click a node to see its properties; type in the search box to highlight matches.
88
88
 
89
- The browser reaches only your own brand's Neo4j — a Maxy device and a Real Agent device share no graph state even when on the same laptop.
89
+ The page reads only your own brand's Neo4j — a Maxy device and a Real Agent device share no graph state even when on the same laptop. No credentials are required; the view inherits your admin session.
90
90
 
91
91
  ## Privacy
92
92
 
@@ -62,6 +62,12 @@ 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
66
+
67
+ The admin UI includes a live terminal surface that opens a real shell on your Pi in the browser, reached via the Software Update modal. Under the hood it's a WebSocket (`/admin/terminal/ws`) attached through `@xterm/xterm` to `ttyd` on `127.0.0.1:7681`, backed by a persistent tmux session named `maxy-pty`.
68
+
69
+ The tmux session outlives admin-server restarts — running an upgrade inside this terminal means you see the live shell output continuously, even through the admin server's own restart mid-upgrade. Closing the browser tab does not kill the running work; re-opening the Software Update window reattaches to the same session and scrollback shows everything that happened in the meantime. Password-protected `sudo` prompts appear natively inside the terminal, and the password you type never leaves the Pi — the admin-server proxy is a raw byte pipe that never inspects frame payloads.
70
+
65
71
  ## AI Content Provenance
66
72
 
67
73
  When your public agent sends a message to someone — via email, WhatsApp, Telegram, or SMS — the platform automatically includes a brief disclosure that the content was generated by AI. This is transparent and cannot be turned off.
@@ -90,3 +90,19 @@ If the tunnel won't reconnect, re-run the Cloudflare setup: ask Maxy "Reconnect
90
90
  If the initial Cloudflare login fails during setup, Maxy will fall back to asking you for a connection key. You can create one in the Cloudflare dashboard (Maxy will guide you through this in the browser).
91
91
 
92
92
  **If you switched Cloudflare accounts or are stuck on the wrong one:** ask Maxy "Reset my Cloudflare login and start over." This is a clean reset — Maxy clears every stored credential, then opens a fresh browser sign-in. The next sign-in binds to whichever Cloudflare account you choose, with no risk of the previous account's stored credentials silently coming back.
93
+
94
+ ---
95
+
96
+ ## Admin Terminal Stuck Disconnected After Upgrade
97
+
98
+ **Symptom:** The Software Update window's terminal goes blank, says "server restart detected — reconnecting…" and never comes back, or the window sits empty after you open it.
99
+
100
+ **Check:** `sudo systemctl --user status maxy-ttyd` — the unit should be `active (running)`. If it is, the admin-server proxy should reattach automatically within a few seconds.
101
+
102
+ **Fix:** Restart the unit:
103
+
104
+ ```bash
105
+ sudo systemctl --user restart maxy-ttyd
106
+ ```
107
+
108
+ This is safe — the tmux session survives the ttyd restart because `tmux new-session -A -s maxy-pty` is idempotent. Any upgrade or other shell command still running inside the session continues uninterrupted; ttyd simply re-attaches to it. If the session itself is wedged, you can kill it explicitly with `tmux kill-session -t maxy-pty` and the next attach will create a fresh one.
@@ -17,11 +17,11 @@ filter in the query.
17
17
 
18
18
  For visual exploration ("can I see this graphically?", "show me the graph"),
19
19
  tell the user to open the **Graph** menu item in the burger menu — it opens
20
- Neo4j Browser pointed at their own brand's graph. Do not build ad-hoc HTML
21
- visualizations, do not start a static file server, do not `Write` an
22
- `.html` file and navigate Playwright to it. The one-sentence reply
23
- ("Open the Graph menu item in the top-right — it opens a visual browser
24
- for your graph") is the correct answer.
20
+ a Maxy-native force-directed view of their own brand's subgraph (Task 587).
21
+ Do not build ad-hoc HTML visualizations, do not start a static file server,
22
+ do not `Write` an `.html` file and navigate Playwright to it. The one-sentence
23
+ reply ("Open the Graph menu item in the top-right — it opens a visual view
24
+ of your graph") is the correct answer.
25
25
 
26
26
  ## When the graph tools are absent
27
27
 
@@ -0,0 +1 @@
1
+ set -g history-limit 50000
@@ -0,0 +1,20 @@
1
+ [Unit]
2
+ Description=Maxy admin terminal (ttyd + tmux) — persistent PTY for admin UI
3
+ After=default.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ # -p 7681 listen on 127.0.0.1:7681 (same-origin proxy in maxy-ui binds to it)
8
+ # -i 127.0.0.1 reject non-loopback connections at the ttyd layer as well
9
+ # -W writable (allow client → server input bytes)
10
+ # tmux new-session -A -s maxy-pty attach if session exists, create otherwise.
11
+ # Lifetime = user session / device lifetime. Outlives maxy-ui restarts because
12
+ # this unit has no After=maxy-ui.service and no Requires= — independent.
13
+ # -x 200 -y 50 initial geometry; xterm.js fit-addon drives runtime resizes.
14
+ ExecStart=/usr/bin/ttyd -p 7681 -i 127.0.0.1 -W tmux new-session -A -s maxy-pty -x 200 -y 50
15
+ Environment=TERM=xterm-256color
16
+ Restart=always
17
+ RestartSec=2
18
+
19
+ [Install]
20
+ WantedBy=default.target