@prisma/cli 2.20.1 → 3.0.0-alpha.0

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 (217) hide show
  1. package/LICENSE +158 -0
  2. package/README.md +29 -28
  3. package/dist/adapters/config.js +74 -0
  4. package/dist/adapters/local-state.js +98 -0
  5. package/dist/adapters/mock-api.js +57 -0
  6. package/dist/adapters/token-storage.js +43 -0
  7. package/dist/cli.js +9 -0
  8. package/dist/cli2.js +59 -0
  9. package/dist/commands/app/index.js +223 -0
  10. package/dist/commands/auth/index.js +42 -0
  11. package/dist/commands/branch/index.js +51 -0
  12. package/dist/commands/project/index.js +45 -0
  13. package/dist/controllers/app.js +813 -0
  14. package/dist/controllers/auth.js +107 -0
  15. package/dist/controllers/branch.js +73 -0
  16. package/dist/controllers/project.js +214 -0
  17. package/dist/controllers/select-prompt-port.js +12 -0
  18. package/dist/lib/app/bun-project.js +39 -0
  19. package/dist/lib/app/env-vars.js +24 -0
  20. package/dist/lib/app/local-dev.js +149 -0
  21. package/dist/lib/app/preview-build.js +283 -0
  22. package/dist/lib/app/preview-interaction.js +38 -0
  23. package/dist/lib/app/preview-progress.js +139 -0
  24. package/dist/lib/app/preview-provider.js +232 -0
  25. package/dist/lib/auth/auth-ops.js +57 -0
  26. package/dist/lib/auth/client.js +22 -0
  27. package/dist/lib/auth/guard.js +34 -0
  28. package/dist/lib/auth/login.js +117 -0
  29. package/dist/output/patterns.js +93 -0
  30. package/dist/presenters/app.js +405 -0
  31. package/dist/presenters/auth.js +73 -0
  32. package/dist/presenters/branch.js +111 -0
  33. package/dist/presenters/project.js +84 -0
  34. package/dist/shell/command-meta.js +320 -0
  35. package/dist/shell/command-runner.js +33 -0
  36. package/dist/shell/errors.js +66 -0
  37. package/dist/shell/global-flags.js +25 -0
  38. package/dist/shell/help.js +78 -0
  39. package/dist/shell/output.js +54 -0
  40. package/dist/shell/prompt.js +31 -0
  41. package/dist/shell/runtime.js +51 -0
  42. package/dist/shell/ui.js +59 -0
  43. package/dist/use-cases/auth.js +70 -0
  44. package/dist/use-cases/branch.js +95 -0
  45. package/dist/use-cases/create-cli-gateways.js +93 -0
  46. package/dist/use-cases/project.js +75 -0
  47. package/package.json +49 -137
  48. package/build/child.js +0 -4110
  49. package/build/index.js +0 -104447
  50. package/build/public/.DS_Store +0 -0
  51. package/build/public/assets/alert.60ea9f84.svg +0 -5
  52. package/build/public/assets/array.1a36c222.svg +0 -4
  53. package/build/public/assets/boolean.9188b434.svg +0 -4
  54. package/build/public/assets/browser.21a575be.js +0 -1
  55. package/build/public/assets/browser.38b7fdb1.js +0 -1
  56. package/build/public/assets/browser.cdd2249a.js +0 -1
  57. package/build/public/assets/chevron-down.24f76e3c.svg +0 -3
  58. package/build/public/assets/cross.c2610cf5.svg +0 -11
  59. package/build/public/assets/datetime.a3bf710a.svg +0 -4
  60. package/build/public/assets/download.8d34b65a.svg +0 -4
  61. package/build/public/assets/ellipsis.a8c5a34a.svg +0 -10
  62. package/build/public/assets/enum.7ec0b64c.svg +0 -6
  63. package/build/public/assets/folder.d77b8eaf.svg +0 -6
  64. package/build/public/assets/hamburger.5fdadeac.svg +0 -4
  65. package/build/public/assets/logotype.a960b169.svg +0 -4
  66. package/build/public/assets/number.85ddf96b.svg +0 -7
  67. package/build/public/assets/object.0ba944a6.svg +0 -5
  68. package/build/public/assets/play.8811691e.svg +0 -6
  69. package/build/public/assets/plus.8fbf7ad3.svg +0 -4
  70. package/build/public/assets/read.79154521.svg +0 -1
  71. package/build/public/assets/refresh.d5448ccc.svg +0 -4
  72. package/build/public/assets/search.2ed766ce.svg +0 -7
  73. package/build/public/assets/settings.5ad25af2.svg +0 -8
  74. package/build/public/assets/string.ea615a24.svg +0 -4
  75. package/build/public/assets/tick-indeterminate.aec8a44d.svg +0 -3
  76. package/build/public/assets/tick.8cbb6a93.svg +0 -4
  77. package/build/public/assets/vendor.c4d0f081.js +0 -354
  78. package/build/public/demo.html +0 -17
  79. package/build/public/demoChunk.js +0 -2
  80. package/build/public/electron-darwin.html +0 -19
  81. package/build/public/electron-linux.html +0 -18
  82. package/build/public/electron-mac.html +0 -18
  83. package/build/public/electron-win.html +0 -17
  84. package/build/public/electron-win32.html +0 -18
  85. package/build/public/electron.html +0 -17
  86. package/build/public/electronBus.js +0 -2
  87. package/build/public/electronChunk.js +0 -2
  88. package/build/public/favicon/apple-touch-icon.png +0 -0
  89. package/build/public/favicon/favicon-16x16.png +0 -0
  90. package/build/public/favicon/favicon-32x32.png +0 -0
  91. package/build/public/favicon/prisma.png +0 -0
  92. package/build/public/favicon.svg +0 -5
  93. package/build/public/fonts/.DS_Store +0 -0
  94. package/build/public/fonts/Inter.ttf +0 -0
  95. package/build/public/fonts/RobotoMono.ttf +0 -0
  96. package/build/public/icons/.DS_Store +0 -0
  97. package/build/public/icons/alert.svg +0 -5
  98. package/build/public/icons/array.svg +0 -4
  99. package/build/public/icons/bin.svg +0 -37
  100. package/build/public/icons/boolean.svg +0 -4
  101. package/build/public/icons/check.svg +0 -3
  102. package/build/public/icons/chevron-down.svg +0 -3
  103. package/build/public/icons/code.svg +0 -4
  104. package/build/public/icons/cross.svg +0 -11
  105. package/build/public/icons/data-tool.svg +0 -5
  106. package/build/public/icons/database.svg +0 -4
  107. package/build/public/icons/datetime.svg +0 -4
  108. package/build/public/icons/double-arrow-right.svg +0 -4
  109. package/build/public/icons/download.svg +0 -4
  110. package/build/public/icons/ellipsis.svg +0 -10
  111. package/build/public/icons/enum.svg +0 -6
  112. package/build/public/icons/expand.svg +0 -4
  113. package/build/public/icons/eye.svg +0 -20
  114. package/build/public/icons/filters.svg +0 -5
  115. package/build/public/icons/folder.svg +0 -6
  116. package/build/public/icons/hamburger.svg +0 -4
  117. package/build/public/icons/icon.svg +0 -199
  118. package/build/public/icons/logo.svg +0 -199
  119. package/build/public/icons/logotype.svg +0 -4
  120. package/build/public/icons/number.svg +0 -7
  121. package/build/public/icons/object.svg +0 -5
  122. package/build/public/icons/play.svg +0 -6
  123. package/build/public/icons/plus.svg +0 -4
  124. package/build/public/icons/refresh.svg +0 -4
  125. package/build/public/icons/search.svg +0 -7
  126. package/build/public/icons/settings.svg +0 -8
  127. package/build/public/icons/string.svg +0 -4
  128. package/build/public/icons/tick-indeterminate.svg +0 -3
  129. package/build/public/icons/tick.svg +0 -4
  130. package/build/public/illustrations/.DS_Store +0 -0
  131. package/build/public/illustrations/empty.svg +0 -1
  132. package/build/public/illustrations/read.svg +0 -1
  133. package/build/public/illustrations/searching.svg +0 -1
  134. package/build/public/images/.DS_Store +0 -0
  135. package/build/public/images/icon-1024.png +0 -0
  136. package/build/public/index.css +0 -1
  137. package/build/public/index.html +0 -49
  138. package/build/public/index.js +0 -1
  139. package/build/public/main.31f688a6254e294d9128.css +0 -118
  140. package/build/public/main.31f688a6254e294d9128.css.map +0 -1
  141. package/build/public/main.364c712f32662ff0e43d.css +0 -116
  142. package/build/public/main.364c712f32662ff0e43d.css.map +0 -1
  143. package/build/public/main.42ef3fe7e97347765c91.css +0 -118
  144. package/build/public/main.42ef3fe7e97347765c91.css.map +0 -1
  145. package/build/public/main.503446defafe7aeca2f3.css +0 -116
  146. package/build/public/main.503446defafe7aeca2f3.css.map +0 -1
  147. package/build/public/main.c50a3b5980fe26f78b65.css +0 -118
  148. package/build/public/main.c50a3b5980fe26f78b65.css.map +0 -1
  149. package/build/public/main.cda25e5813776c2af295.css +0 -116
  150. package/build/public/main.cda25e5813776c2af295.css.map +0 -1
  151. package/build/public/main.dbac3b290f78404ff579.css +0 -116
  152. package/build/public/main.dbac3b290f78404ff579.css.map +0 -1
  153. package/build/public/main.f8ce44e122e5e2b8f778.css +0 -118
  154. package/build/public/main.f8ce44e122e5e2b8f778.css.map +0 -1
  155. package/build/public/main.fc9ea7521a4aecce1a77.css +0 -118
  156. package/build/public/main.fc9ea7521a4aecce1a77.css.map +0 -1
  157. package/build/public/main.js +0 -403
  158. package/build/public/main.js.map +0 -1
  159. package/build/public/mainChunk.0a84f3ba4d2ab481e877.css +0 -116
  160. package/build/public/mainChunk.1b327d58afbddc917bce.css +0 -118
  161. package/build/public/mainChunk.2cdf583b2bd51aa67587.css +0 -118
  162. package/build/public/mainChunk.544af00f7e9ffcbe782c.css +0 -118
  163. package/build/public/mainChunk.56f96a13868b2b4a53be.css +0 -118
  164. package/build/public/mainChunk.5cee429bfbf06e7ecb39.css +0 -118
  165. package/build/public/mainChunk.a862474ed4cdb421ffa2.css +0 -118
  166. package/build/public/mainChunk.ada34153c4911b5ac22b.css +0 -118
  167. package/build/public/mainChunk.c16a8d01b2c49b2f2751.css +0 -118
  168. package/build/public/mainChunk.ca4a878d5478b9320be8.css +0 -116
  169. package/build/public/mainChunk.e3adc8758b4395546cef.css +0 -116
  170. package/build/public/mainChunk.f2c59fcbfc455d8b9de5.css +0 -118
  171. package/build/public/mainChunk.js +0 -396
  172. package/build/public/manifest.json +0 -34
  173. package/build/public/preview.html +0 -16
  174. package/build/public/previewBus.js +0 -2
  175. package/build/public/previewChunk.js +0 -2
  176. package/build/public/projects.html +0 -86
  177. package/build/public/server.html +0 -16
  178. package/build/public/serverBus.js +0 -2
  179. package/build/public/serverChunk.js +0 -2
  180. package/build/public/splash.html +0 -17
  181. package/build/public/studioBundle.828f34b1781061528841.css +0 -118
  182. package/build/public/studioBundle.bfe9138b2e0293fcb7da.css +0 -118
  183. package/build/public/studioBundle.c5b256eede880e502aac.css +0 -118
  184. package/build/public/studioBundle.e43df511c8e2e368900a.css +0 -118
  185. package/build/public/studioBundle.e69382554c2a2942ae32.css +0 -118
  186. package/build/public/studioBundle.ee21aa56a3999a2b380b.css +0 -118
  187. package/build/public/studioBundle.js +0 -396
  188. package/build/public/vercel.html +0 -16
  189. package/build/public/vercelChunk.js +0 -2
  190. package/build/public/views/index.pug +0 -89
  191. package/build/xdg-open +0 -1066
  192. package/install/index.js +0 -5
  193. package/preinstall/index.js +0 -46
  194. package/prisma-client/README.md +0 -27
  195. package/prisma-client/generator-build/.DS_Store +0 -0
  196. package/prisma-client/generator-build/index.js +0 -79697
  197. package/prisma-client/index-browser.js +0 -3
  198. package/prisma-client/index.d.ts +0 -1
  199. package/prisma-client/index.js +0 -11
  200. package/prisma-client/package.json +0 -138
  201. package/prisma-client/runtime/index-browser.d.ts +0 -267
  202. package/prisma-client/runtime/index-browser.js +0 -2273
  203. package/prisma-client/runtime/index.d.ts +0 -1018
  204. package/prisma-client/runtime/index.js +0 -35028
  205. package/prisma-client/scripts/backup-index-browser.js +0 -3
  206. package/prisma-client/scripts/backup-index.d.ts +0 -1
  207. package/prisma-client/scripts/backup-index.js +0 -11
  208. package/prisma-client/scripts/colors.js +0 -180
  209. package/prisma-client/scripts/default-index-browser.js +0 -12
  210. package/prisma-client/scripts/default-index.d.ts +0 -47
  211. package/prisma-client/scripts/default-index.js +0 -12
  212. package/prisma-client/scripts/get-packed-client.js +0 -12
  213. package/prisma-client/scripts/mock-fs.js +0 -14
  214. package/prisma-client/scripts/postinstall.d.ts +0 -5
  215. package/prisma-client/scripts/postinstall.js +0 -398
  216. package/scripts/install-entry.js +0 -8
  217. package/scripts/preinstall-entry.js +0 -9
