spawn-term 1.1.7 → 2.0.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 (61) hide show
  1. package/dist/cjs/components/App.js +110 -9
  2. package/dist/cjs/components/App.js.map +1 -1
  3. package/dist/cjs/components/CompactProcessLine.js +153 -0
  4. package/dist/cjs/components/CompactProcessLine.js.map +1 -0
  5. package/dist/cjs/components/Divider.js +24 -0
  6. package/dist/cjs/components/Divider.js.map +1 -0
  7. package/dist/cjs/components/ErrorDetailModal.js +115 -0
  8. package/dist/cjs/components/ErrorDetailModal.js.map +1 -0
  9. package/dist/cjs/components/ErrorListModal.js +135 -0
  10. package/dist/cjs/components/ErrorListModal.js.map +1 -0
  11. package/dist/cjs/components/StatusBar.js +104 -0
  12. package/dist/cjs/components/StatusBar.js.map +1 -0
  13. package/dist/cjs/createApp.js +30 -33
  14. package/dist/cjs/createApp.js.map +1 -1
  15. package/dist/cjs/lib/figures.js +1 -1
  16. package/dist/cjs/lib/figures.js.map +1 -1
  17. package/dist/cjs/src/components/App.d.ts +1 -5
  18. package/dist/cjs/src/components/CompactProcessLine.d.ts +6 -0
  19. package/dist/cjs/src/components/Divider.d.ts +2 -0
  20. package/dist/cjs/src/components/ErrorDetailModal.d.ts +8 -0
  21. package/dist/cjs/src/components/ErrorListModal.d.ts +8 -0
  22. package/dist/cjs/src/components/StatusBar.d.ts +8 -0
  23. package/dist/cjs/src/createApp.d.ts +4 -5
  24. package/dist/cjs/src/state/processStore.d.ts +38 -0
  25. package/dist/cjs/state/processStore.js +241 -0
  26. package/dist/cjs/state/processStore.js.map +1 -0
  27. package/dist/cjs/worker.js +70 -108
  28. package/dist/cjs/worker.js.map +1 -1
  29. package/dist/esm/components/App.js +108 -8
  30. package/dist/esm/components/App.js.map +1 -1
  31. package/dist/esm/components/CompactProcessLine.js +134 -0
  32. package/dist/esm/components/CompactProcessLine.js.map +1 -0
  33. package/dist/esm/components/Divider.js +13 -0
  34. package/dist/esm/components/Divider.js.map +1 -0
  35. package/dist/esm/components/ErrorDetailModal.js +99 -0
  36. package/dist/esm/components/ErrorDetailModal.js.map +1 -0
  37. package/dist/esm/components/ErrorListModal.js +116 -0
  38. package/dist/esm/components/ErrorListModal.js.map +1 -0
  39. package/dist/esm/components/StatusBar.js +87 -0
  40. package/dist/esm/components/StatusBar.js.map +1 -0
  41. package/dist/esm/createApp.js +31 -32
  42. package/dist/esm/createApp.js.map +1 -1
  43. package/dist/esm/src/components/App.d.ts +1 -5
  44. package/dist/esm/src/components/CompactProcessLine.d.ts +6 -0
  45. package/dist/esm/src/components/Divider.d.ts +2 -0
  46. package/dist/esm/src/components/ErrorDetailModal.d.ts +8 -0
  47. package/dist/esm/src/components/ErrorListModal.d.ts +8 -0
  48. package/dist/esm/src/components/StatusBar.d.ts +8 -0
  49. package/dist/esm/src/createApp.d.ts +4 -5
  50. package/dist/esm/src/state/processStore.d.ts +38 -0
  51. package/dist/esm/state/processStore.js +149 -0
  52. package/dist/esm/state/processStore.js.map +1 -0
  53. package/dist/esm/worker.js +59 -91
  54. package/dist/esm/worker.js.map +1 -1
  55. package/package.json +1 -2
  56. package/dist/cjs/src/state/Store.d.ts +0 -11
  57. package/dist/cjs/state/Store.js +0 -40
  58. package/dist/cjs/state/Store.js.map +0 -1
  59. package/dist/esm/src/state/Store.d.ts +0 -11
  60. package/dist/esm/state/Store.js +0 -19
  61. package/dist/esm/state/Store.js.map +0 -1
