Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/product/cli-style-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ Shared flag rules:

Shared global flags, defined by the engine in `SHARED_FLAG_PARAMETERS` (`packages/cli-engine/src/execution/shared-flags.ts`, the source of truth for this list):

- `--format <human|json>`
- `--format <human|json|markdown>`
- `--json` (shorthand for `--format json`)
- `--log-level <error|warn|info|verbose>`
- `-v`, `--verbose` (shorthand for `--log-level verbose`)
Expand Down
4 changes: 4 additions & 0 deletions docs/product/output-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,10 @@ Rules:
- human-oriented decoration should be suppressed in JSON mode
- missing values should be `null`, not placeholder strings

## `--format markdown`

`--format markdown` renders the same blocks a command describes for human output as plain Markdown: a summary line, `label: value` rows, GFM pipe tables, bullet lists, nested bullets for trees, and fenced code for drawings, followed by `### Next` for the suggested next actions and `### Diagnostics` for any findings. It exists for an agent that reads CLI output as text rather than parsing JSON: every value is labelled, nothing is padded, wrapped, aligned, or coloured, and no tokens go to envelope keys. Every part of the run's output — blocks, next actions, diagnostics, structured errors, help, `--version`, and live events — lands on stdout, and the engine writes nothing to stderr. The format is only ever explicit: without `--format markdown` a terminal gets human output and a pipe gets JSON.

## Non-Streaming JSON Shape

Commands that return one final result should emit one JSON object to stdout.
Expand Down
2 changes: 2 additions & 0 deletions packages/cli-engine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

The execution engine of the unified Prisma CLI: it owns the path from argv to exit code — parsing, execution, rendering, and error handling.

Every command describes its output once, as blocks, and the engine renders it in one of three formats chosen by `--format`: `human` for a person at a terminal (padded, aligned, coloured, on stderr, with the machine-usable data lines on stdout), `json` for a program (a stream of frames ending in a result envelope on stdout), and `markdown` for an agent that reads the output as text (plain Markdown with every value labelled, everything on stdout, nothing on stderr). A terminal gets `human` and a pipe gets `json` unless a format is named; `markdown` is only ever explicit.

## Entry points

- `@prisma/cli-engine` — the engine: command definitions, context, and the runner.
Expand Down
2 changes: 1 addition & 1 deletion packages/cli-engine/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@prisma/cli-engine",
"version": "0.3.0",
"version": "0.4.0",
"description": "The execution engine of the unified Prisma CLI.",
"type": "module",
"exports": {
Expand Down
25 changes: 23 additions & 2 deletions packages/cli-engine/src/execution/command-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,20 @@ function availableWidth(stream: OutputStream): number {
* are stderr's. `width` is a getter because the contract reads it per
* render rather than caching it. */
export function makeUi(colorEnabled: boolean, stderr: OutputStream): Ui {
return uiWith(colorEnabled, () => availableWidth(stderr));
}

/** Markdown is read as text, never on a terminal: no colour, no
* width. */
export function unboundedUi(): Ui {
return uiWith(false, () => Number.POSITIVE_INFINITY);
}

function uiWith(colorEnabled: boolean, width: () => number): Ui {
const paint = makePaint(colorEnabled);
return {
get width() {
return availableWidth(stderr);
return width();
},
emphasize: (text) => paint("emphasis", text),
dim: (text) => paint("muted", text),
Expand Down Expand Up @@ -86,6 +96,14 @@ function materializePresentation(
next: presentations.next?.() ?? [],
};
}
if (state.format === "markdown") {
return {
human: presentations.human(ui),
stdout: [],
json: undefined,
next: presentations.next?.() ?? [],
};
}
return {
human: presentations.human(ui),
stdout: presentations.stdout?.() ?? [],
Expand All @@ -108,7 +126,10 @@ export function makeContext(
capabilities: CommandCapabilities,
): CommandContext<unknown, number> {
const state = invocation.state;
const ui = makeUi(state.colorEnabled, invocation.runtime.stderr);
const ui =
state.format === "markdown"
? unboundedUi()
: makeUi(state.colorEnabled, invocation.runtime.stderr);
const present = <T>(
outcome: {
readonly data: T;
Expand Down
17 changes: 10 additions & 7 deletions packages/cli-engine/src/execution/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,16 +386,19 @@ export class EngineImpl implements Engine {
/** Help prose follows stricli's channel rule: stdout in human
* mode, stderr in json mode so stdout stays a clean frame
* stream. Never fires telemetry, like --version. */
const stream = format === "human" ? runtime.stdout : runtime.stderr;
const stream = format === "json" ? runtime.stderr : runtime.stdout;
renderHelp(
this.spec,
this.tree,
argv,
preParseColorEnabled(
argv,
runtime,
format === "human" ? "stdout" : "stderr",
),
{
format,
colorEnabled: preParseColorEnabled(
argv,
runtime,
format === "json" ? "stderr" : "stdout",
),
},
stream,
);
return 0;
Expand All @@ -405,7 +408,7 @@ export class EngineImpl implements Engine {
* exactly the frame stream, so help prose goes to stderr instead. */
stdout: {
write: (text: string) =>
(state.format === "human" ? runtime.stdout : runtime.stderr).write(
(state.format === "json" ? runtime.stderr : runtime.stdout).write(
text,
),
},
Expand Down
Loading
Loading