prompt-language-shell 0.8.0 → 0.8.4

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.
@@ -0,0 +1,23 @@
1
+ import { TaskType } from './types.js';
2
+ import { TaskSchema } from './schemas.js';
3
+ /**
4
+ * Type guard to check if a task is a ScheduledTask
5
+ * ScheduledTask has optional subtasks property or is a Group type
6
+ */
7
+ export function isScheduledTask(task) {
8
+ return 'subtasks' in task || task.type === TaskType.Group;
9
+ }
10
+ /**
11
+ * Type-safe conversion of Task array to ScheduledTask array
12
+ * This is safe because Tasks can be treated as ScheduledTask when checking for Groups
13
+ */
14
+ export function asScheduledTasks(tasks) {
15
+ return tasks;
16
+ }
17
+ /**
18
+ * Type guard to check if a value is a valid Task.
19
+ * Uses Zod schema for comprehensive runtime validation.
20
+ */
21
+ export function isTask(value) {
22
+ return TaskSchema.safeParse(value).success;
23
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,103 @@
1
+ import { z } from 'zod';
2
+ import { Origin, TaskType } from './types.js';
3
+ /**
4
+ * Zod schema for TaskType enum values.
5
+ * Validates that task types match the expected enum values.
6
+ */
7
+ export const TaskTypeSchema = z.enum([
8
+ TaskType.Config,
9
+ TaskType.Schedule,
10
+ TaskType.Execute,
11
+ TaskType.Answer,
12
+ TaskType.Introspect,
13
+ TaskType.Report,
14
+ TaskType.Define,
15
+ TaskType.Ignore,
16
+ TaskType.Select,
17
+ TaskType.Discard,
18
+ TaskType.Group,
19
+ ]);
20
+ /**
21
+ * Zod schema for Origin enum values.
22
+ * Validates capability origin types.
23
+ */
24
+ export const OriginSchema = z.enum([
25
+ Origin.BuiltIn,
26
+ Origin.UserProvided,
27
+ Origin.Indirect,
28
+ ]);
29
+ /**
30
+ * Zod schema for base Task type.
31
+ * Validates task structure with required action and type fields.
32
+ */
33
+ export const TaskSchema = z.object({
34
+ action: z.string().min(1),
35
+ type: TaskTypeSchema,
36
+ params: z.record(z.string(), z.unknown()).optional(),
37
+ config: z.array(z.string()).optional(),
38
+ });
39
+ /**
40
+ * Zod schema for recursive ScheduledTask type.
41
+ * Uses z.lazy for self-referential subtasks validation.
42
+ */
43
+ export const ScheduledTaskSchema = z.object({
44
+ action: z.string().min(1),
45
+ type: TaskTypeSchema,
46
+ params: z.record(z.string(), z.unknown()).optional(),
47
+ config: z.array(z.string()).optional(),
48
+ subtasks: z.lazy(() => ScheduledTaskSchema.array()).optional(),
49
+ });
50
+ /**
51
+ * Zod schema for ExecuteCommand type.
52
+ * Validates shell command execution parameters.
53
+ */
54
+ export const ExecuteCommandSchema = z.object({
55
+ description: z.string().min(1),
56
+ command: z.string().min(1),
57
+ workdir: z.string().optional(),
58
+ timeout: z.number().int().positive().optional(),
59
+ critical: z.boolean().optional(),
60
+ });
61
+ /**
62
+ * Zod schema for Capability type.
63
+ * Validates skill and capability definitions.
64
+ */
65
+ export const CapabilitySchema = z.object({
66
+ name: z.string().min(1),
67
+ description: z.string().min(1),
68
+ origin: OriginSchema,
69
+ isIncomplete: z.boolean().optional(),
70
+ });
71
+ /**
72
+ * Zod schema for ComponentDefinition type.
73
+ * Flexible schema for debug component validation.
74
+ * Accepts both stateless and stateful component structures.
75
+ */
76
+ export const ComponentDefinitionSchema = z.object({
77
+ id: z.string(),
78
+ name: z.string(),
79
+ props: z.record(z.string(), z.unknown()),
80
+ state: z.record(z.string(), z.unknown()).optional(),
81
+ status: z.string().optional(),
82
+ });
83
+ /**
84
+ * Zod schema for CommandResult type.
85
+ * Validates LLM responses from execute, answer, and schedule tools.
86
+ */
87
+ export const CommandResultSchema = z.object({
88
+ message: z.string(),
89
+ summary: z.string().optional(),
90
+ tasks: z.array(ScheduledTaskSchema),
91
+ answer: z.string().optional(),
92
+ commands: z.array(ExecuteCommandSchema).optional(),
93
+ debug: z.array(ComponentDefinitionSchema).optional(),
94
+ });
95
+ /**
96
+ * Zod schema for IntrospectResult type.
97
+ * Validates LLM responses from introspect tool.
98
+ */
99
+ export const IntrospectResultSchema = z.object({
100
+ message: z.string(),
101
+ capabilities: z.array(CapabilitySchema),
102
+ debug: z.array(ComponentDefinitionSchema).optional(),
103
+ });
@@ -29,9 +29,16 @@ export var TaskType;
29
29
  TaskType["Discard"] = "discard";
30
30
  TaskType["Group"] = "group";
31
31
  })(TaskType || (TaskType = {}));