@@ -0,0 +1,99 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text, useStdout } from 'ink';
3
+ import { memo } from 'react';
4
+ import { LineType } from '../types.js';
5
+ export default /*#__PURE__*/ memo(function ErrorDetailModal({ error, currentIndex, totalErrors }) {
6
+ const { stdout } = useStdout();
7
+ const width = (stdout === null || stdout === void 0 ? void 0 : stdout.columns) || 80;
8
+ const borderH = '─'.repeat(width - 2);
9
+ const title = ` Error Detail (${currentIndex + 1}/${totalErrors}) `;
10
+ const titleBorder = `┌${title}${borderH.slice(title.length + 1)}┐`;
11
+ const name = error.group || error.title;
12
+ const stderrLines = error.lines.filter((l)=>l.type === LineType.stderr);
13
+ return /*#__PURE__*/ _jsxs(Box, {
14
+ flexDirection: "column",
15
+ children: [
16
+ /*#__PURE__*/ _jsx(Text, {
17
+ children: titleBorder
18
+ }),
19
+ /*#__PURE__*/ _jsx(Box, {
20
+ paddingX: 1,
21
+ children: /*#__PURE__*/ _jsx(Text, {
22
+ bold: true,
23
+ children: name
24
+ })
25
+ }),
26
+ /*#__PURE__*/ _jsxs(Box, {
27
+ paddingX: 1,
28
+ children: [
29
+ /*#__PURE__*/ _jsx(Text, {
30
+ dimColor: true,
31
+ children: "Command: "
32
+ }),
33
+ /*#__PURE__*/ _jsx(Text, {
34
+ children: error.title
35
+ })
36
+ ]
37
+ }),
38
+ /*#__PURE__*/ _jsx(Box, {
39
+ paddingX: 1,
40
+ children: /*#__PURE__*/ _jsx(Text, {
41
+ dimColor: true,
42
+ children: '─'.repeat(width - 4)
43
+ })
44
+ }),
45
+ /*#__PURE__*/ _jsx(Box, {
46
+ paddingX: 1,
47
+ children: /*#__PURE__*/ _jsx(Text, {
48
+ dimColor: true,
49
+ children: "stderr:"
50
+ })
51
+ }),
52
+ /*#__PURE__*/ _jsx(Box, {
53
+ flexDirection: "column",
54
+ paddingX: 2,
55
+ children: stderrLines.length === 0 ? /*#__PURE__*/ _jsx(Text, {
56
+ dimColor: true,
57
+ children: "(no stderr output)"
58
+ }) : stderrLines.map((line, index)=>/*#__PURE__*/ _jsx(Text, {
59
+ color: "red",
60
+ children: line.text
61
+ }, `stderr-${index}-${line.text.slice(0, 20)}`))
62
+ }),
63
+ /*#__PURE__*/ _jsx(Box, {
64
+ paddingX: 1,
65
+ children: /*#__PURE__*/ _jsx(Text, {
66
+ children: " "
67
+ })
68
+ }),
69
+ /*#__PURE__*/ _jsxs(Text, {
70
+ children: [
71
+ "├",
72
+ borderH,
73
+ "┤"
74
+ ]
75
+ }),
76
+ /*#__PURE__*/ _jsxs(Box, {
77
+ paddingX: 1,
78
+ justifyContent: "space-between",
79
+ children: [
80
+ /*#__PURE__*/ _jsx(Text, {
81
+ dimColor: true,
82
+ children: "[↑↓] prev/next error"
83
+ }),
84
+ /*#__PURE__*/ _jsx(Text, {
85
+ dimColor: true,
86
+ children: "[Esc] back to list"
87
+ })
88
+ ]
89
+ }),
90
+ /*#__PURE__*/ _jsxs(Text, {
91
+ children: [
92
+ "└",
93
+ borderH,
94
+ "┘"
95
+ ]
96
+ })
97
+ ]
98
+ });
99
+ });
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ErrorDetailModal.tsx"],"sourcesContent":["import { Box, Text, useStdout } from 'ink';\nimport { memo } from 'react';\nimport type { ChildProcess } from '../types.ts';\nimport { LineType } from '../types.ts';\n\ntype Props = {\n error: ChildProcess;\n currentIndex: number;\n totalErrors: number;\n};\n\nexport default memo(function ErrorDetailModal({ error, currentIndex, totalErrors }: Props) {\n const { stdout } = useStdout();\n const width = stdout?.columns || 80;\n\n const borderH = '─'.repeat(width - 2);\n const title = ` Error Detail (${currentIndex + 1}/${totalErrors}) `;\n const titleBorder = `┌${title}${borderH.slice(title.length + 1)}┐`;\n\n const name = error.group || error.title;\n const stderrLines = error.lines.filter((l) => l.type === LineType.stderr);\n\n return (\n <Box flexDirection=\"column\">\n {/* Top border with title */}\n <Text>{titleBorder}</Text>\n\n {/* Process name */}\n <Box paddingX={1}>\n <Text bold>{name}</Text>\n </Box>\n\n {/* Command */}\n <Box paddingX={1}>\n <Text dimColor>Command: </Text>\n <Text>{error.title}</Text>\n </Box>\n\n {/* Separator */}\n <Box paddingX={1}>\n <Text dimColor>{'─'.repeat(width - 4)}</Text>\n </Box>\n\n {/* Error output */}\n <Box paddingX={1}>\n <Text dimColor>stderr:</Text>\n </Box>\n\n {/* Error lines in a box */}\n <Box flexDirection=\"column\" paddingX={2}>\n {stderrLines.length === 0 ? (\n <Text dimColor>(no stderr output)</Text>\n ) : (\n stderrLines.map((line, index) => (\n <Text key={`stderr-${index}-${line.text.slice(0, 20)}`} color=\"red\">\n {line.text}\n </Text>\n ))\n )}\n </Box>\n\n {/* Empty line for padding */}\n <Box paddingX={1}>\n <Text> </Text>\n </Box>\n\n {/* Bottom border with hints */}\n <Text>├{borderH}┤</Text>\n <Box paddingX={1} justifyContent=\"space-between\">\n <Text dimColor>[↑↓] prev/next error</Text>\n <Text dimColor>[Esc] back to list</Text>\n </Box>\n <Text>└{borderH}┘</Text>\n </Box>\n );\n});\n"],"names":["Box","Text","useStdout","memo","LineType","ErrorDetailModal","error","currentIndex","totalErrors","stdout","width","columns","borderH","repeat","title","titleBorder","slice","length","name","group","stderrLines","lines","filter","l","type","stderr","flexDirection","paddingX","bold","dimColor","map","line","index","color","text","justifyContent"],"mappings":";AAAA,SAASA,GAAG,EAAEC,IAAI,EAAEC,SAAS,QAAQ,MAAM;AAC3C,SAASC,IAAI,QAAQ,QAAQ;AAE7B,SAASC,QAAQ,QAAQ,cAAc;AAQvC,6BAAeD,KAAK,SAASE,iBAAiB,EAAEC,KAAK,EAAEC,YAAY,EAAEC,WAAW,EAAS;IACvF,MAAM,EAAEC,MAAM,EAAE,GAAGP;IACnB,MAAMQ,QAAQD,CAAAA,mBAAAA,6BAAAA,OAAQE,OAAO,KAAI;IAEjC,MAAMC,UAAU,IAAIC,MAAM,CAACH,QAAQ;IACnC,MAAMI,QAAQ,CAAC,eAAe,EAAEP,eAAe,EAAE,CAAC,EAAEC,YAAY,EAAE,CAAC;IACnE,MAAMO,cAAc,CAAC,CAAC,EAAED,QAAQF,QAAQI,KAAK,CAACF,MAAMG,MAAM,GAAG,GAAG,CAAC,CAAC;IAElE,MAAMC,OAAOZ,MAAMa,KAAK,IAAIb,MAAMQ,KAAK;IACvC,MAAMM,cAAcd,MAAMe,KAAK,CAACC,MAAM,CAAC,CAACC,IAAMA,EAAEC,IAAI,KAAKpB,SAASqB,MAAM;IAExE,qBACE,MAACzB;QAAI0B,eAAc;;0BAEjB,KAACzB;0BAAMc;;0BAGP,KAACf;gBAAI2B,UAAU;0BACb,cAAA,KAAC1B;oBAAK2B,IAAI;8BAAEV;;;0BAId,MAAClB;gBAAI2B,UAAU;;kCACb,KAAC1B;wBAAK4B,QAAQ;kCAAC;;kCACf,KAAC5B;kCAAMK,MAAMQ,KAAK;;;;0BAIpB,KAACd;gBAAI2B,UAAU;0BACb,cAAA,KAAC1B;oBAAK4B,QAAQ;8BAAE,IAAIhB,MAAM,CAACH,QAAQ;;;0BAIrC,KAACV;gBAAI2B,UAAU;0BACb,cAAA,KAAC1B;oBAAK4B,QAAQ;8BAAC;;;0BAIjB,KAAC7B;gBAAI0B,eAAc;gBAASC,UAAU;0BACnCP,YAAYH,MAAM,KAAK,kBACtB,KAAChB;oBAAK4B,QAAQ;8BAAC;qBAEfT,YAAYU,GAAG,CAAC,CAACC,MAAMC,sBACrB,KAAC/B;wBAAuDgC,OAAM;kCAC3DF,KAAKG,IAAI;uBADD,CAAC,OAAO,EAAEF,MAAM,CAAC,EAAED,KAAKG,IAAI,CAAClB,KAAK,CAAC,GAAG,KAAK;;0BAQ5D,KAAChB;gBAAI2B,UAAU;0BACb,cAAA,KAAC1B;8BAAK;;;0BAIR,MAACA;;oBAAK;oBAAEW;oBAAQ;;;0BAChB,MAACZ;gBAAI2B,UAAU;gBAAGQ,gBAAe;;kCAC/B,KAAClC;wBAAK4B,QAAQ;kCAAC;;kCACf,KAAC5B;wBAAK4B,QAAQ;kCAAC;;;;0BAEjB,MAAC5B;;oBAAK;oBAAEW;oBAAQ;;;;;AAGtB,GAAG"}
@@ -0,0 +1,116 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text, useStdout } from 'ink';
3
+ import { memo } from 'react';
4
+ import figures from '../lib/figures.js';
5
+ import { LineType } from '../types.js';
6
+ function truncate(str, maxLength) {
7
+ if (str.length <= maxLength) return str;
8
+ return `${str.slice(0, maxLength - 1)}…`;
9
+ }
10
+ function getErrorLineCount(process) {
11
+ return process.lines.filter((l)=>l.type === LineType.stderr).length;
12
+ }
13
+ export default /*#__PURE__*/ memo(function ErrorListModal({ errors, selectedIndex, totalErrorLines }) {
14
+ const { stdout } = useStdout();
15
+ const width = (stdout === null || stdout === void 0 ? void 0 : stdout.columns) || 80;
16
+ const innerWidth = width - 4; // 2 chars padding each side
17
+ const borderH = '─'.repeat(width - 2);
18
+ const title = ' Errors ';
19
+ const titleBorder = `┌${title}${borderH.slice(title.length + 1)}┐`;
20
+ return /*#__PURE__*/ _jsxs(Box, {
21
+ flexDirection: "column",
22
+ children: [
23
+ /*#__PURE__*/ _jsx(Text, {
24
+ children: titleBorder
25
+ }),
26
+ /*#__PURE__*/ _jsx(Box, {
27
+ paddingX: 1,
28
+ children: /*#__PURE__*/ _jsxs(Text, {
29
+ children: [
30
+ errors.length,
31
+ " process",
32
+ errors.length !== 1 ? 'es' : '',
33
+ " failed (",
34
+ totalErrorLines,
35
+ " error line",
36
+ totalErrorLines !== 1 ? 's' : '',
37
+ " total)"
38
+ ]
39
+ })
40
+ }),
41
+ /*#__PURE__*/ _jsx(Box, {
42
+ paddingX: 1,
43
+ children: /*#__PURE__*/ _jsx(Text, {
44
+ children: " "
45
+ })
46
+ }),
47
+ errors.map((error, index)=>{
48
+ const isSelected = index === selectedIndex;
49
+ const indicator = isSelected ? figures.pointer : ' ';
50
+ const name = error.group || error.title;
51
+ const lineCount = getErrorLineCount(error);
52
+ const lineText = `${lineCount} line${lineCount !== 1 ? 's' : ''}`;
53
+ // Calculate available space for name
54
+ const prefixLen = 3; // indicator + space + space
55
+ const suffixLen = lineText.length + 2; // space + lineText
56
+ const maxNameLen = innerWidth - prefixLen - suffixLen;
57
+ const truncatedName = truncate(name, maxNameLen);
58
+ return /*#__PURE__*/ _jsxs(Box, {
59
+ paddingX: 1,
60
+ children: [
61
+ /*#__PURE__*/ _jsxs(Text, {
62
+ color: isSelected ? 'cyan' : undefined,
63
+ bold: isSelected,
64
+ children: [
65
+ indicator,
66
+ " ",
67
+ truncatedName
68
+ ]
69
+ }),
70
+ /*#__PURE__*/ _jsx(Box, {
71
+ flexGrow: 1
72
+ }),
73
+ /*#__PURE__*/ _jsx(Text, {
74
+ dimColor: true,
75
+ children: lineText
76
+ })
77
+ ]
78
+ }, error.id);
79
+ }),
80
+ /*#__PURE__*/ _jsx(Box, {
81
+ paddingX: 1,
82
+ children: /*#__PURE__*/ _jsx(Text, {
83
+ children: " "
84
+ })
85
+ }),
86
+ /*#__PURE__*/ _jsxs(Text, {
87
+ children: [
88
+ "├",
89
+ borderH,
90
+ "┤"
91
+ ]
92
+ }),
93
+ /*#__PURE__*/ _jsxs(Box, {
94
+ paddingX: 1,
95
+ justifyContent: "space-between",
96
+ children: [
97
+ /*#__PURE__*/ _jsx(Text, {
98
+ dimColor: true,
99
+ children: "[↑↓] navigate [Enter] view details"
100
+ }),
101
+ /*#__PURE__*/ _jsx(Text, {
102
+ dimColor: true,
103
+ children: "[Esc] close"
104
+ })
105
+ ]
106
+ }),
107
+ /*#__PURE__*/ _jsxs(Text, {
108
+ children: [
109
+ "└",
110
+ borderH,
111
+ "┘"
112
+ ]
113
+ })
114
+ ]
115
+ });
116
+ });
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ErrorListModal.tsx"],"sourcesContent":["import { Box, Text, useStdout } from 'ink';\nimport { memo } from 'react';\nimport figures from '../lib/figures.ts';\nimport type { ChildProcess } from '../types.ts';\nimport { LineType } from '../types.ts';\n\ntype Props = {\n errors: ChildProcess[];\n selectedIndex: number;\n totalErrorLines: number;\n};\n\nfunction truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return `${str.slice(0, maxLength - 1)}…`;\n}\n\nfunction getErrorLineCount(process: ChildProcess): number {\n return process.lines.filter((l) => l.type === LineType.stderr).length;\n}\n\nexport default memo(function ErrorListModal({ errors, selectedIndex, totalErrorLines }: Props) {\n const { stdout } = useStdout();\n const width = stdout?.columns || 80;\n const innerWidth = width - 4; // 2 chars padding each side\n\n const borderH = '─'.repeat(width - 2);\n const title = ' Errors ';\n const titleBorder = `┌${title}${borderH.slice(title.length + 1)}┐`;\n\n return (\n <Box flexDirection=\"column\">\n {/* Top border with title */}\n <Text>{titleBorder}</Text>\n\n {/* Summary */}\n <Box paddingX={1}>\n <Text>\n {errors.length} process{errors.length !== 1 ? 'es' : ''} failed ({totalErrorLines} error line\n {totalErrorLines !== 1 ? 's' : ''} total)\n </Text>\n </Box>\n\n {/* Empty line */}\n <Box paddingX={1}>\n <Text> </Text>\n </Box>\n\n {/* Error list */}\n {errors.map((error, index) => {\n const isSelected = index === selectedIndex;\n const indicator = isSelected ? figures.pointer : ' ';\n const name = error.group || error.title;\n const lineCount = getErrorLineCount(error);\n const lineText = `${lineCount} line${lineCount !== 1 ? 's' : ''}`;\n\n // Calculate available space for name\n const prefixLen = 3; // indicator + space + space\n const suffixLen = lineText.length + 2; // space + lineText\n const maxNameLen = innerWidth - prefixLen - suffixLen;\n const truncatedName = truncate(name, maxNameLen);\n\n return (\n <Box key={error.id} paddingX={1}>\n <Text color={isSelected ? 'cyan' : undefined} bold={isSelected}>\n {indicator} {truncatedName}\n </Text>\n <Box flexGrow={1} />\n <Text dimColor>{lineText}</Text>\n </Box>\n );\n })}\n\n {/* Empty line for padding */}\n <Box paddingX={1}>\n <Text> </Text>\n </Box>\n\n {/* Bottom border with hints */}\n <Text>├{borderH}┤</Text>\n <Box paddingX={1} justifyContent=\"space-between\">\n <Text dimColor>[↑↓] navigate [Enter] view details</Text>\n <Text dimColor>[Esc] close</Text>\n </Box>\n <Text>└{borderH}┘</Text>\n </Box>\n );\n});\n"],"names":["Box","Text","useStdout","memo","figures","LineType","truncate","str","maxLength","length","slice","getErrorLineCount","process","lines","filter","l","type","stderr","ErrorListModal","errors","selectedIndex","totalErrorLines","stdout","width","columns","innerWidth","borderH","repeat","title","titleBorder","flexDirection","paddingX","map","error","index","isSelected","indicator","pointer","name","group","lineCount","lineText","prefixLen","suffixLen","maxNameLen","truncatedName","color","undefined","bold","flexGrow","dimColor","id","justifyContent"],"mappings":";AAAA,SAASA,GAAG,EAAEC,IAAI,EAAEC,SAAS,QAAQ,MAAM;AAC3C,SAASC,IAAI,QAAQ,QAAQ;AAC7B,OAAOC,aAAa,oBAAoB;AAExC,SAASC,QAAQ,QAAQ,cAAc;AAQvC,SAASC,SAASC,GAAW,EAAEC,SAAiB;IAC9C,IAAID,IAAIE,MAAM,IAAID,WAAW,OAAOD;IACpC,OAAO,GAAGA,IAAIG,KAAK,CAAC,GAAGF,YAAY,GAAG,CAAC,CAAC;AAC1C;AAEA,SAASG,kBAAkBC,OAAqB;IAC9C,OAAOA,QAAQC,KAAK,CAACC,MAAM,CAAC,CAACC,IAAMA,EAAEC,IAAI,KAAKX,SAASY,MAAM,EAAER,MAAM;AACvE;AAEA,6BAAeN,KAAK,SAASe,eAAe,EAAEC,MAAM,EAAEC,aAAa,EAAEC,eAAe,EAAS;IAC3F,MAAM,EAAEC,MAAM,EAAE,GAAGpB;IACnB,MAAMqB,QAAQD,CAAAA,mBAAAA,6BAAAA,OAAQE,OAAO,KAAI;IACjC,MAAMC,aAAaF,QAAQ,GAAG,4BAA4B;IAE1D,MAAMG,UAAU,IAAIC,MAAM,CAACJ,QAAQ;IACnC,MAAMK,QAAQ;IACd,MAAMC,cAAc,CAAC,CAAC,EAAED,QAAQF,QAAQhB,KAAK,CAACkB,MAAMnB,MAAM,GAAG,GAAG,CAAC,CAAC;IAElE,qBACE,MAACT;QAAI8B,eAAc;;0BAEjB,KAAC7B;0BAAM4B;;0BAGP,KAAC7B;gBAAI+B,UAAU;0BACb,cAAA,MAAC9B;;wBACEkB,OAAOV,MAAM;wBAAC;wBAASU,OAAOV,MAAM,KAAK,IAAI,OAAO;wBAAG;wBAAUY;wBAAgB;wBACjFA,oBAAoB,IAAI,MAAM;wBAAG;;;;0BAKtC,KAACrB;gBAAI+B,UAAU;0BACb,cAAA,KAAC9B;8BAAK;;;YAIPkB,OAAOa,GAAG,CAAC,CAACC,OAAOC;gBAClB,MAAMC,aAAaD,UAAUd;gBAC7B,MAAMgB,YAAYD,aAAa/B,QAAQiC,OAAO,GAAG;gBACjD,MAAMC,OAAOL,MAAMM,KAAK,IAAIN,MAAML,KAAK;gBACvC,MAAMY,YAAY7B,kBAAkBsB;gBACpC,MAAMQ,WAAW,GAAGD,UAAU,KAAK,EAAEA,cAAc,IAAI,MAAM,IAAI;gBAEjE,qCAAqC;gBACrC,MAAME,YAAY,GAAG,4BAA4B;gBACjD,MAAMC,YAAYF,SAAShC,MAAM,GAAG,GAAG,mBAAmB;gBAC1D,MAAMmC,aAAanB,aAAaiB,YAAYC;gBAC5C,MAAME,gBAAgBvC,SAASgC,MAAMM;gBAErC,qBACE,MAAC5C;oBAAmB+B,UAAU;;sCAC5B,MAAC9B;4BAAK6C,OAAOX,aAAa,SAASY;4BAAWC,MAAMb;;gCACjDC;gCAAU;gCAAES;;;sCAEf,KAAC7C;4BAAIiD,UAAU;;sCACf,KAAChD;4BAAKiD,QAAQ;sCAAET;;;mBALRR,MAAMkB,EAAE;YAQtB;0BAGA,KAACnD;gBAAI+B,UAAU;0BACb,cAAA,KAAC9B;8BAAK;;;0BAIR,MAACA;;oBAAK;oBAAEyB;oBAAQ;;;0BAChB,MAAC1B;gBAAI+B,UAAU;gBAAGqB,gBAAe;;kCAC/B,KAACnD;wBAAKiD,QAAQ;kCAAC;;kCACf,KAACjD;wBAAKiD,QAAQ;kCAAC;;;;0BAEjB,MAACjD;;oBAAK;oBAAEyB;oBAAQ;;;;;AAGtB,GAAG"}
@@ -0,0 +1,87 @@
1
+ function _define_property(obj, key, value) {
2
+ if (key in obj) {
3
+ Object.defineProperty(obj, key, {
4
+ value: value,
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true
8
+ });
9
+ } else {
10
+ obj[key] = value;
11
+ }
12
+ return obj;
13
+ }
14
+ function _object_spread(target) {
15
+ for(var i = 1; i < arguments.length; i++){
16
+ var source = arguments[i] != null ? arguments[i] : {};
17
+ var ownKeys = Object.keys(source);
18
+ if (typeof Object.getOwnPropertySymbols === "function") {
19
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
20
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
21
+ }));
22
+ }
23
+ ownKeys.forEach(function(key) {
24
+ _define_property(target, key, source[key]);
25
+ });
26
+ }
27
+ return target;
28
+ }
29
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
30
+ import { Box, Text } from 'ink';
31
+ import { memo } from 'react';
32
+ import figures from '../lib/figures.js';
33
+ import Spinner from './Spinner.js';
34
+ // From: https://github.com/sindresorhus/cli-spinners/blob/00de8fbeee16fa49502fa4f687449f70f2c8ca2c/spinners.json#L2
35
+ const SPINNER = {
36
+ interval: 80,
37
+ frames: [
38
+ '⠋',
39
+ '⠙',
40
+ '⠹',
41
+ '⠸',
42
+ '⠼',
43
+ '⠴',
44
+ '⠦',
45
+ '⠧',
46
+ '⠇',
47
+ '⠏'
48
+ ]
49
+ };
50
+ export default /*#__PURE__*/ memo(function StatusBar({ running, done, errors, errorLines }) {
51
+ return /*#__PURE__*/ _jsxs(Box, {
52
+ justifyContent: "space-between",
53
+ children: [
54
+ /*#__PURE__*/ _jsx(Box, {
55
+ children: /*#__PURE__*/ _jsxs(Text, {
56
+ children: [
57
+ running > 0 ? /*#__PURE__*/ _jsx(Spinner, _object_spread({}, SPINNER)) : /*#__PURE__*/ _jsx(Text, {
58
+ color: "green",
59
+ children: figures.tick
60
+ }),
61
+ ` Running: ${running} `,
62
+ /*#__PURE__*/ _jsx(Text, {
63
+ color: "green",
64
+ children: figures.tick
65
+ }),
66
+ ` Done: ${done} `,
67
+ /*#__PURE__*/ _jsx(Text, {
68
+ color: "red",
69
+ children: figures.cross
70
+ }),
71
+ ` Errors: ${errors}`,
72
+ errorLines > 0 && /*#__PURE__*/ _jsx(Text, {
73
+ dimColor: true,
74
+ children: ` (${errorLines} lines)`
75
+ })
76
+ ]
77
+ })
78
+ }),
79
+ errors > 0 && /*#__PURE__*/ _jsx(Box, {
80
+ children: /*#__PURE__*/ _jsx(Text, {
81
+ dimColor: true,
82
+ children: "[e]rrors"
83
+ })
84
+ })
85
+ ]
86
+ });
87
+ });
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/StatusBar.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo } from 'react';\nimport figures from '../lib/figures.ts';\nimport Spinner from './Spinner.ts';\n\n// From: https://github.com/sindresorhus/cli-spinners/blob/00de8fbeee16fa49502fa4f687449f70f2c8ca2c/spinners.json#L2\nconst SPINNER = {\n interval: 80,\n frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],\n};\n\ntype Props = {\n running: number;\n done: number;\n errors: number;\n errorLines: number;\n};\n\nexport default memo(function StatusBar({ running, done, errors, errorLines }: Props) {\n return (\n <Box justifyContent=\"space-between\">\n <Box>\n <Text>\n {running > 0 ? <Spinner {...SPINNER} /> : <Text color=\"green\">{figures.tick}</Text>}\n {` Running: ${running} `}\n <Text color=\"green\">{figures.tick}</Text>\n {` Done: ${done} `}\n <Text color=\"red\">{figures.cross}</Text>\n {` Errors: ${errors}`}\n {errorLines > 0 && <Text dimColor>{` (${errorLines} lines)`}</Text>}\n </Text>\n </Box>\n {errors > 0 && (\n <Box>\n <Text dimColor>[e]rrors</Text>\n </Box>\n )}\n </Box>\n );\n});\n"],"names":["Box","Text","memo","figures","Spinner","SPINNER","interval","frames","StatusBar","running","done","errors","errorLines","justifyContent","color","tick","cross","dimColor"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAASA,GAAG,EAAEC,IAAI,QAAQ,MAAM;AAChC,SAASC,IAAI,QAAQ,QAAQ;AAC7B,OAAOC,aAAa,oBAAoB;AACxC,OAAOC,aAAa,eAAe;AAEnC,oHAAoH;AACpH,MAAMC,UAAU;IACdC,UAAU;IACVC,QAAQ;QAAC;QAAK;QAAK;QAAK;QAAK;QAAK;QAAK;QAAK;QAAK;QAAK;KAAI;AAC5D;AASA,6BAAeL,KAAK,SAASM,UAAU,EAAEC,OAAO,EAAEC,IAAI,EAAEC,MAAM,EAAEC,UAAU,EAAS;IACjF,qBACE,MAACZ;QAAIa,gBAAe;;0BAClB,KAACb;0BACC,cAAA,MAACC;;wBACEQ,UAAU,kBAAI,KAACL,4BAAYC,0BAAc,KAACJ;4BAAKa,OAAM;sCAASX,QAAQY,IAAI;;wBAC1E,CAAC,UAAU,EAAEN,QAAQ,EAAE,CAAC;sCACzB,KAACR;4BAAKa,OAAM;sCAASX,QAAQY,IAAI;;wBAChC,CAAC,OAAO,EAAEL,KAAK,EAAE,CAAC;sCACnB,KAACT;4BAAKa,OAAM;sCAAOX,QAAQa,KAAK;;wBAC/B,CAAC,SAAS,EAAEL,QAAQ;wBACpBC,aAAa,mBAAK,KAACX;4BAAKgB,QAAQ;sCAAE,CAAC,EAAE,EAAEL,WAAW,OAAO,CAAC;;;;;YAG9DD,SAAS,mBACR,KAACX;0BACC,cAAA,KAACC;oBAAKgB,QAAQ;8BAAC;;;;;AAKzB,GAAG"}
@@ -1,44 +1,43 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { render } from 'ink';
3
- import throttle from 'lodash.throttle';
4
3
  import App from './components/App.js';
