everything-dev 0.3.3 → 1.3.2

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 (308) hide show
  1. package/README.md +64 -0
  2. package/cli.js +10 -0
  3. package/dist/_virtual/_rolldown/runtime.cjs +29 -0
  4. package/dist/api-contract.cjs +172 -0
  5. package/dist/api-contract.cjs.map +1 -0
  6. package/dist/api-contract.mjs +171 -0
  7. package/dist/api-contract.mjs.map +1 -0
  8. package/dist/api.cjs +124 -0
  9. package/dist/api.cjs.map +1 -0
  10. package/dist/api.d.cts +36 -0
  11. package/dist/api.d.cts.map +1 -0
  12. package/dist/api.d.mts +36 -0
  13. package/dist/api.d.mts.map +1 -0
  14. package/dist/api.mjs +119 -0
  15. package/dist/api.mjs.map +1 -0
  16. package/dist/app.cjs +156 -0
  17. package/dist/app.cjs.map +1 -0
  18. package/dist/app.mjs +153 -0
  19. package/dist/app.mjs.map +1 -0
  20. package/dist/cli/catalog.cjs +30 -0
  21. package/dist/cli/catalog.cjs.map +1 -0
  22. package/dist/cli/catalog.mjs +29 -0
  23. package/dist/cli/catalog.mjs.map +1 -0
  24. package/dist/cli/help.cjs +16 -0
  25. package/dist/cli/help.cjs.map +1 -0
  26. package/dist/cli/help.mjs +16 -0
  27. package/dist/cli/help.mjs.map +1 -0
  28. package/dist/cli/init.cjs +317 -0
  29. package/dist/cli/init.cjs.map +1 -0
  30. package/dist/cli/init.d.cts +36 -0
  31. package/dist/cli/init.d.cts.map +1 -0
  32. package/dist/cli/init.d.mts +36 -0
  33. package/dist/cli/init.d.mts.map +1 -0
  34. package/dist/cli/init.mjs +309 -0
  35. package/dist/cli/init.mjs.map +1 -0
  36. package/dist/cli/parse.cjs +96 -0
  37. package/dist/cli/parse.cjs.map +1 -0
  38. package/dist/cli/parse.mjs +95 -0
  39. package/dist/cli/parse.mjs.map +1 -0
  40. package/dist/cli/prompts.cjs +42 -0
  41. package/dist/cli/prompts.cjs.map +1 -0
  42. package/dist/cli/prompts.mjs +41 -0
  43. package/dist/cli/prompts.mjs.map +1 -0
  44. package/dist/cli.cjs +167 -0
  45. package/dist/cli.cjs.map +1 -0
  46. package/dist/cli.d.cts +1 -0
  47. package/dist/cli.d.mts +1 -0
  48. package/dist/cli.mjs +166 -0
  49. package/dist/cli.mjs.map +1 -0
  50. package/dist/components/dev-view.cjs +307 -0
  51. package/dist/components/dev-view.cjs.map +1 -0
  52. package/dist/components/dev-view.mjs +306 -0
  53. package/dist/components/dev-view.mjs.map +1 -0
  54. package/dist/components/streaming-view.cjs +146 -0
  55. package/dist/components/streaming-view.cjs.map +1 -0
  56. package/dist/components/streaming-view.mjs +144 -0
  57. package/dist/components/streaming-view.mjs.map +1 -0
  58. package/dist/config.cjs +280 -0
  59. package/dist/config.cjs.map +1 -0
  60. package/dist/config.d.cts +35 -0
  61. package/dist/config.d.cts.map +1 -0
  62. package/dist/config.d.mts +35 -0
  63. package/dist/config.d.mts.map +1 -0
  64. package/dist/config.mjs +266 -0
  65. package/dist/config.mjs.map +1 -0
  66. package/dist/contract.cjs +209 -0
  67. package/dist/contract.cjs.map +1 -0
  68. package/dist/contract.d.cts +490 -0
  69. package/dist/contract.d.cts.map +1 -0
  70. package/dist/contract.d.mts +490 -0
  71. package/dist/contract.d.mts.map +1 -0
  72. package/dist/contract.meta.cjs +104 -0
  73. package/dist/contract.meta.cjs.map +1 -0
  74. package/dist/contract.meta.d.cts +141 -0
  75. package/dist/contract.meta.d.cts.map +1 -0
  76. package/dist/contract.meta.d.mts +141 -0
  77. package/dist/contract.meta.d.mts.map +1 -0
  78. package/dist/contract.meta.mjs +102 -0
  79. package/dist/contract.meta.mjs.map +1 -0
  80. package/dist/contract.mjs +186 -0
  81. package/dist/contract.mjs.map +1 -0
  82. package/dist/dev-logs.cjs +53 -0
  83. package/dist/dev-logs.cjs.map +1 -0
  84. package/dist/dev-logs.mjs +51 -0
  85. package/dist/dev-logs.mjs.map +1 -0
  86. package/dist/dev-session.cjs +195 -0
  87. package/dist/dev-session.cjs.map +1 -0
  88. package/dist/dev-session.mjs +194 -0
  89. package/dist/dev-session.mjs.map +1 -0
  90. package/dist/fastkv.cjs +89 -0
  91. package/dist/fastkv.cjs.map +1 -0
  92. package/dist/fastkv.d.cts +11 -0
  93. package/dist/fastkv.d.cts.map +1 -0
  94. package/dist/fastkv.d.mts +11 -0
  95. package/dist/fastkv.d.mts.map +1 -0
  96. package/dist/fastkv.mjs +82 -0
  97. package/dist/fastkv.mjs.map +1 -0
  98. package/dist/federation.server.cjs +27 -0
  99. package/dist/federation.server.cjs.map +1 -0
  100. package/dist/federation.server.mjs +27 -0
  101. package/dist/federation.server.mjs.map +1 -0
  102. package/dist/host.cjs +367 -0
  103. package/dist/host.cjs.map +1 -0
  104. package/dist/host.d.cts +22 -0
  105. package/dist/host.d.cts.map +1 -0
  106. package/dist/host.d.mts +22 -0
  107. package/dist/host.d.mts.map +1 -0
  108. package/dist/host.mjs +364 -0
  109. package/dist/host.mjs.map +1 -0
  110. package/dist/index.cjs +122 -0
  111. package/dist/index.d.cts +7 -0
  112. package/dist/index.d.mts +7 -0
  113. package/dist/index.mjs +9 -0
  114. package/dist/integrity.cjs +39 -0
  115. package/dist/integrity.cjs.map +1 -0
  116. package/dist/integrity.d.cts +7 -0
  117. package/dist/integrity.d.cts.map +1 -0
  118. package/dist/integrity.d.mts +7 -0
  119. package/dist/integrity.d.mts.map +1 -0
  120. package/dist/integrity.mjs +35 -0
  121. package/dist/integrity.mjs.map +1 -0
  122. package/dist/mf.cjs +77 -0
  123. package/dist/mf.cjs.map +1 -0
  124. package/dist/mf.d.cts +19 -0
  125. package/dist/mf.d.cts.map +1 -0
  126. package/dist/mf.d.mts +19 -0
  127. package/dist/mf.d.mts.map +1 -0
  128. package/dist/mf.mjs +71 -0
  129. package/dist/mf.mjs.map +1 -0
  130. package/dist/near-cli.cjs +196 -0
  131. package/dist/near-cli.cjs.map +1 -0
  132. package/dist/near-cli.mjs +193 -0
  133. package/dist/near-cli.mjs.map +1 -0
  134. package/dist/network.cjs +9 -0
  135. package/dist/network.cjs.map +1 -0
  136. package/dist/network.mjs +8 -0
  137. package/dist/network.mjs.map +1 -0
  138. package/dist/orchestrator.cjs +441 -0
  139. package/dist/orchestrator.cjs.map +1 -0
  140. package/dist/orchestrator.d.cts +40 -0
  141. package/dist/orchestrator.d.cts.map +1 -0
  142. package/dist/orchestrator.d.mts +40 -0
  143. package/dist/orchestrator.d.mts.map +1 -0
  144. package/dist/orchestrator.mjs +436 -0
  145. package/dist/orchestrator.mjs.map +1 -0
  146. package/dist/plugin.cjs +825 -0
  147. package/dist/plugin.cjs.map +1 -0
  148. package/dist/plugin.d.cts +347 -0
  149. package/dist/plugin.d.cts.map +1 -0
  150. package/dist/plugin.d.mts +348 -0
  151. package/dist/plugin.d.mts.map +1 -0
  152. package/dist/plugin.mjs +822 -0
  153. package/dist/plugin.mjs.map +1 -0
  154. package/dist/process-registry.cjs +120 -0
  155. package/dist/process-registry.cjs.map +1 -0
  156. package/dist/process-registry.d.cts +25 -0
  157. package/dist/process-registry.d.cts.map +1 -0
  158. package/dist/process-registry.d.mts +25 -0
  159. package/dist/process-registry.d.mts.map +1 -0
  160. package/dist/process-registry.mjs +119 -0
  161. package/dist/process-registry.mjs.map +1 -0
  162. package/dist/sdk.cjs +61 -0
  163. package/dist/sdk.d.cts +5 -0
  164. package/dist/sdk.d.mts +5 -0
  165. package/dist/sdk.mjs +6 -0
  166. package/dist/shared.cjs +143 -0
  167. package/dist/shared.cjs.map +1 -0
  168. package/dist/shared.d.cts +33 -0
  169. package/dist/shared.d.cts.map +1 -0
  170. package/dist/shared.d.mts +33 -0
  171. package/dist/shared.d.mts.map +1 -0
  172. package/dist/shared.mjs +140 -0
  173. package/dist/shared.mjs.map +1 -0
  174. package/dist/types.cjs +160 -0
  175. package/dist/types.cjs.map +1 -0
  176. package/dist/types.d.cts +269 -0
  177. package/dist/types.d.cts.map +1 -0
  178. package/dist/types.d.mts +269 -0
  179. package/dist/types.d.mts.map +1 -0
  180. package/dist/types.mjs +144 -0
  181. package/dist/types.mjs.map +1 -0
  182. package/dist/ui/head.cjs +67 -0
  183. package/dist/ui/head.cjs.map +1 -0
  184. package/dist/ui/head.d.cts +19 -0
  185. package/dist/ui/head.d.cts.map +1 -0
  186. package/dist/ui/head.d.mts +19 -0
  187. package/dist/ui/head.d.mts.map +1 -0
  188. package/dist/ui/head.mjs +61 -0
  189. package/dist/ui/head.mjs.map +1 -0
  190. package/dist/ui/index.cjs +32 -0
  191. package/dist/ui/index.d.cts +7 -0
  192. package/dist/ui/index.d.mts +7 -0
  193. package/dist/ui/index.mjs +6 -0
  194. package/dist/ui/metadata.cjs +106 -0
  195. package/dist/ui/metadata.cjs.map +1 -0
  196. package/dist/ui/metadata.d.cts +35 -0
  197. package/dist/ui/metadata.d.cts.map +1 -0
  198. package/dist/ui/metadata.d.mts +35 -0
  199. package/dist/ui/metadata.d.mts.map +1 -0
  200. package/dist/ui/metadata.mjs +100 -0
  201. package/dist/ui/metadata.mjs.map +1 -0
  202. package/dist/ui/router.cjs +56 -0
  203. package/dist/ui/router.cjs.map +1 -0
  204. package/dist/ui/router.d.cts +11 -0
  205. package/dist/ui/router.d.cts.map +1 -0
  206. package/dist/ui/router.d.mts +11 -0
  207. package/dist/ui/router.d.mts.map +1 -0
  208. package/dist/ui/router.mjs +51 -0
  209. package/dist/ui/router.mjs.map +1 -0
  210. package/dist/ui/runtime.cjs +65 -0
  211. package/dist/ui/runtime.cjs.map +1 -0
  212. package/dist/ui/runtime.d.cts +29 -0
  213. package/dist/ui/runtime.d.cts.map +1 -0
  214. package/dist/ui/runtime.d.mts +29 -0
  215. package/dist/ui/runtime.d.mts.map +1 -0
  216. package/dist/ui/runtime.mjs +53 -0
  217. package/dist/ui/runtime.mjs.map +1 -0
  218. package/dist/ui/types.cjs +0 -0
  219. package/dist/ui/types.d.cts +52 -0
  220. package/dist/ui/types.d.cts.map +1 -0
  221. package/dist/ui/types.d.mts +52 -0
  222. package/dist/ui/types.d.mts.map +1 -0
  223. package/dist/ui/types.mjs +1 -0
  224. package/dist/utils/banner.cjs +24 -0
  225. package/dist/utils/banner.cjs.map +1 -0
  226. package/dist/utils/banner.mjs +23 -0
  227. package/dist/utils/banner.mjs.map +1 -0
  228. package/dist/utils/linkify.cjs +15 -0
  229. package/dist/utils/linkify.cjs.map +1 -0
  230. package/dist/utils/linkify.mjs +14 -0
  231. package/dist/utils/linkify.mjs.map +1 -0
  232. package/dist/utils/run.cjs +40 -0
  233. package/dist/utils/run.cjs.map +1 -0
  234. package/dist/utils/run.mjs +39 -0
  235. package/dist/utils/run.mjs.map +1 -0
  236. package/dist/utils/theme.cjs +44 -0
  237. package/dist/utils/theme.cjs.map +1 -0
  238. package/dist/utils/theme.mjs +37 -0
  239. package/dist/utils/theme.mjs.map +1 -0
  240. package/package.json +269 -80
  241. package/src/api-contract.ts +309 -0
  242. package/src/api.ts +181 -0
  243. package/src/app.ts +346 -0
  244. package/src/cli/catalog.ts +49 -0
  245. package/src/cli/help.ts +13 -0
  246. package/src/cli/init.ts +415 -0
  247. package/src/cli/parse.ts +130 -0
  248. package/src/cli/prompts.ts +64 -0
  249. package/src/cli.ts +203 -1507
  250. package/src/components/dev-view.tsx +307 -255
  251. package/src/components/streaming-view.ts +164 -128
  252. package/src/config.ts +462 -532
  253. package/src/contract.meta.ts +96 -0
  254. package/src/contract.ts +164 -561
  255. package/src/dev-logs.ts +85 -0
  256. package/src/dev-session.ts +318 -0
  257. package/src/fastkv.ts +153 -0
  258. package/src/federation.server.ts +43 -0
  259. package/src/host.ts +526 -0
  260. package/src/index.ts +6 -3
  261. package/src/integrity.ts +54 -0
  262. package/src/mf.ts +105 -0
  263. package/src/near-cli.ts +284 -0
  264. package/src/network.ts +3 -0
  265. package/src/orchestrator.ts +648 -0
  266. package/src/plugin.ts +1115 -2309
  267. package/src/process-registry.ts +154 -0
  268. package/src/scripts/sync-api-contract.ts +24 -0
  269. package/src/sdk.ts +14 -0
  270. package/src/shared.ts +206 -0
  271. package/src/types.ts +152 -206
  272. package/src/ui/head.ts +34 -27
  273. package/src/ui/index.ts +3 -3
  274. package/src/ui/metadata.ts +95 -0
  275. package/src/ui/router.ts +22 -6
  276. package/src/ui/runtime.ts +55 -6
  277. package/src/ui/types.ts +24 -11
  278. package/src/utils/banner.ts +10 -6
  279. package/src/utils/run.ts +26 -27
  280. package/src/utils/theme.ts +3 -66
  281. package/src/components/monitor-view.tsx +0 -475
  282. package/src/components/status-view.tsx +0 -173
  283. package/src/lib/env.ts +0 -109
  284. package/src/lib/near-cli.ts +0 -289
  285. package/src/lib/nova.ts +0 -266
  286. package/src/lib/orchestrator.ts +0 -276
  287. package/src/lib/process-registry.ts +0 -166
  288. package/src/lib/process.ts +0 -550
  289. package/src/lib/resource-monitor/assertions.ts +0 -234
  290. package/src/lib/resource-monitor/command.ts +0 -283
  291. package/src/lib/resource-monitor/diff.ts +0 -157
  292. package/src/lib/resource-monitor/errors.ts +0 -127
  293. package/src/lib/resource-monitor/index.ts +0 -305
  294. package/src/lib/resource-monitor/platform/darwin.ts +0 -306
  295. package/src/lib/resource-monitor/platform/index.ts +0 -35
  296. package/src/lib/resource-monitor/platform/linux.ts +0 -332
  297. package/src/lib/resource-monitor/platform/windows.ts +0 -298
  298. package/src/lib/resource-monitor/snapshot.ts +0 -217
  299. package/src/lib/resource-monitor/types.ts +0 -74
  300. package/src/lib/session-recorder/errors.ts +0 -102
  301. package/src/lib/session-recorder/flows/login.ts +0 -210
  302. package/src/lib/session-recorder/index.ts +0 -361
  303. package/src/lib/session-recorder/playwright.ts +0 -257
  304. package/src/lib/session-recorder/report.ts +0 -353
  305. package/src/lib/session-recorder/server.ts +0 -268
  306. package/src/lib/session-recorder/types.ts +0 -115
  307. package/src/lib/sync.ts +0 -1
  308. package/src/ui/files.ts +0 -134
