Skip to content

Dev - #2420

Merged
namastex888 merged 8 commits into
mainfrom
dev
May 11, 2026
Merged

Dev#2420
namastex888 merged 8 commits into
mainfrom
dev

Conversation

@namastex888

@namastex888 namastex888 commented May 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Added --dev flag (with --next as a deprecated alias); selected channel is persisted after updates.
    • Installer and publish process now support channel-specific manifests (<channel>.json) and validate channel input.
  • Bug Fixes

    • Installer avoids re-running a prerequisite when the service is already running under process manager.
  • Tests

    • Expanded tests for channel resolution, persistence, and installer idempotency.
  • Chores

    • Bumped version to 4.260511.5 and updated release workflows to propagate channel metadata.

Review Change Stack

github-actions Bot and others added 7 commits May 11, 2026 21:06
`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)
@coderabbitai

coderabbitai Bot commented May 11, 2026 •

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9902ffde-125e-46fb-a62f-917a27a56985

📥 Commits

Reviewing files that changed from the base of the PR and between 5f84b6a and 756f0e6.

📒 Files selected for processing (4)
  • .claude-plugin/marketplace.json
  • package.json
  • plugins/genie/.claude-plugin/plugin.json
  • plugins/genie/package.json

📝 Walkthrough

Walkthrough

Renames the legacy update channel next to canonical dev with a deprecated --next alias, persists resolved channels unconditionally, makes install.sh fetch per-channel .well-known manifests, updates release workflows to publish per-channel manifests, adds pm2-aware pgserve install skipping, tests, docs, and version bumps.

Changes

Release Channel Dev

Layer / File(s) Summary
WISH / Documentation
.genie/wishes/release-channel-dev/WISH.md
New wish doc describing scope, groups, success criteria, and file list for next→dev migration.
Release Workflow Channel Propagation
.github/workflows/version.yml, .github/workflows/release.yml, .github/workflows/release-publish.yml
Version workflow computes channel (main→stable, else→dev); release.yml accepts channel input; release-publish.yml writes per-channel .well-known/<channel>.json (stable→latest.json) and stages manifest commits reliably.
Install Script Manifest Routing
install.sh
Replaces LATEST_URL with MANIFEST_BASE; resolve_channel() validates allowed channels and maps deprecated next→dev; resolve_manifest_url() maps stable→latest.json and other channels→<channel>.json; fetch_latest() uses resolved URL.
Type System & Schema
src/genie-commands/update.ts, src/types/genie-config.ts
ReleaseChannel removes 'next' (uses 'dev'). GenieConfigSchema.updateChannel now accepts `latest
CLI Interface
src/genie.ts
update command adds --dev flag; --next is marked and handled as a deprecated alias for --dev.
Channel Resolution & Persistence
src/genie-commands/update.ts
resolveChannel() accepts dev/next/stable flags, prioritizes --stable, aliases --next→dev with a one-time deprecation latch and test-reset hook; config mapping recognizes 'dev' and 'latest'; persistChannel() writes 'dev' or 'latest'; updateCommand persists channel every run.
Install Prerequisite Optimization
src/genie-commands/install.ts
Adds isPgserveOnlinePm2() predicate and updates requirePgserveInstall() to skip pgserve install when pm2 reports an online pgserve process; exports helper in _internals for tests.
Tests
src/genie-commands/__tests__/install.test.ts, src/genie-commands/__tests__/update.test.ts
install.test.ts adds tests for isPgserveOnlinePm2. update.test.ts adds manifest routing tests, resolveChannel/deprecation/latch tests, GenieConfigSchema.updateChannel parsing tests, and persistChannel tests.
Version & Plugin Manifests
package.json, .claude-plugin/marketplace.json, plugins/genie/.claude-plugin/plugin.json, plugins/genie/package.json
Bumped version fields to 4.260511.5 across root and plugin manifests and marketplace entry.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Dev' is too vague and generic; it doesn't convey meaningful information about the changeset beyond a single word. Use a more descriptive title that captures the main change, such as 'Rename next release channel to dev' or 'Implement dev channel with next alias deprecation.'
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@namastex888
namastex888 merged commit fcfeb41 into main May 11, 2026
9 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between de5ba4a and 5f84b6a.

📒 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.yml
  • install.sh
  • package.json
  • plugins/genie/.claude-plugin/plugin.json
  • plugins/genie/package.json
  • src/genie-commands/__tests__/install.test.ts
  • src/genie-commands/__tests__/update.test.ts
  • src/genie-commands/install.ts
  • src/genie-commands/update.ts
  • src/genie.ts
  • src/types/genie-config.ts

Comment thread package.json Outdated
{
"name": "@automagik/genie",
"version": "4.260511.2",
"version": "4.260511.4",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

Comment on lines +1145 to +1162
// --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';
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

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.

Comment on lines +1177 to 1185
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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +1151 to +1157
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';
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +189 to +190
if [ "$BRANCH" = "main" ]; then CHANNEL="stable"; else CHANNEL="dev"; fi
echo "Dispatching release pipeline against ${TAG} (channel=${CHANNEL})..."

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

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.

1 participant