DB migration compat / Back-compat — Current branch migrations with ${{ needs.check-migrations-changed.outputs.base_branch }} branch code (push) Has been cancelled
DB migration compat / Forward-compat — Current branch code with ${{ needs.check-migrations-changed.outputs.base_branch }} branch migrations (push) Has been cancelled
## Stack Auth → Hexclave rename — PR 5 (internal symbols, paths,
packages, brand strings)
PR 5 finishes the **internal / non-wire** half of the Stack→Hexclave
rename. It only touches things where nothing outside the repo depends on
the exact name: internal symbols, file/dir names, the
`@stackframe/template` package, and residual brand strings. Plan +
progress are in `HEXCLAVE-RENAME-PR5-PLAN.md`.
Every step was verified green (`pnpm typecheck` + `pnpm lint`, 28/28)
and committed as its own checkpoint, then a fan-out of review agents
audited all commits and the findings were fixed.
### What changed
- **Internal symbols** (`@hexclave/shared`, `packages/template`, apps):
`stack*`/`Stack*` → `hexclave*`/`Hexclave*` — incl.
`stackGlobalsSymbol`, the `_Stack*AppImpl` classes,
`stackAppInternalsSymbol`, `StackContext`, `getStackStripe`, etc. The
`stack*App` local-variable convention
(`stackServerApp`/`stackClientApp`/…) was renamed across 175
source/example/doc files.
- **File renames**: `hexclave-handler/provider/context.tsx`,
`backend/hexclave.tsx`, `internal-tool/hexclave.ts`,
`hexclave-app-internals.ts`.
- **Directory renames**: `lib/hexclave-app`, `hexclave-companion`,
`[...hexclave]` route segment, `skills/hexclave`,
`dashboard/src/hexclave`, and the package dirs
**`packages/{next,shared,ui,sc,cli}`** (dropping the `stack-` prefix to
match the `@hexclave/*` npm names).
- **Packages**: `@stackframe/template` → `@hexclave/template`; **deleted
`packages/init-stack`** (onboarding lives in `@hexclave/cli init`; the
published npm package is untouched).
- **Brand strings**: reworded `Stack Auth`/`Stack dashboard` prose in
code + docs-mintlify, renamed `hexclave-app.mdx`/`use-hexclave-app.mdx`
with redirects, regenerated OpenAPI, updated coupled e2e assertions;
`doctor`/`init` now prefer `hexclave.config.ts`.
### Intentionally kept (verified, not oversights)
Wire/compat identifiers (`x-stack-*` headers, `stack-*` cookies,
`STACK_*` env names, `*.stack-auth.com`, `stackauth_`, `ask_stack_auth`,
query params), public `Stack*` SDK aliases, crypto/JWT/vault
domain-separation tags, `*-brand-sentinel`s, the
`Symbol.for("StackAuth--…")` string, `_stack_sync_metadata`, Postgres
`stackframe` / docker image names, the `stack-auth-logo*.svg` (used by
the rebrand modal), and `migration.mdx` / "formerly known as Stack Auth"
notes. False positives (Phosphor `StackIcon`/`StackSimple`, `TanStack`,
`OrbStack`, `stackable`/`Stacked` charts) left alone.
### Review pass
Six review agents audited all commits. Found + fixed one real bug — a
build script (`bundle-type-definitions.ts`) hardcoded the old
`lib/stack-app` glob path (not an import, so typecheck/lint were blind),
silently emptying the dashboard AI type bundle — plus stale comments, a
dead CI env var, and stale `.gitignore`/`.dockerignore` entries.
Cross-cutting audit confirmed **zero wire-compat identifiers were
accidentally renamed**.
### ⚠️ Verification note
`typecheck` + `lint` are fully green locally. The **e2e suite was not
run** (needs a live backend+DB), so the brand-string assertion +
OpenAPI-regen changes are verified by grep/codegen only — please let CI
exercise e2e to confirm.
### Base-branch note
This branch was forked from the local-only `cl/friendly-lewin-72293f`
(not on origin, no separate PR), so this PR against `dev` also carries
that branch's ~11 preceding Hexclave-rename commits (config-file rename,
env-var dual-read, AI setup-prompt rebrand). If those should land
separately, re-parent before merge.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Finishes the internal Stack Auth → Hexclave rename and cleans up
remaining stragglers, including dev-tool and prompt copy. All changes
are internal-only; public/wire APIs remain unchanged. Re-merged `dev`
and resolved the payments create-purchase-url conflict.
- **Refactors**
- Internal symbols: stack*/Stack* → hexclave*/Hexclave* (e.g.,
`getHexclaveServerApp` via `@/hexclave`, `getHexclaveStripe`,
`hexclaveAppInternalsSymbol`, `hexclaveSchemaInfo`, Prisma
`__hexclave_*`, `data-hexclave-handler-page`, Stripe mock
`hexclavePortPrefix`).
- Files/dirs: moved to `lib/hexclave-app`; handler route
`[...hexclave]`; backend entry `src/hexclave.tsx`; dashboard internals
`hexclave-app-internals`; companion `hexclave-companion`; dropped
`stack-` prefix across package dirs
(`packages/{shared,ui,sc,cli,next}`); workflows/emulator paths now
`packages/cli`; Quetzal codegen env at `packages/next/.env.local`.
- Packages/docs: `@stackframe/template` → `@hexclave/template`; removed
`packages/init-stack`; regenerated OpenAPI and updated docs
slugs/redirects for hexclave-app/use-hexclave-app.
- Brand strings/prompts: reworded remaining “Stack” dashboard strings to
Hexclave; updated dev-tool copy and prompts; `doctor/init` now prefer
`hexclave.config.ts`. Kept all wire-compat identifiers and public
aliases (`x-stack-*`, `stack-*` cookies, `STACK_*` env,
`*.stack-auth.com`, `Stack*` SDK names).
- Rebased/merged onto latest `dev`: retained `@hexclave/template`, kept
`src` in published files, refreshed setup-prompt imports and docs JSON,
adopted 1.0.5 version bumps, and re-merged `dev` again (resolved
`create-purchase-url` with `getHexclaveStripe`).
- **Bug Fixes**
- Restored dashboard AI type bundle by pointing the glob to
`packages/template/src/lib/hexclave-app`.
- Addressed rename leftovers: updated lingering `@/stack` imports and
CSS selector, fixed schema/meta and port-prefix expansions, and aligned
emulator commands to `packages/cli`.
- CI/build: removed a dead env var and stale ignore entries; fixed
Docker by renaming `STACK_SKIP_TEMPLATE_GENERATION` →
`HEXCLAVE_SKIP_TEMPLATE_GENERATION`.
<sup>Written for commit 3c1af3bff3.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1547?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
isVersionNewer/parseVersionCore no longer gate the npx re-exec (which
always runs @latest); their only remaining consumer is the dashboard
restart check in dev.ts. Move them (and their tests) there so
self-update.ts is purely about the re-exec.
## What
Continues the **Stack Auth → Hexclave** rename for a set of safe,
internal-only surfaces. This intentionally avoids public-contract names.
### Changes
- **Examples** — renamed the user-facing config module
`stack.ts`/`stack.tsx` (and the `convex` / `lovable` `stack/`
directories) to `hexclave`, and updated every importer across
`.ts`/`.tsx`/`.jsx`. The public `app/handler/[...stack]/` route segment
is left unchanged.
- **apps/{dashboard,backend,internal-tool}** — renamed app-local
SDK-init symbols `stackClientApp → hexclaveClientApp` and
`getStackServerApp → getHexclaveServerApp`, and the dashboard
`StackCompanion` component → `HexclaveCompanion` (incl.
`useStackCompanion`, context types). The public
`StackClientApp`/`StackServerApp` SDK classes are **unchanged**.
- **packages/stack-shared** — added comments to the crypto / JWT / vault
`stack-*` literals documenting that they must **not** be renamed (key
derivation / JWKS / KMS-alias stability). The literals are
byte-identical.
### Deliberately excluded
- **`STACK_*` → `HEXCLAVE_*` env-var rename** — `HEXCLAVE_*` already
resolves via the dual-read layers (SDK env, dashboard `_inlineEnvVars`,
`getEnvVariable`). The remaining holdout is the docker post-build
sentinel path, which the codebase authors explicitly deferred and which
is tightly coupled to `entrypoint.sh` + untestable here. A blind rename
there risks silently breaking self-host/emulator bootstrap for ~zero
functional gain.
- **All public-contract names** — SDK class names, env vars, HTTP
headers (`x-stack-*`), and the `/handler` route convention.
## Verification
- `pnpm lint` — **29/29 passing**.
- `pnpm typecheck` — **28/29 passing**; the only failure is
`@hexclave/docs` (pre-existing missing fumadocs `.source` codegen,
untouched by this PR).
- Two rounds of adversarial multi-agent review; findings fixed:
string-literal collateral from the symbol sweep (CLI test fixtures + an
AI-prompt template) reverted, and a missed `.jsx` importer in
`examples/cjs-test` corrected.
## Notes
- Based on a `dev` snapshot from when the branch was cut (a couple
commits behind tip); the diff contains only the changes above.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Complete the internal “Stack” → “Hexclave” rename across examples,
app-local code, config tooling, and setup docs, and standardize env
output to HEXCLAVE_* with correct default API URL handling. Public SDK
classes, handler routes, and legacy env names keep working.
- **Refactors**
- Examples/config: `stack.*` files and `stack/` dirs →
`hexclave.*`/`hexclave/`; imports updated; keep `app/handler/[...stack]`
route.
- Apps: backend/dashboard/internal-tool now use `getHexclaveServerApp`
and `hexclaveClientApp`; dashboard `StackCompanion` →
`HexclaveCompanion`. Public `StackClientApp`/`StackServerApp` unchanged.
- Env/setup: Next.js and CLI generators write HEXCLAVE_* and omit API
URL when using https://api.stack-auth.com; CLI `doctor` and auth
resolution prefer HEXCLAVE_* (e.g. `HEXCLAVE_SECRET_SERVER_KEY`,
`HEXCLAVE_PROJECT_ID`) with `STACK_*` fallback.
- Config tooling: `stack-config-file` → `hexclave-config-file`, emitting
`HexclaveConfig`; imports updated across backend/dashboard/tooling.
- Shared/docs: added “do not rename” notes for crypto/JWT/vault
`stack-*` literals; regenerated setup prompt/docs to use
`hexclave.config.ts`, `hexclave dev`, and `src/hexclave/`.
- Tests: updated snapshots/assertions to expect `HexclaveConfig` and
HEXCLAVE_* env names.
- **Migration**
- No action required. SDK and CLI read both HEXCLAVE_* and STACK_*.
<sup>Written for commit 8a891b4f6c.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1534?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Renamed internal app/client/server instances and companion/provider
components to the new product name across backend, dashboard, examples,
and tooling; imports updated accordingly.
* Updated generated environment variable names and CLI init/doctor
outputs to prefer the new product prefix.
* **Documentation**
* Added clarifying notes about vault/encryption and JWT/key labels to
avoid breaking existing encrypted data.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Address PR review feedback on the RDE CLI self-update:
- shouldAutoUpdate no longer skips CI, so the version that runs in CI
matches what developers run locally.
- Re-exec always runs npx <pkg>@latest guarded by SKIP_AUTO_UPDATE_ENV
instead of fetching/comparing versions. Removes the registry lookup,
version comparison, and the now-orphaned cliUpdateCheck cache in
dev-env-state. isVersionNewer is kept for the dashboard restart check.
## Problem
`pnpx @hexclave/cli <cmd>` (i.e. `pnpm dlx`) fails, even though `npx
@hexclave/cli <cmd>` works.
## Root cause
`@hexclave/cli` exposed **two** bins — `hexclave` and `stack` — and
neither matches the package's unscoped name (`@hexclave/cli` → `cli`).
When a package has multiple bins and none matches the unscoped name, the
two runners diverge:
- **npx** silently picks the *first* bin and runs it → worked by luck.
- **pnpm dlx / pnpx** refuses to guess and errors:
```
ERR_PNPM_DLX_MULTIPLE_BINS Could not determine executable to run.
@hexclave/cli has multiple binaries: hexclave, stack
```
Reproduced and verified offline with a throwaway 2-bin package; also
verified that a **single**-bin package auto-resolves under both `npx`
and `pnpm dlx` even when the bin name doesn't match the unscoped package
name.
## Fix
Drop the `stack` bin, leaving a single `hexclave` bin → both `npx` and
`pnpm dlx`/`pnpx` resolve it unambiguously. Follow-through to keep the
CLI self-consistent:
- `resolveBinName` now prefers `hexclave` for the npx self-update
re-exec, so auto-update targets a bin guaranteed to exist in `@latest`
(it previously hard-preferred `stack`).
- Program name (`--help` usage) `stack` → `hexclave`.
- User-facing `stack <cmd>` guidance strings (in error messages / tips
across `auth`, `init`, `dev`, `config-file`, `exec`, `project`,
`doctor`, `local-emulator-client`) → `hexclave <cmd>`, so the CLI never
points users at a command that no longer exists.
- Unit test updated for the new bin preference.
## ⚠️ Breaking-change note
This drops the `stack` command. Fresh `npx`/`pnpx` users are unaffected,
but anyone with an *older* version installed loses the `stack` bin on
upgrade. Subtly, a stale install's auto-update re-execs `npx -p
@hexclave/cli@latest stack …` (its baked-in logic prefers `stack`); once
`@latest` drops the `stack` bin that one re-exec fails for those stale
installs. If we want a deprecation window, we can keep `stack` as a bin
for a release instead.
## Testing
- `pnpm lint` ✅
- `pnpm typecheck` ✅
- `pnpm test` (stack-cli) ✅ 148/148 (pure unit tests, no backend
required)
> Stacked on top of `rde-cli-auto-update` —
`resolveBinName`/`self-update.ts` only exist on that branch, so this
targets it rather than `dev`.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Ship a single `hexclave` bin for `@hexclave/cli` so `pnpx`/`pnpm dlx`
resolve the executable reliably. The CLI now uses `hexclave` as the
canonical command, including self-update re-execs.
- **Bug Fixes**
- Dropped the `stack` bin; kept only `hexclave`, fixing
ERR_PNPM_DLX_MULTIPLE_BINS when running `pnpx @hexclave/cli <cmd>`.
- `resolveBinName` now prefers `hexclave`; program name, help, and error
messages updated; tests adjusted.
- **Migration**
- The `stack` command is removed. Use `hexclave <cmd>`. Older installs
that re-exec `stack` may fail; run `npx -p @hexclave/cli@latest hexclave
...` or reinstall.
<sup>Written for commit bf5d6ac727.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1533?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
Reconcile dev's per-port dashboard model (localDashboardsByPort, configurable
NEXT_PUBLIC_HEXCLAVE_LOCAL_DASHBOARD_PORT, JSON /api/development-environment/health
probe) with this branch's auto-update + version-based restart feature:
- dev-env-state: add version? to the per-port LocalDashboardState; keep the
cliUpdateCheck cache; validate each per-port entry on read (drops a malformed
entry, e.g. non-string version, so it never reaches parseVersionCore);
recordLocalDashboardProcess regains its version arg.
- dev.ts: keep shouldRestartDashboard/processExists/killLocalDashboard and the
version-based restart, adapted to read pid/version per-port; killLocalDashboard
now takes (url, port); recordLocalDashboardProcess records cliVersion().
- tests updated to the per-port model.
Address PR #1521 review:
- dev-env-state: validate localDashboard on read (mirroring the
cliUpdateCheck cache). A hand-edited/cross-version state file with a
non-string version reached parseVersionCore (version.trim()) via
shouldRestartDashboard -> isVersionNewer inside startDashboardIfNeeded,
which is outside the auto-update fail-open guard and would crash
`stack dev`. Malformed records are now treated as 'no dashboard'.
- self-update: re-exec via npx.cmd on Windows now spawns with shell:true.
After CVE-2024-27980 Node throws EINVAL spawning a .cmd directly without
a shell, so the auto-update re-exec silently never ran on Windows. args
stay a clean argv array; runReexec quotes them for the shell at spawn
time so paths/args with spaces survive.
## Why the build fails on `origin/dev`
The `Lint & build` workflow fails at the **Build** step, in
`@hexclave/lovable-react-18-example`'s `vite build`:
```
[vite]: Rollup failed to resolve import "@stackframe/stack-shared/dist/utils/globals"
from ".../packages/react/dist/esm/providers/stack-context.js".
```
(failing run: [job
78596906597](https://github.com/hexclave/stack-auth/actions/runs/26665187298/job/78596906597))
### Root cause
PR 3 (`feat(hexclave): PR 3 — native @hexclave/* source rename + delete
dual-publish wiring`, #1482) renamed `@stackframe/stack-shared` →
`@hexclave/shared` and **deleted the dual-publish wiring**, so
`@stackframe/stack-shared` is no longer a resolvable package.
Two `packages/template/src` provider files were missed in that rename:
- `packages/template/src/providers/stack-context.tsx`
- `packages/template/src/providers/translation-provider-client.tsx`
`packages/react` ships only `package.json`; its `src`/`dist` are
**generated** from `packages/template/src` by `generate-sdks`, which
copies import specifiers verbatim. So the stale
`@stackframe/stack-shared` import propagated into `packages/react/dist`.
The `@hexclave/react` build itself **succeeds** because tsdown/rolldown
externalizes the import (it never has to resolve it). The failure only
surfaces downstream, when `lovable-react-18-example` bundles
`@hexclave/react` with Vite/Rollup and tries to actually resolve
`@stackframe/stack-shared` — a package that no longer exists.
## Fix
Point both imports at the renamed package, matching the convention
already used by sibling files (e.g. `stack-provider-client.tsx`,
`common.ts`):
```diff
-import { createGlobal } from "@stackframe/stack-shared/dist/utils/globals";
+import { createGlobal } from "@hexclave/shared/dist/utils/globals";
```
## Verification
Reproduced and confirmed the fix locally:
1. Edited the two template files.
2. `pnpm -w run generate-sdks` → generated `packages/react/src` now
imports `@hexclave/shared/dist/utils/globals`.
3. `pnpm --filter @hexclave/react run build` →
`dist/esm/providers/stack-context.js` now imports `@hexclave/shared` ✔
4. `pnpm --filter @hexclave/lovable-react-18-example run build` → **`✓
built`** (previously failed at this exact step).
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Rename leftover imports from `@stackframe/stack-shared` to
`@hexclave/shared` in the template providers to fix downstream build
failures. This unblocks Vite/Rollup consumers (e.g.,
`@hexclave/lovable-react-18-example`) by resolving `createGlobal` from
the correct package.
<sup>Written for commit 15901edb2b.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/hexclave/stack-auth/pull/1525?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated internal module dependencies across provider configurations.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/hexclave/stack-auth/pull/1525?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
DB migration compat / Back-compat — Current branch migrations with ${{ needs.check-migrations-changed.outputs.base_branch }} branch code (push) Has been cancelled
DB migration compat / Forward-compat — Current branch code with ${{ needs.check-migrations-changed.outputs.base_branch }} branch migrations (push) Has been cancelled
Three unresolved review findings on the auto-update feature:
- killLocalDashboard (greptile P1): after SIGTERM, the wait loop gated on
processExists(pid), which false-positives if the dashboard exits and its pid
is recycled onto another same-user process — spinning the full timeout and
then SIGKILLing the unrelated process. Gate purely on the port being freed
(the property that actually lets the replacement bind). SIGKILL is now only
reached when the port is still occupied, i.e. the process is still up and the
pid is necessarily valid.
- dev-env-state (greptile P2): validate the on-disk cliUpdateCheck cache shape
on read; a non-string latestVersion would otherwise reach version parsing and
throw. Malformed entries are treated as "no cache".
- maybeReexecToLatest (cubic P2): documented "fail open" but readDevEnvState
could throw (corrupt/bad-permission state file) and crash `stack dev`. Wrap
the body in try/catch so any unexpected error falls through to the installed
CLI.
Tests: +4 — recycled-pid early-return without SIGKILL, malformed/well-formed
cache read, and fail-open on a corrupt state file. 170 pass.
We only ever invoke `npx` (the npm binary), whose cooldown config is
`min-release-age`. The camelCase `--minimum-release-age` is pnpm/bun's
spelling, and those aren't reached via npx (they use `pnpm dlx` / `bunx`),
so the extra flag was dead weight npm silently ignored. Keep only
`--min-release-age=0`.
The previous commit passed only `--minimum-release-age=0`, but npm's actual
config key is `min-release-age` (days, npm >=11.10.0) — CLI flag
`--min-release-age`. Pass that, plus the camelCase `--minimum-release-age=0`
defensively (the spelling pnpm/bun use, in case npx is shimmed). npm ignores
unrecognized config flags, so the extra one is harmless. Without the correct
flag, npx of a version newer than a user's global cooldown window fails with
ETARGET and would kill `stack dev`.
- buildNpxInvocation now passes `--minimum-release-age=0` so a user's global
`minimumReleaseAge` (npm's supply-chain cooldown, npm >=11.6.1) doesn't
block npx from fetching the just-published latest dashboard. Older npm
ignores the unknown flag. This is the only registry fetch via npx in the
flow — `resolveLatestVersion` hits the registry HTTP API directly (not
subject to the cooldown), and the other spawns run the user's own command
/ the bundled dashboard / local scripts.
- Remove the "A newer <pkg> is available..." log before re-exec.
Correctness:
- killLocalDashboard now waits for the process to actually exit (not just
for /health to stop answering) before returning, so the replacement
dashboard doesn't hit EADDRINUSE while the old socket is still held.
- Bail out without waiting/SIGKILL when the recorded pid is gone (ESRCH) or
owned by another process (EPERM, i.e. pid was recycled), avoiding a hang
and reducing the chance of signalling an unrelated process.
Quality / dedup:
- Extract shared helpers: lib/own-package.ts (single source for reading the
CLI's own package.json + bin resolution; now used by index.ts, sentry.ts,
self-update.ts — was duplicated 3x) and lib/child-process.ts
(forwardSignals, used by dev.ts, emulator.ts, self-update.ts).
- Extract pure decision functions for testability: decideReexec() and
shouldRestartDashboard()/processExists().
- Fix a stale comment that claimed jsdom is the test env (it's node).
Tests: +35 cases — decideReexec branches, resolveBinName/parseOwnPackage,
isVersionNewer edges (v-prefix, x.y, both-prerelease, large nums),
resolveLatestVersion (TTL boundary, malformed/non-string body, fetch URL,
npm_config_registry), buildNpxInvocation (windows, spaced/dashed args),
shouldRestartDashboard table, killLocalDashboard early returns,
dev-env-state back-compat + clobber. 167 pass.
Re-running `stack dev` / `hexclave dev` now picks up the latest published
dashboard without reinstalling the CLI. Before doing any work, the `dev`
command checks npm for a newer `@hexclave/cli` and, if found, re-execs
`npx <pkg>@<latest> stack dev ...` so the running code (and the dashboard
bundled in that tarball) is the latest. The user's installed dependency is
left untouched.
Because `stack dev` keeps a detached background dashboard alive across runs
and reuses it by default, the now-latest process also compares the running
dashboard's version against its own and restarts the stale one so the new
dashboard actually binds the port.
- self-update.ts: maybeReexecToLatest(), resolveLatestVersion() (TTL-cached
registry lookup, short timeout, offline-safe), isVersionNewer(),
buildNpxInvocation(). Loop guard via STACK_CLI_SKIP_AUTO_UPDATE; opt-outs
via STACK_CLI_NO_AUTO_UPDATE, --no-auto-update, and auto-skip in CI.
- dev.ts: re-exec at the top of the dev action; killLocalDashboard() +
version handshake in startDashboardIfNeeded; stamp CLI version when
recording the dashboard process; --no-auto-update flag.
- dev-env-state.ts: localDashboard.version + cliUpdateCheck cache helpers.
- Tests for self-update and the new dev-env-state fields.
Run generate-setup-prompt-docs to sync stale generated files with their
sources, fixing the 'Check for uncommitted changes' CI step:
- llms-full.txt / hexclave-agent-reminders.jsx: @hexclave/stack -> @hexclave/next
(reminders.ts already updated)
- docs-json.generated.ts: github URL hexclave/stack -> hexclave/hexclave
(docs.json already updated in 6a18fef9e)
Brings in #1499 (LLM metadata endpoints) and #1517 (logo SVG fixes).
Conflict resolution:
- apps/mcp/src/mcp-handler.ts: keep @hexclave/shared import, add dev's new
remindersPrompt import (renamed @stackframe/stack-shared -> @hexclave/shared).
- package.json: keep @hexclave/backend filter in generate-openapi-docs:watch;
take dev's broadened watch globs in generate-setup-prompt-docs:watch.
Re-applied the @stackframe/* -> @hexclave/* rename to dev's new code: the 10
new llms*.txt route files and the apps/skills workspace dep now import
@hexclave/shared. Lockfile reconciled. Lint 28/28, typecheck 28/28 green.