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
32 changes: 23 additions & 9 deletions plugins/dev3000/.agents/skills/d3k/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,45 +19,59 @@ When this skill triggers, operate d3k. Do not merely tell the user how to run it

Run from the project root.

1. Check for an existing project runtime:
1. Check canonical Portless readiness before starting any app process:

```bash
d3k portless status --json
```

If `"setupRequired": true`, run:

```bash
d3k portless setup
```

On macOS this opens the system administrator authorization dialog. Wait for the user to approve it, then rerun `d3k portless status --json`. Do not start d3k until `"canonical": true`, `"serviceInstalled": true`, and `"setupRequired": false`. If authorization is declined or unavailable, stop and explain the blocker. Never silently substitute direct localhost.

2. Check for an existing project runtime:

```bash
d3k status --json
```

If it reports `"running": true`, reuse it. Do not start a second dev server or browser.
Reuse it only if it reports `"running": true`, `"ready": true`, `"routing": "portless"`, `"browserConnected": true`, and a genuinely port-free `https://...localhost` `appUrl`. If an active session reports `"routing": "direct"`, stop that retained d3k session and restart after Portless is ready. Do not start a second dev server or browser.

2. If d3k is not installed, install it:
3. If d3k is not installed, install it:

```bash
bun install -g dev3000
```

Use `npm install -g dev3000` only when Bun is unavailable.

3. Start d3k with the agent's shell/process tool as a retained background or yielded session:
4. Start d3k with the agent's shell/process tool as a retained background or yielded session (non-TUI by default):

```bash
d3k --no-agent --no-tui -t
d3k -t
```

Do not wait for this long-running command to exit. Keep its process/session handle so you can monitor or stop it later. Prefer the execution tool's background/session support over shelling with `&`.

If the target URL is already known, pass it so the managed browser opens there:

```bash
d3k --no-agent --no-tui -t --app-url "<url>"
d3k -t --app-url "<url>"
```

Let d3k auto-detect the package manager, dev command, and port. Add `--command`, `--script`, or `--port` only when detection is wrong or the user specified them.

4. Poll until the runtime is ready:
5. Poll until the runtime is ready:

```bash
d3k status --json
```

A successful status response is the readiness boundary. Prefer the reported Portless `appUrl`; the underlying app port may change between runs. If startup fails, inspect the retained process output and `d3k logs --type server`; do not launch a separate dev server.
A successful status response is the readiness boundary only when it reports `"ready": true`, `"routing": "portless"`, `"browserConnected": true`, and a port-free `https://...localhost` `appUrl`. The underlying app port may change between runs. If startup fails, inspect the retained process output and `d3k logs --type server`; do not launch a separate dev server.

## User-Driven Testing

Expand Down Expand Up @@ -125,4 +139,4 @@ Use `--headless` only for CI or when explicitly requested. Use `--servers-only`
- Keep d3k alive across edits and retests.
- Preserve the project-stable Chrome profile unless the user explicitly asks for a fresh profile.
- Leave the runtime running when handing a headed browser to the user; stop it only when asked or when the task requires a clean restart.
- Portless routing is the default. Use `--no-portless` or `PORTLESS=0` only when direct localhost routing is explicitly required.
- Canonical Portless HTTPS routing is required by default. Never add `--no-portless` or set `PORTLESS=0` unless the user explicitly requests direct localhost routing.
32 changes: 23 additions & 9 deletions plugins/dev3000/agent/skills/d3k/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,45 +17,59 @@ When this skill triggers, operate d3k. Do not merely tell the user how to run it

Run from the project root.

1. Check for an existing project runtime:
1. Check canonical Portless readiness before starting any app process:

```bash
d3k portless status --json
```

If `"setupRequired": true`, run:

```bash
d3k portless setup
```

On macOS this opens the system administrator authorization dialog. Wait for the user to approve it, then rerun `d3k portless status --json`. Do not start d3k until `"canonical": true`, `"serviceInstalled": true`, and `"setupRequired": false`. If authorization is declined or unavailable, stop and explain the blocker. Never silently substitute direct localhost.

2. Check for an existing project runtime:

```bash
d3k status --json
```

If it reports `"running": true`, reuse it. Do not start a second dev server or browser.
Reuse it only if it reports `"running": true`, `"ready": true`, `"routing": "portless"`, `"browserConnected": true`, and a genuinely port-free `https://...localhost` `appUrl`. If an active session reports `"routing": "direct"`, stop that retained d3k session and restart after Portless is ready. Do not start a second dev server or browser.

2. If d3k is not installed, install it:
3. If d3k is not installed, install it:

```bash
bun install -g dev3000
```

