Dev - #2420
Dev#2420
Conversation
`genie install` was crashing on hosts where pgserve is already pm2-managed: $ curl -fsSL https://get.automagik.dev/genie | bash ... ==> handing off to: genie install pgserve install: port 8432 is already in use on 127.0.0.1 (something is listening). Error: canonical pgserve registration failed (exit code 1). Root cause: pgserve@^2 install runs an EADDRINUSE bind check on the canonical port BEFORE noticing that the existing listener is its own pm2-supervised instance. The file header's claim that pgserve install is "idempotent — no-op when pgserve is already pm2-managed" was true in intent but not in execution. Fix: probe `pm2 jlist` for an online `pgserve` entry; when found, short- circuit the install shell-out and emit a friendly skip message. Falls through to the original install flow on first-time installs and on hosts where pgserve is missing from pm2. Same defensive shape omni's installer already uses. A pure `isPgserveOnlinePm2(entry)` predicate is exposed via `_internals` so the skip decision is regression-tested across the five interesting inputs (online / stopped / errored / launching / missing pm2_env / null) without mocking `pm2 jlist` itself. Detected on Felipe's box on 2026-05-11 immediately after the v4.260511.3 g1-respawn fix went live and operators re-ran the install on hosts with prior pgserve installs.
…ip-if-online fix(install): skip pgserve install when already pm2-managed
…1-G3)
Implements groups 1-3 of wish release-channel-dev:
G1: CLI + config rename
- `ReleaseChannel` enum: 'next' → 'dev'; manifestUrlForChannel('dev')
now reads .well-known/dev.json (was next.json).
- Add `--dev` option in src/genie.ts; keep `--next` as a deprecated
alias that maps to 'dev' and emits a one-line stderr warning (once
per process). Remove the alias in the next major.
- genie-config schema: updateChannel accepts 'next' as a read-time
alias for 'dev' via zod .transform; writes always emit 'dev'.
- Drop the `if (options.next || options.stable)` gate around
persistChannel — call unconditionally so a one-time --dev flip
persists; subsequent bare `genie update` re-resolves the dev
channel and stays on dev until an explicit --stable.
- Tests: extend src/genie-commands/__tests__/update.test.ts with 12
new cases covering --dev, --next deprecation (single emit), schema
transform of legacy 'next', persistChannel smoke. 87/87 pass.
G2: install.sh channel-aware URL
- Replace hardcoded LATEST_URL with channel-derived
resolve_manifest_url(channel): stable → latest.json,
everything else → <channel>.json.
- Allow-list GENIE_CHANNEL: stable|beta|canary|dev; legacy 'next'
accepted with deprecation warning; everything else dies clean.
- Surface the resolved manifest filename in the install banner
("==> manifest=<file>") so a 404 is self-diagnosing.
G3: Release pipeline plumb channel + write <channel>.json
- version.yml: derive channel from steps.context.outputs.branch
(dev → 'dev', main → 'stable'); pass --field channel=$CHANNEL to
`gh workflow run release.yml`.
- release.yml: add `channel` workflow_dispatch input
(stable|beta|canary|dev); propagate to release-publish via
`with.channel: ${{ inputs.channel || 'stable' }}`. Bare tag
pushes fall through to stable.
- release-publish.yml: generalize the .well-known writer — drop the
`channel == 'stable'` gate; filename derived from the channel
input (stable → latest.json for back-compat with v1 manifest
layout, others → <channel>.json). Keep the !inputs.draft gate.
The existing PRERELEASE_FLAG logic already marks non-stable
releases as prerelease — no change needed there.
G4 (docs + smoke): docs/installation.mdx + docs/release-process.mdx
edits exist in .docs-vendor but are NOT part of this commit (per
CLAUDE.md submodule workflow they ship via a separate PR against
automagik-dev/docs). End-to-end smoke requires this PR to land first
and trigger a dev publish.
See .genie/wishes/release-channel-dev/WISH.md for full scope, IN/OUT
boundaries, decisions, and acceptance criteria.
Three valid review findings on the wish release-channel-dev PR:
1. (codex P2 + gemini medium) `resolveChannel` checked dev/next BEFORE
stable, so `genie update --stable --dev` resolved to dev. Wrappers
that append --stable to force-pull-back from prerelease silently
no-op'd. Fix: reorder so an explicit --stable always wins. The
--next deprecation notice still fires when --next is on the command
line, so operators learn to drop it even when --stable overrode.
Add a new test pinning --stable + --dev → stable.
2. (gemini medium) Test name "--stable wins over --next when both are
set" contradicted its `expect(...).toBe('dev')` assertion. Fix:
the assertion now matches the test name (and matches the corrected
precedence above) — both resolve to 'stable'.
3. (gemini medium) `install.sh` used `sed` with `${MANIFEST_BASE}/`
(containing `/` and `.`) to strip the URL prefix and produce a
filename. Brittle and unnecessary — replace with the idiomatic
shell parameter expansion `${url##*/}`.
Tests: 88 pass (was 87 — +1 for --stable vs --dev coverage).
feat(release): rename --next to --dev + wire dev-channel publisher (wish release-channel-dev)
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughRenames the legacy update channel ChangesRelease Channel Dev
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@package.json`:
- Line 3: The package.json version was bumped to "4.260511.4" but the
binarySha256 integrity pins no longer match the release artifacts; update the
package.json's binarySha256 entries so they match the SHA256 checksums of the
downloaded release assets for version "4.260511.4". Locate the binarySha256
array/object in package.json, recompute the SHA256 of each distributed binary
for this new version, and replace the stale hash strings with the newly computed
values so postinstall integrity checks pass.
In `@src/genie-commands/update.ts`:
- Around line 1177-1185: persistChannel currently accepts the broad
ReleaseChannel but collapses every non-'dev' value to 'latest', which will
silently drop 'beta'/'canary'; update persistChannel to either restrict its
parameter to the persistable subset (e.g. only 'dev' | 'latest') or handle all
ReleaseChannel members explicitly (map 'beta' and 'canary' to their intended
persisted tokens or throw a clear error when they are not persistable), updating
callers to match and keeping loadGenieConfig/saveGenieConfig usage the same; if
you change the exported parameter type, ensure you export-safe the type updates
for other modules that depend on ReleaseChannel.
- Around line 1145-1162: The current early returns skip the deprecation notice
when --next is passed together with --stable or --dev; update the branch logic
in the channel-resolution code so that whenever options.next is true you call
emitNextDeprecationOnce() before returning (e.g., check options.next or call
emitNextDeprecationOnce() at the top of the decision path), then return the
appropriate channel; adjust the checks around options.stable, options.dev and
options.next to ensure emitNextDeprecationOnce() always runs when options.next
is present.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 140000fa-4585-4917-b628-bad7da049951
📒 Files selected for processing (15)
.claude-plugin/marketplace.json.genie/wishes/release-channel-dev/WISH.md.github/workflows/release-publish.yml.github/workflows/release.yml.github/workflows/version.ymlinstall.shpackage.jsonplugins/genie/.claude-plugin/plugin.jsonplugins/genie/package.jsonsrc/genie-commands/__tests__/install.test.tssrc/genie-commands/__tests__/update.test.tssrc/genie-commands/install.tssrc/genie-commands/update.tssrc/genie.tssrc/types/genie-config.ts
| { | ||
| "name": "@automagik/genie", | ||
| "version": "4.260511.2", | ||
| "version": "4.260511.4", |
There was a problem hiding this comment.
Refresh binarySha256 pins for this release.
Binary SHA Drift is failing in CI, which means at least one hash in binarySha256 no longer matches the downloaded release asset. With this version bump, update the affected SHA entry(ies) before merge to keep postinstall integrity checks valid.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@package.json` at line 3, The package.json version was bumped to "4.260511.4"
but the binarySha256 integrity pins no longer match the release artifacts;
update the package.json's binarySha256 entries so they match the SHA256
checksums of the downloaded release assets for version "4.260511.4". Locate the
binarySha256 array/object in package.json, recompute the SHA256 of each
distributed binary for this new version, and replace the stale hash strings with
the newly computed values so postinstall integrity checks pass.
| // --stable is checked FIRST so an explicit override always wins over dev / | ||
| // next prerelease intent. Common case: wrappers / aliases / smoke scripts | ||
| // append `--stable` to force-pull-back from a prerelease channel regardless | ||
| // of what other flags are on the command line. (PR #2419 review: codex | ||
| // P2 + gemini medium — without this ordering, `genie update --stable --dev` | ||
| // resolved to dev, silently ignoring the operator's stable intent.) | ||
| if (options.stable) { | ||
| // Still emit the --next deprecation notice if --next was passed too — | ||
| // operators learn to drop it from muscle memory even when --stable | ||
| // overrode the channel. | ||
| if (options.next) emitNextDeprecationOnce(); | ||
| return 'stable'; | ||
| } | ||
| if (options.dev) return 'dev'; | ||
| if (options.next) { | ||
| emitNextDeprecationOnce(); | ||
| return 'dev'; | ||
| } |
There was a problem hiding this comment.
Emit the --next deprecation warning whenever --next is present.
If a caller passes --dev --next, Line 1158 returns before the deprecated-alias branch runs, so the command resolves to dev with no warning at all.
Suggested fix
export async function resolveChannel(options: {
dev?: boolean;
next?: boolean;
stable?: boolean;
}): Promise<ReleaseChannel> {
+ if (options.next) emitNextDeprecationOnce();
+
// --stable is checked FIRST so an explicit override always wins over dev /
// next prerelease intent. Common case: wrappers / aliases / smoke scripts
// append `--stable` to force-pull-back from a prerelease channel regardless
// of what other flags are on the command line. (PR `#2419` review: codex
// P2 + gemini medium — without this ordering, `genie update --stable --dev`
// resolved to dev, silently ignoring the operator's stable intent.)
if (options.stable) {
- // Still emit the --next deprecation notice if --next was passed too —
- // operators learn to drop it from muscle memory even when --stable
- // overrode the channel.
- if (options.next) emitNextDeprecationOnce();
return 'stable';
}
- if (options.dev) return 'dev';
- if (options.next) {
- emitNextDeprecationOnce();
- return 'dev';
- }
+ if (options.dev || options.next) return 'dev';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/genie-commands/update.ts` around lines 1145 - 1162, The current early
returns skip the deprecation notice when --next is passed together with --stable
or --dev; update the branch logic in the channel-resolution code so that
whenever options.next is true you call emitNextDeprecationOnce() before
returning (e.g., check options.next or call emitNextDeprecationOnce() at the top
of the decision path), then return the appropriate channel; adjust the checks
around options.stable, options.dev and options.next to ensure
emitNextDeprecationOnce() always runs when options.next is present.
| export async function persistChannel(channel: ReleaseChannel): Promise<void> { | ||
| try { | ||
| const config = await loadGenieConfig(); | ||
| // Map back to the legacy schema enum (`'latest' | 'next'`) — the genie-config | ||
| // schema is shared with downstream consumers and changing its enum is | ||
| // out of scope for this wish. | ||
| config.updateChannel = channel === 'next' ? 'next' : 'latest'; | ||
| // Map to the genie-config schema enum. The schema accepts 'next' as a | ||
| // read-time alias but we always write the canonical token ('dev' or | ||
| // 'latest') so the user's config converges to the current naming on | ||
| // their next update. | ||
| config.updateChannel = channel === 'dev' ? 'dev' : 'latest'; | ||
| await saveGenieConfig(config); |
There was a problem hiding this comment.
Don't accept beta/canary here if they will be persisted as stable.
persistChannel() advertises ReleaseChannel, but this implementation serializes every non-dev value as 'latest'. A caller that passes beta or canary will silently lose that choice, and the next bare update resolves to stable. Either narrow this helper to the persistable subset or handle all ReleaseChannel members explicitly. As per coding guidelines, src/**: Core CLI source. Check for breaking changes to exported types.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/genie-commands/update.ts` around lines 1177 - 1185, persistChannel
currently accepts the broad ReleaseChannel but collapses every non-'dev' value
to 'latest', which will silently drop 'beta'/'canary'; update persistChannel to
either restrict its parameter to the persistable subset (e.g. only 'dev' |
'latest') or handle all ReleaseChannel members explicitly (map 'beta' and
'canary' to their intended persisted tokens or throw a clear error when they are
not persistable), updating callers to match and keeping
loadGenieConfig/saveGenieConfig usage the same; if you change the exported
parameter type, ensure you export-safe the type updates for other modules that
depend on ReleaseChannel.
There was a problem hiding this comment.
Code Review
This pull request renames the next release channel to dev across the CLI, configuration, and installation scripts, while maintaining backward compatibility for the --next flag and existing configuration files. It also introduces a fix for an idempotency issue in the installation process where pgserve would fail to install if it was already running under pm2. Feedback includes a suggestion to ensure the deprecation warning for --next is consistently emitted regardless of other flags, and a note regarding the persistence of future release channels like beta or canary to prevent silent preference loss.
| if (options.stable) { | ||
| // Still emit the --next deprecation notice if --next was passed too — | ||
| // operators learn to drop it from muscle memory even when --stable | ||
| // overrode the channel. | ||
| if (options.next) emitNextDeprecationOnce(); | ||
| return 'stable'; | ||
| } |
There was a problem hiding this comment.
The current implementation prioritizes --stable over --next and --dev, which is correct for allowing users to escape a pre-release channel. However, the deprecation warning for --next is only emitted if --stable is also present. If a user passes both --dev and --next, the --dev branch (line 1158) will be taken, and the deprecation warning for --next will be skipped. To ensure users are always notified of the deprecation, the check for options.next should be moved to the top of the function or handled independently of the return path.
if (options.next) emitNextDeprecationOnce();
if (options.stable) return 'stable';
if (options.dev || options.next) return 'dev';| // read-time alias but we always write the canonical token ('dev' or | ||
| // 'latest') so the user's config converges to the current naming on | ||
| // their next update. | ||
| config.updateChannel = channel === 'dev' ? 'dev' : 'latest'; |
There was a problem hiding this comment.
The persistChannel function maps any channel that is not dev to latest. While beta and canary are currently out of scope, if they are ever used, their preference will be lost and reverted to latest on the next update. Consider if these should also be persisted or if the config schema should be expanded to include them as placeholders to avoid silent preference loss.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5f84b6a979
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if [ "$BRANCH" = "main" ]; then CHANNEL="stable"; else CHANNEL="dev"; fi | ||
| echo "Dispatching release pipeline against ${TAG} (channel=${CHANNEL})..." |
There was a problem hiding this comment.
Derive channel from dispatch ref instead of defaulting to dev
This new branch-based channel switch causes manual workflow_dispatch runs of version.yml to always publish to dev: in dispatch runs there is no github.event.workflow_run.head_branch, so the earlier context step falls back to branch=dev, and this block then forces CHANNEL=dev. As a result, an operator-triggered stable release/promotion from main will still be sent down the prerelease/dev path (updating dev.json instead of latest.json).
Useful? React with 👍 / 👎.
Summary by CodeRabbit
New Features
--devflag (with--nextas a deprecated alias); selected channel is persisted after updates.<channel>.json) and validate channel input.Bug Fixes
Tests
Chores