@puddle-code/cli 0.2.0 → 0.2.2

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 (134) hide show
  1. package/CHANGELOG.md +10 -21
  2. package/dist/host-control.mjs +43 -5
  3. package/dist/index.js +172 -87
  4. package/dist/install.sh +13 -0
  5. package/dist/public/assets/App-DYF0TQ7N.js +2 -0
  6. package/dist/public/assets/Dashboard-BLWy1kHm.js +1 -0
  7. package/dist/public/assets/{EditorTabClose-Dxz8ZjM9.js → EditorTabClose-CtInp1cT.js} +1 -1
  8. package/dist/public/assets/{LazyTerminal-CvkHRHQo.js → LazyTerminal-BrJnGoEX.js} +2 -2
  9. package/dist/public/assets/{ModelRefcount-C0ZeHnBJ.js → ModelRefcount-BNtD7p2m.js} +1 -1
  10. package/dist/public/assets/{NewProjectDialog-CHQ7EJYr.js → NewProjectDialog-BHIvFpCo.js} +1 -1
  11. package/dist/public/assets/{PaneEditorBody-Bco44A9M.js → PaneEditorBody--HKVd4ce.js} +4 -4
  12. package/dist/public/assets/{PdfViewer-Xg7NGubF.js → PdfViewer-DhO008IQ.js} +2 -2
  13. package/dist/public/assets/SettingsDialog-rfDhJoO1.js +8 -0
  14. package/dist/public/assets/Terminal-CttD7XcZ.js +60 -0
  15. package/dist/public/assets/Workspace-BB4IS8EP.js +20 -0
  16. package/dist/public/assets/Workspace-DgLBQU_0.css +1 -0
  17. package/dist/public/assets/{abnfDiagram-VCTEODGH-B9xm0g0V.js → abnfDiagram-VCTEODGH-CTMUfqGq.js} +1 -1
  18. package/dist/public/assets/architecture-7GRP2DOG-D65OB2im.js +1 -0
  19. package/dist/public/assets/{architectureDiagram-5GKGNRK7-DrrWczea.js → architectureDiagram-5GKGNRK7-B-L0EtRZ.js} +1 -1
  20. package/dist/public/assets/{blockDiagram-I7D4REHJ-CYEP6Dnn.js → blockDiagram-I7D4REHJ-CnmmDFsq.js} +1 -1
  21. package/dist/public/assets/{buffer-store-pvgusTv-.js → buffer-store-DzO77p-K.js} +2 -2
  22. package/dist/public/assets/{c4Diagram-7LVT6UL2-BAkFUfYR.js → c4Diagram-7LVT6UL2-DU4HXNd-.js} +1 -1
  23. package/dist/public/assets/channel-DDYJkwWS.js +1 -0
  24. package/dist/public/assets/{chunk-2E4U76K2-sXcn0WDZ.js → chunk-2E4U76K2-B8o6iRzd.js} +1 -1
  25. package/dist/public/assets/{chunk-4HAMMTFA-CPPsfbHS.js → chunk-4HAMMTFA-CfxkhHyC.js} +1 -1
  26. package/dist/public/assets/{chunk-75Z2AOVW-Cp3T9-mM.js → chunk-75Z2AOVW-D8v_0vko.js} +1 -1
  27. package/dist/public/assets/{chunk-CLGD4ZFX-aqUnXBfy.js → chunk-CLGD4ZFX-DPBjX4jg.js} +1 -1
  28. package/dist/public/assets/{chunk-DU6HZSFF-BKPHVNGu.js → chunk-DU6HZSFF-CuwQaNw0.js} +1 -1
  29. package/dist/public/assets/{chunk-F27PBJKO-IqOkPRK3.js → chunk-F27PBJKO-lg02cTVZ.js} +1 -1
  30. package/dist/public/assets/{chunk-GMAD6QVW-c9P8ntLy.js → chunk-GMAD6QVW-DICB0y-D.js} +1 -1
  31. package/dist/public/assets/{chunk-GVQU2GXP-DmZAhaXk.js → chunk-GVQU2GXP-9ghjwcoq.js} +1 -1
  32. package/dist/public/assets/{chunk-IMKFNOWR-CXrrJ9cb.js → chunk-IMKFNOWR-i_YIFBJX.js} +1 -1
  33. package/dist/public/assets/{chunk-L3NEJ4N5-Pn0OM8Or.js → chunk-L3NEJ4N5-gR7gj1U0.js} +1 -1
  34. package/dist/public/assets/{chunk-OSK3NFVY-CSxO-Bhw.js → chunk-OSK3NFVY-DHyaWigk.js} +1 -1
  35. package/dist/public/assets/{chunk-P2QGCYS3-DpTPoZQU.js → chunk-P2QGCYS3-ykV2meK0.js} +1 -1
  36. package/dist/public/assets/{chunk-POPQ4Y6H-V45h95Rz.js → chunk-POPQ4Y6H-BfpRTc3s.js} +1 -1
  37. package/dist/public/assets/{chunk-PWAF6VOD-aG71yphl.js → chunk-PWAF6VOD-gWIwGh8g.js} +1 -1
  38. package/dist/public/assets/{chunk-SHT3W25Y-8X6FPG54.js → chunk-SHT3W25Y-BQ_pTF0Z.js} +1 -1
  39. package/dist/public/assets/{chunk-SVP7TREG-x6ifISIm.js → chunk-SVP7TREG-SQwLD6DT.js} +1 -1
  40. package/dist/public/assets/{chunk-TICWLB2K-D9KB9pY5.js → chunk-TICWLB2K-B2zBy15L.js} +1 -1
  41. package/dist/public/assets/{chunk-TLUHSLCS-GPGNxyxD.js → chunk-TLUHSLCS-Bd2UG2tZ.js} +2 -2
  42. package/dist/public/assets/classDiagram-ZZMXUADV-DiYOyJFb.js +1 -0
  43. package/dist/public/assets/classDiagram-v2-VYDZK3BY-DiYOyJFb.js +1 -0
  44. package/dist/public/assets/{context-menu-Dt7h9y20.js → context-menu-Brk2htuk.js} +1 -1
  45. package/dist/public/assets/{cssMode-F3TrjQ2Y.js → cssMode-DqPCL8gS.js} +1 -1
  46. package/dist/public/assets/{cynefin-OW5HDTMX-BCcHZD-7.js → cynefin-OW5HDTMX-CSAZrmjo.js} +1 -1
  47. package/dist/public/assets/{cynefinDiagram-5FMLGOSQ-hEFQTinv.js → cynefinDiagram-5FMLGOSQ-CGKlzaPC.js} +1 -1
  48. package/dist/public/assets/{dagre-GXQ25YYZ-Dj7c-z9-.js → dagre-GXQ25YYZ-CgRwIpkl.js} +1 -1
  49. package/dist/public/assets/{diagram-S7CK7UJ4-i3ABTGXD.js → diagram-S7CK7UJ4-BMP1KOBu.js} +1 -1
  50. package/dist/public/assets/{diagram-UQ7AKVKN-BClHr071.js → diagram-UQ7AKVKN-DNcOIF4W.js} +1 -1
  51. package/dist/public/assets/{diagram-VSXAHHWV-_NoikNWl.js → diagram-VSXAHHWV-BGdHvK5Q.js} +1 -1
  52. package/dist/public/assets/{diagram-VX7I27RA-BxznNmgf.js → diagram-VX7I27RA-F7PfwNlr.js} +1 -1
  53. package/dist/public/assets/{diagram-Z3DM3KII-Dp_Elrik.js → diagram-Z3DM3KII-CPE4T9mi.js} +1 -1
  54. package/dist/public/assets/{dialog-GYBse2vm.js → dialog-B08M5Cgz.js} +2 -2
  55. package/dist/public/assets/disclosure-Bc6Ydabz.js +1 -0
  56. package/dist/public/assets/{dist-BB_jCiks.js → dist-CE40EiFY.js} +1 -1
  57. package/dist/public/assets/{dist-Dd_gMYta.js → dist-w0M7y9KX.js} +1 -1
  58. package/dist/public/assets/{ebnfDiagram-PWID7BFC-BrhXAUqf.js → ebnfDiagram-PWID7BFC-CqTR9kTI.js} +1 -1
  59. package/dist/public/assets/{erDiagram-RLTQ6QDP-DpvzwcpF.js → erDiagram-RLTQ6QDP-CVqix4AT.js} +1 -1
  60. package/dist/public/assets/eventmodeling-NTZA5JFV-BoPTLqKJ.js +1 -0
  61. package/dist/public/assets/flowDiagram-HODETNUW-2TNtc6rJ.js +1 -0
  62. package/dist/public/assets/{ganttDiagram-EL5Y4UJY-MwZQW2Ab.js → ganttDiagram-EL5Y4UJY-CFSX0WK6.js} +1 -1
  63. package/dist/public/assets/{gitGraph-4MIJSDKK-wD3tQrBr.js → gitGraph-4MIJSDKK-Doy-w5G0.js} +1 -1
  64. package/dist/public/assets/{gitGraphDiagram-WWUBYQGX-RZqAMYtF.js → gitGraphDiagram-WWUBYQGX-fQM29HOw.js} +1 -1
  65. package/dist/public/assets/{hotkeys-Bpeih0PX.js → hotkeys-DQNqRgOb.js} +1 -1
  66. package/dist/public/assets/{htmlMode-BQanlpBa.js → htmlMode-DE4OLLtJ.js} +1 -1
  67. package/dist/public/assets/index-CQ-7fSnd.css +2 -0
  68. package/dist/public/assets/{index-D96JjECU.js → index-CmEI98Do.js} +2 -2
  69. package/dist/public/assets/{info-A6RAGUB7-ie0E4iIr.js → info-A6RAGUB7-DPiPYEQe.js} +1 -1
  70. package/dist/public/assets/{infoDiagram-27XIBGKW-u5u8byqk.js → infoDiagram-27XIBGKW-DY5LKiBl.js} +1 -1
  71. package/dist/public/assets/{input-AzsFYZ3g.js → input-CRHttNr9.js} +1 -1
  72. package/dist/public/assets/{ishikawaDiagram-5VMMS53U-4GHMY6KJ.js → ishikawaDiagram-5VMMS53U-DwSURfQE.js} +1 -1
  73. package/dist/public/assets/{journeyDiagram-3NMN7TZE-Cwe5PRBP.js → journeyDiagram-3NMN7TZE-B0OCkFis.js} +1 -1
  74. package/dist/public/assets/{jsonMode-CRZXV6U_.js → jsonMode-F58eqVfl.js} +1 -1
  75. package/dist/public/assets/{kanban-definition-UXKFOSKX-CS-A9ZNT.js → kanban-definition-UXKFOSKX-CAQw3qWz.js} +1 -1
  76. package/dist/public/assets/{line-kZmQKU6y.js → line-Bcu_KJDQ.js} +1 -1
  77. package/dist/public/assets/{media-refresh-store-B_VyvYfl.js → media-refresh-store-B8Wdlks-.js} +1 -1
  78. package/dist/public/assets/{mermaid-parser.core-BEcx5De7.js → mermaid-parser.core-PSjhnHbq.js} +3 -3
  79. package/dist/public/assets/{mermaid.core-ZFBf3aP8.js → mermaid.core-CVDKsXhB.js} +3 -3
  80. package/dist/public/assets/{mindmap-definition-YA3MSWOX-ti5sUvQf.js → mindmap-definition-YA3MSWOX-CVAY5896.js} +1 -1
  81. package/dist/public/assets/{notification-permission-Car54v17.js → notification-permission-CbLpN3ev.js} +1 -1
  82. package/dist/public/assets/{packet-AYTQ26CC-BFLiDvUG.js → packet-AYTQ26CC-CTdFnPq7.js} +1 -1
  83. package/dist/public/assets/{pdf-CDunFg56.js → pdf-CNnH2qu8.js} +1 -1
  84. package/dist/public/assets/{pegDiagram-XKGWAZYB-L1VUrE59.js → pegDiagram-XKGWAZYB-DjAvebfq.js} +1 -1
  85. package/dist/public/assets/{pie-WAS4IAKB-BxBZGMsV.js → pie-WAS4IAKB-DGj7H0HD.js} +1 -1
  86. package/dist/public/assets/{pieDiagram-E7YTZNPT-D_z8Ah38.js → pieDiagram-E7YTZNPT-ZsMHxQiN.js} +1 -1
  87. package/dist/public/assets/{project-abbrev-B7pHIhbk.js → project-abbrev-CaGbOWtr.js} +1 -1
  88. package/dist/public/assets/{quadrantDiagram-AXDQQJYC-DEU0wyvb.js → quadrantDiagram-AXDQQJYC-DVxSJgm4.js} +1 -1
  89. package/dist/public/assets/{radar-RG4KPBEZ-C7ijJa3G.js → radar-RG4KPBEZ-D7tOXZhy.js} +1 -1
  90. package/dist/public/assets/{railroad-74A4TZTK-BR2-uhMp.js → railroad-74A4TZTK-EI9jAf_f.js} +1 -1
  91. package/dist/public/assets/railroad-abnf-HS5TGJTU-DnezvAFa.js +1 -0
  92. package/dist/public/assets/railroad-ebnf-LZEXJU2U-DHOzgi4x.js +1 -0
  93. package/dist/public/assets/railroad-peg-WCYAUIDC-C28W4OGa.js +1 -0
  94. package/dist/public/assets/{railroadDiagram-O6MQD6OU-BO2RgHB_.js → railroadDiagram-O6MQD6OU-uqpSPQV1.js} +1 -1
  95. package/dist/public/assets/{requirementDiagram-BXWQKSXE-DedAgdgA.js → requirementDiagram-BXWQKSXE-BlP0G3V7.js} +1 -1
  96. package/dist/public/assets/{sankeyDiagram-P5KCCOFB-XS4y44C-.js → sankeyDiagram-P5KCCOFB-BcxykWWD.js} +1 -1
  97. package/dist/public/assets/{sequenceDiagram-WJ2MYXX4-BgGPuhmx.js → sequenceDiagram-WJ2MYXX4-BleK5ON1.js} +1 -1
  98. package/dist/public/assets/{stateDiagram-D77RDMKH-t92luW0k.js → stateDiagram-D77RDMKH-C3Ojitqe.js} +1 -1
  99. package/dist/public/assets/stateDiagram-v2-MP3YSRHH-KLRu_NXG.js +1 -0
  100. package/dist/public/assets/{swimlanes-42K2YHIH-BTLMw_Zs.js → swimlanes-42K2YHIH-Bebu_xn2.js} +1 -1
  101. package/dist/public/assets/swimlanesDiagram-VR7AAH4N-BmvrlXmd.js +8 -0
  102. package/dist/public/assets/{switch-DFcV6j9m.js → switch-CaIM4dwn.js} +1 -1
  103. package/dist/public/assets/{timeline-definition-24CTP7MA-Buej45ei.js → timeline-definition-24CTP7MA-BKUpL8jk.js} +1 -1
  104. package/dist/public/assets/{treeView-Q6P3EWNA-CsmFV7PP.js → treeView-Q6P3EWNA-C7zCIwpV.js} +1 -1
  105. package/dist/public/assets/{treemap-WGGIJYW6-C7p2D31t.js → treemap-WGGIJYW6-6M3fRwft.js} +1 -1
  106. package/dist/public/assets/{tsMode-CkssN7v1.js → tsMode-DQRFLRMD.js} +1 -1
  107. package/dist/public/assets/{use-find-controls-o8dHk3Ai.js → use-find-controls-SI1t9mHH.js} +1 -1
  108. package/dist/public/assets/{use-ui-state-GQIbFm75.js → use-ui-state-D-3P_8P_.js} +1 -1
  109. package/dist/public/assets/{vennDiagram-4TSXK5OY-CabgcJgI.js → vennDiagram-4TSXK5OY-DxK4ozKb.js} +1 -1
  110. package/dist/public/assets/{wardley-WFR3VGLG-nDvUESM8.js → wardley-WFR3VGLG-B2zERAcS.js} +1 -1
  111. package/dist/public/assets/{wardleyDiagram-VM6X3IG4-lH7COUmu.js → wardleyDiagram-VM6X3IG4-Ctiwf9vH.js} +1 -1
  112. package/dist/public/assets/{ws-CvBEQDJB.js → ws-DK8JadaZ.js} +1 -1
  113. package/dist/public/assets/{xychartDiagram-S5SC5T6Z-c7fu3ePF.js → xychartDiagram-S5SC5T6Z-CxqvnL8v.js} +1 -1
  114. package/dist/public/index.html +2 -2
  115. package/package.json +1 -1
  116. package/dist/public/assets/App-4wHC7AhU.js +0 -2
  117. package/dist/public/assets/Dashboard-BTqiSGSr.js +0 -1
  118. package/dist/public/assets/SettingsDialog-BbqSqnMS.js +0 -8
  119. package/dist/public/assets/Terminal-DEVWotwh.js +0 -60
  120. package/dist/public/assets/Workspace-9Ke8tXhO.css +0 -1
  121. package/dist/public/assets/Workspace-D0vmiCsp.js +0 -20
  122. package/dist/public/assets/architecture-7GRP2DOG-B8geJhni.js +0 -1
  123. package/dist/public/assets/channel-B2boMkNJ.js +0 -1
  124. package/dist/public/assets/classDiagram-ZZMXUADV-D8W4ja-y.js +0 -1
  125. package/dist/public/assets/classDiagram-v2-VYDZK3BY-D8W4ja-y.js +0 -1
  126. package/dist/public/assets/eventmodeling-NTZA5JFV-DpPAlVka.js +0 -1
  127. package/dist/public/assets/flowDiagram-HODETNUW-emcn6VnU.js +0 -1
  128. package/dist/public/assets/index-BsSnxNPl.css +0 -2
  129. package/dist/public/assets/railroad-abnf-HS5TGJTU-Q_zhOWAR.js +0 -1
  130. package/dist/public/assets/railroad-ebnf-LZEXJU2U-BNV11-bx.js +0 -1
  131. package/dist/public/assets/railroad-peg-WCYAUIDC-D1whgDil.js +0 -1
  132. package/dist/public/assets/session-seed-exhI-dnY.js +0 -1
  133. package/dist/public/assets/stateDiagram-v2-MP3YSRHH-BVx0pqBn.js +0 -1
  134. package/dist/public/assets/swimlanesDiagram-VR7AAH4N-BaHPNnEm.js +0 -8