Use `npm install -g dev3000` only when Bun is unavailable.

3. Start d3k with the agent's shell/process tool as a retained background or yielded session:
4. Start d3k with the agent's shell/process tool as a retained background or yielded session (non-TUI by default):

```bash
d3k --no-agent --no-tui -t
d3k -t
```

Do not wait for this long-running command to exit. Keep its process/session handle so you can monitor or stop it later. Prefer the execution tool's background/session support over shelling with `&`.

If the target URL is already known, pass it so the managed browser opens there:

```bash
d3k --no-agent --no-tui -t --app-url "<url>"
d3k -t --app-url "<url>"
```

Let d3k auto-detect the package manager, dev command, and port. Add `--command`, `--script`, or `--port` only when detection is wrong or the user specified them.

4. Poll until the runtime is ready:
5. Poll until the runtime is ready:

```bash
d3k status --json
```

A successful status response is the readiness boundary. Prefer the reported Portless `appUrl`; the underlying app port may change between runs. If startup fails, inspect the retained process output and `d3k logs --type server`; do not launch a separate dev server.
A successful status response is the readiness boundary only when it reports `"ready": true`, `"routing": "portless"`, `"browserConnected": true`, and a port-free `https://...localhost` `appUrl`. The underlying app port may change between runs. If startup fails, inspect the retained process output and `d3k logs --type server`; do not launch a separate dev server.

## User-Driven Testing

Expand Down Expand Up @@ -123,4 +137,4 @@ Use `--headless` only for CI or when explicitly requested. Use `--servers-only`
- Keep d3k alive across edits and retests.
- Preserve the project-stable Chrome profile unless the user explicitly asks for a fresh profile.
- Leave the runtime running when handing a headed browser to the user; stop it only when asked or when the task requires a clean restart.
- Portless routing is the default. Use `--no-portless` or `PORTLESS=0` only when direct localhost routing is explicitly required.
- Canonical Portless HTTPS routing is required by default. Never add `--no-portless` or set `PORTLESS=0` unless the user explicitly requests direct localhost routing.
2 changes: 1 addition & 1 deletion plugins/dev3000/skills-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"source": "vercel-labs/dev3000",
"sourceType": "github",
"skillPath": "skills/d3k/SKILL.md",
"computedHash": "6462ff3b28aaec3ba02f8419e4a6faace3ccb69165bf0da8f55a7da93393e2d3"
"computedHash": "b8604d8dcb3136f9d04a3a0ec02962380d0260c7b7ffc321ca90e8d5569e2b8d"
}
}
}
2 changes: 1 addition & 1 deletion plugins/emulate/.agents/skills/emulate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ const kvAdapter: PersistenceAdapter = {
}
```

State is loaded on cold start and saved after every mutating request (POST, PUT, PATCH, DELETE). Saves are serialized to prevent race conditions.
State is loaded on cold start and saved after every mutating request (POST, PUT, PATCH, DELETE). Saves are serialized to prevent race conditions. Generated GitHub App identities require `initialize` to atomically create the initial value or return the value another instance created first.

## Architecture

Expand Down
2 changes: 2 additions & 0 deletions plugins/emulate/.agents/skills/github/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ const privateKey = github.generatedSecrets.find(

The key remains stable across `github.reset()`. Explicit keys are not included in `generatedSecrets`.

The Next.js and Nuxt adapters also generate omitted keys. Retain the returned handler and call its server-only `generatedSecrets()` method. With persistence configured, the identity survives cold starts. Keep snapshots private because they contain the signing key, and require custom persistence backends to implement atomic `initialize()` semantics.

For the CLI, omit `private_key` only when requesting a private delivery file:

```bash
Expand Down
7 changes: 5 additions & 2 deletions plugins/emulate/.agents/skills/next/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ import { filePersistence } from '@emulators/core'
persistence: filePersistence('.emulate/state.json'),
```

GitHub App seeds may omit `private_key`. Retain the handler and call server-only `generatedSecrets()`; explicit keys are excluded. Keep persisted snapshots private and implement `initialize` atomically.

### How Persistence Works

- **Cold start**: The adapter loads state from the persistence adapter. If found, it restores the full Store and token map (skipping seed). If not found, it seeds from config and saves the initial state.
Expand All @@ -140,7 +142,7 @@ persistence: filePersistence('.emulate/state.json'),
## Limitations

- Requires the Node.js runtime (not Edge) since emulators use `crypto.randomBytes`
- Concurrent serverless instances writing to the same persistence adapter use last-write-wins semantics (acceptable for dev/preview traffic)
- Concurrent mutations use last-write-wins semantics. Generated identities require `initialize` to select the initial snapshot atomically across cold starts.

## Config Reference

Expand Down Expand Up @@ -172,7 +174,8 @@ Wraps a Next.js config to include emulator font files in the serverless output t
interface PersistenceAdapter {
load(): Promise<string | null>
save(data: string): Promise<void>
initialize?(data: string): Promise<string>
}
```

