everything-dev 1.27.0 → 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 (104) hide show
  1. package/dist/cli/infra.cjs +1 -1
  2. package/dist/cli/infra.mjs +1 -1
  3. package/dist/cli/init.cjs +7 -9
  4. package/dist/cli/init.cjs.map +1 -1
  5. package/dist/cli/init.d.cts +1 -1
  6. package/dist/cli/init.d.cts.map +1 -1
  7. package/dist/cli/init.d.mts +1 -1
  8. package/dist/cli/init.d.mts.map +1 -1
  9. package/dist/cli/init.mjs +7 -9
  10. package/dist/cli/init.mjs.map +1 -1
  11. package/dist/cli/prompts.cjs +28 -24
  12. package/dist/cli/prompts.cjs.map +1 -1
  13. package/dist/cli/prompts.mjs +27 -24
  14. package/dist/cli/prompts.mjs.map +1 -1
  15. package/dist/cli/sync.cjs +4 -1
  16. package/dist/cli/sync.cjs.map +1 -1
  17. package/dist/cli/sync.mjs +4 -1
  18. package/dist/cli/sync.mjs.map +1 -1
  19. package/dist/cli.cjs +187 -12
  20. package/dist/cli.cjs.map +1 -1
  21. package/dist/cli.mjs +186 -11
  22. package/dist/cli.mjs.map +1 -1
  23. package/dist/contract.cjs +1 -1
  24. package/dist/contract.cjs.map +1 -1
  25. package/dist/contract.d.cts +38 -34
  26. package/dist/contract.d.cts.map +1 -1
  27. package/dist/contract.d.mts +38 -34
  28. package/dist/contract.d.mts.map +1 -1
  29. package/dist/contract.mjs +1 -0
  30. package/dist/contract.mjs.map +1 -1
  31. package/dist/dev-session.cjs +0 -1
  32. package/dist/dev-session.mjs +1 -1
  33. package/dist/index.cjs +0 -2
  34. package/dist/index.d.cts +2 -2
  35. package/dist/index.d.mts +2 -2
  36. package/dist/index.mjs +0 -1
  37. package/dist/near-cli.cjs +1 -1
  38. package/dist/near-cli.mjs +1 -1
  39. package/dist/orchestrator.cjs +1 -1
  40. package/dist/orchestrator.mjs +1 -1
  41. package/dist/plugin.cjs +163 -139
  42. package/dist/plugin.cjs.map +1 -1
  43. package/dist/plugin.d.cts +67 -34
  44. package/dist/plugin.d.cts.map +1 -1
  45. package/dist/plugin.d.mts +66 -34
  46. package/dist/plugin.d.mts.map +1 -1
  47. package/dist/plugin.mjs +153 -130
  48. package/dist/plugin.mjs.map +1 -1
  49. package/dist/service-descriptor.d.cts +34 -0
  50. package/dist/service-descriptor.d.cts.map +1 -0
  51. package/dist/service-descriptor.d.mts +36 -0
  52. package/dist/service-descriptor.d.mts.map +1 -0
  53. package/dist/types.d.cts +2 -2
  54. package/dist/types.d.mts +2 -2
  55. package/package.json +2 -2
  56. package/src/api-contract.ts +0 -623
  57. package/src/app.ts +0 -193
  58. package/src/cli/catalog.ts +0 -49
  59. package/src/cli/framework-version.ts +0 -61
  60. package/src/cli/help.ts +0 -13
  61. package/src/cli/infra.ts +0 -190
  62. package/src/cli/init.ts +0 -1145
  63. package/src/cli/parse.ts +0 -147
  64. package/src/cli/prompts.ts +0 -135
  65. package/src/cli/snapshot.ts +0 -46
  66. package/src/cli/status.ts +0 -99
  67. package/src/cli/sync.ts +0 -429
  68. package/src/cli/timing.ts +0 -63
  69. package/src/cli/upgrade.ts +0 -869
  70. package/src/cli.ts +0 -516
  71. package/src/components/dev-view.tsx +0 -352
  72. package/src/components/streaming-view.ts +0 -177
  73. package/src/config.ts +0 -893
  74. package/src/contract.meta.ts +0 -140
  75. package/src/contract.ts +0 -326
  76. package/src/dev-logs.ts +0 -92
  77. package/src/dev-session.ts +0 -283
  78. package/src/fastkv.ts +0 -181
  79. package/src/index.ts +0 -8
  80. package/src/integrity.ts +0 -138
  81. package/src/internal/manifest-normalizer.ts +0 -290
  82. package/src/merge.ts +0 -187
  83. package/src/mf.ts +0 -147
  84. package/src/near-cli.ts +0 -259
  85. package/src/network.ts +0 -3
  86. package/src/orchestrator.ts +0 -493
  87. package/src/plugin.ts +0 -1799
  88. package/src/sdk.ts +0 -14
  89. package/src/service-descriptor.ts +0 -281
  90. package/src/shared.ts +0 -249
  91. package/src/sidebar.ts +0 -140
  92. package/src/types.ts +0 -330
  93. package/src/ui/head.ts +0 -83
  94. package/src/ui/index.ts +0 -5
  95. package/src/ui/metadata.ts +0 -95
  96. package/src/ui/router.ts +0 -88
  97. package/src/ui/runtime.ts +0 -42
  98. package/src/ui/types.ts +0 -65
  99. package/src/utils/banner.ts +0 -21
  100. package/src/utils/linkify.ts +0 -11
  101. package/src/utils/path-match.ts +0 -16
  102. package/src/utils/run.ts +0 -31
  103. package/src/utils/save-config.ts +0 -20
  104. 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
- }