32
+ export var Origin;
33
+ (function (Origin) {
34
+ Origin["BuiltIn"] = "system";
35
+ Origin["UserProvided"] = "user";
36
+ Origin["Indirect"] = "meta";
37
+ })(Origin || (Origin = {}));
32
38
  export var FeedbackType;
33
39
  (function (FeedbackType) {
34
40
  FeedbackType["Info"] = "info";
41
+ FeedbackType["Warning"] = "warning";
35
42
  FeedbackType["Succeeded"] = "succeeded";
36
43
  FeedbackType["Aborted"] = "aborted";
37
44
  FeedbackType["Failed"] = "failed";
package/dist/ui/Answer.js CHANGED
@@ -3,19 +3,18 @@ import { useEffect, useState } from 'react';
3
3
  import { Box, Text } from 'ink';
4
4
  import { ComponentStatus } from '../types/components.js';
5
5
  import { Colors, getTextColor } from '../services/colors.js';
6
- import { addDebugToTimeline } from '../services/components.js';
7
6
  import { useInput } from '../services/keyboard.js';
8
7
  import { formatErrorMessage } from '../services/messages.js';
9
8
  import { withMinimumTime } from '../services/timing.js';
10
9
  import { Spinner } from './Spinner.js';
11
10
  const MINIMUM_PROCESSING_TIME = 400;
12
- export function Answer({ question, state, status, service, handlers, }) {
11
+ export function Answer({ question, state, status, service, stateHandlers, lifecycleHandlers, errorHandlers, workflowHandlers, }) {
13
12
  const isActive = status === ComponentStatus.Active;
14
13
  const [error, setError] = useState(null);
15
14
  const [answer, setAnswer] = useState(state?.answer ?? null);
16
15
  useInput((input, key) => {
17
16
  if (key.escape && isActive) {
18
- handlers?.onAborted('answer');
17
+ errorHandlers?.onAborted('answer');
19
18
  }
20
19
  }, { isActive });
21
20
  useEffect(() => {
@@ -23,11 +22,6 @@ export function Answer({ question, state, status, service, handlers, }) {
23
22
  if (!isActive) {
24
23
  return;
25
24
  }
26
- // Skip processing if no service available
27
- if (!service) {
28
- setError('No service available');
29
- return;
30
- }
31
25
  let mounted = true;
32
26
  async function process(svc) {
33
27
  try {
@@ -35,34 +29,36 @@ export function Answer({ question, state, status, service, handlers, }) {
35
29
  const result = await withMinimumTime(() => svc.processWithTool(question, 'answer'), MINIMUM_PROCESSING_TIME);
36
30
  if (mounted) {
37
31
  // Add debug components to timeline if present
38
- addDebugToTimeline(result.debug, handlers);
32
+ if (result.debug?.length) {
33
+ workflowHandlers?.addToTimeline(...result.debug);
34
+ }
39
35
  // Extract answer from result
40
36
  const answerText = result.answer || '';
41
37
  setAnswer(answerText);
42
38
  // Update component state so answer persists in timeline
43
- handlers?.updateState({
39
+ stateHandlers?.updateState({
44
40
  answer: answerText,
45
41
  });
46
42
  // Signal completion
47
- handlers?.completeActive();
43
+ lifecycleHandlers?.completeActive();
48
44
  }
49
45
  }
50
46
  catch (err) {
51
47
  if (mounted) {
52
48
  const errorMessage = formatErrorMessage(err);
53
49
  setError(errorMessage);
54
- handlers?.updateState({
50
+ stateHandlers?.updateState({
55
51
  error: errorMessage,
56
52
  });
57
- handlers?.onError(errorMessage);
53
+ errorHandlers?.onError(errorMessage);
58
54
  }
59
55
  }
60
56
  }
61
- process(service);
57
+ void process(service);
62
58
  return () => {
63
59
  mounted = false;
64
60
  };
65
- }, [question, isActive, service, handlers]);
61
+ }, [question, isActive, service]);
66
62
  const lines = answer ? answer.split('\n') : [];
67
63
  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] }) }))] }));
