@puddle-code/cli 0.2.3 → 0.2.6

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 (138) hide show
  1. package/CHANGELOG.md +2 -13
  2. package/README.md +33 -23
  3. package/dist/host-control.mjs +40 -2
  4. package/dist/index.js +541 -313
  5. package/dist/install-cli.sh +167 -0
  6. package/dist/install.sh +7 -10
  7. package/dist/public/assets/{App-JZgRWo4t.js → App-CzuHShdO.js} +2 -2
  8. package/dist/public/assets/{Dashboard-DNWLZwxT.js → Dashboard-B5qWtmwb.js} +1 -1
  9. package/dist/public/assets/{EditorTabClose-CdpMpKYq.js → EditorTabClose-uxuNJdgx.js} +1 -1
  10. package/dist/public/assets/FindWidget-lUpiYZJG.js +1 -0
  11. package/dist/public/assets/{LazyTerminal-DVeI2Lkl.js → LazyTerminal-BYbPpGEI.js} +2 -2
  12. package/dist/public/assets/{ModelRefcount-ALfiNB9K.js → ModelRefcount-N0Xh_Y-_.js} +1 -1
  13. package/dist/public/assets/{NewProjectDialog-RHBHLIQe.js → NewProjectDialog-D3bNK3u_.js} +1 -1
  14. package/dist/public/assets/PaneEditorBody-DrSiMzrp.js +553 -0
  15. package/dist/public/assets/{PdfViewer-DZrh-S3Z.js → PdfViewer-BhqrWfmb.js} +2 -2
  16. package/dist/public/assets/{SettingsDialog-D-yMKqY9.js → SettingsDialog-CamnF91I.js} +2 -2
  17. package/dist/public/assets/Terminal-Ds17sCF_.js +60 -0
  18. package/dist/public/assets/Workspace-B6mgQyIM.css +1 -0
  19. package/dist/public/assets/{Workspace-DhFU_Ltc.js → Workspace-BmtA0kYQ.js} +6 -6
  20. package/dist/public/assets/{abnfDiagram-VCTEODGH-Bb_QGl6J.js → abnfDiagram-VCTEODGH-B4ZtDUXi.js} +1 -1
  21. package/dist/public/assets/architecture-7GRP2DOG-D0iH6Lxl.js +1 -0
  22. package/dist/public/assets/{architectureDiagram-5GKGNRK7-CF6YHpo7.js → architectureDiagram-5GKGNRK7-Cyzuyzwl.js} +1 -1
  23. package/dist/public/assets/{blockDiagram-I7D4REHJ-DgUouS8v.js → blockDiagram-I7D4REHJ-BN00JnNl.js} +1 -1
  24. package/dist/public/assets/{buffer-store-DcARHjQ8.js → buffer-store--4yU4YqM.js} +2 -2
  25. package/dist/public/assets/{button-CyO-gAMJ.js → button-DehrlYw7.js} +1 -1
  26. package/dist/public/assets/{c4Diagram-7LVT6UL2-CFhvq4-y.js → c4Diagram-7LVT6UL2-DpUKodBy.js} +1 -1
  27. package/dist/public/assets/channel-DT2izo70.js +1 -0
  28. package/dist/public/assets/{chunk-2E4U76K2-CskNiADZ.js → chunk-2E4U76K2-BksaqXZU.js} +1 -1
  29. package/dist/public/assets/{chunk-4HAMMTFA-DY74ei7y.js → chunk-4HAMMTFA-D01k6w0A.js} +1 -1
  30. package/dist/public/assets/{chunk-75Z2AOVW-sHPItT4L.js → chunk-75Z2AOVW-DJJjslyX.js} +1 -1
  31. package/dist/public/assets/{chunk-CLGD4ZFX-BbZdl00J.js → chunk-CLGD4ZFX-CX1B9i6H.js} +1 -1
  32. package/dist/public/assets/{chunk-DU6HZSFF-BZvHUJoN.js → chunk-DU6HZSFF-Bx2ELCn-.js} +1 -1
  33. package/dist/public/assets/{chunk-F27PBJKO-C-FJqBSD.js → chunk-F27PBJKO-CCDhODx8.js} +1 -1
  34. package/dist/public/assets/{chunk-GMAD6QVW-DPkzF1Ic.js → chunk-GMAD6QVW-C1evXXZi.js} +1 -1
  35. package/dist/public/assets/{chunk-GVQU2GXP-Batc2xZS.js → chunk-GVQU2GXP-C1iphgLK.js} +1 -1
  36. package/dist/public/assets/{chunk-IMKFNOWR-CAMx72vu.js → chunk-IMKFNOWR-5wMdkmsQ.js} +1 -1
  37. package/dist/public/assets/{chunk-L3NEJ4N5-CuIGdGy-.js → chunk-L3NEJ4N5-B-aXfMpF.js} +1 -1
  38. package/dist/public/assets/{chunk-OSK3NFVY-uNp8Mp7C.js → chunk-OSK3NFVY-Bm2MaFOc.js} +1 -1
  39. package/dist/public/assets/{chunk-P2QGCYS3-CoRPhFtM.js → chunk-P2QGCYS3-H02JaAun.js} +1 -1
  40. package/dist/public/assets/{chunk-POPQ4Y6H-DMOCBqAw.js → chunk-POPQ4Y6H-Dmm46Beg.js} +1 -1
  41. package/dist/public/assets/{chunk-PWAF6VOD-DOQkLdyp.js → chunk-PWAF6VOD-CRt8Ete5.js} +1 -1
  42. package/dist/public/assets/{chunk-SHT3W25Y-BJJe_uau.js → chunk-SHT3W25Y-w4aNK54y.js} +1 -1
  43. package/dist/public/assets/{chunk-SVP7TREG-D5B1jrjj.js → chunk-SVP7TREG-Cl3QpMDs.js} +1 -1
  44. package/dist/public/assets/{chunk-TICWLB2K-C9NafHGC.js → chunk-TICWLB2K-BpBbot9h.js} +1 -1
  45. package/dist/public/assets/{chunk-TLUHSLCS-Ctl_RxEM.js → chunk-TLUHSLCS-BOnIB6P6.js} +2 -2
  46. package/dist/public/assets/classDiagram-ZZMXUADV-BSshJUxJ.js +1 -0
  47. package/dist/public/assets/classDiagram-v2-VYDZK3BY-BSshJUxJ.js +1 -0
  48. package/dist/public/assets/{context-menu-BuiHQTu6.js → context-menu-BT88Vgia.js} +1 -1
  49. package/dist/public/assets/{cssMode-DozYXR6g.js → cssMode-gXT_K4po.js} +1 -1
  50. package/dist/public/assets/{cynefin-OW5HDTMX-gj0lEe4i.js → cynefin-OW5HDTMX-CJakxaH8.js} +1 -1
  51. package/dist/public/assets/{cynefinDiagram-5FMLGOSQ-lYCffbhY.js → cynefinDiagram-5FMLGOSQ-BJ_fVnC9.js} +1 -1
  52. package/dist/public/assets/{dagre-GXQ25YYZ-DyYVAAw7.js → dagre-GXQ25YYZ-CjflcbuS.js} +1 -1
  53. package/dist/public/assets/{diagram-S7CK7UJ4-Dop5OEsZ.js → diagram-S7CK7UJ4-g8pKIWrY.js} +1 -1
  54. package/dist/public/assets/{diagram-UQ7AKVKN-B5qxPK0m.js → diagram-UQ7AKVKN-Dm5Pg4rY.js} +1 -1
  55. package/dist/public/assets/{diagram-VSXAHHWV-zvsxaxBC.js → diagram-VSXAHHWV-DV5CVAXg.js} +1 -1
  56. package/dist/public/assets/{diagram-VX7I27RA-S7nRhoRV.js → diagram-VX7I27RA-Be9qCk-h.js} +1 -1
  57. package/dist/public/assets/{diagram-Z3DM3KII-C_jkP2wb.js → diagram-Z3DM3KII-C3-xDrxs.js} +1 -1
  58. package/dist/public/assets/{dialog-D6I1fiX4.js → dialog-CAMTxigV.js} +1 -1
  59. package/dist/public/assets/{disclosure-Dn2Pws0i.js → disclosure-DvM7-z38.js} +1 -1
  60. package/dist/public/assets/dist-3tmIo7Ja.js +1 -0
  61. package/dist/public/assets/{dist-Dt0LZb5E.js → dist-sLs_LTiG.js} +1 -1
  62. package/dist/public/assets/{ebnfDiagram-PWID7BFC-B1OmWQdM.js → ebnfDiagram-PWID7BFC-Bq92n7k-.js} +1 -1
  63. package/dist/public/assets/{erDiagram-RLTQ6QDP-DJKky3Wx.js → erDiagram-RLTQ6QDP-C5I2bKnS.js} +1 -1
  64. package/dist/public/assets/eventmodeling-NTZA5JFV-CWxfOZuS.js +1 -0
  65. package/dist/public/assets/flowDiagram-HODETNUW-ddOOBXlS.js +1 -0
  66. package/dist/public/assets/{ganttDiagram-EL5Y4UJY-qEYH72Jx.js → ganttDiagram-EL5Y4UJY-qUaBgbbK.js} +1 -1
  67. package/dist/public/assets/{gitGraph-4MIJSDKK-DlVqGPr_.js → gitGraph-4MIJSDKK-CUfoq3Sa.js} +1 -1
  68. package/dist/public/assets/{gitGraphDiagram-WWUBYQGX-DjfCMlWr.js → gitGraphDiagram-WWUBYQGX-kj34Cchu.js} +1 -1
  69. package/dist/public/assets/{hotkeys-Bx0QQoOi.js → hotkeys-DbIEec2f.js} +1 -1
  70. package/dist/public/assets/{htmlMode-DlKAkkNW.js → htmlMode-C_uC6TDH.js} +1 -1
  71. package/dist/public/assets/index-BLx1AR0-.js +82 -0
  72. package/dist/public/assets/index-uKreLbru.css +2 -0
  73. package/dist/public/assets/{info-A6RAGUB7-CH2cc1Sk.js → info-A6RAGUB7-C938EzS-.js} +1 -1
  74. package/dist/public/assets/{infoDiagram-27XIBGKW-QLQ5mJz6.js → infoDiagram-27XIBGKW-BoTxIjdn.js} +1 -1
  75. package/dist/public/assets/input-DXYRmAFr.js +1 -0
  76. package/dist/public/assets/{ishikawaDiagram-5VMMS53U-Dgd8STMm.js → ishikawaDiagram-5VMMS53U-j98L6THV.js} +1 -1
  77. package/dist/public/assets/{journeyDiagram-3NMN7TZE-BaIBwMwN.js → journeyDiagram-3NMN7TZE-DI-XCC2F.js} +1 -1
  78. package/dist/public/assets/{jsonMode-B-xhmxpv.js → jsonMode-BQ3590Ds.js} +1 -1
  79. package/dist/public/assets/{kanban-definition-UXKFOSKX-DUwkSFm5.js → kanban-definition-UXKFOSKX-BCTvFJTJ.js} +1 -1
  80. package/dist/public/assets/{line-DBd--km9.js → line-hE2Okp1W.js} +1 -1
  81. package/dist/public/assets/{media-refresh-store-C2PF6Nl9.js → media-refresh-store-CxqhHl8x.js} +1 -1
  82. package/dist/public/assets/{mermaid-parser.core-CH9r0Plq.js → mermaid-parser.core-n0Wb6T7Q.js} +3 -3
  83. package/dist/public/assets/{mermaid.core-Dx4uf1Og.js → mermaid.core-Cb0bw4D8.js} +3 -3
  84. package/dist/public/assets/{mindmap-definition-YA3MSWOX-DFlzr0Rk.js → mindmap-definition-YA3MSWOX-92LM1OuK.js} +1 -1
  85. package/dist/public/assets/{notification-permission-BJ5Ee1QS.js → notification-permission-CG2r3Oi8.js} +1 -1
  86. package/dist/public/assets/{packet-AYTQ26CC-BoGgl5A0.js → packet-AYTQ26CC-_HBkwHYp.js} +1 -1
  87. package/dist/public/assets/{pdf-CIIeLqAE.js → pdf-DABk-fGs.js} +1 -1
  88. package/dist/public/assets/{pegDiagram-XKGWAZYB-dBubzdqe.js → pegDiagram-XKGWAZYB-B-fG_WHS.js} +1 -1
  89. package/dist/public/assets/{pie-WAS4IAKB-C8Ujmmnq.js → pie-WAS4IAKB-ByxJto7v.js} +1 -1
  90. package/dist/public/assets/{pieDiagram-E7YTZNPT-BarO3dDM.js → pieDiagram-E7YTZNPT-Ci8ZSq4L.js} +1 -1
  91. package/dist/public/assets/{project-abbrev-BlBz9tcM.js → project-abbrev-BU2DBpdq.js} +1 -1
  92. package/dist/public/assets/{quadrantDiagram-AXDQQJYC-Bq7mziYZ.js → quadrantDiagram-AXDQQJYC-B97Yoxpb.js} +1 -1
  93. package/dist/public/assets/{radar-RG4KPBEZ-CSOiAaDJ.js → radar-RG4KPBEZ-BT2qdAqW.js} +1 -1
  94. package/dist/public/assets/{railroad-74A4TZTK-B72WpbJE.js → railroad-74A4TZTK-Buny6l3B.js} +1 -1
  95. package/dist/public/assets/railroad-abnf-HS5TGJTU-C_aUf3vj.js +1 -0
  96. package/dist/public/assets/railroad-ebnf-LZEXJU2U-BGUVD_Qq.js +1 -0
  97. package/dist/public/assets/railroad-peg-WCYAUIDC-CGdTjBGv.js +1 -0
  98. package/dist/public/assets/{railroadDiagram-O6MQD6OU-CdpFpJTq.js → railroadDiagram-O6MQD6OU-BktpI6J7.js} +1 -1
  99. package/dist/public/assets/{requirementDiagram-BXWQKSXE-D5gAf9X3.js → requirementDiagram-BXWQKSXE-DYy_YKmd.js} +1 -1
  100. package/dist/public/assets/{sankeyDiagram-P5KCCOFB-CWGxwWQO.js → sankeyDiagram-P5KCCOFB-BeKH_sFV.js} +1 -1
  101. package/dist/public/assets/{sequenceDiagram-WJ2MYXX4-D4OU6YFv.js → sequenceDiagram-WJ2MYXX4-DD8okFGM.js} +1 -1
  102. package/dist/public/assets/{stateDiagram-D77RDMKH-DL34KHS6.js → stateDiagram-D77RDMKH-Bfk3E3Oa.js} +1 -1
  103. package/dist/public/assets/stateDiagram-v2-MP3YSRHH-DCg8-XDy.js +1 -0
  104. package/dist/public/assets/{swimlanes-42K2YHIH-ClnyergN.js → swimlanes-42K2YHIH-OVNrzhfn.js} +1 -1
  105. package/dist/public/assets/swimlanesDiagram-VR7AAH4N-DAqvbP32.js +8 -0
  106. package/dist/public/assets/{switch-JLAneJz1.js → switch-CN9NW-du.js} +1 -1
  107. package/dist/public/assets/{timeline-definition-24CTP7MA-Bouu1PMd.js → timeline-definition-24CTP7MA-C78a8EdU.js} +1 -1
  108. package/dist/public/assets/{treeView-Q6P3EWNA-OLbwx3G_.js → treeView-Q6P3EWNA-Cl5tCoga.js} +1 -1
  109. package/dist/public/assets/{treemap-WGGIJYW6-BWtOLy1c.js → treemap-WGGIJYW6-4YVcjSz9.js} +1 -1
  110. package/dist/public/assets/{tsMode-BChcsbnx.js → tsMode-CmGZ7MCT.js} +1 -1
  111. package/dist/public/assets/{use-ui-state-xRIsbDTY.js → use-ui-state-CzR7YpWb.js} +1 -1
  112. package/dist/public/assets/{vennDiagram-4TSXK5OY-B7Iv-Yti.js → vennDiagram-4TSXK5OY-Lih9MwBs.js} +1 -1
  113. package/dist/public/assets/{wardley-WFR3VGLG-bREi8xGw.js → wardley-WFR3VGLG-CcU7I6bt.js} +1 -1
  114. package/dist/public/assets/{wardleyDiagram-VM6X3IG4-BCZ7iNOW.js → wardleyDiagram-VM6X3IG4-DxHrszj8.js} +1 -1
  115. package/dist/public/assets/{ws-BzWidrUz.js → ws-C-kvwpeD.js} +1 -1
  116. package/dist/public/assets/{xychartDiagram-S5SC5T6Z-eLBpE0yW.js → xychartDiagram-S5SC5T6Z-DpLvvdIG.js} +1 -1
  117. package/dist/public/index.html +2 -2
  118. package/dist/public/preview.html +18 -0
  119. package/package.json +1 -1
  120. package/dist/public/assets/PaneEditorBody-BnTDt5LG.js +0 -553
  121. package/dist/public/assets/Terminal-CoQpOpFQ.js +0 -60
  122. package/dist/public/assets/Workspace-klU-NMuZ.css +0 -1
  123. package/dist/public/assets/architecture-7GRP2DOG-DR2uP7PV.js +0 -1
  124. package/dist/public/assets/channel-CUVxklBM.js +0 -1
  125. package/dist/public/assets/classDiagram-ZZMXUADV-Cgl1n0Dz.js +0 -1
  126. package/dist/public/assets/classDiagram-v2-VYDZK3BY-Cgl1n0Dz.js +0 -1
  127. package/dist/public/assets/dist-tn5vjhJE.js +0 -1
  128. package/dist/public/assets/eventmodeling-NTZA5JFV-mkLPvEKM.js +0 -1
  129. package/dist/public/assets/flowDiagram-HODETNUW-O3VTLiVc.js +0 -1
  130. package/dist/public/assets/index-Ctw2P0rY.css +0 -2
  131. package/dist/public/assets/index-DWTNflld.js +0 -82
  132. package/dist/public/assets/input-CWrHR6Ba.js +0 -1
  133. package/dist/public/assets/railroad-abnf-HS5TGJTU-6aqbSR4_.js +0 -1
  134. package/dist/public/assets/railroad-ebnf-LZEXJU2U-DSe-edrj.js +0 -1
  135. package/dist/public/assets/railroad-peg-WCYAUIDC-CxQjyuGw.js +0 -1
  136. package/dist/public/assets/stateDiagram-v2-MP3YSRHH-C86Q0rld.js +0 -1
  137. package/dist/public/assets/swimlanesDiagram-VR7AAH4N-TVdovaZm.js +0 -8
  138. package/dist/public/assets/use-find-controls-DEA0SpBh.js +0 -1
