spawn-term 3.4.1 → 3.4.2
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/session.js +5 -7
- package/dist/cjs/session.js.map +1 -1
- package/dist/esm/session.js +5 -7
- package/dist/esm/session.js.map +1 -1
- package/package.json +1 -1
package/dist/cjs/session.js
CHANGED
|
@@ -175,13 +175,11 @@ var SessionImpl = /*#__PURE__*/ function() {
|
|
|
175
175
|
this.terminalWidth = 10000;
|
|
176
176
|
// Only render Ink when stdout is a real terminal
|
|
177
177
|
// When piped (e.g., nested spawn-term), skip Ink to avoid cursor positioning artifacts
|
|
178
|
-
|
|
179
|
-
this.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
});
|
|
184
|
-
}
|
|
178
|
+
this.inkApp = (0, _ink.render)(/*#__PURE__*/ (0, _jsxruntime.jsx)(_Appts.default, {
|
|
179
|
+
store: this.store
|
|
180
|
+
}), {
|
|
181
|
+
maxFps: _constantsts.DEFAULT_MAX_FPS
|
|
182
|
+
});
|
|
185
183
|
// Interactive mode requires a TTY to capture user input (e.g., press 'q' to quit)
|
|
186
184
|
// Force non-interactive when no UI is rendered, otherwise waitAndClose would hang
|
|
187
185
|
this.isInteractive = this.inkApp ? (_options_interactive = options.interactive) !== null && _options_interactive !== void 0 ? _options_interactive : false : false;
|
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 this.inkApp = render(<App store={this.store} />, { maxFps: DEFAULT_MAX_FPS });\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","render","App","maxFps","DEFAULT_MAX_FPS","isInteractive","interactive","spawn","command","args","spawnOptions","callback","Error","encoding","stdio","csOptions","cp","crossSpawn","worker","err","res","stdout","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","process","waitUntilExit","then","getExitCallback","catch"],"mappings":"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"}
|
package/dist/esm/session.js
CHANGED
|
@@ -226,13 +226,11 @@ let SessionImpl = class SessionImpl {
|
|
|
226
226
|
this.terminalWidth = 10000;
|
|
227
227
|
// Only render Ink when stdout is a real terminal
|
|
228
228
|
// When piped (e.g., nested spawn-term), skip Ink to avoid cursor positioning artifacts
|
|
229
|
-
|
|
230
|
-
this.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
});
|
|
235
|
-
}
|
|
229
|
+
this.inkApp = render(/*#__PURE__*/ _jsx(App, {
|
|
230
|
+
store: this.store
|
|
231
|
+
}), {
|
|
232
|
+
maxFps: DEFAULT_MAX_FPS
|
|
233
|
+
});
|
|
236
234
|
// Interactive mode requires a TTY to capture user input (e.g., press 'q' to quit)
|
|
237
235
|
// Force non-interactive when no UI is rendered, otherwise waitAndClose would hang
|
|
238
236
|
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":";AAAA,OAAOA,SAASC,UAAU,QAA0B,iBAAiB;AACrE,OAAOC,YAAY,SAAS;AAC5B,SAASC,MAAM,QAAQ,MAAM;AAC7B,OAAOC,QAAQ,SAAS;AACxB,OAAOC,WAAW,WAAW;AAE7B,OAAOC,SAAS,sBAAsB;AACtC,SAASC,eAAe,QAAQ,iBAAiB;AACjD,OAAOC,oBAAoB,0BAA0B;AACrD,OAAOC,qBAAqB,2BAA2B;AACvD,SAASC,cAAc,QAAQ,0BAA0B;AACzD,SAASC,YAAY,QAAQ,0BAA0B;AASvD,IAAA,AAAMC,cAAN,MAAMA;IA4BJZ,MAAMa,OAAe,EAAEC,IAAc,EAAEC,YAA0B,EAAEC,OAAuB,EAAEC,QAA0B,EAAQ;QAC5H,IAAI,IAAI,CAACC,MAAM,EAAE;YACf,MAAM,IAAIC,MAAM;QAClB;QAEA,MAAM,EAAEC,QAAQ,EAAEC,KAAK,EAAE,GAAGC,WAAW,GAAGP;QAE1C,IAAIM,UAAU,WAAW;YACvB,+EAA+E;YAC/E,IAAI,CAAC,IAAI,CAACE,MAAM,EAAE;gBAChB,MAAMC,KAAKvB,WAAWY,SAASC,MAAM;oBAAE,GAAGQ,SAAS;oBAAED,OAAO;gBAAU;gBACtErB,MAAMyB,MAAM,CAACD,IAAIF,WAAW,CAACI;oBAC3B,MAAMC,MAAOD,MAAMA,MAAM,CAAC;oBAC1BC,IAAIC,MAAM,GAAG;oBACbD,IAAIE,MAAM,GAAG;oBACbF,IAAIG,MAAM,GAAG;wBAAC;wBAAM;wBAAM;qBAAK;oBAC/BJ,MAAMT,SAASS,OAAOT,SAAS,MAAMU;gBACvC;gBACA;YACF;YAEA,IAAI,CAACI,YAAY;YACjB,MAAMC,KAAK9B,OAAO+B,UAAU;YAE5B,0DAA0D;YAC1D,MAAMC,iBAAiB,IAAIxB,eAAe,IAAI,CAACyB,aAAa;YAE5D,IAAI,CAACC,KAAK,CAACC,UAAU,CAAC;gBACpBL;gBACAM,OAAO;oBAACzB;iBAAQ,CAAC0B,MAAM,CAAC9B,gBAAgBK,OAAO0B,IAAI,CAAC;gBACpDC,OAAO;gBACPC,OAAO,EAAE;gBACTR;gBACAS,OAAO3B,QAAQ2B,KAAK;gBACpBC,UAAU5B,QAAQ4B,QAAQ;YAC5B;YAEA,MAAMpB,KAAKvB,WAAWY,SAASC,MAAMQ;YAErC,qDAAqD;YACrD,kEAAkE;YAClE,IAAIE,GAAGI,MAAM,EAAE;gBACbJ,GAAGI,MAAM,CAACiB,EAAE,CAAC,QAAQ,CAACC;oBACpBZ,eAAea,KAAK,CAACD;oBACrB,IAAI,CAACV,KAAK,CAACY,MAAM;gBACnB;YACF;YACA,IAAIxB,GAAGK,MAAM,EAAE;gBACbL,GAAGK,MAAM,CAACgB,EAAE,CAAC,QAAQ,CAACC;oBACpBZ,eAAea,KAAK,CAACD;oBACrB,IAAI,CAACV,KAAK,CAACY,MAAM;gBACnB;YACF;YAEA,+BAA+B;YAC/B,MAAMC,QAAQ,IAAI5C;YAClB,IAAImB,GAAGI,MAAM,EAAE;gBACbqB,MAAMC,KAAK,CAAC9C,GAAG+C,IAAI,CAAC,MAAM3B,GAAGI,MAAM,EAAE;oBAAC;oBAAS;oBAAO;iBAAQ;YAChE;YACA,IAAIJ,GAAGK,MAAM,EAAE;gBACboB,MAAMC,KAAK,CAAC9C,GAAG+C,IAAI,CAAC,MAAM3B,GAAGK,MAAM,EAAE;oBAAC;oBAAS;oBAAO;iBAAQ;YAChE;YACAoB,MAAMC,KAAK,CAAClD,MAAMyB,MAAM,CAAC0B,IAAI,CAAC,MAAM3B,IAAIF;YACxC2B,MAAMG,KAAK,CAAC,CAAC1B;gBACX,MAAMC,MAAOD,MAAMA,MAAM,CAAC;gBAC1BC,IAAIC,MAAM,GAAG,MAAM,4CAA4C;gBAC/DD,IAAIE,MAAM,GAAG;gBACbF,IAAIG,MAAM,GAAG;oBAAC;oBAAM;oBAAM;iBAAK;gBAC/B,IAAI,CAACM,KAAK,CAACiB,aAAa,CAACrB,IAAI;oBAAES,OAAOf,MAAM,UAAU;gBAAU;gBAEhE,IAAI,CAAC4B,iBAAiB;gBACtB5B,MAAMT,SAASS,OAAOT,SAAS,MAAMU;YACvC;QACF,OAAO;YACL,2DAA2D;YAC3D,MAAMH,KAAKvB,WAAWY,SAASC,MAAMQ;YACrC,MAAMiC,UAAU;gBAAE3B,QAAQ;gBAAkDC,QAAQ;YAAiD;YAErI,MAAMoB,QAAQ,IAAI5C;YAClB,IAAImB,GAAGI,MAAM,EAAE;gBACb2B,QAAQ3B,MAAM,GAAGpB,eAAe,CAACsB;oBAC9ByB,QAAQ3B,MAAM,CAAmCE,MAAM,GAAGA,OAAO0B,QAAQ,CAACpC,YAAY;gBACzF;gBACA6B,MAAMC,KAAK,CAAC9C,GAAG+C,IAAI,CAAC,MAAM3B,GAAGI,MAAM,CAAC6B,IAAI,CAACF,QAAQ3B,MAAM,GAAG;oBAAC;oBAAS;oBAAO;oBAAS;iBAAS;YAC/F;YACA,IAAIJ,GAAGK,MAAM,EAAE;gBACb0B,QAAQ1B,MAAM,GAAGrB,eAAe,CAACsB;oBAC9ByB,QAAQ1B,MAAM,CAAmCC,MAAM,GAAGA,OAAO0B,QAAQ,CAACpC,YAAY;gBACzF;gBACA6B,MAAMC,KAAK,CAAC9C,GAAG+C,IAAI,CAAC,MAAM3B,GAAGK,MAAM,CAAC4B,IAAI,CAACF,QAAQ1B,MAAM,GAAG;oBAAC;oBAAS;oBAAO;oBAAS;iBAAS;YAC/F;YACAoB,MAAMC,KAAK,CAAClD,MAAMyB,MAAM,CAAC0B,IAAI,CAAC,MAAM3B,IAAIF;YACxC2B,MAAMG,KAAK,CAAC,CAAC1B;gBACX,MAAMC,MAAOD,MAAMA,MAAM,CAAC;gBAC1BC,IAAIC,MAAM,GAAG2B,QAAQ3B,MAAM,GAAG,AAAC2B,QAAQ3B,MAAM,CAAmCE,MAAM,GAAG;gBACzFH,IAAIE,MAAM,GAAG0B,QAAQ1B,MAAM,GAAG,AAAC0B,QAAQ1B,MAAM,CAAmCC,MAAM,GAAG;gBACzFH,IAAIG,MAAM,GAAG;oBAACH,IAAIC,MAAM;oBAAED,IAAIE,MAAM;oBAAE;iBAAK;gBAC3CH,MAAMT,SAASS,OAAOT,SAAS,MAAMU;YACvC;QACF;IACF;IAEA+B,QAAc;QACZ,IAAI,IAAI,CAACxC,MAAM,EAAE;QACjB,IAAI,CAACA,MAAM,GAAG;QACd,IAAI,CAACyC,OAAO;IACd;IAEAC,aAAa3C,QAAqB,EAAQ;QACxC,IAAI,IAAI,CAACC,MAAM,EAAE;YACfD,qBAAAA,+BAAAA;YACA;QACF;QAEA,IAAIA,UAAU,IAAI,CAAC4C,aAAa,CAACC,IAAI,CAAC7C;QAEtC,IAAI,IAAI,CAACc,YAAY,KAAK,GAAG;YAC3B,IAAI,IAAI,CAACgC,aAAa,EAAE;gBACtB,yDAAyD;gBACzD,MAAMC,cAAc,IAAI,CAAC5B,KAAK,CAAC6B,SAAS,CAAC;oBACvC,IAAI,IAAI,CAAC7B,KAAK,CAAC8B,aAAa,IAAI;wBAC9BF;wBACA,IAAI,CAACG,yBAAyB;oBAChC;gBACF;YACF,OAAO;gBACL,IAAI,CAACA,yBAAyB;YAChC;QACF;IACA,sEAAsE;IACxE;IAEQb,oBAA0B;QAChC,IAAI,CAACvB,YAAY;QACjB,IAAI,IAAI,CAACA,YAAY,KAAK,KAAK,IAAI,CAAC8B,aAAa,CAACO,MAAM,GAAG,GAAG;YAC5D,IAAI,IAAI,CAACL,aAAa,EAAE;gBACtB,yDAAyD;gBACzD,MAAMC,cAAc,IAAI,CAAC5B,KAAK,CAAC6B,SAAS,CAAC;oBACvC,IAAI,IAAI,CAAC7B,KAAK,CAAC8B,aAAa,IAAI;wBAC9BF;wBACA,IAAI,CAACG,yBAAyB;oBAChC;gBACF;YACF,OAAO;gBACL,IAAI,CAACA,yBAAyB;YAChC;QACF;IACF;IAEQA,4BAAkC;QACxC,IAAI,IAAI,CAACjD,MAAM,EAAE;QACjB,IAAI,CAACA,MAAM,GAAG;QACd,IAAI,CAACyC,OAAO,CAAC;YACX,KAAK,MAAMU,MAAM,IAAI,CAACR,aAAa,CAAEQ;YACrC,IAAI,CAACR,aAAa,GAAG,EAAE;QACzB;IACF;IAEQF,QAAQW,UAAuB,EAAQ;QAC7C,iCAAiC;QACjC,IAAI,CAAClC,KAAK,CAACmC,UAAU,CAAC;YACpB,IAAI,CAACnC,KAAK,CAACoC,KAAK;YAChBC,QAAQ7C,MAAM,CAACmB,KAAK,CAAC,cAAc,cAAc;QACnD;QAEA,yBAAyB;QACzB,IAAI,IAAI,CAACxB,MAAM,EAAE;YACf,IAAI,CAACA,MAAM,CACRmD,aAAa,GACbC,IAAI,CAAC;gBACJ,MAAMN,KAAK,IAAI,CAACjC,KAAK,CAACwC,eAAe;gBACrCP,eAAAA,yBAAAA;gBACAC,uBAAAA,iCAAAA;YACF,GACCO,KAAK,CAAC;gBACL,MAAMR,KAAK,IAAI,CAACjC,KAAK,CAACwC,eAAe;gBACrCP,eAAAA,yBAAAA;gBACAC,uBAAAA,iCAAAA;YACF;YACF,IAAI,CAAC/C,MAAM,GAAG;QAChB,OAAO;YACL+C,uBAAAA,iCAAAA;QACF;IACF;IA1MA,YAAYtD,UAA0B,CAAC,CAAC,CAAE;YAgBJA;aAvB9BO,SAA2C;aAC3CQ,eAAe;aACfb,SAAS;aACT2C,gBAAgC,EAAE;QAKxC,IAAI,CAACzB,KAAK,GAAG,IAAIzB,aAAaK;QAC9B,2DAA2D;QAC3D,yDAAyD;QACzD,IAAI,CAACmB,aAAa,GAAG;QAErB,iDAAiD;QACjD,uFAAuF;QACvF,IAAIsC,QAAQ7C,MAAM,CAACkD,KAAK,EAAE;YACxB,IAAI,CAACvD,MAAM,GAAGpB,qBAAO,KAACG;gBAAI8B,OAAO,IAAI,CAACA,KAAK;gBAAM;gBAC/C2C,QAAQxE;YACV;QACF;QAEA,kFAAkF;QAClF,kFAAkF;QAClF,IAAI,CAACwD,aAAa,GAAG,IAAI,CAACxC,MAAM,IAAIP,uBAAAA,QAAQgE,WAAW,cAAnBhE,kCAAAA,uBAAuB,QAAS;IACtE;AA0LF;AAEA,OAAO,SAASiE,cAAcjE,UAA0B,CAAC,CAAC;IACxD,OAAO,IAAIJ,YAAYI;AACzB"}
|
|
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 this.inkApp = render(<App store={this.store} />, { maxFps: DEFAULT_MAX_FPS });\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","maxFps","interactive","createSession"],"mappings":";AAAA,OAAOA,SAASC,UAAU,QAA0B,iBAAiB;AACrE,OAAOC,YAAY,SAAS;AAC5B,SAASC,MAAM,QAAQ,MAAM;AAC7B,OAAOC,QAAQ,SAAS;AACxB,OAAOC,WAAW,WAAW;AAE7B,OAAOC,SAAS,sBAAsB;AACtC,SAASC,eAAe,QAAQ,iBAAiB;AACjD,OAAOC,oBAAoB,0BAA0B;AACrD,OAAOC,qBAAqB,2BAA2B;AACvD,SAASC,cAAc,QAAQ,0BAA0B;AACzD,SAASC,YAAY,QAAQ,0BAA0B;AASvD,IAAA,AAAMC,cAAN,MAAMA;IAwBJZ,MAAMa,OAAe,EAAEC,IAAc,EAAEC,YAA0B,EAAEC,OAAuB,EAAEC,QAA0B,EAAQ;QAC5H,IAAI,IAAI,CAACC,MAAM,EAAE;YACf,MAAM,IAAIC,MAAM;QAClB;QAEA,MAAM,EAAEC,QAAQ,EAAEC,KAAK,EAAE,GAAGC,WAAW,GAAGP;QAE1C,IAAIM,UAAU,WAAW;YACvB,+EAA+E;YAC/E,IAAI,CAAC,IAAI,CAACE,MAAM,EAAE;gBAChB,MAAMC,KAAKvB,WAAWY,SAASC,MAAM;oBAAE,GAAGQ,SAAS;oBAAED,OAAO;gBAAU;gBACtErB,MAAMyB,MAAM,CAACD,IAAIF,WAAW,CAACI;oBAC3B,MAAMC,MAAOD,MAAMA,MAAM,CAAC;oBAC1BC,IAAIC,MAAM,GAAG;oBACbD,IAAIE,MAAM,GAAG;oBACbF,IAAIG,MAAM,GAAG;wBAAC;wBAAM;wBAAM;qBAAK;oBAC/BJ,MAAMT,SAASS,OAAOT,SAAS,MAAMU;gBACvC;gBACA;YACF;YAEA,IAAI,CAACI,YAAY;YACjB,MAAMC,KAAK9B,OAAO+B,UAAU;YAE5B,0DAA0D;YAC1D,MAAMC,iBAAiB,IAAIxB,eAAe,IAAI,CAACyB,aAAa;YAE5D,IAAI,CAACC,KAAK,CAACC,UAAU,CAAC;gBACpBL;gBACAM,OAAO;oBAACzB;iBAAQ,CAAC0B,MAAM,CAAC9B,gBAAgBK,OAAO0B,IAAI,CAAC;gBACpDC,OAAO;gBACPC,OAAO,EAAE;gBACTR;gBACAS,OAAO3B,QAAQ2B,KAAK;gBACpBC,UAAU5B,QAAQ4B,QAAQ;YAC5B;YAEA,MAAMpB,KAAKvB,WAAWY,SAASC,MAAMQ;YAErC,qDAAqD;YACrD,kEAAkE;YAClE,IAAIE,GAAGI,MAAM,EAAE;gBACbJ,GAAGI,MAAM,CAACiB,EAAE,CAAC,QAAQ,CAACC;oBACpBZ,eAAea,KAAK,CAACD;oBACrB,IAAI,CAACV,KAAK,CAACY,MAAM;gBACnB;YACF;YACA,IAAIxB,GAAGK,MAAM,EAAE;gBACbL,GAAGK,MAAM,CAACgB,EAAE,CAAC,QAAQ,CAACC;oBACpBZ,eAAea,KAAK,CAACD;oBACrB,IAAI,CAACV,KAAK,CAACY,MAAM;gBACnB;YACF;YAEA,+BAA+B;YAC/B,MAAMC,QAAQ,IAAI5C;YAClB,IAAImB,GAAGI,MAAM,EAAE;gBACbqB,MAAMC,KAAK,CAAC9C,GAAG+C,IAAI,CAAC,MAAM3B,GAAGI,MAAM,EAAE;oBAAC;oBAAS;oBAAO;iBAAQ;YAChE;YACA,IAAIJ,GAAGK,MAAM,EAAE;gBACboB,MAAMC,KAAK,CAAC9C,GAAG+C,IAAI,CAAC,MAAM3B,GAAGK,MAAM,EAAE;oBAAC;oBAAS;oBAAO;iBAAQ;YAChE;YACAoB,MAAMC,KAAK,CAAClD,MAAMyB,MAAM,CAAC0B,IAAI,CAAC,MAAM3B,IAAIF;YACxC2B,MAAMG,KAAK,CAAC,CAAC1B;gBACX,MAAMC,MAAOD,MAAMA,MAAM,CAAC;gBAC1BC,IAAIC,MAAM,GAAG,MAAM,4CAA4C;gBAC/DD,IAAIE,MAAM,GAAG;gBACbF,IAAIG,MAAM,GAAG;oBAAC;oBAAM;oBAAM;iBAAK;gBAC/B,IAAI,CAACM,KAAK,CAACiB,aAAa,CAACrB,IAAI;oBAAES,OAAOf,MAAM,UAAU;gBAAU;gBAEhE,IAAI,CAAC4B,iBAAiB;gBACtB5B,MAAMT,SAASS,OAAOT,SAAS,MAAMU;YACvC;QACF,OAAO;YACL,2DAA2D;YAC3D,MAAMH,KAAKvB,WAAWY,SAASC,MAAMQ;YACrC,MAAMiC,UAAU;gBAAE3B,QAAQ;gBAAkDC,QAAQ;YAAiD;YAErI,MAAMoB,QAAQ,IAAI5C;YAClB,IAAImB,GAAGI,MAAM,EAAE;gBACb2B,QAAQ3B,MAAM,GAAGpB,eAAe,CAACsB;oBAC9ByB,QAAQ3B,MAAM,CAAmCE,MAAM,GAAGA,OAAO0B,QAAQ,CAACpC,YAAY;gBACzF;gBACA6B,MAAMC,KAAK,CAAC9C,GAAG+C,IAAI,CAAC,MAAM3B,GAAGI,MAAM,CAAC6B,IAAI,CAACF,QAAQ3B,MAAM,GAAG;oBAAC;oBAAS;oBAAO;oBAAS;iBAAS;YAC/F;YACA,IAAIJ,GAAGK,MAAM,EAAE;gBACb0B,QAAQ1B,MAAM,GAAGrB,eAAe,CAACsB;oBAC9ByB,QAAQ1B,MAAM,CAAmCC,MAAM,GAAGA,OAAO0B,QAAQ,CAACpC,YAAY;gBACzF;gBACA6B,MAAMC,KAAK,CAAC9C,GAAG+C,IAAI,CAAC,MAAM3B,GAAGK,MAAM,CAAC4B,IAAI,CAACF,QAAQ1B,MAAM,GAAG;oBAAC;oBAAS;oBAAO;oBAAS;iBAAS;YAC/F;YACAoB,MAAMC,KAAK,CAAClD,MAAMyB,MAAM,CAAC0B,IAAI,CAAC,MAAM3B,IAAIF;YACxC2B,MAAMG,KAAK,CAAC,CAAC1B;gBACX,MAAMC,MAAOD,MAAMA,MAAM,CAAC;gBAC1BC,IAAIC,MAAM,GAAG2B,QAAQ3B,MAAM,GAAG,AAAC2B,QAAQ3B,MAAM,CAAmCE,MAAM,GAAG;gBACzFH,IAAIE,MAAM,GAAG0B,QAAQ1B,MAAM,GAAG,AAAC0B,QAAQ1B,MAAM,CAAmCC,MAAM,GAAG;gBACzFH,IAAIG,MAAM,GAAG;oBAACH,IAAIC,MAAM;oBAAED,IAAIE,MAAM;oBAAE;iBAAK;gBAC3CH,MAAMT,SAASS,OAAOT,SAAS,MAAMU;YACvC;QACF;IACF;IAEA+B,QAAc;QACZ,IAAI,IAAI,CAACxC,MAAM,EAAE;QACjB,IAAI,CAACA,MAAM,GAAG;QACd,IAAI,CAACyC,OAAO;IACd;IAEAC,aAAa3C,QAAqB,EAAQ;QACxC,IAAI,IAAI,CAACC,MAAM,EAAE;YACfD,qBAAAA,+BAAAA;YACA;QACF;QAEA,IAAIA,UAAU,IAAI,CAAC4C,aAAa,CAACC,IAAI,CAAC7C;QAEtC,IAAI,IAAI,CAACc,YAAY,KAAK,GAAG;YAC3B,IAAI,IAAI,CAACgC,aAAa,EAAE;gBACtB,yDAAyD;gBACzD,MAAMC,cAAc,IAAI,CAAC5B,KAAK,CAAC6B,SAAS,CAAC;oBACvC,IAAI,IAAI,CAAC7B,KAAK,CAAC8B,aAAa,IAAI;wBAC9BF;wBACA,IAAI,CAACG,yBAAyB;oBAChC;gBACF;YACF,OAAO;gBACL,IAAI,CAACA,yBAAyB;YAChC;QACF;IACA,sEAAsE;IACxE;IAEQb,oBAA0B;QAChC,IAAI,CAACvB,YAAY;QACjB,IAAI,IAAI,CAACA,YAAY,KAAK,KAAK,IAAI,CAAC8B,aAAa,CAACO,MAAM,GAAG,GAAG;YAC5D,IAAI,IAAI,CAACL,aAAa,EAAE;gBACtB,yDAAyD;gBACzD,MAAMC,cAAc,IAAI,CAAC5B,KAAK,CAAC6B,SAAS,CAAC;oBACvC,IAAI,IAAI,CAAC7B,KAAK,CAAC8B,aAAa,IAAI;wBAC9BF;wBACA,IAAI,CAACG,yBAAyB;oBAChC;gBACF;YACF,OAAO;gBACL,IAAI,CAACA,yBAAyB;YAChC;QACF;IACF;IAEQA,4BAAkC;QACxC,IAAI,IAAI,CAACjD,MAAM,EAAE;QACjB,IAAI,CAACA,MAAM,GAAG;QACd,IAAI,CAACyC,OAAO,CAAC;YACX,KAAK,MAAMU,MAAM,IAAI,CAACR,aAAa,CAAEQ;YACrC,IAAI,CAACR,aAAa,GAAG,EAAE;QACzB;IACF;IAEQF,QAAQW,UAAuB,EAAQ;QAC7C,iCAAiC;QACjC,IAAI,CAAClC,KAAK,CAACmC,UAAU,CAAC;YACpB,IAAI,CAACnC,KAAK,CAACoC,KAAK;YAChBC,QAAQ7C,MAAM,CAACmB,KAAK,CAAC,cAAc,cAAc;QACnD;QAEA,yBAAyB;QACzB,IAAI,IAAI,CAACxB,MAAM,EAAE;YACf,IAAI,CAACA,MAAM,CACRmD,aAAa,GACbC,IAAI,CAAC;gBACJ,MAAMN,KAAK,IAAI,CAACjC,KAAK,CAACwC,eAAe;gBACrCP,eAAAA,yBAAAA;gBACAC,uBAAAA,iCAAAA;YACF,GACCO,KAAK,CAAC;gBACL,MAAMR,KAAK,IAAI,CAACjC,KAAK,CAACwC,eAAe;gBACrCP,eAAAA,yBAAAA;gBACAC,uBAAAA,iCAAAA;YACF;YACF,IAAI,CAAC/C,MAAM,GAAG;QAChB,OAAO;YACL+C,uBAAAA,iCAAAA;QACF;IACF;IAtMA,YAAYtD,UAA0B,CAAC,CAAC,CAAE;YAYJA;aAnB9BO,SAA2C;aAC3CQ,eAAe;aACfb,SAAS;aACT2C,gBAAgC,EAAE;QAKxC,IAAI,CAACzB,KAAK,GAAG,IAAIzB,aAAaK;QAC9B,2DAA2D;QAC3D,yDAAyD;QACzD,IAAI,CAACmB,aAAa,GAAG;QAErB,iDAAiD;QACjD,uFAAuF;QACvF,IAAI,CAACZ,MAAM,GAAGpB,qBAAO,KAACG;YAAI8B,OAAO,IAAI,CAACA,KAAK;YAAM;YAAE0C,QAAQvE;QAAgB;QAE3E,kFAAkF;QAClF,kFAAkF;QAClF,IAAI,CAACwD,aAAa,GAAG,IAAI,CAACxC,MAAM,IAAIP,uBAAAA,QAAQ+D,WAAW,cAAnB/D,kCAAAA,uBAAuB,QAAS;IACtE;AA0LF;AAEA,OAAO,SAASgE,cAAchE,UAA0B,CAAC,CAAC;IACxD,OAAO,IAAIJ,YAAYI;AACzB"}
|