prompt-language-shell 0.3.8 → 0.4.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/config/INTROSPECT.md +139 -0
- package/dist/config/PLAN.md +42 -21
- package/dist/services/components.js +0 -11
- package/dist/services/messages.js +35 -0
- package/dist/services/tool-registry.js +5 -0
- package/dist/tools/introspect.tool.js +32 -0
- package/dist/tools/plan.tool.js +1 -1
- package/dist/types/colors.js +90 -0
- package/dist/types/types.js +1 -0
- package/dist/ui/Column.js +3 -2
- package/dist/ui/Component.js +3 -2
- package/dist/ui/Config.js +3 -2
- package/dist/ui/Confirm.js +4 -3
- package/dist/ui/Feedback.js +3 -19
- package/dist/ui/Main.js +47 -10
- package/dist/ui/Plan.js +8 -45
- package/dist/ui/Separator.js +2 -1
- package/package.json +10 -10
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
## Overview
|
|
2
|
+
|
|
3
|
+
You are the introspection execution component of "pls" (please), a professional
|
|
4
|
+
command-line concierge. Your role is to **execute** the listing of available
|
|
5
|
+
capabilities when a task with type "introspect" has been planned and confirmed.
|
|
6
|
+
|
|
7
|
+
## Execution Flow
|
|
8
|
+
|
|
9
|
+
This tool is invoked AFTER:
|
|
10
|
+
1. PLAN detected an introspection request and created a task with type
|
|
11
|
+
"introspect"
|
|
12
|
+
2. User reviewed and confirmed the plan
|
|
13
|
+
3. The introspect task is now being executed
|
|
14
|
+
|
|
15
|
+
Your task is to present available capabilities in a clear, organized list based
|
|
16
|
+
on the confirmed task's parameters.
|
|
17
|
+
|
|
18
|
+
## Input
|
|
19
|
+
|
|
20
|
+
You will receive:
|
|
21
|
+
- A task action describing what to list (e.g., "List available capabilities")
|
|
22
|
+
- Optional params with a "filter" field if user requested filtered results
|
|
23
|
+
(e.g., params: { filter: "deployment" })
|
|
24
|
+
|
|
25
|
+
## Task
|
|
26
|
+
|
|
27
|
+
Present the concierge's capabilities as a list of tasks, each representing one
|
|
28
|
+
capability.
|
|
29
|
+
|
|
30
|
+
## Response Format
|
|
31
|
+
|
|
32
|
+
Every response MUST include an introductory message before the capability list.
|
|
33
|
+
|
|
34
|
+
**Critical rules:**
|
|
35
|
+
- The message is MANDATORY - every single response must include one
|
|
36
|
+
- NEVER repeat the same message - each response should use different wording
|
|
37
|
+
- Must be a SINGLE sentence, maximum 64 characters (including the colon)
|
|
38
|
+
- The message introduces the capabilities that follow
|
|
39
|
+
- ALWAYS end the message with a colon (:)
|
|
40
|
+
- Match the tone to the request (professional, helpful, clear)
|
|
41
|
+
- **NEVER repeat keywords** - If the message uses "skills", the task action
|
|
42
|
+
must use different words like "capabilities" or "operations". If the message
|
|
43
|
+
uses "capabilities", the action must use "skills" or other alternatives.
|
|
44
|
+
Avoid redundancy between the message and task descriptions.
|
|
45
|
+
|
|
46
|
+
**Correct examples:**
|
|
47
|
+
- "Here are my capabilities:" (then use "skills" or "operations" in actions)
|
|
48
|
+
- "I can help with these operations:" (then use "capabilities" or "skills")
|
|
49
|
+
- "Here's what I can do:" (then use "capabilities", "skills", or "operations")
|
|
50
|
+
- "These are my available skills:" (then use "capabilities" or "operations")
|
|
51
|
+
- "Here's an overview of my capabilities:" (then use "skills" or "purposes")
|
|
52
|
+
- "Here's what I can help you with:" (then use "skills" or "capabilities")
|
|
53
|
+
|
|
54
|
+
## Capabilities Structure
|
|
55
|
+
|
|
56
|
+
Present capabilities in two categories:
|
|
57
|
+
|
|
58
|
+
### 1. Built-in Capabilities
|
|
59
|
+
|
|
60
|
+
These are the core operations available to all users:
|
|
61
|
+
|
|
62
|
+
- **CONFIG**: Configuration changes, settings updates
|
|
63
|
+
- **PLAN**: Plan and structure tasks from natural language requests, breaking
|
|
64
|
+
them down into clear, actionable steps
|
|
65
|
+
- **INTROSPECT**: List and describe available capabilities and skills
|
|
66
|
+
- **ANSWER**: Answer questions, explain concepts, provide information
|
|
67
|
+
- **EXECUTE**: Run shell commands, execute programs, process operations
|
|
68
|
+
- **REPORT**: Generate summaries, create reports, display results
|
|
69
|
+
|
|
70
|
+
### 2. User-Defined Skills
|
|
71
|
+
|
|
72
|
+
If skills are provided in the "Available Skills" section below, include them
|
|
73
|
+
in the response. For each skill:
|
|
74
|
+
- Extract the skill name from the first heading (# Skill Name)
|
|
75
|
+
- Extract a brief description from the Description or Overview section
|
|
76
|
+
- Keep descriptions concise (1-2 lines maximum)
|
|
77
|
+
- If the user specified a filter (e.g., "skills for deployment"), only include
|
|
78
|
+
skills whose name or description matches the filter
|
|
79
|
+
|
|
80
|
+
## Task Definition Guidelines
|
|
81
|
+
|
|
82
|
+
Create tasks with type "introspect" for each capability. Each task should:
|
|
83
|
+
|
|
84
|
+
- **Action**: The capability name and a concise description
|
|
85
|
+
- Format: "CAPABILITY: Description"
|
|
86
|
+
- Examples:
|
|
87
|
+
- "PLAN: Break down requests into actionable steps"
|
|
88
|
+
- "EXECUTE: Run shell commands and process operations"
|
|
89
|
+
- "Deploy Application: Build and deploy to staging or production"
|
|
90
|
+
- **Type**: Always use "introspect"
|
|
91
|
+
- **Params**: Omit params field
|
|
92
|
+
|
|
93
|
+
**Keep action descriptions concise, at most 64 characters.**
|
|
94
|
+
|
|
95
|
+
## Filtering
|
|
96
|
+
|
|
97
|
+
When the user specifies a filter (e.g., "skills for deployment", "what can you
|
|
98
|
+
do with files"):
|
|
99
|
+
1. Parse the filter keyword(s) from the request
|
|
100
|
+
2. Match against skill names and descriptions (case-insensitive)
|
|
101
|
+
3. Include built-in capabilities if they match the filter
|
|
102
|
+
4. Only present capabilities that match the filter
|
|
103
|
+
|
|
104
|
+
Examples:
|
|
105
|
+
- "skills for deployment" → Only show skills with "deploy" in name/description
|
|
106
|
+
- "what can you do with files" → Show EXECUTE and any file-related skills
|
|
107
|
+
- "list all skills" → Show all built-in capabilities + all user skills
|
|
108
|
+
|
|
109
|
+
## Examples
|
|
110
|
+
|
|
111
|
+
### Example 1: List All Capabilities
|
|
112
|
+
|
|
113
|
+
When user asks "list your skills", create an introductory message like "here
|
|
114
|
+
are my capabilities:" followed by a task for each built-in capability: PLAN,
|
|
115
|
+
INTROSPECT, ANSWER, EXECUTE, REPORT, and CONFIG. Each task uses type
|
|
116
|
+
"introspect" with an action describing the capability.
|
|
117
|
+
|
|
118
|
+
### Example 2: Filtered Skills
|
|
119
|
+
|
|
120
|
+
When user asks "skills for deployment" and a "deploy app" skill exists, create
|
|
121
|
+
an introductory message like "these skills match 'deployment':" followed by
|
|
122
|
+
only the tasks that match the filter. In this case, show the deploy app skill
|
|
123
|
+
with its description.
|
|
124
|
+
|
|
125
|
+
### Example 3: With User Skills
|
|
126
|
+
|
|
127
|
+
When user asks "what can you do" and user-defined skills like "process data"
|
|
128
|
+
and "backup files" exist, create an introductory message like "i can help with
|
|
129
|
+
these operations:" followed by all built-in capabilities plus the user-defined
|
|
130
|
+
skills. Each capability and skill becomes a task with type "introspect".
|
|
131
|
+
|
|
132
|
+
## Final Validation
|
|
133
|
+
|
|
134
|
+
Before finalizing:
|
|
135
|
+
1. Ensure every task has type "introspect"
|
|
136
|
+
2. Verify action descriptions are concise (≤64 characters)
|
|
137
|
+
3. Confirm the introductory message ends with a colon
|
|
138
|
+
4. Check that filtering was applied correctly if specified
|
|
139
|
+
5. Ensure no duplicate capabilities are listed
|
package/dist/config/PLAN.md
CHANGED
|
@@ -32,22 +32,25 @@ This message should introduce the PLAN, not the execution itself.
|
|
|
32
32
|
**Critical rules:**
|
|
33
33
|
- The message is MANDATORY - every single response must include one
|
|
34
34
|
- NEVER repeat the same message - each response should use different wording
|
|
35
|
-
- Must be a SINGLE sentence, maximum 64 characters (including
|
|
35
|
+
- Must be a SINGLE sentence, maximum 64 characters (including punctuation)
|
|
36
36
|
- The message introduces the plan/steps that follow, NOT the action itself
|
|
37
|
-
- ALWAYS end the message with a
|
|
37
|
+
- ALWAYS end the message with a period (.)
|
|
38
38
|
- Match the tone to the request (professional, helpful, reassuring)
|
|
39
39
|
- Avoid formulaic patterns - vary your phrasing naturally
|
|
40
|
+
- **Special case for introspect-only plans**: When ALL tasks are type
|
|
41
|
+
"introspect", use a message that acknowledges the user is asking about
|
|
42
|
+
capabilities. Avoid technical terms like "introspection".
|
|
40
43
|
|
|
41
44
|
**Correct examples (introducing the plan):**
|
|
42
|
-
- "Here is my plan
|
|
43
|
-
- "Here's what I'll do
|
|
44
|
-
- "Let me break this down
|
|
45
|
-
- "I've planned the following steps
|
|
46
|
-
- "Here's how I'll approach this
|
|
47
|
-
- "Here are the steps I'll take
|
|
48
|
-
- "This is my plan
|
|
49
|
-
- "Let me outline the approach
|
|
50
|
-
- "Here's the plan
|
|
45
|
+
- "Here is my plan."
|
|
46
|
+
- "Here's what I'll do."
|
|
47
|
+
- "Let me break this down."
|
|
48
|
+
- "I've planned the following steps."
|
|
49
|
+
- "Here's how I'll approach this."
|
|
50
|
+
- "Here are the steps I'll take."
|
|
51
|
+
- "This is my plan."
|
|
52
|
+
- "Let me outline the approach."
|
|
53
|
+
- "Here's the plan."
|
|
51
54
|
|
|
52
55
|
**DO NOT:**
|
|
53
56
|
- Use the exact same phrase repeatedly
|
|
@@ -55,10 +58,10 @@ This message should introduce the PLAN, not the execution itself.
|
|
|
55
58
|
- Include unnecessary pleasantries or apologies
|
|
56
59
|
- Use the same sentence structure every time
|
|
57
60
|
- Phrase it as if you're executing (use "plan" language, not "doing" language)
|
|
58
|
-
- Forget the
|
|
61
|
+
- Forget the period at the end
|
|
59
62
|
|
|
60
63
|
Remember: You are presenting a PLAN, not performing the action. The message
|
|
61
|
-
should naturally lead into a list of planned steps. Always end with a
|
|
64
|
+
should naturally lead into a list of planned steps. Always end with a period.
|
|
62
65
|
|
|
63
66
|
## Skills Integration
|
|
64
67
|
|
|
@@ -230,16 +233,30 @@ Examples that should be aborted as offensive:
|
|
|
230
233
|
|
|
231
234
|
**For requests with clear intent:**
|
|
232
235
|
|
|
233
|
-
1. **
|
|
236
|
+
1. **Introspection requests** - Use "introspect" type when request asks about
|
|
237
|
+
capabilities or skills:
|
|
238
|
+
- Verbs: "list skills", "show skills", "what can you do", "list
|
|
239
|
+
capabilities", "show capabilities", "what skills", "describe skills",
|
|
240
|
+
"flex", "show off"
|
|
241
|
+
- **Filtering**: If the request specifies a category, domain, or context
|
|
242
|
+
(e.g., "for deployment", "related to files", "about testing"), add a
|
|
243
|
+
params object with a filter field containing the specified context
|
|
244
|
+
- **IMPORTANT**: Introspection has HIGHER PRIORITY than "answer" for these
|
|
245
|
+
queries. If asking about capabilities/skills, use "introspect", NOT
|
|
246
|
+
"answer"
|
|
247
|
+
|
|
248
|
+
2. **Information requests** - Use "answer" type when request asks for
|
|
234
249
|
information:
|
|
235
250
|
- Verbs: "explain", "answer", "describe", "tell me", "say", "what
|
|
236
251
|
is", "how does"
|
|
237
252
|
- Examples:
|
|
238
|
-
- "explain
|
|
239
|
-
- "tell me about
|
|
253
|
+
- "explain typescript" → type: "answer"
|
|
254
|
+
- "tell me about docker" → type: "answer"
|
|
240
255
|
- "what is the current directory" → type: "answer"
|
|
256
|
+
- **Exception**: Questions about capabilities/skills should use
|
|
257
|
+
"introspect" instead
|
|
241
258
|
|
|
242
|
-
|
|
259
|
+
3. **Skill-based requests** - Use skills when verb matches a defined skill:
|
|
243
260
|
- If "process" skill exists and user says "process" → Use the process skill
|
|
244
261
|
- If "deploy" skill exists and user says "deploy" → Use the deploy skill
|
|
245
262
|
- Extract steps from the matching skill and create tasks for each step
|
|
@@ -359,7 +376,10 @@ When creating task definitions, focus on:
|
|
|
359
376
|
- `execute` - Shell commands, running programs, scripts, processing
|
|
360
377
|
operations
|
|
361
378
|
- `answer` - Answering questions, explaining concepts, providing
|
|
362
|
-
information
|
|
379
|
+
information (EXCEPT for capability/skill queries - use introspect)
|
|
380
|
+
- `introspect` - Listing available capabilities and skills when user
|
|
381
|
+
asks what the concierge can do. Include params { filter: "keyword" }
|
|
382
|
+
if user specifies a filter like "skills for deployment"
|
|
363
383
|
- `report` - Generating summaries, creating reports, displaying
|
|
364
384
|
results
|
|
365
385
|
- `define` - Presenting skill-based options when request matches
|
|
@@ -367,7 +387,8 @@ When creating task definitions, focus on:
|
|
|
367
387
|
(selecting ONE variant, ONE environment, ONE target), NOT sequences of
|
|
368
388
|
steps. Each option represents a single selection that will later be
|
|
369
389
|
expanded into individual sequential steps. NEVER bundle multiple steps
|
|
370
|
-
into a single option like "Process X, run validation, deploy Y"
|
|
390
|
+
into a single option like "Process X, run validation, deploy Y". The
|
|
391
|
+
action text must ALWAYS end with a colon (:) to introduce the options.**
|
|
371
392
|
- `ignore` - Request is too vague and cannot be mapped to skills or
|
|
372
393
|
inferred from context
|
|
373
394
|
|
|
@@ -590,7 +611,7 @@ Split only when multiple distinct queries or operations are needed:
|
|
|
590
611
|
Examples showing proper use of skills and disambiguation:
|
|
591
612
|
|
|
592
613
|
- "process" with process skill requiring {TARGET} parameter (Alpha, Beta, Gamma,
|
|
593
|
-
Delta) → One task: type "define", action "Clarify which target to process",
|
|
614
|
+
Delta) → One task: type "define", action "Clarify which target to process:",
|
|
594
615
|
params { options: ["Process Alpha", "Process Beta", "Process Gamma", "Process
|
|
595
616
|
Delta"] }. NOTE: If variants have descriptions, format as "Process Alpha, the
|
|
596
617
|
legacy version" NOT "Process Alpha (the legacy version)"
|
|
@@ -599,7 +620,7 @@ Examples showing proper use of skills and disambiguation:
|
|
|
599
620
|
target generation script", "Run the Alpha processing pipeline"
|
|
600
621
|
- "process all" with same process skill → Twelve tasks (3 steps × 4 targets)
|
|
601
622
|
- "deploy" with deploy skill (staging, production, canary) → One task: type
|
|
602
|
-
"define", action "Clarify which environment to deploy to", params
|
|
623
|
+
"define", action "Clarify which environment to deploy to:", params
|
|
603
624
|
{ options: ["Deploy to staging environment", "Deploy to production
|
|
604
625
|
environment", "Deploy to canary environment"] }
|
|
605
626
|
- "deploy all" with deploy skill (staging, production) → Two tasks: one for
|
|
@@ -6,17 +6,6 @@ import { StepType } from '../ui/Config.js';
|
|
|
6
6
|
export function markAsDone(component) {
|
|
7
7
|
return { ...component, state: { ...component.state, done: true } };
|
|
8
8
|
}
|
|
9
|
-
export function getRefiningMessage() {
|
|
10
|
-
const messages = [
|
|
11
|
-
'Let me work out the specifics for you.',
|
|
12
|
-
"I'll figure out the concrete steps.",
|
|
13
|
-
'Let me break this down into tasks.',
|
|
14
|
-
"I'll plan out the details.",
|
|
15
|
-
'Let me arrange the steps.',
|
|
16
|
-
"I'll prepare everything you need.",
|
|
17
|
-
];
|
|
18
|
-
return messages[Math.floor(Math.random() * messages.length)];
|
|
19
|
-
}
|
|
20
9
|
export function createWelcomeDefinition(app) {
|
|
21
10
|
return {
|
|
22
11
|
id: randomUUID(),
|
|
@@ -13,3 +13,38 @@ export function getConfirmationMessage() {
|
|
|
13
13
|
];
|
|
14
14
|
return messages[Math.floor(Math.random() * messages.length)];
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Returns a refining message shown during plan refinement.
|
|
18
|
+
* Randomly selects from variations to sound natural.
|
|
19
|
+
*/
|
|
20
|
+
export function getRefiningMessage() {
|
|
21
|
+
const messages = [
|
|
22
|
+
'Let me work out the specifics for you.',
|
|
23
|
+
"I'll figure out the concrete steps.",
|
|
24
|
+
'Let me break this down into tasks.',
|
|
25
|
+
"I'll plan out the details.",
|
|
26
|
+
'Let me arrange the steps.',
|
|
27
|
+
"I'll prepare everything you need.",
|
|
28
|
+
];
|
|
29
|
+
return messages[Math.floor(Math.random() * messages.length)];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns a cancellation message for the given operation.
|
|
33
|
+
* Randomly selects from variations to sound natural.
|
|
34
|
+
*/
|
|
35
|
+
export function getCancellationMessage(operation) {
|
|
36
|
+
const templates = [
|
|
37
|
+
`I've cancelled the ${operation.toLowerCase()}.`,
|
|
38
|
+
`I've aborted the ${operation.toLowerCase()}.`,
|
|
39
|
+
`The ${operation.toLowerCase()} was cancelled.`,
|
|
40
|
+
`The ${operation.toLowerCase()} has been aborted.`,
|
|
41
|
+
];
|
|
42
|
+
return templates[Math.floor(Math.random() * templates.length)];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Feedback messages for various operations
|
|
46
|
+
*/
|
|
47
|
+
export const FeedbackMessages = {
|
|
48
|
+
ConfigurationComplete: 'Configuration complete.',
|
|
49
|
+
UnexpectedError: 'Unexpected error occurred:',
|
|
50
|
+
};
|
|
@@ -33,8 +33,13 @@ class ToolRegistry {
|
|
|
33
33
|
// Create singleton instance
|
|
34
34
|
export const toolRegistry = new ToolRegistry();
|
|
35
35
|
// Register built-in tools
|
|
36
|
+
import { introspectTool } from '../tools/introspect.tool.js';
|
|
36
37
|
import { planTool } from '../tools/plan.tool.js';
|
|
37
38
|
toolRegistry.register('plan', {
|
|
38
39
|
schema: planTool,
|
|
39
40
|
instructionsPath: 'config/PLAN.md',
|
|
40
41
|
});
|
|
42
|
+
toolRegistry.register('introspect', {
|
|
43
|
+
schema: introspectTool,
|
|
44
|
+
instructionsPath: 'config/INTROSPECT.md',
|
|
45
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const introspectTool = {
|
|
2
|
+
name: 'introspect',
|
|
3
|
+
description: 'Execute a task with type "introspect" to list available capabilities and skills. Called after PLAN has identified an introspection request and user has confirmed. Takes the task action and optional filter parameter to present built-in capabilities and user-defined skills.',
|
|
4
|
+
input_schema: {
|
|
5
|
+
type: 'object',
|
|
6
|
+
properties: {
|
|
7
|
+
message: {
|
|
8
|
+
type: 'string',
|
|
9
|
+
description: 'Introductory reply to display before the capabilities list. Must be a single sentence, maximum 64 characters (including the colon at the end). Vary this naturally - try to use a different phrase each time. Always end with a colon.',
|
|
10
|
+
},
|
|
11
|
+
tasks: {
|
|
12
|
+
type: 'array',
|
|
13
|
+
description: 'Array of capabilities, each with type "introspect". Include built-in capabilities (PLAN, INTROSPECT, ANSWER, EXECUTE, REPORT, CONFIG) and user-defined skills from the Available Skills section.',
|
|
14
|
+
items: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
action: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'Capability name and description. Format: "NAME: Brief description". Maximum 64 characters. Examples: "PLAN: Break down requests into steps", "Deploy App: Build and deploy application".',
|
|
20
|
+
},
|
|
21
|
+
type: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'Always "introspect" for capability listings.',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
required: ['action', 'type'],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
required: ['message', 'tasks'],
|
|
31
|
+
},
|
|
32
|
+
};
|
package/dist/tools/plan.tool.js
CHANGED
|
@@ -20,7 +20,7 @@ export const planTool = {
|
|
|
20
20
|
},
|
|
21
21
|
type: {
|
|
22
22
|
type: 'string',
|
|
23
|
-
description: 'Type of task: "config" (settings), "plan" (planning), "execute" (shell/programs/finding files), "answer" (questions), "report" (summaries), "define" (skill-based disambiguation), "ignore" (too vague)',
|
|
23
|
+
description: 'Type of task: "config" (settings), "plan" (planning), "execute" (shell/programs/finding files), "answer" (questions, NOT for capability queries), "introspect" (list capabilities/skills), "report" (summaries), "define" (skill-based disambiguation), "ignore" (too vague)',
|
|
24
24
|
},
|
|
25
25
|
params: {
|
|
26
26
|
type: 'object',
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { FeedbackType, TaskType } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Semantic color palette - colors organized by their purpose/meaning.
|
|
4
|
+
* Prefer adding semantic names here rather than to DescriptiveColors.
|
|
5
|
+
*/
|
|
6
|
+
export const Colors = {
|
|
7
|
+
Action: {
|
|
8
|
+
Execute: '#5aaa8a', // green
|
|
9
|
+
Discard: '#a85c3f', // dark orange
|
|
10
|
+
Select: '#5c8cbc', // steel blue
|
|
11
|
+
},
|
|
12
|
+
Status: {
|
|
13
|
+
Success: '#22aa22', // green
|
|
14
|
+
Error: '#cc5c5c', // red
|
|
15
|
+
Warning: '#cc9c5c', // orange
|
|
16
|
+
Info: '#5c9ccc', // cyan
|
|
17
|
+
},
|
|
18
|
+
Label: {
|
|
19
|
+
Default: '#ffffff', // white
|
|
20
|
+
Inactive: '#888888', // gray
|
|
21
|
+
Discarded: '#666666', // dark gray
|
|
22
|
+
Skipped: '#cccc5c', // yellow
|
|
23
|
+
},
|
|
24
|
+
Type: {
|
|
25
|
+
Config: '#5c9ccc', // cyan
|
|
26
|
+
Plan: '#5ccccc', // magenta
|
|
27
|
+
Execute: '#5aaa8a', // green
|
|
28
|
+
Answer: '#9c5ccc', // purple
|
|
29
|
+
Introspect: '#9c5ccc', // purple
|
|
30
|
+
Report: '#cc9c5c', // orange
|
|
31
|
+
Define: '#cc9c5c', // amber
|
|
32
|
+
Ignore: '#cc7a5c', // dark orange
|
|
33
|
+
Select: '#5c8cbc', // steel blue
|
|
34
|
+
Discard: '#a85c3f', // dark orange
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Task-specific color mappings
|
|
39
|
+
*/
|
|
40
|
+
export const TaskColors = {
|
|
41
|
+
[TaskType.Config]: {
|
|
42
|
+
description: Colors.Label.Default,
|
|
43
|
+
type: Colors.Type.Config,
|
|
44
|
+
},
|
|
45
|
+
[TaskType.Plan]: {
|
|
46
|
+
description: Colors.Label.Default,
|
|
47
|
+
type: Colors.Type.Plan,
|
|
48
|
+
},
|
|
49
|
+
[TaskType.Execute]: {
|
|
50
|
+
description: Colors.Label.Default,
|
|
51
|
+
type: Colors.Type.Execute,
|
|
52
|
+
},
|
|
53
|
+
[TaskType.Answer]: {
|
|
54
|
+
description: Colors.Label.Default,
|
|
55
|
+
type: Colors.Type.Answer,
|
|
56
|
+
},
|
|
57
|
+
[TaskType.Introspect]: {
|
|
58
|
+
description: Colors.Label.Default,
|
|
59
|
+
type: Colors.Type.Introspect,
|
|
60
|
+
},
|
|
61
|
+
[TaskType.Report]: {
|
|
62
|
+
description: Colors.Label.Default,
|
|
63
|
+
type: Colors.Type.Report,
|
|
64
|
+
},
|
|
65
|
+
[TaskType.Define]: {
|
|
66
|
+
description: Colors.Label.Default,
|
|
67
|
+
type: Colors.Type.Define,
|
|
68
|
+
},
|
|
69
|
+
[TaskType.Ignore]: {
|
|
70
|
+
description: Colors.Label.Skipped,
|
|
71
|
+
type: Colors.Type.Ignore,
|
|
72
|
+
},
|
|
73
|
+
[TaskType.Select]: {
|
|
74
|
+
description: Colors.Label.Inactive,
|
|
75
|
+
type: Colors.Type.Select,
|
|
76
|
+
},
|
|
77
|
+
[TaskType.Discard]: {
|
|
78
|
+
description: Colors.Label.Discarded,
|
|
79
|
+
type: Colors.Type.Discard,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Feedback-specific color mappings
|
|
84
|
+
*/
|
|
85
|
+
export const FeedbackColors = {
|
|
86
|
+
[FeedbackType.Info]: Colors.Status.Info,
|
|
87
|
+
[FeedbackType.Succeeded]: Colors.Status.Success,
|
|
88
|
+
[FeedbackType.Aborted]: Colors.Status.Warning,
|
|
89
|
+
[FeedbackType.Failed]: Colors.Status.Error,
|
|
90
|
+
};
|
package/dist/types/types.js
CHANGED
|
@@ -15,6 +15,7 @@ export var TaskType;
|
|
|
15
15
|
TaskType["Plan"] = "plan";
|
|
16
16
|
TaskType["Execute"] = "execute";
|
|
17
17
|
TaskType["Answer"] = "answer";
|
|
18
|
+
TaskType["Introspect"] = "introspect";
|
|
18
19
|
TaskType["Report"] = "report";
|
|
19
20
|
TaskType["Define"] = "define";
|
|
20
21
|
TaskType["Ignore"] = "ignore";
|
package/dist/ui/Column.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
2
3
|
import { Box } from 'ink';
|
|
3
4
|
import { Component } from './Component.js';
|
|
4
|
-
export const Column = ({ items, debug }) => {
|
|
5
|
+
export const Column = React.memo(({ items, debug }) => {
|
|
5
6
|
return (_jsx(Box, { marginTop: 1, marginBottom: 1, marginLeft: 1, flexDirection: "column", gap: 1, children: items.map((item) => (_jsx(Box, { children: _jsx(Component, { def: item, debug: debug }) }, item.id))) }));
|
|
6
|
-
};
|
|
7
|
+
});
|
package/dist/ui/Component.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
2
3
|
import { ComponentName } from '../types/types.js';
|
|
3
4
|
import { Command } from './Command.js';
|
|
4
5
|
import { Confirm } from './Confirm.js';
|
|
@@ -8,7 +9,7 @@ import { Message } from './Message.js';
|
|
|
8
9
|
import { Plan } from './Plan.js';
|
|
9
10
|
import { Refinement } from './Refinement.js';
|
|
10
11
|
import { Welcome } from './Welcome.js';
|
|
11
|
-
export function Component({ def, debug }) {
|
|
12
|
+
export const Component = React.memo(function Component({ def, debug, }) {
|
|
12
13
|
switch (def.name) {
|
|
13
14
|
case ComponentName.Welcome:
|
|
14
15
|
return _jsx(Welcome, { ...def.props });
|
|
@@ -39,4 +40,4 @@ export function Component({ def, debug }) {
|
|
|
39
40
|
return _jsx(Confirm, { ...props, state: state });
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
|
-
}
|
|
43
|
+
});
|
package/dist/ui/Config.js
CHANGED
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Box, Text, useFocus, useInput } from 'ink';
|
|
4
4
|
import TextInput from 'ink-text-input';
|
|
5
|
+
import { Colors } from '../types/colors.js';
|
|
5
6
|
export var StepType;
|
|
6
7
|
(function (StepType) {
|
|
7
8
|
StepType["Text"] = "text";
|
|
@@ -43,7 +44,7 @@ function TextStep({ value, placeholder, validate, onChange, onSubmit, }) {
|
|
|
43
44
|
}, { isActive: validationFailed });
|
|
44
45
|
// When validation fails, show colored text
|
|
45
46
|
if (validationFailed) {
|
|
46
|
-
return (_jsxs(Text, { color:
|
|
47
|
+
return (_jsxs(Text, { color: Colors.Status.Error, children: [inputValue || placeholder, isFocused && _jsx(Text, { inverse: true, children: " " })] }));
|
|
47
48
|
}
|
|
48
49
|
return (_jsx(TextInput, { value: inputValue, onChange: handleChange, onSubmit: handleSubmit, placeholder: placeholder }));
|
|
49
50
|
}
|
|
@@ -216,6 +217,6 @@ export function Config({ steps, state, onFinished, onAborted }) {
|
|
|
216
217
|
if (!shouldShow) {
|
|
217
218
|
return null;
|
|
218
219
|
}
|
|
219
|
-
return (_jsxs(Box, { flexDirection: "column", marginTop: index === 0 ? 0 : 1, children: [_jsx(Box, { children: _jsxs(Text, { children: [stepConfig.description, ":"] }) }), _jsxs(Box, { children: [_jsx(Text, { children: " " }), _jsx(Text, { color:
|
|
220
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: index === 0 ? 0 : 1, children: [_jsx(Box, { children: _jsxs(Text, { children: [stepConfig.description, ":"] }) }), _jsxs(Box, { children: [_jsx(Text, { children: " " }), _jsx(Text, { color: Colors.Action.Select, dimColor: !isCurrentStep, children: ">" }), _jsx(Text, { children: " " }), renderStepInput(stepConfig, isCurrentStep)] })] }, stepConfig.key));
|
|
220
221
|
}) }));
|
|
221
222
|
}
|
package/dist/ui/Confirm.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
import { Colors } from '../types/colors.js';
|
|
4
5
|
export function Confirm({ message, state, onConfirmed, onCancelled, }) {
|
|
5
6
|
const done = state?.done ?? false;
|
|
6
7
|
const [selectedIndex, setSelectedIndex] = React.useState(0); // 0 = Yes, 1 = No
|
|
@@ -27,14 +28,14 @@ export function Confirm({ message, state, onConfirmed, onCancelled, }) {
|
|
|
27
28
|
}
|
|
28
29
|
}, { isActive: !done });
|
|
29
30
|
const options = [
|
|
30
|
-
{ label: 'Yes', value: 'yes', color:
|
|
31
|
-
{ label: 'No', value: 'no', color:
|
|
31
|
+
{ label: 'Yes', value: 'yes', color: Colors.Action.Execute },
|
|
32
|
+
{ label: 'No', value: 'no', color: Colors.Action.Discard },
|
|
32
33
|
];
|
|
33
34
|
if (done) {
|
|
34
35
|
// When done, show both the message and user's choice in timeline
|
|
35
36
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: message }) }), _jsx(Box, { children: _jsxs(Text, { color: "gray", children: ["> ", options[selectedIndex].label] }) })] }));
|
|
36
37
|
}
|
|
37
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: message }) }), _jsxs(Box, { children: [_jsx(Text, { color:
|
|
38
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: message }) }), _jsxs(Box, { children: [_jsx(Text, { color: Colors.Action.Select, children: ">" }), _jsx(Text, { children: " " }), _jsx(Box, { children: options.map((option, index) => {
|
|
38
39
|
const isSelected = index === selectedIndex;
|
|
39
40
|
return (_jsx(Box, { marginRight: 2, children: _jsx(Text, { color: isSelected ? option.color : undefined, dimColor: !isSelected, bold: isSelected, children: option.label }) }, option.value));
|
|
40
41
|
}) })] })] }));
|
package/dist/ui/Feedback.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
|
+
import { FeedbackColors } from '../types/colors.js';
|
|
3
4
|
import { FeedbackType } from '../types/types.js';
|
|
4
5
|
function getSymbol(type) {
|
|
5
6
|
return {
|
|
@@ -9,25 +10,8 @@ function getSymbol(type) {
|
|
|
9
10
|
[FeedbackType.Failed]: '✗',
|
|
10
11
|
}[type];
|
|
11
12
|
}
|
|
12
|
-
function getSymbolColor(type) {
|
|
13
|
-
return {
|
|
14
|
-
[FeedbackType.Info]: '#5c9ccc', // cyan
|
|
15
|
-
[FeedbackType.Succeeded]: '#00aa00', // green
|
|
16
|
-
[FeedbackType.Aborted]: '#cc9c5c', // orange
|
|
17
|
-
[FeedbackType.Failed]: '#cc5c5c', // red
|
|
18
|
-
}[type];
|
|
19
|
-
}
|
|
20
|
-
function getMessageColor(type) {
|
|
21
|
-
return {
|
|
22
|
-
[FeedbackType.Info]: '#aaaaaa', // light grey
|
|
23
|
-
[FeedbackType.Succeeded]: '#5ccc5c', // green
|
|
24
|
-
[FeedbackType.Aborted]: '#cc9c5c', // orange
|
|
25
|
-
[FeedbackType.Failed]: '#cc5c5c', // red
|
|
26
|
-
}[type];
|
|
27
|
-
}
|
|
28
13
|
export function Feedback({ type, message }) {
|
|
29
|
-
const
|
|
30
|
-
const messageColor = getMessageColor(type);
|
|
14
|
+
const color = FeedbackColors[type];
|
|
31
15
|
const symbol = getSymbol(type);
|
|
32
|
-
return (
|
|
16
|
+
return (_jsx(Box, { children: _jsxs(Text, { color: color, children: [symbol, " ", message] }) }));
|
|
33
17
|
}
|
package/dist/ui/Main.js
CHANGED
|
@@ -4,7 +4,8 @@ import { useInput } from 'ink';
|
|
|
4
4
|
import { ComponentName, FeedbackType, TaskType, } from '../types/types.js';
|
|
5
5
|
import { createAnthropicService, } from '../services/anthropic.js';
|
|
6
6
|
import { getConfigurationRequiredMessage, hasValidAnthropicKey, loadConfig, loadDebugSetting, saveAnthropicConfig, saveDebugSetting, } from '../services/config.js';
|
|
7
|
-
import {
|
|
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';
|
|
8
9
|
import { exitApp } from '../services/process.js';
|
|
9
10
|
import { Column } from './Column.js';
|
|
10
11
|
export const Main = ({ app, command }) => {
|
|
@@ -19,6 +20,11 @@ export const Main = ({ app, command }) => {
|
|
|
19
20
|
const [timeline, setTimeline] = React.useState([]);
|
|
20
21
|
const [queue, setQueue] = React.useState([]);
|
|
21
22
|
const [isDebug, setIsDebug] = React.useState(() => loadDebugSetting());
|
|
23
|
+
// Use ref to track latest timeline for callbacks
|
|
24
|
+
const timelineRef = React.useRef(timeline);
|
|
25
|
+
React.useEffect(() => {
|
|
26
|
+
timelineRef.current = timeline;
|
|
27
|
+
}, [timeline]);
|
|
22
28
|
// Top-level Shift+Tab handler for debug mode toggle
|
|
23
29
|
// Child components must ignore Shift+Tab to prevent conflicts
|
|
24
30
|
useInput((input, key) => {
|
|
@@ -52,7 +58,7 @@ export const Main = ({ app, command }) => {
|
|
|
52
58
|
return currentQueue;
|
|
53
59
|
const [first] = currentQueue;
|
|
54
60
|
if (first.name === ComponentName.Command) {
|
|
55
|
-
addToTimeline(markAsDone(first), createFeedback(FeedbackType.Failed,
|
|
61
|
+
addToTimeline(markAsDone(first), createFeedback(FeedbackType.Failed, FeedbackMessages.UnexpectedError, error));
|
|
56
62
|
}
|
|
57
63
|
exitApp(1);
|
|
58
64
|
return [];
|
|
@@ -64,7 +70,7 @@ export const Main = ({ app, command }) => {
|
|
|
64
70
|
return currentQueue;
|
|
65
71
|
const [first] = currentQueue;
|
|
66
72
|
if (!isStateless(first)) {
|
|
67
|
-
addToTimeline(markAsDone(first), createFeedback(FeedbackType.Aborted,
|
|
73
|
+
addToTimeline(markAsDone(first), createFeedback(FeedbackType.Aborted, getCancellationMessage(operationName)));
|
|
68
74
|
}
|
|
69
75
|
exitApp(0);
|
|
70
76
|
return [];
|
|
@@ -76,6 +82,13 @@ export const Main = ({ app, command }) => {
|
|
|
76
82
|
const handlePlanAborted = React.useCallback(() => {
|
|
77
83
|
handleAborted('Task selection');
|
|
78
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]);
|
|
79
92
|
const handleCommandAborted = React.useCallback(() => {
|
|
80
93
|
handleAborted('Request');
|
|
81
94
|
}, [handleAborted]);
|
|
@@ -100,7 +113,23 @@ export const Main = ({ app, command }) => {
|
|
|
100
113
|
return currentQueue;
|
|
101
114
|
const [first] = currentQueue;
|
|
102
115
|
if (first.name === ComponentName.Confirm) {
|
|
103
|
-
|
|
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)));
|
|
104
133
|
}
|
|
105
134
|
exitApp(0);
|
|
106
135
|
return [];
|
|
@@ -139,7 +168,7 @@ export const Main = ({ app, command }) => {
|
|
|
139
168
|
return [];
|
|
140
169
|
});
|
|
141
170
|
// Show final execution plan with confirmation
|
|
142
|
-
const planDefinition = createPlanDefinition(result.message, result.tasks,
|
|
171
|
+
const planDefinition = createPlanDefinition(result.message, result.tasks, createPlanAbortHandler(result.tasks), undefined);
|
|
143
172
|
const confirmDefinition = createConfirmDefinition(handleExecutionConfirmed, handleExecutionCancelled);
|
|
144
173
|
addToTimeline(planDefinition);
|
|
145
174
|
setQueue([confirmDefinition]);
|
|
@@ -154,10 +183,17 @@ export const Main = ({ app, command }) => {
|
|
|
154
183
|
}
|
|
155
184
|
return [];
|
|
156
185
|
});
|
|
157
|
-
addToTimeline(createFeedback(FeedbackType.Failed,
|
|
186
|
+
addToTimeline(createFeedback(FeedbackType.Failed, FeedbackMessages.UnexpectedError, errorMessage));
|
|
158
187
|
exitApp(1);
|
|
159
188
|
}
|
|
160
|
-
}, [
|
|
189
|
+
}, [
|
|
190
|
+
addToTimeline,
|
|
191
|
+
service,
|
|
192
|
+
handleRefinementAborted,
|
|
193
|
+
createPlanAbortHandler,
|
|
194
|
+
handleExecutionConfirmed,
|
|
195
|
+
handleExecutionCancelled,
|
|
196
|
+
]);
|
|
161
197
|
const handleCommandComplete = React.useCallback((message, tasks) => {
|
|
162
198
|
setQueue((currentQueue) => {
|
|
163
199
|
if (currentQueue.length === 0)
|
|
@@ -166,7 +202,7 @@ export const Main = ({ app, command }) => {
|
|
|
166
202
|
// Check if tasks contain a Define task that requires user interaction
|
|
167
203
|
const hasDefineTask = tasks.some((task) => task.type === TaskType.Define);
|
|
168
204
|
if (first.name === ComponentName.Command) {
|
|
169
|
-
const planDefinition = createPlanDefinition(message, tasks,
|
|
205
|
+
const planDefinition = createPlanDefinition(message, tasks, createPlanAbortHandler(tasks), hasDefineTask ? handlePlanSelectionConfirmed : undefined);
|
|
170
206
|
if (hasDefineTask) {
|
|
171
207
|
// Don't exit - keep the plan in the queue for interaction
|
|
172
208
|
addToTimeline(markAsDone(first));
|
|
@@ -184,6 +220,7 @@ export const Main = ({ app, command }) => {
|
|
|
184
220
|
});
|
|
185
221
|
}, [
|
|
186
222
|
addToTimeline,
|
|
223
|
+
createPlanAbortHandler,
|
|
187
224
|
handlePlanSelectionConfirmed,
|
|
188
225
|
handleExecutionConfirmed,
|
|
189
226
|
handleExecutionCancelled,
|
|
@@ -199,7 +236,7 @@ export const Main = ({ app, command }) => {
|
|
|
199
236
|
return currentQueue;
|
|
200
237
|
const [first, ...rest] = currentQueue;
|
|
201
238
|
if (first.name === ComponentName.Config) {
|
|
202
|
-
addToTimeline(markAsDone(first), createFeedback(FeedbackType.Succeeded,
|
|
239
|
+
addToTimeline(markAsDone(first), createFeedback(FeedbackType.Succeeded, FeedbackMessages.ConfigurationComplete));
|
|
203
240
|
}
|
|
204
241
|
// Add command to queue if we have one
|
|
205
242
|
if (command) {
|
|
@@ -253,6 +290,6 @@ export const Main = ({ app, command }) => {
|
|
|
253
290
|
}
|
|
254
291
|
}, [queue, timeline]);
|
|
255
292
|
const current = queue.length > 0 ? queue[0] : null;
|
|
256
|
-
const items = [...timeline, ...(current ? [current] : [])];
|
|
293
|
+
const items = React.useMemo(() => [...timeline, ...(current ? [current] : [])], [timeline, current]);
|
|
257
294
|
return _jsx(Column, { items: items, debug: isDebug });
|
|
258
295
|
};
|
package/dist/ui/Plan.js
CHANGED
|
@@ -1,60 +1,23 @@
|
|
|
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';
|
|
4
5
|
import { TaskType } from '../types/types.js';
|
|
5
6
|
import { Label } from './Label.js';
|
|
6
7
|
import { List } from './List.js';
|
|
7
|
-
const ColorPalette = {
|
|
8
|
-
[TaskType.Config]: {
|
|
9
|
-
description: '#ffffff', // white
|
|
10
|
-
type: '#5c9ccc', // cyan
|
|
11
|
-
},
|
|
12
|
-
[TaskType.Plan]: {
|
|
13
|
-
description: '#ffffff', // white
|
|
14
|
-
type: '#5ccccc', // magenta
|
|
15
|
-
},
|
|
16
|
-
[TaskType.Execute]: {
|
|
17
|
-
description: '#ffffff', // white
|
|
18
|
-
type: '#4a9a7a', // green
|
|
19
|
-
},
|
|
20
|
-
[TaskType.Answer]: {
|
|
21
|
-
description: '#ffffff', // white
|
|
22
|
-
type: '#9c5ccc', // purple
|
|
23
|
-
},
|
|
24
|
-
[TaskType.Report]: {
|
|
25
|
-
description: '#ffffff', // white
|
|
26
|
-
type: '#cc9c5c', // orange
|
|
27
|
-
},
|
|
28
|
-
[TaskType.Define]: {
|
|
29
|
-
description: '#ffffff', // white
|
|
30
|
-
type: '#cc9c5c', // amber
|
|
31
|
-
},
|
|
32
|
-
[TaskType.Ignore]: {
|
|
33
|
-
description: '#cccc5c', // yellow
|
|
34
|
-
type: '#cc7a5c', // orange
|
|
35
|
-
},
|
|
36
|
-
[TaskType.Select]: {
|
|
37
|
-
description: '#888888', // grey
|
|
38
|
-
type: '#5c8cbc', // steel blue
|
|
39
|
-
},
|
|
40
|
-
[TaskType.Discard]: {
|
|
41
|
-
description: '#666666', // dark grey
|
|
42
|
-
type: '#a85c3f', // dark orange
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
8
|
function taskToListItem(task, highlightedChildIndex = null, isDefineTaskWithoutSelection = false) {
|
|
46
9
|
const item = {
|
|
47
10
|
description: {
|
|
48
11
|
text: task.action,
|
|
49
|
-
color:
|
|
12
|
+
color: TaskColors[task.type].description,
|
|
50
13
|
},
|
|
51
|
-
type: { text: task.type, color:
|
|
14
|
+
type: { text: task.type, color: TaskColors[task.type].type },
|
|
52
15
|
children: [],
|
|
53
16
|
};
|
|
54
17
|
// Mark define tasks with right arrow when no selection has been made
|
|
55
18
|
if (isDefineTaskWithoutSelection) {
|
|
56
19
|
item.marker = ' → ';
|
|
57
|
-
item.markerColor =
|
|
20
|
+
item.markerColor = TaskColors[TaskType.Plan].type;
|
|
58
21
|
}
|
|
59
22
|
// Add children for Define tasks with options
|
|
60
23
|
if (task.type === TaskType.Define && Array.isArray(task.params?.options)) {
|
|
@@ -66,17 +29,17 @@ function taskToListItem(task, highlightedChildIndex = null, isDefineTaskWithoutS
|
|
|
66
29
|
childType =
|
|
67
30
|
index === highlightedChildIndex ? TaskType.Execute : TaskType.Discard;
|
|
68
31
|
}
|
|
69
|
-
const colors =
|
|
32
|
+
const colors = TaskColors[childType];
|
|
70
33
|
return {
|
|
71
34
|
description: {
|
|
72
35
|
text: String(option),
|
|
73
36
|
color: colors.description,
|
|
74
|
-
highlightedColor:
|
|
37
|
+
highlightedColor: TaskColors[TaskType.Plan].description,
|
|
75
38
|
},
|
|
76
39
|
type: {
|
|
77
40
|
text: childType,
|
|
78
41
|
color: colors.type,
|
|
79
|
-
highlightedColor:
|
|
42
|
+
highlightedColor: TaskColors[TaskType.Plan].type,
|
|
80
43
|
},
|
|
81
44
|
};
|
|
82
45
|
});
|
|
@@ -209,5 +172,5 @@ export function Plan({ message, tasks, state, debug = false, onSelectionConfirme
|
|
|
209
172
|
!isDone;
|
|
210
173
|
return taskToListItem(task, childIndex, isDefineWithoutSelection);
|
|
211
174
|
});
|
|
212
|
-
return (_jsxs(Box, { flexDirection: "column", children: [message && (_jsx(Box, { marginBottom: 1, children: _jsx(Label, { description: message, descriptionColor:
|
|
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 })] }));
|
|
213
176
|
}
|
package/dist/ui/Separator.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Text } from 'ink';
|
|
3
|
-
|
|
3
|
+
import { Colors } from '../types/colors.js';
|
|
4
|
+
export const Separator = ({ color = Colors.Label.Discarded, spaces = 1, }) => {
|
|
4
5
|
const spacing = ' '.repeat(spaces);
|
|
5
6
|
return (_jsxs(Text, { color: color, children: [spacing, "\u203A", spacing] }));
|
|
6
7
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prompt-language-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.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",
|
|
@@ -46,22 +46,22 @@
|
|
|
46
46
|
},
|
|
47
47
|
"homepage": "https://github.com/aswitalski/pls#readme",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@anthropic-ai/sdk": "^0.
|
|
50
|
-
"ink": "^6.
|
|
49
|
+
"@anthropic-ai/sdk": "^0.69.0",
|
|
50
|
+
"ink": "^6.5.0",
|
|
51
51
|
"ink-text-input": "^6.0.0",
|
|
52
52
|
"react": "^19.2.0",
|
|
53
53
|
"yaml": "^2.8.1"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@types/node": "^
|
|
57
|
-
"@types/react": "^19.2.
|
|
58
|
-
"@vitest/coverage-v8": "^4.0.
|
|
59
|
-
"eslint": "^9.
|
|
56
|
+
"@types/node": "^24.10.1",
|
|
57
|
+
"@types/react": "^19.2.5",
|
|
58
|
+
"@vitest/coverage-v8": "^4.0.9",
|
|
59
|
+
"eslint": "^9.39.1",
|
|
60
60
|
"husky": "^9.1.7",
|
|
61
61
|
"ink-testing-library": "^4.0.0",
|
|
62
62
|
"prettier": "^3.6.2",
|
|
63
|
-
"typescript": "^5.
|
|
64
|
-
"typescript-eslint": "^8.
|
|
65
|
-
"vitest": "^4.0.
|
|
63
|
+
"typescript": "^5.9.3",
|
|
64
|
+
"typescript-eslint": "^8.46.4",
|
|
65
|
+
"vitest": "^4.0.9"
|
|
66
66
|
}
|
|
67
67
|
}
|