alpic 0.0.0-dev.added1b → 0.0.0-dev.adefca3
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/__tests__/auth.e2e.test.d.ts +1 -0
- package/dist/__tests__/auth.e2e.test.js +142 -0
- package/dist/__tests__/auth.e2e.test.js.map +1 -0
- package/dist/__tests__/deploy-flags.e2e.test.d.ts +1 -0
- package/dist/__tests__/deploy-flags.e2e.test.js +87 -0
- package/dist/__tests__/deploy-flags.e2e.test.js.map +1 -0
- package/dist/__tests__/deploy.e2e.test.js +36 -53
- package/dist/__tests__/deploy.e2e.test.js.map +1 -1
- package/dist/__tests__/git.e2e.test.js +51 -13
- package/dist/__tests__/git.e2e.test.js.map +1 -1
- package/dist/__tests__/mock-server.js +60 -3
- package/dist/__tests__/mock-server.js.map +1 -1
- package/dist/__tests__/utils.d.ts +15 -1
- package/dist/__tests__/utils.js +71 -2
- package/dist/__tests__/utils.js.map +1 -1
- package/dist/api.d.ts +0 -1
- package/dist/api.js +5 -9
- package/dist/api.js.map +1 -1
- package/dist/commands/deploy.d.ts +6 -0
- package/dist/commands/deploy.js +41 -13
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/git/connect.js +5 -11
- package/dist/commands/git/connect.js.map +1 -1
- package/dist/commands/git/disconnect.js +5 -9
- package/dist/commands/git/disconnect.js.map +1 -1
- package/dist/commands/git.js +1 -1
- package/dist/commands/git.js.map +1 -1
- package/dist/commands/login.d.ts +6 -0
- package/dist/commands/login.js +39 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +6 -0
- package/dist/commands/logout.js +20 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/whoami.d.ts +6 -0
- package/dist/commands/whoami.js +25 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/env.d.ts +4 -0
- package/dist/env.js +10 -0
- package/dist/env.js.map +1 -0
- package/dist/lib/alpic-command.js +0 -3
- package/dist/lib/alpic-command.js.map +1 -1
- package/dist/lib/auth/auth.d.ts +2 -0
- package/dist/lib/auth/auth.js +21 -0
- package/dist/lib/auth/auth.js.map +1 -0
- package/dist/lib/auth/oauth/client.d.ts +28 -0
- package/dist/lib/auth/oauth/client.js +110 -0
- package/dist/lib/auth/oauth/client.js.map +1 -0
- package/dist/lib/auth/oauth/constants.d.ts +2 -0
- package/dist/lib/auth/oauth/constants.js +3 -0
- package/dist/lib/auth/oauth/constants.js.map +1 -0
- package/dist/lib/auth/oauth/server/assets/alpic-mountain.png +0 -0
- package/dist/lib/auth/oauth/server/assets/authorize.html +195 -0
- package/dist/lib/auth/oauth/server/assets/callback.html +88 -0
- package/dist/lib/auth/oauth/server/index.d.ts +8 -0
- package/dist/lib/auth/oauth/server/index.js +103 -0
- package/dist/lib/auth/oauth/server/index.js.map +1 -0
- package/dist/lib/auth/whoami.d.ts +28 -0
- package/dist/lib/auth/whoami.js +35 -0
- package/dist/lib/auth/whoami.js.map +1 -0
- package/dist/lib/base-workflow.d.ts +10 -0
- package/dist/lib/base-workflow.js +21 -0
- package/dist/lib/base-workflow.js.map +1 -0
- package/dist/lib/deployment.d.ts +3 -3
- package/dist/lib/deployment.js +24 -8
- package/dist/lib/deployment.js.map +1 -1
- package/dist/lib/git.js +2 -3
- package/dist/lib/git.js.map +1 -1
- package/dist/lib/global-store.d.ts +28 -0
- package/dist/lib/global-store.js +75 -0
- package/dist/lib/global-store.js.map +1 -0
- package/dist/lib/project.d.ts +59 -61
- package/dist/lib/project.js +252 -254
- package/dist/lib/project.js.map +1 -1
- package/dist/lib/telemetry.js +6 -6
- package/dist/lib/telemetry.js.map +1 -1
- package/package.json +25 -18
- package/dist/lib/auth.d.ts +0 -1
- package/dist/lib/auth.js +0 -10
- package/dist/lib/auth.js.map +0 -1
- package/dist/lib/global-config.d.ts +0 -9
- package/dist/lib/global-config.js +0 -48
- package/dist/lib/global-config.js.map +0 -1
package/dist/lib/project.d.ts
CHANGED
|
@@ -1,67 +1,65 @@
|
|
|
1
|
-
import type { RouterOutput } from "@alpic-ai/api";
|
|
1
|
+
import type { RouterOutput, Runtime } from "@alpic-ai/api";
|
|
2
2
|
import type { ProjectConfig } from "../types.js";
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
id: string;
|
|
14
|
-
status: "ongoing" | "deployed" | "failed" | "canceled";
|
|
15
|
-
sourceCommitId: string | null;
|
|
16
|
-
sourceCommitMessage: string | null;
|
|
17
|
-
completedAt: Date | null;
|
|
18
|
-
} | null;
|
|
19
|
-
} | null>;
|
|
20
|
-
export declare function confirmDeployDirectory(deployDir: string): Promise<boolean>;
|
|
21
|
-
export declare function confirmLinkExisting(): Promise<boolean>;
|
|
22
|
-
export declare function confirmLinkToAnotherProject(): Promise<boolean>;
|
|
23
|
-
export declare function selectProjectFromList(projects: RouterOutput["projects"]["list"]["v1"]): Promise<{
|
|
24
|
-
id: string;
|
|
25
|
-
name: string;
|
|
26
|
-
teamId: string;
|
|
27
|
-
sourceRepository: string | null;
|
|
28
|
-
runtime: "python3.13" | "python3.14" | "node22" | "node24";
|
|
29
|
-
transport: "stdio" | "sse" | "streamablehttp" | null;
|
|
30
|
-
rootDirectory: string | null;
|
|
31
|
-
buildCommand: string | null;
|
|
32
|
-
buildOutputDir: string | null;
|
|
33
|
-
installCommand: string | null;
|
|
34
|
-
startCommand: string | null;
|
|
35
|
-
createdAt: Date;
|
|
36
|
-
productionEnvironment: {
|
|
37
|
-
id: string;
|
|
38
|
-
name: string;
|
|
39
|
-
mcpServerUrl: string;
|
|
40
|
-
latestDeployment: {
|
|
41
|
-
id: string;
|
|
42
|
-
status: "ongoing" | "deployed" | "failed" | "canceled";
|
|
43
|
-
sourceCommitId: string | null;
|
|
44
|
-
sourceCommitMessage: string | null;
|
|
45
|
-
completedAt: Date | null;
|
|
46
|
-
} | null;
|
|
47
|
-
} | null;
|
|
48
|
-
environments: {
|
|
3
|
+
import { BaseWorkflow } from "./base-workflow.js";
|
|
4
|
+
export type ProjectFlags = {
|
|
5
|
+
yes?: boolean;
|
|
6
|
+
projectName?: string;
|
|
7
|
+
runtime?: Runtime;
|
|
8
|
+
rootDir?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare class ProjectWorkflow extends BaseWorkflow<ProjectFlags> {
|
|
11
|
+
selectEnvironmentFromList(environments: RouterOutput["projects"]["get"]["v1"]["environments"]): Promise<(typeof environments)[number] | null>;
|
|
12
|
+
selectProjectFromList(projects: RouterOutput["projects"]["list"]["v1"]): Promise<{
|
|
49
13
|
id: string;
|
|
50
14
|
name: string;
|
|
51
|
-
|
|
52
|
-
|
|
15
|
+
teamId: string;
|
|
16
|
+
sourceRepository: string | null;
|
|
17
|
+
runtime: "python3.13" | "python3.14" | "node22" | "node24";
|
|
18
|
+
transport: "stdio" | "sse" | "streamablehttp" | null;
|
|
19
|
+
rootDirectory: string | null;
|
|
20
|
+
buildCommand: string | null;
|
|
21
|
+
buildOutputDir: string | null;
|
|
22
|
+
installCommand: string | null;
|
|
23
|
+
startCommand: string | null;
|
|
53
24
|
createdAt: Date;
|
|
54
|
-
|
|
55
|
-
latestDeployment: {
|
|
25
|
+
productionEnvironment: {
|
|
56
26
|
id: string;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
27
|
+
name: string;
|
|
28
|
+
mcpServerUrl: string;
|
|
29
|
+
latestDeployment: {
|
|
30
|
+
id: string;
|
|
31
|
+
status: "ongoing" | "deployed" | "failed" | "canceled";
|
|
32
|
+
sourceCommitId: string | null;
|
|
33
|
+
sourceCommitMessage: string | null;
|
|
34
|
+
completedAt: Date | null;
|
|
35
|
+
} | null;
|
|
61
36
|
} | null;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
37
|
+
environments: {
|
|
38
|
+
id: string;
|
|
39
|
+
name: string;
|
|
40
|
+
sourceBranch: string | null;
|
|
41
|
+
mcpServerUrl: string;
|
|
42
|
+
createdAt: Date;
|
|
43
|
+
projectId: string;
|
|
44
|
+
latestDeployment: {
|
|
45
|
+
id: string;
|
|
46
|
+
status: "ongoing" | "deployed" | "failed" | "canceled";
|
|
47
|
+
sourceCommitId: string | null;
|
|
48
|
+
sourceCommitMessage: string | null;
|
|
49
|
+
completedAt: Date | null;
|
|
50
|
+
} | null;
|
|
51
|
+
}[];
|
|
52
|
+
} | null>;
|
|
53
|
+
promptRootDirectory(deployDir: string): Promise<string | null>;
|
|
54
|
+
private detectRuntime;
|
|
55
|
+
confirmDeployWithExistingConfig(existingConfig: ProjectConfig): Promise<boolean | null>;
|
|
56
|
+
confirmDeployDirectory(deployDir: string): Promise<boolean>;
|
|
57
|
+
confirmLinkExisting(): Promise<boolean>;
|
|
58
|
+
confirmLinkToAnotherProject(): Promise<boolean>;
|
|
59
|
+
resolveProjectForDeploy(deployDir: string): Promise<(ProjectConfig & {
|
|
60
|
+
environmentId: string;
|
|
61
|
+
}) | null>;
|
|
62
|
+
private resolveEnvironmentForProject;
|
|
63
|
+
private runCreateProjectFlow;
|
|
64
|
+
private runLinkingFlow;
|
|
65
|
+
}
|
package/dist/lib/project.js
CHANGED
|
@@ -3,283 +3,281 @@ import chalk from "chalk";
|
|
|
3
3
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
import { api } from "../api.js";
|
|
6
|
+
import { BaseWorkflow } from "./base-workflow.js";
|
|
6
7
|
import { config } from "./config.js";
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
throw new Error(`Path does not exist: ${dir}`);
|
|
11
|
-
}
|
|
12
|
-
if (!statSync(dir).isDirectory()) {
|
|
13
|
-
throw new Error(`Path is not a directory: ${dir}`);
|
|
14
|
-
}
|
|
15
|
-
return dir;
|
|
16
|
-
}
|
|
17
|
-
export async function confirmDeployWithExistingConfig(existingConfig) {
|
|
18
|
-
const envLabel = existingConfig.environmentName ? ` to environment "${existingConfig.environmentName}"` : "";
|
|
19
|
-
const confirm = await p.confirm({
|
|
20
|
-
message: chalk.bold(`Deploy project "${existingConfig.projectName}"${envLabel}?`),
|
|
21
|
-
initialValue: true,
|
|
22
|
-
});
|
|
23
|
-
if (p.isCancel(confirm))
|
|
24
|
-
return null;
|
|
25
|
-
return confirm === true;
|
|
26
|
-
}
|
|
27
|
-
export async function selectEnvironmentFromList(environments) {
|
|
28
|
-
if (environments.length === 0) {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
const choice = await p.select({
|
|
32
|
-
message: chalk.bold("Choose an environment to deploy to"),
|
|
33
|
-
options: environments.map((env) => ({
|
|
34
|
-
value: env.id,
|
|
35
|
-
label: env.sourceBranch ? `${env.name} (${env.sourceBranch})` : env.name,
|
|
36
|
-
})),
|
|
37
|
-
});
|
|
38
|
-
if (p.isCancel(choice))
|
|
39
|
-
return null;
|
|
40
|
-
const environment = environments.find((e) => e.id === choice);
|
|
41
|
-
return environment ?? null;
|
|
42
|
-
}
|
|
43
|
-
export async function confirmDeployDirectory(deployDir) {
|
|
44
|
-
const confirm = await p.confirm({
|
|
45
|
-
message: chalk.bold(`Deploy the directory? `) + chalk.cyan(deployDir),
|
|
46
|
-
initialValue: true,
|
|
47
|
-
});
|
|
48
|
-
if (p.isCancel(confirm))
|
|
49
|
-
return false;
|
|
50
|
-
return confirm === true;
|
|
51
|
-
}
|
|
52
|
-
export async function confirmLinkExisting() {
|
|
53
|
-
const link = await p.confirm({
|
|
54
|
-
message: chalk.bold("Link to existing project?"),
|
|
55
|
-
initialValue: true,
|
|
56
|
-
});
|
|
57
|
-
if (p.isCancel(link))
|
|
58
|
-
return false;
|
|
59
|
-
return link === true;
|
|
60
|
-
}
|
|
61
|
-
export async function confirmLinkToAnotherProject() {
|
|
62
|
-
const link = await p.confirm({
|
|
63
|
-
message: chalk.bold("Link to another project?"),
|
|
64
|
-
initialValue: true,
|
|
65
|
-
});
|
|
66
|
-
if (p.isCancel(link))
|
|
67
|
-
return false;
|
|
68
|
-
return link === true;
|
|
69
|
-
}
|
|
70
|
-
export async function selectProjectFromList(projects) {
|
|
71
|
-
if (projects.length === 0) {
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
const choice = await p.select({
|
|
75
|
-
message: chalk.bold("Choose a project"),
|
|
76
|
-
options: projects.map((proj) => ({ value: proj.id, label: proj.name })),
|
|
77
|
-
});
|
|
78
|
-
if (p.isCancel(choice))
|
|
79
|
-
return null;
|
|
80
|
-
const project = projects.find((proj) => proj.id === choice);
|
|
81
|
-
return project ?? null;
|
|
82
|
-
}
|
|
83
|
-
export async function promptRootDirectory(deployDir) {
|
|
84
|
-
while (true) {
|
|
85
|
-
const rootDir = await p.text({
|
|
86
|
-
message: chalk.bold("Root directory"),
|
|
87
|
-
placeholder: ".",
|
|
88
|
-
initialValue: ".",
|
|
89
|
-
validate: (value) => {
|
|
90
|
-
if (value != null && value.length > 512)
|
|
91
|
-
return "Path must be at most 512 characters.";
|
|
92
|
-
return undefined;
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
if (p.isCancel(rootDir))
|
|
8
|
+
export class ProjectWorkflow extends BaseWorkflow {
|
|
9
|
+
async selectEnvironmentFromList(environments) {
|
|
10
|
+
if (environments.length === 0) {
|
|
96
11
|
return null;
|
|
97
|
-
const trimmed = rootDir.trim();
|
|
98
|
-
if (trimmed === "" || trimmed === ".")
|
|
99
|
-
return undefined;
|
|
100
|
-
const resolved = resolve(deployDir, trimmed);
|
|
101
|
-
if (!existsSync(resolved)) {
|
|
102
|
-
p.log.error(`Path does not exist: ${resolved}`);
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
if (!statSync(resolved).isDirectory()) {
|
|
106
|
-
p.log.error(`Path is not a directory: ${resolved}`);
|
|
107
|
-
continue;
|
|
108
12
|
}
|
|
109
|
-
|
|
13
|
+
const choice = await p.select({
|
|
14
|
+
message: chalk.bold("Choose an environment to deploy to"),
|
|
15
|
+
options: environments.map((env) => ({
|
|
16
|
+
value: env.id,
|
|
17
|
+
label: env.sourceBranch ? `${env.name} (${env.sourceBranch})` : env.name,
|
|
18
|
+
})),
|
|
19
|
+
});
|
|
20
|
+
if (p.isCancel(choice))
|
|
21
|
+
return null;
|
|
22
|
+
const environment = environments.find((e) => e.id === choice);
|
|
23
|
+
return environment ?? null;
|
|
110
24
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
25
|
+
async selectProjectFromList(projects) {
|
|
26
|
+
if (projects.length === 0) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const choice = await p.select({
|
|
30
|
+
message: chalk.bold("Choose a project"),
|
|
31
|
+
options: projects.map((proj) => ({ value: proj.id, label: proj.name })),
|
|
32
|
+
});
|
|
33
|
+
if (p.isCancel(choice))
|
|
34
|
+
return null;
|
|
35
|
+
const project = projects.find((proj) => proj.id === choice);
|
|
36
|
+
return project ?? null;
|
|
117
37
|
}
|
|
118
|
-
|
|
119
|
-
if (!environment)
|
|
120
|
-
return null;
|
|
121
|
-
return { environmentId: environment.id, environmentName: environment.name };
|
|
122
|
-
}
|
|
123
|
-
export async function resolveProjectForDeploy(deployDir) {
|
|
124
|
-
const ok = await confirmDeployDirectory(deployDir);
|
|
125
|
-
if (!ok)
|
|
126
|
-
return null;
|
|
127
|
-
const existingConfig = config.load(deployDir);
|
|
128
|
-
if (existingConfig) {
|
|
129
|
-
let confirm;
|
|
38
|
+
async promptRootDirectory(deployDir) {
|
|
130
39
|
while (true) {
|
|
131
|
-
|
|
132
|
-
|
|
40
|
+
const rootDir = this.flags.rootDir ??
|
|
41
|
+
(await p.text({
|
|
42
|
+
message: chalk.bold("Root directory"),
|
|
43
|
+
placeholder: ".",
|
|
44
|
+
initialValue: ".",
|
|
45
|
+
validate: (value) => {
|
|
46
|
+
if (value != null && value.length > 512)
|
|
47
|
+
return "Path must be at most 512 characters.";
|
|
48
|
+
return undefined;
|
|
49
|
+
},
|
|
50
|
+
}));
|
|
51
|
+
if (p.isCancel(rootDir))
|
|
133
52
|
return null;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const linkAnother = await confirmLinkToAnotherProject();
|
|
137
|
-
if (p.isCancel(linkAnother))
|
|
53
|
+
const trimmed = rootDir.trim();
|
|
54
|
+
if (trimmed === "" || trimmed === ".")
|
|
138
55
|
return null;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
56
|
+
const resolved = resolve(deployDir, trimmed);
|
|
57
|
+
if (!existsSync(resolved) || !statSync(resolved).isDirectory()) {
|
|
58
|
+
p.log.error(`Path is not a directory: ${resolved}`);
|
|
59
|
+
if (this.flags.rootDir)
|
|
60
|
+
return null;
|
|
61
|
+
continue;
|
|
145
62
|
}
|
|
63
|
+
return trimmed;
|
|
146
64
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
65
|
+
}
|
|
66
|
+
detectRuntime(dir) {
|
|
67
|
+
const has = (file) => existsSync(resolve(dir, file));
|
|
68
|
+
const read = (file) => {
|
|
69
|
+
try {
|
|
70
|
+
return readFileSync(resolve(dir, file), "utf8");
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return "";
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
if (has("pyproject.toml") || has("requirements.txt") || has("setup.py") || has(".python-version")) {
|
|
77
|
+
return "python3.13";
|
|
155
78
|
}
|
|
156
|
-
|
|
157
|
-
|
|
79
|
+
if (has("package.json")) {
|
|
80
|
+
const nvmrc = has(".nvmrc") ? (read(".nvmrc").trim().split(/\s/)[0] ?? "") : "";
|
|
81
|
+
const major = nvmrc.replace(/^v/i, "").match(/^(\d+)/)?.[1];
|
|
82
|
+
if (major === "22")
|
|
83
|
+
return "node22";
|
|
84
|
+
return "node24";
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
async confirmDeployWithExistingConfig(existingConfig) {
|
|
89
|
+
const envLabel = existingConfig.environmentName ? ` to environment "${existingConfig.environmentName}"` : "";
|
|
90
|
+
const confirmed = await this.confirm({
|
|
91
|
+
message: chalk.bold(`Deploy project "${existingConfig.projectName}"${envLabel}?`),
|
|
92
|
+
initialValue: true,
|
|
93
|
+
});
|
|
94
|
+
if (p.isCancel(confirmed))
|
|
158
95
|
return null;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
p.note(`Environment "${env.environmentName}" will be used for future deploys.`, undefined, {
|
|
166
|
-
format: (line) => line,
|
|
96
|
+
return confirmed === true;
|
|
97
|
+
}
|
|
98
|
+
async confirmDeployDirectory(deployDir) {
|
|
99
|
+
const confirmed = await this.confirm({
|
|
100
|
+
message: chalk.bold(`Deploy the directory? `) + chalk.cyan(deployDir),
|
|
101
|
+
initialValue: true,
|
|
167
102
|
});
|
|
168
|
-
|
|
103
|
+
if (p.isCancel(confirmed))
|
|
104
|
+
return false;
|
|
105
|
+
return confirmed === true;
|
|
169
106
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
107
|
+
async confirmLinkExisting() {
|
|
108
|
+
const link = await this.confirm({
|
|
109
|
+
message: chalk.bold("Link to existing project?"),
|
|
110
|
+
initialValue: true,
|
|
111
|
+
}, false);
|
|
112
|
+
if (p.isCancel(link))
|
|
113
|
+
return false;
|
|
114
|
+
return link === true;
|
|
173
115
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
116
|
+
async confirmLinkToAnotherProject() {
|
|
117
|
+
const link = await this.confirm({
|
|
118
|
+
message: chalk.bold("Link to another project?"),
|
|
119
|
+
initialValue: true,
|
|
120
|
+
}, false);
|
|
121
|
+
if (p.isCancel(link))
|
|
122
|
+
return false;
|
|
123
|
+
return link === true;
|
|
124
|
+
}
|
|
125
|
+
async resolveProjectForDeploy(deployDir) {
|
|
126
|
+
const ok = await this.confirmDeployDirectory(deployDir);
|
|
127
|
+
if (!ok)
|
|
128
|
+
return null;
|
|
129
|
+
const existingConfig = config.load(deployDir);
|
|
130
|
+
if (existingConfig) {
|
|
131
|
+
let confirmed;
|
|
132
|
+
while (true) {
|
|
133
|
+
confirmed = await this.confirmDeployWithExistingConfig(existingConfig);
|
|
134
|
+
if (confirmed === null)
|
|
135
|
+
return null;
|
|
136
|
+
if (confirmed)
|
|
137
|
+
break;
|
|
138
|
+
const linkAnother = await this.confirmLinkToAnotherProject();
|
|
139
|
+
if (p.isCancel(linkAnother))
|
|
140
|
+
return null;
|
|
141
|
+
if (linkAnother) {
|
|
142
|
+
const linkExisting = await this.confirmLinkExisting();
|
|
143
|
+
if (!linkExisting) {
|
|
144
|
+
return this.runCreateProjectFlow(deployDir);
|
|
145
|
+
}
|
|
146
|
+
return this.runLinkingFlow(deployDir);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (existingConfig.environmentId) {
|
|
150
|
+
return {
|
|
151
|
+
projectId: existingConfig.projectId,
|
|
152
|
+
teamId: existingConfig.teamId,
|
|
153
|
+
projectName: existingConfig.projectName,
|
|
154
|
+
environmentId: existingConfig.environmentId,
|
|
155
|
+
environmentName: existingConfig.environmentName,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
const env = await this.resolveEnvironmentForProject(existingConfig.projectId);
|
|
159
|
+
if (!env)
|
|
160
|
+
return null;
|
|
161
|
+
const updatedConfig = {
|
|
162
|
+
...existingConfig,
|
|
163
|
+
environmentId: env.environmentId,
|
|
164
|
+
environmentName: env.environmentName,
|
|
165
|
+
};
|
|
166
|
+
config.save(updatedConfig, deployDir);
|
|
167
|
+
p.note(`Environment "${env.environmentName}" will be used for future deploys.`, undefined, {
|
|
168
|
+
format: (line) => line,
|
|
169
|
+
});
|
|
170
|
+
return updatedConfig;
|
|
213
171
|
}
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (!productionEnv) {
|
|
218
|
-
throw new Error("Project was created but has no Production environment.");
|
|
172
|
+
const linkExisting = await this.confirmLinkExisting();
|
|
173
|
+
if (!linkExisting) {
|
|
174
|
+
return this.runCreateProjectFlow(deployDir);
|
|
219
175
|
}
|
|
220
|
-
|
|
221
|
-
projectId: created.id,
|
|
222
|
-
teamId: created.teamId,
|
|
223
|
-
projectName: created.name,
|
|
224
|
-
environmentId: productionEnv.id,
|
|
225
|
-
environmentName: productionEnv.name,
|
|
226
|
-
};
|
|
227
|
-
config.save(newConfig, deployDir);
|
|
228
|
-
return newConfig;
|
|
176
|
+
return this.runLinkingFlow(deployDir);
|
|
229
177
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const project = await selectProjectFromList(projects);
|
|
241
|
-
if (!project)
|
|
242
|
-
return null;
|
|
243
|
-
const environments = project.environments ?? [];
|
|
244
|
-
if (environments.length === 0) {
|
|
245
|
-
throw new Error("No environments found for this project.");
|
|
178
|
+
async resolveEnvironmentForProject(projectId) {
|
|
179
|
+
const project = await api.projects.get.v1({ projectId });
|
|
180
|
+
const environments = project.environments ?? [];
|
|
181
|
+
if (environments.length === 0) {
|
|
182
|
+
throw new Error("No environments found for this project.");
|
|
183
|
+
}
|
|
184
|
+
const environment = await this.selectEnvironmentFromList(environments);
|
|
185
|
+
if (!environment)
|
|
186
|
+
return null;
|
|
187
|
+
return { environmentId: environment.id, environmentName: environment.name };
|
|
246
188
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
189
|
+
async runCreateProjectFlow(deployDir) {
|
|
190
|
+
const name = this.flags.projectName ??
|
|
191
|
+
(await p.text({
|
|
192
|
+
message: chalk.bold("Project name"),
|
|
193
|
+
placeholder: "my-app",
|
|
194
|
+
validate: (value) => {
|
|
195
|
+
if (!value?.trim())
|
|
196
|
+
return "Project name is required.";
|
|
197
|
+
if (value.length > 100)
|
|
198
|
+
return "Project name must be at most 100 characters.";
|
|
199
|
+
return undefined;
|
|
200
|
+
},
|
|
201
|
+
}));
|
|
202
|
+
if (p.isCancel(name)) {
|
|
203
|
+
p.cancel("Project name is required.");
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
const detectedRuntime = this.detectRuntime(deployDir);
|
|
207
|
+
const defaultRuntime = detectedRuntime ?? "node24";
|
|
208
|
+
const runtime = this.isNonInteractive() && this.flags.runtime
|
|
209
|
+
? defaultRuntime
|
|
210
|
+
: await p.select({
|
|
211
|
+
message: chalk.bold("Runtime"),
|
|
212
|
+
options: [
|
|
213
|
+
{ value: "node24", label: "Node.js 24" },
|
|
214
|
+
{ value: "node22", label: "Node.js 22" },
|
|
215
|
+
{ value: "python3.14", label: "Python 3.14" },
|
|
216
|
+
{ value: "python3.13", label: "Python 3.13" },
|
|
217
|
+
],
|
|
218
|
+
initialValue: defaultRuntime,
|
|
219
|
+
});
|
|
220
|
+
if (p.isCancel(runtime)) {
|
|
221
|
+
p.cancel("Runtime is required.");
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
const rootDirectory = await this.promptRootDirectory(deployDir);
|
|
225
|
+
const spin = p.spinner();
|
|
226
|
+
spin.start("Creating project...");
|
|
266
227
|
try {
|
|
267
|
-
|
|
228
|
+
const projectInput = {
|
|
229
|
+
name,
|
|
230
|
+
runtime,
|
|
231
|
+
};
|
|
232
|
+
projectInput.rootDirectory = rootDirectory ?? undefined;
|
|
233
|
+
const created = await api.projects.create.v1(projectInput);
|
|
234
|
+
spin.stop("Project created.");
|
|
235
|
+
const productionEnv = created.productionEnvironment;
|
|
236
|
+
if (!productionEnv) {
|
|
237
|
+
throw new Error("Project was created but has no Production environment.");
|
|
238
|
+
}
|
|
239
|
+
const newConfig = {
|
|
240
|
+
projectId: created.id,
|
|
241
|
+
teamId: created.teamId,
|
|
242
|
+
projectName: created.name,
|
|
243
|
+
environmentId: productionEnv.id,
|
|
244
|
+
environmentName: productionEnv.name,
|
|
245
|
+
};
|
|
246
|
+
config.save(newConfig, deployDir);
|
|
247
|
+
return newConfig;
|
|
268
248
|
}
|
|
269
|
-
catch {
|
|
270
|
-
|
|
249
|
+
catch (error) {
|
|
250
|
+
spin.stop();
|
|
251
|
+
throw error;
|
|
271
252
|
}
|
|
272
|
-
};
|
|
273
|
-
if (has("pyproject.toml") || has("requirements.txt") || has("setup.py") || has(".python-version")) {
|
|
274
|
-
return "python3.13";
|
|
275
253
|
}
|
|
276
|
-
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
254
|
+
async runLinkingFlow(deployDir) {
|
|
255
|
+
const projects = await api.projects.list.v1();
|
|
256
|
+
if (projects.length === 0) {
|
|
257
|
+
throw new Error("No projects found. Create a project in the Alpic dashboard first.");
|
|
258
|
+
}
|
|
259
|
+
const project = await this.selectProjectFromList(projects);
|
|
260
|
+
if (!project)
|
|
261
|
+
return null;
|
|
262
|
+
const environments = project.environments ?? [];
|
|
263
|
+
if (environments.length === 0) {
|
|
264
|
+
throw new Error("No environments found for this project.");
|
|
265
|
+
}
|
|
266
|
+
const environment = await this.selectEnvironmentFromList(environments);
|
|
267
|
+
if (!environment)
|
|
268
|
+
return null;
|
|
269
|
+
const newConfig = {
|
|
270
|
+
projectId: project.id,
|
|
271
|
+
teamId: project.teamId,
|
|
272
|
+
projectName: project.name,
|
|
273
|
+
environmentId: environment.id,
|
|
274
|
+
environmentName: environment.name,
|
|
275
|
+
};
|
|
276
|
+
config.save(newConfig, deployDir);
|
|
277
|
+
p.note(`Linked to project "${project.name}", environment "${environment.name}".`, undefined, {
|
|
278
|
+
format: (line) => line,
|
|
279
|
+
});
|
|
280
|
+
return newConfig;
|
|
282
281
|
}
|
|
283
|
-
return null;
|
|
284
282
|
}
|
|
285
283
|
//# sourceMappingURL=project.js.map
|