prompt-language-shell 0.4.0 → 0.4.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.
package/dist/ui/Main.js CHANGED
@@ -1,12 +1,18 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { useInput } from 'ink';
4
- import { ComponentName, FeedbackType, TaskType, } from '../types/types.js';
4
+ import { FeedbackType } from '../types/types.js';
5
5
  import { createAnthropicService, } from '../services/anthropic.js';
6
- import { getConfigurationRequiredMessage, hasValidAnthropicKey, loadConfig, loadDebugSetting, saveAnthropicConfig, saveDebugSetting, } from '../services/config.js';
7
- import { FeedbackMessages, getCancellationMessage, getRefiningMessage, } from '../services/messages.js';
8
- import { createCommandDefinition, createConfirmDefinition, createConfigDefinition, createFeedback, createMessage, createRefinement, createPlanDefinition, createWelcomeDefinition, isStateless, markAsDone, } from '../services/components.js';
6
+ import { getConfigurationRequiredMessage, hasValidAnthropicKey, loadConfig, loadDebugSetting, saveDebugSetting, } from '../services/configuration.js';
7
+ import { getCancellationMessage } from '../services/messages.js';
8
+ import { createCommandDefinition, createConfigDefinition, createFeedback, createMessage, createWelcomeDefinition, isStateless, markAsDone, } from '../services/components.js';
9
9
  import { exitApp } from '../services/process.js';
10
+ import { createAnswerAbortedHandler, createAnswerCompleteHandler, createAnswerErrorHandler, } from '../handlers/answer.js';
11
+ import { createCommandAbortedHandler, createCommandCompleteHandler, createCommandErrorHandler, } from '../handlers/command.js';
12
+ import { createConfigAbortedHandler, createConfigFinishedHandler, } from '../handlers/config.js';
13
+ import { createExecutionCancelledHandler, createExecutionConfirmedHandler, } from '../handlers/execution.js';
14
+ import { createIntrospectAbortedHandler, createIntrospectCompleteHandler, createIntrospectErrorHandler, } from '../handlers/introspect.js';
15
+ import { createPlanAbortedHandler, createPlanAbortHandlerFactory, createPlanSelectionConfirmedHandler, } from '../handlers/plan.js';
10
16
  import { Column } from './Column.js';
11
17
  export const Main = ({ app, command }) => {
12
18
  // Initialize service from existing config if available
@@ -52,18 +58,7 @@ export const Main = ({ app, command }) => {
52
58
  return currentQueue;
53
59
  });
54
60
  }, [addToTimeline]);
