@prisma/composer-cli 0.11.0 → 0.12.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.
- package/dist/bin.mjs +183 -175
- package/dist/bin.mjs.map +1 -1
- package/dist/{execute-deploy-destroy-DJ3BlpgU-DpcJjxvk.mjs → execute-deploy-destroy-Bsdh8hf4-BVXNSBmy.mjs} +4 -3
- package/dist/{execute-deploy-destroy-DJ3BlpgU-BCTSVylF.mjs.map → execute-deploy-destroy-Bsdh8hf4-BVXNSBmy.mjs.map} +1 -1
- package/dist/{execute-deploy-destroy-DJ3BlpgU-BCTSVylF.mjs → execute-deploy-destroy-Bsdh8hf4-CZVPrQtx.mjs} +4 -3
- package/dist/{execute-deploy-destroy-DJ3BlpgU-DpcJjxvk.mjs.map → execute-deploy-destroy-Bsdh8hf4-CZVPrQtx.mjs.map} +1 -1
- package/dist/{execute-dev-CQ0Lo2eN-DBThEMBv.mjs → execute-dev-CQ0Lo2eN-DxMcOjxh.mjs} +2 -2
- package/dist/{execute-dev-CQ0Lo2eN-DBThEMBv.mjs.map → execute-dev-CQ0Lo2eN-DxMcOjxh.mjs.map} +1 -1
- package/dist/{execute-dev-CQ0Lo2eN-BBNilsxZ.mjs → execute-dev-CQ0Lo2eN-WebHkuDn.mjs} +2 -2
- package/dist/{execute-dev-CQ0Lo2eN-BBNilsxZ.mjs.map → execute-dev-CQ0Lo2eN-WebHkuDn.mjs.map} +1 -1
- package/dist/{execute-log-CUzTOzSj-31WISHGD.mjs → execute-log-CUzTOzSj-BndClj6B.mjs} +2 -2
- package/dist/{execute-log-CUzTOzSj-31WISHGD.mjs.map → execute-log-CUzTOzSj-BndClj6B.mjs.map} +1 -1
- package/dist/{execute-log-CUzTOzSj-ERhhGgwJ.mjs → execute-log-CUzTOzSj-DPxnEKA2.mjs} +2 -2
- package/dist/{execute-log-CUzTOzSj-ERhhGgwJ.mjs.map → execute-log-CUzTOzSj-DPxnEKA2.mjs.map} +1 -1
- package/dist/{family-BqgXAnt0-BilZvb88.d.mts → family-BqgXAnt0-CU2L1I6j.d.mts} +50 -3
- package/dist/{family-BqgXAnt0-BilZvb88.d.mts.map → family-BqgXAnt0-CU2L1I6j.d.mts.map} +1 -1
- package/dist/family.d.mts +1 -1
- package/dist/family.mjs +182 -174
- package/dist/family.mjs.map +1 -1
- package/dist/{pipeline-Bt8QocRh-BWGl-fzK.mjs → pipeline-Bt8QocRh-BGjwJqNH.mjs} +138 -10
- package/dist/pipeline-Bt8QocRh-BGjwJqNH.mjs.map +1 -0
- package/dist/{pipeline-Bt8QocRh-DWh8gbfz.mjs → pipeline-Bt8QocRh-B_yOh-0h.mjs} +138 -10
- package/dist/pipeline-Bt8QocRh-B_yOh-0h.mjs.map +1 -0
- package/dist/testing.d.mts +1 -1
- package/package.json +6 -6
- package/dist/pipeline-Bt8QocRh-BWGl-fzK.mjs.map +0 -1
- package/dist/pipeline-Bt8QocRh-DWh8gbfz.mjs.map +0 -1
package/dist/family.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { t as alchemyCommandLine } from "./run-alchemy--ZIvgqyU-Cub4-pDf.mjs";
|
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
import { EnvironmentCredentialManager, createCli, defineCommand, defineCommandFamily, defineConfigSection, defineSessionCommand, exitWithChildStatus, flag, loadConfig, positional } from "@prisma/cli-engine";
|
|
6
6
|
import { CliStructuredError, notOk, ok } from "@prisma/cli-engine/protocol";
|
|
7
|
-
//#region ../../0-framework/3-tooling/cli/dist/log-
|
|
7
|
+
//#region ../../0-framework/3-tooling/cli/dist/log-E_5UMZl8.mjs
|
|
8
8
|
/** In-package variant threading the injection seam (the CLI's RunDeps, unit
|
|
9
9
|
* tests). Deliberately NOT re-exported through `./control` — the seam mirrors
|
|
10
10
|
* internal types and is not part of the published surface. */
|
|
@@ -12,7 +12,7 @@ async function deployWithDeps(input, deps) {
|
|
|
12
12
|
const cwd = input.cwd ?? process.cwd();
|
|
13
13
|
let executor;
|
|
14
14
|
try {
|
|
15
|
-
executor = await import("./execute-deploy-destroy-
|
|
15
|
+
executor = await import("./execute-deploy-destroy-Bsdh8hf4-CZVPrQtx.mjs");
|
|
16
16
|
} catch (error) {
|
|
17
17
|
return notOk$1(executorLoadFailure("deploy", error, cwd));
|
|
18
18
|
}
|
|
@@ -25,7 +25,7 @@ async function destroyWithDeps(input, deps) {
|
|
|
25
25
|
const cwd = input.cwd ?? process.cwd();
|
|
26
26
|
let executor;
|
|
27
27
|
try {
|
|
28
|
-
executor = await import("./execute-deploy-destroy-
|
|
28
|
+
executor = await import("./execute-deploy-destroy-Bsdh8hf4-CZVPrQtx.mjs");
|
|
29
29
|
} catch (error) {
|
|
30
30
|
return notOk$1(executorLoadFailure("destroy", error, cwd));
|
|
31
31
|
}
|
|
@@ -38,7 +38,7 @@ async function devWithDeps(input, deps) {
|
|
|
38
38
|
const cwd = input.cwd ?? process.cwd();
|
|
39
39
|
let executor;
|
|
40
40
|
try {
|
|
41
|
-
executor = await import("./execute-dev-CQ0Lo2eN-
|
|
41
|
+
executor = await import("./execute-dev-CQ0Lo2eN-DxMcOjxh.mjs");
|
|
42
42
|
} catch (error) {
|
|
43
43
|
return notOk$1(executorLoadFailure("dev", error, cwd));
|
|
44
44
|
}
|
|
@@ -51,14 +51,14 @@ async function logWithDeps(input, deps) {
|
|
|
51
51
|
const cwd = input.cwd ?? process.cwd();
|
|
52
52
|
let executor;
|
|
53
53
|
try {
|
|
54
|
-
executor = await import("./execute-log-CUzTOzSj-
|
|
54
|
+
executor = await import("./execute-log-CUzTOzSj-BndClj6B.mjs");
|
|
55
55
|
} catch (error) {
|
|
56
56
|
return notOk$1(executorLoadFailure("log", error, cwd));
|
|
57
57
|
}
|
|
58
58
|
return executor.executeLog(input, deps, cwd);
|
|
59
59
|
}
|
|
60
60
|
//#endregion
|
|
61
|
-
//#region ../../0-framework/3-tooling/cli/dist/engine-cli-
|
|
61
|
+
//#region ../../0-framework/3-tooling/cli/dist/engine-cli-BI4fPmYY.mjs
|
|
62
62
|
/**
|
|
63
63
|
* The family boundary's error translation.
|
|
64
64
|
*
|
|
@@ -266,6 +266,23 @@ const composerSection = defineConfigSection({
|
|
|
266
266
|
validate
|
|
267
267
|
});
|
|
268
268
|
/**
|
|
269
|
+
* `destroy`'s target, from its two mutually exclusive flags. Kept out of the
|
|
270
|
+
* grammar because the engine's flag layer has no "exactly one of these"
|
|
271
|
+
* construct — and because both wrong shapes need their own remedy, which a
|
|
272
|
+
* generic arity error could not give.
|
|
273
|
+
*/
|
|
274
|
+
function targetOf(stage, production) {
|
|
275
|
+
if (stage !== void 0 && production) return notOk(new CliStructuredError("DEPLOY.TARGET_CONFLICT", "Pass either --stage <name> or --production to `destroy`, not both."));
|
|
276
|
+
if (stage === void 0 && !production) return notOk(new CliStructuredError("DEPLOY.TARGET_MISSING", "`destroy` requires an explicit target.", { nextActions: [{
|
|
277
|
+
kind: "user-choice",
|
|
278
|
+
label: "Pass --stage <name> to tear down a branch environment, or --production to tear down the production environment."
|
|
279
|
+
}] }));
|
|
280
|
+
return ok(stage !== void 0 ? {
|
|
281
|
+
kind: "stage",
|
|
282
|
+
stage
|
|
283
|
+
} : { kind: "production" });
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
269
286
|
* The workspace the in-process leg acts in, from the engine's credential
|
|
270
287
|
* read. Handlers never decode a token and never read PRISMA_WORKSPACE_ID:
|
|
271
288
|
* whether the credential came from a stored session or the environment, the
|
|
@@ -280,16 +297,18 @@ async function workspaceIdOf(ctx) {
|
|
|
280
297
|
return (await ctx.activeCredential())?.workspaceId;
|
|
281
298
|
}
|
|
282
299
|
/**
|
|
283
|
-
* `
|
|
300
|
+
* `destroy <entry>` — deploy's mirror: same derivation, alchemy destroy.
|
|
284
301
|
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
302
|
+
* No confirmation prompt, matching the CLI this replaces. The front door
|
|
303
|
+
* cannot know what the child will tear down, so a consent step here would be
|
|
304
|
+
* asking the user to approve a list nobody has computed yet; if destroy
|
|
305
|
+
* deserves one it belongs in composer's own operation, not in the grammar.
|
|
288
306
|
*/
|
|
289
|
-
const
|
|
307
|
+
const createDestroyCommand = (operations) => defineCommand({
|
|
290
308
|
help: {
|
|
291
|
-
summary: "
|
|
292
|
-
|
|
309
|
+
summary: "Tear down the application whose root node is <entry>'s default export.",
|
|
310
|
+
description: "Same derivation as deploy. Requires an explicit target: --stage <name> for a branch environment, or --production for the production environment.",
|
|
311
|
+
examples: ["{bin} destroy src/service.ts --stage feat-auth", "{bin} destroy src/service.ts --production"]
|
|
293
312
|
},
|
|
294
313
|
args: {
|
|
295
314
|
positionals: { entry: positional.string({
|
|
@@ -298,21 +317,14 @@ const createDeployCommand = (operations) => defineCommand({
|
|
|
298
317
|
}) },
|
|
299
318
|
flags: {
|
|
300
319
|
name: flag.string({
|
|
301
|
-
brief: "Override the root node's name — the
|
|
320
|
+
brief: "Override the root node's name — the application name to tear down.",
|
|
302
321
|
placeholder: "name"
|
|
303
322
|
}),
|
|
304
323
|
stage: flag.string({
|
|
305
|
-
brief: "
|
|
324
|
+
brief: "Tear down this branch environment.",
|
|
306
325
|
placeholder: "stage"
|
|
307
326
|
}),
|
|
308
|
-
|
|
309
|
-
brief: "Write the deploy's outcome as JSON to this path — resources, preview URLs, and the failure cause. Also settable as PRISMA_COMPOSER_REPORT_FILE.",
|
|
310
|
-
placeholder: "path"
|
|
311
|
-
}),
|
|
312
|
-
buildId: flag.string({
|
|
313
|
-
brief: "Join the deploy record your CI already created rather than letting the target create one. Each target also reads its own environment variable for this; the flag wins.",
|
|
314
|
-
placeholder: "id"
|
|
315
|
-
})
|
|
327
|
+
production: flag.boolean({ brief: "Tear down the project-level production environment." })
|
|
316
328
|
}
|
|
317
329
|
},
|
|
318
330
|
needs: {
|
|
@@ -321,69 +333,129 @@ const createDeployCommand = (operations) => defineCommand({
|
|
|
321
333
|
},
|
|
322
334
|
maySpawn: true,
|
|
323
335
|
handler: async (args, ctx) => {
|
|
336
|
+
const target = targetOf(args.flags.stage, args.flags.production);
|
|
337
|
+
if (!target.ok) return target;
|
|
324
338
|
const alchemy = convergeSpawn(ctx);
|
|
325
|
-
return settleConverge(await operations.
|
|
339
|
+
return settleConverge(await operations.destroy({
|
|
326
340
|
entry: args.positionals.entry,
|
|
327
341
|
name: args.flags.name,
|
|
328
|
-
|
|
342
|
+
target: target.value,
|
|
329
343
|
cwd: ctx.cwd,
|
|
330
|
-
|
|
331
|
-
|
|
344
|
+
onEvent: (event) => {
|
|
345
|
+
if (event.kind !== "no-local-deploy-state") return;
|
|
346
|
+
ctx.report({
|
|
347
|
+
kind: "message",
|
|
348
|
+
severity: "warn",
|
|
349
|
+
text: `No prior deploy state under ${event.cwd} — if you deployed from a different directory, run destroy from there; otherwise this is a no-op.`
|
|
350
|
+
});
|
|
351
|
+
}
|
|
332
352
|
}, operationDeps({
|
|
333
353
|
alchemy,
|
|
334
354
|
configPath: ctx.config.configPath,
|
|
335
355
|
workspaceId: await workspaceIdOf(ctx),
|
|
336
356
|
client: ctx.api
|
|
337
|
-
})), ctx, (
|
|
338
|
-
human: (
|
|
339
|
-
kind: "summary",
|
|
340
|
-
status: "ok",
|
|
341
|
-
text: "Deployed."
|
|
342
|
-
}] : [{
|
|
357
|
+
})), ctx, () => ctx.present({ data: void 0 }, {
|
|
358
|
+
human: () => [{
|
|
343
359
|
kind: "summary",
|
|
344
360
|
status: "ok",
|
|
345
|
-
text:
|
|
346
|
-
}, {
|
|
347
|
-
kind: "table",
|
|
348
|
-
columns: ["Address", "Deployed"],
|
|
349
|
-
rows: summary.nodes.map((node) => [node.address, node.entities.map((entity) => `${entity.kind} ${entity.id}`).join(", ")])
|
|
361
|
+
text: "Destroyed."
|
|
350
362
|
}],
|
|
351
363
|
stdout: () => [],
|
|
352
|
-
json: () =>
|
|
364
|
+
json: () => void 0,
|
|
353
365
|
next: () => []
|
|
354
366
|
}));
|
|
355
367
|
}
|
|
356
368
|
});
|
|
357
369
|
/**
|
|
358
|
-
* `
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
370
|
+
* `log <entry> [address]` — a session command that tails the merged logs of
|
|
371
|
+
* the app running locally on this machine.
|
|
372
|
+
*
|
|
373
|
+
* It reads the LOCAL dev-emulator daemon, not the platform's logs surface, so
|
|
374
|
+
* it is credential-free. It hands the terminal to nothing, which is why it
|
|
375
|
+
* does not declare `maySpawn` and keeps json support: the log lines ARE its
|
|
376
|
+
* json surface.
|
|
377
|
+
*
|
|
378
|
+
* Windows is refused inside the operation itself (LOG.PLATFORM_UNSUPPORTED),
|
|
379
|
+
* which is why nothing here reads the platform.
|
|
362
380
|
*/
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
381
|
+
/** An empty screen reads as broken, so show a little recent history before going live. */
|
|
382
|
+
const DEFAULT_TAIL = 20;
|
|
383
|
+
const createLogCommand = (operations) => defineSessionCommand({
|
|
384
|
+
help: {
|
|
385
|
+
summary: "Tail the merged logs of the locally-running application whose root node is <entry>'s default export.",
|
|
386
|
+
examples: ["{bin} log src/service.ts", "{bin} log src/service.ts catalog.service"]
|
|
387
|
+
},
|
|
388
|
+
args: {
|
|
389
|
+
positionals: {
|
|
390
|
+
entry: positional.string({
|
|
391
|
+
brief: "The module whose default export is the application root.",
|
|
392
|
+
placeholder: "entry"
|
|
393
|
+
}),
|
|
394
|
+
address: positional.optionalString({
|
|
395
|
+
brief: "Only this service's lines, by its dotted address (catalog.service); every service when absent.",
|
|
396
|
+
placeholder: "address"
|
|
397
|
+
})
|
|
398
|
+
},
|
|
399
|
+
flags: {
|
|
400
|
+
name: flag.string({
|
|
401
|
+
brief: "Override the root node's name — the dev instance's application name.",
|
|
402
|
+
placeholder: "name"
|
|
403
|
+
}),
|
|
404
|
+
tail: flag.number({
|
|
405
|
+
brief: `How many trailing history lines to show before live output (default ${String(DEFAULT_TAIL)}).`,
|
|
406
|
+
placeholder: "lines",
|
|
407
|
+
default: DEFAULT_TAIL
|
|
408
|
+
})
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
needs: { config: composerSection },
|
|
412
|
+
handler: async (args, ctx) => {
|
|
413
|
+
const reportLogEvent = (event) => {
|
|
414
|
+
ctx.report({
|
|
415
|
+
kind: "message",
|
|
416
|
+
severity: "warn",
|
|
417
|
+
text: event.kind === "stream-failed" ? `Stream failed: ${event.message}` : `Falling behind — dropped the ${String(event.count)} oldest lines.`
|
|
418
|
+
});
|
|
419
|
+
};
|
|
420
|
+
const result = await operations.log({
|
|
421
|
+
entry: args.positionals.entry,
|
|
422
|
+
name: args.flags.name,
|
|
423
|
+
address: args.positionals.address,
|
|
424
|
+
tail: args.flags.tail ?? DEFAULT_TAIL,
|
|
425
|
+
cwd: ctx.cwd,
|
|
426
|
+
signal: ctx.signal,
|
|
427
|
+
onEvent: reportLogEvent
|
|
428
|
+
}, { configPath: ctx.config.configPath });
|
|
429
|
+
if (!result.ok) return notOk(toEngineError(result.failure));
|
|
430
|
+
const attached = result.value;
|
|
431
|
+
if (attached.services.length === 0) {
|
|
432
|
+
ctx.report({
|
|
433
|
+
kind: "message",
|
|
434
|
+
severity: "warn",
|
|
435
|
+
text: `No running services for "${attached.appName}" — start it first with \`dev ${args.positionals.entry}\`.`
|
|
436
|
+
});
|
|
437
|
+
return ok(void 0);
|
|
438
|
+
}
|
|
439
|
+
for await (const { service, line } of attached.lines) ctx.report({
|
|
440
|
+
kind: "output",
|
|
441
|
+
source: service,
|
|
442
|
+
channel: "data",
|
|
443
|
+
line: `[${service}] ${line}`
|
|
444
|
+
});
|
|
445
|
+
return ok(void 0);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
374
448
|
/**
|
|
375
|
-
* `
|
|
449
|
+
* `deploy <entry>` — a result command that hands the terminal to alchemy.
|
|
376
450
|
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
* deserves one it belongs in composer's own operation, not in the grammar.
|
|
451
|
+
* `--production` is gone. It was accepted and then always errored ("only
|
|
452
|
+
* valid with destroy"), so no invocation using it could ever have succeeded;
|
|
453
|
+
* deploy targets production by default when no `--stage` is given.
|
|
381
454
|
*/
|
|
382
|
-
const
|
|
455
|
+
const createDeployCommand = (operations) => defineCommand({
|
|
383
456
|
help: {
|
|
384
|
-
summary: "
|
|
385
|
-
|
|
386
|
-
examples: ["{bin} destroy src/service.ts --stage feat-auth", "{bin} destroy src/service.ts --production"]
|
|
457
|
+
summary: "Deploy the application whose root node is <entry>'s default export.",
|
|
458
|
+
examples: ["{bin} deploy src/service.ts", "{bin} deploy src/service.ts --stage feat-auth"]
|
|
387
459
|
},
|
|
388
460
|
args: {
|
|
389
461
|
positionals: { entry: positional.string({
|
|
@@ -392,14 +464,21 @@ const createDestroyCommand = (operations) => defineCommand({
|
|
|
392
464
|
}) },
|
|
393
465
|
flags: {
|
|
394
466
|
name: flag.string({
|
|
395
|
-
brief: "Override the root node's name — the application name
|
|
467
|
+
brief: "Override the root node's name — the deploy's application name.",
|
|
396
468
|
placeholder: "name"
|
|
397
469
|
}),
|
|
398
470
|
stage: flag.string({
|
|
399
|
-
brief: "
|
|
471
|
+
brief: "Deploy scope to target; omit for production.",
|
|
400
472
|
placeholder: "stage"
|
|
401
473
|
}),
|
|
402
|
-
|
|
474
|
+
report: flag.string({
|
|
475
|
+
brief: "Write the deploy's outcome as JSON to this path — resources, preview URLs, and the failure cause. Also settable as PRISMA_COMPOSER_REPORT_FILE.",
|
|
476
|
+
placeholder: "path"
|
|
477
|
+
}),
|
|
478
|
+
buildId: flag.string({
|
|
479
|
+
brief: "Join the deploy record your CI already created rather than letting the target create one. Each target also reads its own environment variable for this; the flag wins.",
|
|
480
|
+
placeholder: "id"
|
|
481
|
+
})
|
|
403
482
|
}
|
|
404
483
|
},
|
|
405
484
|
needs: {
|
|
@@ -408,35 +487,35 @@ const createDestroyCommand = (operations) => defineCommand({
|
|
|
408
487
|
},
|
|
409
488
|
maySpawn: true,
|
|
410
489
|
handler: async (args, ctx) => {
|
|
411
|
-
const target = targetOf(args.flags.stage, args.flags.production);
|
|
412
|
-
if (!target.ok) return target;
|
|
413
490
|
const alchemy = convergeSpawn(ctx);
|
|
414
|
-
return settleConverge(await operations.
|
|
491
|
+
return settleConverge(await operations.deploy({
|
|
415
492
|
entry: args.positionals.entry,
|
|
416
493
|
name: args.flags.name,
|
|
417
|
-
|
|
494
|
+
stage: args.flags.stage,
|
|
418
495
|
cwd: ctx.cwd,
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
ctx.report({
|
|
422
|
-
kind: "message",
|
|
423
|
-
severity: "warn",
|
|
424
|
-
text: `No prior deploy state under ${event.cwd} — if you deployed from a different directory, run destroy from there; otherwise this is a no-op.`
|
|
425
|
-
});
|
|
426
|
-
}
|
|
496
|
+
reportPath: args.flags.report,
|
|
497
|
+
reportId: args.flags.buildId
|
|
427
498
|
}, operationDeps({
|
|
428
499
|
alchemy,
|
|
429
500
|
configPath: ctx.config.configPath,
|
|
430
501
|
workspaceId: await workspaceIdOf(ctx),
|
|
431
502
|
client: ctx.api
|
|
432
|
-
})), ctx, () => ctx.present({ data:
|
|
433
|
-
human: () => [{
|
|
503
|
+
})), ctx, ({ summary }) => ctx.present({ data: { summary: summary ?? null } }, {
|
|
504
|
+
human: (ui) => summary === void 0 ? [{
|
|
434
505
|
kind: "summary",
|
|
435
506
|
status: "ok",
|
|
436
|
-
text: "
|
|
507
|
+
text: "Deployed."
|
|
508
|
+
}] : [{
|
|
509
|
+
kind: "summary",
|
|
510
|
+
status: "ok",
|
|
511
|
+
text: `Deployed ${ui.emphasize(summary.app)}.`
|
|
512
|
+
}, {
|
|
513
|
+
kind: "table",
|
|
514
|
+
columns: ["Address", "Deployed"],
|
|
515
|
+
rows: summary.nodes.map((node) => [node.address, node.entities.map((entity) => `${entity.kind} ${entity.id}`).join(", ")])
|
|
437
516
|
}],
|
|
438
517
|
stdout: () => [],
|
|
439
|
-
json: () =>
|
|
518
|
+
json: () => ({ summary: summary ?? null }),
|
|
440
519
|
next: () => []
|
|
441
520
|
}));
|
|
442
521
|
}
|
|
@@ -578,7 +657,7 @@ Generated stack file: ${event.stackFilePath}\nRun \`${event.reproduceCommand}\`
|
|
|
578
657
|
const createDevCommand = (operations) => defineSessionCommand({
|
|
579
658
|
help: {
|
|
580
659
|
summary: "Bring up the application whose root node is <entry>'s default export, entirely on this machine.",
|
|
581
|
-
description: "Runs credential-free and watches the app for changes, reconverging on every edit.
|
|
660
|
+
description: "Runs credential-free and watches the app for changes, reconverging on every edit.",
|
|
582
661
|
examples: ["{bin} dev src/service.ts", "{bin} dev src/service.ts --fresh"]
|
|
583
662
|
},
|
|
584
663
|
args: {
|
|
@@ -615,85 +694,6 @@ const createDevCommand = (operations) => defineSessionCommand({
|
|
|
615
694
|
}
|
|
616
695
|
});
|
|
617
696
|
/**
|
|
618
|
-
* `log <entry> [address]` — a session command that tails the merged logs of
|
|
619
|
-
* the app running locally on this machine.
|
|
620
|
-
*
|
|
621
|
-
* It reads the LOCAL dev-emulator daemon, not the platform's logs surface, so
|
|
622
|
-
* it is credential-free. It hands the terminal to nothing, which is why it
|
|
623
|
-
* does not declare `maySpawn` and keeps json support: the log lines ARE its
|
|
624
|
-
* json surface.
|
|
625
|
-
*
|
|
626
|
-
* Windows is refused inside the operation itself (LOG.PLATFORM_UNSUPPORTED),
|
|
627
|
-
* which is why nothing here reads the platform.
|
|
628
|
-
*/
|
|
629
|
-
/** An empty screen reads as broken, so show a little recent history before going live. */
|
|
630
|
-
const DEFAULT_TAIL = 20;
|
|
631
|
-
const createLogCommand = (operations) => defineSessionCommand({
|
|
632
|
-
help: {
|
|
633
|
-
summary: "Tail the merged logs of the locally-running application whose root node is <entry>'s default export.",
|
|
634
|
-
examples: ["{bin} log src/service.ts", "{bin} log src/service.ts catalog.service"]
|
|
635
|
-
},
|
|
636
|
-
args: {
|
|
637
|
-
positionals: {
|
|
638
|
-
entry: positional.string({
|
|
639
|
-
brief: "The module whose default export is the application root.",
|
|
640
|
-
placeholder: "entry"
|
|
641
|
-
}),
|
|
642
|
-
address: positional.optionalString({
|
|
643
|
-
brief: "Only this service's lines, by its dotted address (catalog.service); every service when absent.",
|
|
644
|
-
placeholder: "address"
|
|
645
|
-
})
|
|
646
|
-
},
|
|
647
|
-
flags: {
|
|
648
|
-
name: flag.string({
|
|
649
|
-
brief: "Override the root node's name — the dev instance's application name.",
|
|
650
|
-
placeholder: "name"
|
|
651
|
-
}),
|
|
652
|
-
tail: flag.number({
|
|
653
|
-
brief: `How many trailing history lines to show before live output (default ${String(DEFAULT_TAIL)}).`,
|
|
654
|
-
placeholder: "lines",
|
|
655
|
-
default: DEFAULT_TAIL
|
|
656
|
-
})
|
|
657
|
-
}
|
|
658
|
-
},
|
|
659
|
-
needs: { config: composerSection },
|
|
660
|
-
handler: async (args, ctx) => {
|
|
661
|
-
const reportLogEvent = (event) => {
|
|
662
|
-
ctx.report({
|
|
663
|
-
kind: "message",
|
|
664
|
-
severity: "warn",
|
|
665
|
-
text: event.kind === "stream-failed" ? `Stream failed: ${event.message}` : `Falling behind — dropped the ${String(event.count)} oldest lines.`
|
|
666
|
-
});
|
|
667
|
-
};
|
|
668
|
-
const result = await operations.log({
|
|
669
|
-
entry: args.positionals.entry,
|
|
670
|
-
name: args.flags.name,
|
|
671
|
-
address: args.positionals.address,
|
|
672
|
-
tail: args.flags.tail ?? DEFAULT_TAIL,
|
|
673
|
-
cwd: ctx.cwd,
|
|
674
|
-
signal: ctx.signal,
|
|
675
|
-
onEvent: reportLogEvent
|
|
676
|
-
}, { configPath: ctx.config.configPath });
|
|
677
|
-
if (!result.ok) return notOk(toEngineError(result.failure));
|
|
678
|
-
const attached = result.value;
|
|
679
|
-
if (attached.services.length === 0) {
|
|
680
|
-
ctx.report({
|
|
681
|
-
kind: "message",
|
|
682
|
-
severity: "warn",
|
|
683
|
-
text: `No running services for "${attached.appName}" — start it first with \`dev ${args.positionals.entry}\`.`
|
|
684
|
-
});
|
|
685
|
-
return ok(void 0);
|
|
686
|
-
}
|
|
687
|
-
for await (const { service, line } of attached.lines) ctx.report({
|
|
688
|
-
kind: "output",
|
|
689
|
-
source: service,
|
|
690
|
-
channel: "data",
|
|
691
|
-
line: `[${service}] ${line}`
|
|
692
|
-
});
|
|
693
|
-
return ok(void 0);
|
|
694
|
-
}
|
|
695
|
-
});
|
|
696
|
-
/**
|
|
697
697
|
* Composer's `CommandFamily` — the unit the engine mounts, whether the process
|
|
698
698
|
* is composer's own CLI or the `prisma` bin.
|
|
699
699
|
*
|
|
@@ -708,9 +708,14 @@ const createLogCommand = (operations) => defineSessionCommand({
|
|
|
708
708
|
* scripts/check-family-static-graph.mjs enforces this against BUILT output,
|
|
709
709
|
* where type-only imports have already been erased.
|
|
710
710
|
*
|
|
711
|
-
* The
|
|
711
|
+
* The commands close over the operations they are given, so a host can
|
|
712
712
|
* mount this family against the test double and exercise real grammar, real
|
|
713
713
|
* arg validation and real handlers with no alchemy behind them.
|
|
714
|
+
*
|
|
715
|
+
* The family ships `deploy` and `dev` only: `destroy` and `log` were retired
|
|
716
|
+
* from the family surface (2026-08-21 PM review), so hosts mounting the family
|
|
717
|
+
* — the `prisma` bin — never see them. They remain first-class commands of
|
|
718
|
+
* composer's own bin, mounted on top of the family in engine-cli.ts.
|
|
714
719
|
*/
|
|
715
720
|
const realOperations = {
|
|
716
721
|
deploy: deployWithDeps,
|
|
@@ -724,9 +729,7 @@ function createComposerFamily(options = {}) {
|
|
|
724
729
|
configSection: composerSection,
|
|
725
730
|
commands: {
|
|
726
731
|
deploy: createDeployCommand(operations),
|
|
727
|
-
|
|
728
|
-
dev: createDevCommand(operations),
|
|
729
|
-
log: createLogCommand(operations)
|
|
732
|
+
dev: createDevCommand(operations)
|
|
730
733
|
},
|
|
731
734
|
docsBaseUrl: DOCS_BASE
|
|
732
735
|
});
|
|
@@ -895,22 +898,27 @@ function createRuntime(host, loadConfig) {
|
|
|
895
898
|
const BINARY_NAME = "prisma-composer";
|
|
896
899
|
/**
|
|
897
900
|
* Composer's commands mount at the top level of its own CLI (`prisma-composer
|
|
898
|
-
* deploy`)
|
|
899
|
-
*
|
|
900
|
-
*
|
|
901
|
-
*
|
|
901
|
+
* deploy`). The bin mounts more than the family carries: `destroy` and `log`
|
|
902
|
+
* were retired from the family (the surface the `prisma` bin mounts, per the
|
|
903
|
+
* 2026-08-21 PM review) but stay first-class commands of `prisma-composer`
|
|
904
|
+
* itself, so their definitions are mounted here on top of the family.
|
|
902
905
|
*/
|
|
903
|
-
function mountedTree(family) {
|
|
904
|
-
return {
|
|
906
|
+
function mountedTree(family, operations) {
|
|
907
|
+
return {
|
|
908
|
+
...family.commands,
|
|
909
|
+
destroy: createDestroyCommand(operations),
|
|
910
|
+
log: createLogCommand(operations)
|
|
911
|
+
};
|
|
905
912
|
}
|
|
906
913
|
function createComposerCli(spec) {
|
|
907
|
-
const
|
|
914
|
+
const operations = spec.operations ?? realOperations;
|
|
915
|
+
const family = createComposerFamily({ operations });
|
|
908
916
|
return createCli({
|
|
909
917
|
name: BINARY_NAME,
|
|
910
918
|
version: spec.version,
|
|
911
919
|
commandFamilies: [family],
|
|
912
920
|
groups: {},
|
|
913
|
-
commands: mountedTree(family)
|
|
921
|
+
commands: mountedTree(family, operations)
|
|
914
922
|
});
|
|
915
923
|
}
|
|
916
924
|
/**
|