everything-dev 0.3.3 → 1.3.3

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 (313) 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 +287 -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 +279 -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/internal/manifest-normalizer.cjs +140 -0
  123. package/dist/internal/manifest-normalizer.cjs.map +1 -0
  124. package/dist/internal/manifest-normalizer.mjs +138 -0
  125. package/dist/internal/manifest-normalizer.mjs.map +1 -0
  126. package/dist/mf.cjs +77 -0
  127. package/dist/mf.cjs.map +1 -0
  128. package/dist/mf.d.cts +19 -0
  129. package/dist/mf.d.cts.map +1 -0
  130. package/dist/mf.d.mts +19 -0
  131. package/dist/mf.d.mts.map +1 -0
  132. package/dist/mf.mjs +71 -0
  133. package/dist/mf.mjs.map +1 -0
  134. package/dist/near-cli.cjs +196 -0
  135. package/dist/near-cli.cjs.map +1 -0
  136. package/dist/near-cli.mjs +193 -0
  137. package/dist/near-cli.mjs.map +1 -0
  138. package/dist/network.cjs +9 -0
  139. package/dist/network.cjs.map +1 -0
  140. package/dist/network.mjs +8 -0
  141. package/dist/network.mjs.map +1 -0
  142. package/dist/orchestrator.cjs +441 -0
  143. package/dist/orchestrator.cjs.map +1 -0
  144. package/dist/orchestrator.d.cts +40 -0
  145. package/dist/orchestrator.d.cts.map +1 -0
  146. package/dist/orchestrator.d.mts +40 -0
  147. package/dist/orchestrator.d.mts.map +1 -0
  148. package/dist/orchestrator.mjs +436 -0
  149. package/dist/orchestrator.mjs.map +1 -0
  150. package/dist/plugin.cjs +830 -0
  151. package/dist/plugin.cjs.map +1 -0
  152. package/dist/plugin.d.cts +347 -0
  153. package/dist/plugin.d.cts.map +1 -0
  154. package/dist/plugin.d.mts +348 -0
  155. package/dist/plugin.d.mts.map +1 -0
  156. package/dist/plugin.mjs +827 -0
  157. package/dist/plugin.mjs.map +1 -0
  158. package/dist/process-registry.cjs +120 -0
  159. package/dist/process-registry.cjs.map +1 -0
  160. package/dist/process-registry.d.cts +25 -0
  161. package/dist/process-registry.d.cts.map +1 -0
  162. package/dist/process-registry.d.mts +25 -0
  163. package/dist/process-registry.d.mts.map +1 -0
  164. package/dist/process-registry.mjs +119 -0
  165. package/dist/process-registry.mjs.map +1 -0
  166. package/dist/sdk.cjs +61 -0
  167. package/dist/sdk.d.cts +5 -0
  168. package/dist/sdk.d.mts +5 -0
  169. package/dist/sdk.mjs +6 -0
  170. package/dist/shared.cjs +143 -0
  171. package/dist/shared.cjs.map +1 -0
  172. package/dist/shared.d.cts +33 -0
  173. package/dist/shared.d.cts.map +1 -0
  174. package/dist/shared.d.mts +33 -0
  175. package/dist/shared.d.mts.map +1 -0
  176. package/dist/shared.mjs +140 -0
  177. package/dist/shared.mjs.map +1 -0
  178. package/dist/types.cjs +160 -0
  179. package/dist/types.cjs.map +1 -0
  180. package/dist/types.d.cts +269 -0
  181. package/dist/types.d.cts.map +1 -0
  182. package/dist/types.d.mts +269 -0
  183. package/dist/types.d.mts.map +1 -0
  184. package/dist/types.mjs +144 -0
  185. package/dist/types.mjs.map +1 -0
  186. package/dist/ui/head.cjs +67 -0
  187. package/dist/ui/head.cjs.map +1 -0
  188. package/dist/ui/head.d.cts +19 -0
  189. package/dist/ui/head.d.cts.map +1 -0
  190. package/dist/ui/head.d.mts +19 -0
  191. package/dist/ui/head.d.mts.map +1 -0
  192. package/dist/ui/head.mjs +61 -0
  193. package/dist/ui/head.mjs.map +1 -0
  194. package/dist/ui/index.cjs +32 -0
  195. package/dist/ui/index.d.cts +7 -0
  196. package/dist/ui/index.d.mts +7 -0
  197. package/dist/ui/index.mjs +6 -0
  198. package/dist/ui/metadata.cjs +106 -0
  199. package/dist/ui/metadata.cjs.map +1 -0
  200. package/dist/ui/metadata.d.cts +35 -0
  201. package/dist/ui/metadata.d.cts.map +1 -0
  202. package/dist/ui/metadata.d.mts +35 -0
  203. package/dist/ui/metadata.d.mts.map +1 -0
  204. package/dist/ui/metadata.mjs +100 -0
  205. package/dist/ui/metadata.mjs.map +1 -0
  206. package/dist/ui/router.cjs +56 -0
  207. package/dist/ui/router.cjs.map +1 -0
  208. package/dist/ui/router.d.cts +11 -0
  209. package/dist/ui/router.d.cts.map +1 -0
  210. package/dist/ui/router.d.mts +11 -0
  211. package/dist/ui/router.d.mts.map +1 -0
  212. package/dist/ui/router.mjs +51 -0
  213. package/dist/ui/router.mjs.map +1 -0
  214. package/dist/ui/runtime.cjs +65 -0
  215. package/dist/ui/runtime.cjs.map +1 -0
  216. package/dist/ui/runtime.d.cts +29 -0
  217. package/dist/ui/runtime.d.cts.map +1 -0
  218. package/dist/ui/runtime.d.mts +29 -0
  219. package/dist/ui/runtime.d.mts.map +1 -0
  220. package/dist/ui/runtime.mjs +53 -0
  221. package/dist/ui/runtime.mjs.map +1 -0
  222. package/dist/ui/types.cjs +0 -0
  223. package/dist/ui/types.d.cts +52 -0
  224. package/dist/ui/types.d.cts.map +1 -0
  225. package/dist/ui/types.d.mts +52 -0
  226. package/dist/ui/types.d.mts.map +1 -0
  227. package/dist/ui/types.mjs +1 -0
  228. package/dist/utils/banner.cjs +24 -0
  229. package/dist/utils/banner.cjs.map +1 -0
  230. package/dist/utils/banner.mjs +23 -0
  231. package/dist/utils/banner.mjs.map +1 -0
  232. package/dist/utils/linkify.cjs +15 -0
  233. package/dist/utils/linkify.cjs.map +1 -0
  234. package/dist/utils/linkify.mjs +14 -0
  235. package/dist/utils/linkify.mjs.map +1 -0
  236. package/dist/utils/run.cjs +40 -0
  237. package/dist/utils/run.cjs.map +1 -0
  238. package/dist/utils/run.mjs +39 -0
  239. package/dist/utils/run.mjs.map +1 -0
  240. package/dist/utils/theme.cjs +44 -0
  241. package/dist/utils/theme.cjs.map +1 -0
  242. package/dist/utils/theme.mjs +37 -0
  243. package/dist/utils/theme.mjs.map +1 -0
  244. package/package.json +269 -80
  245. package/src/api-contract.ts +309 -0
  246. package/src/api.ts +181 -0
  247. package/src/app.ts +346 -0
  248. package/src/cli/catalog.ts +49 -0
  249. package/src/cli/help.ts +13 -0
  250. package/src/cli/init.ts +386 -0
  251. package/src/cli/parse.ts +130 -0
  252. package/src/cli/prompts.ts +64 -0
  253. package/src/cli.ts +203 -1507
  254. package/src/components/dev-view.tsx +307 -255
  255. package/src/components/streaming-view.ts +164 -128
  256. package/src/config.ts +462 -532
  257. package/src/contract.meta.ts +96 -0
  258. package/src/contract.ts +164 -561
  259. package/src/dev-logs.ts +85 -0
  260. package/src/dev-session.ts +318 -0
  261. package/src/fastkv.ts +153 -0
  262. package/src/federation.server.ts +43 -0
  263. package/src/host.ts +526 -0
  264. package/src/index.ts +6 -3
  265. package/src/integrity.ts +54 -0
  266. package/src/internal/manifest-normalizer.ts +251 -0
  267. package/src/mf.ts +105 -0
  268. package/src/near-cli.ts +284 -0
  269. package/src/network.ts +3 -0
  270. package/src/orchestrator.ts +648 -0
  271. package/src/plugin.ts +1130 -2311
  272. package/src/process-registry.ts +154 -0
  273. package/src/scripts/sync-api-contract.ts +24 -0
  274. package/src/sdk.ts +14 -0
  275. package/src/shared.ts +206 -0
  276. package/src/types.ts +152 -206
  277. package/src/ui/head.ts +34 -27
  278. package/src/ui/index.ts +3 -3
  279. package/src/ui/metadata.ts +95 -0
  280. package/src/ui/router.ts +22 -6
  281. package/src/ui/runtime.ts +55 -6
  282. package/src/ui/types.ts +24 -11
  283. package/src/utils/banner.ts +10 -6
  284. package/src/utils/run.ts +26 -27
  285. package/src/utils/theme.ts +3 -66
  286. package/src/components/monitor-view.tsx +0 -475
  287. package/src/components/status-view.tsx +0 -173
  288. package/src/lib/env.ts +0 -109
  289. package/src/lib/near-cli.ts +0 -289
  290. package/src/lib/nova.ts +0 -266
  291. package/src/lib/orchestrator.ts +0 -276
  292. package/src/lib/process-registry.ts +0 -166
  293. package/src/lib/process.ts +0 -550
  294. package/src/lib/resource-monitor/assertions.ts +0 -234
  295. package/src/lib/resource-monitor/command.ts +0 -283
  296. package/src/lib/resource-monitor/diff.ts +0 -157
  297. package/src/lib/resource-monitor/errors.ts +0 -127
  298. package/src/lib/resource-monitor/index.ts +0 -305
  299. package/src/lib/resource-monitor/platform/darwin.ts +0 -306
  300. package/src/lib/resource-monitor/platform/index.ts +0 -35
  301. package/src/lib/resource-monitor/platform/linux.ts +0 -332
  302. package/src/lib/resource-monitor/platform/windows.ts +0 -298
  303. package/src/lib/resource-monitor/snapshot.ts +0 -217
  304. package/src/lib/resource-monitor/types.ts +0 -74
  305. package/src/lib/session-recorder/errors.ts +0 -102
  306. package/src/lib/session-recorder/flows/login.ts +0 -210
  307. package/src/lib/session-recorder/index.ts +0 -361
  308. package/src/lib/session-recorder/playwright.ts +0 -257
  309. package/src/lib/session-recorder/report.ts +0 -353
  310. package/src/lib/session-recorder/server.ts +0 -268
  311. package/src/lib/session-recorder/types.ts +0 -115
  312. package/src/lib/sync.ts +0 -1
  313. 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
  }