@@ -1,295 +1,347 @@
1
1
  import { Box, render, Text, useApp, useInput } from "ink";
2
2
  import { useEffect, useState } from "react";
3
+ import type { SourceMode } from "../types";
3
4
  import { linkify } from "../utils/linkify";
4
5
  import { colors, divider, frames, gradients, icons } from "../utils/theme";
5
6
 
7
+ const PLUGIN_PREFIX = "plugin:";
8
+
6
9
  export type ProcessStatus = "pending" | "starting" | "ready" | "error";
7
10
 
8
11
  export interface ProcessState {
9
- name: string;
10
- status: ProcessStatus;
11
- port: number;
12
- message?: string;
13
- source?: "local" | "remote";
14
- proxyTarget?: string;
12
+ name: string;
13
+ status: ProcessStatus;
14
+ port: number;
15
+ message?: string;
16
+ source?: SourceMode;
15
17
  }
16
18
 
17
19
  export interface LogEntry {
18
- source: string;
19
- line: string;
20
- timestamp: number;
21
- isError?: boolean;
20
+ id: string;
21
+ source: string;
22
+ line: string;
23
+ timestamp: number;
24
+ isError?: boolean;
22
25
  }
23
26
 
24
27
  interface DevViewProps {
25
- processes: ProcessState[];
26
- logs: LogEntry[];
27
- description: string;
28
- proxyTarget?: string;
29
- onExit?: () => Promise<void> | void;
30
- onExportLogs?: () => Promise<void> | void;
28
+ processes: ProcessState[];
29
+ logs: LogEntry[];
30
+ description: string;
31
+ proxyTarget?: string;
32
+ onExit?: () => Promise<void> | void;
33
+ onExportLogs?: () => Promise<void> | void;
31
34
  }
