Skip to content

fix(cli): unblock new-user onboarding for Homebrew/Chocolatey installs - #2294

Merged
bpamiri merged 2 commits into
developfrom
claude/sweet-cori-a04fb4
Apr 25, 2026
Merged

fix(cli): unblock new-user onboarding for Homebrew/Chocolatey installs#2294
bpamiri merged 2 commits into
developfrom
claude/sweet-cori-a04fb4

Conversation

@bpamiri

@bpamiri bpamiri commented Apr 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes a blocker discovered in a fresh-VM onboarding test: a user installs via Homebrew, runs `wheels new blog` per the tutorial's first step, and hits:

```
Error: Could not locate the Wheels framework source.
A scaffolded app requires vendor/wheels/ to boot.
...
See: https://guides.wheels.dev/docs/getting-started ← 404
```

Zero chapters of the tutorial were reachable from a fresh install.

Root causes

  1. Snapshot releases never published `wheels-core-*.zip`. The release workflow only attached `wheels-module-*` on `develop` snapshots; the companion framework-source zip was main-branch only. Since every current release is a snapshot, the Homebrew formula had nothing to fetch even if updated — the asset literally didn't exist on GitHub. Verified via `gh release view`: 1,594 snapshot releases, zero `wheels-core` assets.

  2. CLI error message pointed at a 404 (`guides.wheels.dev/docs/getting-started`) and didn't mention that Homebrew/Chocolatey distributions must bundle the framework source — users couldn't distinguish "I'm in the wrong directory" from "my install is broken."

  3. `wheels doctor` recommended the same broken command. Run in an empty dir, doctor reported CRITICAL and said "Run 'wheels new' to scaffold" — the exact command just proven broken. No check verified the framework source was actually bundled.

Changes

`.github/workflows/release.yml`

Snapshot pre-release job now publishes the same file set as main-branch releases (wheels-core, wheels-base-template, wheels-cli, wheels-starter-app + the existing wheels-module). Adopts the CommandBox scheme — develop ships snapshots, main ships finals, identical artifact contents differ only by the prerelease flag.

`cli/lucli/Module.cfc`

Error message in `resolveFrameworkSourceOrFail`:

  • URL now points at `/v4-0-0-snapshot/start-here/installing/` (real page) instead of `/docs/getting-started` (404)
  • Calls out Homebrew/Chocolatey explicitly so users recognize distribution-packaging issues
  • Adds a manual curl/unzip path for users who want to unblock themselves now

`cli/lucli/services/Doctor.cfc`

New `checkFrameworkSourceBundled()` — mirrors `resolveFrameworkSource()`'s search order (WHEELS_FRAMEWORK_PATH → projectRoot/vendor/wheels → installedModuleRoot walk-up). Reports a CRITICAL issue when none resolve, only runs when `installedModuleRoot` is set (dev checkouts always have vendor/wheels/ by construction).

Recommendation engine replaces the misleading "Run 'wheels new'" suggestion with "reinstall the CLI or set WHEELS_FRAMEWORK_PATH" when the new issue is present.

Tests

Three new DoctorSpec cases: silent without installedModuleRoot; passes when vendor/wheels/ exists at projectRoot; CRITICAL with correct recommendation when framework source is missing everywhere.

Follow-ups (not in this PR)

  • Homebrew formula (`wheels-dev/homebrew-wheels`): Once this PR merges and the next snapshot release cuts, the formula needs a new `resource "wheels_core"` with the real sha256, plus wrapper changes to sync the framework into `~/.wheels/modules/wheels/vendor/wheels/`. I can open that PR as a follow-up.
  • Chocolatey formula (`wheels-dev/chocolatey-wheels`): Same fix.
  • LuCLI version output (`cybersonic/lucli`): `wheels --version` prints LuCLI branding and mismatches both guide pages' claimed format — a separate upstream fix.
  • `wheels new --help`: LuCLI intercepts `--help` before the `new()` method runs, so per-subcommand help also needs an upstream LuCLI change.