68
64
  }
@@ -1,10 +1,10 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from 'react';
3
3
  import { Box, Text } from 'ink';
4
- import { ComponentStatus, } from '../types/components.js';
4
+ import { ComponentStatus } from '../types/components.js';
5
5
  import { TaskType } from '../types/types.js';
6
6
  import { Colors } from '../services/colors.js';
7
- import { addDebugToTimeline, createScheduleDefinition, } from '../services/components.js';
7
+ import { createScheduleDefinition } from '../services/components.js';
8
8
  import { useInput } from '../services/keyboard.js';
9
9
  import { formatErrorMessage } from '../services/messages.js';
10
10
  import { handleRefinement } from '../services/refinement.js';
@@ -13,12 +13,12 @@ import { ensureMinimumTime } from '../services/timing.js';
13
13
  import { Spinner } from './Spinner.js';
14
14
  import { UserQuery } from './UserQuery.js';
15
15
  const MIN_PROCESSING_TIME = 400; // purely for visual effect
16
- export function Command({ command, state, status, service, handlers, onAborted, }) {
16
+ export function Command({ command, state, status, service, stateHandlers, lifecycleHandlers, queueHandlers, errorHandlers, workflowHandlers, onAborted, }) {
17
17
  const isActive = status === ComponentStatus.Active;
18
18
  const [error, setError] = useState(state?.error ?? null);
19
19
  useInput((_, key) => {
20
20
  if (key.escape && isActive) {
21
- handlers?.onAborted('request');
21
+ errorHandlers?.onAborted('request');
22
22
  onAborted?.('request');
23
23
  }
24
24
  }, { isActive });
@@ -27,11 +27,6 @@ export function Command({ command, state, status, service, handlers, onAborted,
27
27
  if (!isActive) {
28
28
  return;
29
29
  }
30
- // Skip processing if no service available
31
- if (!service) {
32
- setError('No service available');
33
- return;
34
- }
35
30
  let mounted = true;
36
31
  async function process(svc) {
37
32
  const startTime = Date.now();
@@ -56,30 +51,39 @@ export function Command({ command, state, status, service, handlers, onAborted,
56
51
  const debugComponents = allConfig
57
52
  ? [...scheduleDebug, ...(result.debug || [])]
58
53
  : scheduleDebug;
59
- addDebugToTimeline(debugComponents, handlers);
54
+ if (debugComponents.length > 0) {
55
+ workflowHandlers?.addToTimeline(...debugComponents);
56
+ }
60
57
  // Save result to state for timeline display
61
- handlers?.updateState({
58
+ stateHandlers?.updateState({
62
59
  message: result.message,
63
60
  tasks: result.tasks,
64
61
  });
65
62
  // Check if tasks contain DEFINE type (variant selection needed)
66
63
  const hasDefineTask = result.tasks.some((task) => task.type === TaskType.Define);
64
+ // Guard: ensure all required handlers are present
65
+ if (!queueHandlers ||
66
+ !lifecycleHandlers ||
67
+ !workflowHandlers ||
68
+ !errorHandlers) {
69
+ return;
70
+ }
67
71
  // Create Schedule definition
68
72
  const scheduleDefinition = createScheduleDefinition(result.message, result.tasks, hasDefineTask
69
73
  ? async (selectedTasks) => {
70
74
  // Refinement flow for DEFINE tasks
71
- await handleRefinement(selectedTasks, svc, command, handlers);
75
+ await handleRefinement(selectedTasks, svc, command, queueHandlers, lifecycleHandlers, workflowHandlers, errorHandlers);
72
76
  }
73
77
  : undefined);
74
78
  if (hasDefineTask) {
75
79
  // DEFINE tasks: Move Command to timeline, add Schedule to queue
76
- handlers?.completeActive();
77
- handlers?.addToQueue(scheduleDefinition);
80
+ lifecycleHandlers.completeActive();
81
+ queueHandlers.addToQueue(scheduleDefinition);
78
82
  }
79
83
  else {
80
84
  // No DEFINE tasks: Complete Command, then route to Confirm flow
81
- handlers?.completeActive();
82
- routeTasksWithConfirm(result.tasks, result.message, svc, command, handlers, false);
85
+ lifecycleHandlers.completeActive();
86
+ routeTasksWithConfirm(result.tasks, result.message, svc, command, queueHandlers, workflowHandlers, errorHandlers, false);
83
87
  }
84
88
  }
85
89
  }
@@ -88,17 +92,17 @@ export function Command({ command, state, status, service, handlers, onAborted,
88
92
  if (mounted) {
89
93
  const errorMessage = formatErrorMessage(err);
90
94
  setError(errorMessage);
91
- handlers?.updateState({
95
+ stateHandlers?.updateState({
92
96
  error: errorMessage,
93
97
  });
94
- handlers?.onError(errorMessage);
98
+ errorHandlers?.onError(errorMessage);
95
99
  }
96
100
  }
97
101
  }
98
- process(service);
102
+ void process(service);
99
103
  return () => {
100
104
  mounted = false;
101
105
  };
102
- }, [command, isActive, service, handlers]);
106
+ }, [command, isActive, service]);
103
107
  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] }) }))] }));
