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
14 changes: 14 additions & 0 deletions packages/create/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pnpx @marko/create

## Options

- `--name`: The name of the new app (also accepted as the first positional argument).
- `--dir`: Provide a different directory to setup the project in (default to `pwd`).
- `--template`: The name of an example from [marko-js/examples](https://github.com/marko-js/examples/tree/master/examples).
- An example name
Expand All @@ -64,6 +65,19 @@ pnpx @marko/create
- ```bash
marko-create --installer pnpm
```
- `--yes` (`-y`): Skip the interactive prompts and accept the defaults.

## Non-interactive usage (CI & AI agents)

In a real terminal the prompts behave exactly as before. When there is no human
to answer them — `--yes` is passed, `CI` is set, or an AI agent is detected
(e.g. `CLAUDECODE`/`CURSOR_TRACE_ID`/`AGENT`, even with a pseudo-TTY) — the
prompts are skipped and the name defaults to `my-app` and the template to the
starter app instead of hanging. Failures exit non-zero.

```bash
npx @marko/create my-app --template basic --yes
```

# API

Expand Down
26 changes: 25 additions & 1 deletion packages/create/src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ exports.parse = function parse(argv) {
description:
"Override the package manager used to install dependencies. By default will determine from create command and fallback to npm."
},
"--yes -y": {
type: "boolean",
description:
"Skip interactive prompts and accept defaults (also implied under CI and AI agents)."
},
"--version -v": {
type: "boolean",
descrption: `print ${details.name} version`
Expand Down Expand Up @@ -81,11 +86,29 @@ exports.parse = function parse(argv) {
return options;
};

const AGENT_ENV = ["CLAUDECODE", "CURSOR_TRACE_ID", "AI_AGENT", "AGENT"];
const isAgent = () => AGENT_ENV.some(v => process.env[v]);

exports.run = async function run(options = {}) {
const acceptDefaults = options.yes || isAgent() || process.env.CI;
const canPrompt = process.stdin.isTTY && !acceptDefaults;
const spinner = ora("Starting...").start();

try {
if (!options.name || !options.template) {
if ((!options.name || !options.template) && !canPrompt) {
if (!acceptDefaults) {
throw new Error(
"An interactive terminal is required to choose a project name and template.\n" +
"Pass --name and --template, or --yes to accept the defaults."
);
}
if (!options.name) {
options.name = "my-app";
spinner.info(chalk.yellow(`No project name given; using "my-app".`));
}
}

if ((!options.name || !options.template) && canPrompt) {
spinner.stop();
const examples = !options.template && getExamples();
const trimHints = choices =>
Expand Down Expand Up @@ -168,6 +191,7 @@ exports.run = async function run(options = {}) {
} catch (err) {
spinner.fail(err.message + "\n");
console.error(err);
process.exitCode = 1;
} finally {
clearTimeout(spinner.timeout);
}
Expand Down
12 changes: 12 additions & 0 deletions packages/migrate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ npx @marko/migrate ./components/my-component.marko
- `--dry-run`: Runs the migration in memory only.
- `--safe`: Run all safe migrations ignoring any prompts.

## Non-interactive usage (CI & AI agents)

Some migrations ask for a decision via an interactive prompt. When there is no
human to answer — no TTY on `stdin`, `CI` is set, or an AI agent is detected
(e.g. `CLAUDECODE`/`CURSOR_TRACE_ID`/`AGENT`) — the automatic migrations still
run, but rather than hanging on a prompt the command exits with guidance to
re-run with `--safe` (which applies only the automatic migrations):

```bash
npx @marko/migrate ./src --safe
```

# API

## Installation
Expand Down
13 changes: 12 additions & 1 deletion packages/migrate/src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,18 @@ export function parse(argv) {
return options;
}

const AGENT_ENV = ["CLAUDECODE", "CURSOR_TRACE_ID", "AI_AGENT", "AGENT"];
const isAgent = () => AGENT_ENV.some(v => process.env[v]);

const nonInteractivePrompt = () => {
throw new Error(
"This migration needs an interactive prompt, but no interactive terminal is available.\n" +
"Re-run with `--safe` to apply only the automatic migrations, or run in an interactive terminal."
);
};

export async function run(options) {
const interactive = process.stdin.isTTY && !process.env.CI && !isAgent();
await markoMigrate({
syntax: "html",
maxLen: 80,
Expand All @@ -91,7 +102,7 @@ export async function run(options) {
ignore: ["/node_modules", ".*"],
dir: process.cwd(),
...options,
prompt,
prompt: interactive || options.safe ? prompt : nonInteractivePrompt,
onWriteFile(file, source) {
return fs.writeFile(file, source, "utf-8");
},
Expand Down
Loading