@prisma/cli 3.0.0-alpha.1 → 3.0.0-alpha.11

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 (56) hide show
  1. package/README.md +1 -16
  2. package/dist/adapters/git.js +49 -0
  3. package/dist/adapters/local-state.js +39 -1
  4. package/dist/adapters/token-storage.js +57 -1
  5. package/dist/cli2.js +60 -4
  6. package/dist/commands/app/index.js +41 -21
  7. package/dist/commands/auth/index.js +3 -2
  8. package/dist/commands/branch/index.js +2 -1
  9. package/dist/commands/env.js +87 -0
  10. package/dist/commands/git/index.js +36 -0
  11. package/dist/commands/project/index.js +12 -14
  12. package/dist/commands/version/index.js +18 -0
  13. package/dist/controllers/app-env.js +223 -0
  14. package/dist/controllers/app.js +1026 -169
  15. package/dist/controllers/auth.js +9 -9
  16. package/dist/controllers/branch.js +6 -6
  17. package/dist/controllers/project.js +451 -161
  18. package/dist/controllers/version.js +12 -0
  19. package/dist/lib/app/bun-project.js +1 -1
  20. package/dist/lib/app/deploy-output.js +15 -0
  21. package/dist/lib/app/env-config.js +57 -0
  22. package/dist/lib/app/env-vars.js +4 -4
  23. package/dist/lib/app/local-dev.js +1 -1
  24. package/dist/lib/app/preview-build.js +128 -1
  25. package/dist/lib/app/preview-interaction.js +2 -35
  26. package/dist/lib/app/preview-progress.js +43 -58
  27. package/dist/lib/app/preview-provider.js +125 -24
  28. package/dist/lib/auth/auth-ops.js +58 -13
  29. package/dist/lib/auth/client.js +1 -1
  30. package/dist/lib/auth/guard.js +1 -1
  31. package/dist/lib/auth/login.js +115 -4
  32. package/dist/lib/project/local-pin.js +51 -0
  33. package/dist/lib/project/resolution.js +201 -0
  34. package/dist/lib/version.js +55 -0
  35. package/dist/output/patterns.js +15 -18
  36. package/dist/presenters/app-env.js +129 -0
  37. package/dist/presenters/app.js +16 -29
  38. package/dist/presenters/auth.js +2 -2
  39. package/dist/presenters/branch.js +6 -6
  40. package/dist/presenters/project.js +87 -44
  41. package/dist/presenters/version.js +29 -0
  42. package/dist/shell/command-meta.js +148 -91
  43. package/dist/shell/command-runner.js +45 -7
  44. package/dist/shell/errors.js +9 -3
  45. package/dist/shell/global-flags.js +13 -1
  46. package/dist/shell/help.js +8 -7
  47. package/dist/shell/output.js +29 -12
  48. package/dist/shell/prompt.js +12 -2
  49. package/dist/shell/runtime.js +1 -1
  50. package/dist/shell/ui.js +19 -1
  51. package/dist/use-cases/auth.js +9 -12
  52. package/dist/use-cases/branch.js +20 -20
  53. package/dist/use-cases/create-cli-gateways.js +3 -13
  54. package/dist/use-cases/project.js +2 -48
  55. package/package.json +3 -3
  56. package/dist/adapters/config.js +0 -74
package/README.md CHANGED
@@ -18,22 +18,7 @@ pnpm prisma-cli app list-env
18
18
  ```
19
19
 
20
20
  The package exposes `prisma-cli` so it can coexist with the existing `prisma`
21
- executable. If you want local project scripts that use the future command shape,
22
- add:
23
-
24
- ```json
25
- {
26
- "scripts": {
27
- "prisma": "prisma-cli"
28
- }
29
- }
30
- ```
31
-
32
- Then run:
33
-
34
- ```bash
35
- pnpm prisma app deploy
36
- ```
21
+ executable.
37
22
 
38
23
  Notes:
39
24
 
@@ -0,0 +1,49 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ //#region src/adapters/git.ts
4
+ const execFileAsync = promisify(execFile);
5
+ async function readGitOriginRemote(cwd) {
6
+ try {
7
+ const { stdout } = await execFileAsync("git", [
8
+ "config",
9
+ "--get",
10
+ "remote.origin.url"
11
+ ], {
12
+ cwd,
13
+ timeout: 5e3
14
+ });
15
+ const remote = stdout.trim();
16
+ return remote.length > 0 ? remote : null;
17
+ } catch {
18
+ return null;
19
+ }
20
+ }
21
+ function parseGitHubRepositoryUrl(value) {
22
+ const input = value.trim();
23
+ const shorthand = input.match(/^git@github\.com:([^/\s]+)\/([^/\s]+?)(?:\.git)?$/);
24
+ if (shorthand) return toGitHubRepositoryReference(shorthand[1], shorthand[2]);
25
+ let parsed;
26
+ try {
27
+ parsed = new URL(input);
28
+ } catch {
29
+ return null;
30
+ }
31
+ if (parsed.hostname !== "github.com") return null;
32
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:" && parsed.protocol !== "ssh:") return null;
33
+ const parts = parsed.pathname.split("/").filter(Boolean);
34
+ if (parts.length !== 2) return null;
35
+ const [owner, rawName] = parts;
36
+ return toGitHubRepositoryReference(owner, rawName.endsWith(".git") ? rawName.slice(0, -4) : rawName);
37
+ }
38
+ function toGitHubRepositoryReference(owner, name) {
39
+ if (!owner || !name || owner.includes("/") || name.includes("/")) return null;
40
+ return {
41
+ provider: "github",
42
+ owner,
43
+ name,
44
+ fullName: `${owner}/${name}`,
45
+ url: `https://github.com/${owner}/${name}`
46
+ };
47
+ }
48
+ //#endregion
49
+ export { parseGitHubRepositoryUrl, readGitOriginRemote };
@@ -1,8 +1,13 @@
1
- import path from "node:path";
2
1
  import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