package/CHANGELOG.md CHANGED
@@ -7,19 +7,8 @@ Past releases: see docs/changelogs/.
7
7
 
8
8
  # Changelog
9
9
 
10
- ## [0.2.3] — 2026-09-21
11
-
12
- ### Changed
13
-
14
- - Present connected browsers as shared compact cards, collapse them under a desktop settings disclosure, and place Delete registration beside the other registration actions.
15
- - Simplify Puddle Remote home to collapsible host/project groups, add its brand mark, compact the session rail, and hide revoked browsers in mobile and desktop settings.
16
- - Support long-press-and-drag text selection with a shared Copy action in mobile terminals and file content.
17
- - Compact the mobile workspace header, switch sessions from the shared title dropdown, follow desktop project/session ordering, and combine file navigation into one toolbar.
18
- - Replace the mobile keyboard button with an image picker that shares desktop image paste, inserts without submitting, and resizes large photos to fit remote request limits.
10
+ ## [0.2.6] — 2026-09-23
19
11
 
20
12
  ### Fixed
21
13
 
22
- - Fit five-letter project abbreviations in the mobile rail, match desktop gold controls, align the collapse button with both workspace toolbars, and distinguish the Files return action with a computer icon.
23
- - Prepare browser sign-in before the registration click so its tab opens directly on the machine displaying the UI, including desktop windows connected to SSH hosts.
24
- - Prefill mobile path browsing with the current directory or file and resolve both file and directory paths before navigating.
25
- - Keep mobile swipes inside terminal history and agent interfaces, preserve tap-to-type, and prevent terminal, file and session scrolling from moving the surrounding page.
14
+ - Fix standalone CLI distribution checks on Linux and macOS by retaining gzip on the isolated PATH and invoking system utilities at their original paths.
package/README.md CHANGED
@@ -20,7 +20,27 @@ Puddle manages parallel agents anywhere you SSH into, insulates agents in dedica
20
20
 
