pm4ai 0.0.73

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.

Potentially problematic release.


This version of pm4ai might be problematic. Click here for more details.

Files changed (51) hide show
  1. package/README.md +34 -0
  2. package/dist/audit-oQQfgtxr.mjs +287 -0
  3. package/dist/cleanup-M-ALxTqh.mjs +35 -0
  4. package/dist/cli.d.mts +1 -0
  5. package/dist/cli.mjs +77 -0
  6. package/dist/dashboard-DVRNZGun.mjs +39 -0
  7. package/dist/discover-d8ENQC1K.mjs +172 -0
  8. package/dist/fix-BcMN_cuG.mjs +260 -0
  9. package/dist/fix-DvtItv_V.mjs +2 -0
  10. package/dist/guide-BS7-RqpH.d.mts +4 -0
  11. package/dist/guide-CifUmtQN.mjs +59 -0
  12. package/dist/guide.d.mts +2 -0
  13. package/dist/guide.mjs +2 -0
  14. package/dist/ignores-BBl55eUM.mjs +37 -0
  15. package/dist/index.d.mts +83 -0
  16. package/dist/index.mjs +11 -0
  17. package/dist/init-C-073mRX.mjs +120 -0
  18. package/dist/list-QdJPgkEO.mjs +31 -0
  19. package/dist/package-NpIViQjo.mjs +4 -0
  20. package/dist/schemas-Dsbtf6P2.mjs +51 -0
  21. package/dist/schemas.d.mts +48 -0
  22. package/dist/schemas.mjs +2 -0
  23. package/dist/setup-BPuE4oWT.mjs +164 -0
  24. package/dist/status-ByiuW1iF.mjs +2 -0
  25. package/dist/status-CzCNkG58.mjs +1775 -0
  26. package/dist/sync-DN1rgN3P.mjs +732 -0
  27. package/dist/templates/cli/package.json +30 -0
  28. package/dist/templates/cli/src/cli.ts +16 -0
  29. package/dist/templates/cli/src/index.ts +2 -0
  30. package/dist/templates/cli/src/tui.tsx +57 -0
  31. package/dist/templates/cli/tsdown.config.ts +9 -0
  32. package/dist/templates/docs/content/docs/index.mdx +6 -0
  33. package/dist/templates/docs/package.json +20 -0
  34. package/dist/templates/docs/source.config.ts +16 -0
  35. package/dist/templates/docs/src/app/(home)/page.tsx +11 -0
  36. package/dist/templates/lib/package.json +22 -0
  37. package/dist/templates/lib/src/index.ts +2 -0
  38. package/dist/templates/lib/tsdown.config.ts +9 -0
  39. package/dist/templates/root-package.txt +38 -0
  40. package/dist/templates/web/package.json +17 -0
  41. package/dist/templates/web/src/app/page.tsx +6 -0
  42. package/dist/templates/web/src/app/providers.tsx +15 -0
  43. package/dist/utils-CpkOMuQN.mjs +221 -0
  44. package/dist/watch-D4OSFClu.mjs +566 -0
  45. package/dist/watch-emitter-uTmZ3oQd.mjs +177 -0
  46. package/dist/watch-state-DIMHiLr5.d.mts +118 -0
  47. package/dist/watch-state-wF-NfC-k.mjs +274 -0
  48. package/dist/watch-state.d.mts +2 -0
  49. package/dist/watch-state.mjs +2 -0
  50. package/dist/watch-types-BzSNCGb2.mjs +22 -0
  51. package/package.json +65 -0