@@ -0,0 +1,57 @@
1
+ import { FileTokenStorage } from "../../adapters/token-storage.js";
2
+ import { requireComputeAuth } from "./guard.js";
3
+ import { login } from "./login.js";
4
+ //#region src/lib/auth/auth-ops.ts
5
+ function decodeJwtPayload(token) {
6
+ try {
7
+ const payload = token.split(".")[1];
8
+ if (!payload) return {};
9
+ return JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
10
+ } catch {
11
+ return {};
12
+ }
13
+ }
14
+ async function performLogin(env) {
15
+ await login({
16
+ tokenStorage: new FileTokenStorage(env),
17
+ env
18
+ });
19
+ }
20
+ async function readAuthState(env) {
21
+ const tokens = await new FileTokenStorage(env).getTokens();
22
+ if (!tokens) return {
23
+ authenticated: false,
24
+ provider: null,
25
+ user: null,
26
+ workspace: null,
27
+ linkedProjectId: null
28
+ };
29
+ const claims = decodeJwtPayload(tokens.accessToken);
30
+ const client = await requireComputeAuth(env);
31
+ let workspaceId = tokens.workspaceId;
32
+ let workspaceName = tokens.workspaceId;
33
+ if (client) try {
34
+ const { data } = await client.GET("/v1/workspaces/{id}", { params: { path: { id: tokens.workspaceId } } });
35
+ if (data?.data?.id) workspaceId = data.data.id;
36
+ if (data?.data?.name) workspaceName = data.data.name;
37
+ } catch {}
38
+ return {
39
+ authenticated: true,
40
+ provider: null,
41
+ user: {
42
+ id: claims.sub ?? "",
43
+ name: claims.name ?? "",
44
+ email: claims.email ?? ""
45
+ },
46
+ workspace: {
47
+ id: workspaceId,
48
+ name: workspaceName
49
+ },
50
+ linkedProjectId: null
51
+ };
52
+ }
53
+ async function performLogout(env) {
54
+ await new FileTokenStorage(env).clearTokens();
55
+ }
56
+ //#endregion
57
+ export { performLogin, performLogout, readAuthState };
@@ -0,0 +1,22 @@
1
+ import path from "node:path";
2
+ import os from "node:os";
3
+ //#region src/lib/auth/client.ts
4
+ const CLIENT_ID = "cmm3lndn701oo0uefvxzo0ivw";
5
+ const SERVICE_TOKEN_ENV_VAR = "PRISMA_API_TOKEN";
6
+ const AUTH_FILE_ENV_VAR = "PRISMA_COMPUTE_AUTH_FILE";
7
+ function getApiBaseUrl(env = process.env) {
8
+ return env.PRISMA_MANAGEMENT_API_URL?.trim() || "https://api.prisma.io";
9
+ }
10
+ function getAuthFilePath(env = process.env) {
11
+ const configured = env[AUTH_FILE_ENV_VAR];
12
+ if (configured?.trim()) return path.resolve(configured);
13
+ if (process.platform === "darwin") return path.join(os.homedir(), "Library", "Application Support", "prisma", "auth.json");
14
+ if (process.platform === "win32") {
15
+ const appData = env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming");
16
+ return path.join(appData, "prisma", "auth.json");
17
+ }
18
+ const xdgConfigHome = env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config");
19
+ return path.join(xdgConfigHome, "prisma", "auth.json");
20
+ }
21
+ //#endregion
22
+ export { CLIENT_ID, SERVICE_TOKEN_ENV_VAR, getApiBaseUrl, getAuthFilePath };
@@ -0,0 +1,34 @@
1
+ import { CLIENT_ID, SERVICE_TOKEN_ENV_VAR, getApiBaseUrl } from "./client.js";
2
+ import { FileTokenStorage } from "../../adapters/token-storage.js";
3
+ import { createManagementApiClient, createManagementApiSdk } from "@prisma/management-api-sdk";
4
+ //#region src/lib/auth/guard.ts
5
+ /**
6
+ * Resolve authentication and return a ManagementApiClient.
7
+ *
8
+ * Priority:
9
+ * 1. PRISMA_API_TOKEN env var → service token (CI / headless)
10
+ * 2. Stored OAuth tokens → SDK with auto-refresh
11
+ *
12
+ * Returns null if not authenticated.
13
+ */
14
+ async function requireComputeAuth(env = process.env) {
15
+ const rawToken = env[SERVICE_TOKEN_ENV_VAR];
16
+ if (rawToken !== void 0) {
17
+ const token = rawToken.trim();
18
+ if (token.length === 0) throw new Error(`${SERVICE_TOKEN_ENV_VAR} is set but empty. Provide a valid token or unset the variable.`);
19
+ return createManagementApiClient({
20
+ baseUrl: getApiBaseUrl(env),
21
+ token
22
+ });
23
+ }
24
+ const tokenStorage = new FileTokenStorage(env);
25
+ if (!await tokenStorage.getTokens()) return null;
26
+ return createManagementApiSdk({
27
+ clientId: CLIENT_ID,
28
+ redirectUri: "http://localhost:0/auth/callback",
29
+ tokenStorage,
30
+ apiBaseUrl: getApiBaseUrl(env)
31
+ }).client;
32
+ }
33
+ //#endregion
34
+ export { requireComputeAuth };
@@ -0,0 +1,117 @@
1
+ import { getApiBaseUrl } from "./client.js";
2
+ import { FileTokenStorage } from "../../adapters/token-storage.js";
3
+ import open from "open";
4
+ import { AuthError, createManagementApiSdk } from "@prisma/management-api-sdk";
5
+ import events from "node:events";
6
+ import http from "node:http";
7
+ //#region src/lib/auth/login.ts
8
+ var AuthError$1 = class extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = "AuthError";
12
+ }
13
+ };
14
+ async function login(options = {}) {
15
+ const hostname = options.hostname ?? "localhost";
16
+ const port = options.port ?? 0;
17
+ const server = http.createServer();
18
+ server.listen({
19
+ host: hostname,
20
+ port
21
+ });
22
+ try {
23
+ const state = new LoginState({
24
+ hostname,
25
+ port: (await events.once(server, "listening").then(() => server.address())).port,
26
+ tokenStorage: options.tokenStorage,
27
+ clientId: options.clientId,
28
+ apiBaseUrl: options.apiBaseUrl,
29
+ authBaseUrl: options.authBaseUrl,
30
+ openUrl: options.openUrl,
31
+ env: options.env
32
+ });
33
+ const authResult = new Promise((resolve, reject) => {
34
+ server.on("request", async (req, res) => {
35
+ const url = new URL(`http://${state.host}${req.url}`);
36
+ if (url.pathname !== "/auth/callback") {
37
+ res.statusCode = 404;
38
+ res.end("Not found");
39
+ return;
40
+ }
41
+ try {
42
+ await state.handleCallback(url);
43
+ } catch (error) {
44
+ res.statusCode = 400;
45
+ const message = error instanceof Error ? error.message : String(error);
46
+ res.end(message);
47
+ reject(error);
48
+ return;
49
+ }
50
+ res.setHeader("Content-Type", "text/html");
51
+ res.end(`<html><body style="font-family:system-ui;max-width:400px;margin:80px auto;text-align:center"><h2>✓ Signed in</h2><p>You may now close this tab and return to the terminal.</p></body></html>`);
52
+ resolve();
53
+ });
54
+ });
55
+ await state.openLoginPage();
56
+ await authResult;
57
+ } finally {
58
+ if (server.listening) await new Promise((resolve) => server.close(() => resolve()));
59
+ }
60
+ }
61
+ var LoginState = class {
62
+ latestVerifier;
63
+ latestState;
64
+ sdk;
65
+ openUrl;
66
+ constructor(options) {
67
+ this.options = options;
68
+ const tokenStorage = options.tokenStorage ?? new FileTokenStorage(options.env);
69
+ this.sdk = createManagementApiSdk({
70
+ clientId: options.clientId ?? "cmm3lndn701oo0uefvxzo0ivw",
71
+ redirectUri: `http://${options.hostname}:${options.port}/auth/callback`,
72
+ tokenStorage,
73
+ apiBaseUrl: options.apiBaseUrl ?? getApiBaseUrl(options.env),
74
+ authBaseUrl: options.authBaseUrl
75
+ });
76
+ this.openUrl = options.openUrl ?? open;
77
+ }
78
+ async openLoginPage() {
79
+ const { url, state, verifier } = await this.sdk.getLoginUrl({
80
+ scope: "workspace:admin offline_access",
81
+ additionalParams: {
82
+ utm_source: "prisma-cli",
83
+ utm_medium: "command-login",
84
+ utm_campaign: "prisma-cli"
85
+ }
86
+ });
87
+ this.latestState = state;
88
+ this.latestVerifier = verifier;
89
+ await this.openUrl(url);
90
+ }
91
+ async handleCallback(url) {
92
+ if (url.pathname !== "/auth/callback") throw new AuthError$1("Not a callback URL");
93
+ const params = url.searchParams;
94
+ const error = params.get("error");
95
+ if (error) {
96
+ const desc = params.get("error_description");
97
+ throw new AuthError$1(desc ? `${error}: ${desc}` : error);
98
+ }
99
+ if (!this.latestVerifier) throw new AuthError$1("No verifier found");
100
+ if (!this.latestState) throw new AuthError$1("No state found");
101
+ try {
102
+ await this.sdk.handleCallback({
103
+ callbackUrl: url,
104
+ verifier: this.latestVerifier,
105
+ expectedState: this.latestState
106
+ });
107
+ } catch (error) {
108
+ if (error instanceof AuthError) throw new AuthError$1(error.message);
109
+ throw new AuthError$1(error instanceof Error ? error.message : "Unknown error during login");
110
+ }
111
+ }
112
+ get host() {
113
+ return `${this.options.hostname}:${this.options.port}`;
114
+ }
115
+ };
116
+ //#endregion
117
+ export { login };
@@ -0,0 +1,93 @@
1
+ import { formatDescriptorLabel } from "../shell/command-meta.js";
2
+ import { maskValue, padDisplay, renderSummaryLine } from "../shell/ui.js";
3
+ import stringWidth from "string-width";
4
+ //#region src/output/patterns.ts
5
+ function renderList(input, ui) {
6
+ const keyWidth = Math.max(stringWidth(`${input.parentContext.key}:`), ...input.items.map((item) => stringWidth(`⚬ ${item.noun}:`)), stringWidth("Read more"));
7
+ const lines = renderCardTitle(input.descriptor, input.title, ui);
8
+ lines.push(renderCardRow(ui, keyWidth, input.parentContext.key, input.parentContext.value));
9
+ if (input.items.length === 0) lines.push(renderPlainCardLine(ui, ui.dim(input.emptyMessage)));
10
+ else for (const item of input.items) lines.push(renderCardRow(ui, keyWidth, `⚬ ${item.noun}`, formatListItemValue(ui, item)));
11
+ lines.push(renderCardDivider(ui));
12
+ lines.push(renderReadMore(ui, keyWidth, input.descriptor));
13
+ return lines;
14
+ }
15
+ function serializeList(input) {
16
+ return {
17
+ context: input.context,
18
+ items: input.items.map((item) => ({
19
+ name: item.label,
20
+ id: item.id,
21
+ status: item.status
22
+ })),
23
+ count: input.items.length
24
+ };
25
+ }
26
+ function renderShow(input, ui) {
27
+ const keyWidth = Math.max(...input.fields.map((field) => stringWidth(`${field.key}:`)), stringWidth("Read more"));
28
+ const lines = renderCardTitle(input.descriptor, input.title, ui);
29
+ for (const field of input.fields) lines.push(renderCardRow(ui, keyWidth, field.key, formatValue(ui, field.value, field.tone, field.sensitive)));
30
+ lines.push(renderCardDivider(ui));
31
+ lines.push(renderReadMore(ui, keyWidth, input.descriptor));
32
+ return lines;
33
+ }
34
+ function renderMutate(input, ui) {
35
+ const rows = [...input.context, {
36
+ key: "mode",
37
+ value: "apply",
38
+ tone: "dim"
39
+ }];
40
+ const keyWidth = Math.max(...rows.map((row) => stringWidth(`${row.key}:`)), stringWidth("Read more"));
41
+ const lines = renderCardTitle(input.descriptor, input.title, ui);
42
+ for (const row of rows) lines.push(renderCardRow(ui, keyWidth, row.key, formatValue(ui, row.value, row.tone, row.sensitive)));
43
+ lines.push(renderCardDivider(ui));
44
+ lines.push(renderReadMore(ui, keyWidth, input.descriptor));
45
+ lines.push("");
46
+ lines.push(`${ui.warning("◇")} ${input.operationDescription}...`);
47
+ lines.push(renderSummaryLine(ui, "success", `Applied ${input.operationCount} operation(s)`));
48
+ for (const detail of input.details) lines.push(` ${detail}`);
49
+ for (const alert of input.alerts ?? []) {
50
+ lines.push("");
51
+ lines.push(renderSummaryLine(ui, alert.tone, alert.text));
52
+ }
53
+ return lines;
54
+ }
55
+ function renderCardTitle(descriptor, title, ui) {
56
+ return [`${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim(title)}`, ""];
57
+ }
58
+ function renderCardRow(ui, keyWidth, key, value) {
59
+ return `${renderCardRail(ui)} ${ui.accent(padDisplay(`${key}:`, keyWidth))} ${value}`;
60
+ }
61
+ function renderPlainCardLine(ui, text) {
62
+ return `${renderCardRail(ui)} ${text}`;
63
+ }
64
+ function renderCardDivider(ui) {
65
+ return renderCardRail(ui);
66
+ }
67
+ function renderReadMore(ui, keyWidth, descriptor) {
68
+ return `${renderCardRail(ui)} ${ui.accent(padDisplay("Read more", keyWidth))} ${ui.link(descriptor.docsPath ?? "")}`;
69
+ }
70
+ function renderCardRail(ui) {
71
+ return ui.dim("│");
72
+ }
73
+ function formatListItemValue(ui, item) {
74
+ const annotation = renderAnnotation(ui, item.status);
75
+ return annotation ? `${item.label} ${annotation}` : item.label;
76
+ }
77
+ function renderAnnotation(ui, status) {
78
+ if (status === "active") return ui.success("(active)");
79
+ if (status === "linked") return ui.accent("(linked)");
80
+ if (status === "default") return ui.dim("(default)");
81
+ return "";
82
+ }
83
+ function formatValue(ui, value, tone = "default", sensitive = false) {
84
+ const resolvedValue = sensitive ? maskValue(value) : value;
85
+ if (tone === "success") return ui.success(resolvedValue);
86
+ if (tone === "warning") return ui.warning(resolvedValue);
87
+ if (tone === "error") return ui.error(resolvedValue);
88
+ if (tone === "link") return ui.link(resolvedValue);
89
+ if (tone === "dim") return ui.dim(resolvedValue);
90
+ return resolvedValue;
91
+ }
92
+ //#endregion
93
+ export { renderList, renderMutate, renderShow, serializeList };