diff --git a/changelog.d/3378-packages-add-verb.fixed.md b/changelog.d/3378-packages-add-verb.fixed.md new file mode 100644 index 0000000000..2468a0cee7 --- /dev/null +++ b/changelog.d/3378-packages-add-verb.fixed.md @@ -0,0 +1 @@ +- Docs, `--help`, and the packages website now agree that the install verb is `wheels packages add` — `wheels packages install` is intercepted by LuCLI before the Wheels module runs and does not install anything. The Basecoat bonus chapter also says to copy the showcase from `vendor/` after `add`, not from the raw GitHub tree (#3378) diff --git a/cli/lucli/Module.cfc b/cli/lucli/Module.cfc index cf822aa32f..137bab4e1b 100644 --- a/cli/lucli/Module.cfc +++ b/cli/lucli/Module.cfc @@ -2615,7 +2615,7 @@ component extends="modules.BaseModule" { // ───────────────────────────────────────────────── /** - * hint: Install, update, and list Wheels packages — use `add` (not `install`) to install + * hint: Add, update, and list Wheels packages (verb is `add`, not `install`) * * The verb is `add`, NOT `install`. Typing `wheels packages install ` * is intercepted by LuCLI's built-in extension installer before dispatch @@ -2716,7 +2716,7 @@ component extends="modules.BaseModule" { var regCli = new modules.wheels.services.packages.PackagesRegistryCli(); return invoke(regCli, regVerb, [opts]); default: - throw(message="Unknown packages subcommand: #sub#"); + throw(message="Unknown packages subcommand: #sub#. The install verb is `add` (not `install`): wheels packages add "); } } diff --git a/vendor/wheels/tests/specs/cli/PackagesCommandHelpSpec.cfc b/vendor/wheels/tests/specs/cli/PackagesCommandHelpSpec.cfc index 5ba2ccbb6b..05cdf17c01 100644 --- a/vendor/wheels/tests/specs/cli/PackagesCommandHelpSpec.cfc +++ b/vendor/wheels/tests/specs/cli/PackagesCommandHelpSpec.cfc @@ -63,6 +63,34 @@ component extends="wheels.WheelsTest" { } }); + it("packages() hint metadata leads with `Add`, not the intercepted `Install` verb", () => { + var source = fileRead(ctx.modulePath); + + // LuCLI surfaces the `hint:` javadoc on the packages() function + // in auto-introspected help. Leading with "Install" nudges + // users toward `wheels packages install`, which never reaches + // this module. + expect(source contains "hint: Install, update, and list Wheels packages").toBeFalse( + "packages() hint still leads with `Install`. Lead with `Add` " + & "(the canonical verb) so auto-introspected help matches showHelp()." + ); + expect(source contains "hint: Add, update, and list Wheels packages").toBeTrue( + "packages() hint should lead with `Add, update, and list ...` " + & "and mention that the verb is `add`, not `install`." + ); + }); + + it("unknown-subcommand error points users at `wheels packages add`", () => { + var source = fileRead(ctx.modulePath); + + expect(source contains "Unknown packages subcommand").toBeTrue( + "Expected the packages() default branch to throw an unknown-subcommand error." + ); + expect(source contains "The install verb is `add` (not `install`): wheels packages add ").toBeTrue( + "The unknown-subcommand error should tell users the install verb is `add`." + ); + }); + }); } diff --git a/vendor/wheels/tests/specs/packages/PackagesAddVerbAdvertisingSpec.cfc b/vendor/wheels/tests/specs/packages/PackagesAddVerbAdvertisingSpec.cfc new file mode 100644 index 0000000000..18ad605fd8 --- /dev/null +++ b/vendor/wheels/tests/specs/packages/PackagesAddVerbAdvertisingSpec.cfc @@ -0,0 +1,65 @@ +/** + * User-facing surfaces must advertise `wheels packages add`, not + * `wheels packages install`. LuCLI intercepts the literal `install` + * subcommand before Module.cfc runs (#2610, #2706, #3378). + * + * Mentions of `install` that explicitly say it is not the verb are fine; + * copy-to-clipboard snippets and recommended commands are not. + */ +component extends="wheels.WheelsTest" { + + function run() { + + var ctx = {repoRoot: expandPath("/wheels/../..")}; + + describe("User-facing surfaces advertise `packages add`", () => { + + it("the in-app packages page copies `wheels packages add`", () => { + var path = expandPath("/wheels/public/views/packagelist.cfm"); + expect(fileExists(path)).toBeTrue("Missing file: " & path); + var source = fileRead(path); + + expect(source contains "wheels packages add ").toBeTrue( + "packagelist.cfm copy snippet must use `wheels packages add`." + ); + expect(source contains "wheels packages install ").toBeFalse( + "packagelist.cfm must not put `wheels packages install` in a copy snippet. " + & "LuCLI intercepts that verb before Module.cfc." + ); + }); + + it("the packages website copy snippets use `add`, not `install`", () => { + var files = [ + ctx.repoRoot & "/web/sites/packages/src/pages/index.astro", + ctx.repoRoot & "/web/sites/packages/src/pages/[name].astro", + ctx.repoRoot & "/web/sites/packages/src/components/PackageCard.astro" + ]; + var i = 0; + var n = arrayLen(files); + for (i = 1; i <= n; i++) { + expect(fileExists(files[i])).toBeTrue("Missing file: " & files[i]); + var source = fileRead(files[i]); + + // Copy-to-clipboard / recommended command shapes. + expect(find("wheels packages install {", source) > 0).toBeFalse( + files[i] & " still has a copy snippet `wheels packages install {name}`. Use `add`." + ); + expect(find("wheels packages install <name>", source) > 0).toBeFalse( + files[i] & " still recommends `wheels packages install `. Use `add`." + ); + } + }); + + it("the packages website index recommends `wheels packages add`", () => { + var path = ctx.repoRoot & "/web/sites/packages/src/pages/index.astro"; + var source = fileRead(path); + expect(source contains "wheels packages add <name>").toBeTrue( + "packages site index should recommend `wheels packages add `." + ); + }); + + }); + + } + +} diff --git a/web/sites/guides/astro.config.mjs b/web/sites/guides/astro.config.mjs index 3a0d28d8f8..a6971a8ddc 100644 --- a/web/sites/guides/astro.config.mjs +++ b/web/sites/guides/astro.config.mjs @@ -122,6 +122,12 @@ export default defineConfig({ '/v4-0-0/digging-deeper/security/https-detection': '/v4-0-0/deployment/security-hardening/', '/v4-0-0/configuration': '/v4-0-0/core-concepts/environments-and-configuration/', '/v4-0-0/troubleshooting/cross-engine-compatibility': '/v4-0-0/contributing/coding-standards/', + // The `packages add` reference lived at .../packages/install/ while the + // page title already said `add`. The old slug advertised the broken + // LuCLI-intercepted verb. Keep the old URL working. One source only — + // listing both `/install` and `/install/` made Astro warn that the + // route was defined twice. + '/v4-0-0/command-line-tools/commands/packages/install': '/v4-0-0/command-line-tools/commands/packages/add/', }, integrations: [ starlight({ diff --git a/web/sites/guides/src/content/docs/v4-0-0/command-line-tools/commands/packages/install.mdx b/web/sites/guides/src/content/docs/v4-0-0/command-line-tools/commands/packages/add.mdx similarity index 100% rename from web/sites/guides/src/content/docs/v4-0-0/command-line-tools/commands/packages/install.mdx rename to web/sites/guides/src/content/docs/v4-0-0/command-line-tools/commands/packages/add.mdx diff --git a/web/sites/guides/src/content/docs/v4-0-0/command-line-tools/commands/packages/index.mdx b/web/sites/guides/src/content/docs/v4-0-0/command-line-tools/commands/packages/index.mdx index 873c314518..4017cbac08 100644 --- a/web/sites/guides/src/content/docs/v4-0-0/command-line-tools/commands/packages/index.mdx +++ b/web/sites/guides/src/content/docs/v4-0-0/command-line-tools/commands/packages/index.mdx @@ -8,6 +8,8 @@ sidebar: `wheels packages` is the CLI surface for the [wheels-packages registry](https://github.com/wheels-dev/wheels-packages) — a curated, git-based distribution channel for Wheels ecosystem packages. Every verb talks to the registry over plain HTTPS and installs into `vendor//`, where `PackageLoader` picks it up on next reload. +The install verb is [`add`](./add). `wheels packages install ` never reaches this command — LuCLI's built-in extension installer intercepts the literal `install` subcommand and prints `No git or extension dependencies to install` without touching `vendor/`. + There is no ForgeBox and no CommandBox. The registry manifest is authoritative, tarballs live on the registry's GitHub Releases, and every tarball has a sha256 in the manifest that the installer verifies before extraction. Supply-chain attacks via force-pushed tags or drifted source archives are defeated by this design. ## Synopsis @@ -31,7 +33,7 @@ wheels packages registry info | [`list`](./list) | Show every package in the registry, optionally filtered by `--tag`. | | [`search`](./search) | Substring match against name, description, and tags. | | [`show`](./show) | Detail page for a package: versions, homepage, license, install state. | -| [`add`](./install) | Download, verify, extract into `vendor//`. | +| [`add`](./add) | Download, verify, extract into `vendor//`. | | [`update`](./update) | Re-install the latest compatible version. Explicit: requires `--yes`. | | [`remove`](./remove) | Delete `vendor//`. Refuses dirs without a `package.json`. | | [`registry refresh`](./registry/refresh) | Bust the 24h cache. | diff --git a/web/sites/guides/src/content/docs/v4-0-0/digging-deeper/packages.mdx b/web/sites/guides/src/content/docs/v4-0-0/digging-deeper/packages.mdx index 7914825cbf..a497a22b6f 100644 --- a/web/sites/guides/src/content/docs/v4-0-0/digging-deeper/packages.mdx +++ b/web/sites/guides/src/content/docs/v4-0-0/digging-deeper/packages.mdx @@ -64,7 +64,7 @@ The reload re-runs `PackageLoader`, which rediscovers what's in `vendor/` and re Six packages are maintained as first-party modules under the `wheels-dev` GitHub org. All are optional; the framework core runs fine with none of them installed. - **[`wheels-hotwire`](https://github.com/wheels-dev/wheels-hotwire)** — Turbo Drive, Turbo Frames, Turbo Streams, and Stimulus integration for server-rendered UI. Mixes into controllers (and therefore views). Used heavily in the tutorial app. -- **[`wheels-basecoat`](https://github.com/wheels-dev/wheels-basecoat)** — UI component helpers styled with Tailwind CSS. shadcn/ui-quality forms, buttons, and cards without React. Mixes into controllers. +- **[`wheels-basecoat`](https://github.com/wheels-dev/wheels-basecoat)** — UI component helpers styled with Tailwind CSS. shadcn/ui-quality forms, buttons, and cards without React. Mixes into controllers. Add it with `wheels packages add wheels-basecoat` (the verb is `add`, not `install`), then copy CSS and the optional showcase from `vendor/wheels-basecoat/` — not from the raw GitHub tree. The [bonus tutorial chapter](/v4-0-0/start-here/tutorial/08-bonus-basecoat/) walks through both. - **[`wheels-sentry`](https://github.com/wheels-dev/wheels-sentry)** — Sentry.io error tracking with framework-aware context enrichment. Captures exceptions with request, user, and route context. Mixes into controllers. - **[`wheels-legacy-adapter`](https://github.com/wheels-dev/wheels-legacy-adapter)** — Backward-compatibility shim for Wheels 3.x plugins. Deprecation logging, API adapters, and a scanner that flags 3.x patterns you should modernize. Mixes into controllers. - **[`wheels-i18n`](https://github.com/wheels-dev/wheels-i18n)** — Internationalization with JSON-file or database-backed translations, parameter interpolation, and pluralization. Mixes into controllers. diff --git a/web/sites/guides/src/content/docs/v4-0-0/start-here/tutorial/08-bonus-basecoat.mdx b/web/sites/guides/src/content/docs/v4-0-0/start-here/tutorial/08-bonus-basecoat.mdx index d77fe46111..86e0aa50d3 100644 --- a/web/sites/guides/src/content/docs/v4-0-0/start-here/tutorial/08-bonus-basecoat.mdx +++ b/web/sites/guides/src/content/docs/v4-0-0/start-here/tutorial/08-bonus-basecoat.mdx @@ -304,6 +304,52 @@ Three things to verify: **Card content is wrapped in a frame but no styling** — basecoat's JS bundle is failing to load. Check `public/assets/basecoat/basecoat.min.js` exists and look in the browser console for a network error on `/assets/basecoat/`. +## Optional: the Basecoat showcase + +The package ships a full component gallery under `vendor/wheels-basecoat/examples/showcase/`. Use it to browse every helper (`uiBadge`, `uiAlert`, `uiDropdown`, …) against the version you just added. + + + + + +1. Add the package if you have not already: + + ```bash title="your shell" + wheels packages add wheels-basecoat + ``` + +2. Copy the bundled CSS+JS (same step as [Publish the basecoat assets](#publish-the-basecoat-assets)) and the showcase controller + views from `vendor/`: + + ```bash title="macOS / Linux" + cp -r vendor/wheels-basecoat/assets/basecoat public/assets/basecoat + cp vendor/wheels-basecoat/examples/showcase/controllers/Showcase.cfc app/controllers/Showcase.cfc + cp -r vendor/wheels-basecoat/examples/showcase/views/showcase app/views/showcase + ``` + + ```bat title="Windows (cmd)" + xcopy /E /I vendor\wheels-basecoat\assets\basecoat public\assets\basecoat + copy vendor\wheels-basecoat\examples\showcase\controllers\Showcase.cfc app\controllers\Showcase.cfc + xcopy /E /I vendor\wheels-basecoat\examples\showcase\views\showcase app\views\showcase + ``` + +3. Add a named route in `config/routes.cfm` (before `.wildcard()`): + + ```cfm title="config/routes.cfm" + .get(name="basecoatShowcase", pattern="/basecoat-showcase", to="showcase##index") + ``` + +4. Reload and open the gallery: + + ```bash title="your shell" + wheels reload + ``` + + Visit `/basecoat-showcase`. Always check `vendor/wheels-basecoat/INSTALL.md` for the version you added — the asset and showcase layout can change between majors. + + + ## What's next This chapter converted one view. The other views (`index.cfm`, `new.cfm`, `edit.cfm`, the comment partials, the auth screens from Part 6) are still on simple.css. Converting them is a mechanical exercise — the helpers are documented in the [wheels-basecoat README](https://github.com/wheels-dev/wheels-basecoat#component-reference). diff --git a/web/sites/guides/src/sidebars/v4-0-0.json b/web/sites/guides/src/sidebars/v4-0-0.json index c08f848ae6..38a139884b 100644 --- a/web/sites/guides/src/sidebars/v4-0-0.json +++ b/web/sites/guides/src/sidebars/v4-0-0.json @@ -202,7 +202,7 @@ { "label": "packages list", "link": "/v4-0-0/command-line-tools/commands/packages/list/" }, { "label": "packages search", "link": "/v4-0-0/command-line-tools/commands/packages/search/" }, { "label": "packages show", "link": "/v4-0-0/command-line-tools/commands/packages/show/" }, - { "label": "packages add", "link": "/v4-0-0/command-line-tools/commands/packages/install/" }, + { "label": "packages add", "link": "/v4-0-0/command-line-tools/commands/packages/add/" }, { "label": "packages update", "link": "/v4-0-0/command-line-tools/commands/packages/update/" }, { "label": "packages remove", "link": "/v4-0-0/command-line-tools/commands/packages/remove/" }, { diff --git a/web/sites/packages/src/components/PackageCard.astro b/web/sites/packages/src/components/PackageCard.astro index 4e30f973a1..4ca7bc378b 100644 --- a/web/sites/packages/src/components/PackageCard.astro +++ b/web/sites/packages/src/components/PackageCard.astro @@ -23,12 +23,12 @@ const homepage = /^https?:\/\//.test(pkg.homepage) ? pkg.homepage : ''; )}
- wheels packages install {pkg.name} + wheels packages add {pkg.name}
{homepage && ( diff --git a/web/sites/packages/src/pages/[name].astro b/web/sites/packages/src/pages/[name].astro index 00ea03b6ad..06af731116 100644 --- a/web/sites/packages/src/pages/[name].astro +++ b/web/sites/packages/src/pages/[name].astro @@ -63,14 +63,18 @@ const versionsDesc = [...manifest.versions].reverse(); )}
-

Install

+

Add the package

+

+ The verb is add, not install. + wheels packages install is intercepted by LuCLI and does not install anything. +

- wheels packages install {manifest.name} - + wheels packages add {manifest.name} +
- wheels packages install {manifest.name}@{latest.version} - + wheels packages add {manifest.name}@{latest.version} +
@@ -157,6 +161,17 @@ const versionsDesc = [...manifest.versions].reverse(); .install-section h2, .versions-section h2, .readme-section h2 { font-size: 1.25rem; margin-bottom: 0.75rem; } + .install-note { + margin: 0 0 0.75rem; + color: var(--color-fg-muted, #555); + font-size: 0.9375rem; + } + .install-note code { + font-size: 0.875em; + background: var(--color-surface-2, #f3f3f3); + padding: 0.125rem 0.375rem; + border-radius: 4px; + } .install { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; } .install code { flex: 1; diff --git a/web/sites/packages/src/pages/index.astro b/web/sites/packages/src/pages/index.astro index b5c84741f5..a6d4b5cfce 100644 --- a/web/sites/packages/src/pages/index.astro +++ b/web/sites/packages/src/pages/index.astro @@ -15,7 +15,8 @@ const packages = await listAll();

Wheels packages

First-party and community packages for the Wheels framework. Install with - wheels packages install <name>. + wheels packages add <name> + (the verb is add, not install).