@winstonfassett/webdev-gateway 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +78 -0
- package/dist/adapter-helpers.d.ts +64 -0
- package/dist/adapter-helpers.d.ts.map +1 -0
- package/dist/adapter-helpers.js +297 -0
- package/dist/adapter-helpers.js.map +1 -0
- package/dist/admin/assets/index-DEDI8OIx.css +2 -0
- package/dist/admin/assets/index-DaI40ww1.js +70 -0
- package/dist/admin/assets/tinykeys.module-CjuTRcEz.js +1 -0
- package/dist/admin/index.html +13 -0
- package/dist/admin-rpc.d.ts +27 -0
- package/dist/admin-rpc.d.ts.map +1 -0
- package/dist/admin-rpc.js +147 -0
- package/dist/admin-rpc.js.map +1 -0
- package/dist/admin.d.ts +10 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +202 -0
- package/dist/admin.js.map +1 -0
- package/dist/auto-register.d.ts +10 -0
- package/dist/auto-register.d.ts.map +1 -0
- package/dist/auto-register.js +145 -0
- package/dist/auto-register.js.map +1 -0
- package/dist/cdp-relay.d.ts +110 -0
- package/dist/cdp-relay.d.ts.map +1 -0
- package/dist/cdp-relay.js +616 -0
- package/dist/cdp-relay.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +95 -0
- package/dist/cli.js.map +1 -0
- package/dist/doctor.d.ts +6 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +149 -0
- package/dist/doctor.js.map +1 -0
- package/dist/element-grab-client.js +305 -0
- package/dist/element-grab.d.ts +15 -0
- package/dist/element-grab.d.ts.map +1 -0
- package/dist/element-grab.js +102 -0
- package/dist/element-grab.js.map +1 -0
- package/dist/gateway.d.ts +5 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +534 -0
- package/dist/gateway.js.map +1 -0
- package/dist/installer.d.ts +48 -0
- package/dist/installer.d.ts.map +1 -0
- package/dist/installer.js +637 -0
- package/dist/installer.js.map +1 -0
- package/dist/libs/element-source.js +35 -0
- package/dist/libs/modern-screenshot.js +14 -0
- package/dist/log-reader.d.ts +30 -0
- package/dist/log-reader.d.ts.map +1 -0
- package/dist/log-reader.js +174 -0
- package/dist/log-reader.js.map +1 -0
- package/dist/mcp-server.d.ts +22 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +115 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mcp-tools-core.d.ts +30 -0
- package/dist/mcp-tools-core.d.ts.map +1 -0
- package/dist/mcp-tools-core.js +375 -0
- package/dist/mcp-tools-core.js.map +1 -0
- package/dist/mcp-tools-full.d.ts +4 -0
- package/dist/mcp-tools-full.d.ts.map +1 -0
- package/dist/mcp-tools-full.js +141 -0
- package/dist/mcp-tools-full.js.map +1 -0
- package/dist/playwright-commands.d.ts +33 -0
- package/dist/playwright-commands.d.ts.map +1 -0
- package/dist/playwright-commands.js +356 -0
- package/dist/playwright-commands.js.map +1 -0
- package/dist/registry.d.ts +83 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +205 -0
- package/dist/registry.js.map +1 -0
- package/dist/rpc-server.d.ts +54 -0
- package/dist/rpc-server.d.ts.map +1 -0
- package/dist/rpc-server.js +207 -0
- package/dist/rpc-server.js.map +1 -0
- package/dist/session.d.ts +13 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +61 -0
- package/dist/session.js.map +1 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/webdev-client.js +20 -0
- package/dist/writers/base.d.ts +24 -0
- package/dist/writers/base.d.ts.map +1 -0
- package/dist/writers/base.js +98 -0
- package/dist/writers/base.js.map +1 -0
- package/dist/writers/console.d.ts +8 -0
- package/dist/writers/console.d.ts.map +1 -0
- package/dist/writers/console.js +14 -0
- package/dist/writers/console.js.map +1 -0
- package/dist/writers/dev-events.d.ts +28 -0
- package/dist/writers/dev-events.d.ts.map +1 -0
- package/dist/writers/dev-events.js +53 -0
- package/dist/writers/dev-events.js.map +1 -0
- package/dist/writers/errors.d.ts +8 -0
- package/dist/writers/errors.d.ts.map +1 -0
- package/dist/writers/errors.js +14 -0
- package/dist/writers/errors.js.map +1 -0
- package/dist/writers/network.d.ts +9 -0
- package/dist/writers/network.d.ts.map +1 -0
- package/dist/writers/network.js +17 -0
- package/dist/writers/network.js.map +1 -0
- package/dist/writers/server-console.d.ts +8 -0
- package/dist/writers/server-console.d.ts.map +1 -0
- package/dist/writers/server-console.js +14 -0
- package/dist/writers/server-console.js.map +1 -0
- package/package.json +79 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (unreleased)
|
|
4
|
+
|
|
5
|
+
First stable release after the `0.1.0-alpha.0` line.
|
|
6
|
+
|
|
7
|
+
- `npx webdev init` — one-command installer that detects framework, wires config, installs adapters, and registers MCP clients (`.mcp.json`, `.cursor/`, `.windsurf/`, `.vscode/`).
|
|
8
|
+
- `npx webdev register` — standalone MCP registration subcommand.
|
|
9
|
+
- Server-side log clear, SPA fallback, and server lifecycle events.
|
|
10
|
+
- Scope-aware `clearLogs` with per-browser checkpoints.
|
|
11
|
+
- Admin UI improvements: persistent log clears, multi-select channel picker, sticky source header, dark-mode toggle, REPL with command history.
|
|
12
|
+
- Build status `--turbopack`-aware.
|
|
13
|
+
|
|
14
|
+
## 0.1.0-alpha.0
|
|
15
|
+
|
|
16
|
+
Initial alpha. MCP gateway core: SSE endpoint, RPC server, log writers, dynamic proxy, CDP relay for the Chrome extension.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Winston Fassett
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# @winstonfassett/webdev-gateway
|
|
2
|
+
|
|
3
|
+
Universal MCP gateway for web development. Give AI agents live browser observability during development — console logs, errors, network requests, DOM queries, screenshots, and JS evaluation.
|
|
4
|
+
|
|
5
|
+
A dev sidecar, not a browser automation tool. The agent sees your browser tab, with your auth and state.
|
|
6
|
+
|
|
7
|
+
Works with **any** HTTP dev server: Next.js, Vite, Remix, Rails, Django, static files.
|
|
8
|
+
|
|
9
|
+
## Quick Start (standalone proxy)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Start your dev server
|
|
13
|
+
npm run dev # → localhost:3000
|
|
14
|
+
|
|
15
|
+
# Start the gateway
|
|
16
|
+
npx webdev --target http://localhost:3000
|
|
17
|
+
|
|
18
|
+
# Browse http://localhost:3333 (proxied + instrumented)
|
|
19
|
+
# MCP endpoint: http://localhost:3333/__mcp/sse
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Framework Adapters
|
|
23
|
+
|
|
24
|
+
For deeper integration (auto-start, build events, HMR status), use a framework adapter:
|
|
25
|
+
|
|
26
|
+
| Framework | Package | Setup |
|
|
27
|
+
|-----------|---------|-------|
|
|
28
|
+
| Vite | [`@winstonfassett/webdev-vite`](https://www.npmjs.com/package/@winstonfassett/webdev-vite) | 2-line plugin |
|
|
29
|
+
| Storybook | [`@winstonfassett/webdev-vite`](https://www.npmjs.com/package/@winstonfassett/webdev-vite) | 1-line addon |
|
|
30
|
+
| Next.js | [`@winstonfassett/webdev-nextjs`](https://www.npmjs.com/package/@winstonfassett/webdev-nextjs) | 1-line config wrapper |
|
|
31
|
+
|
|
32
|
+
Adapters auto-start the gateway — no separate terminal needed.
|
|
33
|
+
|
|
34
|
+
## How It Works
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
Browser ──→ Gateway (:3333) ──→ Dev Server (:3000)
|
|
38
|
+
│ │
|
|
39
|
+
├─ /__events │ Console/error/network events (WebSocket)
|
|
40
|
+
├─ /__rpc │ JSON commands — eval, screenshot, click, etc. (WebSocket)
|
|
41
|
+
└─ /__mcp/sse │ MCP tools for AI agents (SSE)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
1. Gateway proxies all HTTP/WebSocket traffic to your dev server
|
|
45
|
+
2. Injected `<script>` patches `console.*`, error handlers, `fetch`/`XHR`
|
|
46
|
+
3. Events stream to gateway → written to NDJSON log files
|
|
47
|
+
4. JSON command channel enables browser interaction (eval, screenshot, click, etc.)
|
|
48
|
+
5. MCP server exposes tools that AI agents call
|
|
49
|
+
|
|
50
|
+
## MCP Tools (core set)
|
|
51
|
+
|
|
52
|
+
| Tool | Description |
|
|
53
|
+
|------|-------------|
|
|
54
|
+
| `set_project` | Set active project (when multiple dev servers are registered) |
|
|
55
|
+
| `list_projects` | List registered dev servers + gateway |
|
|
56
|
+
| `list_browsers` | List connected browser tabs |
|
|
57
|
+
| `get_diagnostics` | Consolidated logs + errors + build status snapshot |
|
|
58
|
+
| `clear` | Truncate logs, set checkpoint for incremental reads |
|
|
59
|
+
| `eval_js` | Run JS in browser with full DOM access. Auto-awaits promises. Accepts `string \| string[]` for auto-waited pipelines. Persistent `state` + `browser.*` helpers |
|
|
60
|
+
|
|
61
|
+
Full toolset (23 tools): `/__mcp/sse?tools=full`
|
|
62
|
+
|
|
63
|
+
## CLI
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
npx webdev [options]
|
|
67
|
+
|
|
68
|
+
Options:
|
|
69
|
+
--target, -t <url> Dev server URL to proxy
|
|
70
|
+
--port, -p <port> Gateway port (default: 3333)
|
|
71
|
+
--network Capture fetch/XHR requests
|
|
72
|
+
--auto-register Write MCP config to .mcp.json, .cursor/, .windsurf/, .vscode/
|
|
73
|
+
--help, -h Show help
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared adapter helpers for webdev framework adapters.
|
|
3
|
+
* Extracted from duplicated code in Vite and Next.js adapters.
|
|
4
|
+
*
|
|
5
|
+
* Exported as '@winstonfassett/webdev-gateway/helpers'
|
|
6
|
+
*/
|
|
7
|
+
export { makeServerId, makeProjectId } from './registry.js';
|
|
8
|
+
export declare function setInternalLogging(value: boolean): void;
|
|
9
|
+
export interface RegistrationPayload {
|
|
10
|
+
serverId: string;
|
|
11
|
+
type: string;
|
|
12
|
+
port: number;
|
|
13
|
+
pid: number;
|
|
14
|
+
directory: string;
|
|
15
|
+
key?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface RegistrationResult {
|
|
18
|
+
serverId: string;
|
|
19
|
+
logDir: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Register a dev server with the gateway. Returns result on success, null on failure.
|
|
23
|
+
*/
|
|
24
|
+
export declare function registerWithGateway(gatewayUrl: string, payload: RegistrationPayload): Promise<RegistrationResult | null>;
|
|
25
|
+
/**
|
|
26
|
+
* Register with gateway, retrying every 5s until successful.
|
|
27
|
+
* Calls onRegistered callback once registered.
|
|
28
|
+
*/
|
|
29
|
+
export declare function registerWithRetry(gatewayUrl: string, payload: RegistrationPayload, onRegistered?: (result: RegistrationResult) => void): {
|
|
30
|
+
cancel: () => void;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Patch console.log/warn/error/info/debug to forward to the gateway via WebSocket.
|
|
34
|
+
*/
|
|
35
|
+
export declare function patchConsole(gatewayUrl: string, serverId: string): Promise<void>;
|
|
36
|
+
export interface DevEventsHandle {
|
|
37
|
+
send: (payload: any) => void;
|
|
38
|
+
close: () => void;
|
|
39
|
+
}
|
|
40
|
+
export interface ConnectDevEventsOptions {
|
|
41
|
+
/** Registration payload to re-send on reconnect (gateway restart recovery) */
|
|
42
|
+
registrationPayload?: RegistrationPayload;
|
|
43
|
+
/** Callback when re-registration succeeds after reconnect */
|
|
44
|
+
onReregistered?: (result: RegistrationResult) => void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Connect to the gateway's dev-events WebSocket for build/HMR events.
|
|
48
|
+
* Returns a handle to send events and close the connection.
|
|
49
|
+
*
|
|
50
|
+
* When `registrationPayload` is provided, the adapter will re-register
|
|
51
|
+
* with the gateway on every WebSocket reconnect. This handles the case
|
|
52
|
+
* where the gateway restarts and loses its in-memory server registry.
|
|
53
|
+
*/
|
|
54
|
+
export declare function connectDevEvents(gatewayUrl: string, serverId: string, options?: ConnectDevEventsOptions): Promise<DevEventsHandle>;
|
|
55
|
+
/**
|
|
56
|
+
* Ensure the gateway is running. If not, spawn it as a detached process.
|
|
57
|
+
* Returns once the gateway is reachable.
|
|
58
|
+
*/
|
|
59
|
+
export declare function ensureGateway(gatewayUrl: string): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Stop a previously auto-started gateway.
|
|
62
|
+
*/
|
|
63
|
+
export declare function stopGateway(gatewayUrl: string): boolean;
|
|
64
|
+
//# sourceMappingURL=adapter-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-helpers.d.ts","sourceRoot":"","sources":["../src/adapter-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAK3D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,QAEhD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAepC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,mBAAmB,EAC5B,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,GAClD;IAAE,MAAM,EAAE,MAAM,IAAI,CAAA;CAAE,CAyBxB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+CtF;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,CAAA;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;IACzC,6DAA6D;IAC7D,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAA;CACtD;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,eAAe,CAAC,CAkE1B;AAmBD;;;GAGG;AACH,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDrE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAYvD"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared adapter helpers for webdev framework adapters.
|
|
3
|
+
* Extracted from duplicated code in Vite and Next.js adapters.
|
|
4
|
+
*
|
|
5
|
+
* Exported as '@winstonfassett/webdev-gateway/helpers'
|
|
6
|
+
*/
|
|
7
|
+
import { spawn } from 'node:child_process';
|
|
8
|
+
import { writeFileSync, readFileSync, unlinkSync, existsSync } from 'node:fs';
|
|
9
|
+
import { join, dirname } from 'node:path';
|
|
10
|
+
import { tmpdir } from 'node:os';
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
// Re-export identity functions for adapter use
|
|
14
|
+
export { makeServerId, makeProjectId } from './registry.js';
|
|
15
|
+
// Guard: true while our own code is logging (prevents infinite recursion)
|
|
16
|
+
let _internalLogging = false;
|
|
17
|
+
export function setInternalLogging(value) {
|
|
18
|
+
_internalLogging = value;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Register a dev server with the gateway. Returns result on success, null on failure.
|
|
22
|
+
*/
|
|
23
|
+
export async function registerWithGateway(gatewayUrl, payload) {
|
|
24
|
+
try {
|
|
25
|
+
const res = await fetch(`${gatewayUrl}/__gateway/register`, {
|
|
26
|
+
method: 'POST',
|
|
27
|
+
headers: { 'Content-Type': 'application/json' },
|
|
28
|
+
body: JSON.stringify(payload),
|
|
29
|
+
});
|
|
30
|
+
const data = await res.json();
|
|
31
|
+
if (data.success) {
|
|
32
|
+
return { serverId: data.serverId, logDir: data.logDir };
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Register with gateway, retrying every 5s until successful.
|
|
42
|
+
* Calls onRegistered callback once registered.
|
|
43
|
+
*/
|
|
44
|
+
export function registerWithRetry(gatewayUrl, payload, onRegistered) {
|
|
45
|
+
let registered = false;
|
|
46
|
+
let timer = null;
|
|
47
|
+
async function tryRegister() {
|
|
48
|
+
if (registered)
|
|
49
|
+
return;
|
|
50
|
+
const result = await registerWithGateway(gatewayUrl, payload);
|
|
51
|
+
if (result) {
|
|
52
|
+
registered = true;
|
|
53
|
+
if (timer) {
|
|
54
|
+
clearInterval(timer);
|
|
55
|
+
timer = null;
|
|
56
|
+
}
|
|
57
|
+
_internalLogging = true;
|
|
58
|
+
console.log(` [webdev] Registered with gateway (server: ${result.serverId}, logs: ${result.logDir})`);
|
|
59
|
+
_internalLogging = false;
|
|
60
|
+
onRegistered?.(result);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
tryRegister();
|
|
64
|
+
timer = setInterval(tryRegister, 5000);
|
|
65
|
+
return {
|
|
66
|
+
cancel() {
|
|
67
|
+
if (timer) {
|
|
68
|
+
clearInterval(timer);
|
|
69
|
+
timer = null;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Patch console.log/warn/error/info/debug to forward to the gateway via WebSocket.
|
|
76
|
+
*/
|
|
77
|
+
export async function patchConsole(gatewayUrl, serverId) {
|
|
78
|
+
let WS;
|
|
79
|
+
try {
|
|
80
|
+
WS = (await import('ws')).default;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const wsUrl = gatewayUrl.replace(/^http/, 'ws') + '/__events?server=' + encodeURIComponent(serverId);
|
|
86
|
+
let ws = null;
|
|
87
|
+
let queue = [];
|
|
88
|
+
let closed = false;
|
|
89
|
+
function connect() {
|
|
90
|
+
if (closed)
|
|
91
|
+
return;
|
|
92
|
+
ws = new WS(wsUrl);
|
|
93
|
+
ws.on('open', () => { for (const msg of queue)
|
|
94
|
+
ws.send(msg); queue = []; });
|
|
95
|
+
ws.on('close', () => { ws = null; if (!closed)
|
|
96
|
+
setTimeout(connect, 2000); });
|
|
97
|
+
ws.on('error', () => { });
|
|
98
|
+
}
|
|
99
|
+
connect();
|
|
100
|
+
function send(level, args) {
|
|
101
|
+
const serialized = args.map((a) => {
|
|
102
|
+
if (typeof a === 'string')
|
|
103
|
+
return a.slice(0, 2000);
|
|
104
|
+
try {
|
|
105
|
+
return JSON.stringify(a).slice(0, 2000);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return String(a).slice(0, 2000);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
const msg = JSON.stringify({
|
|
112
|
+
channel: 'server-console',
|
|
113
|
+
payload: { level, args: serialized, source: 'server' },
|
|
114
|
+
});
|
|
115
|
+
if (ws?.readyState === 1)
|
|
116
|
+
ws.send(msg);
|
|
117
|
+
else if (queue.length < 1000)
|
|
118
|
+
queue.push(msg);
|
|
119
|
+
}
|
|
120
|
+
for (const level of ['log', 'warn', 'error', 'info', 'debug']) {
|
|
121
|
+
const orig = console[level];
|
|
122
|
+
console[level] = (...args) => {
|
|
123
|
+
orig.apply(console, args);
|
|
124
|
+
if (_internalLogging)
|
|
125
|
+
return;
|
|
126
|
+
const first = args[0];
|
|
127
|
+
if (typeof first === 'string' && (first.startsWith('[webdev]') || first.startsWith(' [webdev]') || first.startsWith('[registry]')))
|
|
128
|
+
return;
|
|
129
|
+
send(level, args);
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
process.on('exit', () => { closed = true; ws?.close(); });
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Connect to the gateway's dev-events WebSocket for build/HMR events.
|
|
136
|
+
* Returns a handle to send events and close the connection.
|
|
137
|
+
*
|
|
138
|
+
* When `registrationPayload` is provided, the adapter will re-register
|
|
139
|
+
* with the gateway on every WebSocket reconnect. This handles the case
|
|
140
|
+
* where the gateway restarts and loses its in-memory server registry.
|
|
141
|
+
*/
|
|
142
|
+
export async function connectDevEvents(gatewayUrl, serverId, options) {
|
|
143
|
+
let WS;
|
|
144
|
+
try {
|
|
145
|
+
WS = (await import('ws')).default;
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return { send() { }, close() { } };
|
|
149
|
+
}
|
|
150
|
+
const wsUrl = gatewayUrl.replace(/^http/, 'ws') + '/__dev-events?server=' + encodeURIComponent(serverId);
|
|
151
|
+
let ws = null;
|
|
152
|
+
let queue = [];
|
|
153
|
+
let closed = false;
|
|
154
|
+
let gatewayWarned = false;
|
|
155
|
+
let hasConnectedBefore = false;
|
|
156
|
+
async function reregister() {
|
|
157
|
+
if (!options?.registrationPayload)
|
|
158
|
+
return;
|
|
159
|
+
const result = await registerWithGateway(gatewayUrl, options.registrationPayload);
|
|
160
|
+
if (result) {
|
|
161
|
+
_internalLogging = true;
|
|
162
|
+
console.log(` [webdev] Re-registered with gateway (server: ${result.serverId})`);
|
|
163
|
+
_internalLogging = false;
|
|
164
|
+
options.onReregistered?.(result);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function connect() {
|
|
168
|
+
if (closed)
|
|
169
|
+
return;
|
|
170
|
+
ws = new WS(wsUrl);
|
|
171
|
+
ws.on('open', () => {
|
|
172
|
+
for (const msg of queue)
|
|
173
|
+
ws.send(msg);
|
|
174
|
+
queue = [];
|
|
175
|
+
if (gatewayWarned) {
|
|
176
|
+
console.log(` [webdev] Gateway connected at ${gatewayUrl}`);
|
|
177
|
+
gatewayWarned = false;
|
|
178
|
+
}
|
|
179
|
+
// On reconnect (not first connect), re-register with gateway
|
|
180
|
+
// to restore server identity after a gateway restart
|
|
181
|
+
if (hasConnectedBefore) {
|
|
182
|
+
reregister();
|
|
183
|
+
}
|
|
184
|
+
hasConnectedBefore = true;
|
|
185
|
+
});
|
|
186
|
+
ws.on('close', () => { ws = null; if (!closed)
|
|
187
|
+
setTimeout(connect, 3000); });
|
|
188
|
+
ws.on('error', () => {
|
|
189
|
+
if (!gatewayWarned) {
|
|
190
|
+
console.warn(` [webdev] Gateway not running. Start it with: npx webdev`);
|
|
191
|
+
gatewayWarned = true;
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
connect();
|
|
196
|
+
process.on('exit', () => { closed = true; ws?.close(); });
|
|
197
|
+
return {
|
|
198
|
+
send(payload) {
|
|
199
|
+
const msg = JSON.stringify(payload);
|
|
200
|
+
if (ws?.readyState === 1)
|
|
201
|
+
ws.send(msg);
|
|
202
|
+
else if (queue.length < 1000)
|
|
203
|
+
queue.push(msg);
|
|
204
|
+
},
|
|
205
|
+
close() {
|
|
206
|
+
closed = true;
|
|
207
|
+
ws?.close();
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
// --- Gateway auto-start ---
|
|
212
|
+
function pidFilePath(gatewayUrl) {
|
|
213
|
+
const hash = createHash('md5').update(gatewayUrl).digest('hex').slice(0, 8);
|
|
214
|
+
return join(tmpdir(), `webdev-${hash}.pid`);
|
|
215
|
+
}
|
|
216
|
+
async function isGatewayRunning(gatewayUrl) {
|
|
217
|
+
try {
|
|
218
|
+
await fetch(gatewayUrl, { signal: AbortSignal.timeout(2000) });
|
|
219
|
+
// Any response (even 404) means the server is up
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Ensure the gateway is running. If not, spawn it as a detached process.
|
|
228
|
+
* Returns once the gateway is reachable.
|
|
229
|
+
*/
|
|
230
|
+
export async function ensureGateway(gatewayUrl) {
|
|
231
|
+
if (await isGatewayRunning(gatewayUrl))
|
|
232
|
+
return;
|
|
233
|
+
const url = new URL(gatewayUrl);
|
|
234
|
+
const port = url.port || '3333';
|
|
235
|
+
const startTime = Date.now();
|
|
236
|
+
_internalLogging = true;
|
|
237
|
+
console.log(` [webdev] Starting gateway on port ${port}...`);
|
|
238
|
+
_internalLogging = false;
|
|
239
|
+
// Resolve the CLI bin directly — avoids npx overhead (15-30s → ~1-2s)
|
|
240
|
+
let cliBin;
|
|
241
|
+
try {
|
|
242
|
+
// import.meta.resolve gives us the package entry; the CLI is at dist/cli.js
|
|
243
|
+
const pkgDir = dirname(fileURLToPath(import.meta.resolve('@winstonfassett/webdev-gateway/package.json')));
|
|
244
|
+
cliBin = join(pkgDir, 'dist', 'cli.js');
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
// Fallback: resolve relative to this file (we're inside the gateway package)
|
|
248
|
+
cliBin = join(dirname(fileURLToPath(import.meta.url)), 'cli.js');
|
|
249
|
+
}
|
|
250
|
+
const child = spawn('node', [cliBin, '--port', port], {
|
|
251
|
+
detached: true,
|
|
252
|
+
stdio: 'ignore',
|
|
253
|
+
env: { ...process.env },
|
|
254
|
+
});
|
|
255
|
+
child.unref();
|
|
256
|
+
// Write PID for stop/restart — this is the real node process PID (not an npx wrapper)
|
|
257
|
+
if (child.pid) {
|
|
258
|
+
try {
|
|
259
|
+
writeFileSync(pidFilePath(gatewayUrl), String(child.pid));
|
|
260
|
+
}
|
|
261
|
+
catch { }
|
|
262
|
+
}
|
|
263
|
+
// Wait for gateway to become reachable (up to 10s with fast polling)
|
|
264
|
+
for (let i = 0; i < 40; i++) {
|
|
265
|
+
await new Promise(r => setTimeout(r, i < 10 ? 250 : 500));
|
|
266
|
+
if (await isGatewayRunning(gatewayUrl)) {
|
|
267
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
268
|
+
_internalLogging = true;
|
|
269
|
+
console.log(` [webdev] Gateway started in ${elapsed}s (pid: ${child.pid})`);
|
|
270
|
+
_internalLogging = false;
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
console.warn(` [webdev] Gateway did not start within 20s — continuing without it`);
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Stop a previously auto-started gateway.
|
|
278
|
+
*/
|
|
279
|
+
export function stopGateway(gatewayUrl) {
|
|
280
|
+
const pidFile = pidFilePath(gatewayUrl);
|
|
281
|
+
if (!existsSync(pidFile))
|
|
282
|
+
return false;
|
|
283
|
+
try {
|
|
284
|
+
const pid = parseInt(readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
285
|
+
process.kill(pid, 'SIGTERM');
|
|
286
|
+
unlinkSync(pidFile);
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
try {
|
|
291
|
+
unlinkSync(pidFile);
|
|
292
|
+
}
|
|
293
|
+
catch { }
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=adapter-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-helpers.js","sourceRoot":"","sources":["../src/adapter-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--font-weight-medium:500;--font-weight-semibold:600;--tracking-wide:.025em;--leading-tight:1.25;--radius-lg:.5rem;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.top-full{top:100%}.right-0{right:calc(var(--spacing) * 0)}.right-4{right:calc(var(--spacing) * 4)}.bottom-2{bottom:calc(var(--spacing) * 2)}.left-0{left:calc(var(--spacing) * 0)}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.-mb-px{margin-bottom:-1px}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-\[72px\]{margin-left:72px}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-\[18px\]{height:18px}.h-full{height:100%}.h-screen{height:100vh}.max-h-80{max-height:calc(var(--spacing) * 80)}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-3{width:calc(var(--spacing) * 3)}.w-5{width:calc(var(--spacing) * 5)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-48{width:calc(var(--spacing) * 48)}.w-full{width:100%}.max-w-48{max-width:calc(var(--spacing) * 48)}.max-w-60{max-width:calc(var(--spacing) * 60)}.max-w-96{max-width:calc(var(--spacing) * 96)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-24{min-width:calc(var(--spacing) * 24)}.min-w-48{min-width:calc(var(--spacing) * 48)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.animate-pulse{animation:var(--animate-pulse)}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-8{column-gap:calc(var(--spacing) * 8)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border>:not(:last-child)){border-color:var(--border-color)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-accent{border-color:var(--accent)}.border-border,.border-border\/40{border-color:var(--border-color)}@supports (color:color-mix(in lab, red, red)){.border-border\/40{border-color:color-mix(in oklab, var(--border-color) 40%, transparent)}}.border-border\/50{border-color:var(--border-color)}@supports (color:color-mix(in lab, red, red)){.border-border\/50{border-color:color-mix(in oklab, var(--border-color) 50%, transparent)}}.border-transparent{border-color:#0000}.bg-accent{background-color:var(--accent)}.bg-background,.bg-background\/60{background-color:var(--bg)}@supports (color:color-mix(in lab, red, red)){.bg-background\/60{background-color:color-mix(in oklab, var(--bg) 60%, transparent)}}.bg-card{background-color:var(--card)}.bg-destructive,.bg-destructive\/5{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.bg-destructive\/5{background-color:color-mix(in oklab, var(--destructive) 5%, transparent)}}.bg-destructive\/10{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.bg-destructive\/10{background-color:color-mix(in oklab, var(--destructive) 10%, transparent)}}.bg-muted{background-color:var(--muted)}.bg-success,.bg-success\/10{background-color:var(--success)}@supports (color:color-mix(in lab, red, red)){.bg-success\/10{background-color:color-mix(in oklab, var(--success) 10%, transparent)}}.bg-transparent{background-color:#0000}.bg-warning{background-color:var(--warning)}.p-2{padding:calc(var(--spacing) * 2)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-px{padding-block:1px}.pt-2{padding-top:calc(var(--spacing) * 2)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pb-1{padding-bottom:calc(var(--spacing) * 1)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-6{padding-left:calc(var(--spacing) * 6)}.pl-10{padding-left:calc(var(--spacing) * 10)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.leading-\[18px\]{--tw-leading:18px;line-height:18px}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-words{overflow-wrap:break-word}.whitespace-pre-wrap{white-space:pre-wrap}.text-accent{color:var(--accent)}.text-accent-foreground{color:var(--accent-fg)}.text-destructive{color:var(--destructive)}.text-dim{color:var(--dim)}.text-foreground{color:var(--fg)}.text-info{color:var(--info)}.text-muted-foreground,.text-muted-foreground\/50{color:var(--muted-fg)}@supports (color:color-mix(in lab, red, red)){.text-muted-foreground\/50{color:color-mix(in oklab, var(--muted-fg) 50%, transparent)}}.text-muted-foreground\/60{color:var(--muted-fg)}@supports (color:color-mix(in lab, red, red)){.text-muted-foreground\/60{color:color-mix(in oklab, var(--muted-fg) 60%, transparent)}}.text-success{color:var(--success)}.text-warning{color:var(--warning)}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline{text-decoration-line:underline}.opacity-70{opacity:.7}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.outline-none{--tw-outline-style:none;outline-style:none}.\[contain-intrinsic-size\:auto_20px\]{contain-intrinsic-size:auto 20px}.\[content-visibility\:auto\]{content-visibility:auto}@media (hover:hover){.hover\:bg-accent\/90:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/90:hover{background-color:color-mix(in oklab, var(--accent) 90%, transparent)}}.hover\:bg-muted:hover,.hover\:bg-muted\/30:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-muted\/30:hover{background-color:color-mix(in oklab, var(--muted) 30%, transparent)}}.hover\:bg-muted\/50:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-muted\/50:hover{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}.hover\:text-accent:hover{color:var(--accent)}.hover\:text-foreground:hover{color:var(--fg)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:border-accent:focus{border-color:var(--accent)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:opacity-30:disabled{opacity:.3}@media (width>=48rem){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width>=64rem){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}:root{--bg:#f4f4f4;--fg:#111;--muted:#e8e8e8;--muted-fg:#5a5a5a;--dim:#707070;--card:#fff;--card-fg:#111;--border-color:#d0d0d0;--accent:#3b82f6;--accent-fg:#fff;--info:#3b82f6;--destructive:#ef4444;--success:#22c55e;--warning:#f59e0b}.dark{--bg:#0f0f0f;--fg:#e8e8e8;--muted:#262626;--muted-fg:#a3a3a3;--dim:#848484;--card:#1c1c1c;--card-fg:#e8e8e8;--border-color:#333;--accent:#3b82f6;--accent-fg:#fff;--info:#3b82f6;--destructive:#ef4444;--success:#22c55e;--warning:#f59e0b}body{background-color:var(--bg);color:var(--fg);-webkit-font-smoothing:antialiased;margin:0;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:13px}.cp-container{background:var(--card)!important;box-shadow:0 25px 50px -12px #0006, 0 0 0 1px var(--border-color)!important;border-radius:8px!important;font-family:inherit!important}.cp-container form{border-bottom-color:var(--border-color)!important}.cp-input{color:var(--fg)!important;font-family:inherit!important;font-size:13px!important}.cp-input::placeholder,.cp-search-icon{color:var(--muted-fg)!important}.cp-group-header{color:var(--muted-fg)!important;font-family:inherit!important;font-size:10px!important}.cp-result:hover,.cp-result-active,.cp-result-icon{background:var(--muted)!important}.cp-result-title{color:var(--fg)!important;font-size:12px!important}.cp-result-subtitle{color:var(--muted-fg)!important;font-size:11px!important}.cp-result-description{opacity:.7;color:var(--muted-fg)!important;font-size:10px!important}.cp-empty-content{color:var(--muted-fg)!important}.cp-empty-content p{color:var(--fg)!important}.cp-kbd{color:var(--muted-fg)!important;background:var(--muted)!important;border-color:var(--border-color)!important;font-family:inherit!important}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}.cp-kbd.svelte-1vzpvtd{color:#9ca3af;background:#374151;border:1px solid #4b5563;border-radius:4px;justify-content:center;align-items:center;min-width:1.5rem;height:1.5rem;padding:0 .375rem;font-family:inherit;font-size:.75rem;font-weight:500;display:inline-flex;box-shadow:0 1px 2px #0003}.light .cp-kbd.svelte-1vzpvtd,html.light .cp-kbd.svelte-1vzpvtd,body.light .cp-kbd.svelte-1vzpvtd{color:#6b7280;background:#f3f4f6;border-color:#e5e7eb;box-shadow:0 1px 2px #0000000d}@media (prefers-color-scheme:light){.cp-kbd.svelte-1vzpvtd{color:#6b7280;background:#f3f4f6;border-color:#e5e7eb;box-shadow:0 1px 2px #0000000d}}.cp-result.svelte-16igsvt{cursor:pointer;border-radius:8px;align-items:center;gap:.75rem;padding:.75rem;transition:background-color .1s;display:flex}.cp-result.svelte-16igsvt:hover,.cp-result-active.svelte-16igsvt{background:#374151}.cp-result-icon.svelte-16igsvt{background:#374151;border-radius:8px;flex-shrink:0;justify-content:center;align-items:center;width:36px;height:36px;display:flex}.cp-result-emoji.svelte-16igsvt{font-size:1.25rem}.cp-result-icon.svelte-16igsvt img:where(.svelte-16igsvt){border-radius:4px}.cp-result-content.svelte-16igsvt{flex:1;min-width:0}.cp-result-title.svelte-16igsvt{color:#f9fafb;white-space:nowrap;text-overflow:ellipsis;font-weight:500;overflow:hidden}.cp-result-subtitle.svelte-16igsvt{color:#9ca3af;white-space:nowrap;text-overflow:ellipsis;margin-top:.125rem;font-size:.875rem;overflow:hidden}.cp-result-description.svelte-16igsvt{color:#6b7280;margin-top:.25rem;font-size:.75rem}.cp-result-shortcuts.svelte-16igsvt{flex-shrink:0;gap:.25rem;display:flex}.light .cp-result.svelte-16igsvt:hover,.light .cp-result-active.svelte-16igsvt,html.light .cp-result.svelte-16igsvt:hover,html.light .cp-result-active.svelte-16igsvt,body.light .cp-result.svelte-16igsvt:hover,body.light .cp-result-active.svelte-16igsvt,.light .cp-result-icon.svelte-16igsvt,html.light .cp-result-icon.svelte-16igsvt,body.light .cp-result-icon.svelte-16igsvt{background:#f3f4f6}.light .cp-result-title.svelte-16igsvt,html.light .cp-result-title.svelte-16igsvt,body.light .cp-result-title.svelte-16igsvt{color:#111827}.light .cp-result-subtitle.svelte-16igsvt,html.light .cp-result-subtitle.svelte-16igsvt,body.light .cp-result-subtitle.svelte-16igsvt{color:#6b7280}.light .cp-result-description.svelte-16igsvt,html.light .cp-result-description.svelte-16igsvt,body.light .cp-result-description.svelte-16igsvt{color:#9ca3af}@media (prefers-color-scheme:light){.cp-result.svelte-16igsvt:hover,.cp-result-active.svelte-16igsvt,.cp-result-icon.svelte-16igsvt{background:#f3f4f6}.cp-result-title.svelte-16igsvt{color:#111827}.cp-result-subtitle.svelte-16igsvt{color:#6b7280}.cp-result-description.svelte-16igsvt{color:#9ca3af}}.cp-results.svelte-17am6af{width:100%;max-height:calc(70vh - 60px);padding:.5rem;overflow-y:auto}.cp-group-header.svelte-17am6af{text-transform:uppercase;letter-spacing:.05em;color:#9ca3af;margin-top:.5rem;padding:.75rem .75rem .5rem;font-size:.75rem;font-weight:600}.cp-group-header.svelte-17am6af:first-child{margin-top:0}.cp-empty.svelte-17am6af{justify-content:center;align-items:center;padding:3rem 1rem;display:flex}.cp-empty-content.svelte-17am6af{color:#6b7280;text-align:center;flex-direction:column;align-items:center;gap:.75rem;display:flex}.cp-empty-content.svelte-17am6af p:where(.svelte-17am6af){color:#9ca3af;margin:0;font-weight:500}.cp-empty-content.svelte-17am6af span:where(.svelte-17am6af){font-size:.875rem}@media (width<=640px){.cp-results.svelte-17am6af{max-height:calc(85vh - 60px)}}.light .cp-group-header.svelte-17am6af,html.light .cp-group-header.svelte-17am6af,body.light .cp-group-header.svelte-17am6af{color:#6b7280}.light .cp-empty-content.svelte-17am6af,html.light .cp-empty-content.svelte-17am6af,body.light .cp-empty-content.svelte-17am6af{color:#9ca3af}.light .cp-empty-content.svelte-17am6af p:where(.svelte-17am6af),html.light .cp-empty-content.svelte-17am6af p:where(.svelte-17am6af),body.light .cp-empty-content.svelte-17am6af p:where(.svelte-17am6af){color:#6b7280}@media (prefers-color-scheme:light){.cp-group-header.svelte-17am6af{color:#6b7280}.cp-empty-content.svelte-17am6af{color:#9ca3af}.cp-empty-content.svelte-17am6af p:where(.svelte-17am6af){color:#6b7280}}.sr-only.svelte-sfqeu0{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.cp-overlay.svelte-sfqeu0{z-index:9999;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);background:#0009;justify-content:center;align-items:flex-start;padding:10vh 1rem 1rem;animation:.15s ease-out svelte-sfqeu0-fadeIn;display:flex;position:fixed;inset:0}@keyframes svelte-sfqeu0-fadeIn{0%{opacity:0}to{opacity:1}}@keyframes svelte-sfqeu0-slideIn{0%{opacity:0;transform:scale(.96)translateY(-10px)}to{opacity:1;transform:scale(1)translateY(0)}}.cp-wrapper{width:100%;max-width:640px;animation:.2s ease-out svelte-sfqeu0-slideIn}.cp-wrapper *{box-sizing:border-box}.cp-container.svelte-sfqeu0{background:#1f2937;border-radius:12px;flex-direction:column;width:100%;max-height:70vh;display:flex;overflow:hidden;box-shadow:0 25px 50px -12px #00000080,0 0 0 1px #ffffff1a}form.svelte-sfqeu0{border-bottom:1px solid #374151;width:100%}.cp-input-wrapper.svelte-sfqeu0{align-items:center;gap:.75rem;padding:.875rem 1rem;display:flex}.cp-search-icon.svelte-sfqeu0{color:#6b7280;flex-shrink:0}.cp-input.svelte-sfqeu0{color:#f9fafb;background:0 0;border:none;outline:none;flex:1;font-size:1rem}.cp-input.svelte-sfqeu0::placeholder{color:#6b7280}@media (width<=640px){.cp-overlay.svelte-sfqeu0{align-items:flex-end;padding:0}.cp-wrapper{max-width:100%}.cp-container.svelte-sfqeu0{border-radius:12px 12px 0 0;max-height:85vh}}.light .cp-container.svelte-sfqeu0,html.light .cp-container.svelte-sfqeu0,body.light .cp-container.svelte-sfqeu0{background:#fff;box-shadow:0 25px 50px -12px #00000026,0 0 0 1px #00000014}.light form.svelte-sfqeu0,html.light form.svelte-sfqeu0,body.light form.svelte-sfqeu0{border-bottom-color:#e5e7eb}.light .cp-input.svelte-sfqeu0,html.light .cp-input.svelte-sfqeu0,body.light .cp-input.svelte-sfqeu0{color:#111827}.light .cp-input.svelte-sfqeu0::-moz-placeholder{color:#9ca3af}html.light .cp-input.svelte-sfqeu0::-moz-placeholder{color:#9ca3af}body.light .cp-input.svelte-sfqeu0::-moz-placeholder{color:#9ca3af}.light .cp-input.svelte-sfqeu0::placeholder,html.light .cp-input.svelte-sfqeu0::placeholder,body.light .cp-input.svelte-sfqeu0::placeholder,.light .cp-search-icon.svelte-sfqeu0,html.light .cp-search-icon.svelte-sfqeu0,body.light .cp-search-icon.svelte-sfqeu0{color:#9ca3af}@media (prefers-color-scheme:light){.cp-container.svelte-sfqeu0{background:#fff;box-shadow:0 25px 50px -12px #00000026,0 0 0 1px #00000014}form.svelte-sfqeu0{border-bottom-color:#e5e7eb}.cp-input.svelte-sfqeu0{color:#111827}.cp-input.svelte-sfqeu0::placeholder{color:#9ca3af}.cp-search-icon.svelte-sfqeu0{color:#9ca3af}}
|