Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 73 additions & 66 deletions .claude/skills/dev-proxy-init/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: |
setup. Triggers on: "setup dev-proxy", "dev-proxy init", "dev-proxy setup",
"configure dev-proxy", "add dev-proxy", "initialize dev-proxy".
metadata:
version: 1.0.0
verified-against: "@reopt-ai/dev-proxy >= 1.2.0"
---

# dev-proxy-init Skill
Expand Down Expand Up @@ -61,20 +61,21 @@ array — these will be preserved. If this project's path is already in

### 1.4 Check for legacy project config

If `.dev-proxy.json` exists in the project root and contains a `routes` key
(or a `worktrees` key without a sibling `.dev-proxy.worktrees.json`), this is a
pre-split layout. Inform the user and suggest:
If `.dev-proxy.json` exists in the project root, this is a pre-migration
layout (current versions write `dev-proxy.config.mjs` and
`.dev-proxy.worktrees.json`; `.dev-proxy.json` is only read as a fallback).
Inform the user and suggest:

```bash
dev-proxy migrate
```

The command splits the legacy file three ways:
The command relocates every field out of the legacy file:

- `routes` → `dev-proxy.config.mjs`
- `worktrees` instance map → `.dev-proxy.worktrees.json` (new file, CLI-managed)
- `worktreeConfig` → stays in `.dev-proxy.json` (the legacy file is removed if
it would otherwise be empty)
- `worktreeConfig` → `dev-proxy.config.mjs` (same default export)
- `worktrees` instance map → `.dev-proxy.worktrees.json` (CLI-managed)
- `.dev-proxy.json` is deleted once empty

It is idempotent. If the user chooses to migrate, run the command, then
continue at Phase 3.3.
Expand Down Expand Up @@ -166,25 +167,27 @@ Is this correct? Would you like to add, remove, or change any routes?

## Phase 3: Generate Configuration

There are up to three project-level files:
There are two project-level files for new setups:

- **`dev-proxy.config.mjs`** — routes (the main config users edit by hand).
Always created by `dev-proxy init`.
- **`.dev-proxy.json`** — `worktreeConfig` schema (only required when worktrees
are used). Hand-edited.
- **`.dev-proxy.worktrees.json`** — CLI-managed worktree instance map. `init`
writes an empty placeholder; `dev-proxy worktree create/destroy/add/remove`
keep it in sync. **Do not hand-edit.**
- **`dev-proxy.config.mjs`** — hand-edited. Holds `routes` and (optionally)
`worktreeConfig`. `dev-proxy init` creates this if it doesn't exist (and
asks before overwriting).
- **`.dev-proxy.worktrees.json`** — CLI-managed worktree instance map.
`init` writes an empty placeholder; `dev-proxy worktree
create/destroy/add/remove` keep it in sync. **Do not hand-edit.**

All three are project configuration and should be committed to git.
Both should be committed to git.

> **Legacy `.dev-proxy.json`:** Older projects may still have this file. It
> is read as a fallback for `routes`, `worktreeConfig`, and `worktrees` when
> the newer files are absent. New setups should not create it — `dev-proxy
migrate` removes it once everything has been moved into the two files above.

> **Note on `.mjs` vs `.js`:** `dev-proxy init` writes `dev-proxy.config.mjs`
> by default. `dev-proxy.config.js` is also accepted (used in projects that
> already have `"type": "module"` in `package.json`). Both forms work the
> same way; pick one. Resolution order at runtime is `.mjs` → `.js` → legacy
> `.dev-proxy.json` for routes. The `worktrees` map is read from
> `.dev-proxy.worktrees.json` first, falling back to a `worktrees` key in
> the legacy `.dev-proxy.json` for projects mid-migration.
> `.dev-proxy.json`.

### 3.1 Global config (`~/.dev-proxy/config.json`)