21
21
  ## Quick start
22
22
 
23
- **On your local machine where you will be using the GUI, run:**
23
+ **On your local machine where you will be using the GUI:**
24
+
25
+ For a standalone installation without Node.js or npm, use your deployed app's
26
+ installer (replace the example host):
27
+
28
+ ```sh
29
+ curl -fsSL https://app.example.com/install.sh | sh
30
+ ```
31
+
32
+ This installs the CLI under `~/.local/share/puddle/cli` and its launcher at
33
+ `~/.local/bin/puddle`. Add `~/.local/bin` to your `PATH` if the installer asks.
34
+ The standalone releases support Linux x64/arm64 and macOS arm64. The script and
35
+ checksum-verified archives are also attached to this repository's GitHub Releases.
36
+ An optional `--version` selects a release; `--prefix` and `--bin-dir` select the
37
+ installation and launcher directories:
38
+
39
+ ```sh
40
+ curl -fsSL https://app.example.com/install.sh | sh -s -- --version X.Y.Z
41
+ ```
42
+
43
+ Alternatively, with Node.js already installed, use npm:
24
44
 
25
45
  ```sh
26
46
  npm install -g @puddle-code/cli
@@ -56,13 +76,11 @@ detached processes, Puddle instead keeps the daemon attached to the cockpit; clo
56
76
  live processes. The next `puddle launch` restarts the daemon from the host's persistent state and,
57
77
  when auto-resume is enabled (the default), restores the interrupted sessions.
58
78
 
59
- **Daemon-only installs:**
60
-
61
- Daemon-only installs (no CLI) use the `install.sh` attached to each release — see the Releases page of this repository:
62
-
63
- ```sh
64
- curl -fsSL https://github.com/PerceptronV/puddle-code/releases/latest/download/install.sh | sh
65
- ```
79
+ The [deployed app](docs/mobile-access.md#host-the-installer) serves `/install.sh`
80
+ as the single public installer. Install daemon and desktop components through
81
+ `puddle install daemon [user@host]` and `puddle install desktop`. A first
82
+ `puddle launch user@host` still installs a missing daemon automatically from
83
+ GitHub Releases.
66
84
 
67
85
  **Managing components:**
68
86
 
@@ -76,21 +94,13 @@ puddle remove daemon # uninstall; your data stays unless yo
76
94
 
77
95
  **Desktop app (optional):**
78
96
 
79
- The same cockpit also ships as a standalone desktop app — identical UI and engine, plus a File → "Connect to SSH Host…" menu for remote hosts. Grab the dmg (macOS arm64) or AppImage (Linux x64) from the Releases page.
97
+ The same cockpit also ships as a standalone desktop app — identical UI and engine, plus a File → "Connect to SSH Host…" menu for remote hosts. Install it with `puddle install desktop` (macOS arm64 or Linux x64). Once installed, it runs independently of the CLI.
80
98
 
81
99
  An installed Puddle CLI manages the desktop app directly: quit Puddle, then `puddle install desktop`, `puddle upgrade desktop`, or `puddle remove desktop`. On macOS a fresh install goes to `/Applications` when writable, otherwise `~/Applications`; on Linux `install desktop` asks where to put the AppImage (default `~/puddle`) and opens the folder — later updates happen from inside the app.
82
100
 
83
- The macOS downloads are **not code-signed** (an open-source project without Apple Developer Program fees), so Gatekeeper will refuse the first launch. Either allow it once — open the app, let macOS block it, then System Settings → Privacy & Security → **Open Anyway** — or clear the download quarantine in a terminal:
84
-
85
- ```sh
86
- xattr -dr com.apple.quarantine /Applications/Puddle.app
87
- ```
88
-
89
- Building from source avoids the dance entirely (locally built apps are never quarantined): `pnpm build && pnpm --filter @puddle/desktop dist`.
90
-
91
101
  **Host requirements**: Linux with glibc 2.28+ (Ubuntu 20.04+, Debian 11+, RHEL/Rocky 8+;
92
102
  Alpine is not supported) or macOS, with `git` and `curl`, plus whichever agent CLIs you want on
93
- `PATH`. The client side works from any OS with a browser and `ssh` (Windows works, with repeated
103
+ `PATH`. Standalone CLI installs include Node and require no npm; npm installs require Node 22+. The client side works from any OS with a browser and `ssh` (Windows works, with repeated
94
104
  auth prompts unless you use a key).
95
105
 
96
106
  ## How it works
@@ -113,7 +123,7 @@ auth prompts unless you use a key).
113
123
  └───────────────────────────────────┘
114
124
  ```
