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