Test plan

  • CI: tests pass on all engine/database combinations
  • CI: release workflow's `softprops/action-gh-release@v3` step accepts the expanded `files:` list (glob entries that find nothing are soft-ignored by the action, so no failure if a specific artifact is absent)
  • After merge: next develop snapshot release attaches wheels-core-*.zip
  • After merge: follow up with homebrew-wheels PR pointing at the new asset

bpamiri added 2 commits April 24, 2026 13:22
- `wheels new` error now links to the real installing page instead of
  /docs/getting-started (404), and mentions Homebrew/Chocolatey packaging
  explicitly so users distinguish "wrong directory" from "incomplete install."
- `wheels doctor` detects missing vendor/wheels/ via new
  checkFrameworkSourceBundled(), issuing CRITICAL when the CLI can't resolve
  framework source the same way Module.cfc.resolveFrameworkSource() does.
- Recommendation engine now offers "reinstall or set WHEELS_FRAMEWORK_PATH"
  instead of misleading "Run 'wheels new'" when framework source is absent.

Catches the onboarding dead-end where a fresh Homebrew install scaffolds an
app, can't boot it, and doctor points at the same broken command.
Snapshot pre-releases from `develop` now attach wheels-core-*.zip,
wheels-base-template-*.zip, wheels-cli-*.zip, and wheels-starter-app-*.zip
alongside wheels-module-*, mirroring what main-branch releases publish.

Downstream packagers (Homebrew, Chocolatey) depend on wheels-core-*.zip
to bundle framework source alongside the CLI module. Until now, no
snapshot had ever published that asset, so every snapshot-based package
install dead-ended at "wheels new" with a framework-not-found error.

Adopts the CommandBox scheme: develop = snapshot prerelease, main = final,
identical artifact set differentiated only by the prerelease flag.
@bpamiri

bpamiri commented Apr 25, 2026

Copy link
Copy Markdown
Collaborator Author

Deferred follow-ups (filed separately)

The original onboarding-test report had nine findings. This PR addresses #1, #2 (verified non-issue in current code), #3, and #8 directly. The remaining items are tracked here:

bpamiri added a commit that referenced this pull request Apr 25, 2026
…2298)

