@getpaseo/cli 0.3.0 → 0.4.0-beta.1

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 (93) hide show
  1. package/dist/cli.js +0 -5
  2. package/dist/commands/hub/authority.d.ts +17 -0
  3. package/dist/commands/hub/authority.js +18 -0
  4. package/dist/commands/hub/connect.d.ts +21 -0
  5. package/dist/commands/hub/connect.js +34 -0
  6. package/dist/commands/hub/credentials.d.ts +21 -0
  7. package/dist/commands/hub/credentials.js +143 -0
  8. package/dist/commands/hub/daemon-client.d.ts +27 -0
  9. package/dist/commands/hub/daemon-client.js +14 -0
  10. package/dist/commands/hub/deploy-bundle.d.ts +16 -0
  11. package/dist/commands/hub/deploy-bundle.js +248 -0
  12. package/dist/commands/hub/deploy.d.ts +25 -4
  13. package/dist/commands/hub/deploy.js +64 -48
  14. package/dist/commands/hub/disconnect.d.ts +16 -0
  15. package/dist/commands/hub/disconnect.js +24 -0
  16. package/dist/commands/hub/error.d.ts +1 -1
  17. package/dist/commands/hub/error.js +2 -2
  18. package/dist/commands/hub/help.d.ts +3 -0
  19. package/dist/commands/hub/help.js +5 -0
  20. package/dist/commands/hub/hub-client/index.d.ts +18 -0
  21. package/dist/commands/hub/hub-client/index.js +88 -0
  22. package/dist/commands/hub/hub-client/internal/contracts.d.ts +65 -0
  23. package/dist/commands/hub/hub-client/internal/contracts.js +47 -0
  24. package/dist/commands/hub/hub-client/internal/problem.d.ts +3 -0
  25. package/dist/commands/hub/hub-client/internal/problem.js +72 -0
  26. package/dist/commands/hub/hub-client/internal/transport.d.ts +15 -0
  27. package/dist/commands/hub/hub-client/internal/transport.js +30 -0
  28. package/dist/commands/hub/index.d.ts +15 -25
  29. package/dist/commands/hub/index.js +64 -74
  30. package/dist/commands/hub/{device-authorization.d.ts → login-flow.d.ts} +12 -15
  31. package/dist/commands/hub/login-flow.js +78 -0
  32. package/dist/commands/hub/login.d.ts +21 -0
  33. package/dist/commands/hub/login.js +34 -0
  34. package/dist/commands/hub/logout.d.ts +31 -0
  35. package/dist/commands/hub/logout.js +65 -0
  36. package/dist/commands/hub/origin.d.ts +2 -0
  37. package/dist/commands/hub/origin.js +27 -0
  38. package/dist/commands/hub/projects.d.ts +24 -0
  39. package/dist/commands/hub/projects.js +49 -0
  40. package/dist/commands/hub/reporter.d.ts +10 -0
  41. package/dist/commands/hub/reporter.js +11 -0
  42. package/dist/commands/hub/status-output.d.ts +13 -0
  43. package/dist/commands/hub/status-output.js +30 -0
  44. package/dist/commands/provider/diagnostic.d.ts +12 -0
  45. package/dist/commands/provider/diagnostic.js +31 -0
  46. package/dist/commands/provider/index.js +5 -0
  47. package/dist/commands/schedule/types.d.ts +1 -4
  48. package/dist/commands/workspace/index.js +10 -0
  49. package/dist/commands/workspace/rename.d.ts +22 -0
  50. package/dist/commands/workspace/rename.js +61 -0
  51. package/dist/output/types.d.ts +1 -1
  52. package/package.json +4 -4
  53. package/dist/commands/chat/create.d.ts +0 -9
  54. package/dist/commands/chat/create.js +0 -23
  55. package/dist/commands/chat/delete.d.ts +0 -6
  56. package/dist/commands/chat/delete.js +0 -20
  57. package/dist/commands/chat/index.d.ts +0 -3
  58. package/dist/commands/chat/index.js +0 -47
  59. package/dist/commands/chat/inspect.d.ts +0 -6
  60. package/dist/commands/chat/inspect.js +0 -20
  61. package/dist/commands/chat/ls.d.ts +0 -6
  62. package/dist/commands/chat/ls.js +0 -20
  63. package/dist/commands/chat/post.d.ts +0 -9
  64. package/dist/commands/chat/post.js +0 -28
  65. package/dist/commands/chat/read.d.ts +0 -11
  66. package/dist/commands/chat/read.js +0 -40
  67. package/dist/commands/chat/schema.d.ts +0 -36
  68. package/dist/commands/chat/schema.js +0 -81
  69. package/dist/commands/chat/shared.d.ts +0 -19
  70. package/dist/commands/chat/shared.js +0 -118
  71. package/dist/commands/chat/wait.d.ts +0 -9
  72. package/dist/commands/chat/wait.js +0 -45
  73. package/dist/commands/hub/client.d.ts +0 -19
  74. package/dist/commands/hub/client.js +0 -114
  75. package/dist/commands/hub/cloud-device-authorization.d.ts +0 -45
  76. package/dist/commands/hub/cloud-device-authorization.js +0 -92
  77. package/dist/commands/hub/deploy-input.d.ts +0 -17
  78. package/dist/commands/hub/deploy-input.js +0 -264
  79. package/dist/commands/hub/device-authorization.js +0 -87
  80. package/dist/commands/loop/index.d.ts +0 -3
  81. package/dist/commands/loop/index.js +0 -18
  82. package/dist/commands/loop/inspect.d.ts +0 -13
  83. package/dist/commands/loop/inspect.js +0 -100
  84. package/dist/commands/loop/logs.d.ts +0 -8
  85. package/dist/commands/loop/logs.js +0 -69
  86. package/dist/commands/loop/ls.d.ts +0 -18
  87. package/dist/commands/loop/ls.js +0 -62
  88. package/dist/commands/loop/run.d.ts +0 -30
  89. package/dist/commands/loop/run.js +0 -162
  90. package/dist/commands/loop/stop.d.ts +0 -15
  91. package/dist/commands/loop/stop.js +0 -56
  92. package/dist/commands/loop/types.d.ts +0 -138
  93. package/dist/commands/loop/types.js +0 -2
