@vibelet/cli 0.1.38 → 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.
Files changed (323) hide show
  1. package/README.md +80 -0
  2. package/bin/cloudflared-quick-tunnel.mjs +11 -0
  3. package/bin/cloudflared-resolver.mjs +171 -0
  4. package/bin/vibelet-runtime-policy.mjs +36 -0
  5. package/bin/vibelet.cjs +12 -0
  6. package/bin/vibelet.mjs +1062 -0
  7. package/dist/index.cjs +126 -0
  8. package/package.json +24 -22
  9. package/app.json +0 -5
  10. package/dist/advertised-hosts.d.ts +0 -34
  11. package/dist/advertised-hosts.d.ts.map +0 -1
  12. package/dist/advertised-hosts.js +0 -176
  13. package/dist/advertised-hosts.js.map +0 -1
  14. package/dist/advertised-hosts.test.d.ts +0 -2
  15. package/dist/advertised-hosts.test.d.ts.map +0 -1
  16. package/dist/advertised-hosts.test.js +0 -96
  17. package/dist/advertised-hosts.test.js.map +0 -1
  18. package/dist/audit.d.ts +0 -30
  19. package/dist/audit.d.ts.map +0 -1
  20. package/dist/audit.js +0 -73
  21. package/dist/audit.js.map +0 -1
  22. package/dist/audit.test.d.ts +0 -2
  23. package/dist/audit.test.d.ts.map +0 -1
  24. package/dist/audit.test.js +0 -33
  25. package/dist/audit.test.js.map +0 -1
  26. package/dist/auth.d.ts +0 -6
  27. package/dist/auth.d.ts.map +0 -1
  28. package/dist/auth.js +0 -27
  29. package/dist/auth.js.map +0 -1
  30. package/dist/claude-hooks.d.ts +0 -58
  31. package/dist/claude-hooks.d.ts.map +0 -1
  32. package/dist/claude-hooks.js +0 -129
  33. package/dist/claude-hooks.js.map +0 -1
  34. package/dist/cli-version.d.ts +0 -3
  35. package/dist/cli-version.d.ts.map +0 -1
  36. package/dist/cli-version.js +0 -35
  37. package/dist/cli-version.js.map +0 -1
  38. package/dist/cli-version.test.d.ts +0 -2
  39. package/dist/cli-version.test.d.ts.map +0 -1
  40. package/dist/cli-version.test.js +0 -38
  41. package/dist/cli-version.test.js.map +0 -1
  42. package/dist/config.d.ts +0 -30
  43. package/dist/config.d.ts.map +0 -1
  44. package/dist/config.js +0 -327
  45. package/dist/config.js.map +0 -1
  46. package/dist/config.test.d.ts +0 -2
  47. package/dist/config.test.d.ts.map +0 -1
  48. package/dist/config.test.js +0 -184
  49. package/dist/config.test.js.map +0 -1
  50. package/dist/dev-auth.test.d.ts +0 -2
  51. package/dist/dev-auth.test.d.ts.map +0 -1
  52. package/dist/dev-auth.test.js +0 -154
  53. package/dist/dev-auth.test.js.map +0 -1
  54. package/dist/dev-script.test.d.ts +0 -2
  55. package/dist/dev-script.test.d.ts.map +0 -1
  56. package/dist/dev-script.test.js +0 -412
  57. package/dist/dev-script.test.js.map +0 -1
  58. package/dist/drivers/claude.d.ts +0 -34
  59. package/dist/drivers/claude.d.ts.map +0 -1
  60. package/dist/drivers/claude.js +0 -413
  61. package/dist/drivers/claude.js.map +0 -1
  62. package/dist/drivers/claude.test.d.ts +0 -2
  63. package/dist/drivers/claude.test.d.ts.map +0 -1
  64. package/dist/drivers/claude.test.js +0 -951
  65. package/dist/drivers/claude.test.js.map +0 -1
  66. package/dist/drivers/codex.d.ts +0 -38
  67. package/dist/drivers/codex.d.ts.map +0 -1
  68. package/dist/drivers/codex.js +0 -771
  69. package/dist/drivers/codex.js.map +0 -1
  70. package/dist/drivers/codex.test.d.ts +0 -2
  71. package/dist/drivers/codex.test.d.ts.map +0 -1
  72. package/dist/drivers/codex.test.js +0 -939
  73. package/dist/drivers/codex.test.js.map +0 -1
  74. package/dist/drivers/types.d.ts +0 -14
  75. package/dist/drivers/types.d.ts.map +0 -1
  76. package/dist/drivers/types.js +0 -2
  77. package/dist/drivers/types.js.map +0 -1
  78. package/dist/e2e.test.d.ts +0 -2
  79. package/dist/e2e.test.d.ts.map +0 -1
  80. package/dist/e2e.test.js +0 -111
  81. package/dist/e2e.test.js.map +0 -1
  82. package/dist/identity.d.ts +0 -10
  83. package/dist/identity.d.ts.map +0 -1
  84. package/dist/identity.js +0 -66
  85. package/dist/identity.js.map +0 -1
  86. package/dist/identity.test.d.ts +0 -2
  87. package/dist/identity.test.d.ts.map +0 -1
  88. package/dist/identity.test.js +0 -25
  89. package/dist/identity.test.js.map +0 -1
  90. package/dist/index-entry.test.d.ts +0 -2
  91. package/dist/index-entry.test.d.ts.map +0 -1
  92. package/dist/index-entry.test.js +0 -272
  93. package/dist/index-entry.test.js.map +0 -1
  94. package/dist/index.d.ts +0 -2
  95. package/dist/index.d.ts.map +0 -1
  96. package/dist/index.js +0 -707
  97. package/dist/index.js.map +0 -1
  98. package/dist/logger.d.ts +0 -31
  99. package/dist/logger.d.ts.map +0 -1
  100. package/dist/logger.js +0 -75
  101. package/dist/logger.js.map +0 -1
  102. package/dist/metrics.d.ts +0 -52
  103. package/dist/metrics.d.ts.map +0 -1
  104. package/dist/metrics.js +0 -89
  105. package/dist/metrics.js.map +0 -1
  106. package/dist/pairing-store.d.ts +0 -29
  107. package/dist/pairing-store.d.ts.map +0 -1
  108. package/dist/pairing-store.js +0 -131
  109. package/dist/pairing-store.js.map +0 -1
  110. package/dist/pairing-store.test.d.ts +0 -2
  111. package/dist/pairing-store.test.d.ts.map +0 -1
  112. package/dist/pairing-store.test.js +0 -47
  113. package/dist/pairing-store.test.js.map +0 -1
  114. package/dist/paths.d.ts +0 -16
  115. package/dist/paths.d.ts.map +0 -1
  116. package/dist/paths.js +0 -18
  117. package/dist/paths.js.map +0 -1
  118. package/dist/perf-compare.d.ts +0 -13
  119. package/dist/perf-compare.d.ts.map +0 -1
  120. package/dist/perf-compare.js +0 -125
  121. package/dist/perf-compare.js.map +0 -1
  122. package/dist/port-conflict.d.ts +0 -9
  123. package/dist/port-conflict.d.ts.map +0 -1
  124. package/dist/port-conflict.js +0 -33
  125. package/dist/port-conflict.js.map +0 -1
  126. package/dist/port-conflict.test.d.ts +0 -2
  127. package/dist/port-conflict.test.d.ts.map +0 -1
  128. package/dist/port-conflict.test.js +0 -38
  129. package/dist/port-conflict.test.js.map +0 -1
  130. package/dist/process-scanner.d.ts +0 -43
  131. package/dist/process-scanner.d.ts.map +0 -1
  132. package/dist/process-scanner.js +0 -453
  133. package/dist/process-scanner.js.map +0 -1
  134. package/dist/process-scanner.perf.test.d.ts +0 -2
  135. package/dist/process-scanner.perf.test.d.ts.map +0 -1
  136. package/dist/process-scanner.perf.test.js +0 -186
  137. package/dist/process-scanner.perf.test.js.map +0 -1
  138. package/dist/process-scanner.test.d.ts +0 -2
  139. package/dist/process-scanner.test.d.ts.map +0 -1
  140. package/dist/process-scanner.test.js +0 -399
  141. package/dist/process-scanner.test.js.map +0 -1
  142. package/dist/push-protocol.d.ts +0 -15
  143. package/dist/push-protocol.d.ts.map +0 -1
  144. package/dist/push-protocol.js +0 -23
  145. package/dist/push-protocol.js.map +0 -1
  146. package/dist/push-protocol.test.d.ts +0 -2
  147. package/dist/push-protocol.test.d.ts.map +0 -1
  148. package/dist/push-protocol.test.js +0 -57
  149. package/dist/push-protocol.test.js.map +0 -1
  150. package/dist/push-store.d.ts +0 -22
  151. package/dist/push-store.d.ts.map +0 -1
  152. package/dist/push-store.js +0 -103
  153. package/dist/push-store.js.map +0 -1
  154. package/dist/push-store.test.d.ts +0 -2
  155. package/dist/push-store.test.d.ts.map +0 -1
  156. package/dist/push-store.test.js +0 -79
  157. package/dist/push-store.test.js.map +0 -1
  158. package/dist/push.d.ts +0 -65
  159. package/dist/push.d.ts.map +0 -1
  160. package/dist/push.js +0 -202
  161. package/dist/push.js.map +0 -1
  162. package/dist/push.test.d.ts +0 -2
  163. package/dist/push.test.d.ts.map +0 -1
  164. package/dist/push.test.js +0 -199
  165. package/dist/push.test.js.map +0 -1
  166. package/dist/safe-stdio.d.ts +0 -3
  167. package/dist/safe-stdio.d.ts.map +0 -1
  168. package/dist/safe-stdio.js +0 -46
  169. package/dist/safe-stdio.js.map +0 -1
  170. package/dist/scanner.d.ts +0 -30
  171. package/dist/scanner.d.ts.map +0 -1
  172. package/dist/scanner.js +0 -859
  173. package/dist/scanner.js.map +0 -1
  174. package/dist/scanner.perf.test.d.ts +0 -2
  175. package/dist/scanner.perf.test.d.ts.map +0 -1
  176. package/dist/scanner.perf.test.js +0 -320
  177. package/dist/scanner.perf.test.js.map +0 -1
  178. package/dist/scanner.test.d.ts +0 -2
  179. package/dist/scanner.test.d.ts.map +0 -1
  180. package/dist/scanner.test.js +0 -948
  181. package/dist/scanner.test.js.map +0 -1
  182. package/dist/session-inventory.d.ts +0 -63
  183. package/dist/session-inventory.d.ts.map +0 -1
  184. package/dist/session-inventory.js +0 -525
  185. package/dist/session-inventory.js.map +0 -1
  186. package/dist/session-inventory.perf.test.d.ts +0 -2
  187. package/dist/session-inventory.perf.test.d.ts.map +0 -1
  188. package/dist/session-inventory.perf.test.js +0 -220
  189. package/dist/session-inventory.perf.test.js.map +0 -1
  190. package/dist/session-inventory.test.d.ts +0 -2
  191. package/dist/session-inventory.test.d.ts.map +0 -1
  192. package/dist/session-inventory.test.js +0 -712
  193. package/dist/session-inventory.test.js.map +0 -1
  194. package/dist/session-manager.d.ts +0 -75
  195. package/dist/session-manager.d.ts.map +0 -1
  196. package/dist/session-manager.js +0 -1515
  197. package/dist/session-manager.js.map +0 -1
  198. package/dist/session-manager.test.d.ts +0 -2
  199. package/dist/session-manager.test.d.ts.map +0 -1
  200. package/dist/session-manager.test.js +0 -2861
  201. package/dist/session-manager.test.js.map +0 -1
  202. package/dist/session-store.d.ts +0 -42
  203. package/dist/session-store.d.ts.map +0 -1
  204. package/dist/session-store.js +0 -163
  205. package/dist/session-store.js.map +0 -1
  206. package/dist/session-store.test.d.ts +0 -2
  207. package/dist/session-store.test.d.ts.map +0 -1
  208. package/dist/session-store.test.js +0 -236
  209. package/dist/session-store.test.js.map +0 -1
  210. package/dist/session-title.d.ts +0 -6
  211. package/dist/session-title.d.ts.map +0 -1
  212. package/dist/session-title.js +0 -105
  213. package/dist/session-title.js.map +0 -1
  214. package/dist/session-title.perf.test.d.ts +0 -2
  215. package/dist/session-title.perf.test.d.ts.map +0 -1
  216. package/dist/session-title.perf.test.js +0 -99
  217. package/dist/session-title.perf.test.js.map +0 -1
  218. package/dist/session-title.test.d.ts +0 -2
  219. package/dist/session-title.test.d.ts.map +0 -1
  220. package/dist/session-title.test.js +0 -199
  221. package/dist/session-title.test.js.map +0 -1
  222. package/dist/shutdown-endpoint.test.d.ts +0 -2
  223. package/dist/shutdown-endpoint.test.d.ts.map +0 -1
  224. package/dist/shutdown-endpoint.test.js +0 -93
  225. package/dist/shutdown-endpoint.test.js.map +0 -1
  226. package/dist/storage-housekeeping.d.ts +0 -28
  227. package/dist/storage-housekeeping.d.ts.map +0 -1
  228. package/dist/storage-housekeeping.js +0 -76
  229. package/dist/storage-housekeeping.js.map +0 -1
  230. package/dist/storage-housekeeping.test.d.ts +0 -2
  231. package/dist/storage-housekeeping.test.d.ts.map +0 -1
  232. package/dist/storage-housekeeping.test.js +0 -65
  233. package/dist/storage-housekeeping.test.js.map +0 -1
  234. package/dist/test-daemon-harness.d.ts +0 -31
  235. package/dist/test-daemon-harness.d.ts.map +0 -1
  236. package/dist/test-daemon-harness.js +0 -337
  237. package/dist/test-daemon-harness.js.map +0 -1
  238. package/dist/token-auth.test.d.ts +0 -2
  239. package/dist/token-auth.test.d.ts.map +0 -1
  240. package/dist/token-auth.test.js +0 -52
  241. package/dist/token-auth.test.js.map +0 -1
  242. package/dist/utils.d.ts +0 -4
  243. package/dist/utils.d.ts.map +0 -1
  244. package/dist/utils.js +0 -40
  245. package/dist/utils.js.map +0 -1
  246. package/dist/utils.test.d.ts +0 -2
  247. package/dist/utils.test.d.ts.map +0 -1
  248. package/dist/utils.test.js +0 -54
  249. package/dist/utils.test.js.map +0 -1
  250. package/dist/ws-data.d.ts +0 -4
  251. package/dist/ws-data.d.ts.map +0 -1
  252. package/dist/ws-data.js +0 -20
  253. package/dist/ws-data.js.map +0 -1
  254. package/dist/ws-data.test.d.ts +0 -2
  255. package/dist/ws-data.test.d.ts.map +0 -1
  256. package/dist/ws-data.test.js +0 -17
  257. package/dist/ws-data.test.js.map +0 -1
  258. package/perf-reporter.mjs +0 -138
  259. package/scripts/build-release.mjs +0 -41
  260. package/scripts/dev.mjs +0 -537
  261. package/src/advertised-hosts.test.ts +0 -125
  262. package/src/advertised-hosts.ts +0 -225
  263. package/src/audit.test.ts +0 -38
  264. package/src/audit.ts +0 -117
  265. package/src/auth.ts +0 -31
  266. package/src/claude-hooks.ts +0 -195
  267. package/src/cli-version.test.ts +0 -36
  268. package/src/cli-version.ts +0 -46
  269. package/src/config.test.ts +0 -254
  270. package/src/config.ts +0 -324
  271. package/src/dev-auth.test.ts +0 -183
  272. package/src/dev-script.test.ts +0 -511
  273. package/src/drivers/claude.test.ts +0 -1186
  274. package/src/drivers/claude.ts +0 -443
  275. package/src/drivers/codex.test.ts +0 -1096
  276. package/src/drivers/codex.ts +0 -879
  277. package/src/drivers/types.ts +0 -15
  278. package/src/e2e.test.ts +0 -139
  279. package/src/identity.test.ts +0 -26
  280. package/src/identity.ts +0 -82
  281. package/src/index-entry.test.ts +0 -336
  282. package/src/index.ts +0 -781
  283. package/src/logger.ts +0 -112
  284. package/src/metrics.ts +0 -117
  285. package/src/pairing-store.test.ts +0 -53
  286. package/src/pairing-store.ts +0 -154
  287. package/src/paths.ts +0 -19
  288. package/src/perf-compare.ts +0 -164
  289. package/src/port-conflict.test.ts +0 -45
  290. package/src/port-conflict.ts +0 -44
  291. package/src/process-scanner.perf.test.ts +0 -222
  292. package/src/process-scanner.test.ts +0 -575
  293. package/src/process-scanner.ts +0 -514
  294. package/src/push-protocol.test.ts +0 -74
  295. package/src/push-protocol.ts +0 -36
  296. package/src/push-store.test.ts +0 -89
  297. package/src/push-store.ts +0 -126
  298. package/src/push.test.ts +0 -234
  299. package/src/push.ts +0 -318
  300. package/src/safe-stdio.ts +0 -51
  301. package/src/scanner.perf.test.ts +0 -359
  302. package/src/scanner.test.ts +0 -1045
  303. package/src/scanner.ts +0 -924
  304. package/src/session-inventory.perf.test.ts +0 -250
  305. package/src/session-inventory.test.ts +0 -1002
  306. package/src/session-inventory.ts +0 -721
  307. package/src/session-manager.test.ts +0 -3430
  308. package/src/session-manager.ts +0 -1775
  309. package/src/session-store.test.ts +0 -276
  310. package/src/session-store.ts +0 -202
  311. package/src/session-title.perf.test.ts +0 -118
  312. package/src/session-title.test.ts +0 -286
  313. package/src/session-title.ts +0 -108
  314. package/src/shutdown-endpoint.test.ts +0 -95
  315. package/src/storage-housekeeping.test.ts +0 -78
  316. package/src/storage-housekeeping.ts +0 -111
  317. package/src/test-daemon-harness.ts +0 -410
  318. package/src/token-auth.test.ts +0 -67
  319. package/src/utils.test.ts +0 -65
  320. package/src/utils.ts +0 -47
  321. package/src/ws-data.test.ts +0 -20
  322. package/src/ws-data.ts +0 -26
  323. 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
- });