3
  //#region src/adapters/local-state.ts
4
4
  const DEFAULT_STATE = {
5
5
  auth: null,
6
+ project: {
7
+ rememberedByWorkspace: {},
8
+ lastResolved: null,
9
+ repositoryConnectionsByProject: {}
10
+ },
6
11
  branch: { active: "preview" },
7
12
  app: {
8
13
  selectedByProject: {},
@@ -24,6 +29,11 @@ var LocalStateStore = class {
24
29
  const parsed = JSON.parse(raw);
25
30
  return {
26
31
  auth: parsed.auth ?? structuredClone(DEFAULT_STATE.auth),
32
+ project: {
33
+ rememberedByWorkspace: parsed.project?.rememberedByWorkspace ?? {},
34
+ lastResolved: parsed.project?.lastResolved ?? null,
35
+ repositoryConnectionsByProject: parsed.project?.repositoryConnectionsByProject ?? {}
36
+ },
27
37
  branch: { active: parsed.branch?.active ?? DEFAULT_STATE.branch.active },
28
38
  app: {
29
39
  selectedByProject: parsed.app?.selectedByProject ?? {},
@@ -57,6 +67,34 @@ var LocalStateStore = class {
57
67
  await this.write(state);
58
68
  return state;
59
69
  }
70
+ async readRememberedProject(workspaceId) {
71
+ return (await this.read()).project.rememberedByWorkspace[workspaceId] ?? null;
72
+ }
73
+ async readLastResolvedProject() {
74
+ return (await this.read()).project.lastResolved;
75
+ }
76
+ async setRememberedProject(project) {
77
+ const state = await this.read();
78
+ state.project.rememberedByWorkspace[project.workspaceId] = project;
79
+ state.project.lastResolved = project;
80
+ await this.write(state);
81
+ return state;
82
+ }
83
+ async readRepositoryConnection(projectId) {
84
+ return (await this.read()).project.repositoryConnectionsByProject[projectId] ?? null;
85
+ }
86
+ async setRepositoryConnection(projectId, connection) {
87
+ const state = await this.read();
88
+ state.project.repositoryConnectionsByProject[projectId] = connection;
89
+ await this.write(state);
90
+ return state;
91
+ }
92
+ async clearRepositoryConnection(projectId) {
93
+ const state = await this.read();
94
+ delete state.project.repositoryConnectionsByProject[projectId];
95
+ await this.write(state);
96
+ return state;
97
+ }
60
98
  async readSelectedApp(projectId) {
61
99
  return (await this.read()).app.selectedByProject[projectId] ?? null;
62
100
  }
@@ -1,5 +1,8 @@
1
1
  import { getAuthFilePath } from "../lib/auth/client.js";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
2
4
  import { CredentialsStore } from "@prisma/credentials-store";
5
+ import { randomUUID } from "node:crypto";
3
6
  //#region src/adapters/token-storage.ts
4
7
  function findLatestValidTokens(allCredentials) {
5
8
  for (let i = allCredentials.length - 1; i >= 0; i -= 1) {
@@ -14,10 +17,19 @@ function findLatestValidTokens(allCredentials) {
14
17
  }
15
18
  return null;
16
19
  }
20
+ function tokensEqual(a, b) {
21
+ return a?.workspaceId === b?.workspaceId && a?.accessToken === b?.accessToken && a?.refreshToken === b?.refreshToken;
22
+ }
23
+ function sleep(ms) {
24
+ return new Promise((resolve) => setTimeout(resolve, ms));
25
+ }
17
26
  var FileTokenStorage = class {
18
27
  credentialsStore;
28
+ lockFilePath;
19
29
  constructor(env = process.env) {
20
- this.credentialsStore = new CredentialsStore(getAuthFilePath(env));
30
+ const authFilePath = getAuthFilePath(env);
31
+ this.credentialsStore = new CredentialsStore(authFilePath);
32
+ this.lockFilePath = `${authFilePath}.lock`;
21
33
  }
22
34
  async getTokens() {
23
35
  try {
@@ -38,6 +50,50 @@ var FileTokenStorage = class {
38
50
  if (!tokens) return;
39
51
  await this.credentialsStore.deleteCredentials(tokens.workspaceId);
40
52
  }
53
+ async clearTokensIfCurrent(tokens) {
54
+ if (!tokensEqual(await this.getTokens(), tokens)) return;
55
+ await this.clearTokens();
56
+ }
57
+ async withRefreshLock(fn) {
58
+ const lockId = await this.acquireRefreshLock();
59
+ try {
60
+ return await fn();
61
+ } finally {
62
+ await this.releaseRefreshLock(lockId);
63
+ }
64
+ }
65
+ async acquireRefreshLock() {
66
+ const lockId = randomUUID();
67
+ await fs.mkdir(path.dirname(this.lockFilePath), { recursive: true });
68
+ while (true) try {
69
+ const handle = await fs.open(this.lockFilePath, "wx");
70
+ try {
71
+ await handle.writeFile(lockId, "utf8");
72
+ } finally {
73
+ await handle.close();
74
+ }
75
+ return lockId;
76
+ } catch (error) {
77
+ if (error.code !== "EEXIST") throw error;
78
+ const staleLockId = await this.getStaleRefreshLockId();
79
+ if (staleLockId) {
80
+ await this.releaseRefreshLock(staleLockId);
81
+ continue;
82
+ }
83
+ await sleep(100);
84
+ }
85
+ }
86
+ async getStaleRefreshLockId() {
87
+ const lockId = await fs.readFile(this.lockFilePath, "utf8").catch(() => null);
88
+ if (lockId === null) return null;
89
+ const stats = await fs.stat(this.lockFilePath).catch(() => null);
90
+ if (!stats) return null;
91
+ return Date.now() - stats.mtimeMs > 3e4 ? lockId : null;
92
+ }
93
+ async releaseRefreshLock(lockId) {
94
+ if (await fs.readFile(this.lockFilePath, "utf8").catch(() => null) !== lockId) return;
95
+ await fs.unlink(this.lockFilePath).catch(() => {});
96
+ }
41
97
  };
42
98
  //#endregion
43
99
  export { FileTokenStorage };
package/dist/cli2.js CHANGED
@@ -1,18 +1,27 @@
1
+ import { CliError } from "./shell/errors.js";
2
+ import { createShellUi } from "./shell/ui.js";
3
+ import { writeHumanError, writeJsonError, writeJsonSuccess } from "./shell/output.js";
1
4
  import { attachCommandDescriptor } from "./shell/command-meta.js";
2
- import { configureRuntimeCommand } from "./shell/runtime.js";
5
+ import { addCompactGlobalFlags } from "./shell/global-flags.js";
6
+ import { configureRuntimeCommand, createCommandContext } from "./shell/runtime.js";
3
7
  import "./shell/prompt.js";
4
8
  import { createAppCommand } from "./commands/app/index.js";
5
9
  import { createAuthCommand } from "./commands/auth/index.js";
6
10
  import { createBranchCommand } from "./commands/branch/index.js";
11
+ import { createGitCommand } from "./commands/git/index.js";
7
12
  import { createProjectCommand } from "./commands/project/index.js";
13
+ import { getCliName, getCliVersion } from "./lib/version.js";
14
+ import { runVersion } from "./controllers/version.js";
15
+ import { createVersionCommand } from "./commands/version/index.js";
8
16
  import process from "node:process";
9
- import { Command, CommanderError } from "commander";
17
+ import { Command, CommanderError, Option } from "commander";
10
18
  //#region src/cli.ts
11
19
  async function runCli(options = {}) {
12
20
  const runtime = resolveRuntime(options);
13
21
  const program = createProgram(runtime);
14
22
  process.exitCode = 0;
15
23
  try {
24
+ if (runtime.argv.includes("--version")) return await handleVersionFlag(runtime);
16
25
  const bareHelpCommand = resolveBareHelpCommand(program, runtime.argv);
17
26
  if (bareHelpCommand) {
18
27
  runtime.stderr.write(bareHelpCommand.helpInformation());
@@ -31,17 +40,64 @@ async function runCli(options = {}) {
31
40
  }
32
41
  function createProgram(runtime) {
33
42
  const program = attachCommandDescriptor(configureRuntimeCommand(new Command(), runtime), "root");
43
+ addCompactGlobalFlags(program);
44
+ program.addOption(new Option("--version", "Print the CLI version and exit."));
34
45
  program.name("prisma").showSuggestionAfterError();
46
+ program.addCommand(createVersionCommand(runtime));
35
47
  program.addCommand(createAuthCommand(runtime));
36
- program.addCommand(createBranchCommand(runtime));
37
48
  program.addCommand(createProjectCommand(runtime));
49
+ program.addCommand(createGitCommand(runtime));
50
+ program.addCommand(createBranchCommand(runtime));
38
51
  program.addCommand(createAppCommand(runtime));
39
52
  return program;
40
53
  }
54
+ async function handleVersionFlag(runtime) {
55
+ const wantsJson = runtime.argv.includes("--json");
56
+ const output = {
57
+ stdout: runtime.stdout,
58
+ stderr: runtime.stderr
59
+ };
60
+ try {
61
+ if (wantsJson) {
62
+ const success = await runVersion(await createCommandContext(runtime, buildVersionFlagFlags(runtime)));
63
+ writeJsonSuccess(output, {
64
+ command: success.command,
65
+ result: { version: success.result.cli.version },
66
+ warnings: success.warnings,
67
+ nextSteps: success.nextSteps
68
+ });
69
+ return 0;
70
+ }
71
+ const versionLine = `${getCliName()} ${getCliVersion()}`;
72
+ runtime.stdout.write(`${versionLine}\n`);
73
+ return 0;
74
+ } catch (error) {
75
+ if (error instanceof CliError) {
76
+ if (wantsJson) writeJsonError(output, "version", error);
77
+ else writeHumanError(output, createShellUi(runtime, buildVersionFlagFlags(runtime)), error, { trace: false });
78
+ return error.exitCode;
79
+ }
80
+ throw error;
81
+ }
82
+ }
83
+ function buildVersionFlagFlags(runtime) {
84
+ return {
85
+ json: runtime.argv.includes("--json"),
86
+ quiet: false,
87
+ verbose: false,
88
+ trace: false,
89
+ yes: false,
90
+ interactive: void 0,
91
+ color: void 0
92
+ };
93
+ }
41
94
  function resolveBareHelpCommand(program, argv) {
42
95
  if (argv.length === 0) return program;
43
96
  if (argv.length !== 1) return null;
44
- return program.commands.find((command) => command.name() === argv[0]) ?? null;
97
+ const candidate = program.commands.find((command) => command.name() === argv[0]) ?? null;
98
+ if (!candidate) return null;
99
+ if (candidate.commands.length === 0) return null;
100
+ return candidate;
45
101
  }
46
102
  function resolveRuntime(options) {
47
103
  return {
@@ -1,14 +1,15 @@
1
1
  import { attachCommandDescriptor } from "../../shell/command-meta.js";
2
- import { addGlobalFlags } from "../../shell/global-flags.js";
2
+ import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
3
3
  import { configureRuntimeCommand } from "../../shell/runtime.js";
4
4
  import { PREVIEW_BUILD_TYPES } from "../../lib/app/preview-build.js";
5
5
  import { runAppBuild, runAppDeploy, runAppListDeploys, runAppListEnv, runAppLogs, runAppOpen, runAppPromote, runAppRemove, runAppRollback, runAppRun, runAppShow, runAppShowDeploy, runAppUpdateEnv } from "../../controllers/app.js";
6
6
  import { renderAppBuild, renderAppDeploy, renderAppListDeploys, renderAppListEnv, renderAppOpen, renderAppPromote, renderAppRemove, renderAppRollback, renderAppRun, renderAppShow, renderAppShowDeploy, renderAppUpdateEnv, serializeAppBuild, serializeAppDeploy, serializeAppListDeploys, serializeAppListEnv, serializeAppOpen, serializeAppPromote, serializeAppRemove, serializeAppRollback, serializeAppRun, serializeAppShow, serializeAppShowDeploy, serializeAppUpdateEnv } from "../../presenters/app.js";
7
- import { runCommand } from "../../shell/command-runner.js";
7
+ import { runCommand, runStreamingCommand } from "../../shell/command-runner.js";
8
8
  import { Command, Option } from "commander";
9
9
  //#region src/commands/app/index.ts
10
10
  function createAppCommand(runtime) {
11
11
  const app = attachCommandDescriptor(configureRuntimeCommand(new Command("app"), runtime), "app");
12
+ addCompactGlobalFlags(app);
12
13
  app.addCommand(createBuildCommand(runtime));
13
14
  app.addCommand(createRunCommand(runtime));
14
15
  app.addCommand(createDeployCommand(runtime));
@@ -59,17 +60,27 @@ function createRunCommand(runtime) {
59
60
  }
60
61
  function createDeployCommand(runtime) {
61
62
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("deploy"), runtime), "app.deploy");
62
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--entry <path>", "Entrypoint path for Bun or auto deploys")).addOption(new Option("--build-type <type>", "Deploy build type").choices([...PREVIEW_BUILD_TYPES]).default("auto")).addOption(new Option("--http-port <port>", "HTTP port override for the deployed app")).addOption(new Option("--env <name=value>", "Environment variable").argParser(collectRepeatableValues));
63
+ command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--branch <name>", "Branch name")).addOption(new Option("--framework <name>", "Framework to deploy").choices([
64
+ "nextjs",
65
+ "hono",
66
+ "tanstack-start"
67
+ ])).addOption(new Option("--entry <path>", "Entrypoint path for Bun or auto deploys")).addOption(new Option("--build-type <type>", "Legacy deploy build type").choices([...PREVIEW_BUILD_TYPES]).default("auto").hideHelp()).addOption(new Option("--http-port <port>", "HTTP port override for the deployed app")).addOption(new Option("--env <name=value>", "Environment variable").argParser(collectRepeatableValues));
63
68
  addGlobalFlags(command);
64
69
  command.action(async (options) => {
65
70
  const appName = options.app;
66
71
  const entry = options.entry;
67
72
  const buildType = options.buildType;
73
+ const branchName = options.branch;
74
+ const framework = options.framework;
68
75
  const httpPort = options.httpPort;
69
76
  const envAssignments = options.env;
77
+ const projectRef = options.project;
70
78
  await runCommand(runtime, "app.deploy", options, (context) => runAppDeploy(context, appName, {
79
+ projectRef,
80
+ branchName,
71
81
  entrypoint: entry,
72
82
  buildType,
83
+ framework,
73
84
  httpPort,
74
85
  envAssignments
75
86
  }), {
@@ -81,12 +92,13 @@ function createDeployCommand(runtime) {
81
92
  }
82
93
  function createUpdateEnvCommand(runtime) {
83
94
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("update-env"), runtime), "app.update-env");
84
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--env <name=value>", "Environment variable").argParser(collectRepeatableValues));
95
+ command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--env <name=value>", "Environment variable").argParser(collectRepeatableValues));
85
96
  addGlobalFlags(command);
86
97
  command.action(async (options) => {
87
98
  const appName = options.app;
88
99
  const envAssignments = options.env;
89
- await runCommand(runtime, "app.update-env", options, (context) => runAppUpdateEnv(context, appName, envAssignments), {
100
+ const projectRef = options.project;
101
+ await runCommand(runtime, "app.update-env", options, (context) => runAppUpdateEnv(context, appName, envAssignments, projectRef), {
90
102
  renderHuman: (context, descriptor, result) => renderAppUpdateEnv(context, descriptor, result),
91
103
  renderJson: (result) => serializeAppUpdateEnv(result)
92
104
  });
@@ -95,11 +107,12 @@ function createUpdateEnvCommand(runtime) {
95
107
  }
96
108
  function createListEnvCommand(runtime) {
97
109
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list-env"), runtime), "app.list-env");
98
- command.addOption(new Option("--app <name>", "App name"));
110
+ command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
99
111
  addGlobalFlags(command);
100
112
  command.action(async (options) => {
101
113
  const appName = options.app;
102
- await runCommand(runtime, "app.list-env", options, (context) => runAppListEnv(context, appName), {
114
+ const projectRef = options.project;
115
+ await runCommand(runtime, "app.list-env", options, (context) => runAppListEnv(context, appName, projectRef), {
103
116
  renderHuman: (context, descriptor, result) => renderAppListEnv(context, descriptor, result),
104
117
  renderJson: (result) => serializeAppListEnv(result)
105
118
  });
@@ -108,11 +121,12 @@ function createListEnvCommand(runtime) {
108
121
  }
109
122
  function createShowCommand(runtime) {
110
123
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "app.show");
111
- command.addOption(new Option("--app <name>", "App name"));
124
+ command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
112
125
  addGlobalFlags(command);
113
126
  command.action(async (options) => {
114
127
  const appName = options.app;
115
- await runCommand(runtime, "app.show", options, (context) => runAppShow(context, appName), {
128
+ const projectRef = options.project;
129
+ await runCommand(runtime, "app.show", options, (context) => runAppShow(context, appName, projectRef), {
116
130
  renderHuman: (context, descriptor, result) => renderAppShow(context, descriptor, result),
117
131
  renderJson: (result) => serializeAppShow(result)
118
132
  });
@@ -121,11 +135,12 @@ function createShowCommand(runtime) {
121
135
  }
122
136
  function createOpenCommand(runtime) {
123
137
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("open"), runtime), "app.open");
124
- command.addOption(new Option("--app <name>", "App name"));
138
+ command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
125
139
  addGlobalFlags(command);
126
140
  command.action(async (options) => {
127
141
  const appName = options.app;
128
- await runCommand(runtime, "app.open", options, (context) => runAppOpen(context, appName), {
142
+ const projectRef = options.project;
143
+ await runCommand(runtime, "app.open", options, (context) => runAppOpen(context, appName, projectRef), {
129
144
  renderHuman: (context, descriptor, result) => renderAppOpen(context, descriptor, result),
130
145
  renderJson: (result) => serializeAppOpen(result)
131
146
  });
@@ -134,12 +149,13 @@ function createOpenCommand(runtime) {
134
149
  }
135
150
  function createLogsCommand(runtime) {
136
151
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("logs"), runtime), "app.logs");
137
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--deployment <id>", "Deployment id"));
152
+ command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--deployment <id>", "Deployment id"));
138
153
  addGlobalFlags(command);
139
154
  command.action(async (options) => {
140
155
  const appName = options.app;
141
156
  const deploymentId = options.deployment;
142
- await runCommand(runtime, "app.logs", options, (context) => runAppLogs(context, appName, deploymentId), { renderHuman: () => [] });
157
+ const projectRef = options.project;
158
+ await runStreamingCommand(runtime, "app.logs", options, (context) => runAppLogs(context, appName, deploymentId, projectRef));
143
159
  });
144
160
  return command;
145
161
  }
@@ -148,11 +164,12 @@ function collectRepeatableValues(value, previous) {
148
164
  }
149
165
  function createListDeploysCommand(runtime) {
150
166
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list-deploys"), runtime), "app.list-deploys");
151
- command.addOption(new Option("--app <name>", "App name"));
167
+ command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
152
168
  addGlobalFlags(command);
153
169
  command.action(async (options) => {
154
170
  const appName = options.app;
155
- await runCommand(runtime, "app.list-deploys", options, (context) => runAppListDeploys(context, appName), {
171
+ const projectRef = options.project;
172
+ await runCommand(runtime, "app.list-deploys", options, (context) => runAppListDeploys(context, appName, projectRef), {
156
173
  renderHuman: (context, descriptor, result) => renderAppListDeploys(context, descriptor, result),
157
174
  renderJson: (result) => serializeAppListDeploys(result)
158
175
  });
@@ -174,11 +191,12 @@ function createShowDeployCommand(runtime) {
174
191
  function createPromoteCommand(runtime) {
175
192
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("promote"), runtime), "app.promote");
176
193
  command.argument("<deployment>", "Deployment id");
177
- command.addOption(new Option("--app <name>", "App name"));
194
+ command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
178
195
  addGlobalFlags(command);
179
196
  command.action(async (deploymentId, options) => {
180
197
  const appName = options.app;
181
- await runCommand(runtime, "app.promote", options, (context) => runAppPromote(context, deploymentId, appName), {
198
+ const projectRef = options.project;
199
+ await runCommand(runtime, "app.promote", options, (context) => runAppPromote(context, deploymentId, appName, projectRef), {
182
200
  renderHuman: (context, descriptor, result) => renderAppPromote(context, descriptor, result),
183
201
  renderJson: (result) => serializeAppPromote(result)
184
202
  });
@@ -187,12 +205,13 @@ function createPromoteCommand(runtime) {
187
205
  }
188
206
  function createRollbackCommand(runtime) {
189
207
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("rollback"), runtime), "app.rollback");
190
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--to <deployment>", "Deployment id"));
208
+ command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--to <deployment>", "Deployment id"));
191
209
  addGlobalFlags(command);
192
210
  command.action(async (options) => {
193
211
  const appName = options.app;
194
212
  const deploymentId = options.to;
195
- await runCommand(runtime, "app.rollback", options, (context) => runAppRollback(context, appName, deploymentId), {
213
+ const projectRef = options.project;
214
+ await runCommand(runtime, "app.rollback", options, (context) => runAppRollback(context, appName, deploymentId, projectRef), {
196
215
  renderHuman: (context, descriptor, result) => renderAppRollback(context, descriptor, result),
197
216
  renderJson: (result) => serializeAppRollback(result)
198
217
  });
@@ -201,11 +220,12 @@ function createRollbackCommand(runtime) {
201
220
  }
202
221
  function createRemoveCommand(runtime) {
203
222
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("remove"), runtime), "app.remove");
204
- command.addOption(new Option("--app <name>", "App name"));
223
+ command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
205
224
  addGlobalFlags(command);
206
225
  command.action(async (options) => {
207
226
  const appName = options.app;
208
- await runCommand(runtime, "app.remove", options, (context) => runAppRemove(context, appName), {
227
+ const projectRef = options.project;
228
+ await runCommand(runtime, "app.remove", options, (context) => runAppRemove(context, appName, projectRef), {
209
229
  renderHuman: (context, descriptor, result) => renderAppRemove(context, descriptor, result),
210
230
  renderJson: (result) => serializeAppRemove(result)
211
231
  });
@@ -1,13 +1,14 @@
1
1
  import { attachCommandDescriptor } from "../../shell/command-meta.js";
2
- import { addGlobalFlags } from "../../shell/global-flags.js";
2
+ import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
3
3
  import { configureRuntimeCommand } from "../../shell/runtime.js";
4
- import { runCommand } from "../../shell/command-runner.js";
5
4
  import { runAuthLogin, runAuthLogout, runAuthWhoAmI } from "../../controllers/auth.js";
5
+ import { runCommand } from "../../shell/command-runner.js";
6
6
  import { renderAuthSuccess } from "../../presenters/auth.js";
7
7
  import { Command, Option } from "commander";
8
8
  //#region src/commands/auth/index.ts
9
9
  function createAuthCommand(runtime) {
10
10
  const auth = attachCommandDescriptor(configureRuntimeCommand(new Command("auth"), runtime), "auth");
11
+ addCompactGlobalFlags(auth);
11
12
  auth.addCommand(createAuthLoginCommand(runtime));
12
13
  auth.addCommand(createAuthLogoutCommand(runtime));
13
14
  auth.addCommand(createAuthWhoAmICommand(runtime));
@@ -1,5 +1,5 @@
1
1
  import { attachCommandDescriptor } from "../../shell/command-meta.js";
2
- import { addGlobalFlags } from "../../shell/global-flags.js";
2
+ import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
3
3
  import { configureRuntimeCommand } from "../../shell/runtime.js";
4
4
  import { runCommand } from "../../shell/command-runner.js";
5
5
  import { runBranchList, runBranchShow, runBranchUse } from "../../controllers/branch.js";
@@ -8,6 +8,7 @@ import { Command } from "commander";
8
8
  //#region src/commands/branch/index.ts
9
9
  function createBranchCommand(runtime) {
10
10
  const branch = attachCommandDescriptor(configureRuntimeCommand(new Command("branch"), runtime), "branch");
11
+ addCompactGlobalFlags(branch);
11
12
  branch.addCommand(createBranchListCommand(runtime));
12
13
  branch.addCommand(createBranchShowCommand(runtime));
13
14
  branch.addCommand(createBranchUseCommand(runtime));
@@ -0,0 +1,87 @@
1
+ import { attachCommandDescriptor } from "../shell/command-meta.js";
2
+ import { addGlobalFlags } from "../shell/global-flags.js";
3
+ import { configureRuntimeCommand } from "../shell/runtime.js";
4
+ import { runCommand } from "../shell/command-runner.js";
5
+ import { runEnvAdd, runEnvList, runEnvRm, runEnvUpdate } from "../controllers/app-env.js";
6
+ import { renderEnvAdd, renderEnvList, renderEnvRm, renderEnvUpdate, serializeEnvAdd, serializeEnvList, serializeEnvRm, serializeEnvUpdate } from "../presenters/app-env.js";
7
+ import { Command, Option } from "commander";
8
+ //#region src/commands/env.ts
9
+ function createEnvCommand(runtime) {
10
+ const env = attachCommandDescriptor(configureRuntimeCommand(new Command("env"), runtime), "project.env");
11
+ env.description("Manage environment variables for the active project");
12
+ env.addCommand(createEnvAddCommand(runtime));
13
+ env.addCommand(createEnvUpdateCommand(runtime));
14
+ env.addCommand(createEnvListCommand(runtime));
15
+ env.addCommand(createEnvRmCommand(runtime));
16
+ return env;
17
+ }
18
+ function createEnvAddCommand(runtime) {
19
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("add"), runtime), "project.env.add");
20
+ command.argument("<assignment>", "Variable assignment as KEY=VALUE or KEY from the current environment").addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--project <id-or-name>", "Project id or name"));
21
+ addGlobalFlags(command);
22
+ command.action(async (assignment, options) => {
23
+ const roleName = options.role;
24
+ const projectRef = options.project;
25
+ await runCommand(runtime, "project.env.add", options, (context) => runEnvAdd(context, assignment, {
26
+ roleName,
27
+ projectRef
28
+ }), {
29
+ renderHuman: (context, descriptor, result) => renderEnvAdd(context, descriptor, result),
30
+ renderJson: (result) => serializeEnvAdd(result)
31
+ });
32
+ });
33
+ return command;
34
+ }
35
+ function createEnvUpdateCommand(runtime) {
36
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("update"), runtime), "project.env.update");
37
+ command.argument("<assignment>", "Variable assignment as KEY=VALUE or KEY from the current environment").addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--project <id-or-name>", "Project id or name"));
38
+ addGlobalFlags(command);
39
+ command.action(async (assignment, options) => {
40
+ const roleName = options.role;
41
+ const projectRef = options.project;
42
+ await runCommand(runtime, "project.env.update", options, (context) => runEnvUpdate(context, assignment, {
43
+ roleName,
44
+ projectRef
45
+ }), {
46
+ renderHuman: (context, descriptor, result) => renderEnvUpdate(context, descriptor, result),
47
+ renderJson: (result) => serializeEnvUpdate(result)
48
+ });
49
+ });
50
+ return command;
51
+ }
52
+ function createEnvListCommand(runtime) {
53
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list"), runtime), "project.env.list");
54
+ command.addOption(new Option("--role <role>", "Project template scope").choices(["production", "preview"])).addOption(new Option("--project <id-or-name>", "Project id or name"));
55
+ addGlobalFlags(command);
56
+ command.action(async (options) => {
57
+ const roleName = options.role;
58
+ const projectRef = options.project;
59
+ await runCommand(runtime, "project.env.list", options, (context) => runEnvList(context, {
60
+ roleName,
61
+ projectRef
62
+ }), {
63
+ renderHuman: (context, descriptor, result) => renderEnvList(context, descriptor, result),
64
+ renderJson: (result) => serializeEnvList(result)
65
+ });
66
+ });
67
+ return command;
68
+ }
69
+ function createEnvRmCommand(runtime) {
70
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("rm"), runtime), "project.env.rm");
71
+ command.argument("<key>", "Variable key to remove").addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--project <id-or-name>", "Project id or name"));
72
+ addGlobalFlags(command);
73
+ command.action(async (key, options) => {
74
+ const roleName = options.role;
75
+ const projectRef = options.project;
76
+ await runCommand(runtime, "project.env.rm", options, (context) => runEnvRm(context, key, {
77
+ roleName,
78
+ projectRef
79
+ }), {
80
+ renderHuman: (context, descriptor, result) => renderEnvRm(context, descriptor, result),
81
+ renderJson: (result) => serializeEnvRm(result)
82
+ });
83
+ });
84
+ return command;
85
+ }
86
+ //#endregion
87
+ export { createEnvCommand };
@@ -0,0 +1,36 @@
1
+ import { attachCommandDescriptor } from "../../shell/command-meta.js";
2
+ import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
3
+ import { configureRuntimeCommand } from "../../shell/runtime.js";
4
+ import { runGitConnect, runGitDisconnect } from "../../controllers/project.js";
5
+ import { runCommand } from "../../shell/command-runner.js";
6
+ import { renderGitConnect, renderGitDisconnect } from "../../presenters/project.js";
7
+ import { Command } from "commander";
8
+ //#region src/commands/git/index.ts
9
+ function createGitCommand(runtime) {
10
+ const git = attachCommandDescriptor(configureRuntimeCommand(new Command("git"), runtime), "git");
11
+ addCompactGlobalFlags(git);
12
+ git.addCommand(createGitConnectCommand(runtime));
13
+ git.addCommand(createGitDisconnectCommand(runtime));
14
+ return git;
15
+ }
16
+ function createGitConnectCommand(runtime) {
17
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("connect"), runtime), "git.connect");
18
+ command.argument("[git-url]", "GitHub repository URL");
19
+ command.option("--project <id-or-name>", "Project id or name");
20
+ addGlobalFlags(command);
21
+ command.action(async (gitUrl, options) => {
22
+ await runCommand(runtime, "git.connect", options, (context) => runGitConnect(context, gitUrl, { project: typeof options.project === "string" ? options.project : void 0 }), { renderHuman: (context, descriptor, result) => renderGitConnect(context, descriptor, result) });
23
+ });
24
+ return command;
25
+ }
26
+ function createGitDisconnectCommand(runtime) {
27
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("disconnect"), runtime), "git.disconnect");
28
+ command.option("--project <id-or-name>", "Project id or name");
29
+ addGlobalFlags(command);
30
+ command.action(async (options) => {
31
+ await runCommand(runtime, "git.disconnect", options, (context) => runGitDisconnect(context, { project: typeof options.project === "string" ? options.project : void 0 }), { renderHuman: (context, descriptor, result) => renderGitDisconnect(context, descriptor, result) });
32
+ });
33
+ return command;
34
+ }
35
+ //#endregion
36
+ export { createGitCommand };