The built-in `filePersistence(path)` from `@emulators/core` provides a file-based adapter for local development.
`initialize` must atomically create the initial value or return the value another instance created first. Implement it with compare-and-set semantics such as Redis `SET NX`. The built-in `filePersistence(path)` from `@emulators/core` provides this behavior for local development.
2 changes: 1 addition & 1 deletion plugins/emulate/agent/skills/emulate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ const kvAdapter: PersistenceAdapter = {
}
```

State is loaded on cold start and saved after every mutating request (POST, PUT, PATCH, DELETE). Saves are serialized to prevent race conditions.
State is loaded on cold start and saved after every mutating request (POST, PUT, PATCH, DELETE). Saves are serialized to prevent race conditions. Generated GitHub App identities require `initialize` to atomically create the initial value or return the value another instance created first.

## Architecture

Expand Down
2 changes: 2 additions & 0 deletions plugins/emulate/agent/skills/github/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ const privateKey = github.generatedSecrets.find(

The key remains stable across `github.reset()`. Explicit keys are not included in `generatedSecrets`.

The Next.js and Nuxt adapters also generate omitted keys. Retain the returned handler and call its server-only `generatedSecrets()` method. With persistence configured, the identity survives cold starts. Keep snapshots private because they contain the signing key, and require custom persistence backends to implement atomic `initialize()` semantics.

For the CLI, omit `private_key` only when requesting a private delivery file:

```bash
Expand Down
7 changes: 5 additions & 2 deletions plugins/emulate/agent/skills/next/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ import { filePersistence } from '@emulators/core'
persistence: filePersistence('.emulate/state.json'),
```

GitHub App seeds may omit `private_key`. Retain the handler and call server-only `generatedSecrets()`; explicit keys are excluded. Keep persisted snapshots private and implement `initialize` atomically.

### How Persistence Works

- **Cold start**: The adapter loads state from the persistence adapter. If found, it restores the full Store and token map (skipping seed). If not found, it seeds from config and saves the initial state.
Expand All @@ -137,7 +139,7 @@ persistence: filePersistence('.emulate/state.json'),
## Limitations

- Requires the Node.js runtime (not Edge) since emulators use `crypto.randomBytes`
- Concurrent serverless instances writing to the same persistence adapter use last-write-wins semantics (acceptable for dev/preview traffic)
- Concurrent mutations use last-write-wins semantics. Generated identities require `initialize` to select the initial snapshot atomically across cold starts.

## Config Reference

Expand Down Expand Up @@ -169,7 +171,8 @@ Wraps a Next.js config to include emulator font files in the serverless output t
interface PersistenceAdapter {
load(): Promise<string | null>
save(data: string): Promise<void>
initialize?(data: string): Promise<string>
}
```

