prompt-language-shell 0.8.8 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ui/Task.js CHANGED
@@ -1,14 +1,35 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useEffect, useState } from 'react';
3
- import { ExecutionResult, ExecutionStatus, executeCommand, } from '../services/shell.js';
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { Box } from 'ink';
4
+ import { ExecutionResult, ExecutionStatus, executeCommand, setOutputCallback, } from '../services/shell.js';
4
5
  import { calculateElapsed } from '../services/utils.js';
6
+ import { Output } from './Output.js';
5
7
  import { Subtask } from './Subtask.js';
6
- export function Task({ label, command, isActive, index, initialStatus, initialElapsed, onComplete, onAbort, onError, }) {
8
+ export function Task({ label, command, isActive, isFinished, index, initialStatus, initialElapsed, initialOutput, onOutputChange, onComplete, onAbort, onError, }) {
7
9
  const [status, setStatus] = useState(initialStatus ?? ExecutionStatus.Pending);
8
10
  const [startTime, setStartTime] = useState();
9
11
  const [endTime, setEndTime] = useState();
10
12
  const [elapsed, setElapsed] = useState(initialElapsed);
11
13
  const [currentElapsed, setCurrentElapsed] = useState(0);
14
+ const [stdout, setStdout] = useState(initialOutput?.stdout ?? '');
15
+ const [stderr, setStderr] = useState(initialOutput?.stderr ?? '');
16
+ const [error, setError] = useState(initialOutput?.error ?? '');
17
+ // Refs to track current output for callbacks (avoid stale closure)
18
+ const stdoutRef = useRef(stdout);
19
+ const stderrRef = useRef(stderr);
20
+ const errorRef = useRef(error);
21
+ stdoutRef.current = stdout;
22
+ stderrRef.current = stderr;
23
+ errorRef.current = error;
24
+ // Refs for callbacks to avoid stale closures in async effects
25
+ const onOutputChangeRef = useRef(onOutputChange);
26
+ const onCompleteRef = useRef(onComplete);
27
+ const onErrorRef = useRef(onError);
28
+ const onAbortRef = useRef(onAbort);
29
+ onOutputChangeRef.current = onOutputChange;
30
+ onCompleteRef.current = onComplete;
31
+ onErrorRef.current = onError;
32
+ onAbortRef.current = onAbort;
12
33
  // Update elapsed time while running
13
34
  useEffect(() => {
14
35
  if (status !== ExecutionStatus.Running || !startTime)
@@ -37,8 +58,43 @@ export function Task({ label, command, isActive, index, initialStatus, initialEl
37
58
  setStatus(ExecutionStatus.Running);
38
59
  setStartTime(start);
39
60
  setCurrentElapsed(0);
61
+ setStdout('');
62
+ setStderr('');
63
+ setError('');
64
+ // Set up output callback to capture real-time output
65
+ setOutputCallback((data, stream) => {
66
+ if (!mounted)
67
+ return;
68
+ if (stream === 'stdout') {
69
+ setStdout((prev) => {
70
+ const newStdout = prev + data;
71
+ stdoutRef.current = newStdout;
72
+ // Report output change to parent using refs for current values
73
+ onOutputChangeRef.current?.(index, {
74
+ stdout: newStdout,
75
+ stderr: stderrRef.current,
76
+ error: errorRef.current,
77
+ });
78
+ return newStdout;
79
+ });
80
+ }
81
+ else {
82
+ setStderr((prev) => {
83
+ const newStderr = prev + data;
84
+ stderrRef.current = newStderr;
85
+ // Report output change to parent using refs for current values
86
+ onOutputChangeRef.current?.(index, {
87
+ stdout: stdoutRef.current,
88
+ stderr: newStderr,
89
+ error: errorRef.current,
90
+ });
91
+ return newStderr;
92
+ });
93
+ }
94
+ });
40
95
  try {
41
96
  const output = await executeCommand(command, undefined, index);
97
+ setOutputCallback(undefined); // Clear callback
42
98
  if (!mounted)
43
99
  return;
44
100
  const end = Date.now();
@@ -49,13 +105,28 @@ export function Task({ label, command, isActive, index, initialStatus, initialEl
49
105
  ? ExecutionStatus.Success
50
106
  : ExecutionStatus.Failed);
51
107
  if (output.result === ExecutionResult.Success) {
52
- onComplete?.(index, output, taskDuration);
108
+ const taskOutput = {
109
+ stdout: output.output,
110
+ stderr: output.errors,
111
+ error: '',
112
+ workdir: output.workdir,
113
+ };
114
+ onCompleteRef.current?.(index, taskDuration, taskOutput);
53
115
  }
54
116
  else {
55
- onError?.(index, output.errors || 'Command failed', taskDuration);
117
+ const errorMsg = output.errors || output.error || 'Command failed';
118
+ setError(errorMsg);
119
+ const taskOutput = {
120
+ stdout: output.output,
121
+ stderr: output.errors,
122
+ error: errorMsg,
123
+ workdir: output.workdir,
124
+ };
125
+ onErrorRef.current?.(index, errorMsg, taskDuration, taskOutput);
56
126
  }
57
127
  }
58
128
  catch (err) {
129
+ setOutputCallback(undefined); // Clear callback
59
130
  if (!mounted)
60
131
  return;
61
132
  const end = Date.now();
@@ -63,7 +134,20 @@ export function Task({ label, command, isActive, index, initialStatus, initialEl
63
134
  const errorDuration = calculateElapsed(start);
64
135
  setElapsed(errorDuration);
65
136
  setStatus(ExecutionStatus.Failed);
66
- onError?.(index, err instanceof Error ? err.message : 'Unknown error', errorDuration);
137
+ const errorMsg = err instanceof Error ? err.message : 'Unknown error';
138
+ setError(errorMsg);
139
+ const taskOutput = {
140
+ stdout: stdoutRef.current,
141
+ stderr: stderrRef.current,
142
+ error: errorMsg,
143
+ };
144
+ // Use try/catch to prevent callback errors from propagating
145
+ try {
146
+ onErrorRef.current?.(index, errorMsg, errorDuration, taskOutput);
147
+ }
148
+ catch {
149
+ // Callback error - already set error state above
150
+ }
67
151
  }
68
152
  }
69
153
  void execute();
@@ -79,8 +163,13 @@ export function Task({ label, command, isActive, index, initialStatus, initialEl
79
163
  setEndTime(end);
80
164
  setElapsed(calculateElapsed(startTime));
81
165
  setStatus(ExecutionStatus.Aborted);
82
- onAbort?.(index);
166
+ const taskOutput = {
167
+ stdout: stdoutRef.current,
168
+ stderr: stderrRef.current,
169
+ error: errorRef.current,
170
+ };
171
+ onAbortRef.current?.(index, taskOutput);
83
172
  }
84
- }, [isActive, status, startTime, index, onAbort]);
85
- return (_jsx(Subtask, { label: label, command: command, status: status, isActive: isActive, startTime: startTime, endTime: endTime, elapsed: status === ExecutionStatus.Running ? currentElapsed : elapsed }));
173
+ }, [isActive, status, startTime, index]);
174
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Subtask, { label: label, command: command, status: status, isActive: isActive, startTime: startTime, endTime: endTime, elapsed: status === ExecutionStatus.Running ? currentElapsed : elapsed }), _jsx(Output, { stdout: stdout, stderr: stderr, isFinished: isFinished, status: status }, `${stdout.length}-${stderr.length}`)] }));
86
175
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prompt-language-shell",
3
- "version": "0.8.8",
3
+ "version": "0.9.0",
4
4
  "description": "Your personal command-line concierge. Ask politely, and it gets things done.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",