32
35
 
33
36
  function StatusIcon({ status }: { status: ProcessStatus }) {
34
- switch (status) {
35
- case "pending":
36
- return <Text color="gray">{icons.pending}</Text>;
37
- case "starting":
38
- return <Text color="#00ffff">{icons.scan}</Text>;
39
- case "ready":
40
- return <Text color="#00ff41">{icons.ok}</Text>;
41
- case "error":
42
- return <Text color="#ff3366">{icons.err}</Text>;
43
- }
37
+ switch (status) {
38
+ case "pending":
39
+ return <Text color="gray">{icons.pending}</Text>;
40
+ case "starting":
41
+ return <Text color="#00ffff">{icons.scan}</Text>;
42
+ case "ready":
43
+ return <Text color="#00ff41">{icons.ok}</Text>;
44
+ case "error":
45
+ return <Text color="#ff3366">{icons.err}</Text>;
46
+ }
44
47
  }
45
48
 
46
49
  function getServiceColor(name: string): string {
47
- return name === "host" ? "#00ffff" : name === "ui" ? "#ff00ff" : "#0080ff";
50
+ if (name.startsWith(PLUGIN_PREFIX)) return "#ffaa00";
51
+ return name === "host" ? "#00ffff" : name === "ui" ? "#ff00ff" : "#0080ff";
52
+ }
53
+
54
+ function getDisplayName(name: string): string {
55
+ return name.startsWith(PLUGIN_PREFIX)
56
+ ? name.slice(PLUGIN_PREFIX.length).toUpperCase()
57
+ : name.toUpperCase();
58
+ }
59
+
60
+ function isPlugin(name: string): boolean {
61
+ return name.startsWith(PLUGIN_PREFIX);
62
+ }
63
+
64
+ function getSectionedProcesses(processes: ProcessState[]): Array<{
65
+ key: string;
66
+ title: string;
67
+ processes: ProcessState[];
68
+ }> {
69
+ const plugins = processes.filter((p) => isPlugin(p.name));
70
+ const services = processes.filter((p) => !isPlugin(p.name));
71
+ const sections: Array<{ key: string; title: string; processes: ProcessState[] }> = [];
72
+ if (plugins.length > 0) sections.push({ key: "plugins", title: "PLUGINS", processes: plugins });
73
+ if (services.length > 0)
74
+ sections.push({ key: "services", title: "SERVICES", processes: services });
75
+ return sections;
76
+ }
77
+
78
+ function getColumnWidths(processes: ProcessState[]): { name: number; source: number } {
79
+ const name = Math.max(6, ...processes.map((p) => getDisplayName(p.name).length));
80
+ const source = Math.max(10, ...processes.map((p) => (p.source ? `(${p.source})`.length : 0)));
81
+ return { name, source };
82
+ }
83
+
84
+ function ProcessRow({
85
+ proc,
86
+ nameWidth,
87
+ sourceWidth,
88
+ }: {
89
+ proc: ProcessState;
90
+ nameWidth: number;
91
+ sourceWidth: number;
92
+ }) {
93
+ const color = getServiceColor(proc.name);
94
+ const portStr = proc.port > 0 ? `:${proc.port}` : "";
95
+ const sourceLabel = proc.source ? ` (${proc.source})` : "";
96
+
97
+ const statusText =
98
+ proc.status === "pending"
99
+ ? "waiting"
100
+ : proc.status === "starting"
101
+ ? "starting"
102
+ : proc.status === "ready"
103
+ ? "running"
104
+ : "failed";
105
+
106
+ return (
107
+ <Box>
108
+ <Text>{" "}</Text>
109
+ <StatusIcon status={proc.status} />
110
+ <Text> </Text>
111
+ <Text color={color} bold>
112
+ {getDisplayName(proc.name).padEnd(nameWidth)}
113
+ </Text>
114
+ <Text color="gray">{sourceLabel.padEnd(sourceWidth)}</Text>
115
+ <Text color={proc.status === "ready" ? "#00ff41" : "gray"}>{statusText}</Text>
116
+ {proc.port > 0 && <Text color="#00ffff"> {portStr}</Text>}
117
+ </Box>
118
+ );
48
119
  }