Expand All @@ -208,11 +211,11 @@ Write `~/.dev-proxy/config.json`:
}
```

### 3.2 Project routes (`dev-proxy.config.mjs`)
### 3.2 Project config (`dev-proxy.config.mjs`)

This is the main configuration file — only routes go here. If
`dev-proxy.config.mjs` or `dev-proxy.config.js` already exists, ask the user
before overwriting.
This is the main configuration file. It holds **routes** and (optionally)
**worktreeConfig** in one default export. If `dev-proxy.config.mjs` or
`dev-proxy.config.js` already exists, ask the user before overwriting.

Create `dev-proxy.config.mjs` in the project root with the confirmed routes.
The format must match exactly:
Expand All @@ -238,45 +241,49 @@ Format rules:
- Include trailing commas
- JSDoc `@type` annotation enables IDE autocomplete via the exported `Config` type

> **Routes only.** Do not add `worktreeConfig` here. The runtime currently
> reads `worktreeConfig` from `.dev-proxy.json` only (see 3.3) — putting it
> in the `.mjs` file will silently do nothing and `dev-proxy worktree create`
> will fail with `worktreeConfig not configured in .dev-proxy.json`.
If the user also wants worktree support, see 3.3 — `worktreeConfig` is
added to the same default export.

### 3.3 Worktree config (`.dev-proxy.json`) and instance map (`.dev-proxy.worktrees.json`)
### 3.3 Worktree support (optional)

The two roles are now in two separate files:
For users who want `dev-proxy worktree create/destroy` to manage git
worktrees with auto-allocated ports, two pieces are required:

1. **`.dev-proxy.json`** holds `worktreeConfig` — user-authored worktree
settings (port range, directory pattern, services, hooks). Hand-edited.
Only required if the user wants worktree support.
2. **`.dev-proxy.worktrees.json`** holds the live `worktrees` instance map
that `dev-proxy worktree create/destroy/add/remove` rewrite. `dev-proxy
init` always creates this as `{ "worktrees": {} }` so the CLI commands
have a place to write to.
1. **`worktreeConfig`** — user-authored schema (port range, directory
pattern, services, hooks). Added to the `dev-proxy.config.mjs` default
export. Hand-edited.
2. **`.dev-proxy.worktrees.json`** live `worktrees` instance map that
`dev-proxy worktree create/destroy/add/remove` rewrite. `dev-proxy
init` always creates this as `{ "worktrees": {} }` so the CLI has a
place to write to.

If the user does not need worktree support, the empty
`.dev-proxy.worktrees.json` placeholder is enough — skip the rest of this
section. Do **not** create `.dev-proxy.json` in that case.
`.dev-proxy.worktrees.json` placeholder created by `init` is enough — skip
the rest of this section.

If the user **wants worktree support**, write `.dev-proxy.json`:
If the user **wants worktree support**, extend `dev-proxy.config.mjs`:

```json
{
"worktreeConfig": {
"portRange": [4101, 5000],
"directory": "../<project-name>-{branch}",
"services": {
"api": { "env": "API_PORT" },
"web": { "env": "PORT" }
```js
/** @type {import('@reopt-ai/dev-proxy').Config} */
export default {
routes: {
api: "http://localhost:4000",
web: "http://localhost:3001",
},
worktreeConfig: {
portRange: [4101, 5000],
directory: "../<project-name>-{branch}",
services: {
api: { env: "API_PORT" },
web: { env: "PORT" },
},
"envFile": ".env.local",
"hooks": {
envFile: ".env.local",
hooks: {
"post-create": "pnpm install",
"post-remove": "echo cleanup"
}
}
}
"post-remove": "echo cleanup",
},
},
};
```

Ask the user for:
Expand All @@ -287,9 +294,10 @@ Ask the user for:
- Post-create hook (e.g., `pnpm install`, `npm install`) — optional
- Post-remove hook — optional

Both files should be **committed to git**: `.dev-proxy.json` is hand-edited
schema and `.dev-proxy.worktrees.json` is shared worktree state teammates
need to share.
Both files should be **committed to git**: `dev-proxy.config.mjs` is
hand-edited config (routes + worktreeConfig) and
`.dev-proxy.worktrees.json` is shared worktree state teammates need to
share.

### 3.4 Framework-specific setup

Expand Down Expand Up @@ -437,11 +445,10 @@ Output the final setup summary:
```
dev-proxy setup complete!

Routes: <project-path>/dev-proxy.config.mjs
Worktree map: <project-path>/.dev-proxy.worktrees.json (CLI-managed)
Worktree config: <project-path>/.dev-proxy.json (only if worktrees enabled)
Global: ~/.dev-proxy/config.json
Domain: <domain>
Config: <project-path>/dev-proxy.config.mjs (routes + worktreeConfig)
Worktree map: <project-path>/.dev-proxy.worktrees.json (CLI-managed)
Global: ~/.dev-proxy/config.json
Domain: <domain>

Routes:
http://web.<domain>:3000 → localhost:3001
Expand All @@ -463,10 +470,10 @@ dev-proxy setup complete!
- Never run `sudo` commands without explicit user confirmation
- Always use `http://localhost:<port>` format for route targets (not bare ports)
- The `"*"` wildcard route is optional — only add if the user wants a fallback
- `dev-proxy.config.mjs` holds **routes only** — do not add `worktreeConfig` here (the runtime ignores it; worktree commands look in `.dev-proxy.json`)
- `.dev-proxy.json` holds **`worktreeConfig` only** (when worktrees are used) — not the live `worktrees` instance map
- `dev-proxy.config.mjs` holds **routes + (optional) `worktreeConfig`** in one default export
- `.dev-proxy.worktrees.json` holds the **CLI-managed `worktrees` instance map** — never hand-edit it; `dev-proxy worktree create/destroy/add/remove` keep it in sync
- All three files should be **committed to git** — they are shared project configuration teammates need
- If the project already has a `.dev-proxy.json` with routes or with a `worktrees` key sitting next to no `.dev-proxy.worktrees.json`, suggest running `dev-proxy migrate` — it splits routes into `.mjs`, `worktrees` into `.dev-proxy.worktrees.json`, leaves `worktreeConfig` in place, and removes `.dev-proxy.json` if nothing else remains
- Both files should be **committed to git** — they are shared project configuration teammates need
- Never create `.dev-proxy.json` for new setups — it is a read-only legacy fallback that `dev-proxy migrate` removes
- If the project already has a `.dev-proxy.json`, suggest running `dev-proxy migrate` — it moves `routes` and `worktreeConfig` into `dev-proxy.config.mjs`, `worktrees` into `.dev-proxy.worktrees.json`, and deletes the legacy file
- Never modify the user's application code, `.env` files, or `package.json`
- Always confirm the proposed route map before writing any files
77 changes: 60 additions & 17 deletions .claude/skills/dev-proxy-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: |
Triggers on: "dev-proxy review", "release review", "pre-release check",
"review", "publish review".
metadata:
version: 2.0.0
verified-against: "@reopt-ai/dev-proxy >= 1.2.0"
internal: true
---

Expand Down Expand Up @@ -59,19 +59,39 @@ If it crashes or prints nothing, the build is broken.
npm pack --dry-run
```

Confirm the output includes exactly these entries:
`package.json` uses a `files` whitelist — only entries listed there are
shipped. Cross-reference:

- `bin/dev-proxy.js`
- `dist/**/*.js` (compiled source)
- `LICENSE`
- `README.md`
- `README_KO.md`
- `package.json`
```bash
jq -r '.files[]' package.json
```

Every glob in `files` must appear in `npm pack` output, and nothing else
(no `src/`, `node_modules/`, `.github/`, test files, `tsconfig*.json`,
`.releaserc.json`). Check the total package size is reasonable (under 150 kB).

### 1.5 Verify semantic-release configuration

```bash
cat .releaserc.json
ls .github/workflows/release.yml
```

Confirm:

It must NOT include: `src/`, `node_modules/`, `.github/`, test files, `tsconfig*.json`.
Check the total package size is reasonable (under 150 kB).
- `.releaserc.json` lists `@semantic-release/commit-analyzer`,
`@semantic-release/release-notes-generator`, `@semantic-release/npm`,
`@semantic-release/exec` (GitHub Packages mirror publish), and
`@semantic-release/github` plugins in that order
- `branches` is `["main"]`
- `.github/workflows/release.yml` contains a `pnpm exec semantic-release`
step with `packages: write` permission (mirror publish needs it)

### 1.5 Clean working tree
If any plugin is missing or misordered, stop and fix before continuing —
release will partially succeed and leave npmjs.org / GitHub Packages out
of sync.

### 1.6 Clean working tree

```bash
git status
Expand Down Expand Up @@ -120,7 +140,7 @@ Read `docs/guide/installation.md`. Verify:
- Config JSON examples match the `RawGlobalConfig` and `RawProjectConfig` interfaces in `src/cli/config-io.ts`
- `worktreeConfig` example matches the `WorktreeConfig` interface
- All CLI commands referenced actually exist
- The three project config files (`dev-proxy.config.mjs` for routes, `.dev-proxy.json` for `worktreeConfig`, `.dev-proxy.worktrees.json` for the CLI-managed worktree instance map) are described accurately and consistently with `PROJECT_CONFIG_NAME` / `PROJECT_WORKTREES_NAME` in `src/proxy/config.ts`
- The two project files for new setups (`dev-proxy.config.mjs` for routes + `worktreeConfig`, `.dev-proxy.worktrees.json` for the CLI-managed worktree instance map) are described accurately and consistently with `JS_CONFIG_NAMES` / `PROJECT_WORKTREES_NAME` in `src/proxy/config.ts`. `.dev-proxy.json` should be described as a legacy read-only fallback only (deleted by `dev-proxy migrate`)

### 2.5 Help text

Expand Down Expand Up @@ -148,7 +168,17 @@ Every commit must follow `<type>(<scope>): <subject>`. Verify:
- Breaking changes use `!` suffix (e.g., `feat!: ...`)
- No commits violate the convention (semantic-release ignores non-conforming commits)

### 3.3 Preview release impact
### 3.3 Detect explicit breaking changes

```bash
git log $(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~20)..HEAD --grep="BREAKING CHANGE" --format="%h %s"
```

If anything prints, the next release will be a **major** bump even if all
commit subjects look like patches. Confirm this with the user before
pushing.

### 3.4 Preview release impact

Based on commit types, inform the user what semantic-release will do:

Expand Down Expand Up @@ -183,27 +213,40 @@ git push origin main
### 4.3 Wait for CI

```bash
gh run list --branch main --limit 1 --json status,conclusion,name
gh run list --branch main --workflow release.yml --limit 1 --json status,conclusion,name
```

The latest run must show `"conclusion": "success"`. If it shows `"status": "in_progress"`, wait and re-check:
The latest `release.yml` run must show `"conclusion": "success"`. If it
shows `"status": "in_progress"`, wait and re-check:

```bash
gh run watch
```

**If CI fails, investigate the failure before retrying.**
**If CI fails, investigate the failure before retrying.** Common
failures: `@semantic-release/exec` mirror publish (GitHub Packages
authentication or missing `packages: write` permission). The mirror is
fail-soft — npmjs.org release still succeeds, but verify both targets in
step 4.4.

### 4.4 Verify release was created

If releasable commits were present:

```bash
npm view @reopt-ai/dev-proxy version
npm view @reopt-ai/dev-proxy version --registry=https://npm.pkg.github.com
gh release list --limit 1
```

Confirm the new version matches the expected bump from step 3.3.
Confirm:

- Both registries report the new version
- The GitHub Release exists with the same tag
- The new version matches the expected bump from step 3.4

If the GitHub Packages mirror lags behind npmjs.org, check the
`@semantic-release/exec` step in the release workflow logs.

### 4.5 Print summary

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Split happens at store ingress (`pushHttp`/`pushWs`). Events are immutable after

**Proxy flow**: `createProxyServer()` → emitter fires `request` / `request:complete` / `request:error` / `ws` → store receives via `pushHttp`/`pushWs` → React renders via snapshot.

**Config**: `~/.dev-proxy/config.json` (global: domain, ports, TLS, `projects` array) → each project's `dev-proxy.config.mjs` (routes + `worktreeConfig`) plus `.dev-proxy.worktrees.json` (CLI-managed worktree instance map). Legacy `.dev-proxy.json` (pre-`migrate`) is still read with the new file taking precedence. No cwd-based search — projects are explicitly registered.
**Config**: `~/.dev-proxy/config.json` (global: domain, ports, TLS, `projects` array) → each project's `dev-proxy.config.mjs` (routes + `worktreeConfig`) plus `.dev-proxy.worktrees.json` (CLI-managed worktree instance map). Legacy `.dev-proxy.json` (pre-`migrate`) is still read as a fallback for both `routes` and `worktreeConfig` — the mjs file wins when both define the same key, and `dev-proxy migrate` deletes the legacy file once everything has moved. No cwd-based search — projects are explicitly registered.

**Routing**: `host.split(".")[0]` extracts subdomain → exact match in merged routes → `"*"` wildcard fallback → `null` (502). Worktree syntax: `branch--app.domain` → lookup in project worktrees → unregistered = offline error page (no silent fallback).

Expand Down
Loading