spawn-term 3.3.4 → 3.3.6
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.
- package/dist/cjs/compat.js +1 -1
- package/dist/cjs/components/App.js +1 -1
- package/dist/cjs/components/ChildProcess.js +1 -1
- package/dist/cjs/components/CompactProcessLine.js +1 -1
- package/dist/cjs/components/Divider.js +1 -1
- package/dist/cjs/components/ErrorFooter.js +1 -1
- package/dist/cjs/components/ExpandedOutput.js +1 -1
- package/dist/cjs/components/FullscreenOverlay.js +1 -1
- package/dist/cjs/components/Spinner.js +1 -1
- package/dist/cjs/components/StatusBar.js +1 -1
- package/dist/cjs/constants.js +1 -1
- package/dist/cjs/createSessionWrapper.js +1 -1
- package/dist/cjs/index-cjs.js +1 -1
- package/dist/cjs/index-esm.js +1 -1
- package/dist/cjs/lib/TerminalBuffer.js +1 -1
- package/dist/cjs/lib/addLines.js +1 -1
- package/dist/cjs/lib/addLines.js.map +1 -1
- package/dist/cjs/lib/ansiRegex.js +1 -1
- package/dist/cjs/lib/clipText.js +1 -1
- package/dist/cjs/lib/concatWritable.js +1 -1
- package/dist/cjs/lib/concatWritable.js.map +1 -1
- package/dist/cjs/lib/figures.js +1 -1
- package/dist/cjs/lib/format.js +1 -1
- package/dist/cjs/lib/formatArguments.js +1 -1
- package/dist/cjs/lib/loadInk.js +3 -3
- package/dist/cjs/lib/loadInk.js.map +1 -1
- package/dist/cjs/session.js +19 -10
- package/dist/cjs/session.js.map +1 -1
- package/dist/cjs/src/lib/addLines.d.ts +1 -1
- package/dist/cjs/src/lib/concatWritable.d.ts +1 -1
- package/dist/cjs/state/Navigator.js +1 -1
- package/dist/cjs/state/StoreContext.js +1 -1
- package/dist/cjs/state/processStore.js +4 -5
- package/dist/cjs/state/processStore.js.map +1 -1
- package/dist/cjs/types.js +1 -1
- package/dist/esm/lib/addLines.js.map +1 -1
- package/dist/esm/lib/concatWritable.js.map +1 -1
- package/dist/esm/session.js +1 -1
- package/dist/esm/session.js.map +1 -1
- package/dist/esm/src/lib/addLines.d.ts +1 -1
- package/dist/esm/src/lib/concatWritable.d.ts +1 -1
- package/dist/esm/state/processStore.js +3 -4
- package/dist/esm/state/processStore.js.map +1 -1
- package/package.json +12 -12
package/dist/cjs/compat.js
CHANGED
|
@@ -45,4 +45,4 @@ function arrayFind(arr, predicate) {
|
|
|
45
45
|
}
|
|
46
46
|
return undefined;
|
|
47
47
|
}
|
|
48
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
48
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -379,4 +379,4 @@ function App(param) {
|
|
|
379
379
|
})
|
|
380
380
|
});
|
|
381
381
|
}
|
|
382
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
382
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -168,4 +168,4 @@ var _default = /*#__PURE__*/ (0, _react.memo)(function ChildProcess(param) {
|
|
|
168
168
|
item: item
|
|
169
169
|
});
|
|
170
170
|
});
|
|
171
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
171
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -151,4 +151,4 @@ var _default = /*#__PURE__*/ (0, _react.memo)(function CompactProcessLine(param)
|
|
|
151
151
|
]
|
|
152
152
|
});
|
|
153
153
|
});
|
|
154
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
154
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -21,4 +21,4 @@ var _default = /*#__PURE__*/ (0, _react.memo)(function Divider() {
|
|
|
21
21
|
})
|
|
22
22
|
});
|
|
23
23
|
});
|
|
24
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
24
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -109,4 +109,4 @@ var _default = /*#__PURE__*/ (0, _react.memo)(function ErrorFooter(param) {
|
|
|
109
109
|
]
|
|
110
110
|
});
|
|
111
111
|
});
|
|
112
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
112
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -56,4 +56,4 @@ var _default = /*#__PURE__*/ (0, _react.memo)(function ExpandedOutput(param) {
|
|
|
56
56
|
]
|
|
57
57
|
});
|
|
58
58
|
});
|
|
59
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
59
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -90,4 +90,4 @@ var _default = /*#__PURE__*/ (0, _react.memo)(function FullscreenOverlay(param)
|
|
|
90
90
|
]
|
|
91
91
|
});
|
|
92
92
|
});
|
|
93
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
93
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -77,4 +77,4 @@ function Spinner(param) {
|
|
|
77
77
|
children: "".concat(frames[index], " ")
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
80
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -75,4 +75,4 @@ var _default = /*#__PURE__*/ (0, _react.memo)(function StatusBar(param) {
|
|
|
75
75
|
})
|
|
76
76
|
});
|
|
77
77
|
});
|
|
78
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
78
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
package/dist/cjs/constants.js
CHANGED
|
@@ -57,4 +57,4 @@ var SPINNER = {
|
|
|
57
57
|
'⠏'
|
|
58
58
|
]
|
|
59
59
|
};
|
|
60
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
60
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -108,4 +108,4 @@ function createSession(options) {
|
|
|
108
108
|
}
|
|
109
109
|
};
|
|
110
110
|
}
|
|
111
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
111
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
package/dist/cjs/index-cjs.js
CHANGED
|
@@ -41,4 +41,4 @@ function _interop_require_default(obj) {
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
var createSession = undefined;
|
|
44
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
44
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
package/dist/cjs/index-esm.js
CHANGED
|
@@ -43,4 +43,4 @@ function _interop_require_default(obj) {
|
|
|
43
43
|
}
|
|
44
44
|
var major = +process.versions.node.split('.')[0];
|
|
45
45
|
var createSession = major > 18 ? _createSessionWrapperts.createSession : undefined;
|
|
46
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
46
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -276,4 +276,4 @@ var TerminalBuffer = /*#__PURE__*/ function() {
|
|
|
276
276
|
]);
|
|
277
277
|
return TerminalBuffer;
|
|
278
278
|
}();
|
|
279
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
279
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
package/dist/cjs/lib/addLines.js
CHANGED
|
@@ -83,4 +83,4 @@ function addLines(fn) {
|
|
|
83
83
|
});
|
|
84
84
|
return stream;
|
|
85
85
|
}
|
|
86
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
86
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/addLines.ts"],"sourcesContent":["import { Writable } from 'stream';\nimport { BATCH_MAX_LINES, BATCH_MAX_WAIT_MS } from '../constants.ts';\n\nconst REGEX_NEW_LINE = /\\r?\\n|\\r/g;\n\nexport type Callback = (lines: string[]) =>
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/addLines.ts"],"sourcesContent":["import { Writable } from 'stream';\nimport { BATCH_MAX_LINES, BATCH_MAX_WAIT_MS } from '../constants.ts';\n\nconst REGEX_NEW_LINE = /\\r?\\n|\\r/g;\n\nexport type Callback = (lines: string[]) => void;\n\ninterface BatchOptions {\n maxLines?: number;\n maxWait?: number;\n}\n\nexport default function addLines(fn: Callback, options: BatchOptions = {}): Writable {\n const { maxLines = BATCH_MAX_LINES, maxWait = BATCH_MAX_WAIT_MS } = options;\n\n let last = '';\n let lineBuffer: string[] = [];\n let flushTimer: NodeJS.Timeout | null = null;\n\n const flush = () => {\n if (flushTimer) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n if (lineBuffer.length > 0) {\n fn(lineBuffer);\n lineBuffer = [];\n }\n };\n\n const scheduleFlush = () => {\n if (!flushTimer) {\n flushTimer = setTimeout(flush, maxWait);\n }\n };\n\n const stream = new Writable({\n write(chunk, _enc, callback) {\n const more = last + chunk.toString('utf8');\n const lines = more.split(REGEX_NEW_LINE);\n last = lines.pop();\n\n if (lines.length > 0) {\n lineBuffer.push(...lines);\n\n // Flush immediately if buffer is large enough\n if (lineBuffer.length >= maxLines) {\n flush();\n } else {\n scheduleFlush();\n }\n }\n callback();\n },\n });\n\n stream.on('finish', () => {\n // Flush any remaining buffered lines\n if (last.length) lineBuffer.push(last);\n flush();\n last = '';\n });\n\n return stream;\n}\n"],"names":["addLines","REGEX_NEW_LINE","fn","options","maxLines","BATCH_MAX_LINES","maxWait","BATCH_MAX_WAIT_MS","last","lineBuffer","flushTimer","flush","clearTimeout","length","scheduleFlush","setTimeout","stream","Writable","write","chunk","_enc","callback","more","toString","lines","split","pop","push","on"],"mappings":";;;;+BAYA;;;eAAwBA;;;sBAZC;2BAC0B;;;;;;;;;;;;;;;;;;;;;;;;;;AAEnD,IAAMC,iBAAiB;AASR,SAASD,SAASE,EAAY;QAAEC,UAAAA,iEAAwB,CAAC;IACtE,wBAAoEA,QAA5DC,UAAAA,0CAAWC,4BAAe,yCAAkCF,QAAhCG,SAAAA,wCAAUC,8BAAiB;IAE/D,IAAIC,OAAO;IACX,IAAIC,aAAuB,EAAE;IAC7B,IAAIC,aAAoC;IAExC,IAAMC,QAAQ;QACZ,IAAID,YAAY;YACdE,aAAaF;YACbA,aAAa;QACf;QACA,IAAID,WAAWI,MAAM,GAAG,GAAG;YACzBX,GAAGO;YACHA,aAAa,EAAE;QACjB;IACF;IAEA,IAAMK,gBAAgB;QACpB,IAAI,CAACJ,YAAY;YACfA,aAAaK,WAAWJ,OAAOL;QACjC;IACF;IAEA,IAAMU,SAAS,IAAIC,gBAAQ,CAAC;QAC1BC,OAAAA,SAAAA,MAAMC,KAAK,EAAEC,IAAI,EAAEC,QAAQ;YACzB,IAAMC,OAAOd,OAAOW,MAAMI,QAAQ,CAAC;YACnC,IAAMC,QAAQF,KAAKG,KAAK,CAACxB;YACzBO,OAAOgB,MAAME,GAAG;YAEhB,IAAIF,MAAMX,MAAM,GAAG,GAAG;oBACpBJ;gBAAAA,CAAAA,cAAAA,YAAWkB,IAAI,OAAflB,aAAgB,qBAAGe;gBAEnB,8CAA8C;gBAC9C,IAAIf,WAAWI,MAAM,IAAIT,UAAU;oBACjCO;gBACF,OAAO;oBACLG;gBACF;YACF;YACAO;QACF;IACF;IAEAL,OAAOY,EAAE,CAAC,UAAU;QAClB,qCAAqC;QACrC,IAAIpB,KAAKK,MAAM,EAAEJ,WAAWkB,IAAI,CAACnB;QACjCG;QACAH,OAAO;IACT;IAEA,OAAOQ;AACT"}
|
|
@@ -19,4 +19,4 @@ function ansiRegex() {
|
|
|
19
19
|
].join('|');
|
|
20
20
|
return new RegExp(pattern, onlyFirst ? undefined : 'g');
|
|
21
21
|
}
|
|
22
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
22
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
package/dist/cjs/lib/clipText.js
CHANGED
|
@@ -53,4 +53,4 @@ function clipText(str, maxWidth) {
|
|
|
53
53
|
}
|
|
54
54
|
return "".concat(result, "…");
|
|
55
55
|
}
|
|
56
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
56
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -28,4 +28,4 @@ function concatWritable(callback) {
|
|
|
28
28
|
});
|
|
29
29
|
return stream;
|
|
30
30
|
}
|
|
31
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
31
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/concatWritable.ts"],"sourcesContent":["import Stream from 'stream';\n\nconst Writable = Stream.Writable;\n\nexport type Callback = (lines: Buffer) =>
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/concatWritable.ts"],"sourcesContent":["import Stream from 'stream';\n\nconst Writable = Stream.Writable;\n\nexport type Callback = (lines: Buffer) => void;\n\nexport default function concatWritable(callback: Callback): NodeJS.WritableStream {\n const chunks = [];\n const stream = new Writable({\n write: (chunk, _encoding, next) => {\n chunks.push(chunk);\n next();\n },\n });\n stream.on('finish', () => callback(Buffer.concat(chunks.splice(0))));\n return stream;\n}\n"],"names":["concatWritable","Writable","Stream","callback","chunks","stream","write","chunk","_encoding","next","push","on","Buffer","concat","splice"],"mappings":";;;;+BAMA;;;eAAwBA;;;6DANL;;;;;;AAEnB,IAAMC,WAAWC,eAAM,CAACD,QAAQ;AAIjB,SAASD,eAAeG,QAAkB;IACvD,IAAMC,SAAS,EAAE;IACjB,IAAMC,SAAS,IAAIJ,SAAS;QAC1BK,OAAO,SAACC,OAAOC,WAAWC;YACxBL,OAAOM,IAAI,CAACH;YACZE;QACF;IACF;IACAJ,OAAOM,EAAE,CAAC,UAAU;eAAMR,SAASS,OAAOC,MAAM,CAACT,OAAOU,MAAM,CAAC;;IAC/D,OAAOT;AACT"}
|
package/dist/cjs/lib/figures.js
CHANGED
|
@@ -40,4 +40,4 @@ var fallbackSymbols = {
|
|
|
40
40
|
pointer: '>'
|
|
41
41
|
};
|
|
42
42
|
var _default = isUnicodeSupported() ? symbols : fallbackSymbols;
|
|
43
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
43
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
package/dist/cjs/lib/format.js
CHANGED
|
@@ -19,4 +19,4 @@ function calculateColumnWidth(groupWidth, terminalWidth, maxGroupLength) {
|
|
|
19
19
|
}
|
|
20
20
|
return _constantsts.FALLBACK_COLUMN_WIDTH;
|
|
21
21
|
}
|
|
22
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
22
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -13,4 +13,4 @@ var _default = function(args) {
|
|
|
13
13
|
return /\s/.test(text) ? '"'.concat(text, '"') : text;
|
|
14
14
|
});
|
|
15
15
|
};
|
|
16
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
16
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
package/dist/cjs/lib/loadInk.js
CHANGED
|
@@ -63,13 +63,13 @@ function symlinkReactFromInk() {
|
|
|
63
63
|
// It's a real directory (e.g. from devDependencies) - leave it alone
|
|
64
64
|
return resolve();
|
|
65
65
|
}
|
|
66
|
-
} catch (
|
|
66
|
+
} catch (unused) {
|
|
67
67
|
// Doesn't exist, continue to create symlink
|
|
68
68
|
}
|
|
69
69
|
// Create symlink to ink's react
|
|
70
70
|
try {
|
|
71
71
|
_fs.default.symlinkSync(inkReactPath, reactPath);
|
|
72
|
-
} catch (
|
|
72
|
+
} catch (unused) {
|
|
73
73
|
// Ignore errors - react may have been installed another way
|
|
74
74
|
}
|
|
75
75
|
resolve();
|
|
@@ -100,4 +100,4 @@ function loadInk(callback) {
|
|
|
100
100
|
function isInkInstalled() {
|
|
101
101
|
return installed;
|
|
102
102
|
}
|
|
103
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
103
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/loadInk.ts"],"sourcesContent":["import fs from 'fs';\nimport installModule from 'install-module-linked';\nimport path from 'path';\nimport url from 'url';\n\n// Get the node_modules directory relative to this file\nconst _dirname = path.dirname(typeof __dirname !== 'undefined' ? __dirname : url.fileURLToPath(import.meta.url));\nconst nodeModules = path.join(_dirname, '..', '..', '..', 'node_modules');\n\nlet installed = false;\nlet installing: Promise<void> | null = null;\n\nfunction installDependency(name: string): Promise<void> {\n return new Promise((resolve, reject) => {\n // install-module-linked will:\n // 1. Check if module exists locally or in ~/.iml cache\n // 2. If not, install to ~/.iml\n // 3. Create symlink in nodeModules pointing to ~/.iml/package\n installModule(name, nodeModules, {}, (err) => {\n if (err) return reject(err);\n resolve();\n });\n });\n}\n\nfunction symlinkReactFromInk(): Promise<void> {\n return new Promise((resolve) => {\n // After ink is installed, symlink react to ink's react to avoid duplicate React instances\n const inkPath = fs.realpathSync(path.join(nodeModules, 'ink'));\n const inkReactPath = path.join(inkPath, 'node_modules', 'react');\n const reactPath = path.join(nodeModules, 'react');\n\n // Check if react already exists\n try {\n const stat = fs.lstatSync(reactPath);\n if (stat.isSymbolicLink()) {\n // It's a symlink - check if it points to the right place\n const existing = fs.readlinkSync(reactPath);\n if (existing === inkReactPath) {\n return resolve(); // Already correct\n }\n // Wrong symlink, remove it\n fs.unlinkSync(reactPath);\n } else {\n // It's a real directory (e.g. from devDependencies) - leave it alone\n return resolve();\n }\n } catch {\n // Doesn't exist, continue to create symlink\n }\n\n // Create symlink to ink's react\n try {\n fs.symlinkSync(inkReactPath, reactPath);\n } catch {\n // Ignore errors - react may have been installed another way\n }\n resolve();\n });\n}\n\nfunction installInk(): Promise<void> {\n if (installed) return Promise.resolve();\n if (installing) return installing;\n\n // Install ink, then symlink react to ink's bundled react\n // This ensures session.tsx and ink use the SAME React instance\n installing = installDependency('ink')\n .then(() => symlinkReactFromInk())\n .then(() => {\n installed = true;\n })\n .catch((err) => {\n installing = null;\n throw err;\n });\n\n return installing;\n}\n\nexport function loadInk(callback: (err: Error | null) => void): void {\n installInk()\n .then(() => callback(null))\n .catch((err) => callback(err));\n}\n\nexport function isInkInstalled(): boolean {\n return installed;\n}\n"],"names":["isInkInstalled","loadInk","_dirname","path","dirname","__dirname","url","fileURLToPath","nodeModules","join","installed","installing","installDependency","name","Promise","resolve","reject","installModule","err","symlinkReactFromInk","inkPath","fs","realpathSync","inkReactPath","reactPath","stat","lstatSync","isSymbolicLink","existing","readlinkSync","unlinkSync","symlinkSync","installInk","then","catch","callback"],"mappings":";;;;;;;;;;;QAsFgBA;eAAAA;;QANAC;eAAAA;;;yDAhFD;0EACW;2DACT;0DACD;;;;;;AAEhB,uDAAuD;AACvD,IAAMC,WAAWC,aAAI,CAACC,OAAO,CAAC,OAAOC,cAAc,cAAcA,YAAYC,YAAG,CAACC,aAAa,CAAC;AAC/F,IAAMC,cAAcL,aAAI,CAACM,IAAI,CAACP,UAAU,MAAM,MAAM,MAAM;AAE1D,IAAIQ,YAAY;AAChB,IAAIC,aAAmC;AAEvC,SAASC,kBAAkBC,IAAY;IACrC,OAAO,IAAIC,QAAQ,SAACC,SAASC;QAC3B,8BAA8B;QAC9B,uDAAuD;QACvD,+BAA+B;QAC/B,8DAA8D;QAC9DC,IAAAA,4BAAa,EAACJ,MAAML,aAAa,CAAC,GAAG,SAACU;YACpC,IAAIA,KAAK,OAAOF,OAAOE;YACvBH;QACF;IACF;AACF;AAEA,SAASI;IACP,OAAO,IAAIL,QAAQ,SAACC;QAClB,0FAA0F;QAC1F,IAAMK,UAAUC,WAAE,CAACC,YAAY,CAACnB,aAAI,CAACM,IAAI,CAACD,aAAa;QACvD,IAAMe,eAAepB,aAAI,CAACM,IAAI,CAACW,SAAS,gBAAgB;QACxD,IAAMI,YAAYrB,aAAI,CAACM,IAAI,CAACD,aAAa;QAEzC,gCAAgC;QAChC,IAAI;YACF,IAAMiB,OAAOJ,WAAE,CAACK,SAAS,CAACF;YAC1B,IAAIC,KAAKE,cAAc,IAAI;gBACzB,yDAAyD;gBACzD,IAAMC,WAAWP,WAAE,CAACQ,YAAY,CAACL;gBACjC,IAAII,aAAaL,cAAc;oBAC7B,OAAOR,WAAW,kBAAkB;gBACtC;gBACA,2BAA2B;gBAC3BM,WAAE,CAACS,UAAU,CAACN;YAChB,OAAO;gBACL,qEAAqE;gBACrE,OAAOT;YACT;QACF,EAAE,
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/loadInk.ts"],"sourcesContent":["import fs from 'fs';\nimport installModule from 'install-module-linked';\nimport path from 'path';\nimport url from 'url';\n\n// Get the node_modules directory relative to this file\nconst _dirname = path.dirname(typeof __dirname !== 'undefined' ? __dirname : url.fileURLToPath(import.meta.url));\nconst nodeModules = path.join(_dirname, '..', '..', '..', 'node_modules');\n\nlet installed = false;\nlet installing: Promise<void> | null = null;\n\nfunction installDependency(name: string): Promise<void> {\n return new Promise((resolve, reject) => {\n // install-module-linked will:\n // 1. Check if module exists locally or in ~/.iml cache\n // 2. If not, install to ~/.iml\n // 3. Create symlink in nodeModules pointing to ~/.iml/package\n installModule(name, nodeModules, {}, (err) => {\n if (err) return reject(err);\n resolve();\n });\n });\n}\n\nfunction symlinkReactFromInk(): Promise<void> {\n return new Promise((resolve) => {\n // After ink is installed, symlink react to ink's react to avoid duplicate React instances\n const inkPath = fs.realpathSync(path.join(nodeModules, 'ink'));\n const inkReactPath = path.join(inkPath, 'node_modules', 'react');\n const reactPath = path.join(nodeModules, 'react');\n\n // Check if react already exists\n try {\n const stat = fs.lstatSync(reactPath);\n if (stat.isSymbolicLink()) {\n // It's a symlink - check if it points to the right place\n const existing = fs.readlinkSync(reactPath);\n if (existing === inkReactPath) {\n return resolve(); // Already correct\n }\n // Wrong symlink, remove it\n fs.unlinkSync(reactPath);\n } else {\n // It's a real directory (e.g. from devDependencies) - leave it alone\n return resolve();\n }\n } catch {\n // Doesn't exist, continue to create symlink\n }\n\n // Create symlink to ink's react\n try {\n fs.symlinkSync(inkReactPath, reactPath);\n } catch {\n // Ignore errors - react may have been installed another way\n }\n resolve();\n });\n}\n\nfunction installInk(): Promise<void> {\n if (installed) return Promise.resolve();\n if (installing) return installing;\n\n // Install ink, then symlink react to ink's bundled react\n // This ensures session.tsx and ink use the SAME React instance\n installing = installDependency('ink')\n .then(() => symlinkReactFromInk())\n .then(() => {\n installed = true;\n })\n .catch((err) => {\n installing = null;\n throw err;\n });\n\n return installing;\n}\n\nexport function loadInk(callback: (err: Error | null) => void): void {\n installInk()\n .then(() => callback(null))\n .catch((err) => callback(err));\n}\n\nexport function isInkInstalled(): boolean {\n return installed;\n}\n"],"names":["isInkInstalled","loadInk","_dirname","path","dirname","__dirname","url","fileURLToPath","nodeModules","join","installed","installing","installDependency","name","Promise","resolve","reject","installModule","err","symlinkReactFromInk","inkPath","fs","realpathSync","inkReactPath","reactPath","stat","lstatSync","isSymbolicLink","existing","readlinkSync","unlinkSync","symlinkSync","installInk","then","catch","callback"],"mappings":";;;;;;;;;;;QAsFgBA;eAAAA;;QANAC;eAAAA;;;yDAhFD;0EACW;2DACT;0DACD;;;;;;AAEhB,uDAAuD;AACvD,IAAMC,WAAWC,aAAI,CAACC,OAAO,CAAC,OAAOC,cAAc,cAAcA,YAAYC,YAAG,CAACC,aAAa,CAAC;AAC/F,IAAMC,cAAcL,aAAI,CAACM,IAAI,CAACP,UAAU,MAAM,MAAM,MAAM;AAE1D,IAAIQ,YAAY;AAChB,IAAIC,aAAmC;AAEvC,SAASC,kBAAkBC,IAAY;IACrC,OAAO,IAAIC,QAAQ,SAACC,SAASC;QAC3B,8BAA8B;QAC9B,uDAAuD;QACvD,+BAA+B;QAC/B,8DAA8D;QAC9DC,IAAAA,4BAAa,EAACJ,MAAML,aAAa,CAAC,GAAG,SAACU;YACpC,IAAIA,KAAK,OAAOF,OAAOE;YACvBH;QACF;IACF;AACF;AAEA,SAASI;IACP,OAAO,IAAIL,QAAQ,SAACC;QAClB,0FAA0F;QAC1F,IAAMK,UAAUC,WAAE,CAACC,YAAY,CAACnB,aAAI,CAACM,IAAI,CAACD,aAAa;QACvD,IAAMe,eAAepB,aAAI,CAACM,IAAI,CAACW,SAAS,gBAAgB;QACxD,IAAMI,YAAYrB,aAAI,CAACM,IAAI,CAACD,aAAa;QAEzC,gCAAgC;QAChC,IAAI;YACF,IAAMiB,OAAOJ,WAAE,CAACK,SAAS,CAACF;YAC1B,IAAIC,KAAKE,cAAc,IAAI;gBACzB,yDAAyD;gBACzD,IAAMC,WAAWP,WAAE,CAACQ,YAAY,CAACL;gBACjC,IAAII,aAAaL,cAAc;oBAC7B,OAAOR,WAAW,kBAAkB;gBACtC;gBACA,2BAA2B;gBAC3BM,WAAE,CAACS,UAAU,CAACN;YAChB,OAAO;gBACL,qEAAqE;gBACrE,OAAOT;YACT;QACF,EAAE,eAAM;QACN,4CAA4C;QAC9C;QAEA,gCAAgC;QAChC,IAAI;YACFM,WAAE,CAACU,WAAW,CAACR,cAAcC;QAC/B,EAAE,eAAM;QACN,4DAA4D;QAC9D;QACAT;IACF;AACF;AAEA,SAASiB;IACP,IAAItB,WAAW,OAAOI,QAAQC,OAAO;IACrC,IAAIJ,YAAY,OAAOA;IAEvB,yDAAyD;IACzD,+DAA+D;IAC/DA,aAAaC,kBAAkB,OAC5BqB,IAAI,CAAC;eAAMd;OACXc,IAAI,CAAC;QACJvB,YAAY;IACd,GACCwB,KAAK,CAAC,SAAChB;QACNP,aAAa;QACb,MAAMO;IACR;IAEF,OAAOP;AACT;AAEO,SAASV,QAAQkC,QAAqC;IAC3DH,aACGC,IAAI,CAAC;eAAME,SAAS;OACpBD,KAAK,CAAC,SAAChB;eAAQiB,SAASjB;;AAC7B;AAEO,SAASlB;IACd,OAAOU;AACT"}
|
package/dist/cjs/session.js
CHANGED
|
@@ -125,12 +125,22 @@ function _object_spread_props(target, source) {
|
|
|
125
125
|
}
|
|
126
126
|
function _object_without_properties(source, excluded) {
|
|
127
127
|
if (source == null) return {};
|
|
128
|
-
var target =
|
|
129
|
-
|
|
128
|
+
var target = {}, sourceKeys, key, i;
|
|
129
|
+
if (typeof Reflect !== "undefined" && Reflect.ownKeys) {
|
|
130
|
+
sourceKeys = Reflect.ownKeys(source);
|
|
131
|
+
for(i = 0; i < sourceKeys.length; i++){
|
|
132
|
+
key = sourceKeys[i];
|
|
133
|
+
if (excluded.indexOf(key) >= 0) continue;
|
|
134
|
+
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
|
|
135
|
+
target[key] = source[key];
|
|
136
|
+
}
|
|
137
|
+
return target;
|
|
138
|
+
}
|
|
139
|
+
target = _object_without_properties_loose(source, excluded);
|
|
130
140
|
if (Object.getOwnPropertySymbols) {
|
|
131
|
-
|
|
132
|
-
for(i = 0; i <
|
|
133
|
-
key =
|
|
141
|
+
sourceKeys = Object.getOwnPropertySymbols(source);
|
|
142
|
+
for(i = 0; i < sourceKeys.length; i++){
|
|
143
|
+
key = sourceKeys[i];
|
|
134
144
|
if (excluded.indexOf(key) >= 0) continue;
|
|
135
145
|
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
|
|
136
146
|
target[key] = source[key];
|
|
@@ -140,12 +150,11 @@ function _object_without_properties(source, excluded) {
|
|
|
140
150
|
}
|
|
141
151
|
function _object_without_properties_loose(source, excluded) {
|
|
142
152
|
if (source == null) return {};
|
|
143
|
-
var target = {};
|
|
144
|
-
var sourceKeys = Object.keys(source);
|
|
145
|
-
var key, i;
|
|
153
|
+
var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i;
|
|
146
154
|
for(i = 0; i < sourceKeys.length; i++){
|
|
147
155
|
key = sourceKeys[i];
|
|
148
156
|
if (excluded.indexOf(key) >= 0) continue;
|
|
157
|
+
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
|
|
149
158
|
target[key] = source[key];
|
|
150
159
|
}
|
|
151
160
|
return target;
|
|
@@ -155,6 +164,7 @@ var SessionImpl = /*#__PURE__*/ function() {
|
|
|
155
164
|
function SessionImpl() {
|
|
156
165
|
var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
157
166
|
_class_call_check(this, SessionImpl);
|
|
167
|
+
var _options_interactive;
|
|
158
168
|
this.inkApp = null;
|
|
159
169
|
this.runningCount = 0;
|
|
160
170
|
this.closed = false;
|
|
@@ -172,7 +182,6 @@ var SessionImpl = /*#__PURE__*/ function() {
|
|
|
172
182
|
maxFps: _constantsts.DEFAULT_MAX_FPS
|
|
173
183
|
});
|
|
174
184
|
}
|
|
175
|
-
var _options_interactive;
|
|
176
185
|
// Interactive mode requires a TTY to capture user input (e.g., press 'q' to quit)
|
|
177
186
|
// Force non-interactive when no UI is rendered, otherwise waitAndClose would hang
|
|
178
187
|
this.isInteractive = this.inkApp ? (_options_interactive = options.interactive) !== null && _options_interactive !== void 0 ? _options_interactive : false : false;
|
|
@@ -413,4 +422,4 @@ function createSession() {
|
|
|
413
422
|
var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
414
423
|
return new SessionImpl(options);
|
|
415
424
|
}
|
|
416
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
425
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
package/dist/cjs/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/session.tsx"],"sourcesContent":["import spawn, { crossSpawn, type SpawnResult } from 'cross-spawn-cb';\nimport crypto from 'crypto';\nimport { render } from 'ink';\nimport oo from 'on-one';\nimport Queue from 'queue-cb';\n\nimport App from './components/App.ts';\nimport { DEFAULT_MAX_FPS } from './constants.ts';\nimport concatWritable from './lib/concatWritable.ts';\nimport formatArguments from './lib/formatArguments.ts';\nimport { TerminalBuffer } from './lib/TerminalBuffer.ts';\nimport { ProcessStore } from './state/processStore.ts';\nimport type { ProcessOptions, SessionOptions, SpawnError, SpawnOptions, TerminalCallback } from './types.ts';\n\nexport interface Session {\n spawn(command: string, args: string[], spawnOptions: SpawnOptions, options: ProcessOptions, callback: TerminalCallback): void;\n close(): void;\n waitAndClose(callback?: () => void): void;\n}\n\nclass SessionImpl implements Session {\n private store: ProcessStore;\n private inkApp: ReturnType<typeof render> | null = null;\n private runningCount = 0;\n private closed = false;\n private waitCallbacks: (() => void)[] = [];\n private isInteractive: boolean;\n private terminalWidth: number;\n\n constructor(options: SessionOptions = {}) {\n this.store = new ProcessStore(options);\n // Use a very wide buffer to prevent line wrapping in xterm\n // Actual display truncation is handled by Ink components\n this.terminalWidth = 10000;\n\n // Only render Ink when stdout is a real terminal\n // When piped (e.g., nested spawn-term), skip Ink to avoid cursor positioning artifacts\n if (process.stdout.isTTY) {\n this.inkApp = render(<App store={this.store} />, {\n maxFps: DEFAULT_MAX_FPS,\n });\n }\n\n // Interactive mode requires a TTY to capture user input (e.g., press 'q' to quit)\n // Force non-interactive when no UI is rendered, otherwise waitAndClose would hang\n this.isInteractive = this.inkApp ? (options.interactive ?? false) : false;\n }\n\n spawn(command: string, args: string[], spawnOptions: SpawnOptions, options: ProcessOptions, callback: TerminalCallback): void {\n if (this.closed) {\n throw new Error('Session is closed');\n }\n\n const { encoding, stdio, ...csOptions } = spawnOptions;\n\n if (stdio === 'inherit') {\n // When Ink is not rendering (stdout not a TTY), pass output directly to stdout\n if (!this.inkApp) {\n const cp = crossSpawn(command, args, { ...csOptions, stdio: 'inherit' });\n spawn.worker(cp, csOptions, (err?: SpawnError) => {\n const res = (err ? err : {}) as SpawnResult;\n res.stdout = null;\n res.stderr = null;\n res.output = [null, null, null];\n err ? callback(err) : callback(null, res);\n });\n return;\n }\n\n this.runningCount++;\n const id = crypto.randomUUID();\n\n // Create terminal buffer for ANSI sequence interpretation\n const terminalBuffer = new TerminalBuffer(this.terminalWidth);\n\n this.store.addProcess({\n id,\n title: [command].concat(formatArguments(args)).join(' '),\n state: 'running',\n lines: [],\n terminalBuffer,\n group: options.group,\n expanded: options.expanded,\n });\n\n const cp = crossSpawn(command, args, csOptions);\n\n // Pipe stdout and stderr directly to terminal buffer\n // Both streams go to the same buffer to maintain correct ordering\n if (cp.stdout) {\n cp.stdout.on('data', (chunk: Buffer) => {\n terminalBuffer.write(chunk);\n this.store.notify();\n });\n }\n if (cp.stderr) {\n cp.stderr.on('data', (chunk: Buffer) => {\n terminalBuffer.write(chunk);\n this.store.notify();\n });\n }\n\n // Wait for process to complete\n const queue = new Queue();\n if (cp.stdout) {\n queue.defer(oo.bind(null, cp.stdout, ['error', 'end', 'close']));\n }\n if (cp.stderr) {\n queue.defer(oo.bind(null, cp.stderr, ['error', 'end', 'close']));\n }\n queue.defer(spawn.worker.bind(null, cp, csOptions));\n queue.await((err?: SpawnError) => {\n const res = (err ? err : {}) as SpawnResult;\n res.stdout = null; // Not collecting raw output in inherit mode\n res.stderr = null;\n res.output = [null, null, null];\n this.store.updateProcess(id, { state: err ? 'error' : 'success' });\n\n this.onProcessComplete();\n err ? callback(err) : callback(null, res);\n });\n } else {\n // Non-inherit mode: collect output but don't display in UI\n const cp = crossSpawn(command, args, csOptions);\n const outputs = { stdout: null as ReturnType<typeof concatWritable> | null, stderr: null as ReturnType<typeof concatWritable> | null };\n\n const queue = new Queue();\n if (cp.stdout) {\n outputs.stdout = concatWritable((output) => {\n (outputs.stdout as unknown as { output: string }).output = output.toString(encoding || 'utf8');\n });\n queue.defer(oo.bind(null, cp.stdout.pipe(outputs.stdout), ['error', 'end', 'close', 'finish']));\n }\n if (cp.stderr) {\n outputs.stderr = concatWritable((output) => {\n (outputs.stderr as unknown as { output: string }).output = output.toString(encoding || 'utf8');\n });\n queue.defer(oo.bind(null, cp.stderr.pipe(outputs.stderr), ['error', 'end', 'close', 'finish']));\n }\n queue.defer(spawn.worker.bind(null, cp, csOptions));\n queue.await((err?: SpawnError) => {\n const res = (err ? err : {}) as SpawnResult;\n res.stdout = outputs.stdout ? (outputs.stdout as unknown as { output: string }).output : null;\n res.stderr = outputs.stderr ? (outputs.stderr as unknown as { output: string }).output : null;\n res.output = [res.stdout, res.stderr, null];\n err ? callback(err) : callback(null, res);\n });\n }\n }\n\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.cleanup();\n }\n\n waitAndClose(callback?: () => void): void {\n if (this.closed) {\n callback?.();\n return;\n }\n\n if (callback) this.waitCallbacks.push(callback);\n\n if (this.runningCount === 0) {\n if (this.isInteractive) {\n // In interactive mode, wait for user to quit (press 'q')\n const unsubscribe = this.store.subscribe(() => {\n if (this.store.getShouldExit()) {\n unsubscribe();\n this.closeAndCallWaitCallbacks();\n }\n });\n } else {\n this.closeAndCallWaitCallbacks();\n }\n }\n // If runningCount > 0, will close when it hits 0 in onProcessComplete\n }\n\n private onProcessComplete(): void {\n this.runningCount--;\n if (this.runningCount === 0 && this.waitCallbacks.length > 0) {\n if (this.isInteractive) {\n // In interactive mode, wait for user to quit (press 'q')\n const unsubscribe = this.store.subscribe(() => {\n if (this.store.getShouldExit()) {\n unsubscribe();\n this.closeAndCallWaitCallbacks();\n }\n });\n } else {\n this.closeAndCallWaitCallbacks();\n }\n }\n }\n\n private closeAndCallWaitCallbacks(): void {\n if (this.closed) return;\n this.closed = true;\n this.cleanup(() => {\n for (const cb of this.waitCallbacks) cb();\n this.waitCallbacks = [];\n });\n }\n\n private cleanup(onComplete?: () => void): void {\n // Signal exit to React component\n this.store.signalExit(() => {\n this.store.reset();\n process.stdout.write('\\x1b[?25h'); // show cursor\n });\n\n // Wait for Ink to finish\n if (this.inkApp) {\n this.inkApp\n .waitUntilExit()\n .then(() => {\n const cb = this.store.getExitCallback();\n cb?.();\n onComplete?.();\n })\n .catch(() => {\n const cb = this.store.getExitCallback();\n cb?.();\n onComplete?.();\n });\n this.inkApp = null;\n } else {\n onComplete?.();\n }\n }\n}\n\nexport function createSession(options: SessionOptions = {}): Session {\n return new SessionImpl(options);\n}\n"],"names":["createSession","SessionImpl","options","inkApp","runningCount","closed","waitCallbacks","store","ProcessStore","terminalWidth","process","stdout","isTTY","render","App","maxFps","DEFAULT_MAX_FPS","isInteractive","interactive","spawn","command","args","spawnOptions","callback","Error","encoding","stdio","csOptions","cp","crossSpawn","worker","err","res","stderr","output","id","crypto","randomUUID","terminalBuffer","TerminalBuffer","addProcess","title","concat","formatArguments","join","state","lines","group","expanded","on","chunk","write","notify","queue","Queue","defer","oo","bind","await","updateProcess","onProcessComplete","outputs","concatWritable","toString","pipe","close","cleanup","waitAndClose","push","unsubscribe","subscribe","getShouldExit","closeAndCallWaitCallbacks","length","cb","onComplete","signalExit","reset","waitUntilExit","then","getExitCallback","catch"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/session.tsx"],"sourcesContent":["import spawn, { crossSpawn, type SpawnResult } from 'cross-spawn-cb';\nimport crypto from 'crypto';\nimport { render } from 'ink';\nimport oo from 'on-one';\nimport Queue from 'queue-cb';\n\nimport App from './components/App.ts';\nimport { DEFAULT_MAX_FPS } from './constants.ts';\nimport concatWritable from './lib/concatWritable.ts';\nimport formatArguments from './lib/formatArguments.ts';\nimport { TerminalBuffer } from './lib/TerminalBuffer.ts';\nimport { ProcessStore } from './state/processStore.ts';\nimport type { ProcessOptions, SessionOptions, SpawnError, SpawnOptions, TerminalCallback } from './types.ts';\n\nexport interface Session {\n spawn(command: string, args: string[], spawnOptions: SpawnOptions, options: ProcessOptions, callback: TerminalCallback): void;\n close(): void;\n waitAndClose(callback?: () => void): void;\n}\n\nclass SessionImpl implements Session {\n private store: ProcessStore;\n private inkApp: ReturnType<typeof render> | null = null;\n private runningCount = 0;\n private closed = false;\n private waitCallbacks: (() => void)[] = [];\n private isInteractive: boolean;\n private terminalWidth: number;\n\n constructor(options: SessionOptions = {}) {\n this.store = new ProcessStore(options);\n // Use a very wide buffer to prevent line wrapping in xterm\n // Actual display truncation is handled by Ink components\n this.terminalWidth = 10000;\n\n // Only render Ink when stdout is a real terminal\n // When piped (e.g., nested spawn-term), skip Ink to avoid cursor positioning artifacts\n if (process.stdout.isTTY) {\n this.inkApp = render(<App store={this.store} />, {\n maxFps: DEFAULT_MAX_FPS,\n });\n }\n\n // Interactive mode requires a TTY to capture user input (e.g., press 'q' to quit)\n // Force non-interactive when no UI is rendered, otherwise waitAndClose would hang\n this.isInteractive = this.inkApp ? (options.interactive ?? false) : false;\n }\n\n spawn(command: string, args: string[], spawnOptions: SpawnOptions, options: ProcessOptions, callback: TerminalCallback): void {\n if (this.closed) {\n throw new Error('Session is closed');\n }\n\n const { encoding, stdio, ...csOptions } = spawnOptions;\n\n if (stdio === 'inherit') {\n // When Ink is not rendering (stdout not a TTY), pass output directly to stdout\n if (!this.inkApp) {\n const cp = crossSpawn(command, args, { ...csOptions, stdio: 'inherit' });\n spawn.worker(cp, csOptions, (err?: SpawnError) => {\n const res = (err ? err : {}) as SpawnResult;\n res.stdout = null;\n res.stderr = null;\n res.output = [null, null, null];\n err ? callback(err) : callback(null, res);\n });\n return;\n }\n\n this.runningCount++;\n const id = crypto.randomUUID();\n\n // Create terminal buffer for ANSI sequence interpretation\n const terminalBuffer = new TerminalBuffer(this.terminalWidth);\n\n this.store.addProcess({\n id,\n title: [command].concat(formatArguments(args)).join(' '),\n state: 'running',\n lines: [],\n terminalBuffer,\n group: options.group,\n expanded: options.expanded,\n });\n\n const cp = crossSpawn(command, args, csOptions);\n\n // Pipe stdout and stderr directly to terminal buffer\n // Both streams go to the same buffer to maintain correct ordering\n if (cp.stdout) {\n cp.stdout.on('data', (chunk: Buffer) => {\n terminalBuffer.write(chunk);\n this.store.notify();\n });\n }\n if (cp.stderr) {\n cp.stderr.on('data', (chunk: Buffer) => {\n terminalBuffer.write(chunk);\n this.store.notify();\n });\n }\n\n // Wait for process to complete\n const queue = new Queue();\n if (cp.stdout) {\n queue.defer(oo.bind(null, cp.stdout, ['error', 'end', 'close']));\n }\n if (cp.stderr) {\n queue.defer(oo.bind(null, cp.stderr, ['error', 'end', 'close']));\n }\n queue.defer(spawn.worker.bind(null, cp, csOptions));\n queue.await((err?: SpawnError) => {\n const res = (err ? err : {}) as SpawnResult;\n res.stdout = null; // Not collecting raw output in inherit mode\n res.stderr = null;\n res.output = [null, null, null];\n this.store.updateProcess(id, { state: err ? 'error' : 'success' });\n\n this.onProcessComplete();\n err ? callback(err) : callback(null, res);\n });\n } else {\n // Non-inherit mode: collect output but don't display in UI\n const cp = crossSpawn(command, args, csOptions);\n const outputs = { stdout: null as ReturnType<typeof concatWritable> | null, stderr: null as ReturnType<typeof concatWritable> | null };\n\n const queue = new Queue();\n if (cp.stdout) {\n outputs.stdout = concatWritable((output) => {\n (outputs.stdout as unknown as { output: string }).output = output.toString(encoding || 'utf8');\n });\n queue.defer(oo.bind(null, cp.stdout.pipe(outputs.stdout), ['error', 'end', 'close', 'finish']));\n }\n if (cp.stderr) {\n outputs.stderr = concatWritable((output) => {\n (outputs.stderr as unknown as { output: string }).output = output.toString(encoding || 'utf8');\n });\n queue.defer(oo.bind(null, cp.stderr.pipe(outputs.stderr), ['error', 'end', 'close', 'finish']));\n }\n queue.defer(spawn.worker.bind(null, cp, csOptions));\n queue.await((err?: SpawnError) => {\n const res = (err ? err : {}) as SpawnResult;\n res.stdout = outputs.stdout ? (outputs.stdout as unknown as { output: string }).output : null;\n res.stderr = outputs.stderr ? (outputs.stderr as unknown as { output: string }).output : null;\n res.output = [res.stdout, res.stderr, null];\n err ? callback(err) : callback(null, res);\n });\n }\n }\n\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.cleanup();\n }\n\n waitAndClose(callback?: () => void): void {\n if (this.closed) {\n callback?.();\n return;\n }\n\n if (callback) this.waitCallbacks.push(callback);\n\n if (this.runningCount === 0) {\n if (this.isInteractive) {\n // In interactive mode, wait for user to quit (press 'q')\n const unsubscribe = this.store.subscribe(() => {\n if (this.store.getShouldExit()) {\n unsubscribe();\n this.closeAndCallWaitCallbacks();\n }\n });\n } else {\n this.closeAndCallWaitCallbacks();\n }\n }\n // If runningCount > 0, will close when it hits 0 in onProcessComplete\n }\n\n private onProcessComplete(): void {\n this.runningCount--;\n if (this.runningCount === 0 && this.waitCallbacks.length > 0) {\n if (this.isInteractive) {\n // In interactive mode, wait for user to quit (press 'q')\n const unsubscribe = this.store.subscribe(() => {\n if (this.store.getShouldExit()) {\n unsubscribe();\n this.closeAndCallWaitCallbacks();\n }\n });\n } else {\n this.closeAndCallWaitCallbacks();\n }\n }\n }\n\n private closeAndCallWaitCallbacks(): void {\n if (this.closed) return;\n this.closed = true;\n this.cleanup(() => {\n for (const cb of this.waitCallbacks) cb();\n this.waitCallbacks = [];\n });\n }\n\n private cleanup(onComplete?: () => void): void {\n // Signal exit to React component\n this.store.signalExit(() => {\n this.store.reset();\n process.stdout.write('\\x1b[?25h'); // show cursor\n });\n\n // Wait for Ink to finish\n if (this.inkApp) {\n this.inkApp\n .waitUntilExit()\n .then(() => {\n const cb = this.store.getExitCallback();\n cb?.();\n onComplete?.();\n })\n .catch(() => {\n const cb = this.store.getExitCallback();\n cb?.();\n onComplete?.();\n });\n this.inkApp = null;\n } else {\n onComplete?.();\n }\n }\n}\n\nexport function createSession(options: SessionOptions = {}): Session {\n return new SessionImpl(options);\n}\n"],"names":["createSession","SessionImpl","options","inkApp","runningCount","closed","waitCallbacks","store","ProcessStore","terminalWidth","process","stdout","isTTY","render","App","maxFps","DEFAULT_MAX_FPS","isInteractive","interactive","spawn","command","args","spawnOptions","callback","Error","encoding","stdio","csOptions","cp","crossSpawn","worker","err","res","stderr","output","id","crypto","randomUUID","terminalBuffer","TerminalBuffer","addProcess","title","concat","formatArguments","join","state","lines","group","expanded","on","chunk","write","notify","queue","Queue","defer","oo","bind","await","updateProcess","onProcessComplete","outputs","concatWritable","toString","pipe","close","cleanup","waitAndClose","push","unsubscribe","subscribe","getShouldExit","closeAndCallWaitCallbacks","length","cb","onComplete","signalExit","reset","waitUntilExit","then","getExitCallback","catch"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type Callback = (lines: Buffer) =>
|
|
1
|
+
export type Callback = (lines: Buffer) => void;
|
|
2
2
|
export default function concatWritable(callback: Callback): NodeJS.WritableStream;
|
|
@@ -124,4 +124,4 @@ function createNavigator(options) {
|
|
|
124
124
|
}
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
127
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -25,4 +25,4 @@ function useStore() {
|
|
|
25
25
|
}
|
|
26
26
|
return store;
|
|
27
27
|
}
|
|
28
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
28
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -106,6 +106,7 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
106
106
|
var _this = this;
|
|
107
107
|
var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
108
108
|
_class_call_check(this, ProcessStore);
|
|
109
|
+
var _options_showStatusBar, _options_interactive;
|
|
109
110
|
// === DATA: Process collection ===
|
|
110
111
|
this.processes = [];
|
|
111
112
|
this.completedIds = []; // Track completion order
|
|
@@ -248,11 +249,11 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
248
249
|
};
|
|
249
250
|
// Get scroll offset for expanded process (or 0 if none)
|
|
250
251
|
this.getScrollOffset = function() {
|
|
252
|
+
var _ref;
|
|
251
253
|
var _process_scrollNav;
|
|
252
254
|
if (!_this.expandedId) return 0;
|
|
253
255
|
var process = _this.getProcess(_this.expandedId);
|
|
254
|
-
|
|
255
|
-
return (_process_scrollNav_position = process === null || process === void 0 ? void 0 : (_process_scrollNav = process.scrollNav) === null || _process_scrollNav === void 0 ? void 0 : _process_scrollNav.position) !== null && _process_scrollNav_position !== void 0 ? _process_scrollNav_position : 0;
|
|
256
|
+
return (_ref = process === null || process === void 0 ? void 0 : (_process_scrollNav = process.scrollNav) === null || _process_scrollNav === void 0 ? void 0 : _process_scrollNav.position) !== null && _ref !== void 0 ? _ref : 0;
|
|
256
257
|
};
|
|
257
258
|
// Session-level getters (set at session creation, immutable)
|
|
258
259
|
this.getHeader = function() {
|
|
@@ -276,9 +277,7 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
276
277
|
return _this.exitCallback;
|
|
277
278
|
};
|
|
278
279
|
this.header = options.header;
|
|
279
|
-
var _options_showStatusBar;
|
|
280
280
|
this.showStatusBar = (_options_showStatusBar = options.showStatusBar) !== null && _options_showStatusBar !== void 0 ? _options_showStatusBar : false;
|
|
281
|
-
var _options_interactive;
|
|
282
281
|
this.isInteractive = (_options_interactive = options.interactive) !== null && _options_interactive !== void 0 ? _options_interactive : false;
|
|
283
282
|
// Create list navigator with wrap-around behavior
|
|
284
283
|
// Uses filtered processes count so selection works correctly with filters
|
|
@@ -654,4 +653,4 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
654
653
|
return ProcessStore;
|
|
655
654
|
} // Note: No global singleton - session creates its own store instance
|
|
656
655
|
();
|
|
657
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
656
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import { arrayFind } from '../compat.ts';\nimport { DEFAULT_COLUMN_WIDTH } from '../constants.ts';\nimport type { ChildProcess, Line, SessionOptions } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport { createNavigator, type Navigator } from './Navigator.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive';\ntype FilterMode = 'all' | 'running' | 'finished' | 'failed';\n\nconst FILTER_CYCLE: FilterMode[] = ['all', 'running', 'finished', 'failed'];\n\nexport class ProcessStore {\n // === DATA: Process collection ===\n private processes: ChildProcess[] = [];\n private completedIds: string[] = []; // Track completion order\n\n // === NAVIGATION: List cursor ===\n private listNav: Navigator;\n\n // === VIEW STATE ===\n private mode: Mode = 'normal';\n private expandedId: string | null = null;\n private errorFooterExpanded = false; // For non-interactive error footer\n private filterMode: FilterMode = 'all';\n private searchTerm = '';\n private isSearching = false;\n private isFullscreen = false;\n\n // === SESSION CONFIG (immutable after construction) ===\n private header: string | undefined;\n private showStatusBar = false;\n private isInteractive = false;\n\n // === INFRASTRUCTURE ===\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\n private bufferVersion = 0; // Increments on every notify() to trigger re-renders\n\n constructor(options: SessionOptions = {}) {\n this.header = options.header;\n this.showStatusBar = options.showStatusBar ?? false;\n this.isInteractive = options.interactive ?? false;\n\n // Create list navigator with wrap-around behavior\n // Uses filtered processes count so selection works correctly with filters\n this.listNav = createNavigator({\n getLength: () => this.getFilteredProcesses().length,\n wrap: true,\n onMove: () => this.notify(),\n });\n }\n\n // === SUBSCRIPTION API (useSyncExternalStore) ===\n\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n getSnapshot = (): ChildProcess[] => this.processes;\n\n // === DATA: Queries ===\n\n getRunningProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'running');\n };\n\n getCompletedProcesses = (): ChildProcess[] => {\n // Return in completion order\n return this.completedIds.map((id) => arrayFind(this.processes, (p) => p.id === id)).filter((p): p is ChildProcess => p !== undefined);\n };\n\n getFailedProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'error');\n };\n\n // Counts\n getRunningCount = (): number => this.processes.filter((p) => p.state === 'running').length;\n getMaxGroupLength = (): number => {\n if (this.processes.length === 0) return DEFAULT_COLUMN_WIDTH;\n return Math.max(...this.processes.map((p) => (p.group || p.title).length));\n };\n getDoneCount = (): number => this.processes.filter((p) => p.state !== 'running').length;\n getErrorCount = (): number => this.processes.filter((p) => p.state === 'error').length;\n getErrorLineCount = (): number => {\n return this.processes.filter((p) => p.state === 'error').reduce((total, p) => total + this.getProcessLineCount(p.id), 0);\n };\n\n getErrorLines(): Array<{ processName: string; lines: Line[] }> {\n return this.getFailedProcesses().map((p) => ({\n processName: p.group || p.title,\n lines: this.getProcessLines(p.id),\n }));\n }\n\n // === DATA: Mutations ===\n\n addProcess(process: ChildProcess): void {\n // Create scroll navigator for this process\n const processWithNav: ChildProcess = {\n ...process,\n scrollNav: createNavigator({\n getLength: () => this.getProcessLineCount(processWithNav.id),\n wrap: false,\n onMove: () => this.notify(),\n }),\n };\n this.processes = [...this.processes, processWithNav];\n this.notify();\n }\n\n updateProcess(id: string, update: Partial<ChildProcess>): void {\n const oldProcess = arrayFind(this.processes, (p) => p.id === id);\n const wasRunning = oldProcess?.state === 'running';\n const isNowComplete = update.state && update.state !== 'running';\n\n this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\n\n // Track completion order\n if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {\n this.completedIds = [...this.completedIds, id];\n }\n\n // Auto-expand error footer when all complete with errors (non-interactive only)\n if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {\n this.errorFooterExpanded = true;\n }\n\n this.notify();\n }\n\n appendLines(id: string, newLines: Line[]): void {\n const process = arrayFind(this.processes, (p) => p.id === id);\n if (process) {\n this.updateProcess(id, { lines: process.lines.concat(newLines) });\n }\n }\n\n getProcess(id: string): ChildProcess | undefined {\n return arrayFind(this.processes, (p) => p.id === id);\n }\n\n // Get rendered lines from terminal buffer or fallback to lines array\n getProcessLines(id: string): Line[] {\n const process = this.getProcess(id);\n if (!process) return [];\n if (process.terminalBuffer) {\n return process.terminalBuffer.getLines().map((text) => ({\n type: LineType.stdout,\n text,\n }));\n }\n return process.lines;\n }\n\n // Get line count from terminal buffer or lines array\n getProcessLineCount(id: string): number {\n const process = this.getProcess(id);\n if (!process) return 0;\n if (process.terminalBuffer) {\n return process.terminalBuffer.lineCount;\n }\n return process.lines.length;\n }\n\n // === VIEW STATE: Getters ===\n\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.listNav.position;\n getExpandedId = (): string | null => this.expandedId;\n getListScrollOffset = (): number => this.listNav.viewportOffset;\n getErrorFooterExpanded = (): boolean => this.errorFooterExpanded;\n getBufferVersion = (): number => this.bufferVersion;\n getFilterMode = (): FilterMode => this.filterMode;\n getSearchTerm = (): string => this.searchTerm;\n getIsSearching = (): boolean => this.isSearching;\n getIsFullscreen = (): boolean => this.isFullscreen;\n\n // Get processes filtered by current filter mode and search term\n getFilteredProcesses = (): ChildProcess[] => {\n let filtered = this.processes;\n\n // Apply filter mode\n switch (this.filterMode) {\n case 'running':\n filtered = filtered.filter((p) => p.state === 'running');\n break;\n case 'finished':\n filtered = filtered.filter((p) => p.state !== 'running');\n break;\n case 'failed':\n filtered = filtered.filter((p) => p.state === 'error');\n break;\n }\n\n // Apply search term\n if (this.searchTerm) {\n const term = this.searchTerm.toLowerCase();\n filtered = filtered.filter((p) => p.title.toLowerCase().includes(term) || (p.group && p.group.toLowerCase().includes(term)));\n }\n\n return filtered;\n };\n\n // Get scroll offset for expanded process (or 0 if none)\n getScrollOffset = (): number => {\n if (!this.expandedId) return 0;\n const process = this.getProcess(this.expandedId);\n return process?.scrollNav?.position ?? 0;\n };\n\n // Session-level getters (set at session creation, immutable)\n getHeader = (): string | undefined => this.header;\n getShowStatusBar = (): boolean => this.showStatusBar;\n getIsInteractive = (): boolean => this.isInteractive;\n isAllComplete = (): boolean => this.processes.length > 0 && this.processes.every((p) => p.state !== 'running');\n\n // === VIEW STATE: Mutations ===\n\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.listNav.setPosition(0);\n }\n this.notify();\n }\n\n getSelectedProcess(): ChildProcess | undefined {\n return this.getFilteredProcesses()[this.listNav.position];\n }\n\n // Filter mode cycling (left/right arrows)\n cycleFilterNext(): void {\n const currentIndex = FILTER_CYCLE.indexOf(this.filterMode);\n this.filterMode = FILTER_CYCLE[(currentIndex + 1) % FILTER_CYCLE.length] as FilterMode;\n // Reset selection when filter changes\n this.listNav.toStart();\n // Collapse any expanded process when filter changes\n this.expandedId = null;\n this.notify();\n }\n\n cycleFilterPrev(): void {\n const currentIndex = FILTER_CYCLE.indexOf(this.filterMode);\n this.filterMode = FILTER_CYCLE[(currentIndex - 1 + FILTER_CYCLE.length) % FILTER_CYCLE.length] as FilterMode;\n // Reset selection when filter changes\n this.listNav.toStart();\n // Collapse any expanded process when filter changes\n this.expandedId = null;\n this.notify();\n }\n\n // Search mode\n startSearch(): void {\n this.isSearching = true;\n this.searchTerm = '';\n this.notify();\n }\n\n updateSearchTerm(term: string): void {\n this.searchTerm = term;\n // Reset selection when search changes\n this.listNav.toStart();\n this.notify();\n }\n\n cancelSearch(): void {\n this.isSearching = false;\n this.searchTerm = '';\n // Reset selection\n this.listNav.toStart();\n this.notify();\n }\n\n confirmSearch(): void {\n this.isSearching = false;\n // Keep searchTerm applied, reset selection to first match\n this.listNav.toStart();\n this.notify();\n }\n\n clearSearch(): void {\n this.searchTerm = '';\n this.listNav.toStart();\n this.notify();\n }\n\n // Fullscreen mode (alternate screen buffer)\n enterFullscreen(): void {\n // If not expanded, expand the selected process first\n if (!this.expandedId) {\n const selected = this.getSelectedProcess();\n if (selected) {\n this.expandedId = selected.id;\n }\n }\n if (this.expandedId) {\n this.isFullscreen = true;\n this.notify();\n }\n }\n\n exitFullscreen(visibleCountWhenCollapsed?: number): void {\n this.isFullscreen = false;\n // Also collapse when exiting fullscreen\n this.expandedId = null;\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n this.notify();\n }\n\n // Error footer methods (for non-interactive mode)\n toggleErrorFooter(): void {\n this.errorFooterExpanded = !this.errorFooterExpanded;\n this.notify();\n }\n\n expandErrorFooter(): void {\n if (!this.errorFooterExpanded) {\n this.errorFooterExpanded = true;\n this.notify();\n }\n }\n\n // === NAVIGATION: List (delegates to listNav) ===\n\n selectNext(visibleCount?: number): void {\n this.listNav.down();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPrev(visibleCount?: number): void {\n this.listNav.up();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPageDown(pageSize: number, visibleCount?: number): void {\n this.listNav.pageDown(pageSize, visibleCount);\n }\n\n selectPageUp(pageSize: number, visibleCount?: number): void {\n this.listNav.pageUp(pageSize, visibleCount);\n }\n\n selectFirst(visibleCount?: number): void {\n this.listNav.toStart();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectLast(visibleCount?: number): void {\n this.listNav.toEnd();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n clampListViewport(visibleCount: number): void {\n const changed = this.listNav.clampViewport(visibleCount);\n if (changed) {\n this.notify();\n }\n }\n\n // === NAVIGATION: Expanded content (delegates to process.scrollNav) ===\n\n private getExpandedNav(): { nav: Navigator; id: string } | undefined {\n if (!this.expandedId) return undefined;\n const nav = this.getProcess(this.expandedId)?.scrollNav;\n if (!nav) return undefined;\n return { nav, id: this.expandedId };\n }\n\n scrollDown(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - maxVisible);\n\n // Only scroll if not at bottom\n if (expanded.nav.position < maxOffset) {\n expanded.nav.down();\n }\n }\n\n scrollUp(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n if (expanded.nav.position > 0) {\n expanded.nav.up();\n }\n }\n\n scrollPageDown(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - pageSize);\n\n // Clamp to max offset\n const newPosition = Math.min(expanded.nav.position + pageSize, maxOffset);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollPageUp(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const newPosition = Math.max(0, expanded.nav.position - pageSize);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollToTop(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n expanded.nav.toStart();\n }\n\n scrollToBottom(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const newPosition = Math.max(0, lineCount - maxVisible);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n // === EXPANSION ===\n\n toggleExpand(visibleCountWhenExpanded?: number, visibleCountWhenCollapsed?: number): void {\n const selected = this.getSelectedProcess();\n if (!selected) return;\n\n if (this.expandedId === selected.id) {\n // Collapse (keep scroll position for later)\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n } else {\n // Expand (scroll position is preserved in process.scrollNav)\n this.expandedId = selected.id;\n // Adjust list scroll to keep expanded process visible\n if (visibleCountWhenExpanded) {\n this.listNav.ensureVisible(visibleCountWhenExpanded);\n }\n }\n this.notify();\n }\n\n collapse(visibleCountWhenCollapsed?: number): void {\n // Collapse but keep scroll position in process\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n this.notify();\n }\n\n // === EXIT ===\n\n signalExit(callback: () => void): void {\n this.shouldExit = true;\n this.exitCallback = callback;\n this.notify();\n }\n\n getShouldExit = (): boolean => this.shouldExit;\n getExitCallback = (): (() => void) | null => this.exitCallback;\n\n // === RESET ===\n\n reset(): void {\n // Dispose terminal buffers before clearing\n for (const process of this.processes) {\n process.terminalBuffer?.dispose();\n }\n this.processes = [];\n this.completedIds = [];\n this.shouldExit = false;\n this.exitCallback = null;\n this.mode = 'normal';\n this.listNav.reset();\n this.expandedId = null;\n this.errorFooterExpanded = false;\n this.filterMode = 'all';\n this.searchTerm = '';\n this.isSearching = false;\n this.isFullscreen = false;\n this.header = undefined;\n }\n\n // === INFRASTRUCTURE ===\n\n notify(): void {\n this.bufferVersion++;\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\n// Note: No global singleton - session creates its own store instance\n"],"names":["ProcessStore","FILTER_CYCLE","options","processes","completedIds","mode","expandedId","errorFooterExpanded","filterMode","searchTerm","isSearching","isFullscreen","showStatusBar","isInteractive","listeners","Set","shouldExit","exitCallback","bufferVersion","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","p","state","getCompletedProcesses","map","id","arrayFind","undefined","getFailedProcesses","getRunningCount","length","getMaxGroupLength","Math","DEFAULT_COLUMN_WIDTH","max","group","title","getDoneCount","getErrorCount","getErrorLineCount","reduce","total","getProcessLineCount","getMode","getSelectedIndex","listNav","position","getExpandedId","getListScrollOffset","viewportOffset","getErrorFooterExpanded","getBufferVersion","getFilterMode","getSearchTerm","getIsSearching","getIsFullscreen","getFilteredProcesses","filtered","term","toLowerCase","includes","getScrollOffset","process","getProcess","scrollNav","getHeader","header","getShowStatusBar","getIsInteractive","isAllComplete","every","getShouldExit","getExitCallback","interactive","createNavigator","getLength","wrap","onMove","notify","getErrorLines","processName","lines","getProcessLines","addProcess","processWithNav","updateProcess","update","oldProcess","wasRunning","isNowComplete","appendLines","newLines","concat","terminalBuffer","getLines","text","type","LineType","stdout","lineCount","setMode","setPosition","getSelectedProcess","cycleFilterNext","currentIndex","indexOf","toStart","cycleFilterPrev","startSearch","updateSearchTerm","cancelSearch","confirmSearch","clearSearch","enterFullscreen","selected","exitFullscreen","visibleCountWhenCollapsed","clampViewport","toggleErrorFooter","expandErrorFooter","selectNext","visibleCount","down","ensureVisible","selectPrev","up","selectPageDown","pageSize","pageDown","selectPageUp","pageUp","selectFirst","selectLast","toEnd","clampListViewport","changed","getExpandedNav","nav","scrollDown","maxVisible","expanded","maxOffset","scrollUp","scrollPageDown","newPosition","min","scrollPageUp","scrollToTop","scrollToBottom","toggleExpand","visibleCountWhenExpanded","collapse","signalExit","callback","reset","dispose","forEach","l"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import { arrayFind } from '../compat.ts';\nimport { DEFAULT_COLUMN_WIDTH } from '../constants.ts';\nimport type { ChildProcess, Line, SessionOptions } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport { createNavigator, type Navigator } from './Navigator.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive';\ntype FilterMode = 'all' | 'running' | 'finished' | 'failed';\n\nconst FILTER_CYCLE: FilterMode[] = ['all', 'running', 'finished', 'failed'];\n\nexport class ProcessStore {\n // === DATA: Process collection ===\n private processes: ChildProcess[] = [];\n private completedIds: string[] = []; // Track completion order\n\n // === NAVIGATION: List cursor ===\n private listNav: Navigator;\n\n // === VIEW STATE ===\n private mode: Mode = 'normal';\n private expandedId: string | null = null;\n private errorFooterExpanded = false; // For non-interactive error footer\n private filterMode: FilterMode = 'all';\n private searchTerm = '';\n private isSearching = false;\n private isFullscreen = false;\n\n // === SESSION CONFIG (immutable after construction) ===\n private header: string | undefined;\n private showStatusBar = false;\n private isInteractive = false;\n\n // === INFRASTRUCTURE ===\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\n private bufferVersion = 0; // Increments on every notify() to trigger re-renders\n\n constructor(options: SessionOptions = {}) {\n this.header = options.header;\n this.showStatusBar = options.showStatusBar ?? false;\n this.isInteractive = options.interactive ?? false;\n\n // Create list navigator with wrap-around behavior\n // Uses filtered processes count so selection works correctly with filters\n this.listNav = createNavigator({\n getLength: () => this.getFilteredProcesses().length,\n wrap: true,\n onMove: () => this.notify(),\n });\n }\n\n // === SUBSCRIPTION API (useSyncExternalStore) ===\n\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n getSnapshot = (): ChildProcess[] => this.processes;\n\n // === DATA: Queries ===\n\n getRunningProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'running');\n };\n\n getCompletedProcesses = (): ChildProcess[] => {\n // Return in completion order\n return this.completedIds.map((id) => arrayFind(this.processes, (p) => p.id === id)).filter((p): p is ChildProcess => p !== undefined);\n };\n\n getFailedProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'error');\n };\n\n // Counts\n getRunningCount = (): number => this.processes.filter((p) => p.state === 'running').length;\n getMaxGroupLength = (): number => {\n if (this.processes.length === 0) return DEFAULT_COLUMN_WIDTH;\n return Math.max(...this.processes.map((p) => (p.group || p.title).length));\n };\n getDoneCount = (): number => this.processes.filter((p) => p.state !== 'running').length;\n getErrorCount = (): number => this.processes.filter((p) => p.state === 'error').length;\n getErrorLineCount = (): number => {\n return this.processes.filter((p) => p.state === 'error').reduce((total, p) => total + this.getProcessLineCount(p.id), 0);\n };\n\n getErrorLines(): Array<{ processName: string; lines: Line[] }> {\n return this.getFailedProcesses().map((p) => ({\n processName: p.group || p.title,\n lines: this.getProcessLines(p.id),\n }));\n }\n\n // === DATA: Mutations ===\n\n addProcess(process: ChildProcess): void {\n // Create scroll navigator for this process\n const processWithNav: ChildProcess = {\n ...process,\n scrollNav: createNavigator({\n getLength: () => this.getProcessLineCount(processWithNav.id),\n wrap: false,\n onMove: () => this.notify(),\n }),\n };\n this.processes = [...this.processes, processWithNav];\n this.notify();\n }\n\n updateProcess(id: string, update: Partial<ChildProcess>): void {\n const oldProcess = arrayFind(this.processes, (p) => p.id === id);\n const wasRunning = oldProcess?.state === 'running';\n const isNowComplete = update.state && update.state !== 'running';\n\n this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\n\n // Track completion order\n if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {\n this.completedIds = [...this.completedIds, id];\n }\n\n // Auto-expand error footer when all complete with errors (non-interactive only)\n if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {\n this.errorFooterExpanded = true;\n }\n\n this.notify();\n }\n\n appendLines(id: string, newLines: Line[]): void {\n const process = arrayFind(this.processes, (p) => p.id === id);\n if (process) {\n this.updateProcess(id, { lines: process.lines.concat(newLines) });\n }\n }\n\n getProcess(id: string): ChildProcess | undefined {\n return arrayFind(this.processes, (p) => p.id === id);\n }\n\n // Get rendered lines from terminal buffer or fallback to lines array\n getProcessLines(id: string): Line[] {\n const process = this.getProcess(id);\n if (!process) return [];\n if (process.terminalBuffer) {\n return process.terminalBuffer.getLines().map((text) => ({\n type: LineType.stdout,\n text,\n }));\n }\n return process.lines;\n }\n\n // Get line count from terminal buffer or lines array\n getProcessLineCount(id: string): number {\n const process = this.getProcess(id);\n if (!process) return 0;\n if (process.terminalBuffer) {\n return process.terminalBuffer.lineCount;\n }\n return process.lines.length;\n }\n\n // === VIEW STATE: Getters ===\n\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.listNav.position;\n getExpandedId = (): string | null => this.expandedId;\n getListScrollOffset = (): number => this.listNav.viewportOffset;\n getErrorFooterExpanded = (): boolean => this.errorFooterExpanded;\n getBufferVersion = (): number => this.bufferVersion;\n getFilterMode = (): FilterMode => this.filterMode;\n getSearchTerm = (): string => this.searchTerm;\n getIsSearching = (): boolean => this.isSearching;\n getIsFullscreen = (): boolean => this.isFullscreen;\n\n // Get processes filtered by current filter mode and search term\n getFilteredProcesses = (): ChildProcess[] => {\n let filtered = this.processes;\n\n // Apply filter mode\n switch (this.filterMode) {\n case 'running':\n filtered = filtered.filter((p) => p.state === 'running');\n break;\n case 'finished':\n filtered = filtered.filter((p) => p.state !== 'running');\n break;\n case 'failed':\n filtered = filtered.filter((p) => p.state === 'error');\n break;\n }\n\n // Apply search term\n if (this.searchTerm) {\n const term = this.searchTerm.toLowerCase();\n filtered = filtered.filter((p) => p.title.toLowerCase().includes(term) || (p.group && p.group.toLowerCase().includes(term)));\n }\n\n return filtered;\n };\n\n // Get scroll offset for expanded process (or 0 if none)\n getScrollOffset = (): number => {\n if (!this.expandedId) return 0;\n const process = this.getProcess(this.expandedId);\n return process?.scrollNav?.position ?? 0;\n };\n\n // Session-level getters (set at session creation, immutable)\n getHeader = (): string | undefined => this.header;\n getShowStatusBar = (): boolean => this.showStatusBar;\n getIsInteractive = (): boolean => this.isInteractive;\n isAllComplete = (): boolean => this.processes.length > 0 && this.processes.every((p) => p.state !== 'running');\n\n // === VIEW STATE: Mutations ===\n\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.listNav.setPosition(0);\n }\n this.notify();\n }\n\n getSelectedProcess(): ChildProcess | undefined {\n return this.getFilteredProcesses()[this.listNav.position];\n }\n\n // Filter mode cycling (left/right arrows)\n cycleFilterNext(): void {\n const currentIndex = FILTER_CYCLE.indexOf(this.filterMode);\n this.filterMode = FILTER_CYCLE[(currentIndex + 1) % FILTER_CYCLE.length] as FilterMode;\n // Reset selection when filter changes\n this.listNav.toStart();\n // Collapse any expanded process when filter changes\n this.expandedId = null;\n this.notify();\n }\n\n cycleFilterPrev(): void {\n const currentIndex = FILTER_CYCLE.indexOf(this.filterMode);\n this.filterMode = FILTER_CYCLE[(currentIndex - 1 + FILTER_CYCLE.length) % FILTER_CYCLE.length] as FilterMode;\n // Reset selection when filter changes\n this.listNav.toStart();\n // Collapse any expanded process when filter changes\n this.expandedId = null;\n this.notify();\n }\n\n // Search mode\n startSearch(): void {\n this.isSearching = true;\n this.searchTerm = '';\n this.notify();\n }\n\n updateSearchTerm(term: string): void {\n this.searchTerm = term;\n // Reset selection when search changes\n this.listNav.toStart();\n this.notify();\n }\n\n cancelSearch(): void {\n this.isSearching = false;\n this.searchTerm = '';\n // Reset selection\n this.listNav.toStart();\n this.notify();\n }\n\n confirmSearch(): void {\n this.isSearching = false;\n // Keep searchTerm applied, reset selection to first match\n this.listNav.toStart();\n this.notify();\n }\n\n clearSearch(): void {\n this.searchTerm = '';\n this.listNav.toStart();\n this.notify();\n }\n\n // Fullscreen mode (alternate screen buffer)\n enterFullscreen(): void {\n // If not expanded, expand the selected process first\n if (!this.expandedId) {\n const selected = this.getSelectedProcess();\n if (selected) {\n this.expandedId = selected.id;\n }\n }\n if (this.expandedId) {\n this.isFullscreen = true;\n this.notify();\n }\n }\n\n exitFullscreen(visibleCountWhenCollapsed?: number): void {\n this.isFullscreen = false;\n // Also collapse when exiting fullscreen\n this.expandedId = null;\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n this.notify();\n }\n\n // Error footer methods (for non-interactive mode)\n toggleErrorFooter(): void {\n this.errorFooterExpanded = !this.errorFooterExpanded;\n this.notify();\n }\n\n expandErrorFooter(): void {\n if (!this.errorFooterExpanded) {\n this.errorFooterExpanded = true;\n this.notify();\n }\n }\n\n // === NAVIGATION: List (delegates to listNav) ===\n\n selectNext(visibleCount?: number): void {\n this.listNav.down();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPrev(visibleCount?: number): void {\n this.listNav.up();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPageDown(pageSize: number, visibleCount?: number): void {\n this.listNav.pageDown(pageSize, visibleCount);\n }\n\n selectPageUp(pageSize: number, visibleCount?: number): void {\n this.listNav.pageUp(pageSize, visibleCount);\n }\n\n selectFirst(visibleCount?: number): void {\n this.listNav.toStart();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectLast(visibleCount?: number): void {\n this.listNav.toEnd();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n clampListViewport(visibleCount: number): void {\n const changed = this.listNav.clampViewport(visibleCount);\n if (changed) {\n this.notify();\n }\n }\n\n // === NAVIGATION: Expanded content (delegates to process.scrollNav) ===\n\n private getExpandedNav(): { nav: Navigator; id: string } | undefined {\n if (!this.expandedId) return undefined;\n const nav = this.getProcess(this.expandedId)?.scrollNav;\n if (!nav) return undefined;\n return { nav, id: this.expandedId };\n }\n\n scrollDown(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - maxVisible);\n\n // Only scroll if not at bottom\n if (expanded.nav.position < maxOffset) {\n expanded.nav.down();\n }\n }\n\n scrollUp(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n if (expanded.nav.position > 0) {\n expanded.nav.up();\n }\n }\n\n scrollPageDown(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - pageSize);\n\n // Clamp to max offset\n const newPosition = Math.min(expanded.nav.position + pageSize, maxOffset);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollPageUp(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const newPosition = Math.max(0, expanded.nav.position - pageSize);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollToTop(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n expanded.nav.toStart();\n }\n\n scrollToBottom(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const newPosition = Math.max(0, lineCount - maxVisible);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n // === EXPANSION ===\n\n toggleExpand(visibleCountWhenExpanded?: number, visibleCountWhenCollapsed?: number): void {\n const selected = this.getSelectedProcess();\n if (!selected) return;\n\n if (this.expandedId === selected.id) {\n // Collapse (keep scroll position for later)\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n } else {\n // Expand (scroll position is preserved in process.scrollNav)\n this.expandedId = selected.id;\n // Adjust list scroll to keep expanded process visible\n if (visibleCountWhenExpanded) {\n this.listNav.ensureVisible(visibleCountWhenExpanded);\n }\n }\n this.notify();\n }\n\n collapse(visibleCountWhenCollapsed?: number): void {\n // Collapse but keep scroll position in process\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n this.notify();\n }\n\n // === EXIT ===\n\n signalExit(callback: () => void): void {\n this.shouldExit = true;\n this.exitCallback = callback;\n this.notify();\n }\n\n getShouldExit = (): boolean => this.shouldExit;\n getExitCallback = (): (() => void) | null => this.exitCallback;\n\n // === RESET ===\n\n reset(): void {\n // Dispose terminal buffers before clearing\n for (const process of this.processes) {\n process.terminalBuffer?.dispose();\n }\n this.processes = [];\n this.completedIds = [];\n this.shouldExit = false;\n this.exitCallback = null;\n this.mode = 'normal';\n this.listNav.reset();\n this.expandedId = null;\n this.errorFooterExpanded = false;\n this.filterMode = 'all';\n this.searchTerm = '';\n this.isSearching = false;\n this.isFullscreen = false;\n this.header = undefined;\n }\n\n // === INFRASTRUCTURE ===\n\n notify(): void {\n this.bufferVersion++;\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\n// Note: No global singleton - session creates its own store instance\n"],"names":["ProcessStore","FILTER_CYCLE","options","processes","completedIds","mode","expandedId","errorFooterExpanded","filterMode","searchTerm","isSearching","isFullscreen","showStatusBar","isInteractive","listeners","Set","shouldExit","exitCallback","bufferVersion","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","p","state","getCompletedProcesses","map","id","arrayFind","undefined","getFailedProcesses","getRunningCount","length","getMaxGroupLength","Math","DEFAULT_COLUMN_WIDTH","max","group","title","getDoneCount","getErrorCount","getErrorLineCount","reduce","total","getProcessLineCount","getMode","getSelectedIndex","listNav","position","getExpandedId","getListScrollOffset","viewportOffset","getErrorFooterExpanded","getBufferVersion","getFilterMode","getSearchTerm","getIsSearching","getIsFullscreen","getFilteredProcesses","filtered","term","toLowerCase","includes","getScrollOffset","process","getProcess","scrollNav","getHeader","header","getShowStatusBar","getIsInteractive","isAllComplete","every","getShouldExit","getExitCallback","interactive","createNavigator","getLength","wrap","onMove","notify","getErrorLines","processName","lines","getProcessLines","addProcess","processWithNav","updateProcess","update","oldProcess","wasRunning","isNowComplete","appendLines","newLines","concat","terminalBuffer","getLines","text","type","LineType","stdout","lineCount","setMode","setPosition","getSelectedProcess","cycleFilterNext","currentIndex","indexOf","toStart","cycleFilterPrev","startSearch","updateSearchTerm","cancelSearch","confirmSearch","clearSearch","enterFullscreen","selected","exitFullscreen","visibleCountWhenCollapsed","clampViewport","toggleErrorFooter","expandErrorFooter","selectNext","visibleCount","down","ensureVisible","selectPrev","up","selectPageDown","pageSize","pageDown","selectPageUp","pageUp","selectFirst","selectLast","toEnd","clampListViewport","changed","getExpandedNav","nav","scrollDown","maxVisible","expanded","maxOffset","scrollUp","scrollPageDown","newPosition","min","scrollPageUp","scrollToTop","scrollToBottom","toggleExpand","visibleCountWhenExpanded","collapse","signalExit","callback","reset","dispose","forEach","l"],"mappings":"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"}
|
package/dist/cjs/types.js
CHANGED
|
@@ -12,4 +12,4 @@ var LineType = {
|
|
|
12
12
|
stdout: 1,
|
|
13
13
|
stderr: 2
|
|
14
14
|
};
|
|
15
|
-
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (
|
|
15
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/addLines.ts"],"sourcesContent":["import { Writable } from 'stream';\nimport { BATCH_MAX_LINES, BATCH_MAX_WAIT_MS } from '../constants.ts';\n\nconst REGEX_NEW_LINE = /\\r?\\n|\\r/g;\n\nexport type Callback = (lines: string[]) =>
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/addLines.ts"],"sourcesContent":["import { Writable } from 'stream';\nimport { BATCH_MAX_LINES, BATCH_MAX_WAIT_MS } from '../constants.ts';\n\nconst REGEX_NEW_LINE = /\\r?\\n|\\r/g;\n\nexport type Callback = (lines: string[]) => void;\n\ninterface BatchOptions {\n maxLines?: number;\n maxWait?: number;\n}\n\nexport default function addLines(fn: Callback, options: BatchOptions = {}): Writable {\n const { maxLines = BATCH_MAX_LINES, maxWait = BATCH_MAX_WAIT_MS } = options;\n\n let last = '';\n let lineBuffer: string[] = [];\n let flushTimer: NodeJS.Timeout | null = null;\n\n const flush = () => {\n if (flushTimer) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n if (lineBuffer.length > 0) {\n fn(lineBuffer);\n lineBuffer = [];\n }\n };\n\n const scheduleFlush = () => {\n if (!flushTimer) {\n flushTimer = setTimeout(flush, maxWait);\n }\n };\n\n const stream = new Writable({\n write(chunk, _enc, callback) {\n const more = last + chunk.toString('utf8');\n const lines = more.split(REGEX_NEW_LINE);\n last = lines.pop();\n\n if (lines.length > 0) {\n lineBuffer.push(...lines);\n\n // Flush immediately if buffer is large enough\n if (lineBuffer.length >= maxLines) {\n flush();\n } else {\n scheduleFlush();\n }\n }\n callback();\n },\n });\n\n stream.on('finish', () => {\n // Flush any remaining buffered lines\n if (last.length) lineBuffer.push(last);\n flush();\n last = '';\n });\n\n return stream;\n}\n"],"names":["Writable","BATCH_MAX_LINES","BATCH_MAX_WAIT_MS","REGEX_NEW_LINE","addLines","fn","options","maxLines","maxWait","last","lineBuffer","flushTimer","flush","clearTimeout","length","scheduleFlush","setTimeout","stream","write","chunk","_enc","callback","more","toString","lines","split","pop","push","on"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,SAAS;AAClC,SAASC,eAAe,EAAEC,iBAAiB,QAAQ,kBAAkB;AAErE,MAAMC,iBAAiB;AASvB,eAAe,SAASC,SAASC,EAAY,EAAEC,UAAwB,CAAC,CAAC;IACvE,MAAM,EAAEC,WAAWN,eAAe,EAAEO,UAAUN,iBAAiB,EAAE,GAAGI;IAEpE,IAAIG,OAAO;IACX,IAAIC,aAAuB,EAAE;IAC7B,IAAIC,aAAoC;IAExC,MAAMC,QAAQ;QACZ,IAAID,YAAY;YACdE,aAAaF;YACbA,aAAa;QACf;QACA,IAAID,WAAWI,MAAM,GAAG,GAAG;YACzBT,GAAGK;YACHA,aAAa,EAAE;QACjB;IACF;IAEA,MAAMK,gBAAgB;QACpB,IAAI,CAACJ,YAAY;YACfA,aAAaK,WAAWJ,OAAOJ;QACjC;IACF;IAEA,MAAMS,SAAS,IAAIjB,SAAS;QAC1BkB,OAAMC,KAAK,EAAEC,IAAI,EAAEC,QAAQ;YACzB,MAAMC,OAAOb,OAAOU,MAAMI,QAAQ,CAAC;YACnC,MAAMC,QAAQF,KAAKG,KAAK,CAACtB;YACzBM,OAAOe,MAAME,GAAG;YAEhB,IAAIF,MAAMV,MAAM,GAAG,GAAG;gBACpBJ,WAAWiB,IAAI,IAAIH;gBAEnB,8CAA8C;gBAC9C,IAAId,WAAWI,MAAM,IAAIP,UAAU;oBACjCK;gBACF,OAAO;oBACLG;gBACF;YACF;YACAM;QACF;IACF;IAEAJ,OAAOW,EAAE,CAAC,UAAU;QAClB,qCAAqC;QACrC,IAAInB,KAAKK,MAAM,EAAEJ,WAAWiB,IAAI,CAAClB;QACjCG;QACAH,OAAO;IACT;IAEA,OAAOQ;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/concatWritable.ts"],"sourcesContent":["import Stream from 'stream';\n\nconst Writable = Stream.Writable;\n\nexport type Callback = (lines: Buffer) =>
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/concatWritable.ts"],"sourcesContent":["import Stream from 'stream';\n\nconst Writable = Stream.Writable;\n\nexport type Callback = (lines: Buffer) => void;\n\nexport default function concatWritable(callback: Callback): NodeJS.WritableStream {\n const chunks = [];\n const stream = new Writable({\n write: (chunk, _encoding, next) => {\n chunks.push(chunk);\n next();\n },\n });\n stream.on('finish', () => callback(Buffer.concat(chunks.splice(0))));\n return stream;\n}\n"],"names":["Stream","Writable","concatWritable","callback","chunks","stream","write","chunk","_encoding","next","push","on","Buffer","concat","splice"],"mappings":"AAAA,OAAOA,YAAY,SAAS;AAE5B,MAAMC,WAAWD,OAAOC,QAAQ;AAIhC,eAAe,SAASC,eAAeC,QAAkB;IACvD,MAAMC,SAAS,EAAE;IACjB,MAAMC,SAAS,IAAIJ,SAAS;QAC1BK,OAAO,CAACC,OAAOC,WAAWC;YACxBL,OAAOM,IAAI,CAACH;YACZE;QACF;IACF;IACAJ,OAAOM,EAAE,CAAC,UAAU,IAAMR,SAASS,OAAOC,MAAM,CAACT,OAAOU,MAAM,CAAC;IAC/D,OAAOT;AACT"}
|
package/dist/esm/session.js
CHANGED
|
@@ -215,6 +215,7 @@ let SessionImpl = class SessionImpl {
|
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
constructor(options = {}){
|
|
218
|
+
var _options_interactive;
|
|
218
219
|
this.inkApp = null;
|
|
219
220
|
this.runningCount = 0;
|
|
220
221
|
this.closed = false;
|
|
@@ -232,7 +233,6 @@ let SessionImpl = class SessionImpl {
|
|
|
232
233
|
maxFps: DEFAULT_MAX_FPS
|
|
233
234
|
});
|
|
234
235
|
}
|
|
235
|
-
var _options_interactive;
|
|
236
236
|
// Interactive mode requires a TTY to capture user input (e.g., press 'q' to quit)
|
|
237
237
|
// Force non-interactive when no UI is rendered, otherwise waitAndClose would hang
|
|
238
238
|
this.isInteractive = this.inkApp ? (_options_interactive = options.interactive) !== null && _options_interactive !== void 0 ? _options_interactive : false : false;
|
package/dist/esm/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/session.tsx"],"sourcesContent":["import spawn, { crossSpawn, type SpawnResult } from 'cross-spawn-cb';\nimport crypto from 'crypto';\nimport { render } from 'ink';\nimport oo from 'on-one';\nimport Queue from 'queue-cb';\n\nimport App from './components/App.ts';\nimport { DEFAULT_MAX_FPS } from './constants.ts';\nimport concatWritable from './lib/concatWritable.ts';\nimport formatArguments from './lib/formatArguments.ts';\nimport { TerminalBuffer } from './lib/TerminalBuffer.ts';\nimport { ProcessStore } from './state/processStore.ts';\nimport type { ProcessOptions, SessionOptions, SpawnError, SpawnOptions, TerminalCallback } from './types.ts';\n\nexport interface Session {\n spawn(command: string, args: string[], spawnOptions: SpawnOptions, options: ProcessOptions, callback: TerminalCallback): void;\n close(): void;\n waitAndClose(callback?: () => void): void;\n}\n\nclass SessionImpl implements Session {\n private store: ProcessStore;\n private inkApp: ReturnType<typeof render> | null = null;\n private runningCount = 0;\n private closed = false;\n private waitCallbacks: (() => void)[] = [];\n private isInteractive: boolean;\n private terminalWidth: number;\n\n constructor(options: SessionOptions = {}) {\n this.store = new ProcessStore(options);\n // Use a very wide buffer to prevent line wrapping in xterm\n // Actual display truncation is handled by Ink components\n this.terminalWidth = 10000;\n\n // Only render Ink when stdout is a real terminal\n // When piped (e.g., nested spawn-term), skip Ink to avoid cursor positioning artifacts\n if (process.stdout.isTTY) {\n this.inkApp = render(<App store={this.store} />, {\n maxFps: DEFAULT_MAX_FPS,\n });\n }\n\n // Interactive mode requires a TTY to capture user input (e.g., press 'q' to quit)\n // Force non-interactive when no UI is rendered, otherwise waitAndClose would hang\n this.isInteractive = this.inkApp ? (options.interactive ?? false) : false;\n }\n\n spawn(command: string, args: string[], spawnOptions: SpawnOptions, options: ProcessOptions, callback: TerminalCallback): void {\n if (this.closed) {\n throw new Error('Session is closed');\n }\n\n const { encoding, stdio, ...csOptions } = spawnOptions;\n\n if (stdio === 'inherit') {\n // When Ink is not rendering (stdout not a TTY), pass output directly to stdout\n if (!this.inkApp) {\n const cp = crossSpawn(command, args, { ...csOptions, stdio: 'inherit' });\n spawn.worker(cp, csOptions, (err?: SpawnError) => {\n const res = (err ? err : {}) as SpawnResult;\n res.stdout = null;\n res.stderr = null;\n res.output = [null, null, null];\n err ? callback(err) : callback(null, res);\n });\n return;\n }\n\n this.runningCount++;\n const id = crypto.randomUUID();\n\n // Create terminal buffer for ANSI sequence interpretation\n const terminalBuffer = new TerminalBuffer(this.terminalWidth);\n\n this.store.addProcess({\n id,\n title: [command].concat(formatArguments(args)).join(' '),\n state: 'running',\n lines: [],\n terminalBuffer,\n group: options.group,\n expanded: options.expanded,\n });\n\n const cp = crossSpawn(command, args, csOptions);\n\n // Pipe stdout and stderr directly to terminal buffer\n // Both streams go to the same buffer to maintain correct ordering\n if (cp.stdout) {\n cp.stdout.on('data', (chunk: Buffer) => {\n terminalBuffer.write(chunk);\n this.store.notify();\n });\n }\n if (cp.stderr) {\n cp.stderr.on('data', (chunk: Buffer) => {\n terminalBuffer.write(chunk);\n this.store.notify();\n });\n }\n\n // Wait for process to complete\n const queue = new Queue();\n if (cp.stdout) {\n queue.defer(oo.bind(null, cp.stdout, ['error', 'end', 'close']));\n }\n if (cp.stderr) {\n queue.defer(oo.bind(null, cp.stderr, ['error', 'end', 'close']));\n }\n queue.defer(spawn.worker.bind(null, cp, csOptions));\n queue.await((err?: SpawnError) => {\n const res = (err ? err : {}) as SpawnResult;\n res.stdout = null; // Not collecting raw output in inherit mode\n res.stderr = null;\n res.output = [null, null, null];\n this.store.updateProcess(id, { state: err ? 'error' : 'success' });\n\n this.onProcessComplete();\n err ? callback(err) : callback(null, res);\n });\n } else {\n // Non-inherit mode: collect output but don't display in UI\n const cp = crossSpawn(command, args, csOptions);\n const outputs = { stdout: null as ReturnType<typeof concatWritable> | null, stderr: null as ReturnType<typeof concatWritable> | null };\n\n const queue = new Queue();\n if (cp.stdout) {\n outputs.stdout = concatWritable((output) => {\n (outputs.stdout as unknown as { output: string }).output = output.toString(encoding || 'utf8');\n });\n queue.defer(oo.bind(null, cp.stdout.pipe(outputs.stdout), ['error', 'end', 'close', 'finish']));\n }\n if (cp.stderr) {\n outputs.stderr = concatWritable((output) => {\n (outputs.stderr as unknown as { output: string }).output = output.toString(encoding || 'utf8');\n });\n queue.defer(oo.bind(null, cp.stderr.pipe(outputs.stderr), ['error', 'end', 'close', 'finish']));\n }\n queue.defer(spawn.worker.bind(null, cp, csOptions));\n queue.await((err?: SpawnError) => {\n const res = (err ? err : {}) as SpawnResult;\n res.stdout = outputs.stdout ? (outputs.stdout as unknown as { output: string }).output : null;\n res.stderr = outputs.stderr ? (outputs.stderr as unknown as { output: string }).output : null;\n res.output = [res.stdout, res.stderr, null];\n err ? callback(err) : callback(null, res);\n });\n }\n }\n\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.cleanup();\n }\n\n waitAndClose(callback?: () => void): void {\n if (this.closed) {\n callback?.();\n return;\n }\n\n if (callback) this.waitCallbacks.push(callback);\n\n if (this.runningCount === 0) {\n if (this.isInteractive) {\n // In interactive mode, wait for user to quit (press 'q')\n const unsubscribe = this.store.subscribe(() => {\n if (this.store.getShouldExit()) {\n unsubscribe();\n this.closeAndCallWaitCallbacks();\n }\n });\n } else {\n this.closeAndCallWaitCallbacks();\n }\n }\n // If runningCount > 0, will close when it hits 0 in onProcessComplete\n }\n\n private onProcessComplete(): void {\n this.runningCount--;\n if (this.runningCount === 0 && this.waitCallbacks.length > 0) {\n if (this.isInteractive) {\n // In interactive mode, wait for user to quit (press 'q')\n const unsubscribe = this.store.subscribe(() => {\n if (this.store.getShouldExit()) {\n unsubscribe();\n this.closeAndCallWaitCallbacks();\n }\n });\n } else {\n this.closeAndCallWaitCallbacks();\n }\n }\n }\n\n private closeAndCallWaitCallbacks(): void {\n if (this.closed) return;\n this.closed = true;\n this.cleanup(() => {\n for (const cb of this.waitCallbacks) cb();\n this.waitCallbacks = [];\n });\n }\n\n private cleanup(onComplete?: () => void): void {\n // Signal exit to React component\n this.store.signalExit(() => {\n this.store.reset();\n process.stdout.write('\\x1b[?25h'); // show cursor\n });\n\n // Wait for Ink to finish\n if (this.inkApp) {\n this.inkApp\n .waitUntilExit()\n .then(() => {\n const cb = this.store.getExitCallback();\n cb?.();\n onComplete?.();\n })\n .catch(() => {\n const cb = this.store.getExitCallback();\n cb?.();\n onComplete?.();\n });\n this.inkApp = null;\n } else {\n onComplete?.();\n }\n }\n}\n\nexport function createSession(options: SessionOptions = {}): Session {\n return new SessionImpl(options);\n}\n"],"names":["spawn","crossSpawn","crypto","render","oo","Queue","App","DEFAULT_MAX_FPS","concatWritable","formatArguments","TerminalBuffer","ProcessStore","SessionImpl","command","args","spawnOptions","options","callback","closed","Error","encoding","stdio","csOptions","inkApp","cp","worker","err","res","stdout","stderr","output","runningCount","id","randomUUID","terminalBuffer","terminalWidth","store","addProcess","title","concat","join","state","lines","group","expanded","on","chunk","write","notify","queue","defer","bind","await","updateProcess","onProcessComplete","outputs","toString","pipe","close","cleanup","waitAndClose","waitCallbacks","push","isInteractive","unsubscribe","subscribe","getShouldExit","closeAndCallWaitCallbacks","length","cb","onComplete","signalExit","reset","process","waitUntilExit","then","getExitCallback","catch","isTTY","maxFps","interactive","createSession"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/session.tsx"],"sourcesContent":["import spawn, { crossSpawn, type SpawnResult } from 'cross-spawn-cb';\nimport crypto from 'crypto';\nimport { render } from 'ink';\nimport oo from 'on-one';\nimport Queue from 'queue-cb';\n\nimport App from './components/App.ts';\nimport { DEFAULT_MAX_FPS } from './constants.ts';\nimport concatWritable from './lib/concatWritable.ts';\nimport formatArguments from './lib/formatArguments.ts';\nimport { TerminalBuffer } from './lib/TerminalBuffer.ts';\nimport { ProcessStore } from './state/processStore.ts';\nimport type { ProcessOptions, SessionOptions, SpawnError, SpawnOptions, TerminalCallback } from './types.ts';\n\nexport interface Session {\n spawn(command: string, args: string[], spawnOptions: SpawnOptions, options: ProcessOptions, callback: TerminalCallback): void;\n close(): void;\n waitAndClose(callback?: () => void): void;\n}\n\nclass SessionImpl implements Session {\n private store: ProcessStore;\n private inkApp: ReturnType<typeof render> | null = null;\n private runningCount = 0;\n private closed = false;\n private waitCallbacks: (() => void)[] = [];\n private isInteractive: boolean;\n private terminalWidth: number;\n\n constructor(options: SessionOptions = {}) {\n this.store = new ProcessStore(options);\n // Use a very wide buffer to prevent line wrapping in xterm\n // Actual display truncation is handled by Ink components\n this.terminalWidth = 10000;\n\n // Only render Ink when stdout is a real terminal\n // When piped (e.g., nested spawn-term), skip Ink to avoid cursor positioning artifacts\n if (process.stdout.isTTY) {\n this.inkApp = render(<App store={this.store} />, {\n maxFps: DEFAULT_MAX_FPS,\n });\n }\n\n // Interactive mode requires a TTY to capture user input (e.g., press 'q' to quit)\n // Force non-interactive when no UI is rendered, otherwise waitAndClose would hang\n this.isInteractive = this.inkApp ? (options.interactive ?? false) : false;\n }\n\n spawn(command: string, args: string[], spawnOptions: SpawnOptions, options: ProcessOptions, callback: TerminalCallback): void {\n if (this.closed) {\n throw new Error('Session is closed');\n }\n\n const { encoding, stdio, ...csOptions } = spawnOptions;\n\n if (stdio === 'inherit') {\n // When Ink is not rendering (stdout not a TTY), pass output directly to stdout\n if (!this.inkApp) {\n const cp = crossSpawn(command, args, { ...csOptions, stdio: 'inherit' });\n spawn.worker(cp, csOptions, (err?: SpawnError) => {\n const res = (err ? err : {}) as SpawnResult;\n res.stdout = null;\n res.stderr = null;\n res.output = [null, null, null];\n err ? callback(err) : callback(null, res);\n });\n return;\n }\n\n this.runningCount++;\n const id = crypto.randomUUID();\n\n // Create terminal buffer for ANSI sequence interpretation\n const terminalBuffer = new TerminalBuffer(this.terminalWidth);\n\n this.store.addProcess({\n id,\n title: [command].concat(formatArguments(args)).join(' '),\n state: 'running',\n lines: [],\n terminalBuffer,\n group: options.group,\n expanded: options.expanded,\n });\n\n const cp = crossSpawn(command, args, csOptions);\n\n // Pipe stdout and stderr directly to terminal buffer\n // Both streams go to the same buffer to maintain correct ordering\n if (cp.stdout) {\n cp.stdout.on('data', (chunk: Buffer) => {\n terminalBuffer.write(chunk);\n this.store.notify();\n });\n }\n if (cp.stderr) {\n cp.stderr.on('data', (chunk: Buffer) => {\n terminalBuffer.write(chunk);\n this.store.notify();\n });\n }\n\n // Wait for process to complete\n const queue = new Queue();\n if (cp.stdout) {\n queue.defer(oo.bind(null, cp.stdout, ['error', 'end', 'close']));\n }\n if (cp.stderr) {\n queue.defer(oo.bind(null, cp.stderr, ['error', 'end', 'close']));\n }\n queue.defer(spawn.worker.bind(null, cp, csOptions));\n queue.await((err?: SpawnError) => {\n const res = (err ? err : {}) as SpawnResult;\n res.stdout = null; // Not collecting raw output in inherit mode\n res.stderr = null;\n res.output = [null, null, null];\n this.store.updateProcess(id, { state: err ? 'error' : 'success' });\n\n this.onProcessComplete();\n err ? callback(err) : callback(null, res);\n });\n } else {\n // Non-inherit mode: collect output but don't display in UI\n const cp = crossSpawn(command, args, csOptions);\n const outputs = { stdout: null as ReturnType<typeof concatWritable> | null, stderr: null as ReturnType<typeof concatWritable> | null };\n\n const queue = new Queue();\n if (cp.stdout) {\n outputs.stdout = concatWritable((output) => {\n (outputs.stdout as unknown as { output: string }).output = output.toString(encoding || 'utf8');\n });\n queue.defer(oo.bind(null, cp.stdout.pipe(outputs.stdout), ['error', 'end', 'close', 'finish']));\n }\n if (cp.stderr) {\n outputs.stderr = concatWritable((output) => {\n (outputs.stderr as unknown as { output: string }).output = output.toString(encoding || 'utf8');\n });\n queue.defer(oo.bind(null, cp.stderr.pipe(outputs.stderr), ['error', 'end', 'close', 'finish']));\n }\n queue.defer(spawn.worker.bind(null, cp, csOptions));\n queue.await((err?: SpawnError) => {\n const res = (err ? err : {}) as SpawnResult;\n res.stdout = outputs.stdout ? (outputs.stdout as unknown as { output: string }).output : null;\n res.stderr = outputs.stderr ? (outputs.stderr as unknown as { output: string }).output : null;\n res.output = [res.stdout, res.stderr, null];\n err ? callback(err) : callback(null, res);\n });\n }\n }\n\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.cleanup();\n }\n\n waitAndClose(callback?: () => void): void {\n if (this.closed) {\n callback?.();\n return;\n }\n\n if (callback) this.waitCallbacks.push(callback);\n\n if (this.runningCount === 0) {\n if (this.isInteractive) {\n // In interactive mode, wait for user to quit (press 'q')\n const unsubscribe = this.store.subscribe(() => {\n if (this.store.getShouldExit()) {\n unsubscribe();\n this.closeAndCallWaitCallbacks();\n }\n });\n } else {\n this.closeAndCallWaitCallbacks();\n }\n }\n // If runningCount > 0, will close when it hits 0 in onProcessComplete\n }\n\n private onProcessComplete(): void {\n this.runningCount--;\n if (this.runningCount === 0 && this.waitCallbacks.length > 0) {\n if (this.isInteractive) {\n // In interactive mode, wait for user to quit (press 'q')\n const unsubscribe = this.store.subscribe(() => {\n if (this.store.getShouldExit()) {\n unsubscribe();\n this.closeAndCallWaitCallbacks();\n }\n });\n } else {\n this.closeAndCallWaitCallbacks();\n }\n }\n }\n\n private closeAndCallWaitCallbacks(): void {\n if (this.closed) return;\n this.closed = true;\n this.cleanup(() => {\n for (const cb of this.waitCallbacks) cb();\n this.waitCallbacks = [];\n });\n }\n\n private cleanup(onComplete?: () => void): void {\n // Signal exit to React component\n this.store.signalExit(() => {\n this.store.reset();\n process.stdout.write('\\x1b[?25h'); // show cursor\n });\n\n // Wait for Ink to finish\n if (this.inkApp) {\n this.inkApp\n .waitUntilExit()\n .then(() => {\n const cb = this.store.getExitCallback();\n cb?.();\n onComplete?.();\n })\n .catch(() => {\n const cb = this.store.getExitCallback();\n cb?.();\n onComplete?.();\n });\n this.inkApp = null;\n } else {\n onComplete?.();\n }\n }\n}\n\nexport function createSession(options: SessionOptions = {}): Session {\n return new SessionImpl(options);\n}\n"],"names":["spawn","crossSpawn","crypto","render","oo","Queue","App","DEFAULT_MAX_FPS","concatWritable","formatArguments","TerminalBuffer","ProcessStore","SessionImpl","command","args","spawnOptions","options","callback","closed","Error","encoding","stdio","csOptions","inkApp","cp","worker","err","res","stdout","stderr","output","runningCount","id","randomUUID","terminalBuffer","terminalWidth","store","addProcess","title","concat","join","state","lines","group","expanded","on","chunk","write","notify","queue","defer","bind","await","updateProcess","onProcessComplete","outputs","toString","pipe","close","cleanup","waitAndClose","waitCallbacks","push","isInteractive","unsubscribe","subscribe","getShouldExit","closeAndCallWaitCallbacks","length","cb","onComplete","signalExit","reset","process","waitUntilExit","then","getExitCallback","catch","isTTY","maxFps","interactive","createSession"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type Callback = (lines: Buffer) =>
|
|
1
|
+
export type Callback = (lines: Buffer) => void;
|
|
2
2
|
export default function concatWritable(callback: Callback): NodeJS.WritableStream;
|
|
@@ -339,6 +339,7 @@ export class ProcessStore {
|
|
|
339
339
|
});
|
|
340
340
|
}
|
|
341
341
|
constructor(options = {}){
|
|
342
|
+
var _options_showStatusBar, _options_interactive;
|
|
342
343
|
// === DATA: Process collection ===
|
|
343
344
|
this.processes = [];
|
|
344
345
|
this.completedIds = []; // Track completion order
|
|
@@ -420,11 +421,11 @@ export class ProcessStore {
|
|
|
420
421
|
};
|
|
421
422
|
// Get scroll offset for expanded process (or 0 if none)
|
|
422
423
|
this.getScrollOffset = ()=>{
|
|
424
|
+
var _ref;
|
|
423
425
|
var _process_scrollNav;
|
|
424
426
|
if (!this.expandedId) return 0;
|
|
425
427
|
const process = this.getProcess(this.expandedId);
|
|
426
|
-
|
|
427
|
-
return (_process_scrollNav_position = process === null || process === void 0 ? void 0 : (_process_scrollNav = process.scrollNav) === null || _process_scrollNav === void 0 ? void 0 : _process_scrollNav.position) !== null && _process_scrollNav_position !== void 0 ? _process_scrollNav_position : 0;
|
|
428
|
+
return (_ref = process === null || process === void 0 ? void 0 : (_process_scrollNav = process.scrollNav) === null || _process_scrollNav === void 0 ? void 0 : _process_scrollNav.position) !== null && _ref !== void 0 ? _ref : 0;
|
|
428
429
|
};
|
|
429
430
|
// Session-level getters (set at session creation, immutable)
|
|
430
431
|
this.getHeader = ()=>this.header;
|
|
@@ -434,9 +435,7 @@ export class ProcessStore {
|
|
|
434
435
|
this.getShouldExit = ()=>this.shouldExit;
|
|
435
436
|
this.getExitCallback = ()=>this.exitCallback;
|
|
436
437
|
this.header = options.header;
|
|
437
|
-
var _options_showStatusBar;
|
|
438
438
|
this.showStatusBar = (_options_showStatusBar = options.showStatusBar) !== null && _options_showStatusBar !== void 0 ? _options_showStatusBar : false;
|
|
439
|
-
var _options_interactive;
|
|
440
439
|
this.isInteractive = (_options_interactive = options.interactive) !== null && _options_interactive !== void 0 ? _options_interactive : false;
|
|
441
440
|
// Create list navigator with wrap-around behavior
|
|
442
441
|
// Uses filtered processes count so selection works correctly with filters
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import { arrayFind } from '../compat.ts';\nimport { DEFAULT_COLUMN_WIDTH } from '../constants.ts';\nimport type { ChildProcess, Line, SessionOptions } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport { createNavigator, type Navigator } from './Navigator.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive';\ntype FilterMode = 'all' | 'running' | 'finished' | 'failed';\n\nconst FILTER_CYCLE: FilterMode[] = ['all', 'running', 'finished', 'failed'];\n\nexport class ProcessStore {\n // === DATA: Process collection ===\n private processes: ChildProcess[] = [];\n private completedIds: string[] = []; // Track completion order\n\n // === NAVIGATION: List cursor ===\n private listNav: Navigator;\n\n // === VIEW STATE ===\n private mode: Mode = 'normal';\n private expandedId: string | null = null;\n private errorFooterExpanded = false; // For non-interactive error footer\n private filterMode: FilterMode = 'all';\n private searchTerm = '';\n private isSearching = false;\n private isFullscreen = false;\n\n // === SESSION CONFIG (immutable after construction) ===\n private header: string | undefined;\n private showStatusBar = false;\n private isInteractive = false;\n\n // === INFRASTRUCTURE ===\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\n private bufferVersion = 0; // Increments on every notify() to trigger re-renders\n\n constructor(options: SessionOptions = {}) {\n this.header = options.header;\n this.showStatusBar = options.showStatusBar ?? false;\n this.isInteractive = options.interactive ?? false;\n\n // Create list navigator with wrap-around behavior\n // Uses filtered processes count so selection works correctly with filters\n this.listNav = createNavigator({\n getLength: () => this.getFilteredProcesses().length,\n wrap: true,\n onMove: () => this.notify(),\n });\n }\n\n // === SUBSCRIPTION API (useSyncExternalStore) ===\n\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n getSnapshot = (): ChildProcess[] => this.processes;\n\n // === DATA: Queries ===\n\n getRunningProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'running');\n };\n\n getCompletedProcesses = (): ChildProcess[] => {\n // Return in completion order\n return this.completedIds.map((id) => arrayFind(this.processes, (p) => p.id === id)).filter((p): p is ChildProcess => p !== undefined);\n };\n\n getFailedProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'error');\n };\n\n // Counts\n getRunningCount = (): number => this.processes.filter((p) => p.state === 'running').length;\n getMaxGroupLength = (): number => {\n if (this.processes.length === 0) return DEFAULT_COLUMN_WIDTH;\n return Math.max(...this.processes.map((p) => (p.group || p.title).length));\n };\n getDoneCount = (): number => this.processes.filter((p) => p.state !== 'running').length;\n getErrorCount = (): number => this.processes.filter((p) => p.state === 'error').length;\n getErrorLineCount = (): number => {\n return this.processes.filter((p) => p.state === 'error').reduce((total, p) => total + this.getProcessLineCount(p.id), 0);\n };\n\n getErrorLines(): Array<{ processName: string; lines: Line[] }> {\n return this.getFailedProcesses().map((p) => ({\n processName: p.group || p.title,\n lines: this.getProcessLines(p.id),\n }));\n }\n\n // === DATA: Mutations ===\n\n addProcess(process: ChildProcess): void {\n // Create scroll navigator for this process\n const processWithNav: ChildProcess = {\n ...process,\n scrollNav: createNavigator({\n getLength: () => this.getProcessLineCount(processWithNav.id),\n wrap: false,\n onMove: () => this.notify(),\n }),\n };\n this.processes = [...this.processes, processWithNav];\n this.notify();\n }\n\n updateProcess(id: string, update: Partial<ChildProcess>): void {\n const oldProcess = arrayFind(this.processes, (p) => p.id === id);\n const wasRunning = oldProcess?.state === 'running';\n const isNowComplete = update.state && update.state !== 'running';\n\n this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\n\n // Track completion order\n if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {\n this.completedIds = [...this.completedIds, id];\n }\n\n // Auto-expand error footer when all complete with errors (non-interactive only)\n if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {\n this.errorFooterExpanded = true;\n }\n\n this.notify();\n }\n\n appendLines(id: string, newLines: Line[]): void {\n const process = arrayFind(this.processes, (p) => p.id === id);\n if (process) {\n this.updateProcess(id, { lines: process.lines.concat(newLines) });\n }\n }\n\n getProcess(id: string): ChildProcess | undefined {\n return arrayFind(this.processes, (p) => p.id === id);\n }\n\n // Get rendered lines from terminal buffer or fallback to lines array\n getProcessLines(id: string): Line[] {\n const process = this.getProcess(id);\n if (!process) return [];\n if (process.terminalBuffer) {\n return process.terminalBuffer.getLines().map((text) => ({\n type: LineType.stdout,\n text,\n }));\n }\n return process.lines;\n }\n\n // Get line count from terminal buffer or lines array\n getProcessLineCount(id: string): number {\n const process = this.getProcess(id);\n if (!process) return 0;\n if (process.terminalBuffer) {\n return process.terminalBuffer.lineCount;\n }\n return process.lines.length;\n }\n\n // === VIEW STATE: Getters ===\n\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.listNav.position;\n getExpandedId = (): string | null => this.expandedId;\n getListScrollOffset = (): number => this.listNav.viewportOffset;\n getErrorFooterExpanded = (): boolean => this.errorFooterExpanded;\n getBufferVersion = (): number => this.bufferVersion;\n getFilterMode = (): FilterMode => this.filterMode;\n getSearchTerm = (): string => this.searchTerm;\n getIsSearching = (): boolean => this.isSearching;\n getIsFullscreen = (): boolean => this.isFullscreen;\n\n // Get processes filtered by current filter mode and search term\n getFilteredProcesses = (): ChildProcess[] => {\n let filtered = this.processes;\n\n // Apply filter mode\n switch (this.filterMode) {\n case 'running':\n filtered = filtered.filter((p) => p.state === 'running');\n break;\n case 'finished':\n filtered = filtered.filter((p) => p.state !== 'running');\n break;\n case 'failed':\n filtered = filtered.filter((p) => p.state === 'error');\n break;\n }\n\n // Apply search term\n if (this.searchTerm) {\n const term = this.searchTerm.toLowerCase();\n filtered = filtered.filter((p) => p.title.toLowerCase().includes(term) || (p.group && p.group.toLowerCase().includes(term)));\n }\n\n return filtered;\n };\n\n // Get scroll offset for expanded process (or 0 if none)\n getScrollOffset = (): number => {\n if (!this.expandedId) return 0;\n const process = this.getProcess(this.expandedId);\n return process?.scrollNav?.position ?? 0;\n };\n\n // Session-level getters (set at session creation, immutable)\n getHeader = (): string | undefined => this.header;\n getShowStatusBar = (): boolean => this.showStatusBar;\n getIsInteractive = (): boolean => this.isInteractive;\n isAllComplete = (): boolean => this.processes.length > 0 && this.processes.every((p) => p.state !== 'running');\n\n // === VIEW STATE: Mutations ===\n\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.listNav.setPosition(0);\n }\n this.notify();\n }\n\n getSelectedProcess(): ChildProcess | undefined {\n return this.getFilteredProcesses()[this.listNav.position];\n }\n\n // Filter mode cycling (left/right arrows)\n cycleFilterNext(): void {\n const currentIndex = FILTER_CYCLE.indexOf(this.filterMode);\n this.filterMode = FILTER_CYCLE[(currentIndex + 1) % FILTER_CYCLE.length] as FilterMode;\n // Reset selection when filter changes\n this.listNav.toStart();\n // Collapse any expanded process when filter changes\n this.expandedId = null;\n this.notify();\n }\n\n cycleFilterPrev(): void {\n const currentIndex = FILTER_CYCLE.indexOf(this.filterMode);\n this.filterMode = FILTER_CYCLE[(currentIndex - 1 + FILTER_CYCLE.length) % FILTER_CYCLE.length] as FilterMode;\n // Reset selection when filter changes\n this.listNav.toStart();\n // Collapse any expanded process when filter changes\n this.expandedId = null;\n this.notify();\n }\n\n // Search mode\n startSearch(): void {\n this.isSearching = true;\n this.searchTerm = '';\n this.notify();\n }\n\n updateSearchTerm(term: string): void {\n this.searchTerm = term;\n // Reset selection when search changes\n this.listNav.toStart();\n this.notify();\n }\n\n cancelSearch(): void {\n this.isSearching = false;\n this.searchTerm = '';\n // Reset selection\n this.listNav.toStart();\n this.notify();\n }\n\n confirmSearch(): void {\n this.isSearching = false;\n // Keep searchTerm applied, reset selection to first match\n this.listNav.toStart();\n this.notify();\n }\n\n clearSearch(): void {\n this.searchTerm = '';\n this.listNav.toStart();\n this.notify();\n }\n\n // Fullscreen mode (alternate screen buffer)\n enterFullscreen(): void {\n // If not expanded, expand the selected process first\n if (!this.expandedId) {\n const selected = this.getSelectedProcess();\n if (selected) {\n this.expandedId = selected.id;\n }\n }\n if (this.expandedId) {\n this.isFullscreen = true;\n this.notify();\n }\n }\n\n exitFullscreen(visibleCountWhenCollapsed?: number): void {\n this.isFullscreen = false;\n // Also collapse when exiting fullscreen\n this.expandedId = null;\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n this.notify();\n }\n\n // Error footer methods (for non-interactive mode)\n toggleErrorFooter(): void {\n this.errorFooterExpanded = !this.errorFooterExpanded;\n this.notify();\n }\n\n expandErrorFooter(): void {\n if (!this.errorFooterExpanded) {\n this.errorFooterExpanded = true;\n this.notify();\n }\n }\n\n // === NAVIGATION: List (delegates to listNav) ===\n\n selectNext(visibleCount?: number): void {\n this.listNav.down();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPrev(visibleCount?: number): void {\n this.listNav.up();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPageDown(pageSize: number, visibleCount?: number): void {\n this.listNav.pageDown(pageSize, visibleCount);\n }\n\n selectPageUp(pageSize: number, visibleCount?: number): void {\n this.listNav.pageUp(pageSize, visibleCount);\n }\n\n selectFirst(visibleCount?: number): void {\n this.listNav.toStart();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectLast(visibleCount?: number): void {\n this.listNav.toEnd();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n clampListViewport(visibleCount: number): void {\n const changed = this.listNav.clampViewport(visibleCount);\n if (changed) {\n this.notify();\n }\n }\n\n // === NAVIGATION: Expanded content (delegates to process.scrollNav) ===\n\n private getExpandedNav(): { nav: Navigator; id: string } | undefined {\n if (!this.expandedId) return undefined;\n const nav = this.getProcess(this.expandedId)?.scrollNav;\n if (!nav) return undefined;\n return { nav, id: this.expandedId };\n }\n\n scrollDown(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - maxVisible);\n\n // Only scroll if not at bottom\n if (expanded.nav.position < maxOffset) {\n expanded.nav.down();\n }\n }\n\n scrollUp(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n if (expanded.nav.position > 0) {\n expanded.nav.up();\n }\n }\n\n scrollPageDown(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - pageSize);\n\n // Clamp to max offset\n const newPosition = Math.min(expanded.nav.position + pageSize, maxOffset);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollPageUp(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const newPosition = Math.max(0, expanded.nav.position - pageSize);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollToTop(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n expanded.nav.toStart();\n }\n\n scrollToBottom(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const newPosition = Math.max(0, lineCount - maxVisible);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n // === EXPANSION ===\n\n toggleExpand(visibleCountWhenExpanded?: number, visibleCountWhenCollapsed?: number): void {\n const selected = this.getSelectedProcess();\n if (!selected) return;\n\n if (this.expandedId === selected.id) {\n // Collapse (keep scroll position for later)\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n } else {\n // Expand (scroll position is preserved in process.scrollNav)\n this.expandedId = selected.id;\n // Adjust list scroll to keep expanded process visible\n if (visibleCountWhenExpanded) {\n this.listNav.ensureVisible(visibleCountWhenExpanded);\n }\n }\n this.notify();\n }\n\n collapse(visibleCountWhenCollapsed?: number): void {\n // Collapse but keep scroll position in process\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n this.notify();\n }\n\n // === EXIT ===\n\n signalExit(callback: () => void): void {\n this.shouldExit = true;\n this.exitCallback = callback;\n this.notify();\n }\n\n getShouldExit = (): boolean => this.shouldExit;\n getExitCallback = (): (() => void) | null => this.exitCallback;\n\n // === RESET ===\n\n reset(): void {\n // Dispose terminal buffers before clearing\n for (const process of this.processes) {\n process.terminalBuffer?.dispose();\n }\n this.processes = [];\n this.completedIds = [];\n this.shouldExit = false;\n this.exitCallback = null;\n this.mode = 'normal';\n this.listNav.reset();\n this.expandedId = null;\n this.errorFooterExpanded = false;\n this.filterMode = 'all';\n this.searchTerm = '';\n this.isSearching = false;\n this.isFullscreen = false;\n this.header = undefined;\n }\n\n // === INFRASTRUCTURE ===\n\n notify(): void {\n this.bufferVersion++;\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\n// Note: No global singleton - session creates its own store instance\n"],"names":["arrayFind","DEFAULT_COLUMN_WIDTH","LineType","createNavigator","FILTER_CYCLE","ProcessStore","getErrorLines","getFailedProcesses","map","p","processName","group","title","lines","getProcessLines","id","addProcess","process","processWithNav","scrollNav","getLength","getProcessLineCount","wrap","onMove","notify","processes","updateProcess","update","oldProcess","wasRunning","state","isNowComplete","completedIds","includes","isInteractive","isAllComplete","getErrorCount","errorFooterExpanded","appendLines","newLines","concat","getProcess","terminalBuffer","getLines","text","type","stdout","lineCount","length","setMode","mode","listNav","setPosition","getSelectedProcess","getFilteredProcesses","position","cycleFilterNext","currentIndex","indexOf","filterMode","toStart","expandedId","cycleFilterPrev","startSearch","isSearching","searchTerm","updateSearchTerm","term","cancelSearch","confirmSearch","clearSearch","enterFullscreen","selected","isFullscreen","exitFullscreen","visibleCountWhenCollapsed","clampViewport","toggleErrorFooter","expandErrorFooter","selectNext","visibleCount","down","ensureVisible","selectPrev","up","selectPageDown","pageSize","pageDown","selectPageUp","pageUp","selectFirst","selectLast","toEnd","clampListViewport","changed","getExpandedNav","undefined","nav","scrollDown","maxVisible","expanded","maxOffset","Math","max","scrollUp","scrollPageDown","newPosition","min","scrollPageUp","scrollToTop","scrollToBottom","toggleExpand","visibleCountWhenExpanded","collapse","signalExit","callback","shouldExit","exitCallback","reset","dispose","header","bufferVersion","listeners","forEach","l","options","showStatusBar","Set","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","getCompletedProcesses","getRunningCount","getMaxGroupLength","getDoneCount","getErrorLineCount","reduce","total","getMode","getSelectedIndex","getExpandedId","getListScrollOffset","viewportOffset","getErrorFooterExpanded","getBufferVersion","getFilterMode","getSearchTerm","getIsSearching","getIsFullscreen","filtered","toLowerCase","getScrollOffset","getHeader","getShowStatusBar","getIsInteractive","every","getShouldExit","getExitCallback","interactive"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import { arrayFind } from '../compat.ts';\nimport { DEFAULT_COLUMN_WIDTH } from '../constants.ts';\nimport type { ChildProcess, Line, SessionOptions } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport { createNavigator, type Navigator } from './Navigator.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive';\ntype FilterMode = 'all' | 'running' | 'finished' | 'failed';\n\nconst FILTER_CYCLE: FilterMode[] = ['all', 'running', 'finished', 'failed'];\n\nexport class ProcessStore {\n // === DATA: Process collection ===\n private processes: ChildProcess[] = [];\n private completedIds: string[] = []; // Track completion order\n\n // === NAVIGATION: List cursor ===\n private listNav: Navigator;\n\n // === VIEW STATE ===\n private mode: Mode = 'normal';\n private expandedId: string | null = null;\n private errorFooterExpanded = false; // For non-interactive error footer\n private filterMode: FilterMode = 'all';\n private searchTerm = '';\n private isSearching = false;\n private isFullscreen = false;\n\n // === SESSION CONFIG (immutable after construction) ===\n private header: string | undefined;\n private showStatusBar = false;\n private isInteractive = false;\n\n // === INFRASTRUCTURE ===\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\n private bufferVersion = 0; // Increments on every notify() to trigger re-renders\n\n constructor(options: SessionOptions = {}) {\n this.header = options.header;\n this.showStatusBar = options.showStatusBar ?? false;\n this.isInteractive = options.interactive ?? false;\n\n // Create list navigator with wrap-around behavior\n // Uses filtered processes count so selection works correctly with filters\n this.listNav = createNavigator({\n getLength: () => this.getFilteredProcesses().length,\n wrap: true,\n onMove: () => this.notify(),\n });\n }\n\n // === SUBSCRIPTION API (useSyncExternalStore) ===\n\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n getSnapshot = (): ChildProcess[] => this.processes;\n\n // === DATA: Queries ===\n\n getRunningProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'running');\n };\n\n getCompletedProcesses = (): ChildProcess[] => {\n // Return in completion order\n return this.completedIds.map((id) => arrayFind(this.processes, (p) => p.id === id)).filter((p): p is ChildProcess => p !== undefined);\n };\n\n getFailedProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'error');\n };\n\n // Counts\n getRunningCount = (): number => this.processes.filter((p) => p.state === 'running').length;\n getMaxGroupLength = (): number => {\n if (this.processes.length === 0) return DEFAULT_COLUMN_WIDTH;\n return Math.max(...this.processes.map((p) => (p.group || p.title).length));\n };\n getDoneCount = (): number => this.processes.filter((p) => p.state !== 'running').length;\n getErrorCount = (): number => this.processes.filter((p) => p.state === 'error').length;\n getErrorLineCount = (): number => {\n return this.processes.filter((p) => p.state === 'error').reduce((total, p) => total + this.getProcessLineCount(p.id), 0);\n };\n\n getErrorLines(): Array<{ processName: string; lines: Line[] }> {\n return this.getFailedProcesses().map((p) => ({\n processName: p.group || p.title,\n lines: this.getProcessLines(p.id),\n }));\n }\n\n // === DATA: Mutations ===\n\n addProcess(process: ChildProcess): void {\n // Create scroll navigator for this process\n const processWithNav: ChildProcess = {\n ...process,\n scrollNav: createNavigator({\n getLength: () => this.getProcessLineCount(processWithNav.id),\n wrap: false,\n onMove: () => this.notify(),\n }),\n };\n this.processes = [...this.processes, processWithNav];\n this.notify();\n }\n\n updateProcess(id: string, update: Partial<ChildProcess>): void {\n const oldProcess = arrayFind(this.processes, (p) => p.id === id);\n const wasRunning = oldProcess?.state === 'running';\n const isNowComplete = update.state && update.state !== 'running';\n\n this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\n\n // Track completion order\n if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {\n this.completedIds = [...this.completedIds, id];\n }\n\n // Auto-expand error footer when all complete with errors (non-interactive only)\n if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {\n this.errorFooterExpanded = true;\n }\n\n this.notify();\n }\n\n appendLines(id: string, newLines: Line[]): void {\n const process = arrayFind(this.processes, (p) => p.id === id);\n if (process) {\n this.updateProcess(id, { lines: process.lines.concat(newLines) });\n }\n }\n\n getProcess(id: string): ChildProcess | undefined {\n return arrayFind(this.processes, (p) => p.id === id);\n }\n\n // Get rendered lines from terminal buffer or fallback to lines array\n getProcessLines(id: string): Line[] {\n const process = this.getProcess(id);\n if (!process) return [];\n if (process.terminalBuffer) {\n return process.terminalBuffer.getLines().map((text) => ({\n type: LineType.stdout,\n text,\n }));\n }\n return process.lines;\n }\n\n // Get line count from terminal buffer or lines array\n getProcessLineCount(id: string): number {\n const process = this.getProcess(id);\n if (!process) return 0;\n if (process.terminalBuffer) {\n return process.terminalBuffer.lineCount;\n }\n return process.lines.length;\n }\n\n // === VIEW STATE: Getters ===\n\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.listNav.position;\n getExpandedId = (): string | null => this.expandedId;\n getListScrollOffset = (): number => this.listNav.viewportOffset;\n getErrorFooterExpanded = (): boolean => this.errorFooterExpanded;\n getBufferVersion = (): number => this.bufferVersion;\n getFilterMode = (): FilterMode => this.filterMode;\n getSearchTerm = (): string => this.searchTerm;\n getIsSearching = (): boolean => this.isSearching;\n getIsFullscreen = (): boolean => this.isFullscreen;\n\n // Get processes filtered by current filter mode and search term\n getFilteredProcesses = (): ChildProcess[] => {\n let filtered = this.processes;\n\n // Apply filter mode\n switch (this.filterMode) {\n case 'running':\n filtered = filtered.filter((p) => p.state === 'running');\n break;\n case 'finished':\n filtered = filtered.filter((p) => p.state !== 'running');\n break;\n case 'failed':\n filtered = filtered.filter((p) => p.state === 'error');\n break;\n }\n\n // Apply search term\n if (this.searchTerm) {\n const term = this.searchTerm.toLowerCase();\n filtered = filtered.filter((p) => p.title.toLowerCase().includes(term) || (p.group && p.group.toLowerCase().includes(term)));\n }\n\n return filtered;\n };\n\n // Get scroll offset for expanded process (or 0 if none)\n getScrollOffset = (): number => {\n if (!this.expandedId) return 0;\n const process = this.getProcess(this.expandedId);\n return process?.scrollNav?.position ?? 0;\n };\n\n // Session-level getters (set at session creation, immutable)\n getHeader = (): string | undefined => this.header;\n getShowStatusBar = (): boolean => this.showStatusBar;\n getIsInteractive = (): boolean => this.isInteractive;\n isAllComplete = (): boolean => this.processes.length > 0 && this.processes.every((p) => p.state !== 'running');\n\n // === VIEW STATE: Mutations ===\n\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.listNav.setPosition(0);\n }\n this.notify();\n }\n\n getSelectedProcess(): ChildProcess | undefined {\n return this.getFilteredProcesses()[this.listNav.position];\n }\n\n // Filter mode cycling (left/right arrows)\n cycleFilterNext(): void {\n const currentIndex = FILTER_CYCLE.indexOf(this.filterMode);\n this.filterMode = FILTER_CYCLE[(currentIndex + 1) % FILTER_CYCLE.length] as FilterMode;\n // Reset selection when filter changes\n this.listNav.toStart();\n // Collapse any expanded process when filter changes\n this.expandedId = null;\n this.notify();\n }\n\n cycleFilterPrev(): void {\n const currentIndex = FILTER_CYCLE.indexOf(this.filterMode);\n this.filterMode = FILTER_CYCLE[(currentIndex - 1 + FILTER_CYCLE.length) % FILTER_CYCLE.length] as FilterMode;\n // Reset selection when filter changes\n this.listNav.toStart();\n // Collapse any expanded process when filter changes\n this.expandedId = null;\n this.notify();\n }\n\n // Search mode\n startSearch(): void {\n this.isSearching = true;\n this.searchTerm = '';\n this.notify();\n }\n\n updateSearchTerm(term: string): void {\n this.searchTerm = term;\n // Reset selection when search changes\n this.listNav.toStart();\n this.notify();\n }\n\n cancelSearch(): void {\n this.isSearching = false;\n this.searchTerm = '';\n // Reset selection\n this.listNav.toStart();\n this.notify();\n }\n\n confirmSearch(): void {\n this.isSearching = false;\n // Keep searchTerm applied, reset selection to first match\n this.listNav.toStart();\n this.notify();\n }\n\n clearSearch(): void {\n this.searchTerm = '';\n this.listNav.toStart();\n this.notify();\n }\n\n // Fullscreen mode (alternate screen buffer)\n enterFullscreen(): void {\n // If not expanded, expand the selected process first\n if (!this.expandedId) {\n const selected = this.getSelectedProcess();\n if (selected) {\n this.expandedId = selected.id;\n }\n }\n if (this.expandedId) {\n this.isFullscreen = true;\n this.notify();\n }\n }\n\n exitFullscreen(visibleCountWhenCollapsed?: number): void {\n this.isFullscreen = false;\n // Also collapse when exiting fullscreen\n this.expandedId = null;\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n this.notify();\n }\n\n // Error footer methods (for non-interactive mode)\n toggleErrorFooter(): void {\n this.errorFooterExpanded = !this.errorFooterExpanded;\n this.notify();\n }\n\n expandErrorFooter(): void {\n if (!this.errorFooterExpanded) {\n this.errorFooterExpanded = true;\n this.notify();\n }\n }\n\n // === NAVIGATION: List (delegates to listNav) ===\n\n selectNext(visibleCount?: number): void {\n this.listNav.down();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPrev(visibleCount?: number): void {\n this.listNav.up();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPageDown(pageSize: number, visibleCount?: number): void {\n this.listNav.pageDown(pageSize, visibleCount);\n }\n\n selectPageUp(pageSize: number, visibleCount?: number): void {\n this.listNav.pageUp(pageSize, visibleCount);\n }\n\n selectFirst(visibleCount?: number): void {\n this.listNav.toStart();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectLast(visibleCount?: number): void {\n this.listNav.toEnd();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n clampListViewport(visibleCount: number): void {\n const changed = this.listNav.clampViewport(visibleCount);\n if (changed) {\n this.notify();\n }\n }\n\n // === NAVIGATION: Expanded content (delegates to process.scrollNav) ===\n\n private getExpandedNav(): { nav: Navigator; id: string } | undefined {\n if (!this.expandedId) return undefined;\n const nav = this.getProcess(this.expandedId)?.scrollNav;\n if (!nav) return undefined;\n return { nav, id: this.expandedId };\n }\n\n scrollDown(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - maxVisible);\n\n // Only scroll if not at bottom\n if (expanded.nav.position < maxOffset) {\n expanded.nav.down();\n }\n }\n\n scrollUp(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n if (expanded.nav.position > 0) {\n expanded.nav.up();\n }\n }\n\n scrollPageDown(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - pageSize);\n\n // Clamp to max offset\n const newPosition = Math.min(expanded.nav.position + pageSize, maxOffset);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollPageUp(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const newPosition = Math.max(0, expanded.nav.position - pageSize);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollToTop(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n expanded.nav.toStart();\n }\n\n scrollToBottom(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const newPosition = Math.max(0, lineCount - maxVisible);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n // === EXPANSION ===\n\n toggleExpand(visibleCountWhenExpanded?: number, visibleCountWhenCollapsed?: number): void {\n const selected = this.getSelectedProcess();\n if (!selected) return;\n\n if (this.expandedId === selected.id) {\n // Collapse (keep scroll position for later)\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n } else {\n // Expand (scroll position is preserved in process.scrollNav)\n this.expandedId = selected.id;\n // Adjust list scroll to keep expanded process visible\n if (visibleCountWhenExpanded) {\n this.listNav.ensureVisible(visibleCountWhenExpanded);\n }\n }\n this.notify();\n }\n\n collapse(visibleCountWhenCollapsed?: number): void {\n // Collapse but keep scroll position in process\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n this.notify();\n }\n\n // === EXIT ===\n\n signalExit(callback: () => void): void {\n this.shouldExit = true;\n this.exitCallback = callback;\n this.notify();\n }\n\n getShouldExit = (): boolean => this.shouldExit;\n getExitCallback = (): (() => void) | null => this.exitCallback;\n\n // === RESET ===\n\n reset(): void {\n // Dispose terminal buffers before clearing\n for (const process of this.processes) {\n process.terminalBuffer?.dispose();\n }\n this.processes = [];\n this.completedIds = [];\n this.shouldExit = false;\n this.exitCallback = null;\n this.mode = 'normal';\n this.listNav.reset();\n this.expandedId = null;\n this.errorFooterExpanded = false;\n this.filterMode = 'all';\n this.searchTerm = '';\n this.isSearching = false;\n this.isFullscreen = false;\n this.header = undefined;\n }\n\n // === INFRASTRUCTURE ===\n\n notify(): void {\n this.bufferVersion++;\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\n// Note: No global singleton - session creates its own store instance\n"],"names":["arrayFind","DEFAULT_COLUMN_WIDTH","LineType","createNavigator","FILTER_CYCLE","ProcessStore","getErrorLines","getFailedProcesses","map","p","processName","group","title","lines","getProcessLines","id","addProcess","process","processWithNav","scrollNav","getLength","getProcessLineCount","wrap","onMove","notify","processes","updateProcess","update","oldProcess","wasRunning","state","isNowComplete","completedIds","includes","isInteractive","isAllComplete","getErrorCount","errorFooterExpanded","appendLines","newLines","concat","getProcess","terminalBuffer","getLines","text","type","stdout","lineCount","length","setMode","mode","listNav","setPosition","getSelectedProcess","getFilteredProcesses","position","cycleFilterNext","currentIndex","indexOf","filterMode","toStart","expandedId","cycleFilterPrev","startSearch","isSearching","searchTerm","updateSearchTerm","term","cancelSearch","confirmSearch","clearSearch","enterFullscreen","selected","isFullscreen","exitFullscreen","visibleCountWhenCollapsed","clampViewport","toggleErrorFooter","expandErrorFooter","selectNext","visibleCount","down","ensureVisible","selectPrev","up","selectPageDown","pageSize","pageDown","selectPageUp","pageUp","selectFirst","selectLast","toEnd","clampListViewport","changed","getExpandedNav","undefined","nav","scrollDown","maxVisible","expanded","maxOffset","Math","max","scrollUp","scrollPageDown","newPosition","min","scrollPageUp","scrollToTop","scrollToBottom","toggleExpand","visibleCountWhenExpanded","collapse","signalExit","callback","shouldExit","exitCallback","reset","dispose","header","bufferVersion","listeners","forEach","l","options","showStatusBar","Set","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","getCompletedProcesses","getRunningCount","getMaxGroupLength","getDoneCount","getErrorLineCount","reduce","total","getMode","getSelectedIndex","getExpandedId","getListScrollOffset","viewportOffset","getErrorFooterExpanded","getBufferVersion","getFilterMode","getSearchTerm","getIsSearching","getIsFullscreen","filtered","toLowerCase","getScrollOffset","getHeader","getShowStatusBar","getIsInteractive","every","getShouldExit","getExitCallback","interactive"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spawn-term",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.6",
|
|
4
4
|
"description": "Formats spawn with for terminal grouping",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"spawn",
|
|
@@ -43,23 +43,23 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@xterm/headless": "^5.5.0",
|
|
46
|
-
"cross-spawn-cb": "^
|
|
47
|
-
"install-module-linked": "^1.3.
|
|
48
|
-
"on-one": "^1.0.
|
|
49
|
-
"queue-cb": "^1.
|
|
46
|
+
"cross-spawn-cb": "^3.0.0",
|
|
47
|
+
"install-module-linked": "^1.3.16",
|
|
48
|
+
"on-one": "^1.0.0",
|
|
49
|
+
"queue-cb": "^1.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@types/mocha": "
|
|
53
|
-
"@types/node": "
|
|
52
|
+
"@types/mocha": "*",
|
|
53
|
+
"@types/node": "*",
|
|
54
54
|
"@types/react": "^19.2.7",
|
|
55
55
|
"cr": "^0.1.0",
|
|
56
56
|
"ink": "^6.5.1",
|
|
57
|
-
"is-version": "^1.0.
|
|
58
|
-
"node-version-use": "
|
|
59
|
-
"pinkie-promise": "
|
|
57
|
+
"is-version": "^1.0.9",
|
|
58
|
+
"node-version-use": "*",
|
|
59
|
+
"pinkie-promise": "*",
|
|
60
60
|
"react": "^19.2.3",
|
|
61
|
-
"ts-dev-stack": "
|
|
62
|
-
"tsds-config": "
|
|
61
|
+
"ts-dev-stack": "*",
|
|
62
|
+
"tsds-config": "*"
|
|
63
63
|
},
|
|
64
64
|
"engines": {
|
|
65
65
|
"node": ">=0.8"
|