55
- const handleCommandError = React.useCallback((error) => {
56
- setQueue((currentQueue) => {
57
- if (currentQueue.length === 0)
58
- return currentQueue;
59
- const [first] = currentQueue;
60
- if (first.name === ComponentName.Command) {
61
- addToTimeline(markAsDone(first), createFeedback(FeedbackType.Failed, FeedbackMessages.UnexpectedError, error));
62
- }
63
- exitApp(1);
64
- return [];
65
- });
66
- }, [addToTimeline]);
61
+ const handleCommandError = React.useCallback((error) => setQueue(createCommandErrorHandler(addToTimeline)(error)), [addToTimeline]);
67
62
  const handleAborted = React.useCallback((operationName) => {
68
63
  setQueue((currentQueue) => {
69
64
  if (currentQueue.length === 0)
@@ -76,117 +71,31 @@ export const Main = ({ app, command }) => {
76
71
  return [];
77
72
  });
78
73
  }, [addToTimeline]);
79
- const handleConfigAborted = React.useCallback(() => {
80
- handleAborted('Configuration');
81
- }, [handleAborted]);
82
- const handlePlanAborted = React.useCallback(() => {
83
- handleAborted('Task selection');
84
- }, [handleAborted]);
85
- const createPlanAbortHandler = React.useCallback((tasks) => {
86
- const allIntrospect = tasks.every((task) => task.type === TaskType.Introspect);
87
- if (allIntrospect) {
88
- return () => handleAborted('Introspection');
89
- }
90
- return handlePlanAborted;
91
- }, [handleAborted, handlePlanAborted]);
92
- const handleCommandAborted = React.useCallback(() => {
93
- handleAborted('Request');
94
- }, [handleAborted]);
74
+ const handleConfigAborted = React.useCallback(createConfigAbortedHandler(handleAborted), [handleAborted]);
75
+ const handlePlanAborted = React.useCallback(createPlanAbortedHandler(handleAborted), [handleAborted]);
76
+ const createPlanAbortHandler = React.useCallback(createPlanAbortHandlerFactory(handleAborted, handlePlanAborted), [handleAborted, handlePlanAborted]);
77
+ const handleCommandAborted = React.useCallback(createCommandAbortedHandler(handleAborted), [handleAborted]);
95
78
  const handleRefinementAborted = React.useCallback(() => {
96
79
  handleAborted('Plan refinement');
97
80
  }, [handleAborted]);
98
- const handleExecutionConfirmed = React.useCallback(() => {
99
- setQueue((currentQueue) => {
100
- if (currentQueue.length === 0)
101
- return currentQueue;
102
- const [first] = currentQueue;
103
- if (first.name === ComponentName.Confirm) {
104
- addToTimeline(markAsDone(first));
105
- }
106
- exitApp(0);
107
- return [];
108
- });
109
- }, [addToTimeline]);
110
- const handleExecutionCancelled = React.useCallback(() => {
111
- setQueue((currentQueue) => {
112
- if (currentQueue.length === 0)
113
- return currentQueue;
114
- const [first] = currentQueue;
115
- if (first.name === ComponentName.Confirm) {
116
- // Find the most recent Plan in timeline to check task types
117
- const currentTimeline = timelineRef.current;
118
- const lastPlanIndex = [...currentTimeline]
119
- .reverse()
120
- .findIndex((item) => item.name === ComponentName.Plan);
121
- const lastPlan = lastPlanIndex >= 0
122
- ? currentTimeline[currentTimeline.length - 1 - lastPlanIndex]
123
- : null;
124
- const allIntrospect = lastPlan &&
125
- lastPlan.name === ComponentName.Plan &&
126
- 'props' in lastPlan &&
127
- lastPlan.props &&
128
- 'tasks' in lastPlan.props &&
129
- Array.isArray(lastPlan.props.tasks) &&
130
- lastPlan.props.tasks.every((task) => task.type === TaskType.Introspect);
131
- const operation = allIntrospect ? 'introspection' : 'execution';
132
- addToTimeline(markAsDone(first), createFeedback(FeedbackType.Aborted, getCancellationMessage(operation)));
133
- }
134
- exitApp(0);
135
- return [];
136
- });
137
- }, [addToTimeline]);
138
- const handlePlanSelectionConfirmed = React.useCallback(async (selectedTasks) => {
139
- // Mark current plan as done and add refinement to queue
140
- let refinementDef = null;
141
- refinementDef = createRefinement(getRefiningMessage(), handleRefinementAborted);
142
- setQueue((currentQueue) => {
143
- if (currentQueue.length === 0)
144
- return currentQueue;
145
- const [first] = currentQueue;
146
- if (first.name === ComponentName.Plan) {
147
- addToTimeline(markAsDone(first));
148
- }
149
- // Add refinement to queue so it becomes the active component
150
- return [refinementDef];
151
- });
152
- // Process refined command in background
153
- try {
154
- const refinedCommand = selectedTasks
155
- .map((task) => {
156
- const action = task.action.toLowerCase().replace(/,/g, ' -');
157
- const type = task.type || 'execute';
158
- return `${action} (type: ${type})`;
159
- })
160
- .join(', ');
161
- const result = await service.processWithTool(refinedCommand, 'plan');
162
- // Mark refinement as done and move to timeline
163
- setQueue((currentQueue) => {
164
- if (currentQueue.length > 0 &&
165
- currentQueue[0].id === refinementDef.id) {
166
- addToTimeline(markAsDone(currentQueue[0]));
167
- }
168
- return [];
169
- });
170
- // Show final execution plan with confirmation
171
- const planDefinition = createPlanDefinition(result.message, result.tasks, createPlanAbortHandler(result.tasks), undefined);
172
- const confirmDefinition = createConfirmDefinition(handleExecutionConfirmed, handleExecutionCancelled);
173
- addToTimeline(planDefinition);
174
- setQueue([confirmDefinition]);
175
- }
176
- catch (error) {
177
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
178
- // Mark refinement as done and move to timeline before showing error
179
- setQueue((currentQueue) => {
180
- if (currentQueue.length > 0 &&
181
- currentQueue[0].id === refinementDef.id) {
182
- addToTimeline(markAsDone(currentQueue[0]));
183
- }
184
- return [];
185
- });
186
- addToTimeline(createFeedback(FeedbackType.Failed, FeedbackMessages.UnexpectedError, errorMessage));
187
- exitApp(1);
188
- }
189
- }, [
81
+ const handleIntrospectAborted = React.useCallback(createIntrospectAbortedHandler(handleAborted), [handleAborted]);
82
+ const handleIntrospectError = React.useCallback((error) => setQueue(createIntrospectErrorHandler(addToTimeline)(error)), [addToTimeline]);
83
+ const handleIntrospectComplete = React.useCallback((message, capabilities) => setQueue(createIntrospectCompleteHandler(addToTimeline)(message, capabilities)), [addToTimeline]);
84
+ const handleAnswerAborted = React.useCallback(createAnswerAbortedHandler(handleAborted), [handleAborted]);
85
+ const handleAnswerError = React.useCallback((error) => setQueue(createAnswerErrorHandler(addToTimeline)(error)), [addToTimeline]);
86
+ const handleAnswerComplete = React.useCallback((answer) => setQueue(createAnswerCompleteHandler(addToTimeline)(answer)), [addToTimeline]);
87
+ const handleExecutionConfirmed = React.useCallback(() => setQueue(createExecutionConfirmedHandler(timelineRef, addToTimeline, service, handleIntrospectError, handleIntrospectComplete, handleIntrospectAborted, handleAnswerError, handleAnswerComplete, handleAnswerAborted)()), [
88
+ addToTimeline,
89
+ service,
90
+ handleIntrospectError,
91
+ handleIntrospectComplete,
92
+ handleIntrospectAborted,
93
+ handleAnswerError,
94
+ handleAnswerComplete,
95
+ handleAnswerAborted,
96
+ ]);
97
+ const handleExecutionCancelled = React.useCallback(() => setQueue(createExecutionCancelledHandler(timelineRef, addToTimeline)()), [addToTimeline]);
98
+ const handlePlanSelectionConfirmed = React.useCallback(createPlanSelectionConfirmedHandler(addToTimeline, service, handleRefinementAborted, createPlanAbortHandler, handleExecutionConfirmed, handleExecutionCancelled, setQueue), [
190
99
  addToTimeline,
191
100
  service,
192
101
  handleRefinementAborted,
@@ -194,62 +103,20 @@ export const Main = ({ app, command }) => {
194
103
  handleExecutionConfirmed,
195
104
  handleExecutionCancelled,
196
105
  ]);
197
- const handleCommandComplete = React.useCallback((message, tasks) => {
198
- setQueue((currentQueue) => {
199
- if (currentQueue.length === 0)
200
- return currentQueue;
201
- const [first] = currentQueue;
202
- // Check if tasks contain a Define task that requires user interaction
203
- const hasDefineTask = tasks.some((task) => task.type === TaskType.Define);
204
- if (first.name === ComponentName.Command) {
205
- const planDefinition = createPlanDefinition(message, tasks, createPlanAbortHandler(tasks), hasDefineTask ? handlePlanSelectionConfirmed : undefined);
206
- if (hasDefineTask) {
207
- // Don't exit - keep the plan in the queue for interaction
208
- addToTimeline(markAsDone(first));
209
- return [planDefinition];
210
- }
211
- else {
212
- // No define task - show plan and confirmation
213
- const confirmDefinition = createConfirmDefinition(handleExecutionConfirmed, handleExecutionCancelled);
214
- addToTimeline(markAsDone(first), planDefinition);
215
- return [confirmDefinition];
216
- }
217
- }
218
- exitApp(0);
219
- return [];
220
- });
221
- }, [
106
+ const handleCommandComplete = React.useCallback((message, tasks) => setQueue(createCommandCompleteHandler(addToTimeline, createPlanAbortHandler, handlePlanSelectionConfirmed, handleExecutionConfirmed, handleExecutionCancelled)(message, tasks)), [
222
107
  addToTimeline,
223
108
  createPlanAbortHandler,
224
109
  handlePlanSelectionConfirmed,
225
110
  handleExecutionConfirmed,
226
111
  handleExecutionCancelled,
227
112
  ]);
228
- const handleConfigFinished = React.useCallback((config) => {
229
- const anthropicConfig = config;
230
- saveAnthropicConfig(anthropicConfig);
231
- const newService = createAnthropicService(anthropicConfig);
232
- setService(newService);
233
- // Complete config component and add command if present
234
- setQueue((currentQueue) => {
235
- if (currentQueue.length === 0)
236
- return currentQueue;
237
- const [first, ...rest] = currentQueue;
238
- if (first.name === ComponentName.Config) {
239
- addToTimeline(markAsDone(first), createFeedback(FeedbackType.Succeeded, FeedbackMessages.ConfigurationComplete));
240
- }
241
- // Add command to queue if we have one
242
- if (command) {
243
- return [
244
- ...rest,
245
- createCommandDefinition(command, newService, handleCommandError, handleCommandComplete, handleCommandAborted),
246
- ];
247
- }
248
- // No command - exit after showing completion message
249
- exitApp(0);
250
- return rest;
251
- });
252
- }, [addToTimeline, command, handleCommandError, handleCommandComplete]);
113
+ const handleConfigFinished = React.useCallback((config) => setQueue(createConfigFinishedHandler(addToTimeline, command, handleCommandError, handleCommandComplete, handleCommandAborted, setService)(config)), [
114
+ addToTimeline,
115
+ command,
116
+ handleCommandError,
117
+ handleCommandComplete,
118
+ handleCommandAborted,
119
+ ]);
253
120
  // Initialize queue on mount
254
121
  React.useEffect(() => {
255
122
  const hasConfig = !!service;
package/dist/ui/Plan.js CHANGED
@@ -1,23 +1,24 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from 'react';
3
3
  import { Box, useInput } from 'ink';
4
- import { TaskColors } from '../types/colors.js';
5
4
  import { TaskType } from '../types/types.js';
5
+ import { getTaskColors } from '../services/colors.js';
6
6
  import { Label } from './Label.js';
7
7
  import { List } from './List.js';
8
- function taskToListItem(task, highlightedChildIndex = null, isDefineTaskWithoutSelection = false) {
8
+ function taskToListItem(task, highlightedChildIndex = null, isDefineTaskWithoutSelection = false, isCurrent = false) {
9
+ const taskColors = getTaskColors(task.type, isCurrent);
9
10
  const item = {
10
11
  description: {
11
12
  text: task.action,
12
- color: TaskColors[task.type].description,
13
+ color: taskColors.description,
13
14
  },
14
- type: { text: task.type, color: TaskColors[task.type].type },
15
+ type: { text: task.type, color: taskColors.type },
15
16
  children: [],
16
17
  };
17
18
  // Mark define tasks with right arrow when no selection has been made
18
19
  if (isDefineTaskWithoutSelection) {
19
20
  item.marker = ' → ';
20
- item.markerColor = TaskColors[TaskType.Plan].type;
21
+ item.markerColor = getTaskColors(TaskType.Plan, isCurrent).type;
21
22
  }
22
23
  // Add children for Define tasks with options
23
24
  if (task.type === TaskType.Define && Array.isArray(task.params?.options)) {
@@ -29,17 +30,18 @@ function taskToListItem(task, highlightedChildIndex = null, isDefineTaskWithoutS
29
30
  childType =
30
31
  index === highlightedChildIndex ? TaskType.Execute : TaskType.Discard;
31
32
  }
32
- const colors = TaskColors[childType];
33
+ const colors = getTaskColors(childType, isCurrent);
34
+ const planColors = getTaskColors(TaskType.Plan, isCurrent);
33
35
  return {
34
36
  description: {
35
37
  text: String(option),
36
38
  color: colors.description,
37
- highlightedColor: TaskColors[TaskType.Plan].description,
39
+ highlightedColor: planColors.description,
38
40
  },
39
41
  type: {
40
42
  text: childType,
41
43
  color: colors.type,
42
- highlightedColor: TaskColors[TaskType.Plan].type,
44
+ highlightedColor: planColors.type,
43
45
  },
44
46
  };
45
47
  });
@@ -143,6 +145,7 @@ export function Plan({ message, tasks, state, debug = false, onSelectionConfirme
143
145
  isDone,
144
146
  state,
145
147
  ]);
148
+ const isCurrent = isDone === false;
146
149
  const listItems = tasks.map((task, idx) => {
147
150
  // Find which define group this task belongs to (if any)
148
151
  const defineGroupIndex = defineTaskIndices.indexOf(idx);
@@ -170,7 +173,7 @@ export function Plan({ message, tasks, state, debug = false, onSelectionConfirme
170
173
  defineGroupIndex === currentDefineGroupIndex &&
171
174
  highlightedIndex === null &&
172
175
  !isDone;
173
- return taskToListItem(task, childIndex, isDefineWithoutSelection);
176
+ return taskToListItem(task, childIndex, isDefineWithoutSelection, isCurrent);
174
177
  });
175
- return (_jsxs(Box, { flexDirection: "column", children: [message && (_jsx(Box, { marginBottom: 1, children: _jsx(Label, { description: message, descriptionColor: TaskColors[TaskType.Plan].description, type: TaskType.Plan, typeColor: TaskColors[TaskType.Plan].type, showType: debug }) })), _jsx(List, { items: listItems, highlightedIndex: currentDefineTaskIndex >= 0 ? highlightedIndex : null, highlightedParentIndex: currentDefineTaskIndex, showType: debug })] }));
178
+ return (_jsxs(Box, { flexDirection: "column", children: [message && (_jsx(Box, { marginBottom: 1, children: _jsx(Label, { description: message, taskType: TaskType.Plan, showType: debug, isCurrent: isCurrent }) })), _jsx(List, { items: listItems, highlightedIndex: currentDefineTaskIndex >= 0 ? highlightedIndex : null, highlightedParentIndex: currentDefineTaskIndex, showType: debug })] }));
176
179
  }
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ const COLORS = {
4
+ BuiltIn: '#5c9ccc', // blue - for built-in capabilities
5
+ UserDefined: '#5aaa8a', // green - for user-defined skills
6
+ };
7
+ function CapabilityItem({ name, description, isBuiltIn }) {
8
+ const color = isBuiltIn ? COLORS.BuiltIn : COLORS.UserDefined;
9
+ return (_jsxs(Box, { children: [_jsx(Text, { children: "- " }), _jsx(Text, { color: color, children: name }), _jsxs(Text, { children: [" - ", description] })] }));
10
+ }
11
+ export function Report({ message, capabilities }) {
12
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: message }), _jsx(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: capabilities.map((capability, index) => (_jsx(CapabilityItem, { name: capability.name, description: capability.description, isBuiltIn: capability.isBuiltIn }, index))) })] }));
13
+ }
@@ -1,6 +1,6 @@
1
1
  import { jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Text } from 'ink';
3
- import { Colors } from '../types/colors.js';
3
+ import { Colors } from '../services/colors.js';
4
4
  export const Separator = ({ color = Colors.Label.Discarded, spaces = 1, }) => {
5
5
  const spacing = ' '.repeat(spaces);
6
6
  return (_jsxs(Text, { color: color, children: [spacing, "\u203A", spacing] }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prompt-language-shell",
3
- "version": "0.4.0",
3
+ "version": "0.4.4",
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",
File without changes