@@ -0,0 +1,566 @@
1
+ import { M as PKG_NAME, f as projectName } from "./utils-CpkOMuQN.mjs";
2
+ import { a as startEmitter, i as onEvent, o as readCheckResult, r as installCleanup } from "./watch-emitter-uTmZ3oQd.mjs";
3
+ import { t as discover } from "./discover-d8ENQC1K.mjs";
4
+ import { c as createInitState, f as progressDots, g as sparkline, i as RESET_DELAY, l as deriveStats, m as smoothBar, n as IDLE_FALLBACK, o as STEP_COUNT, p as runReducer, s as STEP_LABELS, u as formatTime, v as timeAgo } from "./watch-state-wF-NfC-k.mjs";
5
+ import { t as version } from "./package-NpIViQjo.mjs";
6
+ import { existsSync } from "node:fs";
7
+ import { spawn } from "node:child_process";
8
+ import { Box, Text, render, useApp, useInput, useStdout } from "ink";
9
+ import Spinner from "ink-spinner";
10
+ import { once } from "node:events";
11
+ import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ //#region src/watch.tsx
14
+ /** biome-ignore-all lint/suspicious/noEmptyBlockStatements: signal handler */
15
+ const VERSION = version ?? "0.0.0";
16
+ const safeReadCheck = (path) => {
17
+ try {
18
+ return readCheckResult(path);
19
+ } catch {
20
+ return null;
21
+ }
22
+ };
23
+ const mkIdleFn = (p) => {
24
+ const cached = safeReadCheck(p.path);
25
+ if (!cached) return {
26
+ completedSteps: /* @__PURE__ */ new Set(),
27
+ elapsed: 0,
28
+ status: "idle"
29
+ };
30
+ const label = `${cached.pass ? "clean" : `${cached.violations} issues`} ${timeAgo(cached.at)}`;
31
+ return {
32
+ cachedPass: cached.pass,
33
+ completedSteps: /* @__PURE__ */ new Set(),
34
+ detail: label,
35
+ elapsed: 0,
36
+ status: "idle"
37
+ };
38
+ };
39
+ const safeSpawn = (args, cwd) => {
40
+ try {
41
+ const proc = spawn("bunx", args, {
42
+ cwd,
43
+ detached: true,
44
+ stdio: "ignore"
45
+ });
46
+ proc.on("error", () => {});
47
+ proc.unref();
48
+ return true;
49
+ } catch {
50
+ return false;
51
+ }
52
+ };
53
+ const ProjectRow = ({ focused, name, pad, state }) => {
54
+ const padded = name.padEnd(pad);
55
+ const cursor = focused ? "›" : " ";
56
+ const iconMap = {
57
+ done: "✔",
58
+ failed: "✘",
59
+ idle: state.cachedPass === void 0 ? "·" : "●",
60
+ running: ""
61
+ };
62
+ const colorMap = {
63
+ done: "green",
64
+ failed: "red",
65
+ idle: state.cachedPass ? "green" : state.cachedPass ? void 0 : "red",
66
+ running: "yellow"
67
+ };
68
+ const icon = iconMap[state.status];
69
+ const color = colorMap[state.status];
70
+ const isIdle = state.status === "idle";
71
+ const secs = state.elapsed > 0 ? state.elapsed : void 0;
72
+ const stepInfo = state.status === "running" ? `${STEP_LABELS[state.step] ?? "⚡ working"} ${progressDots(state.completedSteps, state.step)}` : state.detail ?? "";
73
+ return /* @__PURE__ */ jsxs(Box, {
74
+ gap: 1,
75
+ paddingLeft: 1,
76
+ children: [
77
+ /* @__PURE__ */ jsx(Text, {
78
+ color: focused ? "cyan" : void 0,
79
+ dimColor: !focused,
80
+ children: cursor
81
+ }),
82
+ state.status === "running" ? /* @__PURE__ */ jsx(Spinner, { type: "dots" }) : /* @__PURE__ */ jsx(Text, {
83
+ color,
84
+ dimColor: isIdle ? !color : void 0,
85
+ children: icon
86
+ }),
87
+ /* @__PURE__ */ jsx(Text, {
88
+ bold: focused || state.status === "running",
89
+ dimColor: isIdle,
90
+ children: padded
91
+ }),
92
+ stepInfo ? /* @__PURE__ */ jsx(Text, {
93
+ color: state.status === "running" ? "yellow" : color,
94
+ dimColor: isIdle,
95
+ children: stepInfo
96
+ }) : null,
97
+ secs === void 0 ? null : /* @__PURE__ */ jsxs(Text, {
98
+ dimColor: true,
99
+ children: [secs, "s"]
100
+ })
101
+ ]
102
+ });
103
+ };
104
+ ProjectRow.displayName = "ProjectRow";
105
+ const DoneFooter = ({ done, elapsed, failed, history, lastElapsed, slowestElapsed, slowestName }) => {
106
+ const delta = lastElapsed > 0 ? elapsed - lastElapsed : 0;
107
+ const deltaLabel = delta > 0 ? `+${delta}s` : delta < 0 ? `${delta}s` : "";
108
+ const deltaColor = delta > 0 ? "red" : delta < 0 ? "green" : void 0;
109
+ return /* @__PURE__ */ jsxs(Box, {
110
+ flexDirection: "column",
111
+ paddingLeft: 1,
112
+ children: [
113
+ failed > 0 ? /* @__PURE__ */ jsxs(Box, {
114
+ gap: 1,
115
+ children: [/* @__PURE__ */ jsxs(Text, {
116
+ color: "red",
117
+ children: [
118
+ "✘ ",
119
+ failed,
120
+ " failed · ",
121
+ done,
122
+ " passed · ",
123
+ formatTime(elapsed)
124
+ ]
125
+ }), /* @__PURE__ */ jsx(Text, {
126
+ dimColor: true,
127
+ children: "press enter to dismiss"
128
+ })]
129
+ }) : /* @__PURE__ */ jsxs(Box, {
130
+ gap: 1,
131
+ children: [
132
+ /* @__PURE__ */ jsxs(Text, {
133
+ bold: true,
134
+ color: "green",
135
+ children: ["✔ all clean · ", formatTime(elapsed)]
136
+ }),
137
+ deltaLabel && deltaColor ? /* @__PURE__ */ jsxs(Text, {
138
+ color: deltaColor,
139
+ children: [
140
+ "(",
141
+ deltaLabel,
142
+ ")"
143
+ ]
144
+ }) : null,
145
+ history.length > 1 ? /* @__PURE__ */ jsx(Text, {
146
+ dimColor: true,
147
+ children: sparkline(history)
148
+ }) : null
149
+ ]
150
+ }),
151
+ slowestName && slowestElapsed > 0 ? /* @__PURE__ */ jsxs(Text, {
152
+ dimColor: true,
153
+ children: [
154
+ "slowest: ",
155
+ slowestName,
156
+ " (",
157
+ slowestElapsed,
158
+ "s)"
159
+ ]
160
+ }) : null,
161
+ failed > 0 ? null : /* @__PURE__ */ jsxs(Text, {
162
+ dimColor: true,
163
+ children: [
164
+ "resetting in ",
165
+ RESET_DELAY / 1e3,
166
+ "s..."
167
+ ]
168
+ })
169
+ ]
170
+ });
171
+ };
172
+ DoneFooter.displayName = "DoneFooter";
173
+ const IdleFooter = ({ lastElapsed, lastFailed, lastTime, toast }) => /* @__PURE__ */ jsxs(Box, {
174
+ flexDirection: "column",
175
+ paddingLeft: 1,
176
+ children: [
177
+ toast ? /* @__PURE__ */ jsx(Text, {
178
+ color: "cyan",
179
+ children: toast
180
+ }) : null,
181
+ lastTime ? /* @__PURE__ */ jsxs(Text, {
182
+ dimColor: true,
183
+ children: [
184
+ "last run: ",
185
+ lastFailed > 0 ? `${lastFailed} failed` : "all clean",
186
+ " · ",
187
+ formatTime(lastElapsed),
188
+ " · ",
189
+ lastTime
190
+ ]
191
+ }) : null,
192
+ /* @__PURE__ */ jsxs(Text, {
193
+ dimColor: true,
194
+ children: [
195
+ /* @__PURE__ */ jsx(Text, {
196
+ bold: true,
197
+ dimColor: true,
198
+ children: "↑↓/jk"
199
+ }),
200
+ " ",
201
+ "select ·",
202
+ " ",
203
+ /* @__PURE__ */ jsx(Text, {
204
+ bold: true,
205
+ dimColor: true,
206
+ children: "g/G"
207
+ }),
208
+ " ",
209
+ "top/end ·",
210
+ " ",
211
+ /* @__PURE__ */ jsx(Text, {
212
+ bold: true,
213
+ dimColor: true,
214
+ children: "↵"
215
+ }),
216
+ " ",
217
+ "fix one ·",
218
+ " ",
219
+ /* @__PURE__ */ jsx(Text, {
220
+ bold: true,
221
+ dimColor: true,
222
+ children: "f"
223
+ }),
224
+ " ",
225
+ "fix all ·",
226
+ " ",
227
+ /* @__PURE__ */ jsx(Text, {
228
+ bold: true,
229
+ dimColor: true,
230
+ children: "s"
231
+ }),
232
+ " ",
233
+ "status ·",
234
+ " ",
235
+ /* @__PURE__ */ jsx(Text, {
236
+ bold: true,
237
+ dimColor: true,
238
+ children: "q"
239
+ }),
240
+ " ",
241
+ "quit"
242
+ ]
243
+ })
244
+ ]
245
+ });
246
+ IdleFooter.displayName = "IdleFooter";
247
+ const RunningFooter = ({ barWidth, elapsed, eta, fraction, pct }) => /* @__PURE__ */ jsxs(Box, {
248
+ gap: 1,
249
+ paddingLeft: 1,
250
+ children: [
251
+ /* @__PURE__ */ jsx(Text, {
252
+ color: "cyan",
253
+ children: smoothBar(fraction, barWidth)
254
+ }),
255
+ /* @__PURE__ */ jsxs(Text, {
256
+ color: "yellow",
257
+ children: [pct, "%"]
258
+ }),
259
+ elapsed > 0 ? /* @__PURE__ */ jsx(Text, {
260
+ dimColor: true,
261
+ children: formatTime(elapsed)
262
+ }) : null,
263
+ eta !== void 0 && eta > 0 ? /* @__PURE__ */ jsxs(Text, {
264
+ dimColor: true,
265
+ children: [
266
+ "~",
267
+ formatTime(eta),
268
+ " left"
269
+ ]
270
+ }) : null
271
+ ]
272
+ });
273
+ RunningFooter.displayName = "RunningFooter";
274
+ const WatchApp = ({ projects }) => {
275
+ const app = useApp();
276
+ const { stdout } = useStdout();
277
+ const [cols, setCols] = useState(stdout?.columns ?? 80);
278
+ useEffect(() => {
279
+ const handler = () => setCols(stdout?.columns ?? 80);
280
+ stdout?.on("resize", handler);
281
+ return () => {
282
+ stdout?.off("resize", handler);
283
+ };
284
+ }, [stdout]);
285
+ const barWidth = Math.min(Math.max(Math.floor(cols * .3), 12), 40);
286
+ const pad = useMemo(() => Math.max(...projects.map((p) => p.name.length)) + 2, [projects]);
287
+ const projectMap = useMemo(() => new Map(projects.map((p) => [p.name, p])), [projects]);
288
+ const [state, dispatch] = useReducer(runReducer, projects, (p) => createInitState(p, mkIdleFn));
289
+ const [toast, setToast] = useState("");
290
+ const toastTimerRef = useRef(void 0);
291
+ const sorted = useMemo(() => {
292
+ if (state.sortSnapshot.length === 0) return projects;
293
+ const result = [];
294
+ for (const n of state.sortSnapshot) {
295
+ const p = projectMap.get(n);
296
+ if (p) result.push(p);
297
+ }
298
+ return result;
299
+ }, [
300
+ state.sortSnapshot,
301
+ projects,
302
+ projectMap
303
+ ]);
304
+ const focusedIdx = useMemo(() => {
305
+ const idx = sorted.findIndex((p) => p.name === state.focused);
306
+ return Math.max(idx, 0);
307
+ }, [sorted, state.focused]);
308
+ const stats = useMemo(() => deriveStats({
309
+ elapsed: state.elapsed,
310
+ history: state.history,
311
+ lastElapsed: state.lastElapsed,
312
+ projects: state.projects
313
+ }), [
314
+ state.projects,
315
+ state.history,
316
+ state.lastElapsed,
317
+ state.elapsed
318
+ ]);
319
+ const hasFails = state.phase === "done" && stats.failed > 0;
320
+ const showToast = useCallback((msg) => {
321
+ if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
322
+ setToast(msg);
323
+ toastTimerRef.current = setTimeout(() => setToast(""), 2e3);
324
+ }, []);
325
+ const focus = useCallback((name) => dispatch({
326
+ focused: name,
327
+ type: "focus"
328
+ }), []);
329
+ const keymap = useMemo(() => [
330
+ {
331
+ arrow: "up",
332
+ handler: () => {
333
+ const p = sorted[Math.max(0, focusedIdx - 1)];
334
+ if (p) focus(p.name);
335
+ },
336
+ match: (i) => i === "k"
337
+ },
338
+ {
339
+ arrow: "down",
340
+ handler: () => {
341
+ const p = sorted[Math.min(sorted.length - 1, focusedIdx + 1)];
342
+ if (p) focus(p.name);
343
+ },
344
+ match: (i) => i === "j"
345
+ },
346
+ {
347
+ handler: () => {
348
+ if (sorted[0]) focus(sorted[0].name);
349
+ },
350
+ match: (i) => i === "g"
351
+ },
352
+ {
353
+ handler: () => {
354
+ const last = sorted.at(-1);
355
+ if (last) focus(last.name);
356
+ },
357
+ match: (i) => i === "G"
358
+ },
359
+ {
360
+ handler: () => app.exit(),
361
+ match: (i) => i === "q"
362
+ },
363
+ {
364
+ guard: () => hasFails,
365
+ handler: () => dispatch({
366
+ mkIdle: mkIdleFn,
367
+ projects,
368
+ type: "reset"
369
+ }),
370
+ key: "return"
371
+ },
372
+ {
373
+ guard: () => !hasFails && stats.running === 0,
374
+ handler: () => {
375
+ const p = sorted[focusedIdx];
376
+ if (p && existsSync(p.path)) if (safeSpawn([PKG_NAME, "fix"], p.path)) showToast(`fixing ${p.name}...`);
377
+ else showToast(`${p.name}: spawn failed`);
378
+ else if (p) showToast(`${p.name}: ${p.path} not found`);
379
+ },
380
+ key: "return"
381
+ },
382
+ {
383
+ guard: () => !hasFails && stats.running === 0,
384
+ handler: () => {
385
+ if (safeSpawn([
386
+ PKG_NAME,
387
+ "fix",
388
+ "--all"
389
+ ])) showToast("starting fix --all...");
390
+ else showToast("spawn failed");
391
+ },
392
+ match: (i) => i === "f"
393
+ },
394
+ {
395
+ guard: () => !hasFails && stats.running === 0,
396
+ handler: () => {
397
+ if (safeSpawn([
398
+ PKG_NAME,
399
+ "status",
400
+ "--all"
401
+ ])) showToast("starting status --all...");
402
+ else showToast("spawn failed");
403
+ },
404
+ match: (i) => i === "s"
405
+ }
406
+ ], [
407
+ sorted,
408
+ focusedIdx,
409
+ hasFails,
410
+ stats.running,
411
+ projects,
412
+ app,
413
+ focus,
414
+ showToast
415
+ ]);
416
+ useInput((input, key) => {
417
+ if (key.ctrl && input === "c") {
418
+ app.exit();
419
+ return;
420
+ }
421
+ for (const action of keymap) {
422
+ const arrowMatch = action.arrow === "up" && key.upArrow || action.arrow === "down" && key.downArrow;
423
+ const keyMatch = action.key === "return" && key.return;
424
+ const inputMatch = action.match?.(input);
425
+ if ((arrowMatch || keyMatch || inputMatch) && (!action.guard || action.guard())) {
426
+ action.handler();
427
+ return;
428
+ }
429
+ }
430
+ });
431
+ useEffect(() => {
432
+ const interval = setInterval(() => dispatch({ type: "tick" }), 1e3);
433
+ return () => clearInterval(interval);
434
+ }, []);
435
+ useEffect(() => {
436
+ return onEvent((event) => dispatch({
437
+ event,
438
+ type: "event"
439
+ }));
440
+ }, []);
441
+ useEffect(() => {
442
+ if (state.bellPending) {
443
+ stdout?.write("\x07");
444
+ dispatch({ type: "bell-acked" });
445
+ }
446
+ }, [state.bellPending, stdout]);
447
+ useEffect(() => {
448
+ if (state.phase !== "done" || hasFails) return;
449
+ const timer = setTimeout(() => dispatch({
450
+ mkIdle: mkIdleFn,
451
+ projects,
452
+ type: "reset"
453
+ }), RESET_DELAY);
454
+ return () => clearTimeout(timer);
455
+ }, [
456
+ state.phase,
457
+ hasFails,
458
+ projects
459
+ ]);
460
+ useEffect(() => () => {
461
+ if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
462
+ }, []);
463
+ const totalSteps = projects.length * STEP_COUNT;
464
+ const fraction = totalSteps > 0 ? stats.completedStepCount / totalSteps : 0;
465
+ const pct = Math.round(fraction * 100);
466
+ const sepWidth = Math.max(0, cols - 4);
467
+ return /* @__PURE__ */ jsxs(Box, {
468
+ flexDirection: "column",
469
+ children: [
470
+ /* @__PURE__ */ jsxs(Box, {
471
+ gap: 1,
472
+ marginBottom: 1,
473
+ paddingLeft: 1,
474
+ children: [
475
+ /* @__PURE__ */ jsx(Text, {
476
+ bold: true,
477
+ color: "magenta",
478
+ children: "⚡ pm4ai"
479
+ }),
480
+ /* @__PURE__ */ jsxs(Text, {
481
+ dimColor: true,
482
+ children: [
483
+ "v",
484
+ VERSION,
485
+ " · ",
486
+ projects.length,
487
+ " projects"
488
+ ]
489
+ }),
490
+ state.runCount > 0 ? /* @__PURE__ */ jsxs(Text, {
491
+ dimColor: true,
492
+ children: ["· run #", state.runCount]
493
+ }) : null,
494
+ state.history.length > 1 ? /* @__PURE__ */ jsx(Text, {
495
+ dimColor: true,
496
+ children: sparkline(state.history)
497
+ }) : null
498
+ ]
499
+ }),
500
+ sorted.map((p) => /* @__PURE__ */ jsx(ProjectRow, {
501
+ focused: p.name === state.focused,
502
+ name: p.name,
503
+ pad,
504
+ state: state.projects[p.name] ?? IDLE_FALLBACK
505
+ }, p.name)),
506
+ /* @__PURE__ */ jsx(Box, {
507
+ marginTop: 1,
508
+ paddingLeft: 1,
509
+ children: /* @__PURE__ */ jsx(Text, {
510
+ dimColor: true,
511
+ children: "─".repeat(sepWidth)
512
+ })
513
+ }),
514
+ /* @__PURE__ */ jsx(Box, {
515
+ flexDirection: "column",
516
+ marginTop: 1,
517
+ children: state.phase === "running" ? /* @__PURE__ */ jsx(RunningFooter, {
518
+ barWidth,
519
+ elapsed: state.elapsed,
520
+ eta: stats.eta,
521
+ fraction,
522
+ pct
523
+ }) : state.phase === "done" ? /* @__PURE__ */ jsx(DoneFooter, {
524
+ done: stats.done,
525
+ elapsed: state.elapsed,
526
+ failed: stats.failed,
527
+ history: state.history,
528
+ lastElapsed: state.lastElapsed,
529
+ slowestElapsed: stats.slowestElapsed,
530
+ slowestName: stats.slowestName
531
+ }) : /* @__PURE__ */ jsx(IdleFooter, {
532
+ lastElapsed: state.lastElapsed,
533
+ lastFailed: state.lastFailed,
534
+ lastTime: state.lastTime,
535
+ toast
536
+ })
537
+ })
538
+ ]
539
+ });
540
+ };
541
+ WatchApp.displayName = "WatchApp";
542
+ const watchJson = async () => {
543
+ const ac = new AbortController();
544
+ process.on("SIGINT", () => ac.abort());
545
+ process.on("SIGTERM", () => ac.abort());
546
+ onEvent((event) => {
547
+ if (!ac.signal.aborted) process.stdout.write(`${JSON.stringify(event)}\n`);
548
+ });
549
+ await once(ac.signal, "abort").catch(() => {});
550
+ };
551
+ const watch = async (json = false) => {
552
+ await startEmitter();
553
+ installCleanup();
554
+ if (json) return watchJson();
555
+ const { consumers, self, cnsync } = await discover();
556
+ await render(/* @__PURE__ */ jsx(WatchApp, { projects: (cnsync ? [
557
+ self,
558
+ cnsync,
559
+ ...consumers
560
+ ] : [self, ...consumers]).map((p) => ({
561
+ name: p.name || projectName(p.path),
562
+ path: p.path
563
+ })) })).waitUntilExit();
564
+ };
565
+ //#endregion
566
+ export { watch };