147 lines
5.9 KiB
Markdown
147 lines
5.9 KiB
Markdown
---
|
|
name: clack-cli-patterns
|
|
description: Use when creating or modifying OpenChamber CLI commands, prompts, terminal output, non-TTY behavior, `--quiet`, or `--json` behavior.
|
|
license: MIT
|
|
compatibility: opencode
|
|
---
|
|
|
|
## Overview
|
|
|
|
OpenChamber terminal CLI uses `@clack/prompts` for interactive UX, but command policy and validation must be mode-agnostic.
|
|
|
|
**Core principle:** policy-first, UX-second. Clack is presentation, not enforcement.
|
|
|
|
## Scope
|
|
|
|
Use this skill for terminal CLI work only (for example `packages/web/bin/*`).
|
|
|
|
Do not use this skill for web UI or VS Code webview styling work.
|
|
|
|
## Mode Contract
|
|
|
|
Run safety and correctness validation before presentation in every mode. Prompts collect missing input; they never enforce policy alone.
|
|
|
|
| Mode | Prompt | Output | Failure |
|
|
|---|---|---|---|
|
|
| Interactive TTY | Allowed when input is missing | Framed human output | Concise human error, non-zero exit |
|
|
| Fully specified flags | None required | Human output | Same policy and exit semantics |
|
|
| Non-TTY/piped | Never | Deterministic script-safe output | Non-zero without hanging |
|
|
| `--quiet` | Never | Essential result only | Concise error, non-zero exit |
|
|
| `--json` | Never | JSON only, including warnings/errors | JSON failure payload, non-zero exit |
|
|
|
|
Handle prompt cancellation with `isCancel` + `cancel(...)` and SIGINT with consistent exit semantics.
|
|
|
|
## Clack Primitive Standard
|
|
|
|
- **Flow framing:** `intro`, `outro`, `cancel`
|
|
- **Status lines:** `log.info`, `log.success`, `log.warn`, `log.error`, `log.step`
|
|
- **Guidance blocks:**
|
|
- default: `note`
|
|
- high-severity warnings only: `box`
|
|
- **Prompts:** `select`, `confirm`, `text`, `password`
|
|
- **Long-running feedback:**
|
|
- unknown duration: `spinner`
|
|
- known duration: `progress`
|
|
- multi-stage: `tasks`
|
|
|
|
## Preferred Pattern
|
|
|
|
Centralize Clack imports and formatting helpers in one adapter module (for example `cli-output.js`) so command logic stays focused on behavior and policy.
|
|
|
|
### Thin framework (recommended)
|
|
|
|
Use a small shared helper surface rather than command-specific formatting logic.
|
|
|
|
- `isJsonMode(options)`
|
|
- `isQuietMode(options)`
|
|
- `shouldRenderHumanOutput(options)`
|
|
- `canPrompt(options)`
|
|
- `createSpinner(options)`
|
|
- `createProgress(options, config)`
|
|
- `printJson(payload)`
|
|
|
|
Keep this layer minimal. Do not hide core validation or command semantics inside output helpers.
|
|
|
|
## Output Contracts by Mode
|
|
|
|
### `--quiet` contract
|
|
|
|
`--quiet` should still return essential result data.
|
|
|
|
- Read/list commands: emit concise machine-friendly lines (not framed Clack blocks).
|
|
- Action commands: emit one minimal success line and concise errors.
|
|
- Do not suppress required outcomes entirely.
|
|
|
|
Quiet output should still be complete enough for scripts and quick human scanning.
|
|
|
|
- Status-like commands should list all active items, not only `running`/`ok`.
|
|
- Prefer compact stable key tokens in quiet lines (for example `port 3000 pass:yes`).
|
|
|
|
### `--json` contract (strict)
|
|
|
|
- Output must be JSON only (no extra text before/after payload).
|
|
- Warnings/info should be represented in JSON fields (for example `status`, `messages`).
|
|
- Preserve non-zero exit codes for failures.
|
|
|
|
## Human UX Consistency
|
|
|
|
### Framing completeness
|
|
|
|
- If human flow uses `intro`, close with `outro` (or `outro('')` when you want structure without text).
|
|
- Avoid orphan frame/spinner artifacts (prefer `spinner.clear()` when a trailing spinner line is not wanted).
|
|
- If a structured summary section immediately follows a spinner, prefer `spinner.clear()` to avoid duplicate success lines.
|
|
|
|
### Progress feedback for visible operations
|
|
|
|
- For operations users wait on (start/stop/restart/tunnel lifecycle), show in-progress spinner in interactive mode.
|
|
- Resolve each spinner explicitly to done/error so users can see completion state at the same visual location.
|
|
- Keep quiet/json modes non-animated.
|
|
|
|
### Prompt flow design
|
|
|
|
- Ask required inputs in dependency order (for example hostname before token when token depends on chosen host/mode context).
|
|
- When offering save-vs-run flows, ask intent before collecting optional metadata (for example profile name only if user chooses save).
|
|
- Prefill editable values with `initialValue` (not only `placeholder`) so users can accept or edit quickly.
|
|
- Reuse latest relevant values when safe (for example last managed-local config path, last managed-remote hostname).
|
|
|
|
### Readability on narrow terminals
|
|
|
|
- Prefer short lines.
|
|
- Split long guidance into multiple detail lines.
|
|
- Use warning/info codes (`[CODE]`) when the message has follow-up docs or repeat use.
|
|
|
|
### Guidance tone
|
|
|
|
- Use `Optional Tips` for non-required next actions.
|
|
- Avoid wording that implies mandatory follow-up unless it is truly required.
|
|
|
|
### Guidance rendering style (preferred)
|
|
|
|
- Prefer structured status lines for reusable hints:
|
|
- `logStatus('info', '[CODE]', '<actionable command or short guidance>')`
|
|
- Use short, stable codes (for example `[START_PROFILE]`, `[PORT_MISMATCH]`) so users can quickly scan and recognize repeated guidance.
|
|
- Prefer this style over boxed notes for routine follow-up actions.
|
|
- Reserve `note`/boxed callouts for rare, high-context guidance where a long paragraph is truly necessary.
|
|
|
|
## Completion Criteria
|
|
|
|
Every command/subcommand must have a tested answer for:
|
|
|
|
1. default interactive TTY output
|
|
2. `--quiet` output (minimal but informative)
|
|
3. `--json` output (JSON-only)
|
|
4. non-TTY behavior (e.g. piped)
|
|
5. error path in both human and json modes
|
|
|
|
## Reusable Snippets
|
|
|
|
Load `references/snippets.md` when implementing prompt guards, non-interactive fallback, spinner lifecycle, or JSON/human output branching.
|
|
|
|
Implementation is complete when validators run before every mode branch, interactive Clack UX is only an enhancement, and all five cases above produce deterministic output and exit behavior.
|
|
|
|
## References
|
|
|
|
- This skill is the canonical CLI parity and safety policy.
|
|
- Terminal CLI precedent: `packages/web/bin/cli.js`
|
|
- Output adapter precedent: `packages/web/bin/cli-output.js`
|