5
- import { default as Store } from './state/Store.js';
6
- const THROTTLE = 100;
4
+ import { processStore } from './state/processStore.js';
7
5
  export default function createApp() {
8
6
  let refCount = 0;
9
- let store = null;
10
7
  let inkApp = null;
11
- let previousData = null;
12
- const rerender = throttle(()=>{
13
- if (!inkApp || !store) return;
14
- if (store.data() === previousData) return;
15
- previousData = store.data();
16
- inkApp.rerender(/*#__PURE__*/ _jsx(App, {
17
- store: store
18
- }));
19
- }, THROTTLE, {
20
- leading: false
21
- });
22
8
  return {
23
- retain (fn) {
24
- if (++refCount > 1) return fn(store);
25
- if (store) throw new Error('Not expecting store');
26
- store = new Store(rerender);
27
- inkApp = render(/*#__PURE__*/ _jsx(App, {
28
- store: store
29
- }));
30
- fn(store);
9
+ retain () {
10
+ if (++refCount > 1) return processStore;
11
+ // Render once - React handles all subsequent updates via useSyncExternalStore
12
+ inkApp = render(/*#__PURE__*/ _jsx(App, {}));
13
+ return processStore;
31
14
  },
32
- release (cb) {
33
- if (--refCount > 0) return cb();
34
- if (!store) throw new Error('Expecting store');
35
- rerender.flush();
36
- rerender.cancel();
37
- inkApp.waitUntilExit().then(()=>cb()).catch(cb);
38
- inkApp.unmount();
15
+ release (callback) {
16
+ if (--refCount > 0) {
17
+ callback();
18
+ return;
19
+ }
20
+ if (!inkApp) throw new Error('Expecting inkApp');
21
+ // Defer signalExit to allow React's reconciliation to complete fully
22
+ // Using setImmediate ensures we run after I/O callbacks and microtasks,
23
+ // preventing the Static component from outputting the last item twice
24
+ // (the second notify() from signalExit can race with Static's useLayoutEffect)
25
+ setImmediate(()=>{
26
+ processStore.signalExit(()=>{
27
+ processStore.reset();
28
+ process.stdout.write('\x1b[?25h'); // show cursor
29
+ callback();
30
+ });
31
+ });
32
+ // Wait for Ink to finish, then call the callback
33
+ inkApp.waitUntilExit().then(()=>{
34
+ const cb = processStore.getExitCallback();
35
+ cb === null || cb === void 0 ? void 0 : cb();
36
+ }).catch(()=>{
37
+ const cb = processStore.getExitCallback();
38
+ cb === null || cb === void 0 ? void 0 : cb();
39
+ });
39
40
  inkApp = null;
40
- store = null;
41
- process.stdout.write('\x1b[?25h'); // show cursor
42
41
  }
43
42
  };
44
43
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/createApp.tsx"],"sourcesContent":["import { type Instance, render } from 'ink';\nimport throttle from 'lodash.throttle';\nimport App from './components/App.ts';\nimport { default as Store, type StoreData } from './state/Store.ts';\n\nexport type RetainCallback = (app: Store) => undefined;\nexport type ReleaseCallback = () => undefined;\n\nconst THROTTLE = 100;\n\nexport default function createApp() {\n let refCount = 0;\n let store = null;\n let inkApp: Instance | null = null;\n\n let previousData: StoreData[] = null;\n const rerender = throttle(\n () => {\n if (!inkApp || !store) return;\n if (store.data() === previousData) return;\n previousData = store.data();\n inkApp.rerender(<App store={store} />);\n },\n THROTTLE,\n { leading: false }\n );\n\n return {\n retain(fn: RetainCallback): undefined {\n if (++refCount > 1) return fn(store);\n if (store) throw new Error('Not expecting store');\n\n store = new Store(rerender);\n inkApp = render(<App store={store} />);\n fn(store);\n },\n release(cb: ReleaseCallback): undefined {\n if (--refCount > 0) return cb();\n if (!store) throw new Error('Expecting store');\n\n rerender.flush();\n rerender.cancel();\n inkApp\n .waitUntilExit()\n .then(() => cb())\n .catch(cb);\n inkApp.unmount();\n inkApp = null;\n store = null;\n process.stdout.write('\\x1b[?25h'); // show cursor\n },\n };\n}\n"],"names":["render","throttle","App","default","Store","THROTTLE","createApp","refCount","store","inkApp","previousData","rerender","data","leading","retain","fn","Error","release","cb","flush","cancel","waitUntilExit","then","catch","unmount","process","stdout","write"],"mappings":";AAAA,SAAwBA,MAAM,QAAQ,MAAM;AAC5C,OAAOC,cAAc,kBAAkB;AACvC,OAAOC,SAAS,sBAAsB;AACtC,SAASC,WAAWC,KAAK,QAAwB,mBAAmB;AAKpE,MAAMC,WAAW;AAEjB,eAAe,SAASC;IACtB,IAAIC,WAAW;IACf,IAAIC,QAAQ;IACZ,IAAIC,SAA0B;IAE9B,IAAIC,eAA4B;IAChC,MAAMC,WAAWV,SACf;QACE,IAAI,CAACQ,UAAU,CAACD,OAAO;QACvB,IAAIA,MAAMI,IAAI,OAAOF,cAAc;QACnCA,eAAeF,MAAMI,IAAI;QACzBH,OAAOE,QAAQ,eAAC,KAACT;YAAIM,OAAOA;;IAC9B,GACAH,UACA;QAAEQ,SAAS;IAAM;IAGnB,OAAO;QACLC,QAAOC,EAAkB;YACvB,IAAI,EAAER,WAAW,GAAG,OAAOQ,GAAGP;YAC9B,IAAIA,OAAO,MAAM,IAAIQ,MAAM;YAE3BR,QAAQ,IAAIJ,MAAMO;YAClBF,SAAST,qBAAO,KAACE;gBAAIM,OAAOA;;YAC5BO,GAAGP;QACL;QACAS,SAAQC,EAAmB;YACzB,IAAI,EAAEX,WAAW,GAAG,OAAOW;YAC3B,IAAI,CAACV,OAAO,MAAM,IAAIQ,MAAM;YAE5BL,SAASQ,KAAK;YACdR,SAASS,MAAM;YACfX,OACGY,aAAa,GACbC,IAAI,CAAC,IAAMJ,MACXK,KAAK,CAACL;YACTT,OAAOe,OAAO;YACdf,SAAS;YACTD,QAAQ;YACRiB,QAAQC,MAAM,CAACC,KAAK,CAAC,cAAc,cAAc;QACnD;IACF;AACF"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/createApp.tsx"],"sourcesContent":["import { render } from 'ink';\nimport App from './components/App.ts';\nimport { type ProcessStore, processStore } from './state/processStore.ts';\n\nexport type ReleaseCallback = () => void;\n\nexport default function createApp() {\n let refCount = 0;\n let inkApp: ReturnType<typeof render> | null = null;\n\n return {\n retain(): ProcessStore {\n if (++refCount > 1) return processStore;\n\n // Render once - React handles all subsequent updates via useSyncExternalStore\n inkApp = render(<App />);\n return processStore;\n },\n\n release(callback: ReleaseCallback): void {\n if (--refCount > 0) {\n callback();\n return;\n }\n if (!inkApp) throw new Error('Expecting inkApp');\n\n // Defer signalExit to allow React's reconciliation to complete fully\n // Using setImmediate ensures we run after I/O callbacks and microtasks,\n // preventing the Static component from outputting the last item twice\n // (the second notify() from signalExit can race with Static's useLayoutEffect)\n setImmediate(() => {\n processStore.signalExit(() => {\n processStore.reset();\n process.stdout.write('\\x1b[?25h'); // show cursor\n callback();\n });\n });\n\n // Wait for Ink to finish, then call the callback\n inkApp\n .waitUntilExit()\n .then(() => {\n const cb = processStore.getExitCallback();\n cb?.();\n })\n .catch(() => {\n const cb = processStore.getExitCallback();\n cb?.();\n });\n\n inkApp = null;\n },\n };\n}\n"],"names":["render","App","processStore","createApp","refCount","inkApp","retain","release","callback","Error","setImmediate","signalExit","reset","process","stdout","write","waitUntilExit","then","cb","getExitCallback","catch"],"mappings":";AAAA,SAASA,MAAM,QAAQ,MAAM;AAC7B,OAAOC,SAAS,sBAAsB;AACtC,SAA4BC,YAAY,QAAQ,0BAA0B;AAI1E,eAAe,SAASC;IACtB,IAAIC,WAAW;IACf,IAAIC,SAA2C;IAE/C,OAAO;QACLC;YACE,IAAI,EAAEF,WAAW,GAAG,OAAOF;YAE3B,8EAA8E;YAC9EG,SAASL,qBAAO,KAACC;YACjB,OAAOC;QACT;QAEAK,SAAQC,QAAyB;YAC/B,IAAI,EAAEJ,WAAW,GAAG;gBAClBI;gBACA;YACF;YACA,IAAI,CAACH,QAAQ,MAAM,IAAII,MAAM;YAE7B,qEAAqE;YACrE,wEAAwE;YACxE,sEAAsE;YACtE,+EAA+E;YAC/EC,aAAa;gBACXR,aAAaS,UAAU,CAAC;oBACtBT,aAAaU,KAAK;oBAClBC,QAAQC,MAAM,CAACC,KAAK,CAAC,cAAc,cAAc;oBACjDP;gBACF;YACF;YAEA,iDAAiD;YACjDH,OACGW,aAAa,GACbC,IAAI,CAAC;gBACJ,MAAMC,KAAKhB,aAAaiB,eAAe;gBACvCD,eAAAA,yBAAAA;YACF,GACCE,KAAK,CAAC;gBACL,MAAMF,KAAKhB,aAAaiB,eAAe;gBACvCD,eAAAA,yBAAAA;YACF;YAEFb,SAAS;QACX;IACF;AACF"}
@@ -1,5 +1 @@
1
- import type Store from '../state/Store.js';
2
- export interface AppProps {
3
- store: Store;
4
- }
5
- export default function App({ store }: AppProps): React.JSX.Element;
1
+ export default function App(): React.JSX.Element;
@@ -0,0 +1,6 @@
1
+ import type { ChildProcess } from '../types.js';
2
+ type Props = {
3
+ item: ChildProcess;
4
+ };
5
+ declare const _default: import("react").NamedExoticComponent<Props>;
6
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("react").NamedExoticComponent<object>;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import type { ChildProcess } from '../types.js';
2
+ type Props = {
3
+ error: ChildProcess;
4
+ currentIndex: number;
5
+ totalErrors: number;
6
+ };
7
+ declare const _default: import("react").NamedExoticComponent<Props>;
8
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import type { ChildProcess } from '../types.js';
2
+ type Props = {
3
+ errors: ChildProcess[];
4
+ selectedIndex: number;
5
+ totalErrorLines: number;
6
+ };
7
+ declare const _default: import("react").NamedExoticComponent<Props>;
8
+ export default _default;
@@ -0,0 +1,8 @@
1
+ type Props = {
2
+ running: number;
3
+ done: number;
4
+ errors: number;
5
+ errorLines: number;
6
+ };
7
+ declare const _default: import("react").NamedExoticComponent<Props>;
8
+ export default _default;
@@ -1,7 +1,6 @@
1
- import { default as Store } from './state/Store.js';
2
- export type RetainCallback = (app: Store) => undefined;
3
- export type ReleaseCallback = () => undefined;
1
+ import { type ProcessStore } from './state/processStore.js';
2
+ export type ReleaseCallback = () => void;
4
3
  export default function createApp(): {
5
- retain(fn: RetainCallback): undefined;
6
- release(cb: ReleaseCallback): undefined;
4
+ retain(): ProcessStore;
5
+ release(callback: ReleaseCallback): void;
7
6
  };
@@ -0,0 +1,38 @@
1
+ import type { ChildProcess, Line } from '../types.js';
2
+ type Listener = () => void;
3
+ type Mode = 'normal' | 'errorList' | 'errorDetail';
4
+ declare class ProcessStore {
5
+ private processes;
6
+ private completedIds;
7
+ private listeners;
8
+ private shouldExit;
9
+ private exitCallback;
10
+ private mode;
11
+ private selectedErrorIndex;
12
+ subscribe: (listener: Listener) => (() => void);
13
+ getSnapshot: () => ChildProcess[];
14
+ getRunningProcesses: () => ChildProcess[];
15
+ getCompletedProcesses: () => ChildProcess[];
16
+ getFailedProcesses: () => ChildProcess[];
17
+ getRunningCount: () => number;
18
+ getDoneCount: () => number;
19
+ getErrorCount: () => number;
20
+ getErrorLineCount: () => number;
21
+ getMode: () => Mode;
22
+ getSelectedErrorIndex: () => number;
23
+ addProcess(process: ChildProcess): void;
24
+ updateProcess(id: string, update: Partial<ChildProcess>): void;
25
+ appendLines(id: string, newLines: Line[]): void;
26
+ getProcess(id: string): ChildProcess | undefined;
27
+ setMode(mode: Mode): void;
28
+ selectNextError(): void;
29
+ selectPrevError(): void;
30
+ getSelectedError(): ChildProcess | undefined;
31
+ signalExit(callback: () => void): void;
32
+ getShouldExit: () => boolean;
33
+ getExitCallback: () => (() => void) | null;
34
+ reset(): void;
35
+ private notify;
36
+ }
37
+ export declare const processStore: ProcessStore;
38
+ export type { ProcessStore };