Skip to content

feat(cli): plumb init with Tailwind detection (#33) - #128

Merged
aram-devdocs merged 1 commit into
mainfrom
feat/cli-init
Apr 25, 2026
Merged

feat(cli): plumb init with Tailwind detection (#33)#128
aram-devdocs merged 1 commit into
mainfrom
feat/cli-init

Conversation

@aram-devdocs

Copy link
Copy Markdown
Owner

Closes #33.

Summary

  • plumb init now detects Tailwind/Next.js in CWD and branches between two scaffolds. Generic dir → examples/plumb.toml verbatim; Tailwind dir → examples/plumb-tailwind.toml with the discovered tailwind.config.* path substituted into the header comment.
  • Detection is filesystem-only: looks for tailwind.config.{ts,mts,cts,js,mjs,cjs} in CWD and parses package.json for tailwindcss / next across dependencies / devDependencies / peerDependencies. The Tailwind template fires when either the config file is present or the tailwindcss dep is listed; next alone keeps the generic template.
  • Tailwind template body uses Tailwind 3.x defaults (spacing scale 0..96, type scale xs..6xl, radius scale none..3xl/full) so plumb lint plumb-fake://hello runs against the scaffolded config without further hand-tuning.
  • The extends directive isn't yet a real loader feature — it's recorded in the header comment as a future capability, matching the issue's "extends directive" wording without expanding the Config schema in this PR.

Acceptance criteria

  • Detection works on a minimal Next.js + Tailwind fixture (init_detects_tailwind_and_emits_tailwind_template).
  • Generated plumb.toml parses; plumb lint runs against the fixture (init_then_lint_runs_against_fake_driver, exit 3).
  • Fallback: generic template when Tailwind not present (init_writes_generic_config_in_clean_dir).

Test plan

  • cargo nextest run --workspace --all-features
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • cargo fmt --all --check
  • just determinism-check

Out of scope

  • Wiring merge_tailwind into plumb-cli's lint path. The adapter exists in plumb-config but no caller invokes it yet — separate ticket.
  • A real extends directive in Config (would touch plumb-core + plumb-config + schema regen).

🤖 Generated with Claude Code

`plumb init` now inspects the current directory before writing
`plumb.toml`. When a `tailwind.config.{ts,mts,cts,js,mjs,cjs}` file
exists or `package.json` lists `tailwindcss` in any dependency table,
the command emits a Tailwind-flavoured starter populated with
Tailwind 3.x default spacing, type, and radius scales. The header
records the discovered config path via a placeholder substitution so
the future `extends` directive (tracked separately) can wire to it
without further hand-tuning. Next.js without Tailwind keeps the
generic template — we hint at it in the summary line but don't
switch flavours.

Detection is filesystem-only: no JS evaluation, no env var reads.
`package.json` parse failures fall back to the generic template
silently — `plumb init` is a scaffold, not a validator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

I have enough context for a complete review.


PR #128feat(cli): plumb init with Tailwind detection

Scope: crates/plumb-cli/src/commands/init.rs, crates/plumb-cli/tests/cli_integration.rs, examples/plumb-tailwind.toml

File buckets: plumb-cli only. No layer boundaries crossed.


1. Determinism — PASS

All new code is in plumb-cli (I/O tier). detect() takes &Path as a parameter; no SystemTime::now, Instant::now, or non-deterministic sources. No HashMap/HashSet in any output path.

2. Workspace layering — PASS

No new crate dependencies. serde_json and tempfile are already present in plumb-cli/Cargo.toml. std::env::current_dir() in run() is explicitly permitted in plumb-cli by the determinism rule.

3. Error handling — PASS

run() returns Result with anyhow (allowed in plumb-cli). detect() / read_package_deps() are infallible by design; silent fallbacks on missing/malformed package.json are intentional and documented. No unwrap/expect outside #[cfg(test)].

4. Test coverage — REQUEST CHANGES

crates/plumb-cli/tests/cli_integration.rs (PR branch, lines removed around 134–151):
lint_with_viewport_flag_and_no_config_exits_input_error was deleted from the PR branch with no explanation. This test was the explicit regression guard for issue #119 — it asserts that passing --viewport mobile without a plumb.toml exits with code 2 and emits "no [viewports]". The underlying fix is still in the binary, but the guard is gone. If the viewport-no-config path regresses again, CI will not catch it.

The deletion is unrelated to the plumb init feature and looks accidental. It must be restored.

The new unit tests for detect() and render() are well-structured and cover the key paths (generic, tailwind-file, dep-only, Next.js branching, malformed JSON). Integration tests cover init E2E adequately.

5. Documentation — REQUEST CHANGES

docs/src/cli.md:30:
The plumb init entry reads:

Write a starter plumb.toml to the current directory. Pass --force to overwrite.

The Tailwind/Next.js detection behavior is entirely unmentioned. Since this PR adds user-visible detection and branching logic, the entry should describe what signals are checked and what summary line is emitted.


Minor / Non-blocking

crates/plumb-cli/src/commands/init.rs (render(), fallback path): When only has_tailwind_dep is true (no config file found), the fallback label "tailwind.config.js" is substituted into the generated TOML comment even if no such file exists. The comment would read # Tailwind config detected at ./tailwind.config.js — potentially misleading. Suggest using a generic label like tailwind.config.* in the comment text for the dep-only path, or noting that the path is a placeholder.

examples/plumb-tailwind.toml:3: The committed template file shows raw {{TAILWIND_CONFIG}} in the repo. A reader who opens the file directly before running plumb init sees an unusual-looking comment. Consider a brief note at the top of the file that this is a template processed by plumb init.


Punch list

# File Location Severity
1 crates/plumb-cli/tests/cli_integration.rs lint_with_viewport_flag_and_no_config_exits_input_error deleted in PR branch REQUEST CHANGES — restore regression guard
2 docs/src/cli.md:30 plumb init entry omits Tailwind detection behaviour REQUEST CHANGES — update docs
3 crates/plumb-cli/src/commands/init.rs (render()) Fallback label "tailwind.config.js" baked into comment when no file found Warning — not a correctness bug

Verdict: REQUEST_CHANGES

@aram-devdocs
aram-devdocs merged commit 90fdd50 into main Apr 25, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(cli): plumb init with Tailwind detection

1 participant