Two help-text lines added in #2294 contained a single literal `#`
(shell-comment marker shown in the manual-recovery instructions).
CFML treats `#` as the start of a `#expr#` interpolation, so Lucee
parsed `# Pick the wheels-core-<version>.zip…` as an unterminated
interpolation and failed Module.cfc compilation:

    Invalid Syntax Closing [#] not found, at [3540:22]

This broke the post-merge Wheels Snapshots run on develop — the
"Smoke Test Installed Distribution" job in the same release workflow
the original PR added to catch exactly this class of regression.

Doubled `#` to `##` on both lines (CFML's literal-hash escape).
The other `#` references in the surrounding block (`#appName#`,
`#candidate#`, `#projectCandidate#`) are proper interpolations and
remain unchanged.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bpamiri added a commit to wheels-dev/homebrew-wheels that referenced this pull request Apr 25, 2026
Resolves the placeholder/version-pin chicken-and-egg in this PR and
fixes a latent bug in the auto-update formula rewrite.

Formula:
- MODULE_VERSION 4.0.0-SNAPSHOT+1523 → 4.0.0-SNAPSHOT+1596 (the first
  snapshot to publish wheels-core after wheels-dev/wheels#2294)
- wheels_module sha256 → real value for +1596 tarball
- wheels_core sha256 PLACEHOLDER_CORE_SHA → real value for +1596 zip

Workflow rewrite logic:
- Replaces position-based sha rewrite (only updated [0] macOS and [1]
  Linux) and dead PLACEHOLDER_MODULE_SHA activation block with four
  parallel context-anchored regex updates: macOS LuCLI, Linux LuCLI,
  wheels_module resource, wheels_core resource.
- Each replacement asserts exactly 1 match — fails loudly if the
  formula structure ever drifts in a way the regex can't see.
- Closes a silent bug visible in run 24937275010 where bumping
  MODULE_VERSION rotated the URL but left the sha pinned at +1523,
  causing brew fetch to reject the formula. The bug existed since
  PR #3 but only surfaced once REST API auto-update started working.

Verified locally:
- brew audit --strict exit 0
- brew fetch downloads Formula + wheels_module + wheels_core, all
  shas match
- python rewrite is idempotent against the new formula (each pattern
  matches exactly once; replacing with current shas is a no-op)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bpamiri added a commit to wheels-dev/homebrew-wheels that referenced this pull request Apr 25, 2026
* feat: bundle wheels-core framework source alongside CLI module

Adds a second Homebrew resource (wheels_core) that pulls the Wheels
framework-source zip from each GitHub release and stages it into
share/wheels/framework/. The wrapper script syncs it into
~/.wheels/modules/wheels/vendor/wheels/ on version change, mirroring
how wheels-module is already propagated.

This unblocks the new-user Homebrew onboarding path: previously
`brew install wheels` landed only the CLI, so `wheels new myapp`
dead-ended at "Could not locate the Wheels framework source" — the
first command of the Getting Started tutorial.

Extends the auto-update workflow to fetch and substitute the
wheels-core sha256 the same way wheels-module is handled. wheels-core
is now required on every release (snapshots included); see
wheels-dev/wheels PR 2294 for the release-workflow change that
started publishing it.

Blocked on: wheels-dev/wheels PR 2294 merging and the next snapshot
release cutting with the wheels-core-*.zip asset. Until then this
formula has a PLACEHOLDER_CORE_SHA sentinel that auto-update will
replace on its first nightly run after those prereqs land.

* fix(ci): bump module to +1596, fill real shas, rewrite by context

Resolves the placeholder/version-pin chicken-and-egg in this PR and
fixes a latent bug in the auto-update formula rewrite.

Formula:
- MODULE_VERSION 4.0.0-SNAPSHOT+1523 → 4.0.0-SNAPSHOT+1596 (the first
  snapshot to publish wheels-core after wheels-dev/wheels#2294)
- wheels_module sha256 → real value for +1596 tarball
- wheels_core sha256 PLACEHOLDER_CORE_SHA → real value for +1596 zip

Workflow rewrite logic:
- Replaces position-based sha rewrite (only updated [0] macOS and [1]
  Linux) and dead PLACEHOLDER_MODULE_SHA activation block with four
  parallel context-anchored regex updates: macOS LuCLI, Linux LuCLI,
  wheels_module resource, wheels_core resource.
- Each replacement asserts exactly 1 match — fails loudly if the
  formula structure ever drifts in a way the regex can't see.
- Closes a silent bug visible in run 24937275010 where bumping
  MODULE_VERSION rotated the URL but left the sha pinned at +1523,
  causing brew fetch to reject the formula. The bug existed since
  PR #3 but only surfaced once REST API auto-update started working.

Verified locally:
- brew audit --strict exit 0
- brew fetch downloads Formula + wheels_module + wheels_core, all
  shas match
- python rewrite is idempotent against the new formula (each pattern
  matches exactly once; replacing with current shas is a no-op)

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

* fix(formula): install wheels_core into framework/wheels/ subdir

Brew's resource.stage auto-strips a single top-level directory from
the staged archive before yielding to the install block. The
wheels-core zip's only top-level entry is "wheels/", so inside the
stage block Dir["*"] returns its contents (Testbox.cfc, box.json,
tests/, …) — not "wheels" itself.

The previous install put those contents directly into
share/wheels/framework/, with no "wheels/" subdir. The brew test
assertion (and the wrapper's WHEELS_FRAMEWORK_SRC path) both expect
share/wheels/framework/wheels/ to exist, so the test failed:

    Expected #<Pathname:.../share/wheels/framework/wheels> to be exist?

Re-introduce the "wheels/" directory explicitly by installing into
share/wheels/framework/wheels/.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant