@vibelet/cli 0.1.37 → 1.0.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/README.md +80 -0
- package/bin/cloudflared-quick-tunnel.mjs +11 -0
- package/bin/cloudflared-resolver.mjs +171 -0
- package/bin/vibelet-runtime-policy.mjs +36 -0
- package/bin/vibelet.cjs +12 -0
- package/bin/vibelet.mjs +1062 -0
- package/dist/index.cjs +126 -0
- package/package.json +25 -24
- package/app.json +0 -5
- package/dist/advertised-hosts.d.ts +0 -34
- package/dist/advertised-hosts.d.ts.map +0 -1
- package/dist/advertised-hosts.js +0 -176
- package/dist/advertised-hosts.js.map +0 -1
- package/dist/advertised-hosts.test.d.ts +0 -2
- package/dist/advertised-hosts.test.d.ts.map +0 -1
- package/dist/advertised-hosts.test.js +0 -96
- package/dist/advertised-hosts.test.js.map +0 -1
- package/dist/audit.d.ts +0 -30
- package/dist/audit.d.ts.map +0 -1
- package/dist/audit.js +0 -73
- package/dist/audit.js.map +0 -1
- package/dist/audit.test.d.ts +0 -2
- package/dist/audit.test.d.ts.map +0 -1
- package/dist/audit.test.js +0 -33
- package/dist/audit.test.js.map +0 -1
- package/dist/auth.d.ts +0 -6
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js +0 -27
- package/dist/auth.js.map +0 -1
- package/dist/claude-hooks.d.ts +0 -58
- package/dist/claude-hooks.d.ts.map +0 -1
- package/dist/claude-hooks.js +0 -129
- package/dist/claude-hooks.js.map +0 -1
- package/dist/cli-version.d.ts +0 -3
- package/dist/cli-version.d.ts.map +0 -1
- package/dist/cli-version.js +0 -35
- package/dist/cli-version.js.map +0 -1
- package/dist/cli-version.test.d.ts +0 -2
- package/dist/cli-version.test.d.ts.map +0 -1
- package/dist/cli-version.test.js +0 -38
- package/dist/cli-version.test.js.map +0 -1
- package/dist/config.d.ts +0 -30
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -327
- package/dist/config.js.map +0 -1
- package/dist/config.test.d.ts +0 -2
- package/dist/config.test.d.ts.map +0 -1
- package/dist/config.test.js +0 -184
- package/dist/config.test.js.map +0 -1
- package/dist/dev-auth.test.d.ts +0 -2
- package/dist/dev-auth.test.d.ts.map +0 -1
- package/dist/dev-auth.test.js +0 -154
- package/dist/dev-auth.test.js.map +0 -1
- package/dist/dev-script.test.d.ts +0 -2
- package/dist/dev-script.test.d.ts.map +0 -1
- package/dist/dev-script.test.js +0 -412
- package/dist/dev-script.test.js.map +0 -1
- package/dist/drivers/claude.d.ts +0 -34
- package/dist/drivers/claude.d.ts.map +0 -1
- package/dist/drivers/claude.js +0 -413
- package/dist/drivers/claude.js.map +0 -1
- package/dist/drivers/claude.test.d.ts +0 -2
- package/dist/drivers/claude.test.d.ts.map +0 -1
- package/dist/drivers/claude.test.js +0 -951
- package/dist/drivers/claude.test.js.map +0 -1
- package/dist/drivers/codex.d.ts +0 -38
- package/dist/drivers/codex.d.ts.map +0 -1
- package/dist/drivers/codex.js +0 -771
- package/dist/drivers/codex.js.map +0 -1
- package/dist/drivers/codex.test.d.ts +0 -2
- package/dist/drivers/codex.test.d.ts.map +0 -1
- package/dist/drivers/codex.test.js +0 -939
- package/dist/drivers/codex.test.js.map +0 -1
- package/dist/drivers/types.d.ts +0 -14
- package/dist/drivers/types.d.ts.map +0 -1
- package/dist/drivers/types.js +0 -2
- package/dist/drivers/types.js.map +0 -1
- package/dist/e2e.test.d.ts +0 -2
- package/dist/e2e.test.d.ts.map +0 -1
- package/dist/e2e.test.js +0 -111
- package/dist/e2e.test.js.map +0 -1
- package/dist/identity.d.ts +0 -10
- package/dist/identity.d.ts.map +0 -1
- package/dist/identity.js +0 -66
- package/dist/identity.js.map +0 -1
- package/dist/identity.test.d.ts +0 -2
- package/dist/identity.test.d.ts.map +0 -1
- package/dist/identity.test.js +0 -25
- package/dist/identity.test.js.map +0 -1
- package/dist/index-entry.test.d.ts +0 -2
- package/dist/index-entry.test.d.ts.map +0 -1
- package/dist/index-entry.test.js +0 -272
- package/dist/index-entry.test.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -707
- package/dist/index.js.map +0 -1
- package/dist/logger.d.ts +0 -31
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -75
- package/dist/logger.js.map +0 -1
- package/dist/metrics.d.ts +0 -52
- package/dist/metrics.d.ts.map +0 -1
- package/dist/metrics.js +0 -89
- package/dist/metrics.js.map +0 -1
- package/dist/pairing-store.d.ts +0 -29
- package/dist/pairing-store.d.ts.map +0 -1
- package/dist/pairing-store.js +0 -131
- package/dist/pairing-store.js.map +0 -1
- package/dist/pairing-store.test.d.ts +0 -2
- package/dist/pairing-store.test.d.ts.map +0 -1
- package/dist/pairing-store.test.js +0 -47
- package/dist/pairing-store.test.js.map +0 -1
- package/dist/paths.d.ts +0 -16
- package/dist/paths.d.ts.map +0 -1
- package/dist/paths.js +0 -18
- package/dist/paths.js.map +0 -1
- package/dist/perf-compare.d.ts +0 -13
- package/dist/perf-compare.d.ts.map +0 -1
- package/dist/perf-compare.js +0 -125
- package/dist/perf-compare.js.map +0 -1
- package/dist/port-conflict.d.ts +0 -9
- package/dist/port-conflict.d.ts.map +0 -1
- package/dist/port-conflict.js +0 -33
- package/dist/port-conflict.js.map +0 -1
- package/dist/port-conflict.test.d.ts +0 -2
- package/dist/port-conflict.test.d.ts.map +0 -1
- package/dist/port-conflict.test.js +0 -38
- package/dist/port-conflict.test.js.map +0 -1
- package/dist/process-scanner.d.ts +0 -43
- package/dist/process-scanner.d.ts.map +0 -1
- package/dist/process-scanner.js +0 -453
- package/dist/process-scanner.js.map +0 -1
- package/dist/process-scanner.perf.test.d.ts +0 -2
- package/dist/process-scanner.perf.test.d.ts.map +0 -1
- package/dist/process-scanner.perf.test.js +0 -186
- package/dist/process-scanner.perf.test.js.map +0 -1
- package/dist/process-scanner.test.d.ts +0 -2
- package/dist/process-scanner.test.d.ts.map +0 -1
- package/dist/process-scanner.test.js +0 -399
- package/dist/process-scanner.test.js.map +0 -1
- package/dist/push-protocol.d.ts +0 -15
- package/dist/push-protocol.d.ts.map +0 -1
- package/dist/push-protocol.js +0 -23
- package/dist/push-protocol.js.map +0 -1
- package/dist/push-protocol.test.d.ts +0 -2
- package/dist/push-protocol.test.d.ts.map +0 -1
- package/dist/push-protocol.test.js +0 -57
- package/dist/push-protocol.test.js.map +0 -1
- package/dist/push-store.d.ts +0 -22
- package/dist/push-store.d.ts.map +0 -1
- package/dist/push-store.js +0 -103
- package/dist/push-store.js.map +0 -1
- package/dist/push-store.test.d.ts +0 -2
- package/dist/push-store.test.d.ts.map +0 -1
- package/dist/push-store.test.js +0 -79
- package/dist/push-store.test.js.map +0 -1
- package/dist/push.d.ts +0 -65
- package/dist/push.d.ts.map +0 -1
- package/dist/push.js +0 -202
- package/dist/push.js.map +0 -1
- package/dist/push.test.d.ts +0 -2
- package/dist/push.test.d.ts.map +0 -1
- package/dist/push.test.js +0 -199
- package/dist/push.test.js.map +0 -1
- package/dist/safe-stdio.d.ts +0 -3
- package/dist/safe-stdio.d.ts.map +0 -1
- package/dist/safe-stdio.js +0 -46
- package/dist/safe-stdio.js.map +0 -1
- package/dist/scanner.d.ts +0 -30
- package/dist/scanner.d.ts.map +0 -1
- package/dist/scanner.js +0 -859
- package/dist/scanner.js.map +0 -1
- package/dist/scanner.perf.test.d.ts +0 -2
- package/dist/scanner.perf.test.d.ts.map +0 -1
- package/dist/scanner.perf.test.js +0 -320
- package/dist/scanner.perf.test.js.map +0 -1
- package/dist/scanner.test.d.ts +0 -2
- package/dist/scanner.test.d.ts.map +0 -1
- package/dist/scanner.test.js +0 -948
- package/dist/scanner.test.js.map +0 -1
- package/dist/session-inventory.d.ts +0 -63
- package/dist/session-inventory.d.ts.map +0 -1
- package/dist/session-inventory.js +0 -525
- package/dist/session-inventory.js.map +0 -1
- package/dist/session-inventory.perf.test.d.ts +0 -2
- package/dist/session-inventory.perf.test.d.ts.map +0 -1
- package/dist/session-inventory.perf.test.js +0 -220
- package/dist/session-inventory.perf.test.js.map +0 -1
- package/dist/session-inventory.test.d.ts +0 -2
- package/dist/session-inventory.test.d.ts.map +0 -1
- package/dist/session-inventory.test.js +0 -712
- package/dist/session-inventory.test.js.map +0 -1
- package/dist/session-manager.d.ts +0 -75
- package/dist/session-manager.d.ts.map +0 -1
- package/dist/session-manager.js +0 -1515
- package/dist/session-manager.js.map +0 -1
- package/dist/session-manager.test.d.ts +0 -2
- package/dist/session-manager.test.d.ts.map +0 -1
- package/dist/session-manager.test.js +0 -2861
- package/dist/session-manager.test.js.map +0 -1
- package/dist/session-store.d.ts +0 -42
- package/dist/session-store.d.ts.map +0 -1
- package/dist/session-store.js +0 -163
- package/dist/session-store.js.map +0 -1
- package/dist/session-store.test.d.ts +0 -2
- package/dist/session-store.test.d.ts.map +0 -1
- package/dist/session-store.test.js +0 -236
- package/dist/session-store.test.js.map +0 -1
- package/dist/session-title.d.ts +0 -6
- package/dist/session-title.d.ts.map +0 -1
- package/dist/session-title.js +0 -105
- package/dist/session-title.js.map +0 -1
- package/dist/session-title.perf.test.d.ts +0 -2
- package/dist/session-title.perf.test.d.ts.map +0 -1
- package/dist/session-title.perf.test.js +0 -99
- package/dist/session-title.perf.test.js.map +0 -1
- package/dist/session-title.test.d.ts +0 -2
- package/dist/session-title.test.d.ts.map +0 -1
- package/dist/session-title.test.js +0 -199
- package/dist/session-title.test.js.map +0 -1
- package/dist/shutdown-endpoint.test.d.ts +0 -2
- package/dist/shutdown-endpoint.test.d.ts.map +0 -1
- package/dist/shutdown-endpoint.test.js +0 -93
- package/dist/shutdown-endpoint.test.js.map +0 -1
- package/dist/storage-housekeeping.d.ts +0 -28
- package/dist/storage-housekeeping.d.ts.map +0 -1
- package/dist/storage-housekeeping.js +0 -76
- package/dist/storage-housekeeping.js.map +0 -1
- package/dist/storage-housekeeping.test.d.ts +0 -2
- package/dist/storage-housekeeping.test.d.ts.map +0 -1
- package/dist/storage-housekeeping.test.js +0 -65
- package/dist/storage-housekeeping.test.js.map +0 -1
- package/dist/test-daemon-harness.d.ts +0 -31
- package/dist/test-daemon-harness.d.ts.map +0 -1
- package/dist/test-daemon-harness.js +0 -337
- package/dist/test-daemon-harness.js.map +0 -1
- package/dist/token-auth.test.d.ts +0 -2
- package/dist/token-auth.test.d.ts.map +0 -1
- package/dist/token-auth.test.js +0 -52
- package/dist/token-auth.test.js.map +0 -1
- package/dist/utils.d.ts +0 -4
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -40
- package/dist/utils.js.map +0 -1
- package/dist/utils.test.d.ts +0 -2
- package/dist/utils.test.d.ts.map +0 -1
- package/dist/utils.test.js +0 -54
- package/dist/utils.test.js.map +0 -1
- package/dist/ws-data.d.ts +0 -4
- package/dist/ws-data.d.ts.map +0 -1
- package/dist/ws-data.js +0 -20
- package/dist/ws-data.js.map +0 -1
- package/dist/ws-data.test.d.ts +0 -2
- package/dist/ws-data.test.d.ts.map +0 -1
- package/dist/ws-data.test.js +0 -17
- package/dist/ws-data.test.js.map +0 -1
- package/perf-reporter.mjs +0 -138
- package/scripts/build-release.mjs +0 -41
- package/scripts/dev.mjs +0 -537
- package/src/advertised-hosts.test.ts +0 -125
- package/src/advertised-hosts.ts +0 -225
- package/src/audit.test.ts +0 -38
- package/src/audit.ts +0 -117
- package/src/auth.ts +0 -31
- package/src/claude-hooks.ts +0 -195
- package/src/cli-version.test.ts +0 -36
- package/src/cli-version.ts +0 -46
- package/src/config.test.ts +0 -254
- package/src/config.ts +0 -324
- package/src/dev-auth.test.ts +0 -183
- package/src/dev-script.test.ts +0 -511
- package/src/drivers/claude.test.ts +0 -1186
- package/src/drivers/claude.ts +0 -443
- package/src/drivers/codex.test.ts +0 -1096
- package/src/drivers/codex.ts +0 -879
- package/src/drivers/types.ts +0 -15
- package/src/e2e.test.ts +0 -139
- package/src/identity.test.ts +0 -26
- package/src/identity.ts +0 -82
- package/src/index-entry.test.ts +0 -336
- package/src/index.ts +0 -781
- package/src/logger.ts +0 -112
- package/src/metrics.ts +0 -117
- package/src/pairing-store.test.ts +0 -53
- package/src/pairing-store.ts +0 -154
- package/src/paths.ts +0 -19
- package/src/perf-compare.ts +0 -164
- package/src/port-conflict.test.ts +0 -45
- package/src/port-conflict.ts +0 -44
- package/src/process-scanner.perf.test.ts +0 -222
- package/src/process-scanner.test.ts +0 -575
- package/src/process-scanner.ts +0 -514
- package/src/push-protocol.test.ts +0 -74
- package/src/push-protocol.ts +0 -36
- package/src/push-store.test.ts +0 -89
- package/src/push-store.ts +0 -126
- package/src/push.test.ts +0 -234
- package/src/push.ts +0 -318
- package/src/safe-stdio.ts +0 -51
- package/src/scanner.perf.test.ts +0 -359
- package/src/scanner.test.ts +0 -1045
- package/src/scanner.ts +0 -924
- package/src/session-inventory.perf.test.ts +0 -250
- package/src/session-inventory.test.ts +0 -1002
- package/src/session-inventory.ts +0 -721
- package/src/session-manager.test.ts +0 -3430
- package/src/session-manager.ts +0 -1775
- package/src/session-store.test.ts +0 -276
- package/src/session-store.ts +0 -202
- package/src/session-title.perf.test.ts +0 -118
- package/src/session-title.test.ts +0 -286
- package/src/session-title.ts +0 -108
- package/src/shutdown-endpoint.test.ts +0 -95
- package/src/storage-housekeeping.test.ts +0 -78
- package/src/storage-housekeeping.ts +0 -111
- package/src/test-daemon-harness.ts +0 -410
- package/src/token-auth.test.ts +0 -67
- package/src/utils.test.ts +0 -65
- package/src/utils.ts +0 -47
- package/src/ws-data.test.ts +0 -20
- package/src/ws-data.ts +0 -26
- package/tsconfig.json +0 -12
package/perf-reporter.mjs
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Custom Node.js test reporter that extracts performance metrics
|
|
3
|
-
* and writes them to a JSON baseline file.
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* pnpm test:perf:baseline
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
function parseMetrics(text) {
|
|
10
|
-
const metrics = {};
|
|
11
|
-
const totalMatch = text.match(/([\d.]+)ms\s+total/);
|
|
12
|
-
if (totalMatch) metrics.totalMs = parseFloat(totalMatch[1]);
|
|
13
|
-
const avgMatch = text.match(/([\d.]+)ms\s+avg/);
|
|
14
|
-
if (avgMatch) metrics.avgMs = parseFloat(avgMatch[1]);
|
|
15
|
-
const forMatch = text.match(/([\d.]+)ms\s+for\s+(\d+)\s+calls/);
|
|
16
|
-
if (forMatch) {
|
|
17
|
-
metrics.totalMs = parseFloat(forMatch[1]);
|
|
18
|
-
metrics.calls = parseInt(forMatch[2], 10);
|
|
19
|
-
}
|
|
20
|
-
const coldMatch = text.match(/cold:\s*([\d.]+)ms/);
|
|
21
|
-
if (coldMatch) metrics.coldMs = parseFloat(coldMatch[1]);
|
|
22
|
-
const cachedMatch = text.match(/cached:\s*([\d.]+)ms/);
|
|
23
|
-
if (cachedMatch) metrics.cachedMs = parseFloat(cachedMatch[1]);
|
|
24
|
-
const throttledMatch = text.match(/throttled:\s*([\d.]+)ms/);
|
|
25
|
-
if (throttledMatch) metrics.throttledMs = parseFloat(throttledMatch[1]);
|
|
26
|
-
const pagesMatch = text.match(/(\d+)\s+pages,\s+(\d+)\s+sessions,\s+([\d.]+)ms/);
|
|
27
|
-
if (pagesMatch) {
|
|
28
|
-
metrics.pages = parseInt(pagesMatch[1], 10);
|
|
29
|
-
metrics.sessions = parseInt(pagesMatch[2], 10);
|
|
30
|
-
metrics.totalMs = parseFloat(pagesMatch[3]);
|
|
31
|
-
}
|
|
32
|
-
return metrics;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Match a stdout line to its test by looking for key phrases from the test name.
|
|
37
|
-
* E.g., test "small Claude file (10 lines) × 100 < 200ms" matches stdout "small (10 lines): 23.25ms total"
|
|
38
|
-
*/
|
|
39
|
-
function findMetricsLine(allStdout, testName) {
|
|
40
|
-
// Extract a short key from the test name for matching
|
|
41
|
-
// Try to match parenthesized content like "(10 lines)", "(uuid)", "(short)", etc.
|
|
42
|
-
const parenMatch = testName.match(/\(([^)]+)\)/);
|
|
43
|
-
const keyword = parenMatch ? parenMatch[1] : null;
|
|
44
|
-
|
|
45
|
-
for (const line of allStdout) {
|
|
46
|
-
if (line.used) continue;
|
|
47
|
-
if (keyword && line.text.includes(keyword)) {
|
|
48
|
-
line.used = true;
|
|
49
|
-
return line.text;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Fallback: try matching key words from test name
|
|
54
|
-
const words = testName.toLowerCase().split(/\s+/).filter(w => w.length > 3);
|
|
55
|
-
for (const line of allStdout) {
|
|
56
|
-
if (line.used) continue;
|
|
57
|
-
const lower = line.text.toLowerCase();
|
|
58
|
-
const matchCount = words.filter(w => lower.includes(w)).length;
|
|
59
|
-
if (matchCount >= 2) {
|
|
60
|
-
line.used = true;
|
|
61
|
-
return line.text;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export default async function* perfReporter(source) {
|
|
69
|
-
const results = [];
|
|
70
|
-
const suiteStack = [];
|
|
71
|
-
// Collect all stdout lines with a used flag
|
|
72
|
-
const stdoutLines = [];
|
|
73
|
-
|
|
74
|
-
for await (const event of source) {
|
|
75
|
-
switch (event.type) {
|
|
76
|
-
case 'test:stdout':
|
|
77
|
-
if (event.data.message) {
|
|
78
|
-
// Split on newlines in case multiple lines arrive in one event
|
|
79
|
-
for (const line of event.data.message.split('\n')) {
|
|
80
|
-
const trimmed = line.trim();
|
|
81
|
-
if (trimmed) stdoutLines.push({ text: trimmed, used: false });
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
break;
|
|
85
|
-
|
|
86
|
-
case 'test:pass':
|
|
87
|
-
case 'test:fail': {
|
|
88
|
-
const name = event.data.name;
|
|
89
|
-
const nesting = event.data.nesting;
|
|
90
|
-
if (nesting === 0) break;
|
|
91
|
-
|
|
92
|
-
const suite = suiteStack.length > 0 ? suiteStack[suiteStack.length - 1] : '';
|
|
93
|
-
const durationMs = event.data.details?.duration_ms ?? 0;
|
|
94
|
-
|
|
95
|
-
// Find matching metrics from stdout
|
|
96
|
-
const metricsLine = findMetricsLine(stdoutLines, name);
|
|
97
|
-
const metrics = metricsLine ? parseMetrics(metricsLine) : {};
|
|
98
|
-
|
|
99
|
-
results.push({
|
|
100
|
-
test: name,
|
|
101
|
-
suite,
|
|
102
|
-
durationMs,
|
|
103
|
-
passed: event.type === 'test:pass',
|
|
104
|
-
metrics,
|
|
105
|
-
});
|
|
106
|
-
break;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
case 'test:dequeue':
|
|
110
|
-
if (event.data.nesting === 1) {
|
|
111
|
-
suiteStack.push(event.data.name);
|
|
112
|
-
}
|
|
113
|
-
break;
|
|
114
|
-
|
|
115
|
-
case 'test:complete':
|
|
116
|
-
if (event.data.nesting === 1) {
|
|
117
|
-
suiteStack.pop();
|
|
118
|
-
}
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const baseline = {
|
|
124
|
-
timestamp: new Date().toISOString(),
|
|
125
|
-
nodeVersion: process.version,
|
|
126
|
-
platform: process.platform,
|
|
127
|
-
arch: process.arch,
|
|
128
|
-
results,
|
|
129
|
-
summary: {
|
|
130
|
-
total: results.length,
|
|
131
|
-
passed: results.filter(r => r.passed).length,
|
|
132
|
-
failed: results.filter(r => !r.passed).length,
|
|
133
|
-
totalDurationMs: results.reduce((sum, r) => sum + r.durationMs, 0),
|
|
134
|
-
},
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
yield JSON.stringify(baseline, null, 2) + '\n';
|
|
138
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { build } from 'esbuild';
|
|
2
|
-
import { mkdirSync, readFileSync, rmSync } from 'node:fs';
|
|
3
|
-
import { dirname, resolve } from 'node:path';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
|
|
6
|
-
const daemonDir = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
7
|
-
const outdir = resolve(daemonDir, '..', '..', 'dist');
|
|
8
|
-
const rootPackageJson = JSON.parse(readFileSync(resolve(daemonDir, '..', '..', 'package.json'), 'utf8'));
|
|
9
|
-
|
|
10
|
-
rmSync(outdir, { recursive: true, force: true });
|
|
11
|
-
mkdirSync(outdir, { recursive: true });
|
|
12
|
-
|
|
13
|
-
const sharedBuildOptions = {
|
|
14
|
-
bundle: true,
|
|
15
|
-
format: 'cjs',
|
|
16
|
-
platform: 'node',
|
|
17
|
-
target: 'node18',
|
|
18
|
-
minify: true,
|
|
19
|
-
sourcemap: false,
|
|
20
|
-
legalComments: 'none',
|
|
21
|
-
logLevel: 'info',
|
|
22
|
-
define: {
|
|
23
|
-
'process.env.VIBELET_CLI_VERSION': JSON.stringify(rootPackageJson.version),
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
await build({
|
|
28
|
-
...sharedBuildOptions,
|
|
29
|
-
entryPoints: [resolve(daemonDir, 'src/index.ts')],
|
|
30
|
-
outfile: resolve(outdir, 'index.cjs'),
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
await build({
|
|
34
|
-
...sharedBuildOptions,
|
|
35
|
-
stdin: {
|
|
36
|
-
contents: "import { CLI_VERSION } from './src/cli-version.ts'; process.stdout.write(`${CLI_VERSION}\\n`);",
|
|
37
|
-
resolveDir: daemonDir,
|
|
38
|
-
sourcefile: 'runtime-version-entry.ts',
|
|
39
|
-
},
|
|
40
|
-
outfile: resolve(outdir, 'runtime-version.cjs'),
|
|
41
|
-
});
|
package/scripts/dev.mjs
DELETED
|
@@ -1,537 +0,0 @@
|
|
|
1
|
-
import { execFileSync, spawn } from 'node:child_process';
|
|
2
|
-
import { mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
-
import { Socket } from 'node:net';
|
|
4
|
-
import { constants as osConstants, homedir } from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { createRequire } from 'node:module';
|
|
8
|
-
import { extractQuickTunnelUrl } from '../../../bin/cloudflared-quick-tunnel.mjs';
|
|
9
|
-
import { formatCloudflaredFailureMessage, resolveCloudflaredLaunchSpec } from '../../../bin/cloudflared-resolver.mjs';
|
|
10
|
-
|
|
11
|
-
const require = createRequire(import.meta.url);
|
|
12
|
-
const currentScriptPath = fileURLToPath(import.meta.url);
|
|
13
|
-
const scriptDir = path.dirname(currentScriptPath);
|
|
14
|
-
const daemonDir = path.resolve(scriptDir, '..');
|
|
15
|
-
const rootPackageJson = JSON.parse(readFileSync(path.resolve(daemonDir, '..', '..', 'package.json'), 'utf8'));
|
|
16
|
-
const tsxPackageJsonPath = require.resolve('tsx/package.json');
|
|
17
|
-
const tsxCliPath = path.resolve(path.dirname(tsxPackageJsonPath), 'dist/cli.mjs');
|
|
18
|
-
const supportsDetachedGroupKill = process.platform !== 'win32';
|
|
19
|
-
const vibeletDir = path.join(homedir(), '.vibelet');
|
|
20
|
-
const relayConfigPath = path.join(vibeletDir, 'relay.json');
|
|
21
|
-
|
|
22
|
-
let shuttingDown = false;
|
|
23
|
-
let forceKillTimer;
|
|
24
|
-
|
|
25
|
-
function fail(message) {
|
|
26
|
-
console.error(`[dev] ${message}`);
|
|
27
|
-
process.exit(1);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function parseNamedArg(name) {
|
|
31
|
-
const inlinePrefix = `--${name}=`;
|
|
32
|
-
const inlineArg = process.argv.find((arg) => arg.startsWith(inlinePrefix));
|
|
33
|
-
if (inlineArg) {
|
|
34
|
-
return inlineArg.slice(inlinePrefix.length);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const idx = process.argv.indexOf(`--${name}`);
|
|
38
|
-
if (idx === -1) return null;
|
|
39
|
-
const value = process.argv[idx + 1];
|
|
40
|
-
if (!value || value.startsWith('-')) {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
return value;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function parseCommandArg(argv) {
|
|
47
|
-
const positionalArgs = [];
|
|
48
|
-
const namedArgsWithValues = new Set(['--relay', '--host', '--fallback-hosts']);
|
|
49
|
-
|
|
50
|
-
for (let index = 2; index < argv.length; index += 1) {
|
|
51
|
-
const arg = argv[index];
|
|
52
|
-
if (!arg || arg === '--') continue;
|
|
53
|
-
|
|
54
|
-
if (namedArgsWithValues.has(arg)) {
|
|
55
|
-
index += 1;
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (
|
|
60
|
-
arg.startsWith('--relay=')
|
|
61
|
-
|| arg.startsWith('--host=')
|
|
62
|
-
|| arg.startsWith('--fallback-hosts=')
|
|
63
|
-
|| arg.startsWith('--')
|
|
64
|
-
) {
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
positionalArgs.push(arg);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (positionalArgs.length === 0) {
|
|
72
|
-
return 'start';
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (positionalArgs.length > 1) {
|
|
76
|
-
fail(`Too many positional arguments: ${positionalArgs.join(' ')}`);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return positionalArgs[0];
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function readNpmConfigArg(name) {
|
|
83
|
-
const envKey = `npm_config_${name.replace(/-/g, '_')}`;
|
|
84
|
-
const value = process.env[envKey];
|
|
85
|
-
return typeof value === 'string' ? value : null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function loadRelayConfig() {
|
|
89
|
-
try {
|
|
90
|
-
const data = JSON.parse(readFileSync(relayConfigPath, 'utf8'));
|
|
91
|
-
return typeof data.relayUrl === 'string' ? data.relayUrl : '';
|
|
92
|
-
} catch {
|
|
93
|
-
return '';
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function saveRelayConfig(relayUrl) {
|
|
98
|
-
mkdirSync(vibeletDir, { recursive: true });
|
|
99
|
-
writeFileSync(relayConfigPath, JSON.stringify({ relayUrl }, null, 2) + '\n', 'utf8');
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function clearRelayConfig() {
|
|
103
|
-
rmSync(relayConfigPath, { force: true });
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// ─── Tunnel management (shared logic with vibelet.mjs) ──────────────────────
|
|
107
|
-
|
|
108
|
-
const port = Number(process.env.VIBE_PORT) || 9876;
|
|
109
|
-
const tunnelStatePath = path.join(vibeletDir, 'tunnel.json');
|
|
110
|
-
const devStatePath = path.join(vibeletDir, `dev-daemon-${port}.json`);
|
|
111
|
-
const logDir = path.join(vibeletDir, 'logs');
|
|
112
|
-
const command = parseCommandArg(process.argv);
|
|
113
|
-
|
|
114
|
-
if (command !== 'start' && command !== 'restart') {
|
|
115
|
-
fail(`Unknown command: ${command}. Use \`start\` or \`restart\`.`);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function consumeFlag(name) {
|
|
119
|
-
const idx = process.argv.indexOf(`--${name}`);
|
|
120
|
-
if (idx === -1) return false;
|
|
121
|
-
process.argv.splice(idx, 1);
|
|
122
|
-
return true;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function isProcessAlive(pid) {
|
|
126
|
-
try { process.kill(pid, 0); return true; } catch { return false; }
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function loadTunnelState() {
|
|
130
|
-
try { return JSON.parse(readFileSync(tunnelStatePath, 'utf8')); } catch { return null; }
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function saveTunnelState(pid, url) {
|
|
134
|
-
mkdirSync(vibeletDir, { recursive: true });
|
|
135
|
-
writeFileSync(tunnelStatePath, JSON.stringify({ pid, url }, null, 2) + '\n', 'utf8');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function clearTunnelState() { rmSync(tunnelStatePath, { force: true }); }
|
|
139
|
-
|
|
140
|
-
function readDevState() {
|
|
141
|
-
try {
|
|
142
|
-
const parsed = JSON.parse(readFileSync(devStatePath, 'utf8'));
|
|
143
|
-
const pid = Number(parsed?.pid);
|
|
144
|
-
return Number.isFinite(pid) && pid > 0 ? { pid } : null;
|
|
145
|
-
} catch {
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function writeDevState(pid = process.pid) {
|
|
151
|
-
mkdirSync(vibeletDir, { recursive: true });
|
|
152
|
-
writeFileSync(devStatePath, JSON.stringify({ pid, port }, null, 2) + '\n', 'utf8');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function clearDevState(expectedPid = process.pid) {
|
|
156
|
-
const state = readDevState();
|
|
157
|
-
if (state && state.pid !== expectedPid) {
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
rmSync(devStatePath, { force: true });
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function stopTunnel() {
|
|
164
|
-
const state = loadTunnelState();
|
|
165
|
-
if (state?.pid && isProcessAlive(state.pid)) {
|
|
166
|
-
try { process.kill(state.pid, 'SIGTERM'); } catch { /* */ }
|
|
167
|
-
}
|
|
168
|
-
clearTunnelState();
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function getAliveTunnel() {
|
|
172
|
-
const state = loadTunnelState();
|
|
173
|
-
return (state?.pid && state?.url && isProcessAlive(state.pid)) ? state : null;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function readCommandForPid(pid) {
|
|
177
|
-
try {
|
|
178
|
-
return execFileSync('ps', ['-p', String(pid), '-o', 'command='], {
|
|
179
|
-
encoding: 'utf8',
|
|
180
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
181
|
-
}).trim();
|
|
182
|
-
} catch {
|
|
183
|
-
return '';
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function getTrackedWrapperPid() {
|
|
188
|
-
const state = readDevState();
|
|
189
|
-
if (!state || state.pid === process.pid) {
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
if (!isProcessAlive(state.pid)) {
|
|
193
|
-
clearDevState(state.pid);
|
|
194
|
-
return null;
|
|
195
|
-
}
|
|
196
|
-
const commandLine = readCommandForPid(state.pid);
|
|
197
|
-
if (!commandLine.includes(currentScriptPath)) {
|
|
198
|
-
return null;
|
|
199
|
-
}
|
|
200
|
-
return state.pid;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function delay(ms) {
|
|
204
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function isPortListening(targetPort) {
|
|
208
|
-
return new Promise((resolve) => {
|
|
209
|
-
const socket = new Socket();
|
|
210
|
-
|
|
211
|
-
const finish = (result) => {
|
|
212
|
-
socket.removeAllListeners();
|
|
213
|
-
socket.destroy();
|
|
214
|
-
resolve(result);
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
socket.setTimeout(200);
|
|
218
|
-
socket.once('connect', () => finish(true));
|
|
219
|
-
socket.once('timeout', () => finish(false));
|
|
220
|
-
socket.once('error', () => finish(false));
|
|
221
|
-
socket.connect(targetPort, '127.0.0.1');
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
async function waitForPortState(expectedListening, timeoutMs) {
|
|
226
|
-
const deadline = Date.now() + timeoutMs;
|
|
227
|
-
while (Date.now() < deadline) {
|
|
228
|
-
if ((await isPortListening(port)) === expectedListening) {
|
|
229
|
-
return true;
|
|
230
|
-
}
|
|
231
|
-
await delay(100);
|
|
232
|
-
}
|
|
233
|
-
return (await isPortListening(port)) === expectedListening;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
async function waitForProcessExit(pid, timeoutMs) {
|
|
237
|
-
const deadline = Date.now() + timeoutMs;
|
|
238
|
-
while (Date.now() < deadline) {
|
|
239
|
-
if (!isProcessAlive(pid)) {
|
|
240
|
-
return true;
|
|
241
|
-
}
|
|
242
|
-
await delay(100);
|
|
243
|
-
}
|
|
244
|
-
return !isProcessAlive(pid);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function readCloudflaredLog(logPath) {
|
|
248
|
-
try {
|
|
249
|
-
return readFileSync(logPath, 'utf8');
|
|
250
|
-
} catch {
|
|
251
|
-
return '';
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
function startTunnel() {
|
|
256
|
-
return new Promise((resolve, reject) => {
|
|
257
|
-
const logPath = path.join(logDir, 'tunnel.stderr.log');
|
|
258
|
-
mkdirSync(logDir, { recursive: true });
|
|
259
|
-
|
|
260
|
-
const launchSpec = resolveCloudflaredLaunchSpec();
|
|
261
|
-
|
|
262
|
-
writeFileSync(logPath, '', 'utf8');
|
|
263
|
-
const logFd = openSync(logPath, 'a');
|
|
264
|
-
const child = spawn(launchSpec.command, [
|
|
265
|
-
...launchSpec.args,
|
|
266
|
-
'tunnel',
|
|
267
|
-
'--protocol',
|
|
268
|
-
'http2',
|
|
269
|
-
'--url',
|
|
270
|
-
`http://localhost:${port}`,
|
|
271
|
-
], {
|
|
272
|
-
detached: true,
|
|
273
|
-
stdio: ['ignore', logFd, logFd],
|
|
274
|
-
});
|
|
275
|
-
child.unref();
|
|
276
|
-
|
|
277
|
-
const pid = child.pid;
|
|
278
|
-
let url = null;
|
|
279
|
-
|
|
280
|
-
const timeout = setTimeout(() => {
|
|
281
|
-
if (!url) {
|
|
282
|
-
try { process.kill(pid, 'SIGTERM'); } catch { /* */ }
|
|
283
|
-
reject(new Error(formatCloudflaredFailureMessage({
|
|
284
|
-
launchSpec,
|
|
285
|
-
logContent: readCloudflaredLog(logPath),
|
|
286
|
-
logPath,
|
|
287
|
-
phase: 'timeout',
|
|
288
|
-
})));
|
|
289
|
-
}
|
|
290
|
-
}, launchSpec.urlTimeoutMs);
|
|
291
|
-
|
|
292
|
-
const poll = setInterval(() => {
|
|
293
|
-
try {
|
|
294
|
-
const content = readFileSync(logPath, 'utf8');
|
|
295
|
-
const tunnelUrl = extractQuickTunnelUrl(content);
|
|
296
|
-
if (tunnelUrl) {
|
|
297
|
-
url = tunnelUrl;
|
|
298
|
-
clearInterval(poll);
|
|
299
|
-
clearTimeout(timeout);
|
|
300
|
-
saveTunnelState(pid, url);
|
|
301
|
-
resolve({ pid, url });
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
if (!isProcessAlive(pid)) {
|
|
305
|
-
clearInterval(poll);
|
|
306
|
-
clearTimeout(timeout);
|
|
307
|
-
reject(new Error(formatCloudflaredFailureMessage({
|
|
308
|
-
launchSpec,
|
|
309
|
-
logContent: content,
|
|
310
|
-
logPath,
|
|
311
|
-
phase: 'exit',
|
|
312
|
-
})));
|
|
313
|
-
}
|
|
314
|
-
} catch { /* file not ready yet */ }
|
|
315
|
-
}, 300);
|
|
316
|
-
|
|
317
|
-
child.on('error', (err) => {
|
|
318
|
-
clearInterval(poll);
|
|
319
|
-
clearTimeout(timeout);
|
|
320
|
-
reject(new Error(formatCloudflaredFailureMessage({
|
|
321
|
-
launchSpec,
|
|
322
|
-
logContent: readCloudflaredLog(logPath),
|
|
323
|
-
logPath,
|
|
324
|
-
err,
|
|
325
|
-
phase: 'spawn',
|
|
326
|
-
})));
|
|
327
|
-
});
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
async function restartExistingDevDaemon() {
|
|
332
|
-
const trackedWrapperPid = getTrackedWrapperPid();
|
|
333
|
-
if (trackedWrapperPid) {
|
|
334
|
-
console.log(`[dev] Stopping previous dev wrapper (pid ${trackedWrapperPid})...`);
|
|
335
|
-
try {
|
|
336
|
-
process.kill(trackedWrapperPid, 'SIGTERM');
|
|
337
|
-
} catch {}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
await requestDaemonShutdown();
|
|
341
|
-
|
|
342
|
-
const [portClosed, wrapperExited] = await Promise.all([
|
|
343
|
-
waitForPortState(false, 5_000),
|
|
344
|
-
trackedWrapperPid ? waitForProcessExit(trackedWrapperPid, 5_000) : Promise.resolve(true),
|
|
345
|
-
]);
|
|
346
|
-
|
|
347
|
-
if (!wrapperExited) {
|
|
348
|
-
fail(`Timed out waiting for previous dev wrapper (pid ${trackedWrapperPid}) to exit.`);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
if (!portClosed) {
|
|
352
|
-
fail(`Timed out waiting for port ${port} to be released.`);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
if (trackedWrapperPid) {
|
|
356
|
-
clearDevState(trackedWrapperPid);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// ─── Parse flags ────────────────────────────────────────────────────────────
|
|
361
|
-
|
|
362
|
-
function readNpmConfigFlag(name) {
|
|
363
|
-
const value = process.env[`npm_config_${name.replace(/-/g, '_')}`];
|
|
364
|
-
return value === '' || value === 'true';
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
consumeFlag('remote') || consumeFlag('tunnel') || readNpmConfigFlag('remote') || readNpmConfigFlag('tunnel');
|
|
368
|
-
const localFlag = consumeFlag('local') || readNpmConfigFlag('local');
|
|
369
|
-
const forceFlag = consumeFlag('force') || readNpmConfigFlag('force');
|
|
370
|
-
const relayArg = parseNamedArg('relay') ?? readNpmConfigArg('relay');
|
|
371
|
-
const hostArg = parseNamedArg('host') ?? readNpmConfigArg('host');
|
|
372
|
-
const fallbackHostsArg = parseNamedArg('fallback-hosts') ?? readNpmConfigArg('fallback-hosts');
|
|
373
|
-
const envRelayUrl = process.env.VIBELET_RELAY_URL || '';
|
|
374
|
-
const envCanonicalHost = process.env.VIBELET_CANONICAL_HOST || null;
|
|
375
|
-
const envFallbackHosts = process.env.VIBELET_FALLBACK_HOSTS || null;
|
|
376
|
-
const canonicalHost = hostArg ?? envCanonicalHost;
|
|
377
|
-
const fallbackHosts = fallbackHostsArg ?? envFallbackHosts;
|
|
378
|
-
const shouldManageTunnel = !localFlag
|
|
379
|
-
&& relayArg === null
|
|
380
|
-
&& !envRelayUrl
|
|
381
|
-
&& !hostArg
|
|
382
|
-
&& !fallbackHostsArg
|
|
383
|
-
&& !envCanonicalHost
|
|
384
|
-
&& !envFallbackHosts;
|
|
385
|
-
|
|
386
|
-
if (command === 'restart') {
|
|
387
|
-
await restartExistingDevDaemon();
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// Managed remote access: auto-start or reuse a Cloudflare Tunnel by default.
|
|
391
|
-
if (shouldManageTunnel) {
|
|
392
|
-
const existing = forceFlag ? null : getAliveTunnel();
|
|
393
|
-
if (existing) {
|
|
394
|
-
console.log(`[dev] Reusing tunnel: ${existing.url} (pid ${existing.pid})`);
|
|
395
|
-
saveRelayConfig(existing.url);
|
|
396
|
-
} else {
|
|
397
|
-
if (forceFlag) stopTunnel();
|
|
398
|
-
console.log('[dev] Starting Cloudflare Tunnel...');
|
|
399
|
-
try {
|
|
400
|
-
const tunnel = await startTunnel();
|
|
401
|
-
console.log(`[dev] Tunnel ready: ${tunnel.url}`);
|
|
402
|
-
saveRelayConfig(tunnel.url);
|
|
403
|
-
} catch (err) {
|
|
404
|
-
console.error(`[dev] Tunnel failed: ${err.message}`);
|
|
405
|
-
process.exit(1);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
if (relayArg !== null) {
|
|
411
|
-
if (relayArg) {
|
|
412
|
-
saveRelayConfig(relayArg);
|
|
413
|
-
} else {
|
|
414
|
-
clearRelayConfig();
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
const shouldIgnoreSavedRelay = relayArg === null && (localFlag || Boolean(hostArg) || Boolean(fallbackHostsArg) || Boolean(envCanonicalHost) || Boolean(envFallbackHosts));
|
|
419
|
-
const relayUrl = relayArg !== null
|
|
420
|
-
? relayArg
|
|
421
|
-
: (localFlag || Boolean(hostArg) || Boolean(fallbackHostsArg) ? '' : (envRelayUrl || (shouldIgnoreSavedRelay ? '' : loadRelayConfig())));
|
|
422
|
-
|
|
423
|
-
function shouldDetachChild() {
|
|
424
|
-
if (!supportsDetachedGroupKill) {
|
|
425
|
-
return false;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
const override = process.env.VIBE_DEV_DETACHED?.toLowerCase();
|
|
429
|
-
if (override === '1' || override === 'true') {
|
|
430
|
-
return true;
|
|
431
|
-
}
|
|
432
|
-
if (override === '0' || override === 'false') {
|
|
433
|
-
return false;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// In interactive shells, keep tsx watch in the foreground process group so
|
|
437
|
-
// terminal Ctrl+C reaches both the watcher and its child daemon directly.
|
|
438
|
-
return !process.stdin.isTTY;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
const useDetachedGroupKill = shouldDetachChild();
|
|
442
|
-
|
|
443
|
-
if (!getTrackedWrapperPid()) {
|
|
444
|
-
writeDevState();
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// In non-interactive environments, run tsx watch in its own process group so
|
|
448
|
-
// wrapper shutdown can tear down the watcher and the daemon child in one kill.
|
|
449
|
-
const child = spawn(process.execPath, [tsxCliPath, 'watch', 'src/index.ts'], {
|
|
450
|
-
cwd: daemonDir,
|
|
451
|
-
env: {
|
|
452
|
-
...process.env,
|
|
453
|
-
VIBE_DEV: process.env.VIBE_DEV ?? '1',
|
|
454
|
-
VIBELET_CLI_VERSION: process.env.VIBELET_CLI_VERSION ?? rootPackageJson.version,
|
|
455
|
-
...(relayUrl ? { VIBELET_RELAY_URL: relayUrl } : {}),
|
|
456
|
-
...(canonicalHost ? { VIBELET_CANONICAL_HOST: canonicalHost } : {}),
|
|
457
|
-
...(fallbackHosts ? { VIBELET_FALLBACK_HOSTS: fallbackHosts } : {}),
|
|
458
|
-
},
|
|
459
|
-
stdio: 'inherit',
|
|
460
|
-
detached: useDetachedGroupKill,
|
|
461
|
-
});
|
|
462
|
-
|
|
463
|
-
child.once('error', (error) => {
|
|
464
|
-
console.error('[daemon:dev] failed to start tsx watch', error);
|
|
465
|
-
process.exit(1);
|
|
466
|
-
});
|
|
467
|
-
|
|
468
|
-
function getSignalExitCode(signal) {
|
|
469
|
-
const signalNumber = osConstants.signals?.[signal];
|
|
470
|
-
return typeof signalNumber === 'number' ? 128 + signalNumber : 1;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
function requestDaemonShutdown() {
|
|
474
|
-
return fetch(`http://127.0.0.1:${port}/shutdown`, {
|
|
475
|
-
method: 'POST',
|
|
476
|
-
}).catch(() => undefined);
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
function killChildTree(signal = 'SIGTERM') {
|
|
480
|
-
if (child.exitCode !== null || child.signalCode !== null) {
|
|
481
|
-
return;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
try {
|
|
485
|
-
if (useDetachedGroupKill && typeof child.pid === 'number') {
|
|
486
|
-
process.kill(-child.pid, signal);
|
|
487
|
-
} else {
|
|
488
|
-
child.kill(signal);
|
|
489
|
-
}
|
|
490
|
-
} catch (error) {
|
|
491
|
-
if (error && typeof error === 'object' && 'code' in error && error.code === 'ESRCH') {
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
throw error;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
function shutdown(signal) {
|
|
499
|
-
if (shuttingDown) {
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
shuttingDown = true;
|
|
503
|
-
|
|
504
|
-
if (!useDetachedGroupKill) {
|
|
505
|
-
void requestDaemonShutdown();
|
|
506
|
-
}
|
|
507
|
-
killChildTree(signal === 'SIGHUP' ? 'SIGTERM' : signal);
|
|
508
|
-
forceKillTimer = setTimeout(() => {
|
|
509
|
-
try {
|
|
510
|
-
killChildTree('SIGKILL');
|
|
511
|
-
} catch {}
|
|
512
|
-
}, 3000);
|
|
513
|
-
forceKillTimer.unref();
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
process.once('SIGINT', () => shutdown('SIGINT'));
|
|
517
|
-
process.once('SIGTERM', () => shutdown('SIGTERM'));
|
|
518
|
-
process.once('SIGHUP', () => shutdown('SIGHUP'));
|
|
519
|
-
process.once('exit', () => {
|
|
520
|
-
clearDevState(process.pid);
|
|
521
|
-
try {
|
|
522
|
-
killChildTree('SIGTERM');
|
|
523
|
-
} catch {}
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
child.once('exit', (code, signal) => {
|
|
527
|
-
if (forceKillTimer) {
|
|
528
|
-
clearTimeout(forceKillTimer);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
if (signal) {
|
|
532
|
-
process.exit(getSignalExitCode(signal));
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
process.exit(code ?? 0);
|
|
537
|
-
});
|