The built-in `filePersistence(path)` from `@emulators/core` provides a file-based adapter for local development.
`initialize` must atomically create the initial value or return the value another instance created first. Implement it with compare-and-set semantics such as Redis `SET NX`. The built-in `filePersistence(path)` from `@emulators/core` provides this behavior for local development.
10 changes: 5 additions & 5 deletions plugins/emulate/skills-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
"source": "vercel-labs/emulate",
"sourceType": "github",
"skillPath": "skills/emulate/SKILL.md",
"computedHash": "9f490bb96968516335972dc0df78fcd7b75025aab169a6bea24c2f9f4e63987e"
"computedHash": "e0a7a8e5a53676aa84fe1fd8bfdd9b59e78e48a681937560586593d2a8497bc4"
},
"github": {
"source": "vercel-labs/emulate",
"sourceType": "github",
"skillPath": "skills/github/SKILL.md",
"computedHash": "ae3920ffad035acdd71b0764015bc9401223197788092efb0be6a5edb7210fa6"
"computedHash": "04cf1a03b3a1b88315d37216079ee43f2f4b430e2f6e1ca05f5f3b4c253c62a8"
},
"google": {
"source": "vercel-labs/emulate",
Expand All @@ -47,7 +47,7 @@
"source": "vercel-labs/emulate",
"sourceType": "github",
"skillPath": "skills/next/SKILL.md",
"computedHash": "105094c96ab29d6e081554c77bf30fe4393a81d91ddca385f215e09899af8a48"
"computedHash": "77d33a4cb9f9903f337c0e90b28104f53d4a552537273198e4c64ec8266bc3ee"
},
"resend": {
"source": "vercel-labs/emulate",
Expand All @@ -65,13 +65,13 @@
"source": "vercel-labs/emulate",
"sourceType": "github",
"skillPath": "skills/stripe/SKILL.md",
"computedHash": "d2e822c16e3e7698b719e9dd06e21ed1019cc37a62e29c1b51718da838ee106d"
"computedHash": "b429538af7b5c52e8350970d767c02e4c53c3f70baf8af4b7503674d5b334198"
},
"vercel": {
"source": "vercel-labs/emulate",
"sourceType": "github",
"skillPath": "skills/vercel/SKILL.md",
"computedHash": "3cd45b301312b61ce4663a1d8ec1f55daed567470cd62cee77f65a43a9d56905"
"computedHash": "75f252a2d7e42886373f960bbe2c4ca95309cdf7425b6e8cfb0cf980f31132e9"
}
}
}
6 changes: 5 additions & 1 deletion plugins/portless/.agents/skills/portless/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ Set `PORTLESS=0` to run the command directly without the proxy:
PORTLESS=0 pnpm dev # Bypasses proxy, uses default port
```

When a proxied command is stopped with Ctrl+C, portless waits for its process tree to exit. A second
Ctrl+C forwards another interrupt, and remaining descendants are terminated after a short grace
period.

## How It Works

1. `portless proxy start` starts an HTTPS reverse proxy on port 443 as a background daemon. Auto-elevates with sudo on macOS/Linux; falls back to port 1355 if sudo is unavailable. Use `--no-tls` for plain HTTP on port 80. Configurable with `-p` / `--port` or the `PORTLESS_PORT` env var. The proxy also auto-starts when you run an app.
Expand Down Expand Up @@ -411,7 +415,7 @@ portless hosts sync # Adds current routes to /etc/hosts
portless hosts clean # Remove entries later
```

Auto-syncs `/etc/hosts` for route hostnames by default. Set `PORTLESS_SYNC_HOSTS=0` to disable.
Auto-syncs `/etc/hosts` for route hostnames by default. Set `PORTLESS_SYNC_HOSTS=0` to disable. If a route hostname will not resolve, the command that registered it warns and points you to `portless hosts sync`.

### Browser shows certificate warning with --https

Expand Down
6 changes: 5 additions & 1 deletion plugins/portless/agent/skills/portless/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ Set `PORTLESS=0` to run the command directly without the proxy:
PORTLESS=0 pnpm dev # Bypasses proxy, uses default port
```

When a proxied command is stopped with Ctrl+C, portless waits for its process tree to exit. A second
Ctrl+C forwards another interrupt, and remaining descendants are terminated after a short grace
period.

## How It Works

1. `portless proxy start` starts an HTTPS reverse proxy on port 443 as a background daemon. Auto-elevates with sudo on macOS/Linux; falls back to port 1355 if sudo is unavailable. Use `--no-tls` for plain HTTP on port 80. Configurable with `-p` / `--port` or the `PORTLESS_PORT` env var. The proxy also auto-starts when you run an app.
Expand Down Expand Up @@ -409,7 +413,7 @@ portless hosts sync # Adds current routes to /etc/hosts
portless hosts clean # Remove entries later
```

Auto-syncs `/etc/hosts` for route hostnames by default. Set `PORTLESS_SYNC_HOSTS=0` to disable.
Auto-syncs `/etc/hosts` for route hostnames by default. Set `PORTLESS_SYNC_HOSTS=0` to disable. If a route hostname will not resolve, the command that registered it warns and points you to `portless hosts sync`.

### Browser shows certificate warning with --https

Expand Down
2 changes: 1 addition & 1 deletion plugins/portless/skills-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"source": "vercel-labs/portless",
"sourceType": "github",
"skillPath": "skills/portless/SKILL.md",
"computedHash": "4dd2cfba1475a35878d3936d4ce80047b800f7d7f65c9c6ddccb4638651d66a5"
"computedHash": "3554b1c4b77a327e87dfa1fafe8fec5136c19f5adfb9803a412aab7fd6c16e05"
}
}
}

This file was deleted.

This file was deleted.

2 changes: 1 addition & 1 deletion plugins/react-native/skills-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"source": "vercel-labs/agent-skills",
"sourceType": "github",
"skillPath": "skills/react-native-skills/SKILL.md",
"computedHash": "41d24eafa7c3d82e270439808f7cfbc4d51aeb2d14f2809a2267c16275784d06"
"computedHash": "2e9088a7333666d8c2833b8ff58bd51b955501c42b4c7244f72b4cbf22dafcc4"
}
}
}
Loading
Loading