package/dist/index.js CHANGED
@@ -3756,7 +3756,7 @@ var init_wrapper = __esm({
3756
3756
 
3757
3757
  // src/lib/ws-client.ts
3758
3758
  function connectGateway(port, authority) {
3759
- return new Promise((resolve4, reject) => {
3759
+ return new Promise((resolve5, reject) => {
3760
3760
  const ws = new wrapper_default(`ws://127.0.0.1:${port}/ws`, {
3761
3761
  headers: { host: `localhost:${port}` }
3762
3762
  });
@@ -3781,7 +3781,7 @@ function connectGateway(port, authority) {
3781
3781
  }
3782
3782
  if (parsed.t === "authenticated") {
3783
3783
  clearTimeout(timer);
3784
- resolve4({
3784
+ resolve5({
3785
3785
  send(message) {
3786
3786
  if (resource.valid() && ws.readyState === wrapper_default.OPEN)
3787
3787
  ws.send(JSON.stringify(message));
@@ -3855,7 +3855,7 @@ async function attachSession(opts) {
3855
3855
  rows: streams.stdout.rows ?? 24
3856
3856
  });
3857
3857
  gateway.send({ t: "attach", session: session.id, term, ...dims2() });
3858
- return new Promise((resolve4) => {
3858
+ return new Promise((resolve5) => {
3859
3859
  let settled = false;
3860
3860
  const finish = (outcome) => {
3861
3861
  if (settled) return;
@@ -3864,7 +3864,7 @@ async function attachSession(opts) {
3864
3864
  stdin.removeListener("data", onStdin);
3865
3865
  unResize?.();
3866
3866
  gateway.close();
3867
- resolve4(outcome);
3867
+ resolve5(outcome);
3868
3868
  };
3869
3869
  gateway.onMessage((message) => {
3870
3870
  switch (message.t) {
@@ -3925,7 +3925,7 @@ import { createInterface } from "node:readline";
3925
3925
  import { Writable } from "node:stream";
3926
3926
 
3927
3927
  // ../shared/src/protocol.ts
3928
- var PROTOCOL_VERSION = { major: 19, minor: 0 };
3928
+ var PROTOCOL_VERSION = { major: 20, minor: 0 };
3929
3929
 
3930
3930
  // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
3931
3931
  var external_exports = {};
@@ -19807,19 +19807,25 @@ var remoteChunkSchema = external_exports.object({
19807
19807
  }).strict();
19808
19808
 
19809
19809
  // ../shared/src/api/cockpit-remote.ts
19810
- var cockpitRemoteRequestSchema = external_exports.union([
19810
+ var connectorLocalRequestSchema = external_exports.union([
19811
19811
  remoteAdminRequestSchema,
19812
+ external_exports.object({ t: external_exports.literal("delete_registration") }).strict()
19813
+ ]);
19814
+ var cockpitRemoteRequestSchema = external_exports.union([
19815
+ connectorLocalRequestSchema,
19812
19816
  external_exports.object({
19813
19817
  t: external_exports.literal("enable"),
19814
19818
  registration: external_exports.object({ service: remoteOriginSchema, app: remoteOriginSchema, code: remoteSecretSchema }).strict().optional()
19815
19819
  }).strict(),
19816
19820
  external_exports.object({ t: external_exports.literal("reset") }).strict()
19817
19821
  ]);
19822
+ var cockpitRegistrationCheckSchema = external_exports.object({ service: remoteOriginSchema, code: remoteSecretSchema }).strict();
19818
19823
  var cockpitRemoteStatusSchema = external_exports.object({
19819
19824
  availability: external_exports.enum(["ready", "not_installed", "upgrade_required"]),
19820
19825
  configured: external_exports.boolean(),
19821
19826
  enabled: external_exports.boolean(),
19822
19827
  connected: external_exports.boolean(),
19828
+ canDeleteRegistration: external_exports.boolean().optional(),
19823
19829
  supervisor: external_exports.enum(["systemd", "launchd"]).nullable(),
19824
19830
  host: remoteIdSchema.optional(),
19825
19831
  peer: remotePeerSchema.optional(),
@@ -19932,6 +19938,14 @@ var remoteLoginStateSchema = external_exports.object({
19932
19938
  var registerHostRequestSchema = external_exports.object({ label: remoteLabelSchema }).strict();
19933
19939
  var registrationResponseSchema = external_exports.object({ host: remoteIdSchema, code: remoteSecretSchema, expires: external_exports.number() }).strict();
19934
19940
  var redeemRegistrationSchema = external_exports.object({ code: remoteSecretSchema }).strict();
19941
+ var desktopRegistrationSchema = external_exports.object({
19942
+ challenge: remoteSecretSchema,
19943
+ label: remoteLabelSchema,
19944
+ service: remoteOriginSchema,
19945
+ app: remoteOriginSchema,
19946
+ expires: external_exports.number().int().positive()
19947
+ }).strict();
19948
+ var registrationStatusSchema = external_exports.object({ ready: external_exports.boolean() }).strict();
19935
19949
  var connectorRegistrationSchema = external_exports.object({
19936
19950
  host: remoteIdSchema,
19937
19951
  account: remoteAccountSchema,
@@ -19987,7 +20001,7 @@ var LocalTransport = class {
19987
20001
  kind = "local";
19988
20002
  label = "this machine";
19989
20003
  exec(command, opts = {}) {
19990
- return new Promise((resolve4) => {
20004
+ return new Promise((resolve5) => {
19991
20005
  const child = spawn("sh", ["-c", command], { stdio: ["pipe", "pipe", "pipe"] });
19992
20006
  let stdout = "";
19993
20007
  let stderr = "";
@@ -20004,11 +20018,11 @@ var LocalTransport = class {
20004
20018
  child.stderr.on("data", (chunk) => stderr += chunk.toString());
20005
20019
  child.on("error", (err) => {
20006
20020
  if (timer) clearTimeout(timer);
20007
- resolve4({ code: -1, stdout, stderr: stderr + String(err) });
20021
+ resolve5({ code: -1, stdout, stderr: stderr + String(err) });
20008
20022
  });
20009
20023
  child.on("close", (code) => {
20010
20024
  if (timer) clearTimeout(timer);
20011
- resolve4({ code: code ?? -1, stdout, stderr });
20025
+ resolve5({ code: code ?? -1, stdout, stderr });
20012
20026
  });
20013
20027
  child.stdin.on("error", () => {
20014
20028
  });
@@ -20102,7 +20116,7 @@ var SshTransport = class {
20102
20116
  * live control socket behind.
20103
20117
  */
20104
20118
  open() {
20105
- return new Promise((resolve4, reject) => {
20119
+ return new Promise((resolve5, reject) => {
20106
20120
  const child = spawn2(this.ssh, this.args(this.host, "true"), {
20107
20121
  // A GUI has no useful inherited terminal; OpenSSH calls its askpass
20108
20122
  // helper instead. The terminal CLI keeps byte-for-byte inheritance.
@@ -20114,7 +20128,7 @@ var SshTransport = class {
20114
20128
  (err) => reject(new CliError("ssh_unreachable", `could not run ${this.ssh}: ${err.message}`))
20115
20129
  );
20116
20130
  child.on("close", (code) => {
20117
- if (code === 0) resolve4();
20131
+ if (code === 0) resolve5();
20118
20132
  else {
20119
20133
  reject(
20120
20134
  new CliError(
@@ -20130,13 +20144,13 @@ var SshTransport = class {
20130
20144
  /** Whether the master connection is still alive (-O check). */
20131
20145
  isAlive() {
20132
20146
  if (!this.hasControlMaster) return Promise.resolve(true);
20133
- return new Promise((resolve4) => {
20147
+ return new Promise((resolve5) => {
20134
20148
  const child = spawn2(this.ssh, this.args("-O", "check", this.host), {
20135
20149
  stdio: "ignore",
20136
20150
  env: this.spawnEnv()
20137
20151
  });
20138
- child.on("error", () => resolve4(false));
20139
- child.on("close", (code) => resolve4(code === 0));
20152
+ child.on("error", () => resolve5(false));
20153
+ child.on("close", (code) => resolve5(code === 0));
20140
20154
  });
20141
20155
  }
20142
20156
  /**
@@ -20149,18 +20163,18 @@ var SshTransport = class {
20149
20163
  */
20150
20164
  cancelForward(localPort, remotePort) {
20151
20165
  if (!this.hasControlMaster) return Promise.resolve();
20152
- return new Promise((resolve4) => {
20166
+ return new Promise((resolve5) => {
20153
20167
  const spec = `${localPort}:127.0.0.1:${remotePort}`;
20154
20168
  const child = spawn2(this.ssh, this.args("-O", "cancel", "-L", spec, this.host), {
20155
20169
  stdio: "ignore",
20156
20170
  env: this.spawnEnv()
20157
20171
  });
20158
- child.on("error", () => resolve4());
20159
- child.on("close", () => resolve4());
20172
+ child.on("error", () => resolve5());
20173
+ child.on("close", () => resolve5());
20160
20174
  });
20161
20175
  }
20162
20176
  exec(command, opts = {}) {
20163
- return new Promise((resolve4) => {
20177
+ return new Promise((resolve5) => {
20164
20178
  const child = spawn2(this.ssh, this.args(this.host, "--", `sh -c ${shellQuote(command)}`), {
20165
20179
  stdio: ["pipe", "pipe", "pipe"],
20166
20180
  env: this.spawnEnv()
@@ -20180,11 +20194,11 @@ var SshTransport = class {
20180
20194
  child.stderr.on("data", (chunk) => stderr += chunk.toString());
20181
20195
  child.on("error", (err) => {
20182
20196
  if (timer) clearTimeout(timer);
20183
- resolve4({ code: -1, stdout, stderr: stderr + String(err) });
20197
+ resolve5({ code: -1, stdout, stderr: stderr + String(err) });
20184
20198
  });
20185
20199
  child.on("close", (code) => {
20186
20200
  if (timer) clearTimeout(timer);
20187
- resolve4({ code: code ?? -1, stdout, stderr });
20201
+ resolve5({ code: code ?? -1, stdout, stderr });
20188
20202
  });
20189
20203
  child.stdin.on("error", () => {
20190
20204
  });
@@ -20204,11 +20218,11 @@ var SshTransport = class {
20204
20218
  });
20205
20219
  let stdout = "";
20206
20220
  let stderr = "";
20207
- const result = new Promise((resolve4) => {
20221
+ const result = new Promise((resolve5) => {
20208
20222
  child.stdout.on("data", (chunk) => stdout += chunk.toString());
20209
20223
  child.stderr.on("data", (chunk) => stderr += chunk.toString());
20210
- child.on("error", (err) => resolve4({ code: -1, stdout, stderr: stderr + String(err) }));
20211
- child.on("close", (code) => resolve4({ code: code ?? -1, stdout, stderr }));
20224
+ child.on("error", (err) => resolve5({ code: -1, stdout, stderr: stderr + String(err) }));
20225
+ child.on("close", (code) => resolve5({ code: code ?? -1, stdout, stderr }));
20212
20226
  });
20213
20227
  return {
20214
20228
  result,
@@ -20223,14 +20237,14 @@ var SshTransport = class {
20223
20237
  }
20224
20238
  async copyTo(localPath, destPath) {
20225
20239
  await this.exec(`mkdir -p $(dirname ${destPath})`, { timeoutMs: 15e3 });
20226
- await new Promise((resolve4, reject) => {
20240
+ await new Promise((resolve5, reject) => {
20227
20241
  const child = spawn2(this.scp, [...this.controlArgs, localPath, `${this.host}:${destPath}`], {
20228
20242
  stdio: ["ignore", "ignore", "inherit"],
20229
20243
  env: this.spawnEnv()
20230
20244
  });
20231
20245
  child.on("error", reject);
20232
20246
  child.on("close", (code) => {
20233
- if (code === 0) resolve4();
20247
+ if (code === 0) resolve5();
20234
20248
  else reject(new CliError("ssh_unreachable", `scp to ${this.host} failed (exit ${code})`));
20235
20249
  });
20236
20250
  });
@@ -20331,7 +20345,7 @@ async function registrationCode() {
20331
20345
  const readline = createInterface({ input: process.stdin, output: silent, terminal: true });
20332
20346
  try {
20333
20347
  return remoteSecretSchema.parse(
20334
- await new Promise((resolve4) => readline.question("", resolve4))
20348
+ await new Promise((resolve5) => readline.question("", resolve5))
20335
20349
  );
20336
20350
  } finally {
20337
20351
  readline.close();
@@ -20733,6 +20747,9 @@ import { createHash, randomBytes } from "node:crypto";
20733
20747
  import {
20734
20748
  chmodSync,
20735
20749
  closeSync,
20750
+ constants,
20751
+ fchmodSync,
20752
+ fstatSync,
20736
20753
  fsyncSync,
20737
20754
  lstatSync,
20738
20755
  mkdirSync as mkdirSync3,
@@ -20744,7 +20761,7 @@ import {
20744
20761
  writeFileSync
20745
20762
  } from "node:fs";
20746
20763
  import { connect, createServer } from "node:net";
20747
- import { dirname as dirname2, join as join2 } from "node:path";
20764
+ import { dirname as dirname2, join as join2, resolve } from "node:path";
20748
20765
  var digest = (value) => createHash("sha256").update(value).digest("hex");
20749
20766
  var secret = (prefix = "") => prefix + randomBytes(32).toString("hex");
20750
20767
  function privatePath(path, directory = false) {
@@ -20757,6 +20774,27 @@ function privateDirectory(path) {
20757
20774
  mkdirSync3(path, { recursive: true, mode: 448 });
20758
20775
  privatePath(path, true);
20759
20776
  }
20777
+ function initialisePrivateHome(home) {
20778
+ const path = resolve(home);
20779
+ mkdirSync3(path, { recursive: true, mode: 448 });
20780
+ if (process.platform === "win32") {
20781
+ privatePath(path, true);
20782
+ return;
20783
+ }
20784
+ const fd = openSync(path, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
20785
+ try {
20786
+ const st = fstatSync(fd);
20787
+ if (!st.isDirectory() || st.uid !== process.getuid() || (st.mode & 18) !== 0) {
20788
+ throw new Error(
20789
+ `Puddle home must be owned by the current user and not writable by other users: ${path}`
20790
+ );
20791
+ }
20792
+ if ((st.mode & 63) !== 0) fchmodSync(fd, 448);
20793
+ } finally {
20794
+ closeSync(fd);
20795
+ }
20796
+ privatePath(path, true);
20797
+ }
20760
20798
  function atomicPrivateJson(path, value) {
20761
20799
  privateDirectory(dirname2(path));
20762
20800
  const tmp = `${path}.${secret()}.tmp`;
@@ -20778,7 +20816,7 @@ function readPrivateJson(path) {
20778
20816
  return JSON.parse(readFileSync2(path, "utf8"));
20779
20817
  }
20780
20818
  function ipcPath(home, scope) {
20781
- privateDirectory(home);
20819
+ initialisePrivateHome(home);
20782
20820
  const key = digest(`${realpathSync(home)}\0${scope}`).slice(0, 24);
20783
20821
  if (process.platform === "win32") return `\\\\.\\pipe\\puddle-${key}`;
20784
20822
  const dir = join2("/tmp", `puddle-${process.getuid()}-${key}`);
@@ -20791,14 +20829,14 @@ async function listenPrivate(path, onConnection) {
20791
20829
  privatePath(path);
20792
20830
  const before = lstatSync(path);
20793
20831
  if (!before.isSocket()) throw new Error("Puddle control path is not a socket");
20794
- const stale = await new Promise((resolve4, reject) => {
20832
+ const stale = await new Promise((resolve5, reject) => {
20795
20833
  const probe = connect(path);
20796
20834
  probe.once("connect", () => {
20797
20835
  probe.destroy();
20798
- resolve4(false);
20836
+ resolve5(false);
20799
20837
  });
20800
20838
  probe.once("error", (err) => {
20801
- if (err.code === "ECONNREFUSED" || err.code === "ENOENT") resolve4(true);
20839
+ if (err.code === "ECONNREFUSED" || err.code === "ENOENT") resolve5(true);
20802
20840
  else reject(err);
20803
20841
  });
20804
20842
  });
@@ -20811,11 +20849,11 @@ async function listenPrivate(path, onConnection) {
20811
20849
  }
20812
20850
  }
20813
20851
  const server = createServer(onConnection);
20814
- await new Promise((resolve4, reject) => {
20852
+ await new Promise((resolve5, reject) => {
20815
20853
  server.once("error", reject);
20816
20854
  server.listen(path, () => {
20817
20855
  server.off("error", reject);
20818
- resolve4();
20856
+ resolve5();
20819
20857
  });
20820
20858
  });
20821
20859
  if (process.platform !== "win32") chmodSync(path, 384);
@@ -20929,7 +20967,7 @@ var HostControlClient = class {
20929
20967
  }
20930
20968
  this.channel = channel;
20931
20969
  this.until = performance.now() + CONNECTION_POLICY.leaseMs;
20932
- await new Promise((resolve4, reject) => {
20970
+ await new Promise((resolve5, reject) => {
20933
20971
  let pendingAt = null;
20934
20972
  let initial = true;
20935
20973
  const send = (message, sentAt = performance.now()) => {
@@ -20982,7 +21020,7 @@ var HostControlClient = class {
20982
21020
  if (this.channel !== channel) return;
20983
21021
  this.status = "ready";
20984
21022
  this.emit();
20985
- resolve4();
21023
+ resolve5();
20986
21024
  }).catch(() => channel.destroy());
20987
21025
  }
20988
21026
  },
@@ -21103,7 +21141,7 @@ async function inspectHostLocally(home) {
21103
21141
  }
21104
21142
  const socket = connect2(path);
21105
21143
  try {
21106
- const grant = await new Promise((resolve4, reject) => {
21144
+ const grant = await new Promise((resolve5, reject) => {
21107
21145
  socket.setTimeout(5e3, () => socket.destroy(new Error("Host inspection timed out")));
21108
21146
  socket.once("error", reject);
21109
21147
  socket.once("close", () => reject(new Error("Host control closed")));
@@ -21113,7 +21151,7 @@ async function inspectHostLocally(home) {
21113
21151
  const message = controlResponseSchema.parse(value);
21114
21152
  if (message.t !== "authority" || !message.token)
21115
21153
  throw new Error("Host authority unavailable");
21116
- resolve4(message);
21154
+ resolve5(message);
21117
21155
  },
21118
21156
  () => socket.destroy(new Error("Invalid host control response"))
21119
21157
  );
@@ -21254,12 +21292,12 @@ import {
21254
21292
  renameSync as renameSync2,
21255
21293
  writeFileSync as writeFileSync2
21256
21294
  } from "node:fs";
21257
- import { dirname as dirname6, join as join7, resolve } from "node:path";
21295
+ import { dirname as dirname6, join as join7, resolve as resolve2 } from "node:path";
21258
21296
 
21259
21297
  // src/lib/desktop-update.ts
21260
21298
  import { createHash as createHash2 } from "node:crypto";
21261
21299
  import { spawn as spawn4 } from "node:child_process";
21262
- import { constants, createReadStream, createWriteStream } from "node:fs";
21300
+ import { constants as constants2, createReadStream, createWriteStream } from "node:fs";
21263
21301
  import { access, chmod, mkdir, readdir, rm, writeFile } from "node:fs/promises";
21264
21302
  import { dirname as dirname5, join as join6 } from "node:path";
21265
21303
  import { Readable } from "node:stream";
@@ -21271,7 +21309,7 @@ import { readFileSync as readFileSync4 } from "node:fs";
21271
21309
  import { dirname as dirname4, join as join5 } from "node:path";
21272
21310
  import { fileURLToPath as fileURLToPath2 } from "node:url";
21273
21311
  function cliVersion() {
21274
- if (true) return "0.2.0";
21312
+ if (true) return "0.2.2";
21275
21313
  const here = dirname4(fileURLToPath2(import.meta.url));
21276
21314
  for (const candidate of [
21277
21315
  join5(here, "..", "..", "package.json"),
@@ -21539,7 +21577,7 @@ async function desktopAppInstallPath(opts = {}) {
21539
21577
  const systemApplications = opts.systemApplicationsDir ?? "/Applications";
21540
21578
  const canWrite = opts.canWrite ?? (async (path) => {
21541
21579
  try {
21542
- await access(path, constants.W_OK);
21580
+ await access(path, constants2.W_OK);
21543
21581
  return true;
21544
21582
  } catch {
21545
21583
  return false;
@@ -21551,12 +21589,12 @@ async function desktopAppInstallPath(opts = {}) {
21551
21589
  return join6(userApplications, "Puddle.app");
21552
21590
  }
21553
21591
  function isDesktopAppRunning(appPath) {
21554
- return new Promise((resolve4) => {
21592
+ return new Promise((resolve5) => {
21555
21593
  const child = spawn4("/usr/bin/pgrep", ["-f", `${appPath}/Contents/MacOS/`], {
21556
21594
  stdio: "ignore"
21557
21595
  });
21558
- child.on("error", () => resolve4(false));
21559
- child.on("exit", (code) => resolve4(code === 0));
21596
+ child.on("error", () => resolve5(false));
21597
+ child.on("exit", (code) => resolve5(code === 0));
21560
21598
  });
21561
21599
  }
21562
21600
  function fileSha256(path) {
@@ -21564,12 +21602,12 @@ function fileSha256(path) {
21564
21602
  return pipeline(createReadStream(path), hash2).then(() => hash2.digest("hex"));
21565
21603
  }
21566
21604
  function run(command, args) {
21567
- return new Promise((resolve4, reject) => {
21605
+ return new Promise((resolve5, reject) => {
21568
21606
  const child = spawn4(command, args, { stdio: "ignore" });
21569
21607
  child.on("error", reject);
21570
21608
  child.on(
21571
21609
  "exit",
21572
- (code) => code === 0 ? resolve4() : reject(new CliError("not_installed", `${command} exited with ${code ?? "signal"}`))
21610
+ (code) => code === 0 ? resolve5() : reject(new CliError("not_installed", `${command} exited with ${code ?? "signal"}`))
21573
21611
  );
21574
21612
  });
21575
21613
  }
@@ -21644,7 +21682,9 @@ var RELEASE_PROTOCOLS = {
21644
21682
  "0.1.11": { major: 17, minor: 3 },
21645
21683
  "0.1.12": { major: 17, minor: 3 },
21646
21684
  "0.1.13": { major: 17, minor: 3 },
21647
- "0.2.0": { major: 19, minor: 0 }
21685
+ "0.2.0": { major: 19, minor: 0 },
21686
+ "0.2.1": { major: 19, minor: 0 },
21687
+ "0.2.2": { major: 20, minor: 0 }
21648
21688
  };
21649
21689
  function validProtocol(value) {
21650
21690
  if (typeof value !== "object" || value === null) return false;
@@ -21732,7 +21772,7 @@ async function installedComponentVersions(opts = {}) {
21732
21772
  };
21733
21773
  }
21734
21774
  }
21735
- const legacyLinuxPath = resolve(home, "..", "puddle", "Puddle.AppImage");
21775
+ const legacyLinuxPath = resolve2(home, "..", "puddle", "Puddle.AppImage");
21736
21776
  const legacyLinuxDesktop = desktopInstallation === null && (opts.platform ?? process.platform) === "linux" && existsSync2(legacyLinuxPath);
21737
21777
  const desktopProtocol = desktopInstallation?.protocol ?? (desktopInstallation ? componentProtocolForVersion(desktopInstallation.version) : void 0);
21738
21778
  const desktop = desktopInstallation !== null ? {
@@ -21761,7 +21801,7 @@ import { randomUUID } from "node:crypto";
21761
21801
 
21762
21802
  // src/lib/bootstrap.ts
21763
21803
  import { existsSync as existsSync3, readFileSync as readFileSync6 } from "node:fs";
21764
- import { dirname as dirname7, join as join8, resolve as resolve2 } from "node:path";
21804
+ import { dirname as dirname7, join as join8, resolve as resolve3 } from "node:path";
21765
21805
  import { fileURLToPath as fileURLToPath3 } from "node:url";
21766
21806
  init_types();
21767
21807
  async function installedVersion(transport) {
@@ -21780,9 +21820,9 @@ async function installDaemon(transport, opts = {}) {
21780
21820
  throw new CliError("not_installed", `tarball not found: ${opts.tarball}`);
21781
21821
  }
21782
21822
  if (transport.kind === "local") {
21783
- args.push("--tarball", resolve2(opts.tarball));
21823
+ args.push("--tarball", resolve3(opts.tarball));
21784
21824
  const localSums = `${opts.tarball}.sha256`;
21785
- if (existsSync3(localSums)) args.push("--sums", resolve2(localSums));
21825
+ if (existsSync3(localSums)) args.push("--sums", resolve3(localSums));
21786
21826
  } else {
21787
21827
  const base = opts.tarball.split("/").pop() ?? "puddled.tar.gz";
21788
21828
  const destTarball = `.puddle/cache/${base}`;
@@ -21847,22 +21887,22 @@ function readInstallScript() {
21847
21887
  // src/lib/net.ts
21848
21888
  import { connect as connect4, createServer as createServer2 } from "node:net";
21849
21889
  function findFreePort() {
21850
- return new Promise((resolve4, reject) => {
21890
+ return new Promise((resolve5, reject) => {
21851
21891
  const srv = createServer2();
21852
21892
  srv.once("error", reject);
21853
21893
  srv.listen(0, "127.0.0.1", () => {
21854
21894
  const address = srv.address();
21855
21895
  const port = typeof address === "object" && address !== null ? address.port : 0;
21856
- srv.close(() => resolve4(port));
21896
+ srv.close(() => resolve5(port));
21857
21897
  });
21858
21898
  });
21859
21899
  }
21860
21900
  function tcpListening(port, timeoutMs = 500) {
21861
- return new Promise((resolve4) => {
21901
+ return new Promise((resolve5) => {
21862
21902
  const sock = connect4({ host: "127.0.0.1", port });
21863
21903
  const done = (ok) => {
21864
21904
  sock.destroy();
21865
- resolve4(ok);
21905
+ resolve5(ok);
21866
21906
  };
21867
21907
  sock.setTimeout(timeoutMs, () => done(false));
21868
21908
  sock.once("connect", () => done(true));
@@ -22311,7 +22351,7 @@ async function startLauncher(home, identity, invite) {
22311
22351
  path,
22312
22352
  close: async () => {
22313
22353
  for (const socket of sockets) socket.destroy();
22314
- await new Promise((resolve4) => server.close(() => resolve4()));
22354
+ await new Promise((resolve5) => server.close(() => resolve5()));
22315
22355
  }
22316
22356
  };
22317
22357
  }
@@ -22321,14 +22361,14 @@ async function requestInvitation(home, path) {
22321
22361
  const stored = readPrivateJson(secretFile(home, path));
22322
22362
  pipeSecret = stored.secret;
22323
22363
  } else privatePath(path);
22324
- return new Promise((resolve4, reject) => {
22364
+ return new Promise((resolve5, reject) => {
22325
22365
  const socket = connect5(path);
22326
22366
  socket.setTimeout(5e3, () => socket.destroy(new Error("Launcher did not answer")));
22327
22367
  jsonLines(
22328
22368
  socket,
22329
22369
  (value) => {
22330
22370
  const message = launcherResponseSchema.parse(value);
22331
- resolve4(message.url);
22371
+ resolve5(message.url);
22332
22372
  socket.end();
22333
22373
  },
22334
22374
  () => socket.destroy(new Error("Invalid launcher reply"))
@@ -22548,7 +22588,7 @@ function writeStore(file2, store) {
22548
22588
  renameSync3(tmp, file2);
22549
22589
  }
22550
22590
  function readBody(req) {
22551
- return new Promise((resolve4, reject) => {
22591
+ return new Promise((resolve5, reject) => {
22552
22592
  let size = 0;
22553
22593
  const chunks = [];
22554
22594
  req.on("data", (chunk) => {
@@ -22560,7 +22600,7 @@ function readBody(req) {
22560
22600
  }
22561
22601
  chunks.push(chunk);
22562
22602
  });
22563
- req.on("end", () => resolve4(Buffer.concat(chunks).toString("utf8")));
22603
+ req.on("end", () => resolve5(Buffer.concat(chunks).toString("utf8")));
22564
22604
  req.on("error", reject);
22565
22605
  });
22566
22606
  }
@@ -22598,7 +22638,7 @@ function handleLocalSync(req, res, opts, authorised) {
22598
22638
 
22599
22639
  // src/lib/serve/static.ts
22600
22640
  import { createReadStream as createReadStream2, existsSync as existsSync4, statSync } from "node:fs";
22601
- import { extname, join as join11, normalize, resolve as resolve3, sep } from "node:path";
22641
+ import { extname, join as join11, normalize, resolve as resolve4, sep } from "node:path";
22602
22642
  var MIME = {
22603
22643
  ".html": "text/html; charset=utf-8",
22604
22644
  ".js": "text/javascript; charset=utf-8",
@@ -22613,7 +22653,7 @@ var MIME = {
22613
22653
  ".map": "application/json"
22614
22654
  };
22615
22655
  function createStaticHandler(rootDir) {
22616
- const root = resolve3(rootDir);
22656
+ const root = resolve4(rootDir);
22617
22657
  return (req, res) => {
22618
22658
  if (req.method !== "GET" && req.method !== "HEAD") {
22619
22659
  res.writeHead(405, { allow: "GET, HEAD" }).end();
@@ -23103,6 +23143,41 @@ function remoteAccessHandler(control) {
23103
23143
  };
23104
23144
  }
23105
23145
 
23146
+ // src/lib/serve/remote-registration.ts
23147
+ async function checkRemoteRegistration(req, res, authorised) {
23148
+ if (req.method !== "POST") return fail(res, 405, "method_not_allowed");
23149
+ const { service, code } = cockpitRegistrationCheckSchema.parse(await readJson(req));
23150
+ if (!authorised()) return fail(res, 401, "browser_rejected");
23151
+ try {
23152
+ const response = await fetch(`${service}/remote/registration-status`, {
23153
+ method: "POST",
23154
+ headers: { "content-type": "application/json" },
23155
+ body: JSON.stringify({ code }),
23156
+ redirect: "error",
23157
+ signal: AbortSignal.timeout(5e3)
23158
+ });
23159
+ if (!response.ok) {
23160
+ await response.body?.cancel();
23161
+ throw new Error("Service unavailable");
23162
+ }
23163
+ let body = "";
23164
+ for await (const chunk of response.body ?? []) {
23165
+ body += Buffer.from(chunk).toString("utf8");
23166
+ if (body.length > 1024) throw new Error("Response too large");
23167
+ }
23168
+ const status = registrationStatusSchema.parse(JSON.parse(body));
23169
+ if (!authorised()) return fail(res, 401, "browser_rejected");
23170
+ json2(res, 200, status);
23171
+ } catch {
23172
+ fail(
23173
+ res,
23174
+ 503,
23175
+ "registration_unavailable",
23176
+ "Could not check browser sign-in. Check the relay address and update the deployed service, then try again."
23177
+ );
23178
+ }
23179
+ }
23180
+
23106
23181
  // src/lib/serve/ui-server.ts
23107
23182
  var DEFAULT_UI_PORT = 7433;
23108
23183
  var MAX_PORT_PROBES = 50;
@@ -23162,6 +23237,10 @@ async function startUiServer(opts) {
23162
23237
  return handleLocalSync(req, res, opts.localSync, () => browsers.valid(browser));
23163
23238
  if (url2.pathname === "/cockpit/remote")
23164
23239
  return handleRemoteAccess(req, res, () => browsers.valid(browser));
23240
+ if (url2.pathname === "/cockpit/remote/registration") {
23241
+ if (!opts.remoteAccess) return fail(res, 404, "remote_controls_unavailable");
23242
+ return checkRemoteRegistration(req, res, () => browsers.valid(browser));
23243
+ }
23165
23244
  if (url2.pathname === "/cockpit/refresh" && req.method === "POST") {
23166
23245
  if (!opts.control) return fail(res, 404, "refresh_unavailable");
23167
23246
  const body = cockpitRefreshRequestSchema.parse(await readJson(req));
@@ -23246,8 +23325,8 @@ async function startUiServer(opts) {
23246
23325
  browsers.close();
23247
23326
  bridge.close();
23248
23327
  tracker.destroyAll();
23249
- await new Promise((resolve4) => {
23250
- server.close(() => resolve4());
23328
+ await new Promise((resolve5) => {
23329
+ server.close(() => resolve5());
23251
23330
  server.closeAllConnections();
23252
23331
  });
23253
23332
  }
@@ -23257,15 +23336,15 @@ async function listen(server, startPort, strict, avoidPort) {
23257
23336
  for (let probe = 0; probe < MAX_PORT_PROBES; probe += 1) {
23258
23337
  const port = startPort + probe;
23259
23338
  if (!strict && port === avoidPort) continue;
23260
- const ok = await new Promise((resolve4, rejectListen) => {
23339
+ const ok = await new Promise((resolve5, rejectListen) => {
23261
23340
  const onError = (err) => {
23262
23341
  server.off("listening", onListening);
23263
- if (err.code === "EADDRINUSE") resolve4(false);
23342
+ if (err.code === "EADDRINUSE") resolve5(false);
23264
23343
  else rejectListen(err);
23265
23344
  };
23266
23345
  const onListening = () => {
23267
23346
  server.off("error", onError);
23268
- resolve4(true);
23347
+ resolve5(true);
23269
23348
  };
23270
23349
  server.once("error", onError);
23271
23350
  server.once("listening", onListening);
@@ -23292,21 +23371,24 @@ var RemoteAccessControl = class {
23292
23371
  constructor(transport) {
23293
23372
  this.transport = transport;
23294
23373
  }
23295
- async availability() {
23374
+ async capabilities() {
23296
23375
  const result = await this.transport.exec(
23297
23376
  `if test -f ${hostPaths.current}/daemon/connector.mjs; then ${binary} --version; else exit 44; fi`,
23298
23377
  { timeoutMs: 1e4 }
23299
23378
  );
23300
- if (result.code === 44) return "not_installed";
23379
+ if (result.code === 44) return { availability: "not_installed", canDeleteRegistration: false };
23301
23380
  if (result.code !== 0)
23302
23381
  throw new Error("Host control is unavailable. Check the host connection.");
23303
- return result.stdout.includes("cockpit controls 1") ? "ready" : "upgrade_required";
23382
+ return {
23383
+ availability: result.stdout.includes("cockpit controls 1") ? "ready" : "upgrade_required",
23384
+ canDeleteRegistration: result.stdout.includes("delete registration 1")
23385
+ };
23304
23386
  }
23305
23387
  async status() {
23306
- const availability = await this.availability();
23307
- if (availability !== "ready")
23388
+ const capabilities = await this.capabilities();
23389
+ if (capabilities.availability !== "ready")
23308
23390
  return {
23309
- availability,
23391
+ ...capabilities,
23310
23392
  configured: false,
23311
23393
  enabled: false,
23312
23394
  connected: false,
@@ -23315,12 +23397,15 @@ var RemoteAccessControl = class {
23315
23397
  };
23316
23398
  const result = await this.transport.exec(`${binary} --inspect`, { timeoutMs: 1e4 });
23317
23399
  if (result.code !== 0) throw new Error("Could not read remote access status on this host.");
23318
- return cockpitRemoteStatusSchema.parse(JSON.parse(result.stdout));
23400
+ return cockpitRemoteStatusSchema.parse({ ...JSON.parse(result.stdout), ...capabilities });
23319
23401
  }
23320
23402
  async request(value, authorised) {
23321
23403
  const request = cockpitRemoteRequestSchema.parse(value);
23322
- if (await this.availability() !== "ready")
23404
+ const capabilities = await this.capabilities();
23405
+ if (capabilities.availability !== "ready")
23323
23406
  throw new Error("Upgrade the daemon on this host to manage remote access here.");
23407
+ if (request.t === "delete_registration" && !capabilities.canDeleteRegistration)
23408
+ throw new Error("Upgrade the daemon on this host to delete its remote registration.");
23324
23409
  if (!authorised()) throw new Error("Browser authorisation expired before dispatch.");
23325
23410
  const flag = request.t === "enable" ? "--configure" : request.t === "reset" ? "--reset" : "--admin";
23326
23411
  const payload = request.t === "enable" ? { ...request.registration, managed: true } : request;
@@ -24182,7 +24267,7 @@ async function ask(question, def) {
24182
24267
  const rl = createInterface2({ input: process.stdin, output: process.stdout });
24183
24268
  try {
24184
24269
  const answer = await new Promise(
24185
- (resolve4) => rl.question(`${question} [${def}] `, resolve4)
24270
+ (resolve5) => rl.question(`${question} [${def}] `, resolve5)
24186
24271
  );
24187
24272
  return answer.trim() === "" ? def : answer.trim();
24188
24273
  } finally {
@@ -24201,7 +24286,7 @@ async function confirm(question, opts = {}) {
24201
24286
  const rl = createInterface2({ input: process.stdin, output: process.stdout });
24202
24287
  try {
24203
24288
  const answer = await new Promise(
24204
- (resolve4) => rl.question(`${question} [y/N] `, resolve4)
24289
+ (resolve5) => rl.question(`${question} [y/N] `, resolve5)
24205
24290
  );
24206
24291
  return /^y(es)?$/i.test(answer.trim());
24207
24292
  } finally {
@@ -24320,7 +24405,7 @@ async function runUpgrade(cmd, logger) {
24320
24405
  function upgradeCli(version2, logger) {
24321
24406
  const spec = `@puddle-code/cli@${version2 ?? "latest"}`;
24322
24407
  logger.info(`puddle CLI ${cliVersion()} \u2014 asking npm for ${version2 ?? "the latest release"}`);
24323
- return new Promise((resolve4, reject) => {
24408
+ return new Promise((resolve5, reject) => {
24324
24409
  const child = spawn7("npm", ["install", "-g", spec], { stdio: "inherit" });
24325
24410
  child.on(
24326
24411
  "error",
@@ -24335,7 +24420,7 @@ function upgradeCli(version2, logger) {
24335
24420
  child.on("exit", (code) => {
24336
24421
  if (code === 0) {
24337
24422
  logger.info("done \u2014 `puddle --version` shows the installed version");
24338
- resolve4(0);
24423
+ resolve5(0);
24339
24424
  } else {
24340
24425
  reject(new CliError("not_installed", `npm install exited with ${code ?? "a signal"}`));
24341
24426
  }
@@ -24458,10 +24543,10 @@ async function runRemove(cmd, logger) {
24458
24543
  }
24459
24544
  }
24460
24545
  async function removeCli(yes, logger) {
24461
- const managed = await new Promise((resolve4) => {
24546
+ const managed = await new Promise((resolve5) => {
24462
24547
  const child = spawn7("npm", ["ls", "-g", "@puddle-code/cli", "--depth=0"], { stdio: "ignore" });
24463
- child.on("error", () => resolve4(false));
24464
- child.on("exit", (code) => resolve4(code === 0));
24548
+ child.on("error", () => resolve5(false));
24549
+ child.on("exit", (code) => resolve5(code === 0));
24465
24550
  });
24466
24551
  if (!managed) {
24467
24552
  throw new CliError(
@@ -24478,13 +24563,13 @@ async function removeCli(yes, logger) {
24478
24563
  logger.info("nothing removed");
24479
24564
  return 0;
24480
24565
  }
24481
- return new Promise((resolve4, reject) => {
24566
+ return new Promise((resolve5, reject) => {
24482
24567
  const child = spawn7("npm", ["uninstall", "-g", "@puddle-code/cli"], { stdio: "inherit" });
24483
24568
  child.on("error", () => reject(new CliError("not_installed", "npm is not on PATH")));
24484
24569
  child.on("exit", (code) => {
24485
24570
  if (code === 0) {
24486
24571
  logger.info("removed \u2014 daemons keep running (puddle remove daemon uninstalls one)");
24487
- resolve4(0);
24572
+ resolve5(0);
24488
24573
  } else {
24489
24574
  reject(new CliError("not_installed", `npm uninstall exited with ${code ?? "a signal"}`));
24490
24575
  }
@@ -24673,7 +24758,7 @@ async function openTarget(host) {
24673
24758
  };
24674
24759
  }
24675
24760
  function runUntilInterrupted(stop, farewell) {
24676
- return new Promise((resolve4) => {
24761
+ return new Promise((resolve5) => {
24677
24762
  let stopping = false;
24678
24763
  process.on("SIGINT", () => {
24679
24764
  if (stopping) process.exit(130);
@@ -24681,10 +24766,10 @@ function runUntilInterrupted(stop, farewell) {
24681
24766
  process.stderr.write(`
24682
24767
  ${farewell}
24683
24768
  `);
24684
- void stop().then(resolve4);
24769
+ void stop().then(resolve5);
24685
24770
  });
24686
24771
  process.on("SIGTERM", () => {
24687
- void stop().then(resolve4);
24772
+ void stop().then(resolve5);
24688
24773
  });
24689
24774
  });
24690
24775
  }