prompt-language-shell 0.9.2 → 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ui/Main.js → Main.js} +12 -12
- package/dist/{ui → components}/Component.js +28 -26
- package/dist/{ui → components}/Workflow.js +14 -4
- package/dist/{ui → components/controllers}/Answer.js +18 -17
- package/dist/{ui → components/controllers}/Command.js +11 -18
- package/dist/{ui → components/controllers}/Config.js +8 -116
- package/dist/components/controllers/Confirm.js +42 -0
- package/dist/{ui → components/controllers}/Execute.js +75 -144
- package/dist/{ui → components/controllers}/Introspect.js +12 -28
- package/dist/components/controllers/Refinement.js +18 -0
- package/dist/components/controllers/Schedule.js +134 -0
- package/dist/{ui → components/controllers}/Validate.js +14 -32
- package/dist/components/views/Answer.js +28 -0
- package/dist/components/views/Command.js +11 -0
- package/dist/components/views/Config.js +115 -0
- package/dist/components/views/Confirm.js +24 -0
- package/dist/components/views/Debug.js +12 -0
- package/dist/components/views/Execute.js +60 -0
- package/dist/components/views/Feedback.js +8 -0
- package/dist/components/views/Introspect.js +17 -0
- package/dist/{ui → components/views}/Label.js +3 -3
- package/dist/{ui → components/views}/List.js +1 -1
- package/dist/{ui → components/views}/Output.js +2 -2
- package/dist/components/views/Refinement.js +9 -0
- package/dist/{ui → components/views}/Report.js +1 -1
- package/dist/components/views/Schedule.js +121 -0
- package/dist/{ui → components/views}/Separator.js +1 -1
- package/dist/{ui → components/views}/Spinner.js +1 -1
- package/dist/{ui → components/views}/Subtask.js +4 -4
- package/dist/components/views/Table.js +15 -0
- package/dist/components/views/Task.js +18 -0
- package/dist/components/views/Upcoming.js +30 -0
- package/dist/{ui → components/views}/UserQuery.js +1 -1
- package/dist/components/views/Validate.js +17 -0
- package/dist/{ui → components/views}/Welcome.js +1 -1
- package/dist/configuration/steps.js +1 -1
- package/dist/execution/handlers.js +19 -53
- package/dist/execution/reducer.js +26 -38
- package/dist/execution/runner.js +43 -25
- package/dist/execution/types.js +3 -4
- package/dist/execution/utils.js +1 -1
- package/dist/index.js +1 -1
- package/dist/services/anthropic.js +27 -31
- package/dist/services/colors.js +2 -1
- package/dist/services/logger.js +126 -13
- package/dist/services/messages.js +19 -0
- package/dist/services/parser.js +13 -5
- package/dist/services/refinement.js +8 -2
- package/dist/services/router.js +184 -89
- package/dist/services/shell.js +26 -6
- package/dist/services/skills.js +35 -7
- package/dist/services/timing.js +1 -0
- package/dist/skills/execute.md +15 -7
- package/dist/skills/schedule.md +155 -0
- package/dist/tools/execute.tool.js +0 -4
- package/dist/tools/schedule.tool.js +1 -1
- package/dist/types/schemas.js +0 -1
- package/package.json +4 -4
- package/dist/execution/hooks.js +0 -291
- package/dist/ui/Confirm.js +0 -62
- package/dist/ui/Debug.js +0 -7
- package/dist/ui/Feedback.js +0 -19
- package/dist/ui/Refinement.js +0 -23
- package/dist/ui/Schedule.js +0 -257
- package/dist/ui/Task.js +0 -11
- /package/dist/{ui → components/views}/Message.js +0 -0
- /package/dist/{ui → components/views}/Panel.js +0 -0
|
@@ -7,7 +7,7 @@ import { getTotalElapsed } from './utils.js';
|
|
|
7
7
|
*/
|
|
8
8
|
export function handleTaskCompletion(index, elapsed, context) {
|
|
9
9
|
const { tasks, message, summary } = context;
|
|
10
|
-
const
|
|
10
|
+
const updatedTasks = tasks.map((task, i) => i === index ? { ...task, status: ExecutionStatus.Success, elapsed } : task);
|
|
11
11
|
if (index < tasks.length - 1) {
|
|
12
12
|
// More tasks to execute
|
|
13
13
|
return {
|
|
@@ -18,7 +18,7 @@ export function handleTaskCompletion(index, elapsed, context) {
|
|
|
18
18
|
finalState: {
|
|
19
19
|
message,
|
|
20
20
|
summary,
|
|
21
|
-
tasks:
|
|
21
|
+
tasks: updatedTasks,
|
|
22
22
|
completionMessage: null,
|
|
23
23
|
error: null,
|
|
24
24
|
},
|
|
@@ -27,17 +27,17 @@ export function handleTaskCompletion(index, elapsed, context) {
|
|
|
27
27
|
}
|
|
28
28
|
// All tasks complete
|
|
29
29
|
const summaryText = summary.trim() || 'Execution completed';
|
|
30
|
-
const totalElapsed = getTotalElapsed(
|
|
30
|
+
const totalElapsed = getTotalElapsed(updatedTasks);
|
|
31
31
|
const completion = `${summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
32
32
|
return {
|
|
33
33
|
action: {
|
|
34
|
-
type: ExecuteActionType.
|
|
34
|
+
type: ExecuteActionType.ExecutionComplete,
|
|
35
35
|
payload: { index, elapsed, summaryText },
|
|
36
36
|
},
|
|
37
37
|
finalState: {
|
|
38
38
|
message,
|
|
39
39
|
summary,
|
|
40
|
-
tasks:
|
|
40
|
+
tasks: updatedTasks,
|
|
41
41
|
completionMessage: completion,
|
|
42
42
|
error: null,
|
|
43
43
|
},
|
|
@@ -47,63 +47,29 @@ export function handleTaskCompletion(index, elapsed, context) {
|
|
|
47
47
|
/**
|
|
48
48
|
* Handles task error logic and returns the appropriate action and state.
|
|
49
49
|
*/
|
|
50
|
-
export function handleTaskFailure(index, error,
|
|
50
|
+
export function handleTaskFailure(index, error, context) {
|
|
51
51
|
const { tasks, message, summary } = context;
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
},
|
|
62
|
-
finalState: {
|
|
63
|
-
message,
|
|
64
|
-
summary,
|
|
65
|
-
tasks: updatedTaskInfos,
|
|
66
|
-
completionMessage: null,
|
|
67
|
-
error: null,
|
|
68
|
-
},
|
|
69
|
-
shouldComplete: true,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
// Non-critical failure - continue to next task
|
|
73
|
-
if (index < tasks.length - 1) {
|
|
74
|
-
return {
|
|
75
|
-
action: {
|
|
76
|
-
type: ExecuteActionType.TaskErrorContinue,
|
|
77
|
-
payload: { index, elapsed },
|
|
78
|
-
},
|
|
79
|
-
finalState: {
|
|
80
|
-
message,
|
|
81
|
-
summary,
|
|
82
|
-
tasks: updatedTaskInfos,
|
|
83
|
-
completionMessage: null,
|
|
84
|
-
error: null,
|
|
85
|
-
},
|
|
86
|
-
shouldComplete: false,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
// Last task failed (non-critical), complete execution
|
|
90
|
-
// Non-critical failures still show completion message with summary
|
|
91
|
-
const summaryText = summary.trim() || 'Execution completed';
|
|
92
|
-
const totalElapsed = getTotalElapsed(updatedTaskInfos);
|
|
93
|
-
const completion = `${summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
52
|
+
const updatedTasks = tasks.map((task, i) => {
|
|
53
|
+
if (i === index) {
|
|
54
|
+
return { ...task, status: ExecutionStatus.Failed, elapsed: 0 };
|
|
55
|
+
}
|
|
56
|
+
else if (i > index && task.status === ExecutionStatus.Pending) {
|
|
57
|
+
return { ...task, status: ExecutionStatus.Cancelled };
|
|
58
|
+
}
|
|
59
|
+
return task;
|
|
60
|
+
});
|
|
94
61
|
return {
|
|
95
62
|
action: {
|
|
96
|
-
type: ExecuteActionType.
|
|
97
|
-
payload: { index,
|
|
63
|
+
type: ExecuteActionType.TaskError,
|
|
64
|
+
payload: { index, error },
|
|
98
65
|
},
|
|
99
66
|
finalState: {
|
|
100
67
|
message,
|
|
101
68
|
summary,
|
|
102
|
-
tasks:
|
|
103
|
-
completionMessage:
|
|
69
|
+
tasks: updatedTasks,
|
|
70
|
+
completionMessage: null,
|
|
104
71
|
error: null,
|
|
105
72
|
},
|
|
106
|
-
shouldComplete: true,
|
|
107
73
|
};
|
|
108
74
|
}
|
|
109
75
|
/**
|
|
@@ -33,84 +33,72 @@ export function executeReducer(state, action) {
|
|
|
33
33
|
};
|
|
34
34
|
case ExecuteActionType.TaskStarted: {
|
|
35
35
|
const updatedTasks = state.tasks.map((task, i) => i === action.payload.index
|
|
36
|
-
? {
|
|
36
|
+
? {
|
|
37
|
+
...task,
|
|
38
|
+
status: ExecutionStatus.Running,
|
|
39
|
+
startTime: action.payload.startTime,
|
|
40
|
+
}
|
|
37
41
|
: task);
|
|
38
42
|
return {
|
|
39
43
|
...state,
|
|
40
44
|
tasks: updatedTasks,
|
|
41
45
|
};
|
|
42
46
|
}
|
|
43
|
-
case ExecuteActionType.
|
|
44
|
-
const
|
|
47
|
+
case ExecuteActionType.TaskProgress: {
|
|
48
|
+
const updatedTasks = state.tasks.map((task, i) => i === action.payload.index
|
|
45
49
|
? {
|
|
46
50
|
...task,
|
|
47
|
-
status: ExecutionStatus.Success,
|
|
48
51
|
elapsed: action.payload.elapsed,
|
|
52
|
+
output: action.payload.output,
|
|
49
53
|
}
|
|
50
54
|
: task);
|
|
51
55
|
return {
|
|
52
56
|
...state,
|
|
53
|
-
tasks:
|
|
57
|
+
tasks: updatedTasks,
|
|
54
58
|
};
|
|
55
59
|
}
|
|
56
|
-
case ExecuteActionType.
|
|
57
|
-
const
|
|
60
|
+
case ExecuteActionType.TaskComplete: {
|
|
61
|
+
const updatedTasks = state.tasks.map((task, i) => i === action.payload.index
|
|
58
62
|
? {
|
|
59
63
|
...task,
|
|
60
64
|
status: ExecutionStatus.Success,
|
|
61
65
|
elapsed: action.payload.elapsed,
|
|
62
66
|
}
|
|
63
67
|
: task);
|
|
64
|
-
const totalElapsed = getTotalElapsed(updatedTaskInfos);
|
|
65
|
-
const completion = `${action.payload.summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
66
68
|
return {
|
|
67
69
|
...state,
|
|
68
|
-
tasks:
|
|
69
|
-
completionMessage: completion,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
case ExecuteActionType.TaskErrorCritical: {
|
|
73
|
-
const updatedTaskInfos = state.tasks.map((task, i) => i === action.payload.index
|
|
74
|
-
? { ...task, status: ExecutionStatus.Failed, elapsed: 0 }
|
|
75
|
-
: task);
|
|
76
|
-
return {
|
|
77
|
-
...state,
|
|
78
|
-
tasks: updatedTaskInfos,
|
|
79
|
-
error: action.payload.error,
|
|
70
|
+
tasks: updatedTasks,
|
|
80
71
|
};
|
|
81
72
|
}
|
|
82
|
-
case ExecuteActionType.
|
|
83
|
-
const
|
|
73
|
+
case ExecuteActionType.ExecutionComplete: {
|
|
74
|
+
const updatedTasks = state.tasks.map((task, i) => i === action.payload.index
|
|
84
75
|
? {
|
|
85
76
|
...task,
|
|
86
|
-
status: ExecutionStatus.
|
|
77
|
+
status: ExecutionStatus.Success,
|
|
87
78
|
elapsed: action.payload.elapsed,
|
|
88
79
|
}
|
|
89
80
|
: task);
|
|
81
|
+
const totalElapsed = getTotalElapsed(updatedTasks);
|
|
82
|
+
const completion = `${action.payload.summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
90
83
|
return {
|
|
91
84
|
...state,
|
|
92
|
-
tasks:
|
|
85
|
+
tasks: updatedTasks,
|
|
86
|
+
completionMessage: completion,
|
|
93
87
|
};
|
|
94
88
|
}
|
|
95
|
-
case ExecuteActionType.
|
|
96
|
-
const
|
|
97
|
-
? {
|
|
98
|
-
...task,
|
|
99
|
-
status: ExecutionStatus.Failed,
|
|
100
|
-
elapsed: action.payload.elapsed,
|
|
101
|
-
}
|
|
89
|
+
case ExecuteActionType.TaskError: {
|
|
90
|
+
const updatedTasks = state.tasks.map((task, i) => i === action.payload.index
|
|
91
|
+
? { ...task, status: ExecutionStatus.Failed, elapsed: 0 }
|
|
102
92
|
: task);
|
|
103
|
-
const totalElapsed = getTotalElapsed(updatedTaskInfos);
|
|
104
|
-
const completion = `${action.payload.summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
105
93
|
return {
|
|
106
94
|
...state,
|
|
107
|
-
tasks:
|
|
108
|
-
|
|
95
|
+
tasks: updatedTasks,
|
|
96
|
+
error: action.payload.error,
|
|
109
97
|
};
|
|
110
98
|
}
|
|
111
99
|
case ExecuteActionType.CancelExecution: {
|
|
112
100
|
// Mark running task as aborted, pending tasks as cancelled
|
|
113
|
-
const
|
|
101
|
+
const updatedTasks = state.tasks.map((task) => {
|
|
114
102
|
if (task.status === ExecutionStatus.Running) {
|
|
115
103
|
return { ...task, status: ExecutionStatus.Aborted };
|
|
116
104
|
}
|
|
@@ -121,7 +109,7 @@ export function executeReducer(state, action) {
|
|
|
121
109
|
});
|
|
122
110
|
return {
|
|
123
111
|
...state,
|
|
124
|
-
tasks:
|
|
112
|
+
tasks: updatedTasks,
|
|
125
113
|
};
|
|
126
114
|
}
|
|
127
115
|
default:
|
package/dist/execution/runner.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { ExecutionResult, ExecutionStatus, executeCommand, setOutputCallback, } from '../services/shell.js';
|
|
2
2
|
import { calculateElapsed } from '../services/utils.js';
|
|
3
|
+
// Maximum number of output lines to keep in memory
|
|
4
|
+
const MAX_OUTPUT_LINES = 128;
|
|
5
|
+
/**
|
|
6
|
+
* Limit output to last MAX_OUTPUT_LINES lines to prevent memory exhaustion
|
|
7
|
+
*/
|
|
8
|
+
function limitLines(output) {
|
|
9
|
+
const lines = output.split('\n');
|
|
10
|
+
return lines.slice(-MAX_OUTPUT_LINES).join('\n');
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* Execute a single task and track its progress.
|
|
5
14
|
* All execution logic is contained here, outside of React components.
|
|
@@ -17,21 +26,38 @@ export async function executeTask(command, index, callbacks) {
|
|
|
17
26
|
error,
|
|
18
27
|
workdir,
|
|
19
28
|
});
|
|
29
|
+
// Throttle updates to avoid excessive re-renders (100ms minimum interval)
|
|
30
|
+
let lastUpdateTime = 0;
|
|
31
|
+
let pendingTimeout;
|
|
32
|
+
const throttledUpdate = () => {
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
if (now - lastUpdateTime >= 100) {
|
|
35
|
+
lastUpdateTime = now;
|
|
36
|
+
callbacks.onUpdate(createOutput());
|
|
37
|
+
}
|
|
38
|
+
else if (!pendingTimeout) {
|
|
39
|
+
pendingTimeout = setTimeout(() => {
|
|
40
|
+
pendingTimeout = undefined;
|
|
41
|
+
lastUpdateTime = Date.now();
|
|
42
|
+
callbacks.onUpdate(createOutput());
|
|
43
|
+
}, 100 - (now - lastUpdateTime));
|
|
44
|
+
}
|
|
45
|
+
};
|
|
20
46
|
// Set up output streaming callback
|
|
21
47
|
setOutputCallback((data, stream) => {
|
|
22
48
|
if (stream === 'stdout') {
|
|
23
|
-
stdout
|
|
49
|
+
stdout = limitLines(stdout + data);
|
|
24
50
|
}
|
|
25
51
|
else {
|
|
26
|
-
stderr
|
|
52
|
+
stderr = limitLines(stderr + data);
|
|
27
53
|
}
|
|
28
|
-
|
|
54
|
+
throttledUpdate();
|
|
29
55
|
});
|
|
30
|
-
callbacks.onStart?.();
|
|
31
56
|
try {
|
|
32
57
|
const result = await executeCommand(command, undefined, index);
|
|
33
|
-
// Clear callback
|
|
58
|
+
// Clear callback and pending timeout
|
|
34
59
|
setOutputCallback(undefined);
|
|
60
|
+
clearTimeout(pendingTimeout);
|
|
35
61
|
const elapsed = calculateElapsed(startTime);
|
|
36
62
|
// Update final output from result
|
|
37
63
|
stdout = result.output;
|
|
@@ -39,42 +65,34 @@ export async function executeTask(command, index, callbacks) {
|
|
|
39
65
|
workdir = result.workdir;
|
|
40
66
|
if (result.result === ExecutionResult.Success) {
|
|
41
67
|
const output = createOutput();
|
|
42
|
-
callbacks.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
elapsed,
|
|
46
|
-
output,
|
|
47
|
-
};
|
|
68
|
+
callbacks.onUpdate(output);
|
|
69
|
+
callbacks.onComplete(elapsed, output);
|
|
70
|
+
return { status: ExecutionStatus.Success, elapsed, output };
|
|
48
71
|
}
|
|
49
72
|
else {
|
|
50
73
|
const errorMsg = result.errors || result.error || 'Command failed';
|
|
51
74
|
error = errorMsg;
|
|
52
75
|
const output = createOutput();
|
|
53
|
-
callbacks.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
elapsed,
|
|
57
|
-
output,
|
|
58
|
-
};
|
|
76
|
+
callbacks.onUpdate(output);
|
|
77
|
+
callbacks.onError(errorMsg, output);
|
|
78
|
+
return { status: ExecutionStatus.Failed, elapsed, output };
|
|
59
79
|
}
|
|
60
80
|
}
|
|
61
81
|
catch (err) {
|
|
62
|
-
// Clear callback
|
|
82
|
+
// Clear callback and pending timeout
|
|
63
83
|
setOutputCallback(undefined);
|
|
84
|
+
clearTimeout(pendingTimeout);
|
|
64
85
|
const elapsed = calculateElapsed(startTime);
|
|
65
86
|
const errorMsg = err instanceof Error ? err.message : 'Unknown error';
|
|
66
87
|
error = errorMsg;
|
|
67
88
|
const output = createOutput();
|
|
68
|
-
callbacks.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
elapsed,
|
|
72
|
-
output,
|
|
73
|
-
};
|
|
89
|
+
callbacks.onUpdate(output);
|
|
90
|
+
callbacks.onError(errorMsg, output);
|
|
91
|
+
return { status: ExecutionStatus.Failed, elapsed, output };
|
|
74
92
|
}
|
|
75
93
|
}
|
|
76
94
|
/**
|
|
77
|
-
* Create an empty
|
|
95
|
+
* Create an empty execution output
|
|
78
96
|
*/
|
|
79
97
|
export function createEmptyOutput() {
|
|
80
98
|
return { stdout: '', stderr: '', error: '' };
|
package/dist/execution/types.js
CHANGED
|
@@ -4,10 +4,9 @@ export var ExecuteActionType;
|
|
|
4
4
|
ExecuteActionType["CommandsReady"] = "COMMANDS_READY";
|
|
5
5
|
ExecuteActionType["ProcessingError"] = "PROCESSING_ERROR";
|
|
6
6
|
ExecuteActionType["TaskStarted"] = "TASK_STARTED";
|
|
7
|
+
ExecuteActionType["TaskProgress"] = "TASK_PROGRESS";
|
|
7
8
|
ExecuteActionType["TaskComplete"] = "TASK_COMPLETE";
|
|
8
|
-
ExecuteActionType["
|
|
9
|
-
ExecuteActionType["
|
|
10
|
-
ExecuteActionType["TaskErrorContinue"] = "TASK_ERROR_CONTINUE";
|
|
11
|
-
ExecuteActionType["LastTaskError"] = "LAST_TASK_ERROR";
|
|
9
|
+
ExecuteActionType["ExecutionComplete"] = "EXECUTION_COMPLETE";
|
|
10
|
+
ExecuteActionType["TaskError"] = "TASK_ERROR";
|
|
12
11
|
ExecuteActionType["CancelExecution"] = "CANCEL_EXECUTION";
|
|
13
12
|
})(ExecuteActionType || (ExecuteActionType = {}));
|
package/dist/execution/utils.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { dirname, join } from 'path';
|
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { render } from 'ink';
|
|
7
7
|
import { DebugLevel } from './configuration/types.js';
|
|
8
|
-
import { Main } from './
|
|
8
|
+
import { Main } from './Main.js';
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
10
|
const __dirname = dirname(__filename);
|
|
11
11
|
// Get package info
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Anthropic from '@anthropic-ai/sdk';
|
|
2
2
|
import { getAvailableConfigStructure, getConfiguredKeys, } from '../configuration/schema.js';
|
|
3
3
|
import { logPrompt, logResponse } from './logger.js';
|
|
4
|
-
import {
|
|
4
|
+
import { loadSkillsForPrompt } from './skills.js';
|
|
5
5
|
import { toolRegistry } from './registry.js';
|
|
6
6
|
import { CommandResultSchema, IntrospectResultSchema, } from '../types/schemas.js';
|
|
7
7
|
/**
|
|
@@ -69,36 +69,32 @@ export class AnthropicService {
|
|
|
69
69
|
async processWithTool(command, toolName, customInstructions) {
|
|
70
70
|
// Load tool from registry
|
|
71
71
|
const tool = toolRegistry.getSchema(toolName);
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
// Check if this tool uses skills
|
|
73
|
+
const usesSkills = toolName === 'schedule' ||
|
|
74
|
+
toolName === 'introspect' ||
|
|
75
|
+
toolName === 'execute' ||
|
|
76
|
+
toolName === 'validate';
|
|
77
|
+
// Load base instructions and skills
|
|
78
|
+
const baseInstructions = customInstructions || toolRegistry.getInstructions(toolName);
|
|
79
|
+
let formattedSkills = '';
|
|
80
|
+
let skillDefinitions = [];
|
|
81
|
+
let systemPrompt = baseInstructions;
|
|
82
|
+
if (!customInstructions && usesSkills) {
|
|
83
|
+
const skillsResult = loadSkillsForPrompt();
|
|
84
|
+
formattedSkills = skillsResult.formatted;
|
|
85
|
+
skillDefinitions = skillsResult.definitions;
|
|
86
|
+
systemPrompt += formattedSkills;
|
|
77
87
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const skillsSection = formatSkillsForPrompt(skills);
|
|
89
|
-
systemPrompt += skillsSection;
|
|
90
|
-
}
|
|
91
|
-
// Add config structure for configure tool only
|
|
92
|
-
if (toolName === 'configure') {
|
|
93
|
-
const configStructure = getAvailableConfigStructure();
|
|
94
|
-
const configuredKeys = getConfiguredKeys();
|
|
95
|
-
const configSection = '\n## Available Configuration\n\n' +
|
|
96
|
-
'Config structure (key: description):\n' +
|
|
97
|
-
JSON.stringify(configStructure, null, 2) +
|
|
98
|
-
'\n\nConfigured keys (keys that exist in config file):\n' +
|
|
99
|
-
JSON.stringify(configuredKeys, null, 2);
|
|
100
|
-
systemPrompt += configSection;
|
|
101
|
-
}
|
|
88
|
+
// Add config structure for configure tool only
|
|
89
|
+
if (!customInstructions && toolName === 'configure') {
|
|
90
|
+
const configStructure = getAvailableConfigStructure();
|
|
91
|
+
const configuredKeys = getConfiguredKeys();
|
|
92
|
+
const configSection = '\n## Available Configuration\n\n' +
|
|
93
|
+
'Config structure (key: description):\n' +
|
|
94
|
+
JSON.stringify(configStructure, null, 2) +
|
|
95
|
+
'\n\nConfigured keys (keys that exist in config file):\n' +
|
|
96
|
+
JSON.stringify(configuredKeys, null, 2);
|
|
97
|
+
systemPrompt += configSection;
|
|
102
98
|
}
|
|
103
99
|
// Build tools array - add web search for answer tool
|
|
104
100
|
const tools = [tool];
|
|
@@ -111,7 +107,7 @@ export class AnthropicService {
|
|
|
111
107
|
// Collect debug components
|
|
112
108
|
const debug = [];
|
|
113
109
|
// Log prompt at Verbose level
|
|
114
|
-
const promptDebug = logPrompt(toolName, command,
|
|
110
|
+
const promptDebug = logPrompt(toolName, command, baseInstructions, formattedSkills, skillDefinitions);
|
|
115
111
|
if (promptDebug) {
|
|
116
112
|
debug.push(promptDebug);
|
|
117
113
|
}
|
package/dist/services/colors.js
CHANGED
|
@@ -20,6 +20,7 @@ export const Palette = {
|
|
|
20
20
|
Yellow: '#cccc5c',
|
|
21
21
|
Orange: '#f48c80',
|
|
22
22
|
MediumOrange: '#d07560',
|
|
23
|
+
WarmOrange: '#ce985e',
|
|
23
24
|
DarkOrange: '#ab5e40',
|
|
24
25
|
BurntOrange: '#cc7a5c',
|
|
25
26
|
Red: '#cc5c5c',
|
|
@@ -132,7 +133,7 @@ const taskColors = {
|
|
|
132
133
|
*/
|
|
133
134
|
const feedbackColors = {
|
|
134
135
|
[FeedbackType.Info]: Colors.Status.Info,
|
|
135
|
-
[FeedbackType.Warning]: Palette.
|
|
136
|
+
[FeedbackType.Warning]: Palette.WarmOrange,
|
|
136
137
|
[FeedbackType.Succeeded]: Colors.Status.Success,
|
|
137
138
|
[FeedbackType.Aborted]: Palette.MediumOrange,
|
|
138
139
|
[FeedbackType.Failed]: Colors.Status.Error,
|
package/dist/services/logger.js
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { DebugLevel } from '../configuration/types.js';
|
|
2
|
-
import { createDebug } from './components.js';
|
|
3
2
|
import { loadDebugSetting } from '../configuration/io.js';
|
|
4
3
|
import { Palette } from './colors.js';
|
|
4
|
+
import { createDebug } from './components.js';
|
|
5
|
+
/**
|
|
6
|
+
* Enum controlling what content is shown in debug prompt output
|
|
7
|
+
* - LLM: Exact prompt as sent to LLM (no display formatting)
|
|
8
|
+
* - Skills: Same content with visual separators for readability
|
|
9
|
+
* - Summary: Condensed view (Name, Steps, Execution only)
|
|
10
|
+
*/
|
|
11
|
+
export var PromptDisplay;
|
|
12
|
+
(function (PromptDisplay) {
|
|
13
|
+
PromptDisplay["LLM"] = "llm";
|
|
14
|
+
PromptDisplay["Skills"] = "skills";
|
|
15
|
+
PromptDisplay["Summary"] = "summary";
|
|
16
|
+
})(PromptDisplay || (PromptDisplay = {}));
|
|
5
17
|
/**
|
|
6
18
|
* Debug logger for the application
|
|
7
19
|
* Logs information based on the current debug level setting
|
|
@@ -49,24 +61,125 @@ export function getWarnings() {
|
|
|
49
61
|
warnings.length = 0;
|
|
50
62
|
return result;
|
|
51
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Content width for debug display (matches Debug component)
|
|
66
|
+
* Box width 80 - 2 borders - 4 padding = 74 chars
|
|
67
|
+
*/
|
|
68
|
+
const DISPLAY_CONTENT_WIDTH = 74;
|
|
69
|
+
/**
|
|
70
|
+
* Join sections with separators matching display width
|
|
71
|
+
*/
|
|
72
|
+
function joinWithSeparators(sections) {
|
|
73
|
+
const separator = '-'.repeat(DISPLAY_CONTENT_WIDTH);
|
|
74
|
+
return sections.join('\n\n' + separator + '\n\n');
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Format a single skill definition as summary markdown
|
|
78
|
+
*/
|
|
79
|
+
function formatSkillSummary(skill) {
|
|
80
|
+
const lines = [];
|
|
81
|
+
lines.push(`### Name`);
|
|
82
|
+
lines.push(skill.name);
|
|
83
|
+
lines.push('');
|
|
84
|
+
if (skill.steps.length > 0) {
|
|
85
|
+
lines.push(`### Steps`);
|
|
86
|
+
for (const step of skill.steps) {
|
|
87
|
+
lines.push(`- ${step}`);
|
|
88
|
+
}
|
|
89
|
+
lines.push('');
|
|
90
|
+
}
|
|
91
|
+
if (skill.execution.length > 0) {
|
|
92
|
+
lines.push(`### Execution`);
|
|
93
|
+
for (const cmd of skill.execution) {
|
|
94
|
+
lines.push(`- ${cmd}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return lines.join('\n').trim();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Format skill definitions as summary for debug display
|
|
101
|
+
* Shows only Name, Steps, and Execution with visual separators
|
|
102
|
+
*/
|
|
103
|
+
export function formatSkillsSummary(definitions) {
|
|
104
|
+
if (definitions.length === 0) {
|
|
105
|
+
return '(no skills)';
|
|
106
|
+
}
|
|
107
|
+
const header = '## Available Skills';
|
|
108
|
+
const skillSummaries = definitions.map(formatSkillSummary);
|
|
109
|
+
return joinWithSeparators([header, ...skillSummaries]);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Format skills section with visual separators for debug display
|
|
113
|
+
* Layout: Header description -> separator -> skills separated by lines
|
|
114
|
+
*/
|
|
115
|
+
function formatSkillsForDisplay(formattedSkills) {
|
|
116
|
+
if (!formattedSkills) {
|
|
117
|
+
return '(no skills)';
|
|
118
|
+
}
|
|
119
|
+
// Find the header (everything before first ### Name)
|
|
120
|
+
const firstNameIndex = formattedSkills.search(/^###\s+Name/m);
|
|
121
|
+
if (firstNameIndex === -1) {
|
|
122
|
+
return '(no skills)';
|
|
123
|
+
}
|
|
124
|
+
const header = formattedSkills.slice(0, firstNameIndex).trim();
|
|
125
|
+
const skillsContent = formattedSkills.slice(firstNameIndex);
|
|
126
|
+
// Split by ### Name to get individual skills
|
|
127
|
+
const skillParts = skillsContent
|
|
128
|
+
.split(/(?=^###\s+Name)/m)
|
|
129
|
+
.map((s) => s.trim())
|
|
130
|
+
.filter(Boolean);
|
|
131
|
+
if (skillParts.length === 0) {
|
|
132
|
+
return '(no skills)';
|
|
133
|
+
}
|
|
134
|
+
// Join header and skills with separators
|
|
135
|
+
return joinWithSeparators([header, ...skillParts]);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Format prompt content based on the specified detail level
|
|
139
|
+
*
|
|
140
|
+
* - LLM: Returns header + base instructions + formatted skills (as sent to LLM)
|
|
141
|
+
* - Skills: Returns header + skills with visual separators (no base instructions)
|
|
142
|
+
* - Summary: Returns header + skill summaries (Name, Steps, Execution)
|
|
143
|
+
*/
|
|
144
|
+
export function formatPromptContent(toolName, command, baseInstructions, formattedSkills, mode, definitions) {
|
|
145
|
+
const header = ['', `Tool: ${toolName}`, `Command: ${command}`];
|
|
146
|
+
switch (mode) {
|
|
147
|
+
case PromptDisplay.LLM:
|
|
148
|
+
return [...header, '', baseInstructions + formattedSkills].join('\n');
|
|
149
|
+
case PromptDisplay.Skills: {
|
|
150
|
+
// Layout: header -> separator -> skills with visual separators
|
|
151
|
+
const headerString = header.join('\n');
|
|
152
|
+
const skillsDisplay = formatSkillsForDisplay(formattedSkills);
|
|
153
|
+
return joinWithSeparators([headerString, skillsDisplay]);
|
|
154
|
+
}
|
|
155
|
+
case PromptDisplay.Summary: {
|
|
156
|
+
const headerString = header.join('\n');
|
|
157
|
+
const summary = definitions
|
|
158
|
+
? formatSkillsSummary(definitions)
|
|
159
|
+
: '(no skills)';
|
|
160
|
+
return joinWithSeparators([headerString, summary]);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
52
164
|
/**
|
|
53
165
|
* Create debug component for system prompts sent to the LLM
|
|
54
166
|
* Only creates at Verbose level
|
|
167
|
+
*
|
|
168
|
+
* @param toolName - Name of the tool being invoked
|
|
169
|
+
* @param command - User command being processed
|
|
170
|
+
* @param baseInstructions - Base tool instructions (without skills)
|
|
171
|
+
* @param formattedSkills - Formatted skills section (as sent to LLM)
|
|
172
|
+
* @param definitions - Parsed skill definitions for summary display
|
|
55
173
|
*/
|
|
56
|
-
export function logPrompt(toolName, command,
|
|
174
|
+
export function logPrompt(toolName, command, baseInstructions, formattedSkills, definitions = []) {
|
|
57
175
|
if (currentDebugLevel !== DebugLevel.Verbose) {
|
|
58
176
|
return null;
|
|
59
177
|
}
|
|
60
|
-
const content =
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
instructions,
|
|
66
|
-
].join('\n');
|
|
67
|
-
// Calculate stats for the instructions
|
|
68
|
-
const lines = instructions.split('\n').length;
|
|
69
|
-
const bytes = Buffer.byteLength(instructions, 'utf-8');
|
|
178
|
+
const content = formatPromptContent(toolName, command, baseInstructions, formattedSkills, PromptDisplay.Summary, definitions);
|
|
179
|
+
// Calculate stats for the full prompt
|
|
180
|
+
const fullPrompt = baseInstructions + formattedSkills;
|
|
181
|
+
const lines = fullPrompt.split('\n').length;
|
|
182
|
+
const bytes = Buffer.byteLength(fullPrompt, 'utf-8');
|
|
70
183
|
const title = `SYSTEM PROMPT (${String(lines)} lines, ${String(bytes)} bytes)`;
|
|
71
184
|
return createDebug({ title, content, color: Palette.Gray });
|
|
72
185
|
}
|
|
@@ -85,5 +198,5 @@ export function logResponse(toolName, response, durationMs) {
|
|
|
85
198
|
JSON.stringify(response, null, 2),
|
|
86
199
|
].join('\n');
|
|
87
200
|
const title = `LLM RESPONSE (${String(durationMs)} ms)`;
|
|
88
|
-
return createDebug({ title, content, color: Palette.
|
|
201
|
+
return createDebug({ title, content, color: Palette.LightGray });
|
|
89
202
|
}
|
|
@@ -162,3 +162,22 @@ export function getExecutionErrorMessage(_error) {
|
|
|
162
162
|
];
|
|
163
163
|
return messages[Math.floor(Math.random() * messages.length)];
|
|
164
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Returns a loading message while fetching an answer.
|
|
167
|
+
* Randomly selects from variations to sound natural.
|
|
168
|
+
*/
|
|
169
|
+
export function getAnswerLoadingMessage() {
|
|
170
|
+
const messages = [
|
|
171
|
+
'Finding that out for you.',
|
|
172
|
+
'Looking into this.',
|
|
173
|
+
'Let me find out.',
|
|
174
|
+
'One moment please.',
|
|
175
|
+
'Checking on that.',
|
|
176
|
+
'Let me look that up.',
|
|
177
|
+
'Give me a moment.',
|
|
178
|
+
'Looking that up now.',
|
|
179
|
+
'Let me check.',
|
|
180
|
+
'Just a moment.',
|
|
181
|
+
];
|
|
182
|
+
return messages[Math.floor(Math.random() * messages.length)];
|
|
183
|
+
}
|