diff --git a/AGENTS.md b/AGENTS.md index 041d8e5..d9e99fe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,6 +12,17 @@ User-facing setup and installation guidance belongs in `README.md`. - `configs/` contains the files copied into the user's home directory. - `tests/` contains Vitest coverage for setup flows and generated files. +## CLI Mode Design + +`setup` and `init` are intentionally distinct public modes: + +- `setup` is interactive. It asks the user to select steps, tools, apps, and configurable presets. +- `init` is non-interactive. It passes an explicit recommended-defaults option to the shared setup engine, which selects recommended steps and content without prompting. +- Package installers used by either mode should remain non-interactive once selections have been resolved. +- `init` must not launch secondary interactive tools such as `p10k configure`. Personalization that cannot be expressed through parameters belongs in a later explicit user action. + +Do not turn `init` into an alias for `setup`. New recommended content should be controlled through setup-engine parameters and recommended-value lists, not through prompts in the `init` path. + ## Zsh Architecture Suitup generates a thin `~/.zshrc` that only orchestrates loading. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000..47dc3e3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/README.md b/README.md index 6c776e1..a818784 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ When you run suitup locally from the repo, use a zsh session. The curl installer curl -fsSL https://raw.githubusercontent.com/ChangeHow/suitup/main/install.sh | bash ``` -The installer bootstraps missing `zsh` and Node.js/npm when possible, downloads a temporary copy of the repo, runs `npm ci`, then asks whether you want `setup` or guided `init` before launching the interactive flow inside `zsh`. Package installation commands themselves run without extra confirmation prompts. On Linux, Node.js bootstrap now uses the official Node.js 20.x binary tarball so it is not tied to a specific distro repository. +The installer bootstraps missing `zsh` and Node.js/npm when possible, downloads a temporary copy of the repo, runs `npm ci`, then asks whether you want interactive `setup` or non-interactive `init`. Package installation commands themselves run without extra confirmation prompts. On Linux, Node.js bootstrap now uses the official Node.js 20.x binary tarball so it is not tied to a specific distro repository. You can also pass a command directly to skip the prompt: @@ -58,15 +58,15 @@ You can also pass a command directly to skip the prompt: curl -fsSL https://raw.githubusercontent.com/ChangeHow/suitup/main/install.sh | bash -s -- init ``` -`init` is an interactive guided initialization path. It asks which steps, tools, and apps to install; the underlying package installation commands do not ask for confirmation again: +`init` is a non-interactive initialization path. The command passes the recommended-defaults option to the setup engine, which selects the recommended steps and content without asking questions: - bootstrap package manager + zsh when needed - install the layered zsh config - install zinit + Powerlevel10k preset -- choose CLI tools and frontend tooling -- choose GUI apps on macOS +- install recommended CLI tools and frontend tooling +- install recommended GUI apps on macOS - write shared aliases -- run `p10k configure` at the end to set up your prompt theme +- leave Powerlevel10k personalization to a later manual `p10k configure` run You can also pass any other command: @@ -93,7 +93,7 @@ node src/cli.js | Command | Description | |---------|-------------| -| `node src/cli.js init` | Interactive guided initialization | +| `node src/cli.js init` | Non-interactive initialization with recommended defaults | | `node src/cli.js` | Full interactive setup (default) | | `node src/cli.js setup` | Same as above | | `node src/cli.js append` | Append configs to existing `.zshrc` | diff --git a/README.zh-CN.md b/README.zh-CN.md index ae72455..3e712a8 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -50,7 +50,7 @@ Suitup 可以帮你初始化 Zsh 和 Homebrew,但更稳妥的路径仍然是 curl -fsSL https://raw.githubusercontent.com/ChangeHow/suitup/main/install.sh | bash ``` -安装脚本会在必要时自动安装 `zsh` 和 Node.js/npm,临时下载仓库,执行 `npm ci`,然后询问你想要运行 `setup` 还是引导式 `init`,再在 `zsh` 中启动交互流程。底层软件包安装命令本身不会重复要求确认。在 Linux 上,Node.js 引导安装现在会使用官方 Node.js 20.x 二进制 tarball,不再依赖某个发行版的软件源。 +安装脚本会在必要时自动安装 `zsh` 和 Node.js/npm,临时下载仓库,执行 `npm ci`,然后询问你想要运行交互式 `setup` 还是非交互式 `init`。底层软件包安装命令本身不会重复要求确认。在 Linux 上,Node.js 引导安装现在会使用官方 Node.js 20.x 二进制 tarball,不再依赖某个发行版的软件源。 你也可以直接传入命令来跳过询问: @@ -58,15 +58,15 @@ curl -fsSL https://raw.githubusercontent.com/ChangeHow/suitup/main/install.sh | curl -fsSL https://raw.githubusercontent.com/ChangeHow/suitup/main/install.sh | bash -s -- init ``` -`init` 是交互式引导初始化路径,会询问要执行的步骤、工具和应用;底层软件包安装命令不会再次要求确认: +`init` 是非交互式初始化路径。该命令会向 setup 引擎传入“推荐默认值”参数,不经询问直接选择推荐步骤和内容: - 按需安装包管理器和 zsh - 安装分层 zsh 配置 - 安装 zinit + Powerlevel10k 预设 -- 选择 CLI 工具和前端工具链 -- 在 macOS 上选择 GUI 应用 +- 安装推荐的 CLI 工具和前端工具链 +- 在 macOS 上安装推荐的 GUI 应用 - 写入共享 aliases -- 最后运行 `p10k configure` 完成提示符主题配置 +- Powerlevel10k 个性化配置留待之后手动运行 `p10k configure` 你也可以传入其他命令: @@ -93,7 +93,7 @@ node src/cli.js | 命令 | 说明 | |------|------| -| `node src/cli.js init` | 交互式引导初始化 | +| `node src/cli.js init` | 使用推荐默认值的非交互式初始化 | | `node src/cli.js` | 完整交互式安装(默认) | | `node src/cli.js setup` | 同上 | | `node src/cli.js append` | 追加配置到已有 `.zshrc` | diff --git a/install.sh b/install.sh index f2338b2..670bdfb 100644 --- a/install.sh +++ b/install.sh @@ -272,7 +272,7 @@ elif [[ -r /dev/tty ]]; then echo '' >&2 echo 'How would you like to run suitup?' >&2 echo ' 1) setup — interactive, choose each step yourself' >&2 - echo ' 2) init — interactive guided initialization' >&2 + echo ' 2) init — non-interactive, install recommended defaults' >&2 echo '' >&2 read -r -p 'Enter 1 or 2 [default: 1]: ' _suitup_choice < /dev/tty case "${_suitup_choice}" in diff --git a/src/cli-config.js b/src/cli-config.js index 89cc8fe..6f48511 100644 --- a/src/cli-config.js +++ b/src/cli-config.js @@ -6,7 +6,7 @@ export function getHelpText(executable = "node src/cli.js") { Run suitup from a zsh session. Commands: - init Interactive guided initialization + init Non-interactive init with recommended defaults setup Full interactive environment setup (default) append Append recommended configs to existing .zshrc verify Verify installation and config integrity diff --git a/src/cli.js b/src/cli.js index ecbf2be..a568d0d 100644 --- a/src/cli.js +++ b/src/cli.js @@ -29,7 +29,7 @@ export async function main(argv = process.argv) { await runSetup(); break; case "init": - await runSetup(); + await runSetup({ defaults: true }); break; case "append": await runAppend(); diff --git a/src/setup.js b/src/setup.js index 4243ebf..4419920 100644 --- a/src/setup.js +++ b/src/setup.js @@ -3,7 +3,6 @@ import pc from "picocolors"; import { existsSync } from "node:fs"; import { homedir } from "node:os"; import { join } from "node:path"; -import { spawnSync } from "node:child_process"; import { bootstrap } from "./steps/bootstrap.js"; import { installZinit } from "./steps/plugin-manager.js"; import { CLI_TOOLS, installCliTools } from "./steps/cli-tools.js"; @@ -457,12 +456,7 @@ export async function runSetup({ defaults = false } = {}) { } if (promptTheme === "p10k" && !existsSync(join(homedir(), ".p10k.zsh"))) { - if (defaults) { - p.log.step("Launching Powerlevel10k configuration wizard..."); - spawnSync("zsh", ["-lc", "p10k configure"], { stdio: "inherit" }); - } else { - p.log.info("Powerlevel10k is selected, but `~/.p10k.zsh` was not found. Suitup keeps a basic prompt until you run `p10k configure` in zsh, which avoids dropping you into an interactive wizard during setup."); - } + p.log.info("Powerlevel10k is selected, but `~/.p10k.zsh` was not found. Suitup keeps a basic prompt until you run `p10k configure` in zsh, which avoids dropping you into an interactive wizard during setup."); } p.outro( diff --git a/tests/cli-main.test.js b/tests/cli-main.test.js index 88e13c5..fb63312 100644 --- a/tests/cli-main.test.js +++ b/tests/cli-main.test.js @@ -53,13 +53,13 @@ describe("cli main", () => { expect(runSetup).toHaveBeenCalledTimes(1); }); - test("routes init to interactive setup", async () => { + test("routes init to non-interactive recommended setup", async () => { const { main } = await import("../src/cli.js"); await main(["node", "src/cli.js", "init"]); expect(requireZshShell).toHaveBeenCalledWith(); - expect(runSetup).toHaveBeenCalledWith(); + expect(runSetup).toHaveBeenCalledWith({ defaults: true }); }); test("prints help without invoking async commands", async () => { diff --git a/tests/cli.test.js b/tests/cli.test.js index 387d500..8688dcb 100644 --- a/tests/cli.test.js +++ b/tests/cli.test.js @@ -21,7 +21,7 @@ describe("cli command resolution", () => { test("help text lists init", () => { const helpText = getHelpText(); - expect(helpText).toContain("init"); + expect(helpText).toContain("init Non-interactive init with recommended defaults"); }); test("help text lists migrate-paths", () => { diff --git a/tests/install-script.test.js b/tests/install-script.test.js index bef1eea..c798cb6 100644 --- a/tests/install-script.test.js +++ b/tests/install-script.test.js @@ -32,7 +32,7 @@ describe("install.sh", () => { expect(content).toContain("How would you like to run suitup?"); expect(content).toContain("interactive, choose each step yourself"); - expect(content).toContain("interactive guided initialization"); + expect(content).toContain("non-interactive, install recommended defaults"); }); test("passes init directly to the CLI and validates supported commands", () => {