115
125
 
116
- The CLI serves the UI at a stable local origin and reverse-proxies the API to the daemon, directly in local mode, through the tunnel in SSH mode. The daemon is headless and host-agnostic on `127.0.0.1:7434`. UI updates ship with the CLI (`npm update -g @puddle-code/cli` refreshes the cockpit for every host); the daemon only has to update when the versioned protocol breaks, and the CLI does that automatically. Short-lived host connection leases, separate browser authorisation and exact cockpit Host/Origin checks guard local access. Launch invitations are single-use; browser login survives cockpit restarts, while forwarded applications use a separate loopback origin. After upgrading from the old token flow, run `puddle launch` once to authorise existing tabs.
126
+ The CLI serves the UI at a stable local origin and reverse-proxies the API to the daemon, directly in local mode, through the tunnel in SSH mode. The daemon is headless and host-agnostic on `127.0.0.1:7434`. UI updates ship with the CLI (`puddle upgrade cli` refreshes the cockpit for every host); the daemon only has to update when the versioned protocol breaks, and the launcher asks for approval before updating it. The prompt shows the host, both protocols and how many live sessions the restart interrupts; declining leaves the daemon running. `--no-upgrade` refuses before prompting, and non-interactive launches require an explicit `puddle upgrade daemon [user@host]` first. Short-lived host connection leases, separate browser authorisation and exact cockpit Host/Origin checks guard local access. Launch invitations are single-use; browser login survives cockpit restarts, while forwarded applications use a separate loopback origin. After upgrading from the old token flow, run `puddle launch` once to authorise existing tabs.
117
127
 