@@ -1,87 +1,77 @@
1
1
  import { Command } from "commander";
2
- import { hostname } from "node:os";
3
2
  import { withOutput } from "../../output/index.js";
4
3
  import { addJsonAndDaemonHostOptions } from "../../utils/command-options.js";
5
- import { connectToDaemon } from "../../utils/client.js";
6
- import { createDeviceAuthorizationWorkflow } from "./device-authorization.js";
4
+ import { HubHttpClient } from "./hub-client/index.js";
5
+ import { addHubConnectCommand } from "./connect.js";
6
+ import { PrivateHubCredentialStore } from "./credentials.js";
7
+ import { productionHubDaemonConnection, withHubDaemon, } from "./daemon-client.js";
7
8
  import { addHubDeployCommand } from "./deploy.js";
8
- const productionEnvironment = {
9
- connect: (host) => connectToDaemon({ host }),
10
- authorize: (url, displayName) => createDeviceAuthorizationWorkflow().authorize(url, displayName),
11
- displayName: hostname,
12
- };
13
- const schema = {
14
- idField: "state",
15
- columns: [
16
- { header: "STATE", field: "state" },
17
- { header: "HUB", field: "hub" },
18
- { header: "DAEMON", field: "daemonId" },
19
- { header: "SCOPES", field: "scopes" },
20
- { header: "CONNECTED", field: "connectedAt" },
21
- { header: "ERROR", field: "error" },
22
- { header: "WARNING", field: "warning" },
23
- ],
24
- };
25
- function result(status, warning) {
9
+ import { addHubDisconnectCommand } from "./disconnect.js";
10
+ import { createCliLoginFlow } from "./login-flow.js";
11
+ import { addHubLoginCommand } from "./login.js";
12
+ import { addHubLogoutCommand, productionLogoutPrompt } from "./logout.js";
13
+ import { addHubProjectsCommand } from "./projects.js";
14
+ import { processHubReporter } from "./reporter.js";
15
+ import { hubStatusResult } from "./status-output.js";
16
+ import { addHubResolutionHelp } from "./help.js";
17
+ function productionEnvironment() {
18
+ const env = process.env;
19
+ const hub = new HubHttpClient();
26
20
  return {
27
- type: "list",
28
- data: [
29
- {
30
- state: status.state,
31
- daemonId: status.daemonId,
32
- hub: status.hubOrigin,
33
- scopes: status.scopes.join(", "),
34
- connectedAt: status.connectedAt,
35
- error: status.lastError,
36
- warning,
37
- },
38
- ],
39
- schema,
21
+ env,
22
+ credentials: new PrivateHubCredentialStore(env),
23
+ hub,
24
+ login: createCliLoginFlow(hub),
25
+ daemon: productionHubDaemonConnection,
26
+ reporter: processHubReporter,
27
+ cwd: () => process.cwd(),
28
+ ...productionLogoutPrompt,
40
29
  };
41
30
  }
42
- async function withClient(environment, host, action) {
43
- const client = await environment.connect(host);
44
- try {
45
- return await action(client);
46
- }
47
- finally {
48
- await client.close().catch(() => undefined);
49
- }
50
- }
51
- export function createHubCommand(environment = productionEnvironment) {
52
- const hub = new Command("hub").description("Manage Paseo Hub");
53
- addJsonAndDaemonHostOptions(hub.command("connect").argument("<url>").option("--token <token>")).action(withOutput(async (...args) => {
54
- const url = args[0];
55
- const options = args.at(-2);
56
- return withClient(environment, options.host, async (client) => {
57
- if (options.token !== undefined) {
58
- return result((await client.connectHub(url, options.token)).status);
59
- }
60
- const existing = (await client.getHubStatus()).status;
61
- if (existing.state !== "not_connected" && existing.state !== "revoked") {
62
- throw new Error("This daemon already has a Hub relationship");
63
- }
64
- const token = await environment.authorize(url, suggestedDisplayName(environment.displayName()));
65
- return result((await client.connectHub(url, token)).status);
66
- });
67
- }));
31
+ export function createHubCommand(overrides = {}) {
32
+ const environment = { ...productionEnvironment(), ...overrides };
33
+ const hub = addHubResolutionHelp(new Command("hub").description("Manage Paseo Hub"));
34
+ addHubLoginCommand(hub, {
35
+ env: environment.env,
36
+ credentials: environment.credentials,
37
+ flow: environment.login,
38
+ reporter: environment.reporter,
39
+ });
40
+ addHubConnectCommand(hub, {
41
+ env: environment.env,
42
+ credentials: environment.credentials,
43
+ hub: environment.hub,
44
+ daemon: environment.daemon,
45
+ reporter: environment.reporter,
46
+ });
68
47
  addJsonAndDaemonHostOptions(hub.command("status")).action(withOutput(async (...args) => {
69
48
  const options = args.at(-2);
70
- return withClient(environment, options.host, async (client) => result((await client.getHubStatus()).status));
49
+ return withHubDaemon(environment.daemon, options.host, async (client) => hubStatusResult((await client.getHubStatus()).status));
71
50
  }));
72
- addJsonAndDaemonHostOptions(hub
73
- .command("disconnect")
74
- .option("--force", "Remove local authority even if the Hub is offline")).action(withOutput(async (...args) => {
75
- const options = args.at(-2);
76
- return withClient(environment, options.host, async (client) => {
77
- const response = await client.disconnectHub(options.force ?? false);
78
- return result(response.status, response.warning);
79
- });
80
- }));
81
- addHubDeployCommand(hub);
51
+ addHubDisconnectCommand(hub, {
52
+ daemon: environment.daemon,
53
+ reporter: environment.reporter,
54
+ });
55
+ addHubProjectsCommand(hub, {
56
+ env: environment.env,
57
+ credentials: environment.credentials,
58
+ hub: environment.hub,
59
+ reporter: environment.reporter,
60
+ });
61
+ addHubDeployCommand(hub, {
62
+ env: environment.env,
63
+ credentials: environment.credentials,
64
+ hub: environment.hub,
65
+ reporter: environment.reporter,
66
+ cwd: environment.cwd,
67
+ });
68
+ addHubLogoutCommand(hub, {
69
+ credentials: environment.credentials,
70
+ daemon: environment.daemon,
71
+ isInteractive: environment.isInteractive,
72
+ confirmDisconnect: environment.confirmDisconnect,
73
+ reporter: environment.reporter,
74
+ });
82
75
  return hub;
83
76
  }
84
- function suggestedDisplayName(value) {
85
- return value.trim().slice(0, 100) || "Paseo daemon";
86
- }
87
77
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,5 @@
1
- import { type CloudDeviceAuthorization } from "./cloud-device-authorization.js";
2
- export interface AuthorizationWaiter {
1
+ import type { HubHttpClient } from "./hub-client/index.js";
2
+ export interface LoginWaiter {
3
3
  wait(milliseconds: number): Promise<void>;
4
4
  now(): number;
5
5
  }
@@ -17,21 +17,18 @@ export declare class SystemBrowser implements BrowserOpener {
17
17
  constructor(options?: SystemBrowserOptions);
18
18
  open(url: string): Promise<void>;
19
19
  }
20
- export interface AuthorizationReporter {
21
- instructions(verificationUri: string, userCode: string): void;
22
- }
23
- interface DeviceAuthorizationWorkflowOptions {
24
- cloud: CloudDeviceAuthorization;
25
- waiter: AuthorizationWaiter;
20
+ interface CliLoginFlowOptions {
21
+ hub: Pick<HubHttpClient, "startCliAuthorization" | "pollCliAuthorization">;
22
+ waiter: LoginWaiter;
26
23
  browser: BrowserOpener;
27
- reporter: AuthorizationReporter;
28
- openBrowser?: boolean;
24
+ instructions(verificationUri: string, userCode: string): void;
25
+ openBrowser: boolean;
29
26
  }
30
- export declare class DeviceAuthorizationWorkflow {
27
+ export declare class CliLoginFlow {
31
28
  private readonly options;
32
- constructor(options: DeviceAuthorizationWorkflowOptions);
33
- authorize(hubUrl: string, displayName: string): Promise<string>;
29
+ constructor(options: CliLoginFlowOptions);
30
+ authorize(origin: string): Promise<string>;
34
31
  }
35
- export declare function createDeviceAuthorizationWorkflow(): DeviceAuthorizationWorkflow;
32
+ export declare function createCliLoginFlow(hub: HubHttpClient): CliLoginFlow;
36
33
  export {};
37
- //# sourceMappingURL=device-authorization.d.ts.map
34
+ //# sourceMappingURL=login-flow.d.ts.map
@@ -0,0 +1,78 @@
1
+ import { spawn } from "node:child_process";
2
+ import { platform } from "node:os";
3
+ export class SystemBrowser {
4
+ constructor(options = {}) {
5
+ this.hostPlatform = options.hostPlatform ?? platform();
6
+ this.launch = options.launch ?? launchDetached;
7
+ }
8
+ async open(url) {
9
+ if (this.hostPlatform === "win32") {
10
+ await this.launch("rundll32.exe", ["url.dll,FileProtocolHandler", url]);
11
+ return;
12
+ }
13
+ await this.launch(this.hostPlatform === "darwin" ? "open" : "xdg-open", [url]);
14
+ }
15
+ }
16
+ export class CliLoginFlow {
17
+ constructor(options) {
18
+ this.options = options;
19
+ }
20
+ async authorize(origin) {
21
+ const authorization = await this.options.hub.startCliAuthorization(origin);
22
+ this.options.instructions(authorization.verificationUri, authorization.userCode);
23
+ if (this.options.openBrowser) {
24
+ await this.options.browser.open(authorization.verificationUriComplete).catch(() => undefined);
25
+ }
26
+ let interval = authorization.interval;
27
+ const expiresAt = Date.parse(authorization.expiresAt);
28
+ while (true) {
29
+ const remaining = expiresAt - this.options.waiter.now();
30
+ if (remaining <= 0)
31
+ throw new Error("Hub CLI login expired");
32
+ await this.options.waiter.wait(Math.min(interval * 1000, remaining));
33
+ const pollLifetime = expiresAt - this.options.waiter.now();
34
+ if (pollLifetime <= 0)
35
+ throw new Error("Hub CLI login expired");
36
+ const outcome = await this.options.hub.pollCliAuthorization(origin, authorization.deviceCode, pollLifetime);
37
+ const credential = approvedCredential(outcome);
38
+ if (credential !== null)
39
+ return credential;
40
+ if (outcome.status === "denied")
41
+ throw new Error("Hub CLI login was denied");
42
+ if (outcome.status === "expired")
43
+ throw new Error("Hub CLI login expired");
44
+ if (outcome.status === "disclosed")
45
+ throw new Error("Hub CLI login was already completed");
46
+ if (outcome.status !== "retry_later")
47
+ interval = outcome.interval;
48
+ }
49
+ }
50
+ }
51
+ export function createCliLoginFlow(hub) {
52
+ return new CliLoginFlow({
53
+ hub,
54
+ waiter: {
55
+ wait: (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)),
56
+ now: Date.now,
57
+ },
58
+ browser: new SystemBrowser(),
59
+ instructions(verificationUri, userCode) {
60
+ process.stderr.write(`Open ${verificationUri} and enter code ${userCode}\n`);
61
+ },
62
+ openBrowser: process.stderr.isTTY === true,
63
+ });
64
+ }
65
+ function approvedCredential(outcome) {
66
+ return outcome.status === "authorized" ? outcome.credential : null;
67
+ }
68
+ async function launchDetached(command, args) {
69
+ await new Promise((resolve, reject) => {
70
+ const child = spawn(command, args, { detached: true, shell: false, stdio: "ignore" });
71
+ child.once("spawn", () => {
72
+ child.unref();
73
+ resolve();
74
+ });
75
+ child.once("error", reject);
76
+ });
77
+ }
78
+ //# sourceMappingURL=login-flow.js.map
@@ -0,0 +1,21 @@
1
+ import type { Command } from "commander";
2
+ import { type SingleResult } from "../../output/index.js";
3
+ import type { HubCredentialStore } from "./credentials.js";
4
+ import type { CliLoginFlow } from "./login-flow.js";
5
+ import { type HubReporter } from "./reporter.js";
6
+ interface HubLoginResult {
7
+ origin: string;
8
+ status: "logged_in";
9
+ }
10
+ interface HubLoginDependencies {
11
+ env: Readonly<Record<string, string | undefined>>;
12
+ credentials: HubCredentialStore;
13
+ flow: Pick<CliLoginFlow, "authorize">;
14
+ reporter: HubReporter;
15
+ }
16
+ export declare function runHubLogin(originInput: string | undefined, options: {
17
+ json?: boolean;
18
+ }, dependencies: HubLoginDependencies): Promise<SingleResult<HubLoginResult>>;
19
+ export declare function addHubLoginCommand(parent: Command, dependencies: HubLoginDependencies): void;
20
+ export {};
21
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1,34 @@
1
+ import { withOutput } from "../../output/index.js";
2
+ import { addJsonOption } from "../../utils/command-options.js";
3
+ import { resolveHubOrigin } from "./authority.js";
4
+ import { reportHubProgress } from "./reporter.js";
5
+ import { addHubResolutionHelp } from "./help.js";
6
+ const schema = {
7
+ idField: "origin",
8
+ columns: [
9
+ { header: "HUB", field: "origin" },
10
+ { header: "STATUS", field: "status" },
11
+ ],
12
+ };
13
+ export async function runHubLogin(originInput, options, dependencies) {
14
+ const origin = resolveHubOrigin({
15
+ options: { origin: originInput },
16
+ env: dependencies.env,
17
+ credentials: dependencies.credentials,
18
+ });
19
+ reportHubProgress(dependencies.reporter, options, `Logging in to ${origin}`);
20
+ const credential = await dependencies.flow.authorize(origin);
21
+ dependencies.credentials.save({ origin, credential });
22
+ return { type: "single", data: { origin, status: "logged_in" }, schema };
23
+ }
24
+ export function addHubLoginCommand(parent, dependencies) {
25
+ addJsonOption(addHubResolutionHelp(parent
26
+ .command("login")
27
+ .description("Log in to a Paseo Hub for CLI access")
28
+ .argument("[origin]", "Paseo Hub origin"))).action(withOutput(async (...args) => {
29
+ const origin = args[0];
30
+ const options = args.at(-2);
31
+ return runHubLogin(origin, options, dependencies);
32
+ }));
33
+ }
34
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1,31 @@
1
+ import type { Command } from "commander";
2
+ import { type SingleResult } from "../../output/index.js";
3
+ import type { HubCredentialStore } from "./credentials.js";
4
+ import type { HubDaemonConnection } from "./daemon-client.js";
5
+ import { type HubReporter } from "./reporter.js";
6
+ interface HubLogoutResult {
7
+ origin: string | null;
8
+ status: "logged_out" | "not_logged_in";
9
+ daemonDisconnected: boolean;
10
+ }
11
+ interface HubLogoutOptions {
12
+ disconnectDaemon?: boolean;
13
+ force?: boolean;
14
+ host?: string;
15
+ json?: boolean;
16
+ }
17
+ interface HubLogoutDependencies {
18
+ credentials: HubCredentialStore;
19
+ daemon: HubDaemonConnection;
20
+ isInteractive(): boolean;
21
+ confirmDisconnect(origin: string): Promise<boolean>;
22
+ reporter: HubReporter;
23
+ }
24
+ export declare function runHubLogout(options: HubLogoutOptions, dependencies: HubLogoutDependencies): Promise<SingleResult<HubLogoutResult>>;
25
+ export declare function addHubLogoutCommand(parent: Command, dependencies: HubLogoutDependencies): void;
26
+ export declare const productionLogoutPrompt: {
27
+ isInteractive: () => boolean;
28
+ confirmDisconnect(origin: string): Promise<boolean>;
29
+ };
30
+ export {};
31
+ //# sourceMappingURL=logout.d.ts.map
@@ -0,0 +1,65 @@
1
+ import { confirm, isCancel } from "@clack/prompts";
2
+ import { withOutput } from "../../output/index.js";
3
+ import { addJsonAndDaemonHostOptions } from "../../utils/command-options.js";
4
+ import { withHubDaemon } from "./daemon-client.js";
5
+ import { reportHubProgress } from "./reporter.js";
6
+ const schema = {
7
+ idField: "status",
8
+ columns: [
9
+ { header: "HUB", field: "origin" },
10
+ { header: "STATUS", field: "status" },
11
+ { header: "DAEMON DISCONNECTED", field: "daemonDisconnected" },
12
+ ],
13
+ };
14
+ export async function runHubLogout(options, dependencies) {
15
+ const active = dependencies.credentials.active();
16
+ if (active === null) {
17
+ return logoutResult({ origin: null, status: "not_logged_in", daemonDisconnected: false });
18
+ }
19
+ reportHubProgress(dependencies.reporter, options, `Logging out of ${active.origin}`);
20
+ const mayPrompt = options.json !== true && dependencies.isInteractive();
21
+ let daemonStatus = null;
22
+ const shouldInspectDaemon = options.disconnectDaemon === true || mayPrompt;
23
+ if (shouldInspectDaemon) {
24
+ daemonStatus = await withHubDaemon(dependencies.daemon, options.host, async (daemon) => daemon.getHubStatus().then((response) => response.status));
25
+ }
26
+ const sameHub = daemonStatus?.hubOrigin === active.origin;
27
+ let shouldDisconnect = options.disconnectDaemon === true && sameHub;
28
+ if (options.disconnectDaemon !== true && mayPrompt && sameHub) {
29
+ shouldDisconnect = await dependencies.confirmDisconnect(active.origin);
30
+ }
31
+ if (!shouldDisconnect) {
32
+ dependencies.credentials.logoutActive();
33
+ return logoutResult({ origin: active.origin, status: "logged_out", daemonDisconnected: false });
34
+ }
35
+ reportHubProgress(dependencies.reporter, options, `Disconnecting this daemon from ${active.origin}`);
36
+ await withHubDaemon(dependencies.daemon, options.host, async (daemon) => {
37
+ await daemon.disconnectHub(options.force ?? false);
38
+ });
39
+ dependencies.credentials.logoutActive();
40
+ return logoutResult({ origin: active.origin, status: "logged_out", daemonDisconnected: true });
41
+ }
42
+ export function addHubLogoutCommand(parent, dependencies) {
43
+ addJsonAndDaemonHostOptions(parent
44
+ .command("logout")
45
+ .description("Remove the active stored Hub CLI login")
46
+ .option("--disconnect-daemon", "Also disconnect a daemon related to the same Hub")
47
+ .option("--force", "Remove daemon authority even if Hub is offline")).action(withOutput(async (...args) => {
48
+ const options = args.at(-2);
49
+ return runHubLogout(options, dependencies);
50
+ }));
51
+ }
52
+ export const productionLogoutPrompt = {
53
+ isInteractive: () => Boolean(process.stdin.isTTY && process.stdout.isTTY),
54
+ async confirmDisconnect(origin) {
55
+ const answer = await confirm({
56
+ message: `Disconnect this daemon from ${origin}?`,
57
+ initialValue: false,
58
+ });
59
+ return !isCancel(answer) && answer;
60
+ },
61
+ };
62
+ function logoutResult(data) {
63
+ return { type: "single", data, schema };
64
+ }
65
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1,2 @@
1
+ export declare function normalizeHubOrigin(value: string): string;
2
+ //# sourceMappingURL=origin.d.ts.map
@@ -0,0 +1,27 @@
1
+ import { HubCommandError } from "./error.js";
2
+ export function normalizeHubOrigin(value) {
3
+ let url;
4
+ try {
5
+ url = new URL(value);
6
+ }
7
+ catch {
8
+ throw invalidHubOrigin();
9
+ }
10
+ if (!["http:", "https:"].includes(url.protocol) ||
11
+ (url.protocol === "http:" && !isLoopbackHostname(url.hostname)) ||
12
+ url.username ||
13
+ url.password ||
14
+ url.pathname !== "/" ||
15
+ url.search ||
16
+ url.hash) {
17
+ throw invalidHubOrigin();
18
+ }
19
+ return url.origin;
20
+ }
21
+ function isLoopbackHostname(hostname) {
22
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
23
+ }
24
+ function invalidHubOrigin() {
25
+ return new HubCommandError("HUB_INVALID_ORIGIN", "Hub URL must be an HTTPS origin without credentials, path, query, or hash. HTTP is allowed only for localhost, 127.0.0.1, or [::1].");
26
+ }
27
+ //# sourceMappingURL=origin.js.map
@@ -0,0 +1,24 @@
1
+ import type { Command } from "commander";
2
+ import { type SingleResult } from "../../output/index.js";
3
+ import type { HubHttpClient, HubProject } from "./hub-client/index.js";
4
+ import type { HubCredentialStore } from "./credentials.js";
5
+ import { type HubReporter } from "./reporter.js";
6
+ interface HubProjectsResult {
7
+ origin: string;
8
+ projects: HubProject[];
9
+ }
10
+ export interface HubProjectsOptions {
11
+ hub?: string;
12
+ apiKey?: string;
13
+ json?: boolean;
14
+ }
15
+ interface HubProjectsDependencies {
16
+ env: Readonly<Record<string, string | undefined>>;
17
+ credentials: HubCredentialStore;
18
+ hub: Pick<HubHttpClient, "listProjects">;
19
+ reporter: HubReporter;
20
+ }
21
+ export declare function runHubProjects(options: HubProjectsOptions, dependencies: HubProjectsDependencies): Promise<SingleResult<HubProjectsResult>>;
22
+ export declare function addHubProjectsCommand(parent: Command, dependencies: HubProjectsDependencies): void;
23
+ export {};
24
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1,49 @@
1
+ import { render, withOutput } from "../../output/index.js";
2
+ import { addJsonOption } from "../../utils/command-options.js";
3
+ import { resolveHubCredential, resolveHubOrigin } from "./authority.js";
4
+ import { reportHubProgress } from "./reporter.js";
5
+ import { addHubResolutionHelp } from "./help.js";
6
+ const projectSchema = {
7
+ idField: "id",
8
+ columns: [
9
+ { header: "SLUG", field: "slug" },
10
+ { header: "NAME", field: "name" },
11
+ { header: "ID", field: "id" },
12
+ { header: "HUB", field: "origin" },
13
+ ],
14
+ };
15
+ const schema = {
16
+ idField: "origin",
17
+ columns: [
18
+ { header: "HUB", field: "origin" },
19
+ { header: "PROJECTS", field: (result) => result.projects.length },
20
+ ],
21
+ renderHuman(result, options) {
22
+ const results = result.type === "single" ? [result.data] : result.data;
23
+ const data = results.flatMap((entry) => entry.projects.map((project) => ({ ...project, origin: entry.origin })));
24
+ return render({ type: "list", data, schema: projectSchema }, options);
25
+ },
26
+ };
27
+ export async function runHubProjects(options, dependencies) {
28
+ const resolution = {
29
+ options: { origin: options.hub, apiKey: options.apiKey },
30
+ env: dependencies.env,
31
+ credentials: dependencies.credentials,
32
+ };
33
+ const origin = resolveHubOrigin(resolution);
34
+ reportHubProgress(dependencies.reporter, options, `Listing projects from ${origin}`);
35
+ const credential = resolveHubCredential({ ...resolution, origin });
36
+ const projects = await dependencies.hub.listProjects(origin, credential);
37
+ return { type: "single", data: { origin, projects }, schema };
38
+ }
39
+ export function addHubProjectsCommand(parent, dependencies) {
40
+ addJsonOption(addHubResolutionHelp(parent
41
+ .command("projects")
42
+ .description("List projects for the authenticated Hub organization")
43
+ .option("--hub <origin>", "Paseo Hub origin")
44
+ .option("--api-key <secret>", "Organization API key"))).action(withOutput(async (...args) => {
45
+ const options = args.at(-2);
46
+ return runHubProjects(options, dependencies);
47
+ }));
48
+ }
49
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1,10 @@
1
+ export interface HubReporter {
2
+ progress(message: string): void;
3
+ }
4
+ export declare const processHubReporter: HubReporter;
5
+ interface HubReportOptions {
6
+ json?: boolean;
7
+ }
8
+ export declare function reportHubProgress(reporter: HubReporter, options: HubReportOptions, message: string): void;
9
+ export {};
10
+ //# sourceMappingURL=reporter.d.ts.map
@@ -0,0 +1,11 @@
1
+ export const processHubReporter = {
2
+ progress(message) {
3
+ process.stderr.write(`${message}\n`);
4
+ },
5
+ };
6
+ export function reportHubProgress(reporter, options, message) {
7
+ if (options.json === true)
8
+ return;
9
+ reporter.progress(message);
10
+ }
11
+ //# sourceMappingURL=reporter.js.map
@@ -0,0 +1,13 @@
1
+ import type { ListResult } from "../../output/index.js";
2
+ import type { HubStatus } from "./daemon-client.js";
3
+ export interface HubRow {
4
+ state: string;
5
+ daemonId: string | null;
6
+ hub: string | null;
7
+ scopes: string;
8
+ connectedAt: string | null;
9
+ error: string | null;
10
+ warning?: string;
11
+ }
12
+ export declare function hubStatusResult(status: HubStatus, warning?: string, reportedHubOrigin?: string | null): ListResult<HubRow>;
13
+ //# sourceMappingURL=status-output.d.ts.map
@@ -0,0 +1,30 @@
1
+ const schema = {
2
+ idField: "state",
3
+ columns: [
4
+ { header: "STATE", field: "state" },
5
+ { header: "HUB", field: "hub" },
6
+ { header: "DAEMON", field: "daemonId" },
7
+ { header: "SCOPES", field: "scopes" },
8
+ { header: "CONNECTED", field: "connectedAt" },
9
+ { header: "ERROR", field: "error" },
10
+ { header: "WARNING", field: "warning" },
11
+ ],
12
+ };
13
+ export function hubStatusResult(status, warning, reportedHubOrigin = status.hubOrigin) {
14
+ return {
15
+ type: "list",
16
+ data: [
17
+ {
18
+ state: status.state,
19
+ daemonId: status.daemonId,
20
+ hub: reportedHubOrigin,
21
+ scopes: status.scopes.join(", "),
22
+ connectedAt: status.connectedAt,
23
+ error: status.lastError,
24
+ warning,
25
+ },
26
+ ],
27
+ schema,
28
+ };
29
+ }
30
+ //# sourceMappingURL=status-output.js.map
@@ -0,0 +1,12 @@
1
+ import type { Command } from "commander";
2
+ import type { CommandOptions, OutputSchema, SingleResult } from "../../output/index.js";
3
+ export interface ProviderDiagnosticResult {
4
+ provider: string;
5
+ diagnostic: string;
6
+ }
7
+ export declare const providerDiagnosticSchema: OutputSchema<ProviderDiagnosticResult>;
8
+ export interface ProviderDiagnosticOptions extends CommandOptions {
9
+ host?: string;
10
+ }
11
+ export declare function runDiagnosticCommand(provider: string, options: ProviderDiagnosticOptions, _command: Command): Promise<SingleResult<ProviderDiagnosticResult>>;
12
+ //# sourceMappingURL=diagnostic.d.ts.map
@@ -0,0 +1,31 @@
1
+ import { connectToDaemon } from "../../utils/client.js";
2
+ export const providerDiagnosticSchema = {
3
+ idField: "provider",
4
+ columns: [
5
+ { header: "PROVIDER", field: "provider" },
6
+ { header: "DIAGNOSTIC", field: "diagnostic" },
7
+ ],
8
+ renderHuman(result) {
9
+ if (result.type === "single")
10
+ return result.data.diagnostic;
11
+ return result.data.map((entry) => entry.diagnostic).join("\n\n");
12
+ },
13
+ };
14
+ export async function runDiagnosticCommand(provider, options, _command) {
15
+ const client = await connectToDaemon({ host: options.host });
16
+ try {
17
+ const result = await client.getProviderDiagnostic(provider.trim().toLowerCase());
18
+ return {
19
+ type: "single",
20
+ data: {
21
+ provider: result.provider,
22
+ diagnostic: result.diagnostic,
23
+ },
24
+ schema: providerDiagnosticSchema,
25
+ };
26
+ }
27
+ finally {
28
+ await client.close();
29
+ }
30
+ }
31
+ //# sourceMappingURL=diagnostic.js.map