skydive-cli 0.5.0-beta.31 → 0.5.0-beta.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +20 -0
  2. package/dist/js/api-DQCaztBg.mjs +315 -0
  3. package/dist/js/{billing-blocked-Dgu5-oDy.mjs → billing-blocked-SE6tySLd.mjs} +1 -1
  4. package/dist/js/bin.mjs +214 -50
  5. package/dist/js/{boot-iaVSnd7h.mjs → boot-C5HJfwRS.mjs} +17 -14
  6. package/dist/js/chunk-BbwQpWto.mjs +33 -0
  7. package/dist/js/{client-DbqRBquD.mjs → client-d6K9qm6B.mjs} +70 -2
  8. package/dist/js/client-yz3zrpAS.mjs +5 -0
  9. package/dist/js/{daemon-BTyg329O.mjs → daemon-BPGZufS1.mjs} +4 -2
  10. package/dist/js/daemon-WQ8QYrFt.mjs +7 -0
  11. package/dist/js/daemon-client-DTfIza0O.mjs +8 -0
  12. package/dist/js/{daemon-client--A_yMKq6.mjs → daemon-client-MpAGVkqP.mjs} +1 -1
  13. package/dist/js/dist-CRtjM7ba.mjs +1750 -0
  14. package/dist/js/{forward-DL6DYqyc.mjs → forward-zwB55Bls.mjs} +25 -4
  15. package/dist/js/{profiler-BVbYs_Yg.mjs → install-BPUAm8bS.mjs} +274 -210
  16. package/dist/js/localhost-cert-Bn-UBUmj.mjs +67 -0
  17. package/dist/js/{print-DACzRUwQ.mjs → print-B9djx8GU.mjs} +3 -3
  18. package/dist/js/{print-C_TnQSPg.mjs → print-Clgq46GU.mjs} +3 -3
  19. package/dist/js/{print-share-BH9gvCls.mjs → print-share-BBy3OTno.mjs} +6 -2
  20. package/dist/js/{raw-pty-DY4KelZW.mjs → raw-pty-B9Bue8gg.mjs} +1 -1
  21. package/dist/js/raw-pty-g3kATVQe.mjs +5 -0
  22. package/dist/js/{rest-CgfbKXst.mjs → rest-C6E4mS2A.mjs} +2 -2
  23. package/dist/js/rest-CaWUSrnH.mjs +6 -0
  24. package/dist/js/tls-cert-CLgSQALB.mjs +4 -0
  25. package/dist/js/tls-cert-CV-pwxVN.mjs +67 -0
  26. package/package.json +1 -1
  27. package/dist/js/api-DG5W6iwx.mjs +0 -131
  28. package/dist/js/client-hH2PJL8y.mjs +0 -5
  29. package/dist/js/daemon-SPQgtsbW.mjs +0 -6
  30. package/dist/js/daemon-client-C7emKKlj.mjs +0 -7
  31. package/dist/js/raw-pty-DmdUf4_w.mjs +0 -5
  32. package/dist/js/rest-VV5nc-Mn.mjs +0 -6
  33. /package/dist/js/{billing-blocked-2wju4gC_.mjs → billing-blocked-D3l5kJlX.mjs} +0 -0
  34. /package/dist/js/{client-c4c5MmgN.mjs → client-BTQ1fwzM.mjs} +0 -0
  35. /package/dist/js/{http-error-DzyrsLAZ.mjs → http-error-UHH3mVBF.mjs} +0 -0
  36. /package/dist/js/{output-DYzzdXYV.mjs → output-wY0VQDea.mjs} +0 -0
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { t as HttpError } from "./http-error-DzyrsLAZ.mjs";
3
- import { a as billingBlockedOutcomeSchema } from "./billing-blocked-2wju4gC_.mjs";
2
+ import { t as HttpError } from "./http-error-UHH3mVBF.mjs";
3
+ import { a as billingBlockedOutcomeSchema } from "./billing-blocked-D3l5kJlX.mjs";
4
4
  import { z } from "zod";
5
5
  import { createParser } from "eventsource-parser";