49
120
 
50
- function ProcessRow({ proc }: { proc: ProcessState }) {
51
- const color = getServiceColor(proc.name);
52
- const portStr = proc.port > 0 ? `:${proc.port}` : "";
53
- const sourceLabel = proc.source ? ` (${proc.source})` : "";
54
-
55
- const statusText =
56
- proc.status === "pending"
57
- ? "waiting"
58
- : proc.status === "starting"
59
- ? "starting"
60
- : proc.status === "ready"
61
- ? "running"
62
- : "failed";
63
-
64
- return (
65
- <Box>
66
- <Text>{" "}</Text>
67
- <StatusIcon status={proc.status} />
68
- <Text> </Text>
69
- <Text color={color} bold>
70
- {proc.name.toUpperCase().padEnd(6)}
71
- </Text>
72
- <Text color="gray">{sourceLabel.padEnd(10)}</Text>
73
- <Text color={proc.status === "ready" ? "#00ff41" : "gray"}>
74
- {statusText}
75
- </Text>
76
- {proc.port > 0 && <Text color="#00ffff"> {portStr}</Text>}
77
- </Box>
78
- );
121
+ function SectionHeader({ title }: { title: string }) {
122
+ return (
123
+ <Box marginBottom={0} marginTop={1}>
124
+ <Text color="#00ffff" bold>
125
+ {title}
126
+ </Text>
127
+ </Box>
128
+ );
79
129
  }
80
130
 
81
131
  function LogLine({ entry }: { entry: LogEntry }) {
82
- const color = getServiceColor(entry.source);
83
-
84
- return (
85
- <Box>
86
- <Text color={color}>[{entry.source}]</Text>
87
- <Text color={entry.isError ? "#ff3366" : undefined}>
88
- {" "}
89
- {linkify(entry.line)}
90
- </Text>
91
- </Box>
92
- );
132
+ const color = getServiceColor(entry.source);
133
+
134
+ return (
135
+ <Box>
136
+ <Text color={color}>[{entry.source}]</Text>
137
+ <Text color={entry.isError ? "#ff3366" : undefined}> {linkify(entry.line)}</Text>
138
+ </Box>
139
+ );
93
140
  }
94
141
 
95
142
  function truncateUrl(url: string, maxLen: number): string {
96
- if (url.length <= maxLen) return url;
97
- try {
98
- const parsed = new URL(url);
99
- const host = parsed.host;
100
- if (host.length > maxLen - 10) {
101
- return `${host.slice(0, maxLen - 13)}...`;
102
- }
103
- return host;
104
- } catch {
105
- return `${url.slice(0, maxLen - 3)}...`;
106
- }
143
+ if (url.length <= maxLen) return url;
144
+ try {
145
+ const parsed = new URL(url);
146
+ const host = parsed.host;
147
+ if (host.length > maxLen - 10) {
148
+ return `${host.slice(0, maxLen - 13)}...`;
149
+ }
150
+ return host;
151
+ } catch {
152
+ return `${url.slice(0, maxLen - 3)}...`;
153
+ }
107
154
  }
108
155
 
109
156
  function DevView({
110
- processes,
111
- logs,
112
- description,
113
- proxyTarget,
114
- onExit,
115
- onExportLogs,
157
+ processes,
158
+ logs,
159
+ description,
160
+ proxyTarget,
161
+ onExit,
162
+ onExportLogs,
116
163
  }: DevViewProps) {
117
- const { exit } = useApp();
118
- const [isShuttingDown, setIsShuttingDown] = useState(false);
119
-
120
- useInput((input, key) => {
121
- if (isShuttingDown) return;
122
-
123
- if (input === "q" || (key.ctrl && input === "c")) {
124
- setIsShuttingDown(true);
125
- // Run cleanup async, then force exit
126
- Promise.resolve(onExit?.()).then(() => {
127
- exit();
128
- process.exit(0);
129
- });
130
- }
131
- if (input === "l") {
132
- setIsShuttingDown(true);
133
- // Run export logs async, then force exit
134
- Promise.resolve(onExportLogs?.()).then(() => {
135
- exit();
136
- process.exit(0);
137
- });
138
- }
139
- });
140
-
141
- const readyCount = processes.filter((p) => p.status === "ready").length;
142
- const total = processes.length;
143
- const allReady = readyCount === total;
144
- const hostProcess = processes.find((p) => p.name === "host");
145
- const hostPort = hostProcess?.port || 3000;
146
-
147
- const recentLogs = logs.slice(-12);
148
-
149
- return (
150
- <Box flexDirection="column">
151
- <Box marginBottom={0}>
152
- <Text color="#00ffff">{frames.top(52)}</Text>
153
- </Box>
154
- <Box>
155
- <Text>
156
- {" "}
157
- {icons.run} {gradients.cyber(description.toUpperCase())}
158
- </Text>
159
- </Box>
160
- <Box marginBottom={1}>
161
- <Text color="#00ffff">{frames.bottom(52)}</Text>
162
- </Box>
163
-
164
- {allReady && (
165
- <Box marginBottom={1} flexDirection="column">
166
- <Box>
167
- <Text color="#00ff41">
168
- {" "}
169
- {icons.app} APP READY
170
- </Text>
171
- </Box>
172
- <Box>
173
- <Text color="#00ff41" bold>
174
- {" "}
175
- {icons.arrow} http://localhost:{hostPort}
176
- </Text>
177
- </Box>
178
- </Box>
179
- )}
180
-
181
- {proxyTarget && (
182
- <Box marginBottom={1}>
183
- <Text color="#ffaa00">
184
- {" "}
185
- {icons.arrow} API PROXY → {truncateUrl(proxyTarget, 38)}
186
- </Text>
187
- </Box>
188
- )}
189
-
190
- <Box marginTop={0} marginBottom={0}>
191
- <Text>{colors.dim(divider(52))}</Text>
192
- </Box>
193
-
194
- {processes.map((proc) => (
195
- <ProcessRow key={proc.name} proc={proc} />
196
- ))}
197
-
198
- <Box marginTop={1} marginBottom={0}>
199
- <Text>{colors.dim(divider(52))}</Text>
200
- </Box>
201
-
202
- <Box marginTop={0}>
203
- <Text color={allReady ? "#00ff41" : "#00ffff"}>
204
- {" "}
205
- {allReady
206
- ? `${icons.ok} All ${total} services running`
207
- : `${icons.scan} ${readyCount}/${total} ready`}
208
- </Text>
209
- <Text color="gray">
210
- {" "}
211
- {icons.dot} q quit {icons.dot} l logs
212
- </Text>
213
- </Box>
214
-
215
- {recentLogs.length > 0 && (
216
- <>
217
- <Box marginTop={1} marginBottom={0}>
218
- <Text>{colors.dim(divider(52))}</Text>
219
- </Box>
220
- <Box flexDirection="column" marginTop={0}>
221
- {recentLogs.map((entry, i) => (
222
- <LogLine key={`${entry.timestamp}-${i}`} entry={entry} />
223
- ))}
224
- </Box>
225
- </>
226
- )}
227
- </Box>
228
- );
164
+ const { exit } = useApp();
165
+ const [isShuttingDown, setIsShuttingDown] = useState(false);
166
+
167
+ useInput((input, key) => {
168
+ if (isShuttingDown) return;
169
+
170
+ if (input === "q" || (key.ctrl && input === "c")) {
171
+ setIsShuttingDown(true);
172
+ Promise.resolve(onExit?.()).then(() => {
173
+ exit();
174
+ });
175
+ }
176
+ if (input === "l") {
177
+ setIsShuttingDown(true);
178
+ Promise.resolve(onExportLogs?.()).then(() => {
179
+ exit();
180
+ });
181
+ }
182
+ });
183
+
184
+ const readyCount = processes.filter((p) => p.status === "ready").length;
185
+ const total = processes.length;
186
+ const allReady = readyCount === total;
187
+ const hostProcess = processes.find((p) => p.name === "host");
188
+ const hostPort = hostProcess?.port || 3000;
189
+ const recentLogs = logs.slice(-12);
190
+ const sectionedProcesses = getSectionedProcesses(processes);
191
+ const columnWidths = getColumnWidths(processes);
192
+
193
+ return (
194
+ <Box flexDirection="column">
195
+ <Box marginBottom={0}>
196
+ <Text color="#00ffff">{frames.top(52)}</Text>
197
+ </Box>
198
+ <Box>
199
+ <Text>
200
+ {" "}
201
+ {icons.run} {gradients.cyber(description.toUpperCase())}
202
+ </Text>
203
+ </Box>
204
+ <Box marginBottom={1}>
205
+ <Text color="#00ffff">{frames.bottom(52)}</Text>
206
+ </Box>
207
+
208
+ {allReady && (
209
+ <Box marginBottom={1} flexDirection="column">
210
+ <Box>
211
+ <Text color="#00ff41">
212
+ {" "}
213
+ {icons.app} APP READY
214
+ </Text>
215
+ </Box>
216
+ <Box>
217
+ <Text color="#00ff41" bold>
218
+ {" "}
219
+ {icons.arrow} http://localhost:{hostPort}
220
+ </Text>
221
+ </Box>
222
+ </Box>
223
+ )}
224
+
225
+ {proxyTarget && (
226
+ <Box marginBottom={1}>
227
+ <Text color="#ffaa00">
228
+ {" "}
229
+ {icons.arrow} API PROXY → {truncateUrl(proxyTarget, 38)}
230
+ </Text>
231
+ </Box>
232
+ )}
233
+
234
+ <Box marginTop={0} marginBottom={0}>
235
+ <Text>{colors.dim(divider(52))}</Text>
236
+ </Box>
237
+
238
+ {sectionedProcesses.map((section) => (
239
+ <Box key={section.key} flexDirection="column">
240
+ <SectionHeader title={section.title} />
241
+ {section.processes.map((proc) => (
242
+ <ProcessRow
243
+ key={proc.name}
244
+ proc={proc}
245
+ nameWidth={columnWidths.name}
246
+ sourceWidth={columnWidths.source}
247
+ />
248
+ ))}
249
+ </Box>
250
+ ))}
251
+
252
+ <Box marginTop={1} marginBottom={0}>
253
+ <Text>{colors.dim(divider(52))}</Text>
254
+ </Box>
255
+
256
+ <Box marginTop={0}>
257
+ <Text color={allReady ? "#00ff41" : "#00ffff"}>
258
+ {" "}
259
+ {allReady
260
+ ? `${icons.ok} All ${total} services running`
261
+ : `${icons.scan} ${readyCount}/${total} ready`}
262
+ </Text>
263
+ <Text color="gray">
264
+ {" "}
265
+ {icons.dot} q quit {icons.dot} l logs
266
+ </Text>
267
+ </Box>
268
+
269
+ {recentLogs.length > 0 && (
270
+ <>
271
+ <Box marginTop={1} marginBottom={0}>
272
+ <Text>{colors.dim(divider(52))}</Text>
273
+ </Box>
274
+ <Box flexDirection="column" marginTop={0}>
275
+ {recentLogs.map((entry) => (
276
+ <LogLine key={entry.id} entry={entry} />
277
+ ))}
278
+ </Box>
279
+ </>
280
+ )}
281
+ </Box>
282
+ );
229
283
  }
230
284
 
231
285
  export interface DevViewHandle {
232
- updateProcess: (
233
- name: string,
234
- status: ProcessStatus,
235
- message?: string,
236
- ) => void;
237
- addLog: (source: string, line: string, isError?: boolean) => void;
238
- unmount: () => void;
286
+ updateProcess: (name: string, status: ProcessStatus, message?: string) => void;
287
+ addLog: (source: string, line: string, isError?: boolean) => void;
288
+ unmount: () => void;
239
289
  }
240
290
 
241
291
  export function renderDevView(
242
- initialProcesses: ProcessState[],
243
- description: string,
244
- env: Record<string, string>,
245
- onExit?: () => Promise<void> | void,
246
- onExportLogs?: () => Promise<void> | void,
292
+ initialProcesses: ProcessState[],
293
+ description: string,
294
+ env: Record<string, string>,
295
+ onExit?: () => Promise<void> | void,
296
+ onExportLogs?: () => Promise<void> | void,
247
297
  ): DevViewHandle {
248
- let processes = [...initialProcesses];
249
- let logs: LogEntry[] = [];
250
- let rerender: (() => void) | null = null;
251
- const proxyTarget = env.API_PROXY;
252
-
253
- const updateProcess = (
254
- name: string,
255
- status: ProcessStatus,
256
- message?: string,
257
- ) => {
258
- processes = processes.map((p) =>
259
- p.name === name ? { ...p, status, message } : p,
260
- );
261
- rerender?.();
262
- };
263
-
264
- const addLog = (source: string, line: string, isError = false) => {
265
- logs = [...logs, { source, line, timestamp: Date.now(), isError }];
266
- if (logs.length > 100) logs = logs.slice(-100);
267
- rerender?.();
268
- };
269
-
270
- function DevViewWrapper() {
271
- const [, forceUpdate] = useState(0);
272
-
273
- useEffect(() => {
274
- rerender = () => forceUpdate((n) => n + 1);
275
- return () => {
276
- rerender = null;
277
- };
278
- }, []);
279
-
280
- return (
281
- <DevView
282
- processes={processes}
283
- logs={logs}
284
- description={description}
285
- proxyTarget={proxyTarget}
286
- onExit={onExit}
287
- onExportLogs={onExportLogs}
288
- />
289
- );
290
- }
291
-
292
- const { unmount } = render(<DevViewWrapper />);
293
-
294
- return { updateProcess, addLog, unmount };
298
+ let processes = [...initialProcesses];
299
+ let logs: LogEntry[] = [];
300
+ let rerender: (() => void) | null = null;
301
+ const proxyTarget = env.API_PROXY;
302
+ let logSeq = 0;
303
+ let lastLogKey: string | null = null;
304
+
305
+ const updateProcess = (name: string, status: ProcessStatus, message?: string) => {
306
+ processes = processes.map((p) => (p.name === name ? { ...p, status, message } : p));
307
+ rerender?.();
308
+ };
309
+
310
+ const addLog = (source: string, line: string, isError = false) => {
311
+ const nextKey = `${source}:${isError ? "1" : "0"}:${line}`;
312
+ if (nextKey === lastLogKey) return;
313
+ lastLogKey = nextKey;
314
+
315
+ logs = [
316
+ ...logs,
317
+ { id: `${Date.now()}-${++logSeq}`, source, line, timestamp: Date.now(), isError },
318
+ ];
319
+ if (logs.length > 100) logs = logs.slice(-100);
320
+ rerender?.();
321
+ };
322
+
323
+ function DevViewWrapper() {
324
+ const [, forceUpdate] = useState(0);
325
+
326
+ useEffect(() => {
327
+ rerender = () => forceUpdate((n: number) => n + 1);
328
+ return () => {
329
+ rerender = null;
330
+ };
331
+ }, []);
332
+
333
+ return (
334
+ <DevView
335
+ processes={processes}
336
+ logs={logs}
337
+ description={description}
338
+ proxyTarget={proxyTarget}
339
+ onExit={onExit}
340
+ onExportLogs={onExportLogs}
341
+ />
342
+ );
343
+ }
344
+
345
+ const { unmount } = render(<DevViewWrapper />);
346
+ return { updateProcess, addLog, unmount };
295
347
  }