@prisma/cli 3.0.0-beta.17 → 3.0.0-beta.19
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/adapters/local-state.js +14 -3
- package/dist/adapters/token-storage.js +1 -1
- package/dist/cli2.js +6 -2
- package/dist/commands/agent/index.js +60 -0
- package/dist/commands/app/index.js +5 -3
- package/dist/commands/auth/index.js +1 -1
- package/dist/commands/build/index.js +29 -0
- package/dist/commands/git/index.js +1 -1
- package/dist/commands/project/index.js +1 -1
- package/dist/controllers/agent.js +228 -0
- package/dist/controllers/app.js +157 -73
- package/dist/controllers/auth.js +38 -3
- package/dist/controllers/build.js +88 -0
- package/dist/controllers/project.js +2 -2
- package/dist/controllers/select-prompt-port.js +1 -0
- package/dist/lib/agent/cli-command.js +17 -0
- package/dist/lib/agent/constants.js +12 -0
- package/dist/lib/agent/package-manager.js +99 -0
- package/dist/lib/agent/setup-status.js +83 -0
- package/dist/lib/app/app-provider.js +3 -3
- package/dist/lib/app/branch-database-deploy.js +3 -2
- package/dist/lib/app/branch-database.js +2 -1
- package/dist/lib/app/build-settings.js +1 -1
- package/dist/lib/app/build.js +2 -2
- package/dist/lib/app/bun-project.js +1 -1
- package/dist/lib/app/compute-config.js +27 -29
- package/dist/lib/app/deploy-plan.js +1 -0
- package/dist/lib/app/env-file.js +1 -1
- package/dist/lib/app/local-dev.js +1 -1
- package/dist/lib/app/production-deploy-gate.js +2 -1
- package/dist/lib/auth/login.js +1 -1
- package/dist/lib/git/local-branch.js +1 -1
- package/dist/lib/project/interactive-setup.js +1 -0
- package/dist/lib/project/local-pin.js +1 -1
- package/dist/lib/project/resolution.js +2 -2
- package/dist/lib/project/setup.js +1 -1
- package/dist/presenters/agent.js +74 -0
- package/dist/presenters/auth.js +1 -1
- package/dist/presenters/project.js +1 -1
- package/dist/shell/cli-command.js +12 -0
- package/dist/shell/command-arguments.js +7 -1
- package/dist/shell/command-meta.js +88 -0
- package/dist/shell/command-runner.js +3 -3
- package/dist/shell/help.js +6 -5
- package/dist/shell/prompt.js +7 -3
- package/dist/shell/runtime.js +2 -2
- package/dist/shell/update-check.js +2 -2
- package/package.json +4 -3
package/dist/controllers/app.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
+
import { resolvePrismaCliPackageCommand } from "../lib/agent/cli-command.js";
|
|
2
|
+
import { PRISMA_AGENT_INSTALL_ARGS, PRISMA_COMPUTE_AGENT_SKILL } from "../lib/agent/constants.js";
|
|
3
|
+
import { readPrismaAgentSetupStatus, shouldOfferPrismaAgentSetup } from "../lib/agent/setup-status.js";
|
|
4
|
+
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
5
|
+
import { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
6
|
+
import { runAgentInstall } from "./agent.js";
|
|
7
|
+
import { renderCommandHeader, renderSummaryLine } from "../shell/ui.js";
|
|
8
|
+
import { canPrompt } from "../shell/runtime.js";
|
|
9
|
+
import { writeJsonEvent } from "../shell/output.js";
|
|
1
10
|
import { SERVICE_TOKEN_ENV_VAR, getApiBaseUrl } from "../lib/auth/client.js";
|
|
2
11
|
import { FileTokenStorage } from "../adapters/token-storage.js";
|
|
3
|
-
import { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
4
12
|
import { confirmPrompt, selectPrompt, textPrompt } from "../shell/prompt.js";
|
|
5
|
-
import
|
|
13
|
+
import "../lib/app/app-interaction.js";
|
|
6
14
|
import { PRISMA_APP_CONFIG_FILENAME, detectLegacyBuildSettings, resolveConfiguredAppBuildSettings, resolveInferredAppBuildSettings } from "../lib/app/build-settings.js";
|
|
7
15
|
import { APP_BUILD_TYPES, APP_BUILD_TYPE_LABELS, RESOLVED_APP_BUILD_TYPES, executeAppBuild } from "../lib/app/build.js";
|
|
8
16
|
import { envVarNames, parseEnvInputs } from "../lib/app/env-vars.js";
|
|
9
17
|
import { DomainApiError, createAppProvider } from "../lib/app/app-provider.js";
|
|
10
|
-
import { renderCommandHeader } from "../shell/ui.js";
|
|
11
|
-
import { canPrompt } from "../shell/runtime.js";
|
|
12
18
|
import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, readLocalResolutionPin } from "../lib/project/local-pin.js";
|
|
13
|
-
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
14
19
|
import { buildProjectSetupNextActions, inferTargetName, localProjectWorkspaceMismatchError, projectNotFoundError, projectResolutionErrorToCliError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
15
20
|
import { bindProjectToDirectory, projectCreateFailedError, projectDirectoryBindingErrorToCliError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
|
|
16
21
|
import { maybeSetupBranchDatabase } from "../lib/app/branch-database-deploy.js";
|
|
@@ -27,19 +32,19 @@ import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
|
27
32
|
import { readAuthState } from "../lib/auth/auth-ops.js";
|
|
28
33
|
import { readLocalGitBranch } from "../lib/git/local-branch.js";
|
|
29
34
|
import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
|
|
30
|
-
import { writeJsonEvent } from "../shell/output.js";
|
|
31
35
|
import { createSelectPromptPort } from "./select-prompt-port.js";
|
|
32
36
|
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
33
37
|
import { listRealWorkspaceProjects } from "./project.js";
|
|
34
|
-
import { ENTRYPOINT_BUILD_TYPES, FRAMEWORKS, LOCAL_DEV_BUILD_TYPES, frameworkByKey, frameworkFromAlias, isConfigBackedBuildType } from "@prisma/compute-sdk/config";
|
|
35
|
-
import { access, readFile } from "node:fs/promises";
|
|
36
38
|
import path from "node:path";
|
|
39
|
+
import { access, readFile } from "node:fs/promises";
|
|
40
|
+
import { COMPUTE_REGIONS, ENTRYPOINT_BUILD_TYPES, FRAMEWORKS, LOCAL_DEV_BUILD_TYPES, frameworkByKey, frameworkFromAlias, isConfigBackedBuildType } from "@prisma/compute-sdk/config";
|
|
37
41
|
import { Result, matchError } from "better-result";
|
|
38
42
|
import open from "open";
|
|
39
43
|
//#region src/controllers/app.ts
|
|
40
44
|
const FRAMEWORK_DEFAULT_HTTP_PORT = 3e3;
|
|
41
45
|
const PRISMA_PROJECT_ID_ENV_VAR = "PRISMA_PROJECT_ID";
|
|
42
46
|
const PRISMA_APP_ID_ENV_VAR = "PRISMA_APP_ID";
|
|
47
|
+
const COMPUTE_REGION_IDS = new Set(COMPUTE_REGIONS);
|
|
43
48
|
function isRealMode(context) {
|
|
44
49
|
return !context.runtime.fixturePath && !context.runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
|
|
45
50
|
}
|
|
@@ -154,7 +159,7 @@ async function runAppDeploy(context, appName, options) {
|
|
|
154
159
|
return runSingleAppDeploy(context, appName, options, config);
|
|
155
160
|
}
|
|
156
161
|
async function runAppDeployAll(context, config, plannedTargets, appName, options) {
|
|
157
|
-
assertNoPerAppInputsForDeployAll(context,
|
|
162
|
+
assertNoPerAppInputsForDeployAll(context, plannedTargets, appName, options);
|
|
158
163
|
const deployments = [];
|
|
159
164
|
const warnings = [];
|
|
160
165
|
for (const planned of plannedTargets) {
|
|
@@ -172,7 +177,7 @@ async function runAppDeployAll(context, config, plannedTargets, appName, options
|
|
|
172
177
|
});
|
|
173
178
|
warnings.push(...single.warnings);
|
|
174
179
|
} catch (error) {
|
|
175
|
-
throw deployAllFailedError(error,
|
|
180
|
+
throw deployAllFailedError(error, plannedTargets, planned.index, deployments);
|
|
176
181
|
}
|
|
177
182
|
}
|
|
178
183
|
return {
|
|
@@ -182,12 +187,13 @@ async function runAppDeployAll(context, config, plannedTargets, appName, options
|
|
|
182
187
|
nextSteps: ["prisma-cli app list-deploys <app>"]
|
|
183
188
|
};
|
|
184
189
|
}
|
|
185
|
-
function assertNoPerAppInputsForDeployAll(context,
|
|
190
|
+
function assertNoPerAppInputsForDeployAll(context, plannedTargets, appName, options) {
|
|
186
191
|
const used = perAppInputsForDeployAll({
|
|
187
192
|
appName,
|
|
188
193
|
framework: options?.framework,
|
|
189
194
|
entrypoint: options?.entrypoint,
|
|
190
195
|
httpPort: options?.httpPort,
|
|
196
|
+
region: options?.region,
|
|
191
197
|
envAssignments: options?.envAssignments,
|
|
192
198
|
appIdEnvVar: {
|
|
193
199
|
name: PRISMA_APP_ID_ENV_VAR,
|
|
@@ -195,17 +201,17 @@ function assertNoPerAppInputsForDeployAll(context, config, appName, options) {
|
|
|
195
201
|
}
|
|
196
202
|
});
|
|
197
203
|
if (used.length === 0) return;
|
|
198
|
-
const
|
|
199
|
-
throw usageError(`Deploying all apps does not accept ${used.join(", ")}`, `Without a target, app deploy deploys every configured app (${
|
|
204
|
+
const targetKeys = plannedTargets.map((target) => target.targetKey);
|
|
205
|
+
throw usageError(`Deploying all apps does not accept ${used.join(", ")}`, `Without a target, app deploy deploys every configured app (${targetKeys.join(", ")}), so per-app inputs are ambiguous.`, "Pass the app target to apply per-app inputs to one app, or remove them to deploy all apps.", targetKeys.map((target) => `prisma-cli app deploy ${target}`), "app");
|
|
200
206
|
}
|
|
201
207
|
function maybeRenderDeployAllTargetHeader(context, planned) {
|
|
202
208
|
if (context.flags.json || context.flags.quiet) return;
|
|
203
209
|
context.output.stderr.write(`${planned.index > 0 ? "\n" : ""}── ${planned.targetKey} (${planned.index + 1}/${planned.total}) ──\n\n`);
|
|
204
210
|
}
|
|
205
|
-
function deployAllFailedError(error,
|
|
211
|
+
function deployAllFailedError(error, plannedTargets, failedIndex, deployments) {
|
|
206
212
|
if (!(error instanceof CliError)) return error;
|
|
207
213
|
const failure = describeDeployAllFailure({
|
|
208
|
-
targetKeys:
|
|
214
|
+
targetKeys: plannedTargets.map((target) => target.targetKey),
|
|
209
215
|
failedIndex,
|
|
210
216
|
completed: deployments.map(({ target, result }) => ({
|
|
211
217
|
target,
|
|
@@ -255,6 +261,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
255
261
|
framework: options?.framework,
|
|
256
262
|
entrypoint: options?.entrypoint,
|
|
257
263
|
httpPort: options?.httpPort,
|
|
264
|
+
region: options?.region,
|
|
258
265
|
envInputs: options?.envAssignments
|
|
259
266
|
},
|
|
260
267
|
target: computeConfig.target,
|
|
@@ -262,11 +269,13 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
262
269
|
});
|
|
263
270
|
const appDir = await resolveComputeAppDir(context, computeConfig);
|
|
264
271
|
const projectDir = computeConfig.config?.configDir ?? context.runtime.cwd;
|
|
272
|
+
const agentSetupWarnings = await maybePromptForAgentSetup(context, projectDir);
|
|
265
273
|
const localPinReadResult = Boolean(envProjectId || options?.projectRef || options?.createProjectName) ? Result.ok({ kind: "missing" }) : await readLocalResolutionPin(projectDir, context.runtime.signal);
|
|
266
274
|
if (localPinReadResult.isErr()) throw localPinReadErrorToDeployError(localPinReadResult.error);
|
|
267
275
|
const localPin = localPinReadResult.value;
|
|
268
276
|
const branch = await resolveDeployBranch(context, options?.branchName);
|
|
269
277
|
if (merged.httpPort) parseDeployHttpPort(merged.httpPort.value);
|
|
278
|
+
const deployRegion = normalizeDeployRegionInput(merged.region);
|
|
270
279
|
assertSupportedEntrypointForRequestedDeployShape({
|
|
271
280
|
requestedFramework: merged.framework?.value,
|
|
272
281
|
entrypoint: merged.entrypoint?.value
|
|
@@ -299,6 +308,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
299
308
|
explicitAppName: appName,
|
|
300
309
|
explicitAppId: envAppId,
|
|
301
310
|
configAppName: merged.configAppName,
|
|
311
|
+
configRegion: deployRegion,
|
|
302
312
|
firstDeploy: Boolean(target.localPinAction),
|
|
303
313
|
inferName: () => inferTargetName(appDir, context.runtime.signal)
|
|
304
314
|
});
|
|
@@ -328,15 +338,9 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
328
338
|
const buildType = framework.buildType;
|
|
329
339
|
assertSupportedEntrypoint(buildType, merged.entrypoint?.value, "deploy");
|
|
330
340
|
const entrypoint = await resolveDeployEntrypoint(appDir, framework, merged.entrypoint?.value, context.runtime.signal);
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
buildType,
|
|
335
|
-
configured: computeConfig.target.build,
|
|
336
|
-
configPath: computeConfig.config.configPath,
|
|
337
|
-
signal: context.runtime.signal
|
|
338
|
-
}) : await resolveInferredAppBuildSettings({
|
|
339
|
-
appPath: appDir,
|
|
341
|
+
const buildSettingsResolution = await resolveDeployBuildSettings({
|
|
342
|
+
computeConfig,
|
|
343
|
+
appDir,
|
|
340
344
|
buildType,
|
|
341
345
|
signal: context.runtime.signal
|
|
342
346
|
});
|
|
@@ -409,16 +413,36 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
409
413
|
},
|
|
410
414
|
entrypoint: entrypoint ?? buildSettingsResolution.settings.entrypoint ?? null,
|
|
411
415
|
httpPort: runtime.port,
|
|
412
|
-
region: selectedApp.region ?? null,
|
|
416
|
+
region: deployResult.app.region ?? selectedApp.region ?? null,
|
|
413
417
|
envVars: envVarNames(envVars)
|
|
414
418
|
},
|
|
415
419
|
durationMs: deployDurationMs,
|
|
416
420
|
localPin: localPinResult
|
|
417
421
|
},
|
|
418
|
-
warnings: [
|
|
422
|
+
warnings: [
|
|
423
|
+
...agentSetupWarnings,
|
|
424
|
+
...legacyWarnings,
|
|
425
|
+
...branchDatabaseSetup.warnings
|
|
426
|
+
],
|
|
419
427
|
nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${deployResult.deployment.id}`]
|
|
420
428
|
};
|
|
421
429
|
}
|
|
430
|
+
async function resolveDeployBuildSettings(options) {
|
|
431
|
+
const { computeConfig, appDir, buildType, signal } = options;
|
|
432
|
+
if (computeConfig.target?.build) assertConfigBackedBuildSettings(buildType);
|
|
433
|
+
if (computeConfig.config && computeConfig.target?.build && isConfigBackedBuildType(buildType)) return resolveConfiguredAppBuildSettings({
|
|
434
|
+
appPath: appDir,
|
|
435
|
+
buildType,
|
|
436
|
+
configured: computeConfig.target.build,
|
|
437
|
+
configPath: computeConfig.config.configPath,
|
|
438
|
+
signal
|
|
439
|
+
});
|
|
440
|
+
return resolveInferredAppBuildSettings({
|
|
441
|
+
appPath: appDir,
|
|
442
|
+
buildType,
|
|
443
|
+
signal
|
|
444
|
+
});
|
|
445
|
+
}
|
|
422
446
|
async function runAppListDeploys(context, appName, projectRef, configTarget) {
|
|
423
447
|
ensurePreviewAppMode(context);
|
|
424
448
|
const compute = await resolveComputeManagementContext(context, configTarget, "list-deploys");
|
|
@@ -1064,7 +1088,7 @@ function toAppDomainSummary(domain) {
|
|
|
1064
1088
|
type: domain.type,
|
|
1065
1089
|
url: domain.url,
|
|
1066
1090
|
hostname: domain.hostname,
|
|
1067
|
-
|
|
1091
|
+
appId: domain.appId,
|
|
1068
1092
|
status: domain.status,
|
|
1069
1093
|
foundryStatus: domain.foundryStatus,
|
|
1070
1094
|
failureReason: domain.failureReason,
|
|
@@ -1102,6 +1126,7 @@ async function confirmDomainRemoval(context, target, hostname) {
|
|
|
1102
1126
|
if (!await confirmPrompt({
|
|
1103
1127
|
input: context.runtime.stdin,
|
|
1104
1128
|
output: context.output.stderr,
|
|
1129
|
+
signal: context.runtime.signal,
|
|
1105
1130
|
message: `Detach ${hostname} from App "${target.app.name}"?`,
|
|
1106
1131
|
initialValue: false
|
|
1107
1132
|
})) throw usageError("Custom domain removal canceled", "The command was canceled before the domain was detached.", "Rerun the command and confirm removal, or pass --yes.", [`prisma-cli app domain remove ${hostname} --app ${target.app.name} --yes`], "app");
|
|
@@ -1276,27 +1301,19 @@ async function sleep(milliseconds, signal) {
|
|
|
1276
1301
|
});
|
|
1277
1302
|
}
|
|
1278
1303
|
async function resolveDeployAppSelection(context, projectId, apps, options) {
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
};
|
|
1289
|
-
return {
|
|
1290
|
-
appName: options.explicitAppName,
|
|
1291
|
-
region: DEFAULT_REGION,
|
|
1292
|
-
displayName: options.explicitAppName,
|
|
1293
|
-
annotation: "set by --app",
|
|
1294
|
-
firstDeploy: options.firstDeploy
|
|
1295
|
-
};
|
|
1296
|
-
}
|
|
1304
|
+
const newAppRegion = deployNewAppRegion(options.configRegion);
|
|
1305
|
+
if (options.explicitAppName) return resolveDeployAppByName(context, apps, {
|
|
1306
|
+
name: options.explicitAppName,
|
|
1307
|
+
matchedAnnotation: "set by --app",
|
|
1308
|
+
newAnnotation: "set by --app",
|
|
1309
|
+
requestedRegion: options.configRegion,
|
|
1310
|
+
newAppRegion,
|
|
1311
|
+
firstDeploy: options.firstDeploy
|
|
1312
|
+
});
|
|
1297
1313
|
if (options.explicitAppId) {
|
|
1298
1314
|
const matched = apps.find((app) => app.id === options.explicitAppId);
|
|
1299
1315
|
if (!matched) throw usageError("Selected app does not exist in the resolved project", `The app "${options.explicitAppId}" from ${PRISMA_APP_ID_ENV_VAR} could not be found in resolved project "${projectId}".`, `Unset ${PRISMA_APP_ID_ENV_VAR}, pass --app <name>, or choose an app from prisma-cli app list-deploys.`, ["prisma-cli app list-deploys"], "app");
|
|
1316
|
+
assertDeployRegionMatchesExistingApp(matched, options.configRegion);
|
|
1300
1317
|
return {
|
|
1301
1318
|
appId: matched.id,
|
|
1302
1319
|
displayName: matched.name,
|
|
@@ -1306,42 +1323,52 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
|
|
|
1306
1323
|
}
|
|
1307
1324
|
if (options.configAppName) {
|
|
1308
1325
|
const configName = options.configAppName;
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
annotation: configName.annotation,
|
|
1326
|
+
return resolveDeployAppByName(context, apps, {
|
|
1327
|
+
name: configName.value,
|
|
1328
|
+
matchedAnnotation: configName.annotation,
|
|
1329
|
+
newAnnotation: configName.annotation,
|
|
1330
|
+
requestedRegion: options.configRegion,
|
|
1331
|
+
newAppRegion,
|
|
1316
1332
|
firstDeploy: options.firstDeploy
|
|
1317
|
-
};
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
const inferredName = await options.inferName();
|
|
1336
|
+
const newAnnotation = inferredName.source === "package-name" ? "created from package.json" : "created from directory name";
|
|
1337
|
+
return resolveDeployAppByName(context, apps, {
|
|
1338
|
+
name: inferredName.name,
|
|
1339
|
+
matchedAnnotation: "existing app on this branch",
|
|
1340
|
+
newAnnotation,
|
|
1341
|
+
requestedRegion: options.configRegion,
|
|
1342
|
+
newAppRegion,
|
|
1343
|
+
firstDeploy: options.firstDeploy
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
async function resolveDeployAppByName(context, apps, options) {
|
|
1347
|
+
const matches = findAppsByName(apps, options.name);
|
|
1348
|
+
if (matches.length > 1) return resolveAmbiguousDeployApp(context, matches, options.name, options.requestedRegion, options.newAppRegion, options.firstDeploy);
|
|
1349
|
+
const matched = matches[0];
|
|
1350
|
+
if (matched) {
|
|
1351
|
+
assertDeployRegionMatchesExistingApp(matched, options.requestedRegion);
|
|
1318
1352
|
return {
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
annotation: configName.annotation,
|
|
1353
|
+
appId: matched.id,
|
|
1354
|
+
displayName: matched.name,
|
|
1355
|
+
annotation: options.matchedAnnotation,
|
|
1323
1356
|
firstDeploy: options.firstDeploy
|
|
1324
1357
|
};
|
|
1325
1358
|
}
|
|
1326
|
-
const inferredName = await options.inferName();
|
|
1327
|
-
const matches = findAppsByName(apps, inferredName.name);
|
|
1328
|
-
if (matches.length > 1) return resolveAmbiguousDeployApp(context, matches, inferredName.name, options.firstDeploy);
|
|
1329
|
-
const matched = matches[0];
|
|
1330
|
-
if (matched) return {
|
|
1331
|
-
appId: matched.id,
|
|
1332
|
-
displayName: matched.name,
|
|
1333
|
-
annotation: "existing app on this branch",
|
|
1334
|
-
firstDeploy: options.firstDeploy
|
|
1335
|
-
};
|
|
1336
1359
|
return {
|
|
1337
|
-
appName:
|
|
1338
|
-
region:
|
|
1339
|
-
displayName:
|
|
1340
|
-
annotation:
|
|
1360
|
+
appName: options.name,
|
|
1361
|
+
region: options.newAppRegion,
|
|
1362
|
+
displayName: options.name,
|
|
1363
|
+
annotation: options.newAnnotation,
|
|
1341
1364
|
firstDeploy: options.firstDeploy
|
|
1342
1365
|
};
|
|
1343
1366
|
}
|
|
1344
|
-
|
|
1367
|
+
function assertDeployRegionMatchesExistingApp(app, requestedRegion) {
|
|
1368
|
+
if (requestedRegion?.annotation !== "set by --region" || !app.region || app.region === requestedRegion.value) return;
|
|
1369
|
+
throw usageError("App already exists in another region", `The selected app "${app.name}" is in region "${app.region}", but --region requested "${requestedRegion.value}".`, "Remove --region to deploy the existing app, or pass --app <new-name> to create a new app in that region.", [`prisma-cli app deploy --app ${formatCommandArgument(app.name)}`, `prisma-cli app deploy --app <new-name> --region ${formatCommandArgument(requestedRegion.value)}`], "app");
|
|
1370
|
+
}
|
|
1371
|
+
async function resolveAmbiguousDeployApp(context, matches, targetName, requestedRegion, newAppRegion, firstDeploy) {
|
|
1345
1372
|
if (canPrompt(context)) {
|
|
1346
1373
|
const createNew = "__create_new_app__";
|
|
1347
1374
|
const cancel = "__cancel__";
|
|
@@ -1367,11 +1394,12 @@ async function resolveAmbiguousDeployApp(context, matches, targetName, firstDepl
|
|
|
1367
1394
|
if (selected === cancel) throw usageError("App selection canceled", "The command was canceled before an app was selected.", "Re-run the command and choose an app, or pass --app <name>.", ["prisma-cli app deploy --app <name>"], "app");
|
|
1368
1395
|
if (selected === createNew) return {
|
|
1369
1396
|
appName: targetName,
|
|
1370
|
-
region:
|
|
1397
|
+
region: newAppRegion,
|
|
1371
1398
|
displayName: targetName,
|
|
1372
1399
|
annotation: "created from package.json",
|
|
1373
1400
|
firstDeploy
|
|
1374
1401
|
};
|
|
1402
|
+
assertDeployRegionMatchesExistingApp(selected, requestedRegion);
|
|
1375
1403
|
return {
|
|
1376
1404
|
appId: selected.id,
|
|
1377
1405
|
displayName: selected.name,
|
|
@@ -1393,6 +1421,9 @@ async function resolveAmbiguousDeployApp(context, matches, targetName, firstDepl
|
|
|
1393
1421
|
nextSteps: ["prisma-cli app deploy --app <name>"]
|
|
1394
1422
|
});
|
|
1395
1423
|
}
|
|
1424
|
+
function deployNewAppRegion(configRegion) {
|
|
1425
|
+
return configRegion?.value ?? "eu-central-1";
|
|
1426
|
+
}
|
|
1396
1427
|
async function resolveExistingAppSelection(context, projectId, apps, explicitAppName) {
|
|
1397
1428
|
if (explicitAppName) {
|
|
1398
1429
|
const matched = findAppByName(apps, explicitAppName);
|
|
@@ -1435,6 +1466,7 @@ async function confirmAppRemoval(context, app) {
|
|
|
1435
1466
|
await textPrompt({
|
|
1436
1467
|
input: context.runtime.stdin,
|
|
1437
1468
|
output: context.output.stderr,
|
|
1469
|
+
signal: context.runtime.signal,
|
|
1438
1470
|
message: `Type ${app.name} to confirm app removal`,
|
|
1439
1471
|
placeholder: app.name,
|
|
1440
1472
|
validate: (value) => value === app.name ? void 0 : `Type "${app.name}" to confirm removal.`
|
|
@@ -2059,6 +2091,42 @@ function maybeRenderProjectLinked(context, directory, projectName, localPinPath)
|
|
|
2059
2091
|
if (context.flags.json || context.flags.quiet) return;
|
|
2060
2092
|
context.output.stderr.write(`${context.ui.success("✔")} Linked "${directory}" to Project "${projectName}"\nSaved ${localPinPath}\n\n`);
|
|
2061
2093
|
}
|
|
2094
|
+
async function maybePromptForAgentSetup(context, projectDir) {
|
|
2095
|
+
if (!canPrompt(context) || context.flags.yes) return [];
|
|
2096
|
+
if (!shouldOfferPrismaAgentSetup(await readPrismaAgentSetupStatus({
|
|
2097
|
+
cwd: projectDir,
|
|
2098
|
+
stateStore: context.stateStore,
|
|
2099
|
+
signal: context.runtime.signal,
|
|
2100
|
+
requiredSkill: "prisma-compute"
|
|
2101
|
+
}))) return [];
|
|
2102
|
+
if (!await confirmPrompt({
|
|
2103
|
+
input: context.runtime.stdin,
|
|
2104
|
+
output: context.runtime.stderr,
|
|
2105
|
+
signal: context.runtime.signal,
|
|
2106
|
+
message: "Install the Prisma Compute skill for this project?",
|
|
2107
|
+
initialValue: true
|
|
2108
|
+
})) {
|
|
2109
|
+
await context.stateStore.setAgentSetupPromptDismissedAt((/* @__PURE__ */ new Date()).toISOString());
|
|
2110
|
+
return [];
|
|
2111
|
+
}
|
|
2112
|
+
try {
|
|
2113
|
+
await runAgentInstall(context, { skill: [PRISMA_COMPUTE_AGENT_SKILL] }, "install", { cwd: projectDir });
|
|
2114
|
+
if (!context.flags.quiet && !context.flags.json) context.output.stderr.write(`${renderSummaryLine(context.ui, "success", "Installed the Prisma Compute skill for this project.")}\n\n`);
|
|
2115
|
+
return [];
|
|
2116
|
+
} catch (error) {
|
|
2117
|
+
const message = error instanceof Error ? error.message : "Prisma skill install failed.";
|
|
2118
|
+
if (!context.flags.quiet && !context.flags.json) context.output.stderr.write(`${renderSummaryLine(context.ui, "warning", `Skipped Prisma skill install: ${message}`)}\n\n`);
|
|
2119
|
+
return [`The Prisma Compute skill was not installed. Run ${await resolvePrismaCliPackageCommand({
|
|
2120
|
+
cwd: projectDir,
|
|
2121
|
+
signal: context.runtime.signal,
|
|
2122
|
+
args: [
|
|
2123
|
+
...PRISMA_AGENT_INSTALL_ARGS,
|
|
2124
|
+
"--skill",
|
|
2125
|
+
PRISMA_COMPUTE_AGENT_SKILL
|
|
2126
|
+
]
|
|
2127
|
+
})} to try again.`];
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2062
2130
|
async function maybeCustomizeDeploySettings(context, options) {
|
|
2063
2131
|
if (!options.firstDeploy || context.flags.yes || options.explicitFramework || options.explicitEntrypoint || options.explicitHttpPort || !canPrompt(context)) return {
|
|
2064
2132
|
framework: options.framework,
|
|
@@ -2071,6 +2139,7 @@ async function maybeCustomizeDeploySettings(context, options) {
|
|
|
2071
2139
|
if (!await confirmPrompt({
|
|
2072
2140
|
input: context.runtime.stdin,
|
|
2073
2141
|
output: context.runtime.stderr,
|
|
2142
|
+
signal: context.runtime.signal,
|
|
2074
2143
|
message: "Customize build settings?",
|
|
2075
2144
|
initialValue: false
|
|
2076
2145
|
})) return {
|
|
@@ -2080,6 +2149,7 @@ async function maybeCustomizeDeploySettings(context, options) {
|
|
|
2080
2149
|
const framework = frameworkFromUserFacingValue(await selectPrompt({
|
|
2081
2150
|
input: context.runtime.stdin,
|
|
2082
2151
|
output: context.runtime.stderr,
|
|
2152
|
+
signal: context.runtime.signal,
|
|
2083
2153
|
message: `Framework (${options.framework.displayName})`,
|
|
2084
2154
|
choices: FRAMEWORKS.map((framework) => ({
|
|
2085
2155
|
label: framework.displayName,
|
|
@@ -2089,6 +2159,7 @@ async function maybeCustomizeDeploySettings(context, options) {
|
|
|
2089
2159
|
const requestedPort = await textPrompt({
|
|
2090
2160
|
input: context.runtime.stdin,
|
|
2091
2161
|
output: context.runtime.stderr,
|
|
2162
|
+
signal: context.runtime.signal,
|
|
2092
2163
|
message: `HTTP port (${options.runtime.port})`,
|
|
2093
2164
|
placeholder: String(options.runtime.port),
|
|
2094
2165
|
validate: validateDeployHttpPortText
|
|
@@ -2198,6 +2269,19 @@ function parseDeployHttpPort(requestedPort) {
|
|
|
2198
2269
|
if (!Number.isInteger(port) || port <= 0 || port > 65535) throw usageError(`Invalid HTTP port "${requestedPort}"`, "HTTP port must be an integer between 1 and 65535.", "Pass --http-port <number> with a valid port value.", ["prisma-cli app deploy --http-port 3000"], "app");
|
|
2199
2270
|
return port;
|
|
2200
2271
|
}
|
|
2272
|
+
function parseDeployRegion(requestedRegion, source) {
|
|
2273
|
+
const region = requestedRegion.trim();
|
|
2274
|
+
if (region.length === 0) throw usageError("Invalid app region", `The app region ${source} must be a non-empty region id.`, "Pass a Prisma Compute region id.", ["prisma-cli app deploy --region eu-central-1"], "app");
|
|
2275
|
+
if (!COMPUTE_REGION_IDS.has(region)) throw usageError("Invalid app region", `The app region ${source} must be one of: ${COMPUTE_REGIONS.join(", ")}.`, "Pass a supported Prisma Compute region id.", ["prisma-cli app deploy --region eu-central-1"], "app");
|
|
2276
|
+
return region;
|
|
2277
|
+
}
|
|
2278
|
+
function normalizeDeployRegionInput(region) {
|
|
2279
|
+
if (!region) return;
|
|
2280
|
+
return {
|
|
2281
|
+
...region,
|
|
2282
|
+
value: parseDeployRegion(region.value, region.annotation)
|
|
2283
|
+
};
|
|
2284
|
+
}
|
|
2201
2285
|
function ensurePreviewAppMode(context) {
|
|
2202
2286
|
if (isRealMode(context)) return;
|
|
2203
2287
|
throw featureUnavailableError("App commands are not available in fixture mode", "Preview app commands require live app deployment integration.", "Rerun without fixture mode enabled to use preview app deployment workflows.", ["prisma-cli auth login", "prisma-cli project show"], "app");
|
package/dist/controllers/auth.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { resolvePrismaCliPackageCommand } from "../lib/agent/cli-command.js";
|
|
2
|
+
import { PRISMA_AGENT_INSTALL_ARGS } from "../lib/agent/constants.js";
|
|
3
|
+
import { isLikelyProjectDirectory, readPrismaAgentSetupStatus, resolvePrismaAgentSetupCwd, shouldOfferPrismaAgentSetup } from "../lib/agent/setup-status.js";
|
|
3
4
|
import { authRequiredError, usageError, workspaceAmbiguousError, workspaceNotAuthenticatedError, workspaceSwitchUnavailableError } from "../shell/errors.js";
|
|
4
5
|
import { canPrompt } from "../shell/runtime.js";
|
|
6
|
+
import { CLIENT_ID, SERVICE_TOKEN_ENV_VAR, getApiBaseUrl } from "../lib/auth/client.js";
|
|
7
|
+
import { FileTokenStorage, WorkspaceSelectionError } from "../adapters/token-storage.js";
|
|
5
8
|
import { performLogin, performLogout, readAuthState } from "../lib/auth/auth-ops.js";
|
|
6
9
|
import { createAuthUseCases } from "../use-cases/auth.js";
|
|
7
10
|
import { createCliUseCaseGateways } from "../use-cases/create-cli-gateways.js";
|
|
@@ -17,7 +20,16 @@ async function runAuthLogin(context, options) {
|
|
|
17
20
|
await performLogin(context.runtime.env, context.runtime.signal);
|
|
18
21
|
result = await readAuthState(context.runtime.env, context.runtime.signal);
|
|
19
22
|
} else result = await loginWithSelectionFlow(context, createAuthUseCases(createCliUseCaseGateways(context)), options);
|
|
20
|
-
|
|
23
|
+
const agentSetupTipCommand = await resolveAgentSetupTipCommand(context);
|
|
24
|
+
if (agentSetupTipCommand) result = {
|
|
25
|
+
...result,
|
|
26
|
+
agentSetupTip: { command: agentSetupTipCommand }
|
|
27
|
+
};
|
|
28
|
+
return createAuthSuccess("auth.login", result, [
|
|
29
|
+
"prisma-cli auth whoami",
|
|
30
|
+
"prisma-cli project list",
|
|
31
|
+
...result.agentSetupTip ? [result.agentSetupTip.command] : []
|
|
32
|
+
]);
|
|
21
33
|
}
|
|
22
34
|
async function runAuthLogout(context) {
|
|
23
35
|
let result;
|
|
@@ -312,5 +324,28 @@ function createAuthSuccess(command, result, nextSteps) {
|
|
|
312
324
|
nextSteps
|
|
313
325
|
};
|
|
314
326
|
}
|
|
327
|
+
async function resolveAgentSetupTipCommand(context) {
|
|
328
|
+
if (context.flags.json || context.flags.quiet) return null;
|
|
329
|
+
if (context.runtime.env.CI && context.flags.interactive !== true) return null;
|
|
330
|
+
if (!context.runtime.stderr.isTTY && context.flags.interactive !== true) return null;
|
|
331
|
+
const setupCwd = await resolvePrismaAgentSetupCwd({
|
|
332
|
+
cwd: context.runtime.cwd,
|
|
333
|
+
signal: context.runtime.signal
|
|
334
|
+
});
|
|
335
|
+
if (!await isLikelyProjectDirectory({
|
|
336
|
+
cwd: setupCwd,
|
|
337
|
+
signal: context.runtime.signal
|
|
338
|
+
})) return null;
|
|
339
|
+
if (!shouldOfferPrismaAgentSetup(await readPrismaAgentSetupStatus({
|
|
340
|
+
cwd: setupCwd,
|
|
341
|
+
stateStore: context.stateStore,
|
|
342
|
+
signal: context.runtime.signal
|
|
343
|
+
}))) return null;
|
|
344
|
+
return await resolvePrismaCliPackageCommand({
|
|
345
|
+
cwd: setupCwd,
|
|
346
|
+
signal: context.runtime.signal,
|
|
347
|
+
args: PRISMA_AGENT_INSTALL_ARGS
|
|
348
|
+
});
|
|
349
|
+
}
|
|
315
350
|
//#endregion
|
|
316
351
|
export { requireAuthenticatedAuthState, runAuthLogin, runAuthLogout, runAuthWhoAmI, runAuthWorkspaceList, runAuthWorkspaceLogout, runAuthWorkspaceUse };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { CliError, authRequiredError } from "../shell/errors.js";
|
|
2
|
+
import { writeJsonEvent } from "../shell/output.js";
|
|
3
|
+
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
4
|
+
//#region src/controllers/build.ts
|
|
5
|
+
async function runBuildLogs(context, buildId, options = {}) {
|
|
6
|
+
const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
|
|
7
|
+
if (!client) throw authRequiredError(["prisma-cli auth login"]);
|
|
8
|
+
if (!context.flags.json && !context.flags.quiet) context.output.stderr.write(`build logs → Streaming logs for build ${buildId}\n\n`);
|
|
9
|
+
const { data, response } = await client.GET("/v1/builds/{buildId}/logs", {
|
|
10
|
+
params: {
|
|
11
|
+
path: { buildId },
|
|
12
|
+
query: {
|
|
13
|
+
...options.follow ? { follow: "true" } : {},
|
|
14
|
+
...options.cursor ? { cursor: options.cursor } : {}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
parseAs: "stream",
|
|
18
|
+
signal: context.runtime.signal
|
|
19
|
+
});
|
|
20
|
+
const body = data;
|
|
21
|
+
if (!response.ok || !body) throw buildLogsRequestError(buildId, response.status);
|
|
22
|
+
let sawError = false;
|
|
23
|
+
await forEachNdjsonRecord(body, (record) => {
|
|
24
|
+
if (record.type === "terminal" && record.kind === "error") sawError = true;
|
|
25
|
+
writeBuildLogRecord(context, record);
|
|
26
|
+
});
|
|
27
|
+
if (sawError) process.exitCode = 1;
|
|
28
|
+
}
|
|
29
|
+
function writeBuildLogRecord(context, record) {
|
|
30
|
+
if (context.flags.json) {
|
|
31
|
+
writeJsonEvent(context.output, {
|
|
32
|
+
type: record.type,
|
|
33
|
+
command: "build.logs",
|
|
34
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
35
|
+
data: record
|
|
36
|
+
});
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (record.type === "log") {
|
|
40
|
+
const stream = record.source === "stderr" || record.level === "error" ? context.output.stderr : context.output.stdout;
|
|
41
|
+
stream.write(record.text);
|
|
42
|
+
if (!record.text.endsWith("\n")) stream.write("\n");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (record.code !== "end") context.output.stderr.write(`${record.message}\n`);
|
|
46
|
+
}
|
|
47
|
+
/** Reads a newline-delimited JSON body line by line, parsing each into a record. */
|
|
48
|
+
async function forEachNdjsonRecord(body, onRecord) {
|
|
49
|
+
const reader = body.getReader();
|
|
50
|
+
const decoder = new TextDecoder();
|
|
51
|
+
let buffer = "";
|
|
52
|
+
for (;;) {
|
|
53
|
+
const { done, value } = await reader.read();
|
|
54
|
+
if (value) buffer += decoder.decode(value, { stream: true });
|
|
55
|
+
let newlineIndex = buffer.indexOf("\n");
|
|
56
|
+
while (newlineIndex !== -1) {
|
|
57
|
+
const line = buffer.slice(0, newlineIndex).trim();
|
|
58
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
59
|
+
if (line) onRecord(JSON.parse(line));
|
|
60
|
+
newlineIndex = buffer.indexOf("\n");
|
|
61
|
+
}
|
|
62
|
+
if (done) {
|
|
63
|
+
const tail = buffer.trim();
|
|
64
|
+
if (tail) onRecord(JSON.parse(tail));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function buildLogsRequestError(buildId, status) {
|
|
70
|
+
if (status === 404) return new CliError({
|
|
71
|
+
code: "BUILD_NOT_FOUND",
|
|
72
|
+
domain: "app",
|
|
73
|
+
summary: `Build ${buildId} was not found`,
|
|
74
|
+
why: "The build does not exist, or your workspace does not have access to it.",
|
|
75
|
+
fix: "Check the build id, or run prisma-cli auth login to switch to the workspace that owns it.",
|
|
76
|
+
exitCode: 1
|
|
77
|
+
});
|
|
78
|
+
return new CliError({
|
|
79
|
+
code: "BUILD_LOGS_FAILED",
|
|
80
|
+
domain: "app",
|
|
81
|
+
summary: `Failed to read logs for build ${buildId}`,
|
|
82
|
+
why: `The Management API returned HTTP ${status}.`,
|
|
83
|
+
fix: "Retry the command, or rerun with --trace for more detail.",
|
|
84
|
+
exitCode: 1
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { runBuildLogs };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
1
2
|
import { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
2
|
-
import { createAppProvider } from "../lib/app/app-provider.js";
|
|
3
3
|
import { renderSummaryLine } from "../shell/ui.js";
|
|
4
4
|
import { canPrompt } from "../shell/runtime.js";
|
|
5
|
+
import { createAppProvider } from "../lib/app/app-provider.js";
|
|
5
6
|
import { readLocalResolutionPin } from "../lib/project/local-pin.js";
|
|
6
|
-
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
7
7
|
import { buildProjectSetupNextActions, inferTargetName, inspectProjectBinding, projectResolutionErrorToCliError, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
8
8
|
import { bindProjectToDirectory, isValidProjectSetupName, projectCreateFailedError, projectDirectoryBindingErrorToCliError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
|
|
9
9
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { formatPrismaCliCommand } from "../../shell/cli-command.js";
|
|
2
|
+
import { resolvePackageRunner, resolvePackageRunnerSync } from "./package-manager.js";
|
|
3
|
+
//#region src/lib/agent/cli-command.ts
|
|
4
|
+
async function resolvePrismaCliPackageCommandFormatter(options) {
|
|
5
|
+
return createPrismaCliPackageCommandFormatter(await resolvePackageRunner(options));
|
|
6
|
+
}
|
|
7
|
+
async function resolvePrismaCliPackageCommand(options) {
|
|
8
|
+
return (await resolvePrismaCliPackageCommandFormatter(options))(options.args);
|
|
9
|
+
}
|
|
10
|
+
function resolvePrismaCliPackageCommandFormatterSync(cwd) {
|
|
11
|
+
return createPrismaCliPackageCommandFormatter(resolvePackageRunnerSync(cwd));
|
|
12
|
+
}
|
|
13
|
+
function createPrismaCliPackageCommandFormatter(packageRunner) {
|
|
14
|
+
return (args) => formatPrismaCliCommand(args, { packageRunner });
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { resolvePrismaCliPackageCommand, resolvePrismaCliPackageCommandFormatterSync };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/lib/agent/constants.ts
|
|
2
|
+
const PRISMA_SKILLS_SOURCE = "prisma/skills";
|
|
3
|
+
const PRISMA_SKILLS_LOCK_FILENAME = "skills-lock.json";
|
|
4
|
+
const SKILLS_CLI_PACKAGE = "skills@latest";
|
|
5
|
+
const DEFAULT_PRISMA_AGENT_SKILLS = ["*"];
|
|
6
|
+
const PRISMA_COMPUTE_AGENT_SKILL = "prisma-compute";
|
|
7
|
+
const DEFAULT_PRISMA_AGENT_TARGETS = ["codex", "claude-code"];
|
|
8
|
+
const PRISMA_AGENT_INSTALL_ARGS = ["agent", "install"];
|
|
9
|
+
const PRISMA_AGENT_UPDATE_ARGS = ["agent", "update"];
|
|
10
|
+
const PRISMA_AGENT_STATUS_ARGS = ["agent", "status"];
|
|
11
|
+
//#endregion
|
|
12
|
+
export { DEFAULT_PRISMA_AGENT_SKILLS, DEFAULT_PRISMA_AGENT_TARGETS, PRISMA_AGENT_INSTALL_ARGS, PRISMA_AGENT_STATUS_ARGS, PRISMA_AGENT_UPDATE_ARGS, PRISMA_COMPUTE_AGENT_SKILL, PRISMA_SKILLS_LOCK_FILENAME, PRISMA_SKILLS_SOURCE, SKILLS_CLI_PACKAGE };
|