104
108
  }
package/dist/ui/Config.js CHANGED
@@ -8,6 +8,19 @@ import { Colors } from '../services/colors.js';
8
8
  import { createFeedback } from '../services/components.js';
9
9
  import { DebugLevel } from '../services/configuration.js';
10
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
+ }
11
24
  export var StepType;
12
25
  (function (StepType) {
13
26
  StepType["Text"] = "text";
@@ -65,7 +78,8 @@ function SelectionStep({ options, selectedIndex, isCurrentStep, }) {
65
78
  return (_jsx(Box, { marginRight: 2, children: _jsx(Text, { dimColor: !isSelected || !isCurrentStep, bold: isSelected, children: option.label }) }, option.value));
66
79
  }) }));
67
80
  }
68
- export function Config({ steps, state, status, debug = DebugLevel.None, handlers, onFinished, onAborted, }) {
81
+ export function Config(props) {
82
+ const { steps, state, status, debug = DebugLevel.None, stateHandlers, lifecycleHandlers, onFinished, onAborted, } = props;
69
83
  const isActive = status === ComponentStatus.Active;
70
84
  const [step, setStep] = useState(!isActive ? (state?.completedStep ?? steps.length) : 0);
71
85
  const [values, setValues] = useState(() => {
@@ -89,8 +103,8 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
89
103
  stepConfig.options[stepConfig.defaultIndex].value;
90
104
  break;
91
105
  default: {
92
- const exhaustiveCheck = stepConfig;
93
- throw new Error(`Unsupported step type: ${exhaustiveCheck}`);
106
+ const _exhaustiveCheck = stepConfig;
107
+ throw new Error('Unsupported step type');
94
108
  }
95
109
  }
96
110
  });
@@ -132,7 +146,6 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
132
146
  const value = values[configKey] || '';
133
147
  setInputValue(value);
134
148
  }
135
- // eslint-disable-next-line react-hooks/exhaustive-deps
136
149
  }, [step, isActive, steps]);