118
128
  Everything lives under `~/.puddle` on the host, installed without sudo — and `puddle remove daemon` takes it apart again.
119
129
 
@@ -121,14 +131,14 @@ Everything lives under `~/.puddle` on the host, installed without sudo — and `
121
131
 
122
132
  **One daemon, many clients.** There is a single local daemon per machine, living under `~/.puddle` and run by one supervised service (launchd's `dev.puddle.puddled` on macOS, systemd's `puddled` on Linux). The global `puddle` and a repo-run `node packages/cli/dist/index.js` are **both just clients** that talk to — and, when needed, install — that same daemon. They never run side by side, and there is no separate "dev daemon" alongside a "production daemon".
123
133
 
124
- **Dev build vs. production.** `npm i -g @puddle-code/cli` is the production path — its `puddle` fetches and upgrades the daemon from this repo's GitHub Releases. To exercise uncommitted changes, build and run from the repo:
134
+ **Dev build vs. production.** The standalone installer or `npm i -g @puddle-code/cli` is the production path — its `puddle` fetches and upgrades the daemon from this repo's GitHub Releases. To exercise uncommitted changes, build and run from the repo:
125
135
 
126
136
  ```sh
127
137
  pnpm build && pnpm build:tarball
128
- node packages/cli/dist/index.js start --tarball dist-release/puddled-v*.tar.gz --foreground
138
+ node packages/cli/dist/index.js launch --tarball dist-release/puddled-v*.tar.gz --foreground
129
139
  ```
130
140
 
131
- `--tarball` sets the install _source_ only, and is consulted **only when the CLI actually installs the daemon** — when none is running, the daemon is stopped, or a protocol-major upgrade fires. If a compatible daemon (same protocol major) is already up, `start` just serves the cockpit against it and **the tarball is ignored** (even a newer app version — nothing compares app versions). So to load a fresh dev build over a running daemon you must **stop it first** (see _Kill_ below), then re-run `start --tarball …`. `--foreground` keeps the cockpit attached (`connect <user>@<host> --tarball …` is the remote form). Both clients share one `~/.puddle` daemon and cockpit registry, so `puddle list` / `puddle kill` see either — don't point both at the same host at once. (Never launch the daemon from inside a coding-agent shell: it inherits the agent's env and breaks conversation resume — use a plain terminal.)
141
+ `--tarball` sets the install _source_ only, and is consulted **only when the CLI actually installs the daemon** — when none is running, the daemon is stopped, or a protocol-major upgrade fires. If a compatible daemon (same protocol major) is already up, `launch` just serves the cockpit against it and **the tarball is ignored** (even a newer app version — nothing compares app versions). So to load a fresh dev build over a running daemon you must **stop it first** (see _Kill_ below), then re-run `launch --tarball …`. `--foreground` keeps the cockpit attached (`launch <user>@<host> --tarball …` is the remote form). Both clients share one `~/.puddle` daemon and cockpit registry, so `puddle list` / `puddle kill` see either — don't point both at the same host at once. (Never launch the daemon from inside a coding-agent shell: it inherits the agent's env and breaks conversation resume — use a plain terminal.)
132
142
 
133
143
  **Kill.** `puddle kill --all` (or Ctrl-C in a `--foreground` run) normally stops the local cockpit
134
144
  UI only; a supervised daemon and its sessions keep running. When launch reported that it is keeping
@@ -150,7 +160,7 @@ kill "$(cat ~/.puddle/puddled.pid)" # nohup fallback (no supervi
150
160
 
151
161
  ```sh
