@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.
- package/CHANGELOG.md +2 -13
- package/README.md +33 -23
- package/dist/host-control.mjs +40 -2
- package/dist/index.js +541 -313
- package/dist/install-cli.sh +167 -0
- package/dist/install.sh +7 -10
- package/dist/public/assets/{App-JZgRWo4t.js → App-CzuHShdO.js} +2 -2
- package/dist/public/assets/{Dashboard-DNWLZwxT.js → Dashboard-B5qWtmwb.js} +1 -1
- package/dist/public/assets/{EditorTabClose-CdpMpKYq.js → EditorTabClose-uxuNJdgx.js} +1 -1
- package/dist/public/assets/FindWidget-lUpiYZJG.js +1 -0
- package/dist/public/assets/{LazyTerminal-DVeI2Lkl.js → LazyTerminal-BYbPpGEI.js} +2 -2
- package/dist/public/assets/{ModelRefcount-ALfiNB9K.js → ModelRefcount-N0Xh_Y-_.js} +1 -1
- package/dist/public/assets/{NewProjectDialog-RHBHLIQe.js → NewProjectDialog-D3bNK3u_.js} +1 -1
- package/dist/public/assets/PaneEditorBody-DrSiMzrp.js +553 -0
- package/dist/public/assets/{PdfViewer-DZrh-S3Z.js → PdfViewer-BhqrWfmb.js} +2 -2
- package/dist/public/assets/{SettingsDialog-D-yMKqY9.js → SettingsDialog-CamnF91I.js} +2 -2
- package/dist/public/assets/Terminal-Ds17sCF_.js +60 -0
- package/dist/public/assets/Workspace-B6mgQyIM.css +1 -0
- package/dist/public/assets/{Workspace-DhFU_Ltc.js → Workspace-BmtA0kYQ.js} +6 -6
- package/dist/public/assets/{abnfDiagram-VCTEODGH-Bb_QGl6J.js → abnfDiagram-VCTEODGH-B4ZtDUXi.js} +1 -1
- package/dist/public/assets/architecture-7GRP2DOG-D0iH6Lxl.js +1 -0
- package/dist/public/assets/{architectureDiagram-5GKGNRK7-CF6YHpo7.js → architectureDiagram-5GKGNRK7-Cyzuyzwl.js} +1 -1
- package/dist/public/assets/{blockDiagram-I7D4REHJ-DgUouS8v.js → blockDiagram-I7D4REHJ-BN00JnNl.js} +1 -1
- package/dist/public/assets/{buffer-store-DcARHjQ8.js → buffer-store--4yU4YqM.js} +2 -2
- package/dist/public/assets/{button-CyO-gAMJ.js → button-DehrlYw7.js} +1 -1
- package/dist/public/assets/{c4Diagram-7LVT6UL2-CFhvq4-y.js → c4Diagram-7LVT6UL2-DpUKodBy.js} +1 -1
- package/dist/public/assets/channel-DT2izo70.js +1 -0
- package/dist/public/assets/{chunk-2E4U76K2-CskNiADZ.js → chunk-2E4U76K2-BksaqXZU.js} +1 -1
- package/dist/public/assets/{chunk-4HAMMTFA-DY74ei7y.js → chunk-4HAMMTFA-D01k6w0A.js} +1 -1
- package/dist/public/assets/{chunk-75Z2AOVW-sHPItT4L.js → chunk-75Z2AOVW-DJJjslyX.js} +1 -1
- package/dist/public/assets/{chunk-CLGD4ZFX-BbZdl00J.js → chunk-CLGD4ZFX-CX1B9i6H.js} +1 -1
- package/dist/public/assets/{chunk-DU6HZSFF-BZvHUJoN.js → chunk-DU6HZSFF-Bx2ELCn-.js} +1 -1
- package/dist/public/assets/{chunk-F27PBJKO-C-FJqBSD.js → chunk-F27PBJKO-CCDhODx8.js} +1 -1
- package/dist/public/assets/{chunk-GMAD6QVW-DPkzF1Ic.js → chunk-GMAD6QVW-C1evXXZi.js} +1 -1
- package/dist/public/assets/{chunk-GVQU2GXP-Batc2xZS.js → chunk-GVQU2GXP-C1iphgLK.js} +1 -1
- package/dist/public/assets/{chunk-IMKFNOWR-CAMx72vu.js → chunk-IMKFNOWR-5wMdkmsQ.js} +1 -1
- package/dist/public/assets/{chunk-L3NEJ4N5-CuIGdGy-.js → chunk-L3NEJ4N5-B-aXfMpF.js} +1 -1
- package/dist/public/assets/{chunk-OSK3NFVY-uNp8Mp7C.js → chunk-OSK3NFVY-Bm2MaFOc.js} +1 -1
- package/dist/public/assets/{chunk-P2QGCYS3-CoRPhFtM.js → chunk-P2QGCYS3-H02JaAun.js} +1 -1
- package/dist/public/assets/{chunk-POPQ4Y6H-DMOCBqAw.js → chunk-POPQ4Y6H-Dmm46Beg.js} +1 -1
- package/dist/public/assets/{chunk-PWAF6VOD-DOQkLdyp.js → chunk-PWAF6VOD-CRt8Ete5.js} +1 -1
- package/dist/public/assets/{chunk-SHT3W25Y-BJJe_uau.js → chunk-SHT3W25Y-w4aNK54y.js} +1 -1
- package/dist/public/assets/{chunk-SVP7TREG-D5B1jrjj.js → chunk-SVP7TREG-Cl3QpMDs.js} +1 -1
- package/dist/public/assets/{chunk-TICWLB2K-C9NafHGC.js → chunk-TICWLB2K-BpBbot9h.js} +1 -1
- package/dist/public/assets/{chunk-TLUHSLCS-Ctl_RxEM.js → chunk-TLUHSLCS-BOnIB6P6.js} +2 -2
- package/dist/public/assets/classDiagram-ZZMXUADV-BSshJUxJ.js +1 -0
- package/dist/public/assets/classDiagram-v2-VYDZK3BY-BSshJUxJ.js +1 -0
- package/dist/public/assets/{context-menu-BuiHQTu6.js → context-menu-BT88Vgia.js} +1 -1
- package/dist/public/assets/{cssMode-DozYXR6g.js → cssMode-gXT_K4po.js} +1 -1
- package/dist/public/assets/{cynefin-OW5HDTMX-gj0lEe4i.js → cynefin-OW5HDTMX-CJakxaH8.js} +1 -1
- package/dist/public/assets/{cynefinDiagram-5FMLGOSQ-lYCffbhY.js → cynefinDiagram-5FMLGOSQ-BJ_fVnC9.js} +1 -1
- package/dist/public/assets/{dagre-GXQ25YYZ-DyYVAAw7.js → dagre-GXQ25YYZ-CjflcbuS.js} +1 -1
- package/dist/public/assets/{diagram-S7CK7UJ4-Dop5OEsZ.js → diagram-S7CK7UJ4-g8pKIWrY.js} +1 -1
- package/dist/public/assets/{diagram-UQ7AKVKN-B5qxPK0m.js → diagram-UQ7AKVKN-Dm5Pg4rY.js} +1 -1
- package/dist/public/assets/{diagram-VSXAHHWV-zvsxaxBC.js → diagram-VSXAHHWV-DV5CVAXg.js} +1 -1
- package/dist/public/assets/{diagram-VX7I27RA-S7nRhoRV.js → diagram-VX7I27RA-Be9qCk-h.js} +1 -1
- package/dist/public/assets/{diagram-Z3DM3KII-C_jkP2wb.js → diagram-Z3DM3KII-C3-xDrxs.js} +1 -1
- package/dist/public/assets/{dialog-D6I1fiX4.js → dialog-CAMTxigV.js} +1 -1
- package/dist/public/assets/{disclosure-Dn2Pws0i.js → disclosure-DvM7-z38.js} +1 -1
- package/dist/public/assets/dist-3tmIo7Ja.js +1 -0
- package/dist/public/assets/{dist-Dt0LZb5E.js → dist-sLs_LTiG.js} +1 -1
- package/dist/public/assets/{ebnfDiagram-PWID7BFC-B1OmWQdM.js → ebnfDiagram-PWID7BFC-Bq92n7k-.js} +1 -1
- package/dist/public/assets/{erDiagram-RLTQ6QDP-DJKky3Wx.js → erDiagram-RLTQ6QDP-C5I2bKnS.js} +1 -1
- package/dist/public/assets/eventmodeling-NTZA5JFV-CWxfOZuS.js +1 -0
- package/dist/public/assets/flowDiagram-HODETNUW-ddOOBXlS.js +1 -0
- package/dist/public/assets/{ganttDiagram-EL5Y4UJY-qEYH72Jx.js → ganttDiagram-EL5Y4UJY-qUaBgbbK.js} +1 -1
- package/dist/public/assets/{gitGraph-4MIJSDKK-DlVqGPr_.js → gitGraph-4MIJSDKK-CUfoq3Sa.js} +1 -1
- package/dist/public/assets/{gitGraphDiagram-WWUBYQGX-DjfCMlWr.js → gitGraphDiagram-WWUBYQGX-kj34Cchu.js} +1 -1
- package/dist/public/assets/{hotkeys-Bx0QQoOi.js → hotkeys-DbIEec2f.js} +1 -1
- package/dist/public/assets/{htmlMode-DlKAkkNW.js → htmlMode-C_uC6TDH.js} +1 -1
- package/dist/public/assets/index-BLx1AR0-.js +82 -0
- package/dist/public/assets/index-uKreLbru.css +2 -0
- package/dist/public/assets/{info-A6RAGUB7-CH2cc1Sk.js → info-A6RAGUB7-C938EzS-.js} +1 -1
- package/dist/public/assets/{infoDiagram-27XIBGKW-QLQ5mJz6.js → infoDiagram-27XIBGKW-BoTxIjdn.js} +1 -1
- package/dist/public/assets/input-DXYRmAFr.js +1 -0
- package/dist/public/assets/{ishikawaDiagram-5VMMS53U-Dgd8STMm.js → ishikawaDiagram-5VMMS53U-j98L6THV.js} +1 -1
- package/dist/public/assets/{journeyDiagram-3NMN7TZE-BaIBwMwN.js → journeyDiagram-3NMN7TZE-DI-XCC2F.js} +1 -1
- package/dist/public/assets/{jsonMode-B-xhmxpv.js → jsonMode-BQ3590Ds.js} +1 -1
- package/dist/public/assets/{kanban-definition-UXKFOSKX-DUwkSFm5.js → kanban-definition-UXKFOSKX-BCTvFJTJ.js} +1 -1
- package/dist/public/assets/{line-DBd--km9.js → line-hE2Okp1W.js} +1 -1
- package/dist/public/assets/{media-refresh-store-C2PF6Nl9.js → media-refresh-store-CxqhHl8x.js} +1 -1
- package/dist/public/assets/{mermaid-parser.core-CH9r0Plq.js → mermaid-parser.core-n0Wb6T7Q.js} +3 -3
- package/dist/public/assets/{mermaid.core-Dx4uf1Og.js → mermaid.core-Cb0bw4D8.js} +3 -3
- package/dist/public/assets/{mindmap-definition-YA3MSWOX-DFlzr0Rk.js → mindmap-definition-YA3MSWOX-92LM1OuK.js} +1 -1
- package/dist/public/assets/{notification-permission-BJ5Ee1QS.js → notification-permission-CG2r3Oi8.js} +1 -1
- package/dist/public/assets/{packet-AYTQ26CC-BoGgl5A0.js → packet-AYTQ26CC-_HBkwHYp.js} +1 -1
- package/dist/public/assets/{pdf-CIIeLqAE.js → pdf-DABk-fGs.js} +1 -1
- package/dist/public/assets/{pegDiagram-XKGWAZYB-dBubzdqe.js → pegDiagram-XKGWAZYB-B-fG_WHS.js} +1 -1
- package/dist/public/assets/{pie-WAS4IAKB-C8Ujmmnq.js → pie-WAS4IAKB-ByxJto7v.js} +1 -1
- package/dist/public/assets/{pieDiagram-E7YTZNPT-BarO3dDM.js → pieDiagram-E7YTZNPT-Ci8ZSq4L.js} +1 -1
- package/dist/public/assets/{project-abbrev-BlBz9tcM.js → project-abbrev-BU2DBpdq.js} +1 -1
- package/dist/public/assets/{quadrantDiagram-AXDQQJYC-Bq7mziYZ.js → quadrantDiagram-AXDQQJYC-B97Yoxpb.js} +1 -1
- package/dist/public/assets/{radar-RG4KPBEZ-CSOiAaDJ.js → radar-RG4KPBEZ-BT2qdAqW.js} +1 -1
- package/dist/public/assets/{railroad-74A4TZTK-B72WpbJE.js → railroad-74A4TZTK-Buny6l3B.js} +1 -1
- package/dist/public/assets/railroad-abnf-HS5TGJTU-C_aUf3vj.js +1 -0
- package/dist/public/assets/railroad-ebnf-LZEXJU2U-BGUVD_Qq.js +1 -0
- package/dist/public/assets/railroad-peg-WCYAUIDC-CGdTjBGv.js +1 -0
- package/dist/public/assets/{railroadDiagram-O6MQD6OU-CdpFpJTq.js → railroadDiagram-O6MQD6OU-BktpI6J7.js} +1 -1
- package/dist/public/assets/{requirementDiagram-BXWQKSXE-D5gAf9X3.js → requirementDiagram-BXWQKSXE-DYy_YKmd.js} +1 -1
- package/dist/public/assets/{sankeyDiagram-P5KCCOFB-CWGxwWQO.js → sankeyDiagram-P5KCCOFB-BeKH_sFV.js} +1 -1
- package/dist/public/assets/{sequenceDiagram-WJ2MYXX4-D4OU6YFv.js → sequenceDiagram-WJ2MYXX4-DD8okFGM.js} +1 -1
- package/dist/public/assets/{stateDiagram-D77RDMKH-DL34KHS6.js → stateDiagram-D77RDMKH-Bfk3E3Oa.js} +1 -1
- package/dist/public/assets/stateDiagram-v2-MP3YSRHH-DCg8-XDy.js +1 -0
- package/dist/public/assets/{swimlanes-42K2YHIH-ClnyergN.js → swimlanes-42K2YHIH-OVNrzhfn.js} +1 -1
- package/dist/public/assets/swimlanesDiagram-VR7AAH4N-DAqvbP32.js +8 -0
- package/dist/public/assets/{switch-JLAneJz1.js → switch-CN9NW-du.js} +1 -1
- package/dist/public/assets/{timeline-definition-24CTP7MA-Bouu1PMd.js → timeline-definition-24CTP7MA-C78a8EdU.js} +1 -1
- package/dist/public/assets/{treeView-Q6P3EWNA-OLbwx3G_.js → treeView-Q6P3EWNA-Cl5tCoga.js} +1 -1
- package/dist/public/assets/{treemap-WGGIJYW6-BWtOLy1c.js → treemap-WGGIJYW6-4YVcjSz9.js} +1 -1
- package/dist/public/assets/{tsMode-BChcsbnx.js → tsMode-CmGZ7MCT.js} +1 -1
- package/dist/public/assets/{use-ui-state-xRIsbDTY.js → use-ui-state-CzR7YpWb.js} +1 -1
- package/dist/public/assets/{vennDiagram-4TSXK5OY-B7Iv-Yti.js → vennDiagram-4TSXK5OY-Lih9MwBs.js} +1 -1
- package/dist/public/assets/{wardley-WFR3VGLG-bREi8xGw.js → wardley-WFR3VGLG-CcU7I6bt.js} +1 -1
- package/dist/public/assets/{wardleyDiagram-VM6X3IG4-BCZ7iNOW.js → wardleyDiagram-VM6X3IG4-DxHrszj8.js} +1 -1
- package/dist/public/assets/{ws-BzWidrUz.js → ws-C-kvwpeD.js} +1 -1
- package/dist/public/assets/{xychartDiagram-S5SC5T6Z-eLBpE0yW.js → xychartDiagram-S5SC5T6Z-DpLvvdIG.js} +1 -1
- package/dist/public/index.html +2 -2
- package/dist/public/preview.html +18 -0
- package/package.json +1 -1
- package/dist/public/assets/PaneEditorBody-BnTDt5LG.js +0 -553
- package/dist/public/assets/Terminal-CoQpOpFQ.js +0 -60
- package/dist/public/assets/Workspace-klU-NMuZ.css +0 -1
- package/dist/public/assets/architecture-7GRP2DOG-DR2uP7PV.js +0 -1
- package/dist/public/assets/channel-CUVxklBM.js +0 -1
- package/dist/public/assets/classDiagram-ZZMXUADV-Cgl1n0Dz.js +0 -1
- package/dist/public/assets/classDiagram-v2-VYDZK3BY-Cgl1n0Dz.js +0 -1
- package/dist/public/assets/dist-tn5vjhJE.js +0 -1
- package/dist/public/assets/eventmodeling-NTZA5JFV-mkLPvEKM.js +0 -1
- package/dist/public/assets/flowDiagram-HODETNUW-O3VTLiVc.js +0 -1
- package/dist/public/assets/index-Ctw2P0rY.css +0 -2
- package/dist/public/assets/index-DWTNflld.js +0 -82
- package/dist/public/assets/input-CWrHR6Ba.js +0 -1
- package/dist/public/assets/railroad-abnf-HS5TGJTU-6aqbSR4_.js +0 -1
- package/dist/public/assets/railroad-ebnf-LZEXJU2U-DSe-edrj.js +0 -1
- package/dist/public/assets/railroad-peg-WCYAUIDC-CxQjyuGw.js +0 -1
- package/dist/public/assets/stateDiagram-v2-MP3YSRHH-C86Q0rld.js +0 -1
- package/dist/public/assets/swimlanesDiagram-VR7AAH4N-TVdovaZm.js +0 -8
- 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.
|
|
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
|
-
-
|
|
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
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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.
|
|
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 (`
|
|
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
|
|
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, `
|
|
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
|
|
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.
|
package/dist/host-control.mjs
CHANGED
|
@@ -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,
|