claw-design 1.0.1
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/LICENSE +21 -0
- package/README.md +72 -0
- package/dist/cli/commands/start.d.ts +7 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +176 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +20 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/claude.d.ts +21 -0
- package/dist/cli/utils/claude.d.ts.map +1 -0
- package/dist/cli/utils/claude.js +42 -0
- package/dist/cli/utils/claude.js.map +1 -0
- package/dist/cli/utils/dev-server.d.ts +14 -0
- package/dist/cli/utils/dev-server.d.ts.map +1 -0
- package/dist/cli/utils/dev-server.js +57 -0
- package/dist/cli/utils/dev-server.js.map +1 -0
- package/dist/cli/utils/electron.d.ts +7 -0
- package/dist/cli/utils/electron.d.ts.map +1 -0
- package/dist/cli/utils/electron.js +36 -0
- package/dist/cli/utils/electron.js.map +1 -0
- package/dist/cli/utils/output.d.ts +6 -0
- package/dist/cli/utils/output.d.ts.map +1 -0
- package/dist/cli/utils/output.js +21 -0
- package/dist/cli/utils/output.js.map +1 -0
- package/dist/cli/utils/port-detect.d.ts +30 -0
- package/dist/cli/utils/port-detect.d.ts.map +1 -0
- package/dist/cli/utils/port-detect.js +95 -0
- package/dist/cli/utils/port-detect.js.map +1 -0
- package/dist/cli/utils/preflight.d.ts +20 -0
- package/dist/cli/utils/preflight.d.ts.map +1 -0
- package/dist/cli/utils/preflight.js +33 -0
- package/dist/cli/utils/preflight.js.map +1 -0
- package/dist/cli/utils/process.d.ts +23 -0
- package/dist/cli/utils/process.d.ts.map +1 -0
- package/dist/cli/utils/process.js +57 -0
- package/dist/cli/utils/process.js.map +1 -0
- package/out/main/index.js +1123 -0
- package/out/preload/overlay.cjs +56 -0
- package/out/preload/sidebar.cjs +29 -0
- package/out/renderer/assets/overlay-Bsx1u_qg.css +449 -0
- package/out/renderer/assets/overlay-DZl3I3jq.js +689 -0
- package/out/renderer/assets/sidebar-Bt34gvPU.js +563 -0
- package/out/renderer/assets/sidebar-BxEPS84k.css +515 -0
- package/out/renderer/assets/toast-CLlgwMU_.js +110 -0
- package/out/renderer/overlay.html +131 -0
- package/out/renderer/sidebar.html +64 -0
- package/package.json +67 -0
- package/resources/icon.icns +0 -0
- package/resources/icon.png +0 -0
- package/scripts/postinstall.cjs +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 prodoxx
|
|
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,72 @@
|
|
|
1
|
+
# Claw Design
|
|
2
|
+
|
|
3
|
+
Point at your running website. Describe what to change. Watch Claude edit the code live.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/claw-design)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
## Why Claw Design?
|
|
12
|
+
|
|
13
|
+
Web developers constantly context-switch between browser and editor. Claw Design eliminates this -- select any part of your running site, describe the change in plain English, and Claude Code edits the source files directly. Changes appear instantly via hot module reload.
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g claw-design
|
|
19
|
+
cd your-project
|
|
20
|
+
clawdesign start
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Requirements
|
|
24
|
+
|
|
25
|
+
- **Node.js >= 20** (LTS recommended)
|
|
26
|
+
- **[Claude Code CLI](https://claude.ai/download)** installed and authenticated
|
|
27
|
+
- A web project with a dev server
|
|
28
|
+
|
|
29
|
+
## How It Works
|
|
30
|
+
|
|
31
|
+
1. **Detects your dev server** from `package.json` scripts and starts it automatically
|
|
32
|
+
2. **Opens a browser window** showing your running site with a selection overlay
|
|
33
|
+
3. **You draw a selection** over any area and describe what you want to change
|
|
34
|
+
4. **Claude Code edits your source files** based on the visual context and instruction -- HMR shows the result instantly
|
|
35
|
+
|
|
36
|
+
## CLI Options
|
|
37
|
+
|
|
38
|
+
| Flag | Description |
|
|
39
|
+
|------|-------------|
|
|
40
|
+
| `--cmd <command>` | Override dev server command (e.g. `--cmd "python -m http.server 8000"`) |
|
|
41
|
+
| `--port <number>` | Specify dev server port instead of auto-detecting |
|
|
42
|
+
| `--verbose` | Show dev server output in the terminal |
|
|
43
|
+
| `--version` | Show version number |
|
|
44
|
+
|
|
45
|
+
## Viewport Switching
|
|
46
|
+
|
|
47
|
+
Switch between viewport presets using the toolbar buttons:
|
|
48
|
+
|
|
49
|
+
- **Desktop** (1280x800)
|
|
50
|
+
- **Tablet** (768x1024)
|
|
51
|
+
- **Mobile** (375x812)
|
|
52
|
+
|
|
53
|
+
## Framework Support
|
|
54
|
+
|
|
55
|
+
Works with anything that serves on localhost:
|
|
56
|
+
|
|
57
|
+
- React
|
|
58
|
+
- Vue
|
|
59
|
+
- Svelte
|
|
60
|
+
- Next.js
|
|
61
|
+
- Nuxt
|
|
62
|
+
- Angular
|
|
63
|
+
- Astro
|
|
64
|
+
- Plain HTML
|
|
65
|
+
|
|
66
|
+
## Contributing
|
|
67
|
+
|
|
68
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup and guidelines.
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
|
|
72
|
+
MIT -- see [LICENSE](./LICENSE) for details.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAkNvE"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { detectDevServerScript, detectPackageManager, spawnDevServer, DetectionError } from '../utils/dev-server.js';
|
|
2
|
+
import { extractPortFromOutput, waitForPort, getProcessOnPort } from '../utils/port-detect.js';
|
|
3
|
+
import { isClaudeInstalled, getClaudeAuthStatus } from '../utils/claude.js';
|
|
4
|
+
import { checkNodeVersion, checkElectronBinary } from '../utils/preflight.js';
|
|
5
|
+
import { spawnElectron } from '../utils/electron.js';
|
|
6
|
+
import { registerShutdownHandlers } from '../utils/process.js';
|
|
7
|
+
import { createSpinner, printReady, printError } from '../utils/output.js';
|
|
8
|
+
import pc from 'picocolors';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { createInterface } from 'node:readline';
|
|
12
|
+
export async function startCommand(options) {
|
|
13
|
+
const verbose = options.verbose ?? false;
|
|
14
|
+
// Pre-flight checks (D-14): fast checks before any async work
|
|
15
|
+
const nodeCheck = checkNodeVersion();
|
|
16
|
+
if (!nodeCheck.ok) {
|
|
17
|
+
printError('Node.js 20+ required', `Found Node ${nodeCheck.version}.`, 'Update Node.js: https://nodejs.org');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
if (!checkElectronBinary()) {
|
|
21
|
+
printError('Browser component not found', 'A required browser component is missing from the installation.', 'Reinstall: npm install -g claw-design');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
// Step 1: Check Claude Code installed (per D-12)
|
|
25
|
+
if (!isClaudeInstalled()) {
|
|
26
|
+
printError('Claude Code not found', 'Claude Code CLI is not installed or not in PATH.', 'Install: https://claude.ai/download');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
// Step 1b: Check Claude Code authentication
|
|
30
|
+
const authStatus = getClaudeAuthStatus();
|
|
31
|
+
if (!authStatus.loggedIn) {
|
|
32
|
+
printError('Claude Code not authenticated', 'You need to sign in before using clawdesign.', 'Run: claude login');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
// Step 2: Detect dev server (per D-05, D-06)
|
|
36
|
+
let command;
|
|
37
|
+
const detectSpinner = createSpinner('Detecting dev server...');
|
|
38
|
+
if (options.cmd) {
|
|
39
|
+
command = options.cmd;
|
|
40
|
+
detectSpinner.succeed(`Using custom command: ${pc.cyan(command)}`);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
try {
|
|
44
|
+
const detected = await detectDevServerScript(process.cwd());
|
|
45
|
+
const pm = await detectPackageManager(process.cwd());
|
|
46
|
+
const runCmd = pm === 'npm' ? `npm run ${detected.name}` : `${pm} run ${detected.name}`;
|
|
47
|
+
command = runCmd;
|
|
48
|
+
detectSpinner.succeed(`Detected: ${pc.cyan(runCmd)} (from package.json)`);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (err instanceof DetectionError) {
|
|
52
|
+
detectSpinner.fail('No dev server detected');
|
|
53
|
+
printError('No dev server detected', err.message);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
detectSpinner.fail('Dev server detection failed');
|
|
57
|
+
printError('Dev server detection failed', err instanceof Error ? err.message : String(err));
|
|
58
|
+
}
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Read project name from package.json for Claw Design window title (D-03)
|
|
63
|
+
let projectName = 'unknown';
|
|
64
|
+
try {
|
|
65
|
+
const pkg = JSON.parse(readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8'));
|
|
66
|
+
projectName = pkg.name || 'unknown';
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Not critical -- window title will show 'unknown'
|
|
70
|
+
}
|
|
71
|
+
// Step 3: Spawn dev server (per CLI-04)
|
|
72
|
+
const serverSpinner = createSpinner('Starting dev server...');
|
|
73
|
+
const devServer = spawnDevServer(command, verbose);
|
|
74
|
+
serverSpinner.succeed(`Dev server started ${pc.dim(command)}`);
|
|
75
|
+
// Step 4: Detect port (per D-07, D-08)
|
|
76
|
+
let port;
|
|
77
|
+
if (options.port) {
|
|
78
|
+
port = parseInt(options.port, 10);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Listen to stdout/stderr for port detection
|
|
82
|
+
const portSpinner = createSpinner('Detecting port from dev server output...');
|
|
83
|
+
let accumulatedOutput = '';
|
|
84
|
+
port = await new Promise((resolve, reject) => {
|
|
85
|
+
const timeout = setTimeout(() => {
|
|
86
|
+
cleanup();
|
|
87
|
+
reject(new Error('port-detect-timeout'));
|
|
88
|
+
}, 10_000);
|
|
89
|
+
function onData(chunk) {
|
|
90
|
+
accumulatedOutput += chunk.toString();
|
|
91
|
+
const detected = extractPortFromOutput(accumulatedOutput);
|
|
92
|
+
if (detected !== null) {
|
|
93
|
+
cleanup();
|
|
94
|
+
resolve(detected);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function cleanup() {
|
|
98
|
+
clearTimeout(timeout);
|
|
99
|
+
devServer.stdout?.removeListener('data', onData);
|
|
100
|
+
devServer.stderr?.removeListener('data', onData);
|
|
101
|
+
}
|
|
102
|
+
devServer.stdout?.on('data', onData);
|
|
103
|
+
devServer.stderr?.on('data', onData);
|
|
104
|
+
}).catch(async () => {
|
|
105
|
+
// Port not detected from stdout -- prompt user interactively (per D-07)
|
|
106
|
+
portSpinner.stop();
|
|
107
|
+
const rl = createInterface({
|
|
108
|
+
input: process.stdin,
|
|
109
|
+
output: process.stdout,
|
|
110
|
+
});
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
rl.question(`${pc.yellow(' Could not detect port from dev server output.')}\n Enter port number: `, (answer) => {
|
|
113
|
+
rl.close();
|
|
114
|
+
const parsed = parseInt(answer.trim(), 10);
|
|
115
|
+
if (Number.isNaN(parsed) || parsed <= 0 || parsed > 65535) {
|
|
116
|
+
reject(new Error('Invalid port number'));
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
resolve(parsed);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
portSpinner.succeed(`Port detected: ${pc.cyan(String(port))}`);
|
|
125
|
+
}
|
|
126
|
+
// Step 5: Wait for port readiness (per D-09, D-14, D-15)
|
|
127
|
+
const readySpinner = createSpinner(`Waiting for localhost:${port}...`);
|
|
128
|
+
const readyStart = Date.now();
|
|
129
|
+
const elapsedTimer = setInterval(() => {
|
|
130
|
+
const elapsed = Math.round((Date.now() - readyStart) / 1000);
|
|
131
|
+
readySpinner.text = `Waiting for localhost:${port}... ${pc.dim(`${elapsed}s`)}`;
|
|
132
|
+
}, 1000);
|
|
133
|
+
try {
|
|
134
|
+
await waitForPort(port, { timeout: 30_000 });
|
|
135
|
+
clearInterval(elapsedTimer);
|
|
136
|
+
readySpinner.succeed(`Dev server ready on ${pc.cyan(`http://localhost:${port}`)}`);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
clearInterval(elapsedTimer);
|
|
140
|
+
readySpinner.fail(`Port ${port} not ready`);
|
|
141
|
+
// Check if port is in use by another process (per D-14)
|
|
142
|
+
const occupant = getProcessOnPort(port);
|
|
143
|
+
if (occupant) {
|
|
144
|
+
printError('Port already in use', `Port ${port} is occupied by ${occupant.name} (PID ${occupant.pid})`, `Try: kill ${occupant.pid} or clawdesign start --port <other>`);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
printError('Startup timeout', `Port ${port} not ready after 30s`, 'Try: clawdesign start --verbose\n Or: clawdesign start --port <port>');
|
|
148
|
+
}
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
// Step 6: Launch Electron window (per CLI-06)
|
|
152
|
+
// Pre-built by `npm run build` / prepublishOnly hook (D-18).
|
|
153
|
+
// No runtime build needed -- out/ is included in the npm package.
|
|
154
|
+
// Claude Code session is managed by AgentManager inside the Electron main process.
|
|
155
|
+
const electronSpinner = createSpinner('Starting Claw Design...');
|
|
156
|
+
const electronProcess = spawnElectron(`http://localhost:${port}`, projectName);
|
|
157
|
+
electronSpinner.succeed(`Claw Design ready ${pc.dim(`localhost:${port}`)}`);
|
|
158
|
+
// Step 7: Register shutdown and print ready (per D-01 final step)
|
|
159
|
+
// AgentManager handles its own cleanup from within Electron main process.
|
|
160
|
+
registerShutdownHandlers({
|
|
161
|
+
devServer: { pid: devServer.pid },
|
|
162
|
+
electronProcess: { pid: electronProcess.pid },
|
|
163
|
+
});
|
|
164
|
+
// Dev server crash handling (per D-13): notify but do NOT exit
|
|
165
|
+
devServer.on('exit', (code, signal) => {
|
|
166
|
+
console.log(pc.yellow('\n Dev server exited.'));
|
|
167
|
+
console.log(pc.dim(' Press Ctrl+C to stop, then re-run clawdesign start'));
|
|
168
|
+
});
|
|
169
|
+
// Electron window closed -- trigger shutdown to kill dev server + Claude
|
|
170
|
+
electronProcess.on('exit', () => {
|
|
171
|
+
console.log(pc.dim('\n Claw Design window closed.'));
|
|
172
|
+
process.emit('SIGINT');
|
|
173
|
+
});
|
|
174
|
+
printReady(port);
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { startCommand } from './commands/start.js';
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
const { version } = require('../../package.json');
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name('clawdesign')
|
|
10
|
+
.description('Visual web development tool powered by Claude Code')
|
|
11
|
+
.version(version);
|
|
12
|
+
program
|
|
13
|
+
.command('start')
|
|
14
|
+
.description('Launch dev server and open visual editor')
|
|
15
|
+
.option('--cmd <command>', 'Override dev server command')
|
|
16
|
+
.option('--port <number>', 'Specify dev server port (skip auto-detection)')
|
|
17
|
+
.option('--verbose', 'Show dev server output')
|
|
18
|
+
.action(startCommand);
|
|
19
|
+
program.parse();
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,oDAAoD,CAAC;KACjE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,0CAA0C,CAAC;KACvD,MAAM,CAAC,iBAAiB,EAAE,6BAA6B,CAAC;KACxD,MAAM,CAAC,iBAAiB,EAAE,+CAA+C,CAAC;KAC1E,MAAM,CAAC,WAAW,EAAE,wBAAwB,CAAC;KAC7C,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if Claude Code CLI is installed and available in PATH.
|
|
3
|
+
* Synchronous check -- runs once at startup (per D-12).
|
|
4
|
+
*/
|
|
5
|
+
export declare function isClaudeInstalled(): boolean;
|
|
6
|
+
export interface ClaudeAuthStatus {
|
|
7
|
+
loggedIn: boolean;
|
|
8
|
+
authMethod?: string;
|
|
9
|
+
apiProvider?: string;
|
|
10
|
+
apiKeySource?: string;
|
|
11
|
+
email?: string | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Check if the user is authenticated with Claude Code.
|
|
15
|
+
*
|
|
16
|
+
* Runs `claude auth status --json` and parses the result.
|
|
17
|
+
* Returns the parsed status, or `{ loggedIn: false }` if the command
|
|
18
|
+
* fails or produces unparseable output.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getClaudeAuthStatus(): ClaudeAuthStatus;
|
|
21
|
+
//# sourceMappingURL=claude.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/claude.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAO3C;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,IAAI,gBAAgB,CAkBtD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Check if Claude Code CLI is installed and available in PATH.
|
|
4
|
+
* Synchronous check -- runs once at startup (per D-12).
|
|
5
|
+
*/
|
|
6
|
+
export function isClaudeInstalled() {
|
|
7
|
+
try {
|
|
8
|
+
execFileSync('which', ['claude'], { stdio: 'ignore' });
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Check if the user is authenticated with Claude Code.
|
|
17
|
+
*
|
|
18
|
+
* Runs `claude auth status --json` and parses the result.
|
|
19
|
+
* Returns the parsed status, or `{ loggedIn: false }` if the command
|
|
20
|
+
* fails or produces unparseable output.
|
|
21
|
+
*/
|
|
22
|
+
export function getClaudeAuthStatus() {
|
|
23
|
+
try {
|
|
24
|
+
const raw = execFileSync('claude', ['auth', 'status', '--json'], {
|
|
25
|
+
encoding: 'utf-8',
|
|
26
|
+
timeout: 10_000,
|
|
27
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
28
|
+
});
|
|
29
|
+
const parsed = JSON.parse(raw.trim());
|
|
30
|
+
return {
|
|
31
|
+
loggedIn: Boolean(parsed.loggedIn),
|
|
32
|
+
authMethod: parsed.authMethod,
|
|
33
|
+
apiProvider: parsed.apiProvider,
|
|
34
|
+
apiKeySource: parsed.apiKeySource,
|
|
35
|
+
email: parsed.email,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return { loggedIn: false };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../../src/cli/utils/claude.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC;QACH,YAAY,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAUD;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB;IACjC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE;YAC/D,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,MAAM;YACf,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QACtC,OAAO;YACL,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;YAClC,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ChildProcess } from 'node:child_process';
|
|
2
|
+
export declare const SCRIPT_PRIORITY: readonly ["dev", "start", "serve"];
|
|
3
|
+
export declare class DetectionError extends Error {
|
|
4
|
+
constructor(message: string);
|
|
5
|
+
}
|
|
6
|
+
export interface DetectedScript {
|
|
7
|
+
name: string;
|
|
8
|
+
command: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function detectDevServerScript(projectDir: string): Promise<DetectedScript>;
|
|
11
|
+
export type PackageManager = 'npm' | 'pnpm' | 'bun';
|
|
12
|
+
export declare function detectPackageManager(projectDir: string): Promise<PackageManager>;
|
|
13
|
+
export declare function spawnDevServer(command: string, verbose: boolean): ChildProcess;
|
|
14
|
+
//# sourceMappingURL=dev-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/dev-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE9D,eAAO,MAAM,eAAe,oCAAqC,CAAC;AAElE,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,cAAc,CAAC,CAoBzB;AAED,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;AASpD,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAUtF;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,GACf,YAAY,CAad"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { readFile, access } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
export const SCRIPT_PRIORITY = ['dev', 'start', 'serve'];
|
|
5
|
+
export class DetectionError extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'DetectionError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export async function detectDevServerScript(projectDir) {
|
|
12
|
+
const pkgPath = join(projectDir, 'package.json');
|
|
13
|
+
const raw = await readFile(pkgPath, 'utf-8');
|
|
14
|
+
const pkg = JSON.parse(raw);
|
|
15
|
+
if (!pkg.scripts) {
|
|
16
|
+
throw new DetectionError('No "scripts" field found in package.json');
|
|
17
|
+
}
|
|
18
|
+
for (const name of SCRIPT_PRIORITY) {
|
|
19
|
+
if (pkg.scripts[name]) {
|
|
20
|
+
return { name, command: pkg.scripts[name] };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
throw new DetectionError(`No dev server script found in package.json.\n` +
|
|
24
|
+
` Looked for: ${SCRIPT_PRIORITY.join(', ')}\n` +
|
|
25
|
+
` Tip: use --cmd "your-dev-command" to specify manually`);
|
|
26
|
+
}
|
|
27
|
+
const LOCKFILE_MAP = [
|
|
28
|
+
['bun.lock', 'bun'],
|
|
29
|
+
['bun.lockb', 'bun'],
|
|
30
|
+
['pnpm-lock.yaml', 'pnpm'],
|
|
31
|
+
['package-lock.json', 'npm'],
|
|
32
|
+
];
|
|
33
|
+
export async function detectPackageManager(projectDir) {
|
|
34
|
+
for (const [lockfile, pm] of LOCKFILE_MAP) {
|
|
35
|
+
try {
|
|
36
|
+
await access(join(projectDir, lockfile));
|
|
37
|
+
return pm;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// lockfile not found, try next
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return 'npm';
|
|
44
|
+
}
|
|
45
|
+
export function spawnDevServer(command, verbose) {
|
|
46
|
+
const child = spawn(command, {
|
|
47
|
+
shell: true,
|
|
48
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
49
|
+
cwd: process.cwd(),
|
|
50
|
+
});
|
|
51
|
+
if (verbose) {
|
|
52
|
+
child.stdout?.pipe(process.stdout);
|
|
53
|
+
child.stderr?.pipe(process.stderr);
|
|
54
|
+
}
|
|
55
|
+
return child;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=dev-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-server.js","sourceRoot":"","sources":["../../../src/cli/utils/dev-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAE9D,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAU,CAAC;AAElE,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAOD,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,UAAkB;IAElB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAE5B,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,IAAI,cAAc,CAAC,0CAA0C,CAAC,CAAC;IACvE,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;QACnC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,MAAM,IAAI,cAAc,CACtB,+CAA+C;QAC7C,iBAAiB,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QAC/C,yDAAyD,CAC5D,CAAC;AACJ,CAAC;AAID,MAAM,YAAY,GAAoC;IACpD,CAAC,UAAU,EAAE,KAAK,CAAC;IACnB,CAAC,WAAW,EAAE,KAAK,CAAC;IACpB,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAC1B,CAAC,mBAAmB,EAAE,KAAK,CAAC;CAC7B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,UAAkB;IAC3D,KAAK,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,YAAY,EAAE,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;YACzC,OAAO,EAAE,CAAC;QACZ,CAAC;QAAC,MAAM,CAAC;YACP,+BAA+B;QACjC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,OAAe,EACf,OAAgB;IAEhB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE;QAC3B,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;QACjC,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;KACnB,CAAC,CAAC;IAEH,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACnC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ChildProcess } from 'node:child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Spawn the Electron binary with the built main process script.
|
|
4
|
+
* Passes URL and project metadata via environment variables.
|
|
5
|
+
*/
|
|
6
|
+
export declare function spawnElectron(url: string, projectName: string): ChildProcess;
|
|
7
|
+
//# sourceMappingURL=electron.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"electron.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/electron.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAQ9D;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY,CA4B5E"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
/**
|
|
8
|
+
* Spawn the Electron binary with the built main process script.
|
|
9
|
+
* Passes URL and project metadata via environment variables.
|
|
10
|
+
*/
|
|
11
|
+
export function spawnElectron(url, projectName) {
|
|
12
|
+
// Resolve electron binary path from the electron npm package
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
const electronPath = require('electron');
|
|
15
|
+
// Path to built main process (from electron-vite build output)
|
|
16
|
+
const projectRoot = path.resolve(__dirname, '..', '..', '..');
|
|
17
|
+
const mainScript = path.join(projectRoot, 'out', 'main', 'index.js');
|
|
18
|
+
const child = spawn(electronPath, [mainScript], {
|
|
19
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
20
|
+
env: {
|
|
21
|
+
...process.env,
|
|
22
|
+
CLAW_URL: url,
|
|
23
|
+
CLAW_PROJECT_NAME: projectName,
|
|
24
|
+
CLAW_PROJECT_DIR: process.cwd(),
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
// Forward Electron main process logs to CLI terminal
|
|
28
|
+
child.stdout?.on('data', (chunk) => {
|
|
29
|
+
process.stdout.write(chunk);
|
|
30
|
+
});
|
|
31
|
+
child.stderr?.on('data', (chunk) => {
|
|
32
|
+
process.stderr.write(chunk);
|
|
33
|
+
});
|
|
34
|
+
return child;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=electron.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"electron.js","sourceRoot":"","sources":["../../../src/cli/utils/electron.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,WAAmB;IAC5D,6DAA6D;IAC7D,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,CAAsB,CAAC;IAE9D,+DAA+D;IAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IAErE,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,EAAE,CAAC,UAAU,CAAC,EAAE;QAC9C,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;QAC/B,GAAG,EAAE;YACH,GAAG,OAAO,CAAC,GAAG;YACd,QAAQ,EAAE,GAAG;YACb,iBAAiB,EAAE,WAAW;YAC9B,gBAAgB,EAAE,OAAO,CAAC,GAAG,EAAE;SAChC;KACF,CAAC,CAAC;IAEH,qDAAqD;IACrD,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;QACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;QACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type Ora } from 'ora';
|
|
2
|
+
export declare function createSpinner(text: string): Ora;
|
|
3
|
+
export declare function printHeader(version: string): void;
|
|
4
|
+
export declare function printReady(port: number): void;
|
|
5
|
+
export declare function printError(title: string, message: string, suggestion?: string): void;
|
|
6
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/output.ts"],"names":[],"mappings":"AAAA,OAAY,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAGpC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAE/C;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI7C;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAClB,IAAI,CAMN"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
export function createSpinner(text) {
|
|
4
|
+
return ora(text).start();
|
|
5
|
+
}
|
|
6
|
+
export function printHeader(version) {
|
|
7
|
+
console.log(pc.bold(`clawdesign v${version}`));
|
|
8
|
+
}
|
|
9
|
+
export function printReady(port) {
|
|
10
|
+
console.log(`\n ${pc.green('Ready!')}`);
|
|
11
|
+
console.log(pc.dim(` Dev server: http://localhost:${port}`));
|
|
12
|
+
console.log(pc.dim(' Press Ctrl+C to stop'));
|
|
13
|
+
}
|
|
14
|
+
export function printError(title, message, suggestion) {
|
|
15
|
+
console.error(`\n ${pc.red('\u2718')} ${pc.bold(title)}`);
|
|
16
|
+
console.error(` ${message}`);
|
|
17
|
+
if (suggestion) {
|
|
18
|
+
console.error(pc.dim(` ${suggestion}`));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/cli/utils/output.ts"],"names":[],"mappings":"AAAA,OAAO,GAAiB,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,kCAAkC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,KAAa,EACb,OAAe,EACf,UAAmB;IAEnB,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3D,OAAO,CAAC,KAAK,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;IAC9B,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,UAAU,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ordered patterns for extracting port numbers from dev server stdout.
|
|
3
|
+
* Most specific first to avoid false positives (Pitfall 4 from research).
|
|
4
|
+
*/
|
|
5
|
+
export declare const PORT_PATTERNS: readonly RegExp[];
|
|
6
|
+
/**
|
|
7
|
+
* Extract a port number from dev server output text.
|
|
8
|
+
* Tests patterns from most specific (URL) to least specific (colon:digits).
|
|
9
|
+
* Filters out error lines to avoid false positives from port-in-use messages.
|
|
10
|
+
* Returns null if no valid port found.
|
|
11
|
+
*/
|
|
12
|
+
export declare function extractPortFromOutput(output: string): number | null;
|
|
13
|
+
/**
|
|
14
|
+
* Poll a TCP port until it accepts connections or timeout expires.
|
|
15
|
+
* Default timeout: 30s (per D-09). Default poll interval: 250ms.
|
|
16
|
+
*/
|
|
17
|
+
export declare function waitForPort(port: number, opts?: {
|
|
18
|
+
timeout?: number;
|
|
19
|
+
interval?: number;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Attempt to identify which process is listening on a given port.
|
|
23
|
+
* Best-effort -- returns null if lsof/ps unavailable or port is free.
|
|
24
|
+
* Used for D-14: port-in-use diagnostics.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getProcessOnPort(port: number): {
|
|
27
|
+
pid: number;
|
|
28
|
+
name: string;
|
|
29
|
+
} | null;
|
|
30
|
+
//# sourceMappingURL=port-detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-detect.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/port-detect.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,MAAM,EASjC,CAAC;AASX;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAenE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GACX;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAkBtC"}
|