@otto-code/cli 0.8.12 → 0.8.13
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/cli.js +1 -5
- package/dist/commands/daemon/index.js +1 -0
- package/dist/commands/daemon/local-daemon.js +3 -0
- package/dist/commands/daemon/pair.d.ts +27 -1
- package/dist/commands/daemon/pair.js +133 -46
- package/dist/commands/daemon/start.js +1 -0
- package/dist/commands/daemon/status.d.ts +11 -0
- package/dist/commands/daemon/status.js +47 -22
- package/dist/commands/hub/authority.d.ts +17 -0
- package/dist/commands/hub/authority.js +18 -0
- 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-bundle.d.ts +16 -0
- package/dist/commands/hub/deploy-bundle.js +248 -0
- package/dist/commands/hub/deploy.d.ts +40 -0
- package/dist/commands/hub/deploy.js +90 -0
- package/dist/commands/hub/disconnect.d.ts +16 -0
- package/dist/commands/hub/disconnect.js +24 -0
- package/dist/commands/hub/error.d.ts +6 -0
- package/dist/commands/hub/error.js +9 -0
- package/dist/commands/hub/help.d.ts +3 -0
- package/dist/commands/hub/help.js +5 -0
- package/dist/commands/hub/hub-client/index.d.ts +19 -0
- package/dist/commands/hub/hub-client/index.js +99 -0
- package/dist/commands/hub/hub-client/internal/contracts.d.ts +86 -0
- package/dist/commands/hub/hub-client/internal/contracts.js +62 -0
- package/dist/commands/hub/hub-client/internal/problem.d.ts +3 -0
- package/dist/commands/hub/hub-client/internal/problem.js +85 -0
- package/dist/commands/hub/hub-client/internal/transport.d.ts +15 -0
- package/dist/commands/hub/hub-client/internal/transport.js +30 -0
- package/dist/commands/hub/index.d.ts +15 -25
- package/dist/commands/hub/index.js +67 -73
- package/dist/commands/hub/init-plan.d.ts +50 -0
- package/dist/commands/hub/init-plan.js +136 -0
- package/dist/commands/hub/init.d.ts +20 -0
- package/dist/commands/hub/init.js +415 -0
- 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 +32 -0
- package/dist/commands/hub/logout.js +71 -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/onboard.js +20 -40
- package/dist/commands/provider/diagnostic.d.ts +12 -0
- package/dist/commands/provider/diagnostic.js +31 -0
- package/dist/commands/provider/index.js +5 -0
- package/dist/commands/schedule/types.d.ts +1 -4
- package/dist/commands/workspace/index.js +10 -0
- package/dist/commands/workspace/rename.d.ts +22 -0
- package/dist/commands/workspace/rename.js +61 -0
- package/dist/output/types.d.ts +1 -1
- package/dist/run.js +8 -1
- package/dist/utils/client.js +4 -1
- package/package.json +5 -5
- package/dist/commands/chat/create.d.ts +0 -9
- package/dist/commands/chat/create.js +0 -23
- package/dist/commands/chat/delete.d.ts +0 -6
- package/dist/commands/chat/delete.js +0 -20
- package/dist/commands/chat/index.d.ts +0 -3
- package/dist/commands/chat/index.js +0 -47
- package/dist/commands/chat/inspect.d.ts +0 -6
- package/dist/commands/chat/inspect.js +0 -20
- package/dist/commands/chat/ls.d.ts +0 -6
- package/dist/commands/chat/ls.js +0 -20
- package/dist/commands/chat/post.d.ts +0 -9
- package/dist/commands/chat/post.js +0 -28
- package/dist/commands/chat/read.d.ts +0 -11
- package/dist/commands/chat/read.js +0 -40
- package/dist/commands/chat/schema.d.ts +0 -36
- package/dist/commands/chat/schema.js +0 -81
- package/dist/commands/chat/shared.d.ts +0 -19
- package/dist/commands/chat/shared.js +0 -118
- package/dist/commands/chat/wait.d.ts +0 -9
- package/dist/commands/chat/wait.js +0 -45
- 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
- package/dist/commands/loop/index.d.ts +0 -3
- package/dist/commands/loop/index.js +0 -18
- package/dist/commands/loop/inspect.d.ts +0 -13
- package/dist/commands/loop/inspect.js +0 -100
- package/dist/commands/loop/logs.d.ts +0 -8
- package/dist/commands/loop/logs.js +0 -69
- package/dist/commands/loop/ls.d.ts +0 -18
- package/dist/commands/loop/ls.js +0 -62
- package/dist/commands/loop/run.d.ts +0 -30
- package/dist/commands/loop/run.js +0 -162
- package/dist/commands/loop/stop.d.ts +0 -15
- package/dist/commands/loop/stop.js +0 -56
- package/dist/commands/loop/types.d.ts +0 -138
- package/dist/commands/loop/types.js +0 -2
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { HubCommandError } from "../error.js";
|
|
2
|
+
import { authorizationPollSchema, authorizationSchema, configurationResourcesSchema, enrollmentTokenSchema, installResponseSchema, projectsResponseSchema, validationResponseSchema, } from "./internal/contracts.js";
|
|
3
|
+
import { requestHub } from "./internal/transport.js";
|
|
4
|
+
export class HubHttpClient {
|
|
5
|
+
startCliAuthorization(origin) {
|
|
6
|
+
return requestHub({
|
|
7
|
+
origin,
|
|
8
|
+
path: "/api/v1/cli-authorizations",
|
|
9
|
+
method: "POST",
|
|
10
|
+
body: {},
|
|
11
|
+
successStatus: 201,
|
|
12
|
+
schema: authorizationSchema,
|
|
13
|
+
failureMessage: "Hub CLI login could not be started",
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
async pollCliAuthorization(origin, deviceCode, timeoutMilliseconds) {
|
|
17
|
+
try {
|
|
18
|
+
return await requestHub({
|
|
19
|
+
origin,
|
|
20
|
+
path: "/api/v1/cli-authorizations/poll",
|
|
21
|
+
method: "POST",
|
|
22
|
+
body: { deviceCode },
|
|
23
|
+
successStatus: 200,
|
|
24
|
+
schema: authorizationPollSchema,
|
|
25
|
+
timeoutMilliseconds,
|
|
26
|
+
failureMessage: "Hub CLI login polling failed",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (error instanceof HubCommandError && error.code === "HUB_NETWORK_ERROR") {
|
|
31
|
+
return { status: "retry_later" };
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async listProjects(origin, apiKey) {
|
|
37
|
+
const response = await requestHub({
|
|
38
|
+
origin,
|
|
39
|
+
path: "/api/v1/projects",
|
|
40
|
+
method: "GET",
|
|
41
|
+
apiKey,
|
|
42
|
+
successStatus: 200,
|
|
43
|
+
schema: projectsResponseSchema,
|
|
44
|
+
failureMessage: "Hub project listing failed",
|
|
45
|
+
});
|
|
46
|
+
return response.projects;
|
|
47
|
+
}
|
|
48
|
+
listConfigurationResources(origin, apiKey) {
|
|
49
|
+
return requestHub({
|
|
50
|
+
origin,
|
|
51
|
+
path: "/api/v1/configuration-resources",
|
|
52
|
+
method: "GET",
|
|
53
|
+
apiKey,
|
|
54
|
+
successStatus: 200,
|
|
55
|
+
schema: configurationResourcesSchema,
|
|
56
|
+
failureMessage: "Hub configuration resource listing failed",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
installConfiguration(input) {
|
|
60
|
+
return requestHub({
|
|
61
|
+
origin: input.origin,
|
|
62
|
+
path: "/api/v1/configurations/install",
|
|
63
|
+
method: "POST",
|
|
64
|
+
apiKey: input.apiKey,
|
|
65
|
+
body: configurationBody(input),
|
|
66
|
+
successStatus: 201,
|
|
67
|
+
schema: installResponseSchema,
|
|
68
|
+
failureMessage: "Hub deployment failed",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
validateConfiguration(input) {
|
|
72
|
+
return requestHub({
|
|
73
|
+
origin: input.origin,
|
|
74
|
+
path: "/api/v1/configurations/validate",
|
|
75
|
+
method: "POST",
|
|
76
|
+
apiKey: input.apiKey,
|
|
77
|
+
body: configurationBody(input),
|
|
78
|
+
successStatus: 200,
|
|
79
|
+
schema: validationResponseSchema,
|
|
80
|
+
failureMessage: "Hub configuration validation failed",
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async issueEnrollmentToken(origin, apiKey) {
|
|
84
|
+
const response = await requestHub({
|
|
85
|
+
origin,
|
|
86
|
+
path: "/api/v1/daemons/enrollment-tokens",
|
|
87
|
+
method: "POST",
|
|
88
|
+
apiKey,
|
|
89
|
+
successStatus: 201,
|
|
90
|
+
schema: enrollmentTokenSchema,
|
|
91
|
+
failureMessage: "Hub daemon enrollment authorization failed",
|
|
92
|
+
});
|
|
93
|
+
return response.token;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function configurationBody(input) {
|
|
97
|
+
return { projectSlug: input.projectSlug, files: input.files };
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const authorizationSchema: z.ZodObject<{
|
|
3
|
+
deviceCode: z.ZodString;
|
|
4
|
+
userCode: z.ZodString;
|
|
5
|
+
verificationUri: z.ZodURL;
|
|
6
|
+
verificationUriComplete: z.ZodURL;
|
|
7
|
+
expiresAt: z.ZodString;
|
|
8
|
+
interval: z.ZodNumber;
|
|
9
|
+
}, z.core.$strict>;
|
|
10
|
+
export declare const authorizationPollSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
11
|
+
status: z.ZodLiteral<"pending">;
|
|
12
|
+
interval: z.ZodNumber;
|
|
13
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
14
|
+
status: z.ZodLiteral<"slow_down">;
|
|
15
|
+
interval: z.ZodNumber;
|
|
16
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
17
|
+
status: z.ZodLiteral<"authorized">;
|
|
18
|
+
interval: z.ZodNumber;
|
|
19
|
+
credential: z.ZodString;
|
|
20
|
+
organizationId: z.ZodString;
|
|
21
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
22
|
+
status: z.ZodLiteral<"denied">;
|
|
23
|
+
interval: z.ZodNumber;
|
|
24
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
25
|
+
status: z.ZodLiteral<"expired">;
|
|
26
|
+
interval: z.ZodNumber;
|
|
27
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
28
|
+
status: z.ZodLiteral<"disclosed">;
|
|
29
|
+
interval: z.ZodNumber;
|
|
30
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
31
|
+
status: z.ZodLiteral<"retry_later">;
|
|
32
|
+
}, z.core.$strict>], "status">;
|
|
33
|
+
declare const projectSchema: z.ZodObject<{
|
|
34
|
+
id: z.ZodString;
|
|
35
|
+
slug: z.ZodString;
|
|
36
|
+
name: z.ZodString;
|
|
37
|
+
}, z.core.$strict>;
|
|
38
|
+
export declare const projectsResponseSchema: z.ZodObject<{
|
|
39
|
+
projects: z.ZodArray<z.ZodObject<{
|
|
40
|
+
id: z.ZodString;
|
|
41
|
+
slug: z.ZodString;
|
|
42
|
+
name: z.ZodString;
|
|
43
|
+
}, z.core.$strict>>;
|
|
44
|
+
}, z.core.$strict>;
|
|
45
|
+
export declare const configurationResourcesSchema: z.ZodObject<{
|
|
46
|
+
daemons: z.ZodArray<z.ZodObject<{
|
|
47
|
+
id: z.ZodString;
|
|
48
|
+
slug: z.ZodString;
|
|
49
|
+
}, z.core.$strict>>;
|
|
50
|
+
github: z.ZodArray<z.ZodObject<{
|
|
51
|
+
slug: z.ZodString;
|
|
52
|
+
accountLogin: z.ZodString;
|
|
53
|
+
accountType: z.ZodString;
|
|
54
|
+
repositories: z.ZodArray<z.ZodString>;
|
|
55
|
+
}, z.core.$strict>>;
|
|
56
|
+
discord: z.ZodArray<z.ZodObject<{
|
|
57
|
+
slug: z.ZodString;
|
|
58
|
+
guildName: z.ZodString;
|
|
59
|
+
}, z.core.$strict>>;
|
|
60
|
+
slack: z.ZodArray<z.ZodObject<{
|
|
61
|
+
slug: z.ZodString;
|
|
62
|
+
teamName: z.ZodString;
|
|
63
|
+
}, z.core.$strict>>;
|
|
64
|
+
}, z.core.$strict>;
|
|
65
|
+
export declare const installResponseSchema: z.ZodObject<{
|
|
66
|
+
projectSlug: z.ZodString;
|
|
67
|
+
version: z.ZodNumber;
|
|
68
|
+
versionId: z.ZodString;
|
|
69
|
+
active: z.ZodLiteral<true>;
|
|
70
|
+
}, z.core.$strict>;
|
|
71
|
+
export declare const validationResponseSchema: z.ZodObject<{
|
|
72
|
+
projectSlug: z.ZodString;
|
|
73
|
+
valid: z.ZodLiteral<true>;
|
|
74
|
+
}, z.core.$strict>;
|
|
75
|
+
export declare const enrollmentTokenSchema: z.ZodObject<{
|
|
76
|
+
token: z.ZodString;
|
|
77
|
+
expiresAt: z.ZodString;
|
|
78
|
+
}, z.core.$strict>;
|
|
79
|
+
export type CliAuthorization = z.infer<typeof authorizationSchema>;
|
|
80
|
+
export type CliAuthorizationPoll = z.infer<typeof authorizationPollSchema>;
|
|
81
|
+
export type HubProject = z.infer<typeof projectSchema>;
|
|
82
|
+
export type HubConfigurationResources = z.infer<typeof configurationResourcesSchema>;
|
|
83
|
+
export type HubInstallResult = z.infer<typeof installResponseSchema>;
|
|
84
|
+
export type HubValidationResult = z.infer<typeof validationResponseSchema>;
|
|
85
|
+
export {};
|
|
86
|
+
//# sourceMappingURL=contracts.d.ts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const activationUrlSchema = z.url({ protocol: /^https?$/u });
|
|
3
|
+
export const authorizationSchema = z
|
|
4
|
+
.object({
|
|
5
|
+
deviceCode: z.string().min(32),
|
|
6
|
+
userCode: z.string().min(1),
|
|
7
|
+
verificationUri: activationUrlSchema,
|
|
8
|
+
verificationUriComplete: activationUrlSchema,
|
|
9
|
+
expiresAt: z.string().datetime(),
|
|
10
|
+
interval: z.number().int().min(1),
|
|
11
|
+
})
|
|
12
|
+
.strict();
|
|
13
|
+
export const authorizationPollSchema = z.discriminatedUnion("status", [
|
|
14
|
+
z.object({ status: z.literal("pending"), interval: z.number().int().min(1) }).strict(),
|
|
15
|
+
z.object({ status: z.literal("slow_down"), interval: z.number().int().min(1) }).strict(),
|
|
16
|
+
z
|
|
17
|
+
.object({
|
|
18
|
+
status: z.literal("authorized"),
|
|
19
|
+
interval: z.number().int().min(1),
|
|
20
|
+
credential: z.string().min(32),
|
|
21
|
+
organizationId: z.string().min(1),
|
|
22
|
+
})
|
|
23
|
+
.strict(),
|
|
24
|
+
z.object({ status: z.literal("denied"), interval: z.number().int().min(1) }).strict(),
|
|
25
|
+
z.object({ status: z.literal("expired"), interval: z.number().int().min(1) }).strict(),
|
|
26
|
+
z.object({ status: z.literal("disclosed"), interval: z.number().int().min(1) }).strict(),
|
|
27
|
+
z.object({ status: z.literal("retry_later") }).strict(),
|
|
28
|
+
]);
|
|
29
|
+
const projectSchema = z
|
|
30
|
+
.object({ id: z.string().uuid(), slug: z.string().min(1), name: z.string().min(1) })
|
|
31
|
+
.strict();
|
|
32
|
+
export const projectsResponseSchema = z.object({ projects: z.array(projectSchema) }).strict();
|
|
33
|
+
export const configurationResourcesSchema = z
|
|
34
|
+
.object({
|
|
35
|
+
daemons: z.array(z.object({ id: z.string().uuid(), slug: z.string().min(1) }).strict()),
|
|
36
|
+
github: z.array(z
|
|
37
|
+
.object({
|
|
38
|
+
slug: z.string().min(1),
|
|
39
|
+
accountLogin: z.string().min(1),
|
|
40
|
+
accountType: z.string().min(1),
|
|
41
|
+
repositories: z.array(z.string().min(1)),
|
|
42
|
+
})
|
|
43
|
+
.strict()),
|
|
44
|
+
discord: z.array(z.object({ slug: z.string().min(1), guildName: z.string().min(1) }).strict()),
|
|
45
|
+
slack: z.array(z.object({ slug: z.string().min(1), teamName: z.string().min(1) }).strict()),
|
|
46
|
+
})
|
|
47
|
+
.strict();
|
|
48
|
+
export const installResponseSchema = z
|
|
49
|
+
.object({
|
|
50
|
+
projectSlug: z.string().min(1),
|
|
51
|
+
version: z.number().int().positive(),
|
|
52
|
+
versionId: z.string().uuid(),
|
|
53
|
+
active: z.literal(true),
|
|
54
|
+
})
|
|
55
|
+
.strict();
|
|
56
|
+
export const validationResponseSchema = z
|
|
57
|
+
.object({ projectSlug: z.string().min(1), valid: z.literal(true) })
|
|
58
|
+
.strict();
|
|
59
|
+
export const enrollmentTokenSchema = z
|
|
60
|
+
.object({ token: z.string().min(32), expiresAt: z.string().datetime() })
|
|
61
|
+
.strict();
|
|
62
|
+
//# sourceMappingURL=contracts.js.map
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { HubCommandError } from "../../error.js";
|
|
3
|
+
const issuePathSchema = z.union([z.string(), z.array(z.union([z.string(), z.number()]))]);
|
|
4
|
+
const fieldIssueSchema = z.object({
|
|
5
|
+
field: z.string().optional(),
|
|
6
|
+
path: issuePathSchema.optional(),
|
|
7
|
+
message: z.string(),
|
|
8
|
+
});
|
|
9
|
+
const problemSchema = z.object({
|
|
10
|
+
type: z.string().optional(),
|
|
11
|
+
title: z.string().optional(),
|
|
12
|
+
status: z.number().int().optional(),
|
|
13
|
+
detail: z.string().optional(),
|
|
14
|
+
instance: z.string().optional(),
|
|
15
|
+
errors: z
|
|
16
|
+
.union([z.array(fieldIssueSchema), z.record(z.string(), z.array(z.string()))])
|
|
17
|
+
.optional(),
|
|
18
|
+
issues: z.array(fieldIssueSchema).optional(),
|
|
19
|
+
});
|
|
20
|
+
export async function hubRequestFailure(response, failureMessage, apiKey) {
|
|
21
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
22
|
+
if (!contentType.toLowerCase().includes("application/problem+json")) {
|
|
23
|
+
return new HubCommandError("HUB_REQUEST_FAILED", `${failureMessage} with HTTP ${response.status}.`);
|
|
24
|
+
}
|
|
25
|
+
let body;
|
|
26
|
+
try {
|
|
27
|
+
body = await response.json();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return new HubCommandError("HUB_INVALID_RESPONSE", `Hub returned malformed problem details for HTTP ${response.status}.`);
|
|
31
|
+
}
|
|
32
|
+
const parsed = problemSchema.safeParse(body);
|
|
33
|
+
if (!parsed.success ||
|
|
34
|
+
(parsed.data.status !== undefined && parsed.data.status !== response.status)) {
|
|
35
|
+
return new HubCommandError("HUB_INVALID_RESPONSE", `Hub returned nonconforming problem details for HTTP ${response.status}.`);
|
|
36
|
+
}
|
|
37
|
+
const title = parsed.data.title ?? `${failureMessage} with HTTP ${response.status}`;
|
|
38
|
+
const details = formatFieldIssues(parsed.data.errors, parsed.data.issues);
|
|
39
|
+
const message = details !== undefined || parsed.data.detail === undefined
|
|
40
|
+
? title
|
|
41
|
+
: `${title}: ${parsed.data.detail}`;
|
|
42
|
+
let code = "HUB_REQUEST_FAILED";
|
|
43
|
+
if (response.status === 422)
|
|
44
|
+
code = "HUB_VALIDATION_FAILED";
|
|
45
|
+
if (response.status === 404)
|
|
46
|
+
code = "HUB_NOT_FOUND";
|
|
47
|
+
return new HubCommandError(code, redactSecret(message, apiKey), details === undefined ? undefined : redactSecret(details, apiKey));
|
|
48
|
+
}
|
|
49
|
+
function formatFieldIssues(errors, issues) {
|
|
50
|
+
const fieldIssues = Array.isArray(errors) ? errors : issues;
|
|
51
|
+
if (fieldIssues !== undefined) {
|
|
52
|
+
const lines = fieldIssues.map((issue) => {
|
|
53
|
+
const field = issue.field ?? formatIssuePath(issue.path);
|
|
54
|
+
return field === undefined ? issue.message : `${field}: ${issue.message}`;
|
|
55
|
+
});
|
|
56
|
+
return lines.length === 0 ? undefined : lines.join("\n");
|
|
57
|
+
}
|
|
58
|
+
if (errors === undefined)
|
|
59
|
+
return undefined;
|
|
60
|
+
const lines = Object.entries(errors).flatMap(([field, messages]) => messages.map((message) => `${field}: ${message}`));
|
|
61
|
+
return lines.length === 0 ? undefined : lines.join("\n");
|
|
62
|
+
}
|
|
63
|
+
function formatIssuePath(path) {
|
|
64
|
+
if (path === undefined || typeof path === "string")
|
|
65
|
+
return path;
|
|
66
|
+
const [file, ...fieldPath] = path;
|
|
67
|
+
if (typeof file === "string" && file.startsWith(".otto/") && fieldPath.length > 0) {
|
|
68
|
+
return `${file}: ${formatPathSegments(fieldPath)}`;
|
|
69
|
+
}
|
|
70
|
+
return formatPathSegments(path) || undefined;
|
|
71
|
+
}
|
|
72
|
+
function formatPathSegments(path) {
|
|
73
|
+
let formatted = "";
|
|
74
|
+
for (const segment of path) {
|
|
75
|
+
if (typeof segment === "number")
|
|
76
|
+
formatted += `[${segment}]`;
|
|
77
|
+
else
|
|
78
|
+
formatted += formatted.length === 0 ? segment : `.${segment}`;
|
|
79
|
+
}
|
|
80
|
+
return formatted;
|
|
81
|
+
}
|
|
82
|
+
function redactSecret(value, secret) {
|
|
83
|
+
return secret === undefined ? value : value.split(secret).join("[redacted]");
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=problem.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
interface HubRequest<T> {
|
|
3
|
+
origin: string;
|
|
4
|
+
path: string;
|
|
5
|
+
method: "GET" | "POST";
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
body?: unknown;
|
|
8
|
+
successStatus: number;
|
|
9
|
+
schema: z.ZodType<T>;
|
|
10
|
+
timeoutMilliseconds?: number;
|
|
11
|
+
failureMessage: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function requestHub<T>(input: HubRequest<T>): Promise<T>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { HubCommandError } from "../../error.js";
|
|
2
|
+
import { hubRequestFailure } from "./problem.js";
|
|
3
|
+
export async function requestHub(input) {
|
|
4
|
+
const signal = AbortSignal.timeout(input.timeoutMilliseconds ?? 15000);
|
|
5
|
+
let response;
|
|
6
|
+
try {
|
|
7
|
+
response = await fetch(`${input.origin}${input.path}`, {
|
|
8
|
+
method: input.method,
|
|
9
|
+
headers: {
|
|
10
|
+
...(input.apiKey === undefined ? {} : { authorization: `Bearer ${input.apiKey}` }),
|
|
11
|
+
...(input.body === undefined ? {} : { "content-type": "application/json" }),
|
|
12
|
+
},
|
|
13
|
+
...(input.body === undefined ? {} : { body: JSON.stringify(input.body) }),
|
|
14
|
+
signal,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
throw new HubCommandError("HUB_NETWORK_ERROR", `Could not reach Paseo Hub at ${input.origin}. Check the Hub URL and network connection.`);
|
|
19
|
+
}
|
|
20
|
+
if (response.status !== input.successStatus) {
|
|
21
|
+
throw await hubRequestFailure(response, input.failureMessage, input.apiKey);
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
return input.schema.parse(await response.json());
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
throw new HubCommandError("HUB_INVALID_RESPONSE", "Hub returned a malformed response.");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=transport.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 "./hub-client/index.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,85 +1,79 @@
|
|
|
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 {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
],
|
|
23
|
-
};
|
|
24
|
-
function result(status, warning) {
|
|
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";
|
|
8
|
+
import { addHubDeployCommand } from "./deploy.js";
|
|
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
|
+
import { addHubInitCommand } from "./init.js";
|
|
18
|
+
function productionEnvironment() {
|
|
19
|
+
const env = process.env;
|
|
20
|
+
const hub = new HubHttpClient();
|
|
25
21
|
return {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
error: status.lastError,
|
|
35
|
-
warning,
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
schema,
|
|
22
|
+
env,
|
|
23
|
+
credentials: new PrivateHubCredentialStore(env),
|
|
24
|
+
hub,
|
|
25
|
+
login: createCliLoginFlow(hub),
|
|
26
|
+
daemon: productionHubDaemonConnection,
|
|
27
|
+
reporter: processHubReporter,
|
|
28
|
+
cwd: () => process.cwd(),
|
|
29
|
+
...productionLogoutPrompt,
|
|
39
30
|
};
|
|
40
31
|
}
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
const existing = (await client.getHubStatus()).status;
|
|
60
|
-
if (existing.state !== "not_connected" && existing.state !== "revoked") {
|
|
61
|
-
throw new Error("This daemon already has a Hub relationship");
|
|
62
|
-
}
|
|
63
|
-
const token = await environment.authorize(url, suggestedDisplayName(environment.displayName()));
|
|
64
|
-
return result((await client.connectHub(url, token)).status);
|
|
65
|
-
});
|
|
66
|
-
}));
|
|
32
|
+
export function createHubCommand(overrides = {}) {
|
|
33
|
+
const environment = { ...productionEnvironment(), ...overrides };
|
|
34
|
+
const hub = addHubResolutionHelp(new Command("hub").description("Manage Otto Hub"));
|
|
35
|
+
addHubLoginCommand(hub, {
|
|
36
|
+
env: environment.env,
|
|
37
|
+
credentials: environment.credentials,
|
|
38
|
+
flow: environment.login,
|
|
39
|
+
reporter: environment.reporter,
|
|
40
|
+
});
|
|
41
|
+
addHubInitCommand(hub, environment);
|
|
42
|
+
addHubConnectCommand(hub, {
|
|
43
|
+
env: environment.env,
|
|
44
|
+
credentials: environment.credentials,
|
|
45
|
+
hub: environment.hub,
|
|
46
|
+
daemon: environment.daemon,
|
|
47
|
+
reporter: environment.reporter,
|
|
48
|
+
});
|
|
67
49
|
addJsonAndDaemonHostOptions(hub.command("status")).action(withOutput(async (...args) => {
|
|
68
50
|
const options = args.at(-2);
|
|
69
|
-
return
|
|
70
|
-
}));
|
|
71
|
-
addJsonAndDaemonHostOptions(hub
|
|
72
|
-
.command("disconnect")
|
|
73
|
-
.option("--force", "Remove local authority even if the Hub is offline")).action(withOutput(async (...args) => {
|
|
74
|
-
const options = args.at(-2);
|
|
75
|
-
return withClient(environment, options.host, async (client) => {
|
|
76
|
-
const response = await client.disconnectHub(options.force ?? false);
|
|
77
|
-
return result(response.status, response.warning);
|
|
78
|
-
});
|
|
51
|
+
return withHubDaemon(environment.daemon, options.host, async (client) => hubStatusResult((await client.getHubStatus()).status));
|
|
79
52
|
}));
|
|
53
|
+
addHubDisconnectCommand(hub, {
|
|
54
|
+
daemon: environment.daemon,
|
|
55
|
+
reporter: environment.reporter,
|
|
56
|
+
});
|
|
57
|
+
addHubProjectsCommand(hub, {
|
|
58
|
+
env: environment.env,
|
|
59
|
+
credentials: environment.credentials,
|
|
60
|
+
hub: environment.hub,
|
|
61
|
+
reporter: environment.reporter,
|
|
62
|
+
});
|
|
63
|
+
addHubDeployCommand(hub, {
|
|
64
|
+
env: environment.env,
|
|
65
|
+
credentials: environment.credentials,
|
|
66
|
+
hub: environment.hub,
|
|
67
|
+
reporter: environment.reporter,
|
|
68
|
+
cwd: environment.cwd,
|
|
69
|
+
});
|
|
70
|
+
addHubLogoutCommand(hub, {
|
|
71
|
+
credentials: environment.credentials,
|
|
72
|
+
daemon: environment.daemon,
|
|
73
|
+
isInteractive: environment.isInteractive,
|
|
74
|
+
confirmDisconnect: environment.confirmDisconnect,
|
|
75
|
+
reporter: environment.reporter,
|
|
76
|
+
});
|
|
80
77
|
return hub;
|
|
81
78
|
}
|
|
82
|
-
function suggestedDisplayName(value) {
|
|
83
|
-
return value.trim().slice(0, 100) || "Otto daemon";
|
|
84
|
-
}
|
|
85
79
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { HubDeployBundle } from "./deploy-bundle.js";
|
|
2
|
+
import type { HubProject } from "./hub-client/index.js";
|
|
3
|
+
import type { HubStatus } from "./daemon-client.js";
|
|
4
|
+
export type HubInitProvider = "github" | "slack" | "discord";
|
|
5
|
+
export type HubInitProjectResolution = {
|
|
6
|
+
kind: "none";
|
|
7
|
+
} | {
|
|
8
|
+
kind: "selected";
|
|
9
|
+
project: HubProject;
|
|
10
|
+
} | {
|
|
11
|
+
kind: "choose";
|
|
12
|
+
projects: readonly HubProject[];
|
|
13
|
+
};
|
|
14
|
+
export type HubInitConnectionResolution = {
|
|
15
|
+
kind: "connected";
|
|
16
|
+
daemonId: string;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "pending";
|
|
19
|
+
state: "connecting" | "reconnecting";
|
|
20
|
+
} | {
|
|
21
|
+
kind: "connect";
|
|
22
|
+
} | {
|
|
23
|
+
kind: "conflict";
|
|
24
|
+
origin: string;
|
|
25
|
+
};
|
|
26
|
+
export interface HubInitOpeningPlan {
|
|
27
|
+
replaceExisting: boolean;
|
|
28
|
+
steps: readonly ("login" | "connect" | "project" | "scaffold")[];
|
|
29
|
+
}
|
|
30
|
+
export interface HubInitScaffoldInput {
|
|
31
|
+
cwd: string;
|
|
32
|
+
daemonSlug: string;
|
|
33
|
+
provider: HubInitProvider;
|
|
34
|
+
providerFilters: Readonly<Record<string, string>>;
|
|
35
|
+
}
|
|
36
|
+
export interface HubInitScaffold {
|
|
37
|
+
hub: string;
|
|
38
|
+
workflowPath: string;
|
|
39
|
+
workflow: string;
|
|
40
|
+
testAction: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function planHubInitOpening(input: {
|
|
43
|
+
loggedIn: boolean;
|
|
44
|
+
ottoDirectoryExists: boolean;
|
|
45
|
+
}): HubInitOpeningPlan;
|
|
46
|
+
export declare function createHubInitBundle(projectSlug: string, scaffold: HubInitScaffold): HubDeployBundle;
|
|
47
|
+
export declare function resolveHubInitProjects(projects: readonly HubProject[]): HubInitProjectResolution;
|
|
48
|
+
export declare function resolveHubInitConnection(status: HubStatus, origin: string): HubInitConnectionResolution;
|
|
49
|
+
export declare function createHubInitScaffold(input: HubInitScaffoldInput): HubInitScaffold;
|
|
50
|
+
//# sourceMappingURL=init-plan.d.ts.map
|