prompt-language-shell 0.4.9 → 0.5.2
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/README.md +114 -10
- package/dist/config/INTROSPECT.md +9 -5
- package/dist/config/PLAN.md +39 -1
- package/dist/config/VALIDATE.md +139 -0
- package/dist/handlers/config.js +23 -6
- package/dist/handlers/execute.js +10 -2
- package/dist/handlers/execution.js +68 -1
- package/dist/services/anthropic.js +3 -2
- package/dist/services/colors.js +2 -2
- package/dist/services/components.js +33 -1
- package/dist/services/config-loader.js +67 -0
- package/dist/services/execution-validator.js +110 -0
- package/dist/services/placeholder-resolver.js +120 -0
- package/dist/services/shell.js +1 -0
- package/dist/services/skill-expander.js +91 -0
- package/dist/services/skill-parser.js +169 -0
- package/dist/services/skills.js +26 -0
- package/dist/services/timing.js +38 -0
- package/dist/services/tool-registry.js +5 -0
- package/dist/tools/validate.tool.js +43 -0
- package/dist/types/skills.js +4 -0
- package/dist/types/types.js +1 -0
- package/dist/ui/Answer.js +3 -9
- package/dist/ui/Command.js +3 -6
- package/dist/ui/Component.js +7 -1
- package/dist/ui/Config.js +2 -2
- package/dist/ui/Execute.js +59 -14
- package/dist/ui/Introspect.js +6 -7
- package/dist/ui/Validate.js +120 -0
- package/dist/ui/Welcome.js +12 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Your personal command-line concierge. Ask politely, and it gets things done.
|
|
4
4
|
|
|
5
|
+
> **Note:** This project is in early preview. Features and APIs may change as
|
|
6
|
+
> development continues.
|
|
7
|
+
|
|
5
8
|
## Installation
|
|
6
9
|
|
|
7
10
|
```bash
|
|
@@ -14,30 +17,74 @@ On first run, `pls` walks you through a quick setup. Your settings will be saved
|
|
|
14
17
|
|
|
15
18
|
## Usage
|
|
16
19
|
|
|
17
|
-
Type `pls` followed by your request in natural language
|
|
20
|
+
Type `pls` followed by your request in natural language.
|
|
21
|
+
|
|
22
|
+
To see what `pls` can
|
|
23
|
+
do, start by listing available capabilities:
|
|
18
24
|
|
|
19
|
-
```bash
|
|
20
|
-
pls change dir to ~
|
|
21
25
|
```
|
|
26
|
+
$ pls list skills
|
|
27
|
+
|
|
28
|
+
Here's what I can help with:
|
|
29
|
+
|
|
30
|
+
- Introspect - list available capabilities and skills
|
|
31
|
+
- Config - manage and configure system settings
|
|
32
|
+
- Answer - respond to questions and provide information
|
|
33
|
+
- Execute - run shell commands and process operations
|
|
34
|
+
```
|
|
22
35
|
|
|
23
|
-
|
|
36
|
+
Skills are custom workflows you can define to teach `pls` about your specific
|
|
37
|
+
projects and commands. Once defined, you can use them naturally:
|
|
24
38
|
|
|
25
39
|
```
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
$ pls build project
|
|
41
|
+
|
|
42
|
+
Here's my plan.
|
|
43
|
+
|
|
44
|
+
- Navigate to project directory
|
|
45
|
+
- Compile source code
|
|
28
46
|
```
|
|
29
47
|
|
|
30
48
|
You can provide multiple requests at once:
|
|
31
49
|
|
|
32
50
|
```
|
|
33
|
-
|
|
51
|
+
$ pls install deps, run tests and build
|
|
52
|
+
|
|
53
|
+
Here's what I'll do.
|
|
54
|
+
|
|
34
55
|
- Install dependencies
|
|
35
56
|
- Run tests
|
|
36
|
-
-
|
|
57
|
+
- Build the project
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
When `pls` needs clarification, it will present options to choose from:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
$ pls deploy
|
|
64
|
+
|
|
65
|
+
Let me clarify.
|
|
66
|
+
|
|
67
|
+
→ Choose which environment to deploy to:
|
|
68
|
+
- Deploy to staging
|
|
69
|
+
- Deploy to production
|
|
37
70
|
```
|
|
38
71
|
|
|
39
72
|
Run `pls` without arguments to see the welcome screen.
|
|
40
73
|
|
|
74
|
+
## How It Works
|
|
75
|
+
|
|
76
|
+
When you make a request, `pls` interprets your intent and creates a structured
|
|
77
|
+
plan breaking down the work into individual tasks. You'll see this plan
|
|
78
|
+
displayed in your terminal before anything executes.
|
|
79
|
+
|
|
80
|
+
After reviewing the plan, you can confirm to proceed or cancel if something
|
|
81
|
+
doesn't look right. Once confirmed, `pls` executes each task sequentially and
|
|
82
|
+
shows real-time progress and results.
|
|
83
|
+
|
|
84
|
+
If you've defined custom skills, `pls` uses them to understand your
|
|
85
|
+
project-specific workflows and translate high-level requests into the exact
|
|
86
|
+
commands your environment requires.
|
|
87
|
+
|
|
41
88
|
## Configuration
|
|
42
89
|
|
|
43
90
|
Your configuration is stored in `~/.plsrc` as a YAML file. Supported settings:
|
|
@@ -47,9 +94,66 @@ Your configuration is stored in `~/.plsrc` as a YAML file. Supported settings:
|
|
|
47
94
|
|
|
48
95
|
## Skills
|
|
49
96
|
|
|
50
|
-
|
|
97
|
+
Skills let you teach `pls` about your project-specific workflows. Create
|
|
98
|
+
markdown files in `~/.pls/skills/` to define custom operations that `pls` can
|
|
99
|
+
understand and execute.
|
|
100
|
+
|
|
101
|
+
### Structure
|
|
102
|
+
|
|
103
|
+
Each skill file uses a simple markdown format:
|
|
104
|
+
|
|
105
|
+
- **Name**: What you call this workflow (e.g., "Build Project")
|
|
106
|
+
- **Description**: What it does and any variants or options
|
|
107
|
+
- **Steps**: What needs to happen, in order
|
|
108
|
+
- **Execution** (optional): The actual shell commands to run
|
|
109
|
+
|
|
110
|
+
### Example
|
|
111
|
+
|
|
112
|
+
Here's a skill that builds different project variants:
|
|
113
|
+
|
|
114
|
+
```markdown
|
|
115
|
+
### Name
|
|
116
|
+
Build Project
|
|
117
|
+
|
|
118
|
+
### Description
|
|
119
|
+
Build a project in different configurations:
|
|
120
|
+
- dev (debug build with source maps)
|
|
121
|
+
- prod (optimized build)
|
|
122
|
+
- test (with test coverage)
|
|
123
|
+
|
|
124
|
+
### Steps
|
|
125
|
+
- Navigate to the project directory
|
|
126
|
+
- Install dependencies if needed
|
|
127
|
+
- Run the {ENV} build script
|
|
128
|
+
- Generate build artifacts
|
|
51
129
|
|
|
52
|
-
|
|
130
|
+
### Execution
|
|
131
|
+
- cd ~/projects/next
|
|
132
|
+
- npm install
|
|
133
|
+
- npm run build:{ENV}
|
|
134
|
+
- cp -r dist/ builds/{ENV}/
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
With this skill defined, you can use natural language like:
|
|
138
|
+
```
|
|
139
|
+
$ pls build project for production
|
|
140
|
+
$ pls build dev environment
|
|
141
|
+
$ pls build with testing enabled
|
|
142
|
+
```
|
|
143
|
+
The `{ENV}` placeholder gets replaced with the variant you specify.
|
|
144
|
+
Instead of remembering the exact commands and paths for each environment, just
|
|
145
|
+
tell `pls` what you want in plain English. The Execution section ensures the right commands run every time.
|
|
146
|
+
|
|
147
|
+
### Keep It Short
|
|
148
|
+
|
|
149
|
+
Skills also work with concise commands. Once you've taught `pls` about your
|
|
150
|
+
workflow, you can use minimal phrasing:
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
$ pls build prod
|
|
154
|
+
$ pls build dev
|
|
155
|
+
$ pls build test
|
|
156
|
+
```
|
|
53
157
|
|
|
54
158
|
## Development
|
|
55
159
|
|
|
@@ -75,12 +75,13 @@ These MUST appear FIRST, in this EXACT sequence:
|
|
|
75
75
|
3. **Answer** ← ALWAYS THIRD
|
|
76
76
|
4. **Execute** ← ALWAYS FOURTH
|
|
77
77
|
|
|
78
|
-
### Position 5-
|
|
78
|
+
### Position 5-7: Indirect Workflow Capabilities
|
|
79
79
|
|
|
80
80
|
These MUST appear AFTER Execute and BEFORE user skills:
|
|
81
81
|
|
|
82
82
|
5. **Plan** ← NEVER FIRST, ALWAYS position 5 (after Execute)
|
|
83
|
-
6. **
|
|
83
|
+
6. **Validate** ← ALWAYS position 6 (after Plan)
|
|
84
|
+
7. **Report** ← NEVER FIRST, ALWAYS position 7 (after Validate)
|
|
84
85
|
|
|
85
86
|
### 3. User-Defined Skills
|
|
86
87
|
|
|
@@ -132,7 +133,9 @@ Examples:
|
|
|
132
133
|
|
|
133
134
|
When user asks "list your skills", create an introductory message like "here
|
|
134
135
|
are my capabilities:" followed by tasks for built-in capabilities (Introspect,
|
|
135
|
-
Config, Answer, Execute), then indirect workflow capabilities (Plan,
|
|
136
|
+
Config, Answer, Execute), then indirect workflow capabilities (Plan, Validate,
|
|
137
|
+
Report).
|
|
138
|
+
|
|
136
139
|
Each task uses type "introspect" with an action describing the capability.
|
|
137
140
|
|
|
138
141
|
### Example 2: Filtered Skills
|
|
@@ -146,8 +149,9 @@ with its description.
|
|
|
146
149
|
|
|
147
150
|
When user asks "what can you do" and user-defined skills like "process data"
|
|
148
151
|
and "backup files" exist, create an introductory message like "i can help with
|
|
149
|
-
these operations:" followed by all built-in capabilities
|
|
150
|
-
|
|
152
|
+
these operations:" followed by all built-in capabilities (Introspect, Config,
|
|
153
|
+
Answer, Execute, Validate, Plan, Report) plus the user-defined skills. Each
|
|
154
|
+
capability and skill becomes a task with type "introspect".
|
|
151
155
|
|
|
152
156
|
## Final Validation
|
|
153
157
|
|
package/dist/config/PLAN.md
CHANGED
|
@@ -113,6 +113,26 @@ executable operations.
|
|
|
113
113
|
Extract the individual steps from the skill's "Execution" or "Steps"
|
|
114
114
|
section (prefer Execution if available)
|
|
115
115
|
- Replace ALL parameter placeholders with the specified value
|
|
116
|
+
- **CRITICAL - Variant Placeholder Resolution**: If the execution commands
|
|
117
|
+
contain variant placeholders (any uppercase word in a placeholder path,
|
|
118
|
+
e.g., {section.VARIANT.property}, {project.TARGET.path}, {env.TYPE.name}),
|
|
119
|
+
you MUST:
|
|
120
|
+
1. Identify the variant name from the user's request (e.g., "alpha", "beta")
|
|
121
|
+
2. Normalize the variant to lowercase (e.g., "alpha", "beta")
|
|
122
|
+
3. Replace the uppercase placeholder component with the actual variant name
|
|
123
|
+
in ALL task actions
|
|
124
|
+
4. Examples:
|
|
125
|
+
- User says "process alpha target" → variant is "alpha"
|
|
126
|
+
- Execution line: `cd {project.VARIANT.path}`
|
|
127
|
+
- Task action MUST be: `cd {project.alpha.path}` (NOT `cd {project.VARIANT.path}`)
|
|
128
|
+
- User says "deploy to staging environment" → variant is "staging"
|
|
129
|
+
- Execution line: `setup {env.TYPE.config}`
|
|
130
|
+
- Task action MUST be: `setup {env.staging.config}` (NOT `setup {env.TYPE.config}`)
|
|
131
|
+
5. This applies to ALL placeholders in task actions, whether from direct
|
|
132
|
+
execution lines or from referenced skills (e.g., [Navigate To Target])
|
|
133
|
+
6. The uppercase word can be ANY name (VARIANT, TARGET, TYPE, PRODUCT, etc.) -
|
|
134
|
+
all uppercase path components indicate variant placeholders that must
|
|
135
|
+
be resolved
|
|
116
136
|
|
|
117
137
|
4. **Handle partial execution:**
|
|
118
138
|
- Keywords indicating partial execution: "only", "just", specific verbs
|
|
@@ -129,11 +149,16 @@ executable operations.
|
|
|
129
149
|
- type: category of operation (if the skill specifies it or you can infer it)
|
|
130
150
|
- params: MUST include:
|
|
131
151
|
- skill: the skill name (REQUIRED for all skill-based tasks)
|
|
132
|
-
-
|
|
152
|
+
- variant: the resolved variant value (REQUIRED if skill has variant placeholders)
|
|
153
|
+
- All other parameter values used in the step (e.g., target, environment, etc.)
|
|
133
154
|
- Any other specific parameters mentioned in the step
|
|
134
155
|
- NEVER replace the skill's detailed steps with a generic restatement
|
|
135
156
|
- The params.skill field is CRITICAL for execution to use the skill's
|
|
136
157
|
Execution section
|
|
158
|
+
- The params.variant field is CRITICAL for config validation to resolve
|
|
159
|
+
variant placeholders in the skill's Execution section
|
|
160
|
+
- Example: If user selects "Deploy to production" and skill has {env.VARIANT.url},
|
|
161
|
+
params must include variant: "production" so validator can resolve to {env.production.url}
|
|
137
162
|
|
|
138
163
|
6. **Handle additional requirements beyond the skill:**
|
|
139
164
|
- If the user's query includes additional requirements beyond the skill,
|
|
@@ -157,6 +182,19 @@ Example 1 - Skill with parameter, variant specified:
|
|
|
157
182
|
params: { skill: "Process Data", target: "Alpha" } }
|
|
158
183
|
- WRONG: Tasks without params.skill or single task "Process Alpha"
|
|
159
184
|
|
|
185
|
+
Example 1b - Skill with variant placeholder in config:
|
|
186
|
+
- Skill name: "Navigate To Target"
|
|
187
|
+
- Skill config defines: target.alpha.path, target.beta.path, target.gamma.path
|
|
188
|
+
- Skill execution: "cd {target.VARIANT.path}"
|
|
189
|
+
- User: "navigate to beta"
|
|
190
|
+
- Variant matched: "beta"
|
|
191
|
+
- Correct task: { action: "Navigate to Beta target directory", type: "execute",
|
|
192
|
+
params: { skill: "Navigate To Target", variant: "beta" } }
|
|
193
|
+
- WRONG: params without variant field
|
|
194
|
+
- WRONG: task action "cd {target.VARIANT.path}" (uppercase VARIANT not resolved!)
|
|
195
|
+
- Note: The config validator will use params.variant="beta" to resolve
|
|
196
|
+
{target.VARIANT.path} → {target.beta.path}, then check if it exists in ~/.plsrc
|
|
197
|
+
|
|
160
198
|
Example 2 - Skill with parameter, variant NOT specified:
|
|
161
199
|
- Same skill as Example 1
|
|
162
200
|
- User: "process"
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
## Overview
|
|
2
|
+
|
|
3
|
+
You are the validation component of "pls" (please), responsible for validating skill requirements and generating natural language descriptions for missing configuration values.
|
|
4
|
+
|
|
5
|
+
Your role is to help users understand what configuration values are needed and why, using context from skill descriptions to create clear, helpful prompts.
|
|
6
|
+
|
|
7
|
+
## Input
|
|
8
|
+
|
|
9
|
+
You will receive information about missing configuration values:
|
|
10
|
+
- Config path (e.g., "project.alpha.repo")
|
|
11
|
+
- Skill name that requires this config
|
|
12
|
+
- Variant (if applicable)
|
|
13
|
+
- Config type (string, boolean, number)
|
|
14
|
+
|
|
15
|
+
## Your Task
|
|
16
|
+
|
|
17
|
+
Generate a response with two required fields:
|
|
18
|
+
|
|
19
|
+
1. **message**: An empty string `""`
|
|
20
|
+
2. **tasks**: An array of CONFIG tasks, one for each missing config value
|
|
21
|
+
|
|
22
|
+
For each CONFIG task, create a natural language description that:
|
|
23
|
+
|
|
24
|
+
1. **Explains what the value is for** using context from the skill's description
|
|
25
|
+
2. **Keeps it SHORT** - one brief phrase (3-6 words max)
|
|
26
|
+
3. **Does NOT include the config path** - the path will be shown separately in debug mode
|
|
27
|
+
|
|
28
|
+
**CRITICAL**: You MUST include both the `message` field (set to empty string) and the `tasks` array in your response.
|
|
29
|
+
|
|
30
|
+
## Description Format
|
|
31
|
+
|
|
32
|
+
**Format:** "Brief description" (NO {config.path} at the end!)
|
|
33
|
+
|
|
34
|
+
The description should:
|
|
35
|
+
- Start with what the config value represents (e.g., "Path to...", "URL for...", "Name of...")
|
|
36
|
+
- Be SHORT and direct - no extra details or variant explanations
|
|
37
|
+
- NOT include the config path in curly brackets - that's added automatically
|
|
38
|
+
|
|
39
|
+
## Examples
|
|
40
|
+
|
|
41
|
+
### Example 1: Repository Path
|
|
42
|
+
|
|
43
|
+
**Input:**
|
|
44
|
+
- Config path: `project.alpha.repo`
|
|
45
|
+
- Skill: "Navigate To Project"
|
|
46
|
+
- Variant: "alpha"
|
|
47
|
+
|
|
48
|
+
**Correct output:**
|
|
49
|
+
```
|
|
50
|
+
message: ""
|
|
51
|
+
tasks: [
|
|
52
|
+
{
|
|
53
|
+
action: "Path to Alpha repository {project.alpha.repo}",
|
|
54
|
+
type: "config",
|
|
55
|
+
params: { key: "project.alpha.repo" }
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Example 2: Environment URL
|
|
61
|
+
|
|
62
|
+
**Input:**
|
|
63
|
+
- Config path: `env.staging.url`
|
|
64
|
+
- Skill: "Deploy Service"
|
|
65
|
+
- Variant: "staging"
|
|
66
|
+
|
|
67
|
+
**Correct output:**
|
|
68
|
+
```
|
|
69
|
+
message: ""
|
|
70
|
+
tasks: [
|
|
71
|
+
{
|
|
72
|
+
action: "Staging environment URL {env.staging.url}",
|
|
73
|
+
type: "config",
|
|
74
|
+
params: { key: "env.staging.url" }
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Example 3: Project Directory
|
|
80
|
+
|
|
81
|
+
**Input:**
|
|
82
|
+
- Config path: `workspace.beta.path`
|
|
83
|
+
- Skill: "Process Workspace"
|
|
84
|
+
- Variant: "beta"
|
|
85
|
+
|
|
86
|
+
**Correct output:**
|
|
87
|
+
```
|
|
88
|
+
message: ""
|
|
89
|
+
tasks: [
|
|
90
|
+
{
|
|
91
|
+
action: "Path to Beta workspace {workspace.beta.path}",
|
|
92
|
+
type: "config",
|
|
93
|
+
params: { key: "workspace.beta.path" }
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Guidelines
|
|
99
|
+
|
|
100
|
+
1. **Use skill context**: Read the skill's Description section to understand what the variant represents
|
|
101
|
+
2. **Be specific**: Don't just say "Repository path" - say "Alpha project repository path"
|
|
102
|
+
3. **Add helpful details**: Include information from the description (e.g., "legacy implementation")
|
|
103
|
+
4. **Keep it concise**: One sentence that clearly explains what's needed
|
|
104
|
+
5. **Always include the path**: End with `{config.path}` for technical reference
|
|
105
|
+
|
|
106
|
+
## Common Config Types
|
|
107
|
+
|
|
108
|
+
- **repo / repository**: "Path to [name] repository"
|
|
109
|
+
- **path / dir / directory**: "Path to [name] directory"
|
|
110
|
+
- **url**: "[Name] URL"
|
|
111
|
+
- **host**: "[Name] host address"
|
|
112
|
+
- **port**: "[Name] port number"
|
|
113
|
+
- **name**: "Name of [context]"
|
|
114
|
+
- **key / token / secret**: "[Name] authentication key/token/secret"
|
|
115
|
+
- **enabled**: "Enable/disable [feature]"
|
|
116
|
+
|
|
117
|
+
## Response Format
|
|
118
|
+
|
|
119
|
+
Return a message field (can be empty string) and an array of CONFIG tasks:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
message: ""
|
|
123
|
+
tasks: [
|
|
124
|
+
{
|
|
125
|
+
action: "Natural description {config.path}",
|
|
126
|
+
type: "config",
|
|
127
|
+
params: { key: "config.path" }
|
|
128
|
+
},
|
|
129
|
+
// ... more tasks
|
|
130
|
+
]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Important Notes
|
|
134
|
+
|
|
135
|
+
- All tasks must have type "config"
|
|
136
|
+
- All tasks must include params.key with the config path
|
|
137
|
+
- Descriptions should be helpful and contextual, not just technical
|
|
138
|
+
- Use information from Available Skills section to provide context
|
|
139
|
+
- Keep descriptions to one concise sentence
|
package/dist/handlers/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComponentName, FeedbackType } from '../types/types.js';
|
|
2
2
|
import { createAnthropicService, } from '../services/anthropic.js';
|
|
3
|
-
import { createCommandDefinition, createFeedback, markAsDone, } from '../services/components.js';
|
|
3
|
+
import { createCommandDefinition, createExecuteDefinition, createFeedback, markAsDone, } from '../services/components.js';
|
|
4
4
|
import { saveAnthropicConfig, saveConfig } from '../services/configuration.js';
|
|
5
5
|
import { FeedbackMessages } from '../services/messages.js';
|
|
6
6
|
import { exitApp } from '../services/process.js';
|
|
@@ -33,18 +33,27 @@ export function createConfigHandlers(ops, handleAborted, command, commandHandler
|
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* Creates config execution finished handler for CONFIG skill
|
|
36
|
-
* Saves arbitrary config keys and
|
|
36
|
+
* Saves arbitrary config keys and optionally continues with execution
|
|
37
37
|
*/
|
|
38
|
-
export function createConfigExecutionFinishedHandler(addToTimeline, keys) {
|
|
38
|
+
export function createConfigExecutionFinishedHandler(addToTimeline, keys, tasks, service, executeHandlers) {
|
|
39
39
|
return (config) => {
|
|
40
|
+
// Group by top-level section
|
|
40
41
|
const sections = {};
|
|
41
42
|
for (const fullKey of keys) {
|
|
42
43
|
const parts = fullKey.split('.');
|
|
43
44
|
const shortKey = parts[parts.length - 1];
|
|
44
|
-
const
|
|
45
|
-
|
|
45
|
+
const topSection = parts[0];
|
|
46
|
+
// Initialize section if needed
|
|
47
|
+
sections[topSection] = sections[topSection] ?? {};
|
|
46
48
|
if (shortKey in config) {
|
|
47
|
-
|
|
49
|
+
const value = config[shortKey];
|
|
50
|
+
// Build nested structure recursively
|
|
51
|
+
let current = sections[topSection];
|
|
52
|
+
for (let i = 1; i < parts.length - 1; i++) {
|
|
53
|
+
current[parts[i]] = current[parts[i]] ?? {};
|
|
54
|
+
current = current[parts[i]];
|
|
55
|
+
}
|
|
56
|
+
current[parts[parts.length - 1]] = value;
|
|
48
57
|
}
|
|
49
58
|
}
|
|
50
59
|
for (const [section, sectionConfig] of Object.entries(sections)) {
|
|
@@ -52,6 +61,14 @@ export function createConfigExecutionFinishedHandler(addToTimeline, keys) {
|
|
|
52
61
|
}
|
|
53
62
|
return withQueueHandler(ComponentName.Config, (first, rest) => {
|
|
54
63
|
addToTimeline(markAsDone(first), createFeedback(FeedbackType.Succeeded, FeedbackMessages.ConfigurationComplete));
|
|
64
|
+
// If tasks are provided, continue with execution
|
|
65
|
+
if (tasks && service && executeHandlers) {
|
|
66
|
+
return [
|
|
67
|
+
...rest,
|
|
68
|
+
createExecuteDefinition(tasks, service, executeHandlers.onError, executeHandlers.onComplete, executeHandlers.onAborted),
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
// Otherwise, exit (legacy behavior for initial setup)
|
|
55
72
|
exitApp(0);
|
|
56
73
|
return rest;
|
|
57
74
|
}, false, 0);
|
package/dist/handlers/execute.js
CHANGED
|
@@ -8,6 +8,7 @@ import { withQueueHandler } from '../services/queue.js';
|
|
|
8
8
|
* Creates all execute handlers
|
|
9
9
|
*/
|
|
10
10
|
export function createExecuteHandlers(ops, handleAborted) {
|
|
11
|
+
void handleAborted;
|
|
11
12
|
const onError = (error) => {
|
|
12
13
|
ops.setQueue(withQueueHandler(ComponentName.Execute, (first) => {
|
|
13
14
|
ops.addToTimeline(markAsDone(first), createFeedback(FeedbackType.Failed, error));
|
|
@@ -31,8 +32,15 @@ export function createExecuteHandlers(ops, handleAborted) {
|
|
|
31
32
|
return [];
|
|
32
33
|
}));
|
|
33
34
|
};
|
|
34
|
-
const onAborted = () => {
|
|
35
|
-
|
|
35
|
+
const onAborted = (elapsedTime) => {
|
|
36
|
+
ops.setQueue(withQueueHandler(ComponentName.Execute, (first) => {
|
|
37
|
+
const message = elapsedTime > 0
|
|
38
|
+
? `The execution was cancelled after ${formatDuration(elapsedTime)}.`
|
|
39
|
+
: 'The execution was cancelled.';
|
|
40
|
+
ops.addToTimeline(markAsDone(first), createFeedback(FeedbackType.Aborted, message));
|
|
41
|
+
exitApp(0);
|
|
42
|
+
return [];
|
|
43
|
+
}));
|
|
36
44
|
};
|
|
37
45
|
return { onError, onComplete, onAborted };
|
|
38
46
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ComponentName, FeedbackType, TaskType } from '../types/types.js';
|
|
2
|
-
import { createAnswerDefinition, createConfigDefinitionWithKeys, createExecuteDefinition, createFeedback, createIntrospectDefinition, markAsDone, } from '../services/components.js';
|
|
2
|
+
import { createAnswerDefinition, createConfigDefinitionWithKeys, createExecuteDefinition, createFeedback, createIntrospectDefinition, createValidateDefinition, markAsDone, } from '../services/components.js';
|
|
3
|
+
import { StepType } from '../ui/Config.js';
|
|
3
4
|
import { getCancellationMessage } from '../services/messages.js';
|
|
4
5
|
import { exitApp } from '../services/process.js';
|
|
5
6
|
import { withQueueHandler } from '../services/queue.js';
|
|
6
7
|
import { createConfigExecutionAbortedHandler, createConfigExecutionFinishedHandler, } from './config.js';
|
|
8
|
+
import { validateExecuteTasks } from '../services/execution-validator.js';
|
|
7
9
|
/**
|
|
8
10
|
* Creates all execution handlers
|
|
9
11
|
*/
|
|
@@ -49,6 +51,71 @@ export function createExecutionHandlers(ops, taskHandlers) {
|
|
|
49
51
|
];
|
|
50
52
|
}
|
|
51
53
|
else if (allExecute && tasks.length > 0) {
|
|
54
|
+
// Validate config requirements before execution
|
|
55
|
+
const missingConfig = validateExecuteTasks(tasks);
|
|
56
|
+
if (missingConfig.length > 0) {
|
|
57
|
+
// Config is missing - call VALIDATE tool to get contextual descriptions
|
|
58
|
+
const keys = missingConfig.map((req) => req.path);
|
|
59
|
+
const userRequest = tasks.map((t) => t.action).join(', ');
|
|
60
|
+
ops.addToTimeline(markAsDone(first));
|
|
61
|
+
// Create handlers for Validate completion
|
|
62
|
+
const handleValidateComplete = (configWithDescriptions) => {
|
|
63
|
+
ops.setQueue(withQueueHandler(ComponentName.Validate, (first) => {
|
|
64
|
+
// Create CONFIG component with descriptions from VALIDATE
|
|
65
|
+
const handleConfigFinished = (config) => {
|
|
66
|
+
ops.setQueue(createConfigExecutionFinishedHandler(ops.addToTimeline, keys, tasks, service, taskHandlers.execute)(config));
|
|
67
|
+
};
|
|
68
|
+
const handleConfigAborted = () => {
|
|
69
|
+
ops.setQueue(createConfigExecutionAbortedHandler(ops.addToTimeline)());
|
|
70
|
+
};
|
|
71
|
+
// Create config steps from validated descriptions
|
|
72
|
+
const steps = configWithDescriptions.map((req) => {
|
|
73
|
+
const keyParts = req.path.split('.');
|
|
74
|
+
const shortKey = keyParts[keyParts.length - 1];
|
|
75
|
+
// Extract description without the {path} suffix
|
|
76
|
+
// Format from VALIDATE: "Description {path}"
|
|
77
|
+
let description = req.description || req.path;
|
|
78
|
+
const pathPattern = /\s*\{[^}]+\}\s*$/;
|
|
79
|
+
description = description.replace(pathPattern, '').trim();
|
|
80
|
+
const step = {
|
|
81
|
+
description,
|
|
82
|
+
key: shortKey,
|
|
83
|
+
path: req.path,
|
|
84
|
+
type: StepType.Text,
|
|
85
|
+
value: null,
|
|
86
|
+
validate: () => true,
|
|
87
|
+
};
|
|
88
|
+
return step;
|
|
89
|
+
});
|
|
90
|
+
// Mark Validate as done and move to timeline
|
|
91
|
+
ops.addToTimeline(markAsDone(first));
|
|
92
|
+
return [
|
|
93
|
+
{
|
|
94
|
+
id: crypto.randomUUID(),
|
|
95
|
+
name: ComponentName.Config,
|
|
96
|
+
state: { done: false },
|
|
97
|
+
props: {
|
|
98
|
+
steps,
|
|
99
|
+
onFinished: handleConfigFinished,
|
|
100
|
+
onAborted: handleConfigAborted,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
}));
|
|
105
|
+
};
|
|
106
|
+
const handleValidateError = (error) => {
|
|
107
|
+
ops.addToTimeline(createFeedback(FeedbackType.Failed, error));
|
|
108
|
+
exitApp(1);
|
|
109
|
+
};
|
|
110
|
+
const handleValidateAborted = () => {
|
|
111
|
+
ops.addToTimeline(createFeedback(FeedbackType.Aborted, 'Configuration validation cancelled'));
|
|
112
|
+
exitApp(0);
|
|
113
|
+
};
|
|
114
|
+
return [
|
|
115
|
+
createValidateDefinition(missingConfig, userRequest, service, handleValidateError, handleValidateComplete, handleValidateAborted),
|
|
116
|
+
];
|
|
117
|
+
}
|
|
118
|
+
// No missing config - execute directly
|
|
52
119
|
ops.addToTimeline(markAsDone(first));
|
|
53
120
|
return [
|
|
54
121
|
createExecuteDefinition(tasks, service, taskHandlers.execute.onError, taskHandlers.execute.onComplete, taskHandlers.execute.onAborted),
|
|
@@ -18,7 +18,8 @@ export class AnthropicService {
|
|
|
18
18
|
// Add skills section for applicable tools
|
|
19
19
|
if (toolName === 'plan' ||
|
|
20
20
|
toolName === 'introspect' ||
|
|
21
|
-
toolName === 'execute'
|
|
21
|
+
toolName === 'execute' ||
|
|
22
|
+
toolName === 'validate') {
|
|
22
23
|
const skills = loadSkills();
|
|
23
24
|
const skillsSection = formatSkillsForPrompt(skills);
|
|
24
25
|
systemPrompt += skillsSection;
|
|
@@ -114,7 +115,7 @@ export class AnthropicService {
|
|
|
114
115
|
};
|
|
115
116
|
}
|
|
116
117
|
// Handle plan and introspect tool responses
|
|
117
|
-
if (
|
|
118
|
+
if (input.message === undefined || typeof input.message !== 'string') {
|
|
118
119
|
throw new Error('Invalid tool response: missing or invalid message field');
|
|
119
120
|
}
|
|
120
121
|
if (!input.tasks || !Array.isArray(input.tasks)) {
|
package/dist/services/colors.js
CHANGED
|
@@ -15,8 +15,8 @@ export const Palette = {
|
|
|
15
15
|
BrightGreen: '#3e9a3e',
|
|
16
16
|
Yellow: '#cccc5c',
|
|
17
17
|
LightYellow: '#d4d47a',
|
|
18
|
-
Orange: '#
|
|
19
|
-
DarkOrange: '#
|
|
18
|
+
Orange: '#f48c80',
|
|
19
|
+
DarkOrange: '#ab5e40',
|
|
20
20
|
BurntOrange: '#cc7a5c',
|
|
21
21
|
Red: '#cc5c5c',
|
|
22
22
|
Cyan: '#5c9ccc',
|
|
@@ -65,8 +65,22 @@ export function createConfigStepsFromSchema(keys) {
|
|
|
65
65
|
// Config doesn't exist yet, use defaults
|
|
66
66
|
}
|
|
67
67
|
return keys.map((key) => {
|
|
68
|
+
// Check if key is in schema (built-in config)
|
|
68
69
|
if (!(key in schema)) {
|
|
69
|
-
|
|
70
|
+
// Key is not in schema - it's from a skill
|
|
71
|
+
// Create a simple text step with placeholder description
|
|
72
|
+
const keyParts = key.split('.');
|
|
73
|
+
const shortKey = keyParts[keyParts.length - 1];
|
|
74
|
+
const description = keyParts
|
|
75
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
76
|
+
.join(' ');
|
|
77
|
+
return {
|
|
78
|
+
description: `${description} {${key}}`,
|
|
79
|
+
key: shortKey,
|
|
80
|
+
type: StepType.Text,
|
|
81
|
+
value: null,
|
|
82
|
+
validate: () => true, // Accept any string for now
|
|
83
|
+
};
|
|
70
84
|
}
|
|
71
85
|
const definition = schema[key];
|
|
72
86
|
const currentValue = getConfigValue(currentConfig, key);
|
|
@@ -318,3 +332,21 @@ export function createExecuteDefinition(tasks, service, onError, onComplete, onA
|
|
|
318
332
|
},
|
|
319
333
|
};
|
|
320
334
|
}
|
|
335
|
+
export function createValidateDefinition(missingConfig, userRequest, service, onError, onComplete, onAborted) {
|
|
336
|
+
return {
|
|
337
|
+
id: randomUUID(),
|
|
338
|
+
name: ComponentName.Validate,
|
|
339
|
+
state: {
|
|
340
|
+
done: false,
|
|
341
|
+
isLoading: true,
|
|
342
|
+
},
|
|
343
|
+
props: {
|
|
344
|
+
missingConfig,
|
|
345
|
+
userRequest,
|
|
346
|
+
service,
|
|
347
|
+
onError,
|
|
348
|
+
onComplete,
|
|
349
|
+
onAborted,
|
|
350
|
+
},
|
|
351
|
+
};
|
|
352
|
+
}
|