137
150
  useInput((_, key) => {
138
151
  if (!isActive || step >= steps.length)
@@ -140,27 +153,25 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
140
153
  const currentStepConfig = steps[step];
141
154
  if (key.escape) {
142
155
  // Save current value before aborting
143
- if (currentStepConfig) {
144
- const configKey = currentStepConfig.path || currentStepConfig.key;
145
- let currentValue = '';
146
- switch (currentStepConfig.type) {
147
- case StepType.Text:
148
- currentValue = inputValue || values[configKey] || '';
149
- break;
150
- case StepType.Selection:
151
- currentValue = values[configKey] || '';
152
- break;
153
- default: {
154
- const exhaustiveCheck = currentStepConfig;
155
- throw new Error(`Unsupported step type: ${exhaustiveCheck}`);
156
- }
157
- }
158
- if (currentValue) {
159
- setValues({ ...values, [configKey]: currentValue });
156
+ const configKey = currentStepConfig.path || currentStepConfig.key;
157
+ let currentValue = '';
158
+ switch (currentStepConfig.type) {
159
+ case StepType.Text:
160
+ currentValue = inputValue || values[configKey] || '';
161
+ break;
162
+ case StepType.Selection:
163
+ currentValue = values[configKey] || '';
164
+ break;
165
+ default: {
166
+ const _exhaustiveCheck = currentStepConfig;
167
+ throw new Error('Unsupported step type');
160
168
  }
161
169
  }
170
+ if (currentValue) {
171
+ setValues({ ...values, [configKey]: currentValue });
172
+ }
162
173
  // Save state before aborting
163
- handlers?.updateState({
174
+ stateHandlers?.updateState({
164
175
  values,
165
176
  completedStep: step,
166
177
  selectedIndex,
@@ -169,7 +180,7 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
169
180
  onAborted('configuration');
170
181
  }
171
182
  // Complete with abort feedback
172
- handlers?.completeActive(createFeedback(FeedbackType.Aborted, 'Configuration cancelled.'));
183
+ lifecycleHandlers?.completeActive(createFeedback(FeedbackType.Aborted, 'Configuration cancelled.'));
173
184
  return;
174
185
  }
175
186
  // Handle selection step navigation
@@ -204,8 +215,8 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
204
215
  break;
205
216
  }
206
217
  default: {
207
- const exhaustiveCheck = currentStepConfig;
208
- throw new Error(`Unsupported step type: ${exhaustiveCheck}`);
218
+ const _exhaustiveCheck = currentStepConfig;
219
+ throw new Error('Unsupported step type');
209
220
  }
210
221
  }
211
222
  // Don't allow empty or invalid value
@@ -226,19 +237,19 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
226
237
  completedStep: steps.length,
227
238
  selectedIndex,
228
239
  };
229
- handlers?.updateState(stateUpdate);
240
+ stateHandlers?.updateState(stateUpdate);
230
241
  // Call onFinished callback and handle result
231
242
  try {
232
243
  if (onFinished) {
233
244
  onFinished(newValues);
234
245
  }
235
246
  // Success - complete with success feedback
236
- handlers?.completeActive(createFeedback(FeedbackType.Succeeded, 'Configuration saved successfully.'));
247
+ lifecycleHandlers?.completeActive(createFeedback(FeedbackType.Succeeded, 'Configuration saved successfully.'));
237
248
  }
238
249
  catch (error) {
239
250
  // Failure - complete with error feedback
240
251
  const errorMessage = error instanceof Error ? error.message : 'Configuration failed';
241
- handlers?.completeActive(createFeedback(FeedbackType.Failed, errorMessage));
252
+ lifecycleHandlers?.completeActive(createFeedback(FeedbackType.Failed, errorMessage));
242
253
  }
243
254
  setStep(steps.length);
244
255
  }
@@ -249,7 +260,7 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
249
260
  completedStep: step + 1,
250
261
  selectedIndex,
251
262
  };
252
- handlers?.updateState(stateUpdate);
263
+ stateHandlers?.updateState(stateUpdate);
253
264
  const nextStep = step + 1;
254
265
  setStep(nextStep);
255
266
  // Reset selectedIndex for next step
@@ -278,8 +289,8 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
278
289
  return (_jsx(SelectionStep, { options: stepConfig.options, selectedIndex: selectedIndex, isCurrentStep: true }));
279
290
  }
280
291
  default: {
281
- const exhaustiveCheck = stepConfig;
282
- throw new Error(`Unsupported step type: ${exhaustiveCheck}`);
292
+ const _exhaustiveCheck = stepConfig;
293
+ throw new Error('Unsupported step type');
283
294
  }
284
295
  }