152
162
  puddle remove daemon --purge # stops the daemon, unregisters its service, deletes ~/.puddle
153
- puddle remove cli # npm uninstall -g, once the daemons you care about are gone
163
+ puddle remove cli # standalone or npm removal, using its installation channel
154
164
  ```
155
165
 
156
166
  > ⚠️ `~/.puddle` **is** your local state — the SQLite database with every profile, account, and session (plus conversation history), the daemon's worktree tracking, and the auth token. `--purge` deletes it irreversibly (the command lists dirty or unpushed worktrees and asks first); without it, `puddle remove daemon` keeps the data for a later reinstall.
@@ -14539,6 +14539,8 @@ var profileId = external_exports.string().regex(/^[0-9a-f]{10}$/);
14539
14539
  // ../shared/src/api/version.ts
14540
14540
  var versionResponseSchema = external_exports.object({
14541
14541
  version: external_exports.string(),
14542
+ /** Added by the host connector; absent on direct daemon responses and older connectors. */
14543
+ remote_image_uploads: external_exports.boolean().optional(),
14542
14544
  protocol: external_exports.object({
14543
14545
  major: external_exports.number().int().nonnegative(),
14544
14546
  minor: external_exports.number().int().nonnegative()
@@ -15466,6 +15468,11 @@ var fileResponseSchema = external_exports.object({
15466
15468
  size: external_exports.number().int().nonnegative(),
15467
15469
  mtime_ms: external_exports.number()
15468
15470
  });
15471
+ var MAX_PREVIEW_ASSET_BYTES = 8 * 1024 * 1024;
15472
+ var previewAssetResponseSchema = external_exports.object({
15473
+ mime: external_exports.string().min(1).max(128),
15474
+ data: external_exports.string().max(4 * Math.ceil(MAX_PREVIEW_ASSET_BYTES / 3))
15475
+ });
15469
15476
  var putFileRequestSchema = external_exports.object({
15470
15477
  content: external_exports.string(),
15471
15478
  /** Optimistic-concurrency guard: reject the write if the file changed since this mtime. */
@@ -15994,6 +16001,36 @@ var browserAuthorityStateSchema = external_exports.object({
15994
16001
  proxies: external_exports.array(proxyRecordSchema)
15995
16002
  });
15996
16003
 
16004
+ // ../shared/src/remote/image-upload.ts
16005
+ var IMAGE_UPLOAD_POLICY = {
16006
+ imageBytes: 4 * 1024 * 1024,
16007
+ chunkBytes: 64 * 1024,
16008
+ idleMs: 6e4,
16009
+ lifetimeMs: 5 * 6e4
16010
+ };
16011
+ var imageUploadRequestSchema = external_exports.discriminatedUnion("action", [
16012
+ external_exports.object({
16013
+ action: external_exports.literal("start"),
16014
+ upload: external_exports.string().uuid(),
16015
+ mime: pasteImageMimeSchema,
16016
+ size: external_exports.number().int().positive().max(IMAGE_UPLOAD_POLICY.imageBytes)
16017
+ }).strict(),
16018
+ external_exports.object({
16019
+ action: external_exports.literal("chunk"),
16020
+ upload: external_exports.string().uuid(),
16021
+ offset: external_exports.number().int().nonnegative().max(IMAGE_UPLOAD_POLICY.imageBytes),
16022
+ data: external_exports.string().min(4).max(4 * Math.ceil(IMAGE_UPLOAD_POLICY.chunkBytes / 3)).regex(/^[A-Za-z0-9+/]+={0,2}$/).refine((data) => {
16023
+ const padding = data.endsWith("==") ? 2 : data.endsWith("=") ? 1 : 0;
16024
+ return data.length % 4 === 0 && data.length / 4 * 3 - padding <= IMAGE_UPLOAD_POLICY.chunkBytes;
16025
+ }, "Image chunk is too large or malformed")
16026
+ }).strict(),
16027
+ external_exports.object({ action: external_exports.literal("finish"), upload: external_exports.string().uuid() }).strict(),
16028
+ external_exports.object({ action: external_exports.literal("cancel"), upload: external_exports.string().uuid() }).strict()
16029
+ ]);
16030
+ var imageUploadProgressSchema = external_exports.object({
16031
+ received: external_exports.number().int().nonnegative().max(IMAGE_UPLOAD_POLICY.imageBytes)
16032
+ });
16033
+
15997
16034
  // ../shared/src/remote/service.ts
15998
16035
  var remoteHostSchema = external_exports.object({
15999
16036
  id: remoteIdSchema,
@@ -16018,6 +16055,7 @@ var remoteLoginStateSchema = external_exports.object({
16018
16055
  var registerHostRequestSchema = external_exports.object({ label: remoteLabelSchema }).strict();
16019
16056
  var registrationResponseSchema = external_exports.object({ host: remoteIdSchema, code: remoteSecretSchema, expires: external_exports.number() }).strict();
16020
16057
  var redeemRegistrationSchema = external_exports.object({ code: remoteSecretSchema }).strict();
16058
+ var unregisterHostRequestSchema = external_exports.object({ credential: remoteSecretSchema }).strict();
16021
16059
  var desktopRegistrationSchema = external_exports.object({
16022
16060
  challenge: remoteSecretSchema,
16023
16061
  label: remoteLabelSchema,
@@ -16203,7 +16241,7 @@ async function inspectLegacyHost(home) {
16203
16241
  };
16204
16242
  try {
16205
16243
  const version2 = versionResponseSchema.parse(await get("/api/version"));
16206
- const sessions = sessionSchema.array().parse(await get("/api/sessions"));
16244
+ const sessions = sessionSchema.pick({ status: true }).array().parse(await get("/api/sessions"));
16207
16245
  return hostInspectionSchema.parse({
16208
16246
  t: "inspection",
16209
16247
  port,
@@ -16248,7 +16286,7 @@ async function inspectHostLocally(home) {
16248
16286
  signal: AbortSignal.timeout(3e3)
16249
16287
  });
16250
16288
  if (!response.ok) throw new Error("Host inspection rejected");
16251
- const sessions = sessionSchema.array().parse(await response.json());
16289
+ const sessions = sessionSchema.pick({ status: true }).array().parse(await response.json());
16252
16290
  return hostInspectionSchema.parse({
16253
16291
  t: "inspection",
16254
16292
  port: grant.port,