@getpaseo/cli 0.3.0-beta.4 → 0.3.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.
- package/dist/commands/hub/authority.d.ts +17 -0
- package/dist/commands/hub/authority.js +18 -0
- package/dist/commands/hub/client.d.ts +55 -3
- package/dist/commands/hub/client.js +158 -38
- package/dist/commands/hub/connect.d.ts +21 -0
- package/dist/commands/hub/connect.js +34 -0
- package/dist/commands/hub/credentials.d.ts +21 -0
- package/dist/commands/hub/credentials.js +143 -0
- package/dist/commands/hub/daemon-client.d.ts +27 -0
- package/dist/commands/hub/daemon-client.js +14 -0
- package/dist/commands/hub/deploy-input.js +28 -28
- package/dist/commands/hub/deploy.d.ts +23 -3
- package/dist/commands/hub/deploy.js +51 -42
- package/dist/commands/hub/disconnect.d.ts +16 -0
- package/dist/commands/hub/disconnect.js +24 -0
- package/dist/commands/hub/error.d.ts +1 -1
- package/dist/commands/hub/error.js +2 -2
- package/dist/commands/hub/help.d.ts +3 -0
- package/dist/commands/hub/help.js +5 -0
- package/dist/commands/hub/index.d.ts +15 -25
- package/dist/commands/hub/index.js +64 -74
- package/dist/commands/hub/{device-authorization.d.ts → login-flow.d.ts} +12 -15
- package/dist/commands/hub/login-flow.js +78 -0
- package/dist/commands/hub/login.d.ts +21 -0
- package/dist/commands/hub/login.js +34 -0
- package/dist/commands/hub/logout.d.ts +31 -0
- package/dist/commands/hub/logout.js +65 -0
- package/dist/commands/hub/origin.d.ts +2 -0
- package/dist/commands/hub/origin.js +27 -0
- package/dist/commands/hub/projects.d.ts +24 -0
- package/dist/commands/hub/projects.js +49 -0
- package/dist/commands/hub/reporter.d.ts +10 -0
- package/dist/commands/hub/reporter.js +11 -0
- package/dist/commands/hub/status-output.d.ts +13 -0
- package/dist/commands/hub/status-output.js +30 -0
- package/dist/commands/schedule/types.d.ts +1 -4
- package/dist/output/types.d.ts +1 -1
- package/package.json +4 -4
- package/dist/commands/hub/cloud-device-authorization.d.ts +0 -45
- package/dist/commands/hub/cloud-device-authorization.js +0 -92
- package/dist/commands/hub/device-authorization.js +0 -87
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { lstat, readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import YAML from "yaml";
|
|
4
|
-
import {
|
|
4
|
+
import { HubCommandError } from "./error.js";
|
|
5
5
|
const DEFAULT_CONFIGURATION_PATH = ".paseo/hub.yml";
|
|
6
6
|
const PROMPT_PARTIAL_ROOT = ".paseo/partials";
|
|
7
7
|
const PROMPT_PARTIAL_ROOT_PREFIX = `${PROMPT_PARTIAL_ROOT}/`;
|
|
@@ -19,10 +19,10 @@ export async function resolveHubDeployInput(input) {
|
|
|
19
19
|
const configuration = parseConfiguration(yaml);
|
|
20
20
|
const projectSlug = input.project ?? projectFromConfiguration(configuration);
|
|
21
21
|
if (projectSlug === undefined) {
|
|
22
|
-
throw new
|
|
22
|
+
throw new HubCommandError("HUB_PROJECT_REQUIRED", "Project is required. Pass --project <slug> or add top-level project to the YAML.");
|
|
23
23
|
}
|
|
24
24
|
if (!PROJECT_SLUG_PATTERN.test(projectSlug)) {
|
|
25
|
-
throw new
|
|
25
|
+
throw new HubCommandError("HUB_INVALID_PROJECT", "Project must be a bare slug such as my-project.");
|
|
26
26
|
}
|
|
27
27
|
const partials = await resolvePromptPartials(projectRoot, configuration);
|
|
28
28
|
return {
|
|
@@ -47,7 +47,7 @@ function resolveConfigurationPath(cwd, file) {
|
|
|
47
47
|
return resolved;
|
|
48
48
|
}
|
|
49
49
|
async function readConfiguration(projectRoot, configurationPath, displayPath) {
|
|
50
|
-
const unsafePath = () => new
|
|
50
|
+
const unsafePath = () => new HubCommandError("HUB_CONFIGURATION_UNSAFE_PATH", `Hub configuration at ${displayPath} must not use a symlink.`);
|
|
51
51
|
await rejectSymlinkComponents(projectRoot, configurationPath, unsafePath);
|
|
52
52
|
let stats;
|
|
53
53
|
try {
|
|
@@ -60,10 +60,10 @@ async function readConfiguration(projectRoot, configurationPath, displayPath) {
|
|
|
60
60
|
throw unsafePath();
|
|
61
61
|
}
|
|
62
62
|
if (!stats.isFile()) {
|
|
63
|
-
throw new
|
|
63
|
+
throw new HubCommandError("HUB_CONFIGURATION_NOT_FILE", `Hub configuration at ${displayPath} must be a regular file.`);
|
|
64
64
|
}
|
|
65
65
|
if (!hasReadPermission(stats.mode)) {
|
|
66
|
-
throw new
|
|
66
|
+
throw new HubCommandError("HUB_CONFIGURATION_UNREADABLE", `Could not read Hub configuration at ${displayPath}. Check file permissions.`);
|
|
67
67
|
}
|
|
68
68
|
let bytes;
|
|
69
69
|
try {
|
|
@@ -74,7 +74,7 @@ async function readConfiguration(projectRoot, configurationPath, displayPath) {
|
|
|
74
74
|
}
|
|
75
75
|
const yaml = bytes.toString("utf8");
|
|
76
76
|
if (yaml.length > MAX_CONFIGURATION_LENGTH) {
|
|
77
|
-
throw new
|
|
77
|
+
throw new HubCommandError("HUB_CONFIGURATION_TOO_LARGE", `Hub configuration at ${displayPath} exceeds the ${MAX_CONFIGURATION_LENGTH}-character limit.`);
|
|
78
78
|
}
|
|
79
79
|
return yaml;
|
|
80
80
|
}
|
|
@@ -84,10 +84,10 @@ function parseConfiguration(yaml) {
|
|
|
84
84
|
configuration = YAML.parse(yaml);
|
|
85
85
|
}
|
|
86
86
|
catch {
|
|
87
|
-
throw new
|
|
87
|
+
throw new HubCommandError("HUB_INVALID_CONFIGURATION", "Hub configuration is not valid YAML.");
|
|
88
88
|
}
|
|
89
89
|
if (!isRecord(configuration)) {
|
|
90
|
-
throw new
|
|
90
|
+
throw new HubCommandError("HUB_INVALID_CONFIGURATION", "Hub configuration must be a YAML mapping.");
|
|
91
91
|
}
|
|
92
92
|
return configuration;
|
|
93
93
|
}
|
|
@@ -96,14 +96,14 @@ function projectFromConfiguration(configuration) {
|
|
|
96
96
|
if (project === undefined)
|
|
97
97
|
return undefined;
|
|
98
98
|
if (typeof project !== "string") {
|
|
99
|
-
throw new
|
|
99
|
+
throw new HubCommandError("HUB_INVALID_PROJECT", "Top-level project must be a bare project slug.");
|
|
100
100
|
}
|
|
101
101
|
return project;
|
|
102
102
|
}
|
|
103
103
|
async function resolvePromptPartials(projectRoot, configuration) {
|
|
104
104
|
const references = collectPromptPartialReferences(configuration);
|
|
105
105
|
if (references.length > MAX_PROMPT_PARTIAL_COUNT) {
|
|
106
|
-
throw new
|
|
106
|
+
throw new HubCommandError("HUB_PARTIAL_LIMIT_EXCEEDED", `Hub configuration references ${references.length} partials; the limit is ${MAX_PROMPT_PARTIAL_COUNT}.`);
|
|
107
107
|
}
|
|
108
108
|
const partials = [];
|
|
109
109
|
let bundleBytes = 0;
|
|
@@ -112,11 +112,11 @@ async function resolvePromptPartials(projectRoot, configuration) {
|
|
|
112
112
|
const content = await readPartial(projectRoot, partialPath, reference.path);
|
|
113
113
|
const contentBytes = Buffer.byteLength(content, "utf8");
|
|
114
114
|
if (contentBytes > MAX_PROMPT_PARTIAL_CONTENT_BYTES) {
|
|
115
|
-
throw new
|
|
115
|
+
throw new HubCommandError("HUB_PARTIAL_TOO_LARGE", `Referenced Hub partial ${reference.path} exceeds the ${MAX_PROMPT_PARTIAL_CONTENT_BYTES}-byte limit.`);
|
|
116
116
|
}
|
|
117
117
|
bundleBytes += contentBytes;
|
|
118
118
|
if (bundleBytes > MAX_PROMPT_PARTIAL_BUNDLE_BYTES) {
|
|
119
|
-
throw new
|
|
119
|
+
throw new HubCommandError("HUB_PARTIAL_BUNDLE_TOO_LARGE", `Referenced Hub partials exceed the ${MAX_PROMPT_PARTIAL_BUNDLE_BYTES}-byte combined limit.`);
|
|
120
120
|
}
|
|
121
121
|
partials.push({ path: reference.path, content });
|
|
122
122
|
}
|
|
@@ -139,11 +139,11 @@ function collectPromptPartialReferences(configuration) {
|
|
|
139
139
|
continue;
|
|
140
140
|
const include = block["include"];
|
|
141
141
|
if (typeof include !== "string") {
|
|
142
|
-
throw new
|
|
142
|
+
throw new HubCommandError("HUB_PARTIAL_PATH_INVALID", "Hub partial include path must be a string.");
|
|
143
143
|
}
|
|
144
144
|
const normalizedPath = normalizePromptPartialPath(include);
|
|
145
145
|
if (seen.has(normalizedPath)) {
|
|
146
|
-
throw new
|
|
146
|
+
throw new HubCommandError("HUB_PARTIAL_DUPLICATE", `Hub partial ${normalizedPath} is referenced more than once. Remove the duplicate include.`);
|
|
147
147
|
}
|
|
148
148
|
seen.add(normalizedPath);
|
|
149
149
|
references.push({ path: normalizedPath });
|
|
@@ -168,7 +168,7 @@ function normalizePromptPartialPath(value) {
|
|
|
168
168
|
throw invalidPromptPartialPath(value);
|
|
169
169
|
}
|
|
170
170
|
if (canonical.length > MAX_PROMPT_PARTIAL_PATH_LENGTH) {
|
|
171
|
-
throw new
|
|
171
|
+
throw new HubCommandError("HUB_PARTIAL_PATH_TOO_LONG", `Hub partial path ${value} exceeds the ${MAX_PROMPT_PARTIAL_PATH_LENGTH}-character limit.`);
|
|
172
172
|
}
|
|
173
173
|
return canonical.slice(PROMPT_PARTIAL_ROOT_PREFIX.length);
|
|
174
174
|
}
|
|
@@ -192,31 +192,31 @@ function decodePromptPartialPath(value) {
|
|
|
192
192
|
return decoded;
|
|
193
193
|
}
|
|
194
194
|
async function readPartial(projectRoot, partialPath, displayPath) {
|
|
195
|
-
await rejectSymlinkComponents(projectRoot, partialPath, () => new
|
|
195
|
+
await rejectSymlinkComponents(projectRoot, partialPath, () => new HubCommandError("HUB_PARTIAL_UNSAFE_PATH", `Referenced Hub partial ${displayPath} must not use a symlink.`));
|
|
196
196
|
let stats;
|
|
197
197
|
try {
|
|
198
198
|
stats = await lstat(partialPath);
|
|
199
199
|
}
|
|
200
200
|
catch (error) {
|
|
201
201
|
if (errorCode(error) === "ENOENT") {
|
|
202
|
-
throw new
|
|
202
|
+
throw new HubCommandError("HUB_PARTIAL_MISSING", `Referenced Hub partial ${displayPath} does not exist.`);
|
|
203
203
|
}
|
|
204
|
-
throw new
|
|
204
|
+
throw new HubCommandError("HUB_PARTIAL_UNREADABLE", `Could not read referenced Hub partial ${displayPath}. Check the file and permissions.`);
|
|
205
205
|
}
|
|
206
206
|
if (stats.isSymbolicLink()) {
|
|
207
|
-
throw new
|
|
207
|
+
throw new HubCommandError("HUB_PARTIAL_UNSAFE_PATH", `Referenced Hub partial ${displayPath} must not be a symlink.`);
|
|
208
208
|
}
|
|
209
209
|
if (!stats.isFile()) {
|
|
210
|
-
throw new
|
|
210
|
+
throw new HubCommandError("HUB_PARTIAL_NOT_FILE", `Referenced Hub partial ${displayPath} must be a regular file.`);
|
|
211
211
|
}
|
|
212
212
|
if (!hasReadPermission(stats.mode)) {
|
|
213
|
-
throw new
|
|
213
|
+
throw new HubCommandError("HUB_PARTIAL_UNREADABLE", `Could not read referenced Hub partial ${displayPath}. Check the file and permissions.`);
|
|
214
214
|
}
|
|
215
215
|
try {
|
|
216
216
|
return (await readFile(partialPath)).toString("utf8");
|
|
217
217
|
}
|
|
218
218
|
catch {
|
|
219
|
-
throw new
|
|
219
|
+
throw new HubCommandError("HUB_PARTIAL_UNREADABLE", `Could not read referenced Hub partial ${displayPath}. Check the file and permissions.`);
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
async function rejectSymlinkComponents(root, target, error) {
|
|
@@ -229,7 +229,7 @@ async function rejectSymlinkComponents(root, target, error) {
|
|
|
229
229
|
throw error();
|
|
230
230
|
}
|
|
231
231
|
catch (failure) {
|
|
232
|
-
if (failure instanceof
|
|
232
|
+
if (failure instanceof HubCommandError)
|
|
233
233
|
throw failure;
|
|
234
234
|
if (errorCode(failure) === "ENOENT")
|
|
235
235
|
return;
|
|
@@ -239,15 +239,15 @@ async function rejectSymlinkComponents(root, target, error) {
|
|
|
239
239
|
}
|
|
240
240
|
function configurationReadError(displayPath, error) {
|
|
241
241
|
if (errorCode(error) === "ENOENT") {
|
|
242
|
-
return new
|
|
242
|
+
return new HubCommandError("HUB_CONFIGURATION_UNREADABLE", `Could not read Hub configuration at ${displayPath}. Pass an existing YAML file.`);
|
|
243
243
|
}
|
|
244
|
-
return new
|
|
244
|
+
return new HubCommandError("HUB_CONFIGURATION_UNREADABLE", `Could not read Hub configuration at ${displayPath}. Check the file and permissions.`);
|
|
245
245
|
}
|
|
246
246
|
function invalidConfigurationPath() {
|
|
247
|
-
return new
|
|
247
|
+
return new HubCommandError("HUB_CONFIGURATION_PATH_INVALID", "Hub configuration path must stay within the current project root; parent-directory paths are not allowed.");
|
|
248
248
|
}
|
|
249
249
|
function invalidPromptPartialPath(value) {
|
|
250
|
-
return new
|
|
250
|
+
return new HubCommandError("HUB_PARTIAL_PATH_INVALID", `Hub partial path must be a safe relative path under .paseo/partials/: ${value}`);
|
|
251
251
|
}
|
|
252
252
|
function hasReadPermission(mode) {
|
|
253
253
|
return (mode & 0o444) !== 0;
|
|
@@ -1,17 +1,37 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
import { type SingleResult } from "../../output/index.js";
|
|
3
|
-
import { type HubInstallResult } from "./client.js";
|
|
3
|
+
import { HubHttpClient, type HubInstallResult, type HubValidationResult } from "./client.js";
|
|
4
|
+
import { type HubCredentialStore } from "./credentials.js";
|
|
5
|
+
import { type HubReporter } from "./reporter.js";
|
|
4
6
|
export interface HubDeployOptions {
|
|
5
7
|
file?: string;
|
|
6
8
|
project?: string;
|
|
7
9
|
hub?: string;
|
|
8
10
|
apiKey?: string;
|
|
11
|
+
dryRun?: boolean;
|
|
12
|
+
json?: boolean;
|
|
9
13
|
}
|
|
10
14
|
interface HubDeployEnvironment {
|
|
11
15
|
cwd: string;
|
|
12
16
|
env: Readonly<Record<string, string | undefined>>;
|
|
17
|
+
credentials?: HubCredentialStore;
|
|
18
|
+
hub?: Pick<HubHttpClient, "installConfiguration" | "validateConfiguration">;
|
|
19
|
+
reporter?: HubReporter;
|
|
13
20
|
}
|
|
14
|
-
export
|
|
15
|
-
|
|
21
|
+
export interface HubDeployCommandDependencies {
|
|
22
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
23
|
+
credentials: HubCredentialStore;
|
|
24
|
+
hub: Pick<HubHttpClient, "installConfiguration" | "validateConfiguration">;
|
|
25
|
+
reporter: HubReporter;
|
|
26
|
+
cwd(): string;
|
|
27
|
+
}
|
|
28
|
+
interface HubDeployResult extends HubInstallResult {
|
|
29
|
+
origin: string;
|
|
30
|
+
}
|
|
31
|
+
interface HubDryRunResult extends HubValidationResult {
|
|
32
|
+
origin: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function runHubDeploy(options: HubDeployOptions, environment?: HubDeployEnvironment): Promise<SingleResult<HubDeployResult> | SingleResult<HubDryRunResult>>;
|
|
35
|
+
export declare function addHubDeployCommand(hub: Command, dependencies: HubDeployCommandDependencies): void;
|
|
16
36
|
export {};
|
|
17
37
|
//# sourceMappingURL=deploy.d.ts.map
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { withOutput } from "../../output/index.js";
|
|
2
2
|
import { addJsonOption } from "../../utils/command-options.js";
|
|
3
|
-
import {
|
|
3
|
+
import { resolveHubCredential, resolveHubOrigin } from "./authority.js";
|
|
4
|
+
import { HubHttpClient } from "./client.js";
|
|
5
|
+
import { PrivateHubCredentialStore } from "./credentials.js";
|
|
4
6
|
import { resolveHubDeployInput } from "./deploy-input.js";
|
|
5
|
-
import {
|
|
7
|
+
import { processHubReporter, reportHubProgress } from "./reporter.js";
|
|
8
|
+
import { addHubResolutionHelp } from "./help.js";
|
|
6
9
|
const resultSchema = {
|
|
7
10
|
idField: "versionId",
|
|
8
11
|
columns: [
|
|
@@ -10,62 +13,68 @@ const resultSchema = {
|
|
|
10
13
|
{ header: "VERSION", field: "version" },
|
|
11
14
|
{ header: "VERSION ID", field: "versionId" },
|
|
12
15
|
{ header: "ACTIVE", field: "active" },
|
|
16
|
+
{ header: "HUB", field: "origin" },
|
|
13
17
|
],
|
|
14
18
|
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
const validationSchema = {
|
|
20
|
+
idField: "projectSlug",
|
|
21
|
+
columns: [
|
|
22
|
+
{ header: "PROJECT", field: "projectSlug" },
|
|
23
|
+
{ header: "VALID", field: "valid" },
|
|
24
|
+
{ header: "HUB", field: "origin" },
|
|
25
|
+
],
|
|
26
|
+
};
|
|
27
|
+
export async function runHubDeploy(options, environment = {
|
|
28
|
+
cwd: process.cwd(),
|
|
29
|
+
env: process.env,
|
|
30
|
+
credentials: new PrivateHubCredentialStore(),
|
|
31
|
+
hub: new HubHttpClient(),
|
|
32
|
+
}) {
|
|
33
|
+
const credentials = environment.credentials ?? new PrivateHubCredentialStore(environment.env);
|
|
34
|
+
const resolution = {
|
|
35
|
+
options: { origin: options.hub, apiKey: options.apiKey },
|
|
36
|
+
env: environment.env,
|
|
37
|
+
credentials,
|
|
38
|
+
};
|
|
39
|
+
const origin = resolveHubOrigin(resolution);
|
|
25
40
|
const deployInput = await resolveHubDeployInput({
|
|
26
41
|
cwd: environment.cwd,
|
|
27
42
|
...(options.file === undefined ? {} : { file: options.file }),
|
|
28
43
|
...(options.project === undefined ? {} : { project: options.project }),
|
|
29
44
|
});
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
45
|
+
const action = options.dryRun === true ? "Validating" : "Deploying";
|
|
46
|
+
reportHubProgress(environment.reporter ?? processHubReporter, options, `${action} ${deployInput.projectSlug} ${options.dryRun === true ? "against" : "to"} ${origin}`);
|
|
47
|
+
const credential = resolveHubCredential({ ...resolution, origin });
|
|
48
|
+
const request = {
|
|
49
|
+
origin,
|
|
50
|
+
apiKey: credential,
|
|
33
51
|
...deployInput,
|
|
34
|
-
}
|
|
35
|
-
|
|
52
|
+
};
|
|
53
|
+
if (options.dryRun === true) {
|
|
54
|
+
const validated = await (environment.hub ?? new HubHttpClient()).validateConfiguration(request);
|
|
55
|
+
return { type: "single", data: { ...validated, origin }, schema: validationSchema };
|
|
56
|
+
}
|
|
57
|
+
const deployed = await (environment.hub ?? new HubHttpClient()).installConfiguration(request);
|
|
58
|
+
return { type: "single", data: { ...deployed, origin }, schema: resultSchema };
|
|
36
59
|
}
|
|
37
|
-
export function addHubDeployCommand(hub) {
|
|
38
|
-
addJsonOption(hub
|
|
60
|
+
export function addHubDeployCommand(hub, dependencies) {
|
|
61
|
+
addJsonOption(addHubResolutionHelp(hub
|
|
39
62
|
.command("deploy")
|
|
40
63
|
.description("Install and activate a Hub configuration")
|
|
41
64
|
.argument("[file]", "Hub configuration YAML", ".paseo/hub.yml")
|
|
42
65
|
.option("-p, --project <slug>", "Target project slug")
|
|
43
66
|
.option("--hub <origin>", "Paseo Hub origin")
|
|
44
|
-
.option("--api-key <secret>", "Organization API key")
|
|
67
|
+
.option("--api-key <secret>", "Organization API key")
|
|
68
|
+
.option("--dry-run", "Validate without installing or activating"))).action(withOutput(async (...args) => {
|
|
45
69
|
const file = args[0];
|
|
46
70
|
const options = args.at(-2);
|
|
47
|
-
return runHubDeploy({ ...options, file }
|
|
71
|
+
return runHubDeploy({ ...options, file }, {
|
|
72
|
+
cwd: dependencies.cwd(),
|
|
73
|
+
env: dependencies.env,
|
|
74
|
+
credentials: dependencies.credentials,
|
|
75
|
+
hub: dependencies.hub,
|
|
76
|
+
reporter: dependencies.reporter,
|
|
77
|
+
});
|
|
48
78
|
}));
|
|
49
79
|
}
|
|
50
|
-
function parseHubOrigin(value) {
|
|
51
|
-
let url;
|
|
52
|
-
try {
|
|
53
|
-
url = new URL(value);
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
throw invalidHubOrigin();
|
|
57
|
-
}
|
|
58
|
-
if (!["http:", "https:"].includes(url.protocol) ||
|
|
59
|
-
url.username ||
|
|
60
|
-
url.password ||
|
|
61
|
-
url.pathname !== "/" ||
|
|
62
|
-
url.search ||
|
|
63
|
-
url.hash) {
|
|
64
|
-
throw invalidHubOrigin();
|
|
65
|
-
}
|
|
66
|
-
return url.origin;
|
|
67
|
-
}
|
|
68
|
-
function invalidHubOrigin() {
|
|
69
|
-
return new HubDeployError("HUB_INVALID_ORIGIN", "Hub URL must be an HTTP or HTTPS origin without credentials, path, query, or hash.");
|
|
70
|
-
}
|
|
71
80
|
//# sourceMappingURL=deploy.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { HubDaemonConnection } from "./daemon-client.js";
|
|
3
|
+
import { type HubReporter } from "./reporter.js";
|
|
4
|
+
interface HubDisconnectOptions {
|
|
5
|
+
force?: boolean;
|
|
6
|
+
host?: string;
|
|
7
|
+
json?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface HubDisconnectDependencies {
|
|
10
|
+
daemon: HubDaemonConnection;
|
|
11
|
+
reporter: HubReporter;
|
|
12
|
+
}
|
|
13
|
+
export declare function runHubDisconnect(options: HubDisconnectOptions, dependencies: HubDisconnectDependencies): Promise<import("../../output/types.js").ListResult<import("./status-output.js").HubRow>>;
|
|
14
|
+
export declare function addHubDisconnectCommand(parent: Command, dependencies: HubDisconnectDependencies): void;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=disconnect.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { withOutput } from "../../output/index.js";
|
|
2
|
+
import { addJsonAndDaemonHostOptions } from "../../utils/command-options.js";
|
|
3
|
+
import { withHubDaemon } from "./daemon-client.js";
|
|
4
|
+
import { reportHubProgress } from "./reporter.js";
|
|
5
|
+
import { hubStatusResult } from "./status-output.js";
|
|
6
|
+
export function runHubDisconnect(options, dependencies) {
|
|
7
|
+
return withHubDaemon(dependencies.daemon, options.host, async (client) => {
|
|
8
|
+
const current = (await client.getHubStatus()).status;
|
|
9
|
+
if (current.hubOrigin !== null) {
|
|
10
|
+
reportHubProgress(dependencies.reporter, options, `Disconnecting this daemon from ${current.hubOrigin}`);
|
|
11
|
+
}
|
|
12
|
+
const response = await client.disconnectHub(options.force ?? false);
|
|
13
|
+
return hubStatusResult(response.status, response.warning, current.hubOrigin);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export function addHubDisconnectCommand(parent, dependencies) {
|
|
17
|
+
addJsonAndDaemonHostOptions(parent
|
|
18
|
+
.command("disconnect")
|
|
19
|
+
.option("--force", "Remove local authority even if the Hub is offline")).action(withOutput(async (...args) => {
|
|
20
|
+
const options = args.at(-2);
|
|
21
|
+
return runHubDisconnect(options, dependencies);
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=disconnect.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export class
|
|
1
|
+
export class HubCommandError extends Error {
|
|
2
2
|
constructor(code, message, details) {
|
|
3
3
|
super(message);
|
|
4
4
|
this.code = code;
|
|
5
5
|
this.details = details;
|
|
6
|
-
this.name = "
|
|
6
|
+
this.name = "HubCommandError";
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
const resolutionHelp = "\nHub origin precedence: command origin/--hub, PASEO_HUB_URL, active stored login, then https://hub.paseo.sh.\nCredential precedence: --api-key, PASEO_HUB_API_KEY, then a stored login for the exact resolved origin.\n";
|
|
2
|
+
export function addHubResolutionHelp(command) {
|
|
3
|
+
return command.addHelpText("after", resolutionHelp);
|
|
4
|
+
}
|
|
5
|
+
//# sourceMappingURL=help.js.map
|
|
@@ -1,30 +1,20 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
status: HubStatus;
|
|
8
|
-
}>;
|
|
9
|
-
disconnectHub(force: boolean): Promise<{
|
|
10
|
-
status: HubStatus;
|
|
11
|
-
warning?: string;
|
|
12
|
-
}>;
|
|
13
|
-
close(): Promise<void>;
|
|
14
|
-
}
|
|
15
|
-
interface HubStatus {
|
|
16
|
-
state: string;
|
|
17
|
-
daemonId: string | null;
|
|
18
|
-
hubOrigin: string | null;
|
|
19
|
-
scopes: string[];
|
|
20
|
-
connectedAt: string | null;
|
|
21
|
-
lastError: string | null;
|
|
22
|
-
}
|
|
2
|
+
import { HubHttpClient } from "./client.js";
|
|
3
|
+
import { type HubCredentialStore } from "./credentials.js";
|
|
4
|
+
import { type HubDaemonConnection } from "./daemon-client.js";
|
|
5
|
+
import { type CliLoginFlow } from "./login-flow.js";
|
|
6
|
+
import { type HubReporter } from "./reporter.js";
|
|
23
7
|
interface HubCommandEnvironment {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
8
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
9
|
+
credentials: HubCredentialStore;
|
|
10
|
+
hub: HubHttpClient;
|
|
11
|
+
login: Pick<CliLoginFlow, "authorize">;
|
|
12
|
+
daemon: HubDaemonConnection;
|
|
13
|
+
isInteractive(): boolean;
|
|
14
|
+
confirmDisconnect(origin: string): Promise<boolean>;
|
|
15
|
+
reporter: HubReporter;
|
|
16
|
+
cwd(): string;
|
|
27
17
|
}
|
|
28
|
-
export declare function createHubCommand(
|
|
18
|
+
export declare function createHubCommand(overrides?: Partial<HubCommandEnvironment>): Command;
|
|
29
19
|
export {};
|
|
30
20
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -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 {
|
|
6
|
-
import {
|
|
4
|
+
import { HubHttpClient } from "./client.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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
49
|
+
return withHubDaemon(environment.daemon, options.host, async (client) => hubStatusResult((await client.getHubStatus()).status));
|
|
71
50
|
}));
|
|
72
|
-
|
|
73
|
-
.
|
|
74
|
-
.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|