prompt-language-shell 0.9.2 → 0.9.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/{ui/Main.js → Main.js} +12 -12
- package/dist/{ui → components}/Component.js +28 -26
- package/dist/{ui → components}/Workflow.js +14 -4
- package/dist/{ui → components/controllers}/Answer.js +18 -17
- package/dist/{ui → components/controllers}/Command.js +11 -18
- package/dist/{ui → components/controllers}/Config.js +8 -116
- package/dist/components/controllers/Confirm.js +42 -0
- package/dist/{ui → components/controllers}/Execute.js +75 -144
- package/dist/{ui → components/controllers}/Introspect.js +12 -28
- package/dist/components/controllers/Refinement.js +18 -0
- package/dist/components/controllers/Schedule.js +134 -0
- package/dist/{ui → components/controllers}/Validate.js +14 -32
- package/dist/components/views/Answer.js +28 -0
- package/dist/components/views/Command.js +11 -0
- package/dist/components/views/Config.js +115 -0
- package/dist/components/views/Confirm.js +24 -0
- package/dist/components/views/Debug.js +12 -0
- package/dist/components/views/Execute.js +60 -0
- package/dist/components/views/Feedback.js +8 -0
- package/dist/components/views/Introspect.js +17 -0
- package/dist/{ui → components/views}/Label.js +3 -3
- package/dist/{ui → components/views}/List.js +1 -1
- package/dist/{ui → components/views}/Output.js +2 -2
- package/dist/components/views/Refinement.js +9 -0
- package/dist/{ui → components/views}/Report.js +1 -1
- package/dist/components/views/Schedule.js +121 -0
- package/dist/{ui → components/views}/Separator.js +1 -1
- package/dist/{ui → components/views}/Spinner.js +1 -1
- package/dist/{ui → components/views}/Subtask.js +4 -4
- package/dist/components/views/Table.js +15 -0
- package/dist/components/views/Task.js +18 -0
- package/dist/components/views/Upcoming.js +30 -0
- package/dist/{ui → components/views}/UserQuery.js +1 -1
- package/dist/components/views/Validate.js +17 -0
- package/dist/{ui → components/views}/Welcome.js +1 -1
- package/dist/configuration/steps.js +1 -1
- package/dist/execution/handlers.js +19 -53
- package/dist/execution/reducer.js +26 -38
- package/dist/execution/runner.js +43 -25
- package/dist/execution/types.js +3 -4
- package/dist/execution/utils.js +1 -1
- package/dist/index.js +1 -1
- package/dist/services/anthropic.js +27 -31
- package/dist/services/colors.js +2 -1
- package/dist/services/logger.js +126 -13
- package/dist/services/messages.js +19 -0
- package/dist/services/parser.js +13 -5
- package/dist/services/refinement.js +8 -2
- package/dist/services/router.js +184 -89
- package/dist/services/shell.js +26 -6
- package/dist/services/skills.js +35 -7
- package/dist/services/timing.js +1 -0
- package/dist/skills/execute.md +15 -7
- package/dist/skills/schedule.md +155 -0
- package/dist/tools/execute.tool.js +0 -4
- package/dist/tools/schedule.tool.js +1 -1
- package/dist/types/schemas.js +0 -1
- package/package.json +4 -4
- package/dist/execution/hooks.js +0 -291
- package/dist/ui/Confirm.js +0 -62
- package/dist/ui/Debug.js +0 -7
- package/dist/ui/Feedback.js +0 -19
- package/dist/ui/Refinement.js +0 -23
- package/dist/ui/Schedule.js +0 -257
- package/dist/ui/Task.js +0 -11
- /package/dist/{ui → components/views}/Message.js +0 -0
- /package/dist/{ui → components/views}/Panel.js +0 -0
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
-
import { DebugLevel } from '
|
|
4
|
-
import { FeedbackType } from '
|
|
5
|
-
import { loadConfig, loadDebugSetting, saveConfig, saveDebugSetting, } from '
|
|
6
|
-
import { getConfigurationRequiredMessage } from '
|
|
7
|
-
import { getMissingConfigKeys } from '
|
|
8
|
-
import { createConfigStepsFromSchema } from '
|
|
9
|
-
import { unflattenConfig } from '
|
|
10
|
-
import { createAnthropicService } from '
|
|
11
|
-
import { createCommand, createConfig, createFeedback, createMessage, createWelcome, } from '
|
|
12
|
-
import { registerGlobalShortcut } from '
|
|
13
|
-
import { initializeLogger, setDebugLevel } from '
|
|
14
|
-
import { Workflow } from './Workflow.js';
|
|
3
|
+
import { DebugLevel } from './configuration/types.js';
|
|
4
|
+
import { FeedbackType } from './types/types.js';
|
|
5
|
+
import { loadConfig, loadDebugSetting, saveConfig, saveDebugSetting, } from './configuration/io.js';
|
|
6
|
+
import { getConfigurationRequiredMessage } from './configuration/messages.js';
|
|
7
|
+
import { getMissingConfigKeys } from './configuration/schema.js';
|
|
8
|
+
import { createConfigStepsFromSchema } from './configuration/steps.js';
|
|
9
|
+
import { unflattenConfig } from './configuration/transformation.js';
|
|
10
|
+
import { createAnthropicService } from './services/anthropic.js';
|
|
11
|
+
import { createCommand, createConfig, createFeedback, createMessage, createWelcome, } from './services/components.js';
|
|
12
|
+
import { registerGlobalShortcut } from './services/keyboard.js';
|
|
13
|
+
import { initializeLogger, setDebugLevel } from './services/logger.js';
|
|
14
|
+
import { Workflow } from './components/Workflow.js';
|
|
15
15
|
export const Main = ({ app, command, serviceFactory = createAnthropicService, }) => {
|
|
16
16
|
const [service, setService] = useState(null);
|
|
17
17
|
const [initialQueue, setInitialQueue] = useState(null);
|
|
@@ -2,20 +2,20 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { memo } from 'react';
|
|
3
3
|
import { ComponentStatus, } from '../types/components.js';
|
|
4
4
|
import { ComponentName } from '../types/types.js';
|
|
5
|
-
import { Answer, AnswerView } from './Answer.js';
|
|
6
|
-
import { Command, CommandView } from './Command.js';
|
|
7
|
-
import { Config, ConfigView } from './Config.js';
|
|
8
|
-
import { Confirm, ConfirmView } from './Confirm.js';
|
|
9
|
-
import { Debug } from './Debug.js';
|
|
10
|
-
import { Execute, ExecuteView, mapStateToViewProps } from './Execute.js';
|
|
11
|
-
import { Feedback } from './Feedback.js';
|
|
12
|
-
import { Introspect, IntrospectView } from './Introspect.js';
|
|
13
|
-
import { Message } from './Message.js';
|
|
14
|
-
import { Refinement, RefinementView } from './Refinement.js';
|
|
15
|
-
import { Report } from './Report.js';
|
|
16
|
-
import { Schedule, ScheduleView } from './Schedule.js';
|
|
17
|
-
import { Validate, ValidateView } from './Validate.js';
|
|
18
|
-
import { Welcome } from './Welcome.js';
|
|
5
|
+
import { Answer, AnswerView } from './controllers/Answer.js';
|
|
6
|
+
import { Command, CommandView } from './controllers/Command.js';
|
|
7
|
+
import { Config, ConfigView } from './controllers/Config.js';
|
|
8
|
+
import { Confirm, ConfirmView } from './controllers/Confirm.js';
|
|
9
|
+
import { Debug } from './views/Debug.js';
|
|
10
|
+
import { Execute, ExecuteView, mapStateToViewProps, } from './controllers/Execute.js';
|
|
11
|
+
import { Feedback } from './views/Feedback.js';
|
|
12
|
+
import { Introspect, IntrospectView } from './controllers/Introspect.js';
|
|
13
|
+
import { Message } from './views/Message.js';
|
|
14
|
+
import { Refinement, RefinementView } from './controllers/Refinement.js';
|
|
15
|
+
import { Report } from './views/Report.js';
|
|
16
|
+
import { Schedule, ScheduleView } from './controllers/Schedule.js';
|
|
17
|
+
import { Validate, ValidateView } from './controllers/Validate.js';
|
|
18
|
+
import { Welcome } from './views/Welcome.js';
|
|
19
19
|
/**
|
|
20
20
|
* Render a simple component (no lifecycle management)
|
|
21
21
|
*/
|
|
@@ -75,16 +75,16 @@ export const ControllerComponent = memo(function ControllerComponent({ def, debu
|
|
|
75
75
|
return (_jsx(Introspect, { tasks: tasks, service: service, children: children, requestHandlers: requestHandlers, lifecycleHandlers: lifecycleHandlers, workflowHandlers: workflowHandlers, status: status, debug: debug }));
|
|
76
76
|
}
|
|
77
77
|
case ComponentName.Answer: {
|
|
78
|
-
const { props: { question, service }, status, } = def;
|
|
79
|
-
return (_jsx(Answer, { question: question, service: service, requestHandlers: requestHandlers, lifecycleHandlers: lifecycleHandlers, workflowHandlers: workflowHandlers, status: status }));
|
|
78
|
+
const { props: { question, service, upcoming }, status, } = def;
|
|
79
|
+
return (_jsx(Answer, { question: question, service: service, upcoming: upcoming, requestHandlers: requestHandlers, lifecycleHandlers: lifecycleHandlers, workflowHandlers: workflowHandlers, status: status }));
|
|
80
80
|
}
|
|
81
81
|
case ComponentName.Validate: {
|
|
82
82
|
const { props: { missingConfig, userRequest, service, onError, onValidationComplete, onAborted, }, status, } = def;
|
|
83
83
|
return (_jsx(Validate, { missingConfig: missingConfig, userRequest: userRequest, service: service, onError: onError, onValidationComplete: onValidationComplete, onAborted: onAborted, requestHandlers: requestHandlers, lifecycleHandlers: lifecycleHandlers, workflowHandlers: workflowHandlers, status: status }));
|
|
84
84
|
}
|
|
85
85
|
case ComponentName.Execute: {
|
|
86
|
-
const { props: { tasks, service }, status, } = def;
|
|
87
|
-
return (_jsx(Execute, { tasks: tasks, service: service, requestHandlers: requestHandlers, lifecycleHandlers: lifecycleHandlers, workflowHandlers: workflowHandlers, status: status }));
|
|
86
|
+
const { props: { tasks, service, upcoming, label }, status, } = def;
|
|
87
|
+
return (_jsx(Execute, { tasks: tasks, service: service, upcoming: upcoming, label: label, requestHandlers: requestHandlers, lifecycleHandlers: lifecycleHandlers, workflowHandlers: workflowHandlers, status: status }));
|
|
88
88
|
}
|
|
89
89
|
default:
|
|
90
90
|
throw new Error(`Unknown managed component: ${def.name}`);
|
|
@@ -97,7 +97,7 @@ export const ViewComponent = memo(function ViewComponent({ def, }) {
|
|
|
97
97
|
switch (def.name) {
|
|
98
98
|
case ComponentName.Confirm: {
|
|
99
99
|
const { props: { message }, state, status, } = def;
|
|
100
|
-
return _jsx(ConfirmView, {
|
|
100
|
+
return (_jsx(ConfirmView, { status: status, message: message, selectedIndex: state.selectedIndex }));
|
|
101
101
|
}
|
|
102
102
|
case ComponentName.Config: {
|
|
103
103
|
const { props: { steps }, state, status, } = def;
|
|
@@ -105,17 +105,18 @@ export const ViewComponent = memo(function ViewComponent({ def, }) {
|
|
|
105
105
|
}
|
|
106
106
|
case ComponentName.Schedule: {
|
|
107
107
|
const { props: { message, tasks }, state, status, } = def;
|
|
108
|
-
return (_jsx(ScheduleView, { message: message, tasks: tasks, state: state,
|
|
108
|
+
return (_jsx(ScheduleView, { status: status, message: message, tasks: tasks, highlightedIndex: state.highlightedIndex, currentDefineGroupIndex: state.currentDefineGroupIndex, completedSelections: state.completedSelections }));
|
|
109
109
|
}
|
|
110
110
|
case ComponentName.Execute: {
|
|
111
|
-
const { state, status } = def;
|
|
111
|
+
const { props: { upcoming, label }, state, status, } = def;
|
|
112
112
|
const isActive = status === ComponentStatus.Active;
|
|
113
|
-
const viewProps = mapStateToViewProps(state, isActive);
|
|
113
|
+
const viewProps = mapStateToViewProps(state, isActive, upcoming, label);
|
|
114
114
|
return _jsx(ExecuteView, { ...viewProps });
|
|
115
115
|
}
|
|
116
116
|
case ComponentName.Answer: {
|
|
117
|
-
const { props: { question }, state, status, } = def;
|
|
118
|
-
|
|
117
|
+
const { props: { question, upcoming }, state, status, } = def;
|
|
118
|
+
const lines = state.answer ? state.answer.split('\n') : null;
|
|
119
|
+
return (_jsx(AnswerView, { status: status, question: question, lines: lines, error: state.error, upcoming: upcoming, cancelled: state.cancelled }));
|
|
119
120
|
}
|
|
120
121
|
case ComponentName.Command: {
|
|
121
122
|
const { props: { command }, state, status, } = def;
|
|
@@ -123,11 +124,12 @@ export const ViewComponent = memo(function ViewComponent({ def, }) {
|
|
|
123
124
|
}
|
|
124
125
|
case ComponentName.Introspect: {
|
|
125
126
|
const { props: { children }, state, status, } = def;
|
|
126
|
-
|
|
127
|
+
const hasCapabilities = state.capabilities.length > 0;
|
|
128
|
+
return (_jsx(IntrospectView, { status: status, hasCapabilities: hasCapabilities, error: state.error, children: children }));
|
|
127
129
|
}
|
|
128
130
|
case ComponentName.Validate: {
|
|
129
131
|
const { state, status } = def;
|
|
130
|
-
return _jsx(ValidateView, {
|
|
132
|
+
return (_jsx(ValidateView, { status: status, completionMessage: state.completionMessage, error: state.error }));
|
|
131
133
|
}
|
|
132
134
|
case ComponentName.Refinement: {
|
|
133
135
|
const { props: { text }, status, } = def;
|
|
@@ -47,9 +47,8 @@ export const Workflow = ({ initialQueue, debug }) => {
|
|
|
47
47
|
const requestHandlers = useMemo(() => ({
|
|
48
48
|
onError: (error) => {
|
|
49
49
|
moveActiveToTimeline();
|
|
50
|
-
//
|
|
51
|
-
setQueue(
|
|
52
|
-
...queue,
|
|
50
|
+
// Clear queue and add only feedback to prevent subsequent components from executing
|
|
51
|
+
setQueue([
|
|
53
52
|
createFeedback({ type: FeedbackType.Failed, message: error }),
|
|
54
53
|
]);
|
|
55
54
|
},
|
|
@@ -108,7 +107,18 @@ export const Workflow = ({ initialQueue, debug }) => {
|
|
|
108
107
|
setQueue((queue) => [...queue, ...items]);
|
|
109
108
|
},
|
|
110
109
|
addToTimeline: (...items) => {
|
|
111
|
-
|
|
110
|
+
// Flush pending to timeline first, then add new items
|
|
111
|
+
// Both are added in a SINGLE setTimeline call to guarantee order
|
|
112
|
+
setCurrent((curr) => {
|
|
113
|
+
const { active, pending } = curr;
|
|
114
|
+
if (pending) {
|
|
115
|
+
const donePending = markAsDone(pending);
|
|
116
|
+
setTimeline((prev) => [...prev, donePending, ...items]);
|
|
117
|
+
return { active, pending: null };
|
|
118
|
+
}
|
|
119
|
+
setTimeline((prev) => [...prev, ...items]);
|
|
120
|
+
return curr;
|
|
121
|
+
});
|
|
112
122
|
},
|
|
113
123
|
}), []);
|
|
114
124
|
// Global Esc handler removed - components handle their own Esc individually
|
|
@@ -1,28 +1,29 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import { Spinner } from './Spinner.js';
|
|
3
|
+
import { ComponentStatus, } from '../../types/components.js';
|
|
4
|
+
import { useInput } from '../../services/keyboard.js';
|
|
5
|
+
import { formatErrorMessage } from '../../services/messages.js';
|
|
6
|
+
import { withMinimumTime } from '../../services/timing.js';
|
|
7
|
+
import { AnswerView } from '../views/Answer.js';
|
|
8
|
+
export { AnswerView } from '../views/Answer.js';
|
|
10
9
|
const MINIMUM_PROCESSING_TIME = 400;
|
|
11
|
-
export const AnswerView = ({ question, state, status }) => {
|
|
12
|
-
const isActive = status === ComponentStatus.Active;
|
|
13
|
-
const { error, answer } = state;
|
|
14
|
-
const lines = answer ? answer.split('\n') : [];
|
|
15
|
-
return (_jsxs(Box, { alignSelf: "flex-start", flexDirection: "column", children: [isActive && !answer && !error && (_jsxs(Box, { marginLeft: 1, children: [_jsx(Text, { color: getTextColor(isActive), children: "Finding answer. " }), _jsx(Spinner, {})] })), answer && (_jsxs(_Fragment, { children: [_jsx(Box, { marginLeft: 1, marginBottom: 1, children: _jsx(Text, { color: getTextColor(isActive), children: question }) }), _jsx(Box, { flexDirection: "column", paddingLeft: 3, children: lines.map((line, index) => (_jsx(Text, { color: getTextColor(isActive), children: line }, index))) })] })), error && (_jsx(Box, { marginTop: 1, marginLeft: 1, children: _jsxs(Text, { color: Colors.Status.Error, children: ["Error: ", error] }) }))] }));
|
|
16
|
-
};
|
|
17
10
|
/**
|
|
18
11
|
* Answer controller: Fetches answer from LLM
|
|
19
12
|
*/
|
|
20
|
-
export function Answer({ question, status, service, requestHandlers, lifecycleHandlers, workflowHandlers, }) {
|
|
13
|
+
export function Answer({ question, status, service, upcoming, requestHandlers, lifecycleHandlers, workflowHandlers, }) {
|
|
21
14
|
const isActive = status === ComponentStatus.Active;
|
|
22
15
|
const [error, setError] = useState(null);
|
|
23
16
|
const [answer, setAnswer] = useState(null);
|
|
17
|
+
const [cancelled, setCancelled] = useState(false);
|
|
24
18
|
useInput((input, key) => {
|
|
25
19
|
if (key.escape && isActive) {
|
|
20
|
+
setCancelled(true);
|
|
21
|
+
const finalState = {
|
|
22
|
+
answer: null,
|
|
23
|
+
error: null,
|
|
24
|
+
cancelled: true,
|
|
25
|
+
};
|
|
26
|
+
requestHandlers.onCompleted(finalState);
|
|
26
27
|
requestHandlers.onAborted('answer');
|
|
27
28
|
}
|
|
28
29
|
}, { isActive });
|
|
@@ -80,6 +81,6 @@ export function Answer({ question, status, service, requestHandlers, lifecycleHa
|
|
|
80
81
|
lifecycleHandlers,
|
|
81
82
|
workflowHandlers,
|
|
82
83
|
]);
|
|
83
|
-
const
|
|
84
|
-
return _jsx(AnswerView, { question: question,
|
|
84
|
+
const lines = answer ? answer.split('\n') : null;
|
|
85
|
+
return (_jsx(AnswerView, { status: status, question: question, lines: lines, error: error, upcoming: upcoming, cancelled: cancelled }));
|
|
85
86
|
}
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
import { Spinner } from './Spinner.js';
|
|
14
|
-
import { UserQuery } from './UserQuery.js';
|
|
3
|
+
import { ComponentStatus, } from '../../types/components.js';
|
|
4
|
+
import { TaskType } from '../../types/types.js';
|
|
5
|
+
import { createSchedule } from '../../services/components.js';
|
|
6
|
+
import { useInput } from '../../services/keyboard.js';
|
|
7
|
+
import { formatErrorMessage } from '../../services/messages.js';
|
|
8
|
+
import { handleRefinement } from '../../services/refinement.js';
|
|
9
|
+
import { routeTasksWithConfirm } from '../../services/router.js';
|
|
10
|
+
import { ensureMinimumTime } from '../../services/timing.js';
|
|
11
|
+
import { CommandView } from '../views/Command.js';
|
|
12
|
+
export { CommandView } from '../views/Command.js';
|
|
15
13
|
const MIN_PROCESSING_TIME = 400; // purely for visual effect
|
|
16
|
-
export const CommandView = ({ command, state, status }) => {
|
|
17
|
-
const isActive = status === ComponentStatus.Active;
|
|
18
|
-
const { error } = state;
|
|
19
|
-
return (_jsxs(Box, { alignSelf: "flex-start", flexDirection: "column", children: [!isActive ? (_jsxs(UserQuery, { children: ["> pls ", command] })) : (_jsxs(Box, { marginLeft: 1, children: [_jsxs(Text, { color: Colors.Text.Active, children: ["> pls ", command] }), _jsx(Text, { children: " " }), _jsx(Spinner, {})] })), error && (_jsx(Box, { marginTop: 1, marginLeft: 1, children: _jsxs(Text, { color: Colors.Status.Error, children: ["Error: ", error] }) }))] }));
|
|
20
|
-
};
|
|
21
14
|
/**
|
|
22
15
|
* Command controller: Processes and routes command
|
|
23
16
|
*/
|
|
@@ -1,120 +1,12 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
import { useInput } from '../services/keyboard.js';
|
|
11
|
-
/**
|
|
12
|
-
* Get postfix with debug brackets if debug is enabled
|
|
13
|
-
* Info: {key} | Verbose: {key} entry
|
|
14
|
-
*/
|
|
15
|
-
function getPostfix(text, debugLevel) {
|
|
16
|
-
if (debugLevel === DebugLevel.None || !text) {
|
|
17
|
-
return '';
|
|
18
|
-
}
|
|
19
|
-
if (debugLevel === DebugLevel.Info) {
|
|
20
|
-
return `{${text}}`;
|
|
21
|
-
}
|
|
22
|
-
return `{${text}} entry`;
|
|
23
|
-
}
|
|
24
|
-
export var StepType;
|
|
25
|
-
(function (StepType) {
|
|
26
|
-
StepType["Text"] = "text";
|
|
27
|
-
StepType["Selection"] = "selection";
|
|
28
|
-
})(StepType || (StepType = {}));
|
|
29
|
-
function TextStep({ value, placeholder, validate, onChange, onSubmit, }) {
|
|
30
|
-
const [inputValue, setInputValue] = useState(value);
|
|
31
|
-
const [validationFailed, setValidationFailed] = useState(false);
|
|
32
|
-
const { isFocused } = useFocus({ autoFocus: true });
|
|
33
|
-
// Sync internal state with prop changes
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
setInputValue(value);
|
|
36
|
-
}, [value]);
|
|
37
|
-
const handleChange = (newValue) => {
|
|
38
|
-
setInputValue(newValue);
|
|
39
|
-
onChange(newValue);
|
|
40
|
-
if (validationFailed) {
|
|
41
|
-
setValidationFailed(false);
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
const handleSubmit = (value) => {
|
|
45
|
-
// Use placeholder if input is empty
|
|
46
|
-
const finalValue = value || placeholder || '';
|
|
47
|
-
if (!validate(finalValue)) {
|
|
48
|
-
setValidationFailed(true);
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
onSubmit(finalValue);
|
|
52
|
-
};
|
|
53
|
-
// Handle input manually when validation fails
|
|
54
|
-
useInput((input, key) => {
|
|
55
|
-
if (!validationFailed)
|
|
56
|
-
return;
|
|
57
|
-
if (key.return) {
|
|
58
|
-
handleSubmit(inputValue);
|
|
59
|
-
}
|
|
60
|
-
else if (key.backspace || key.delete) {
|
|
61
|
-
const newValue = inputValue.slice(0, -1);
|
|
62
|
-
handleChange(newValue);
|
|
63
|
-
}
|
|
64
|
-
else if (!key.ctrl && !key.meta && input) {
|
|
65
|
-
const newValue = inputValue + input;
|
|
66
|
-
handleChange(newValue);
|
|
67
|
-
}
|
|
68
|
-
}, { isActive: validationFailed });
|
|
69
|
-
// When validation fails, show colored text
|
|
70
|
-
if (validationFailed) {
|
|
71
|
-
return (_jsxs(Text, { color: Colors.Status.Error, children: [inputValue || placeholder, isFocused && _jsx(Text, { inverse: true, children: " " })] }));
|
|
72
|
-
}
|
|
73
|
-
return (_jsx(TextInput, { value: inputValue, onChange: handleChange, onSubmit: handleSubmit, placeholder: placeholder }));
|
|
74
|
-
}
|
|
75
|
-
function SelectionStep({ options, selectedIndex, isCurrentStep, }) {
|
|
76
|
-
return (_jsx(Box, { children: options.map((option, optIndex) => {
|
|
77
|
-
const isSelected = optIndex === selectedIndex;
|
|
78
|
-
return (_jsx(Box, { marginRight: 2, children: _jsx(Text, { dimColor: !isSelected || !isCurrentStep, bold: isSelected, children: option.label }) }, option.value));
|
|
79
|
-
}) }));
|
|
80
|
-
}
|
|
81
|
-
export const ConfigView = ({ steps, state, status, debug = DebugLevel.None, onInputChange, onInputSubmit, }) => {
|
|
82
|
-
const isActive = status === ComponentStatus.Active;
|
|
83
|
-
const { values, completedStep, selectedIndex } = state;
|
|
84
|
-
const renderStepInput = (stepConfig, isCurrentStep) => {
|
|
85
|
-
const configKey = stepConfig.path || stepConfig.key;
|
|
86
|
-
const displayValue = values[configKey];
|
|
87
|
-
switch (stepConfig.type) {
|
|
88
|
-
case StepType.Text:
|
|
89
|
-
if (isCurrentStep && onInputChange && onInputSubmit) {
|
|
90
|
-
return (_jsx(TextStep, { value: values[configKey] || '', placeholder: stepConfig.value || undefined, validate: stepConfig.validate, onChange: onInputChange, onSubmit: onInputSubmit }));
|
|
91
|
-
}
|
|
92
|
-
return (_jsx(Text, { dimColor: true, wrap: "truncate-end", children: displayValue || '' }));
|
|
93
|
-
case StepType.Selection: {
|
|
94
|
-
if (!isCurrentStep) {
|
|
95
|
-
const option = stepConfig.options.find((opt) => opt.value === displayValue);
|
|
96
|
-
return _jsx(Text, { dimColor: true, children: option?.label || '' });
|
|
97
|
-
}
|
|
98
|
-
return (_jsx(SelectionStep, { options: stepConfig.options, selectedIndex: selectedIndex, isCurrentStep: true }));
|
|
99
|
-
}
|
|
100
|
-
default: {
|
|
101
|
-
const _exhaustiveCheck = stepConfig;
|
|
102
|
-
throw new Error('Unsupported step type');
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
return (_jsx(Box, { flexDirection: "column", marginLeft: 1, children: steps.map((stepConfig, index) => {
|
|
107
|
-
const isCurrentStep = index === completedStep && isActive;
|
|
108
|
-
const isCompleted = index < completedStep;
|
|
109
|
-
const wasAborted = index === completedStep && !isActive;
|
|
110
|
-
const shouldShow = isCompleted || isCurrentStep || wasAborted;
|
|
111
|
-
if (!shouldShow) {
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
const postfix = getPostfix(stepConfig.path, debug);
|
|
115
|
-
return (_jsxs(Box, { flexDirection: "column", marginTop: index === 0 ? 0 : 1, children: [_jsxs(Box, { children: [_jsx(Text, { children: stepConfig.description }), _jsx(Text, { children: ": " }), postfix && _jsx(Text, { color: Colors.Type.Config, children: postfix })] }), _jsxs(Box, { children: [_jsx(Text, { children: " " }), _jsx(Text, { color: Colors.Action.Select, dimColor: !isCurrentStep, children: ">" }), _jsx(Text, { children: " " }), renderStepInput(stepConfig, isCurrentStep)] })] }, stepConfig.path || stepConfig.key));
|
|
116
|
-
}) }));
|
|
117
|
-
};
|
|
3
|
+
import { ComponentStatus } from '../../types/components.js';
|
|
4
|
+
import { FeedbackType } from '../../types/types.js';
|
|
5
|
+
import { createFeedback } from '../../services/components.js';
|
|
6
|
+
import { DebugLevel } from '../../configuration/types.js';
|
|
7
|
+
import { useInput } from '../../services/keyboard.js';
|
|
8
|
+
import { ConfigView, StepType } from '../views/Config.js';
|
|
9
|
+
export { ConfigView, StepType, } from '../views/Config.js';
|
|
118
10
|
/**
|
|
119
11
|
* Config controller: Multi-step wizard logic
|
|
120
12
|
*/
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { ComponentStatus, } from '../../types/components.js';
|
|
4
|
+
import { useInput } from '../../services/keyboard.js';
|
|
5
|
+
import { ConfirmView } from '../views/Confirm.js';
|
|
6
|
+
export { ConfirmView } from '../views/Confirm.js';
|
|
7
|
+
/**
|
|
8
|
+
* Confirm controller: Manages yes/no selection
|
|
9
|
+
*/
|
|
10
|
+
export function Confirm({ message, status, requestHandlers, onConfirmed, onCancelled, }) {
|
|
11
|
+
const isActive = status === ComponentStatus.Active;
|
|
12
|
+
const [selectedIndex, setSelectedIndex] = useState(0); // 0 = Yes, 1 = No
|
|
13
|
+
useInput((input, key) => {
|
|
14
|
+
if (!isActive)
|
|
15
|
+
return;
|
|
16
|
+
if (key.escape) {
|
|
17
|
+
// Escape: highlight "No" and cancel
|
|
18
|
+
const finalState = { selectedIndex: 1, confirmed: false };
|
|
19
|
+
requestHandlers.onCompleted(finalState);
|
|
20
|
+
onCancelled();
|
|
21
|
+
}
|
|
22
|
+
else if (key.tab) {
|
|
23
|
+
// Toggle between Yes (0) and No (1)
|
|
24
|
+
setSelectedIndex((prev) => (prev === 0 ? 1 : 0));
|
|
25
|
+
}
|
|
26
|
+
else if (key.return) {
|
|
27
|
+
// Confirm selection
|
|
28
|
+
const finalState = {
|
|
29
|
+
selectedIndex,
|
|
30
|
+
confirmed: true,
|
|
31
|
+
};
|
|
32
|
+
requestHandlers.onCompleted(finalState);
|
|
33
|
+
if (selectedIndex === 0) {
|
|
34
|
+
onConfirmed();
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
onCancelled();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}, { isActive });
|
|
41
|
+
return (_jsx(ConfirmView, { status: status, message: message, selectedIndex: selectedIndex }));
|
|
42
|
+
}
|