285
296
  };
@@ -291,6 +302,7 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
291
302
  if (!shouldShow) {
292
303
  return null;
293
304
  }
294
- return (_jsxs(Box, { flexDirection: "column", marginTop: index === 0 ? 0 : 1, children: [_jsxs(Box, { children: [_jsx(Text, { children: stepConfig.description }), _jsx(Text, { children: ": " }), debug !== DebugLevel.None && stepConfig.path && (_jsxs(Text, { color: Colors.Type.Define, children: ['{', stepConfig.path, '}'] }))] }), _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));
305
+ const postfix = getPostfix(stepConfig.path, debug);
306
+ 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));
295
307
  }) }));
296
308
  }
@@ -2,10 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
3
  import { Box, Text } from 'ink';
4
4
  import { ComponentStatus } from '../types/components.js';
5
- import { Colors, Palette } from '../services/colors.js';
5
+ import { Colors, getTextColor, Palette } from '../services/colors.js';
6
6
  import { useInput } from '../services/keyboard.js';
7
7
  import { UserQuery } from './UserQuery.js';
8
- export function Confirm({ message, state, status, handlers, onConfirmed, onCancelled, }) {
8
+ export function Confirm({ message, state, status, stateHandlers, onConfirmed, onCancelled, }) {
9
9
  const isActive = status === ComponentStatus.Active;
10
10
  const [selectedIndex, setSelectedIndex] = useState(state?.selectedIndex ?? 0); // 0 = Yes, 1 = No
11
11
  useInput((input, key) => {
@@ -14,23 +14,23 @@ export function Confirm({ message, state, status, handlers, onConfirmed, onCance
14
14
  if (key.escape) {
15
15
  // Escape: highlight "No" and cancel
16
16
  setSelectedIndex(1);
17
- handlers?.updateState({ selectedIndex: 1 });
18
- onCancelled?.();
17
+ stateHandlers?.updateState({ selectedIndex: 1 });
18
+ onCancelled();
19
19
  }
20
20
  else if (key.tab) {
21
21
  // Toggle between Yes (0) and No (1)
22
22
  const newIndex = selectedIndex === 0 ? 1 : 0;
23
23
  setSelectedIndex(newIndex);
24
- handlers?.updateState({ selectedIndex: newIndex });
24
+ stateHandlers?.updateState({ selectedIndex: newIndex });
25
25
  }
26
26
  else if (key.return) {
27
27
  // Confirm selection
28
- handlers?.updateState({ selectedIndex, confirmed: true });
28
+ stateHandlers?.updateState({ selectedIndex, confirmed: true });
29
29
  if (selectedIndex === 0) {
30
- onConfirmed?.();
30
+ onConfirmed();
31
31
  }
32
32
  else {
33
- onCancelled?.();
33
+ onCancelled();
34
34
  }
35
35
  }
36
36
  }, { isActive });
@@ -42,7 +42,7 @@ export function Confirm({ message, state, status, handlers, onConfirmed, onCance
42
42
  // When done, show both the message and user's choice in timeline
43
43
  return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, marginLeft: 1, children: _jsx(Text, { color: undefined, children: message }) }), _jsxs(UserQuery, { children: ["> ", options[selectedIndex].label] })] }));
44
44
  }
45
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, marginLeft: 1, children: _jsx(Text, { color: isActive ? Colors.Text.Active : Colors.Text.Inactive, children: message }) }), _jsxs(Box, { marginLeft: 1, children: [_jsx(Text, { color: Colors.Action.Select, children: ">" }), _jsx(Text, { children: " " }), _jsx(Box, { children: options.map((option, index) => {
45
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, marginLeft: 1, children: _jsx(Text, { color: getTextColor(isActive), children: message }) }), _jsxs(Box, { marginLeft: 1, children: [_jsx(Text, { color: Colors.Action.Select, children: ">" }), _jsx(Text, { children: " " }), _jsx(Box, { children: options.map((option, index) => {
46
46
  const isSelected = index === selectedIndex;
47
47
  return (_jsx(Box, { marginRight: 2, children: _jsx(Text, { color: isSelected ? option.color : undefined, dimColor: !isSelected, children: option.label }) }, option.value));
48
48
  }) })] })] }));