6
6
 
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import { t as HttpError } from "./http-error-UHH3mVBF.mjs";
3
+ import { n as errorDetail, r as sendErrorMessage, t as createRestClient } from "./rest-C6E4mS2A.mjs";
4
+ import "./billing-blocked-D3l5kJlX.mjs";
5
+
6
+ export { createRestClient };
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { n as envTlsCertSource, r as warnOnRebindProtection, t as defaultTlsCertSource } from "./tls-cert-CV-pwxVN.mjs";
3
+
4
+ export { defaultTlsCertSource };
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ import { readFile } from "node:fs/promises";
3
+ import dns from "node:dns";
4
+
5
+ //#region ../portal-daemon/src/tls-cert.ts
6
+ /**
7
+ * File-backed cert source, configured by environment:
8
+ * SKYDIVE_PORTAL_TLS_KEY / SKYDIVE_PORTAL_TLS_CERT (PEM file paths) and
9
+ * SKYDIVE_PORTAL_TLS_HOST (the name the cert covers). All three or nothing —
10
+ * a partial configuration is reported once and treated as absent, so a typo
11
+ * degrades to today's behavior instead of a crash loop.
12
+ */
13
+ function envTlsCertSource(env, log) {
14
+ return async () => {
15
+ const keyPath = env.SKYDIVE_PORTAL_TLS_KEY;
16
+ const certPath = env.SKYDIVE_PORTAL_TLS_CERT;
17
+ const hostname = env.SKYDIVE_PORTAL_TLS_HOST;
18
+ if (!keyPath && !certPath && !hostname) return null;
19
+ if (!keyPath || !certPath || !hostname) {
20
+ log("forward: SKYDIVE_PORTAL_TLS_KEY, SKYDIVE_PORTAL_TLS_CERT and SKYDIVE_PORTAL_TLS_HOST must all be set to enable the TLS origin; continuing with http only");
21
+ return null;
22
+ }
23
+ try {
24
+ const [key, cert] = await Promise.all([readFile(keyPath, "utf8"), readFile(certPath, "utf8")]);
25
+ return {
26
+ key,
27
+ cert,
28
+ hostname
29
+ };
30
+ } catch (err) {
31
+ log(`forward: could not read TLS key/cert (${err instanceof Error ? err.message : String(err)}); continuing with http only`);
32
+ return null;
33
+ }
34
+ };
35
+ }
36
+ /**
37
+ * The default cert source for both tunnel surfaces: an explicit env/file
38
+ * configuration wins (BYO cert — also the escape hatch for machines where the
39
+ * trust prompt is unwanted, e.g. CI), otherwise the fully automatic
40
+ * devcert-backed localhost source.
41
+ */
42
+ function defaultTlsCertSource(env, log) {
43
+ const fromEnv = envTlsCertSource(env, log);
44
+ return async () => {
45
+ if (env.SKYDIVE_PORTAL_TLS_KEY || env.SKYDIVE_PORTAL_TLS_CERT || env.SKYDIVE_PORTAL_TLS_HOST) return fromEnv();
46
+ const { localhostCertSource } = await import("./localhost-cert-Bn-UBUmj.mjs");
47
+ return localhostCertSource(log)();
48
+ };
49
+ }
50
+ /**
51
+ * Detect resolver-level DNS rebind protection: some routers/resolvers refuse
52
+ * public names that answer with loopback addresses (Plex documents this exact
53
+ * failure for *.plex.direct). The https origin simply won't resolve for such
54
+ * users — warn with the cause, and leave the http origin (unaffected) as the
55
+ * fallback. Never fatal: the browser may use a different resolver than the
56
+ * OS, so we start the listener regardless.
57
+ */
58
+ async function warnOnRebindProtection(hostname, log) {
59
+ try {
60
+ if (!(await dns.promises.lookup(hostname, { all: true })).some((a) => a.address === "127.0.0.1" || a.address === "::1")) log(`forward: ${hostname} did not resolve to 127.0.0.1 — a resolver on this network may block public names pointing at loopback (DNS rebind protection). The https origin may not work here; http://localhost is unaffected.`);
61
+ } catch (error) {
62
+ log(`forward: ${hostname} did not resolve (${error instanceof Error ? error.message : String(error)}) — a resolver on this network may block public names pointing at loopback (DNS rebind protection). The https origin may not work here; http://localhost is unaffected.`);
63
+ }
64
+ }
65
+
66
+ //#endregion
67
+ export { envTlsCertSource as n, warnOnRebindProtection as r, defaultTlsCertSource as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skydive-cli",
3
- "version": "0.5.0-beta.31",
3
+ "version": "0.5.0-beta.33",
4
4
  "description": "Skydive CLI — cloud agents from the command line",
5
5
  "homepage": "https://skydive.com",
6
6
  "license": "MIT",
@@ -1,131 +0,0 @@
1
- #!/usr/bin/env node
2
- import { t as HttpError } from "./http-error-DzyrsLAZ.mjs";
3
- import { z } from "zod";
4
-
5
- //#region ../portal-daemon/src/api.ts
6
- /**
7
- * The portal's session-authed REST surface, shared by `PortalClient` (the
8
- * TUI/`portal open` connection) and the `skydive portal` management
9
- * commands, so the endpoint contracts and response schemas live in exactly
10
- * one place.
11
- */
12
- const deviceSchema = z.object({
13
- id: z.string(),
14
- machineName: z.string(),
15
- friendlyName: z.string(),
16
- connected: z.boolean(),
17
- lastSeen: z.string().nullable(),
18
- grantedAgentIds: z.array(z.string())
19
- });
20
- const devicesResponseSchema = z.object({
21
- devices: z.array(deviceSchema),
22
- agents: z.array(z.object({
23
- id: z.string(),
24
- name: z.string()
25
- }))
26
- });
27
- const deviceTokenSchema = z.object({ token: z.string().min(1) });
28
- async function portalFetch(auth, path, init) {
29
- const res = await fetch(`${auth.appUrl}${path}`, {
30
- method: init.method,
31
- headers: {
32
- authorization: `Bearer ${auth.sessionToken}`,
33
- accept: "application/json",
34
- ...init.body ? { "content-type": "application/json" } : {}
35
- },
36
- ...init.body ? { body: init.body } : {}
37
- });
38
- if (!res.ok) {
39
- const body = await res.text().catch(() => "");
40
- throw new HttpError(res.status, body);
41
- }
42
- return res.json();
43
- }
44
- async function fetchPortalDevices(auth) {
45
- const json = await portalFetch(auth, "/api/v1/portal/devices", { method: "GET" });
46
- return devicesResponseSchema.parse(json);
47
- }
48
- const registerResponseSchema = z.object({ device: z.object({ id: z.string() }) });
49
- /**
50
- * Register this machine's device row without connecting. Connecting registers
51
- * as a side effect; this covers granting an agent on a machine that has never
52
- * shared yet (the grant references the device row).
53
- */
54
- async function registerPortalDevice(auth, { machineName, friendlyName }) {
55
- const json = await portalFetch(auth, "/api/v1/portal/devices", {
56
- method: "POST",
57
- body: JSON.stringify({
58
- machineName,
59
- friendlyName
60
- })
61
- });
62
- return registerResponseSchema.parse(json).device;
63
- }
64
- /** Short-lived token the machine presents when dialing the portal WebSocket. */
65
- async function mintPortalDeviceToken(auth) {
66
- const json = await portalFetch(auth, "/api/v1/portal/device-token", { method: "POST" });
67
- return deviceTokenSchema.parse(json).token;
68
- }
69
- const forwardTargetSchema = z.object({
70
- daemonOrigin: z.string().min(1),
71
- token: z.string().min(1),
72
- expiresInSeconds: z.number()
73
- });
74
- /**
75
- * Everything `portal forward` needs to dial an agent's sandbox daemon through
76
- * the agent-webserver edge Worker: the daemon's stable public origin and a
77
- * daemon auth token (canUse-gated server-side).
78
- */
79
- async function fetchForwardTarget(auth, agentId) {
80
- const json = await portalFetch(auth, "/api/v1/portal/forward-target", {
81
- method: "POST",
82
- body: JSON.stringify({ agentId })
83
- });
84
- return forwardTargetSchema.parse(json);
85
- }
86
- async function grantPortalAccess(auth, { deviceId, agentId, conversationId }) {
87
- await portalFetch(auth, `/api/v1/portal/devices/${encodeURIComponent(deviceId)}/grants`, {
88
- method: "POST",
89
- body: JSON.stringify({
90
- agentId,
91
- conversationId
92
- })
93
- });
94
- }
95
- async function revokePortalAccess(auth, { deviceId, agentId }) {
96
- await portalFetch(auth, `/api/v1/portal/devices/${encodeURIComponent(deviceId)}/grants/${encodeURIComponent(agentId)}`, { method: "DELETE" });
97
- }
98
- /**
99
- * The device row for a given machine identity. Matching is by `machineName`
100
- * equality — the stable handle the machine registers under, not the display
101
- * label.
102
- */
103
- function findThisDevice(devices, machineName) {
104
- return devices.find((device) => device.machineName === machineName) ?? null;
105
- }
106
- /**
107
- * One-time grant migration onto the merged device. Earlier CLI builds
108
- * registered a separate `<machineName>-cli` device, so a user's existing
109
- * approvals hang off that row; the merged device would start with zero grants
110
- * and every already-authorized agent would ask again. Copy any grant the
111
- * merged device is missing (the grant endpoint upserts, so re-runs are
112
- * no-ops). The legacy row is left in place — an old CLI build may still
113
- * connect under it. Returns how many grants were copied.
114
- */
115
- async function unifyLegacyCliGrants(auth, machineName) {
116
- const { devices } = await fetchPortalDevices(auth);
117
- const merged = findThisDevice(devices, machineName);
118
- const legacy = findThisDevice(devices, `${machineName}-cli`);
119
- if (!merged || !legacy) return 0;
120
- const have = new Set(merged.grantedAgentIds);
121
- const missing = legacy.grantedAgentIds.filter((id) => !have.has(id));
122
- for (const agentId of missing) await grantPortalAccess(auth, {
123
- deviceId: merged.id,
124
- agentId,
125
- conversationId: null
126
- });
127
- return missing.length;
128
- }
129
-
130
- //#endregion
131
- export { mintPortalDeviceToken as a, unifyLegacyCliGrants as c, grantPortalAccess as i, fetchPortalDevices as n, registerPortalDevice as o, findThisDevice as r, revokePortalAccess as s, fetchForwardTarget as t };
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- import { t as PortalClient } from "./client-DbqRBquD.mjs";
3
- import "./api-DG5W6iwx.mjs";
4
-
5
- export { PortalClient };
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./client-DbqRBquD.mjs";
3
- import { a as runPortalDaemon, i as queryDaemonStatus, n as ensureDaemonRunning, o as startPortalDaemon, r as isDaemonListening, s as stopDaemon, t as PortalDaemon } from "./daemon-BTyg329O.mjs";
4
- import "./api-DG5W6iwx.mjs";
5
-
6
- export { runPortalDaemon };
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./client-DbqRBquD.mjs";
3
- import "./daemon-BTyg329O.mjs";
4
- import "./api-DG5W6iwx.mjs";
5
- import { t as PortalDaemonClient } from "./daemon-client--A_yMKq6.mjs";
6
-
7
- export { PortalDaemonClient };
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./client-c4c5MmgN.mjs";
3
- import { t as runRawPtyPassthrough } from "./raw-pty-DY4KelZW.mjs";
4
-
5
- export { runRawPtyPassthrough };
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env node
2
- import { t as HttpError } from "./http-error-DzyrsLAZ.mjs";
3
- import { n as errorDetail, r as sendErrorMessage, t as createRestClient } from "./rest-CgfbKXst.mjs";
4
- import "./billing-blocked-2wju4gC_.mjs";
5
-
6
- export { createRestClient };