@denizokcu/haze 0.0.1 → 0.0.3
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/CHANGELOG.md +24 -0
- package/README.md +169 -70
- package/dist/cli/commands/chat.d.ts +4 -1
- package/dist/cli/commands/chat.js +606 -24
- package/dist/cli/commands/commands.d.ts +5 -0
- package/dist/cli/commands/commands.js +220 -11
- package/dist/cli/commands/formatters.d.ts +1 -0
- package/dist/cli/commands/formatters.js +23 -3
- package/dist/cli/commands/skills.d.ts +1 -1
- package/dist/cli/commands/skills.js +8 -5
- package/dist/cli/commands/streaming.d.ts +7 -1
- package/dist/cli/commands/streaming.js +533 -41
- package/dist/cli/index.js +5 -12
- package/dist/config/inputHistory.js +8 -0
- package/dist/config/paths.d.ts +0 -1
- package/dist/config/paths.js +0 -1
- package/dist/config/providers.d.ts +26 -0
- package/dist/config/providers.js +88 -0
- package/dist/config/settings.d.ts +9 -2
- package/dist/core/agent/compaction.d.ts +13 -0
- package/dist/core/agent/compaction.js +34 -0
- package/dist/core/agent/errors.d.ts +3 -0
- package/dist/core/agent/errors.js +13 -0
- package/dist/core/agent/events.d.ts +58 -0
- package/dist/core/agent/events.js +3 -0
- package/dist/core/goal/completionPolicy.d.ts +27 -0
- package/dist/core/goal/completionPolicy.js +67 -0
- package/dist/core/goal/requestClassifier.d.ts +6 -0
- package/dist/core/goal/requestClassifier.js +31 -0
- package/dist/core/goal/sessionGoal.d.ts +30 -0
- package/dist/core/goal/sessionGoal.js +88 -0
- package/dist/core/session/sessionStore.d.ts +37 -0
- package/dist/core/session/sessionStore.js +59 -0
- package/dist/llm/client.d.ts +1 -1
- package/dist/llm/client.js +6 -6
- package/dist/llm/hazeTools.d.ts +70 -0
- package/dist/llm/hazeTools.js +311 -97
- package/dist/llm/initPrompt.js +7 -5
- package/dist/llm/systemPrompt.js +25 -11
- package/dist/skills/SkillLoader.d.ts +12 -2
- package/dist/skills/SkillLoader.js +64 -18
- package/dist/skills/SkillRegistry.d.ts +1 -5
- package/dist/skills/SkillRegistry.js +10 -21
- package/dist/skills/builder/SkillBuilder.d.ts +31 -1
- package/dist/skills/builder/SkillBuilder.js +291 -20
- package/dist/skills/skillTools.d.ts +20 -0
- package/dist/skills/skillTools.js +25 -0
- package/dist/skills/types.d.ts +12 -51
- package/dist/ui/components/ErrorView.d.ts +2 -1
- package/dist/ui/components/Header.d.ts +4 -2
- package/dist/ui/components/Header.js +2 -2
- package/dist/ui/components/MarkdownText.d.ts +2 -1
- package/dist/ui/components/TextInput.d.ts +13 -2
- package/dist/ui/components/TextInput.js +125 -25
- package/dist/ui/theme.d.ts +2 -0
- package/dist/ui/theme.js +3 -1
- package/dist/utils/fs.d.ts +1 -0
- package/dist/utils/fs.js +10 -6
- package/examples/skills/files/SKILL.md +16 -0
- package/examples/skills/files/examples/file-editing.md +3 -0
- package/package.json +9 -9
- package/dist/skills/installer/SkillInstaller.d.ts +0 -1
- package/dist/skills/installer/SkillInstaller.js +0 -48
- package/dist/skills/manifestSchema.d.ts +0 -31
- package/dist/skills/manifestSchema.js +0 -23
- package/dist/tools/ToolExecutor.d.ts +0 -3
- package/dist/tools/ToolExecutor.js +0 -15
- package/dist/tools/types.d.ts +0 -9
- package/dist/tools/types.js +0 -1
- package/examples/skills/files/prompts/file_tasks.md +0 -1
- package/examples/skills/files/skill.yaml +0 -28
- package/examples/skills/files/tools/list_files.ts +0 -21
- package/examples/skills/files/tools/read_file.ts +0 -12
|
@@ -5,8 +5,13 @@ export type CommandContext = {
|
|
|
5
5
|
settings: HazeSettings;
|
|
6
6
|
contextFiles: ContextFile[];
|
|
7
7
|
setMode: (mode: Mode) => void;
|
|
8
|
+
setModelProviderFilter?: (providerName: string | undefined) => void;
|
|
8
9
|
addSystemMessage: (text: string) => void;
|
|
9
10
|
clearConversation: () => void;
|
|
11
|
+
newSession?: () => Promise<void>;
|
|
12
|
+
resumeSession?: () => Promise<void>;
|
|
13
|
+
sessionInfo?: () => string;
|
|
14
|
+
compactConversation?: (instructions?: string) => boolean;
|
|
10
15
|
runAgentTurn: (prompt: string, displayValue?: string) => Promise<void>;
|
|
11
16
|
refreshContextFiles: () => Promise<ContextFile[]>;
|
|
12
17
|
updateSettings: (patch: Partial<HazeSettings>) => Promise<HazeSettings>;
|
|
@@ -1,10 +1,176 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'node:path';
|
|
1
3
|
import { buildInitPrompt } from '../../llm/initPrompt.js';
|
|
2
|
-
import {
|
|
4
|
+
import { activeProvider, configuredProviders, modelSelector, providerHasKey, resolveModelSelector, upsertProvider } from '../../config/providers.js';
|
|
5
|
+
function skillHelp() {
|
|
6
|
+
return [
|
|
7
|
+
'Skill commands:',
|
|
8
|
+
'/create-skill <description>',
|
|
9
|
+
' Create a Markdown skill in ~/.haze/skills.',
|
|
10
|
+
'/list-skills',
|
|
11
|
+
' List installed skills.',
|
|
12
|
+
'/skill-info <name>',
|
|
13
|
+
' Show a skill description and path.',
|
|
14
|
+
'/validate-skill <name-or-dir>',
|
|
15
|
+
' Validate a skill directory containing SKILL.md.',
|
|
16
|
+
'/remove-skill <name> --yes',
|
|
17
|
+
' Remove an installed skill. Requires --yes because it deletes files.',
|
|
18
|
+
].join('\n');
|
|
19
|
+
}
|
|
20
|
+
async function skillOverview() {
|
|
21
|
+
const { loadSkillRegistry } = await import('../../skills/SkillRegistry.js');
|
|
22
|
+
const registry = await loadSkillRegistry();
|
|
23
|
+
const skills = [...registry.skills.values()];
|
|
24
|
+
const installed = skills.length === 0
|
|
25
|
+
? ['Installed skills:', '- None yet. Create one with /create-skill <description>.']
|
|
26
|
+
: ['Installed skills:', ...skills.map(s => `- /${s.name} — ${s.description}`)];
|
|
27
|
+
return `${skillHelp()}\n\n${installed.join('\n')}`;
|
|
28
|
+
}
|
|
29
|
+
async function handleSkillCommand(value, ctx) {
|
|
30
|
+
const parts = value.trim().split(/\s+/).filter(Boolean);
|
|
31
|
+
const subcommand = parts[1];
|
|
32
|
+
if (!subcommand || subcommand === 'help') {
|
|
33
|
+
ctx.addSystemMessage(await skillOverview());
|
|
34
|
+
return 'handled';
|
|
35
|
+
}
|
|
36
|
+
if (subcommand === 'create') {
|
|
37
|
+
const description = parts.slice(2).join(' ');
|
|
38
|
+
if (!description) {
|
|
39
|
+
ctx.addSystemMessage('Usage: /create-skill <description>');
|
|
40
|
+
return 'handled';
|
|
41
|
+
}
|
|
42
|
+
const { createSkill } = await import('../../skills/builder/SkillBuilder.js');
|
|
43
|
+
const result = await createSkill(description);
|
|
44
|
+
ctx.addSystemMessage(`Created skill ${result.name} at ${result.file}. Invoke it with /${result.name}. Edit SKILL.md to refine its workflow.`);
|
|
45
|
+
return 'handled';
|
|
46
|
+
}
|
|
47
|
+
if (subcommand === 'list') {
|
|
48
|
+
const { loadSkillRegistry } = await import('../../skills/SkillRegistry.js');
|
|
49
|
+
const registry = await loadSkillRegistry();
|
|
50
|
+
const skills = [...registry.skills.values()];
|
|
51
|
+
ctx.addSystemMessage(skills.length === 0
|
|
52
|
+
? 'No installed skills found. Create one with /create-skill <description>.'
|
|
53
|
+
: ['Installed skills:', ...skills.map(s => `- /${s.name} — ${s.description}`)].join('\n'));
|
|
54
|
+
return 'handled';
|
|
55
|
+
}
|
|
56
|
+
if (subcommand === 'info') {
|
|
57
|
+
const name = parts[2];
|
|
58
|
+
if (!name) {
|
|
59
|
+
ctx.addSystemMessage('Usage: /skill-info <name>');
|
|
60
|
+
return 'handled';
|
|
61
|
+
}
|
|
62
|
+
const { loadSkillRegistry } = await import('../../skills/SkillRegistry.js');
|
|
63
|
+
const registry = await loadSkillRegistry();
|
|
64
|
+
const skill = registry.skills.get(name);
|
|
65
|
+
if (!skill) {
|
|
66
|
+
ctx.addSystemMessage(`No skill named ${name}`);
|
|
67
|
+
return 'handled';
|
|
68
|
+
}
|
|
69
|
+
ctx.addSystemMessage([
|
|
70
|
+
`${skill.name}`,
|
|
71
|
+
skill.description,
|
|
72
|
+
'',
|
|
73
|
+
`References: ${skill.references.length}`,
|
|
74
|
+
`Path: ${skill.dir}`,
|
|
75
|
+
].join('\n'));
|
|
76
|
+
return 'handled';
|
|
77
|
+
}
|
|
78
|
+
if (subcommand === 'validate') {
|
|
79
|
+
const target = parts[2];
|
|
80
|
+
if (!target) {
|
|
81
|
+
ctx.addSystemMessage('Usage: /validate-skill <name-or-dir>');
|
|
82
|
+
return 'handled';
|
|
83
|
+
}
|
|
84
|
+
const { GLOBAL_SKILLS_DIR } = await import('../../config/paths.js');
|
|
85
|
+
const { loadSkill } = await import('../../skills/SkillLoader.js');
|
|
86
|
+
const direct = path.resolve(target);
|
|
87
|
+
const dir = await fs.pathExists(path.join(direct, 'SKILL.md')) ? direct : path.join(GLOBAL_SKILLS_DIR, target);
|
|
88
|
+
const skill = await loadSkill(dir, 'global');
|
|
89
|
+
ctx.addSystemMessage(skill ? `Valid: ${skill.name}` : 'No SKILL.md found');
|
|
90
|
+
return 'handled';
|
|
91
|
+
}
|
|
92
|
+
if (subcommand === 'remove') {
|
|
93
|
+
const name = parts[2];
|
|
94
|
+
if (!name || !parts.includes('--yes')) {
|
|
95
|
+
ctx.addSystemMessage('Usage: /remove-skill <name> --yes');
|
|
96
|
+
return 'handled';
|
|
97
|
+
}
|
|
98
|
+
const { loadSkillRegistry } = await import('../../skills/SkillRegistry.js');
|
|
99
|
+
const registry = await loadSkillRegistry();
|
|
100
|
+
const skill = registry.skills.get(name);
|
|
101
|
+
if (!skill) {
|
|
102
|
+
ctx.addSystemMessage(`No skill named ${name}`);
|
|
103
|
+
return 'handled';
|
|
104
|
+
}
|
|
105
|
+
await fs.remove(skill.dir);
|
|
106
|
+
ctx.addSystemMessage(`Removed ${name} from ${skill.dir}.`);
|
|
107
|
+
return 'handled';
|
|
108
|
+
}
|
|
109
|
+
ctx.addSystemMessage(`Unknown skill command: ${parts[0]} ${subcommand}\n\n${skillHelp()}`);
|
|
110
|
+
return 'handled';
|
|
111
|
+
}
|
|
3
112
|
export async function handleSlashCommand(value, ctx) {
|
|
4
113
|
if (value === '/exit' || value === '/quit')
|
|
5
114
|
return 'exit';
|
|
6
115
|
if (value === '/help') {
|
|
7
|
-
ctx.addSystemMessage(
|
|
116
|
+
ctx.addSystemMessage([
|
|
117
|
+
'Commands:',
|
|
118
|
+
'/help',
|
|
119
|
+
' Show all available slash commands and what they do.',
|
|
120
|
+
'/provider',
|
|
121
|
+
' Choose a provider, then use it or add models; choose add provider at the bottom to create one.',
|
|
122
|
+
'/model',
|
|
123
|
+
' Choose a model from all configured providers.',
|
|
124
|
+
'/model <name-or-provider:name>',
|
|
125
|
+
' Set a model directly. Selecting a model also sets its provider.',
|
|
126
|
+
'/settings',
|
|
127
|
+
' Show the configured provider, model, API key status, and loaded context files.',
|
|
128
|
+
'/create-skill <description>',
|
|
129
|
+
' Create a reusable Markdown workflow from how you work.',
|
|
130
|
+
'/skills',
|
|
131
|
+
' Show Markdown skill commands and installed skill slash commands.',
|
|
132
|
+
'/init',
|
|
133
|
+
' Inspect the current workspace and create or update AGENTS.md project instructions.',
|
|
134
|
+
'/session',
|
|
135
|
+
' Show the current durable session file.',
|
|
136
|
+
'/resume',
|
|
137
|
+
' Resume the latest saved session for this workspace.',
|
|
138
|
+
'/new',
|
|
139
|
+
' Start a fresh durable session.',
|
|
140
|
+
'/compact [instructions]',
|
|
141
|
+
' Summarize older model context and keep recent messages.',
|
|
142
|
+
'/clear',
|
|
143
|
+
' Clear the current chat conversation history.',
|
|
144
|
+
'/exit',
|
|
145
|
+
' Exit Haze.',
|
|
146
|
+
'/quit',
|
|
147
|
+
' Exit Haze.',
|
|
148
|
+
].join('\n'));
|
|
149
|
+
return 'handled';
|
|
150
|
+
}
|
|
151
|
+
if (value === '/session') {
|
|
152
|
+
ctx.addSystemMessage(ctx.sessionInfo?.() ?? 'Session persistence is unavailable.');
|
|
153
|
+
return 'handled';
|
|
154
|
+
}
|
|
155
|
+
if (value === '/resume') {
|
|
156
|
+
if (ctx.resumeSession)
|
|
157
|
+
await ctx.resumeSession();
|
|
158
|
+
else
|
|
159
|
+
ctx.addSystemMessage('Session persistence is unavailable.');
|
|
160
|
+
return 'handled';
|
|
161
|
+
}
|
|
162
|
+
if (value === '/new') {
|
|
163
|
+
if (ctx.newSession)
|
|
164
|
+
await ctx.newSession();
|
|
165
|
+
else
|
|
166
|
+
ctx.addSystemMessage('Session persistence is unavailable.');
|
|
167
|
+
return 'handled';
|
|
168
|
+
}
|
|
169
|
+
if (value === '/compact' || value.startsWith('/compact ')) {
|
|
170
|
+
if (ctx.compactConversation)
|
|
171
|
+
ctx.compactConversation(value.slice('/compact'.length).trim() || undefined);
|
|
172
|
+
else
|
|
173
|
+
ctx.addSystemMessage('Compaction is unavailable.');
|
|
8
174
|
return 'handled';
|
|
9
175
|
}
|
|
10
176
|
if (value === '/clear') {
|
|
@@ -13,24 +179,51 @@ export async function handleSlashCommand(value, ctx) {
|
|
|
13
179
|
return 'handled';
|
|
14
180
|
}
|
|
15
181
|
if (value === '/settings') {
|
|
16
|
-
|
|
182
|
+
const providers = configuredProviders(ctx.settings);
|
|
183
|
+
const activeProvider = providers.find(provider => provider.name === ctx.settings.provider) ?? providers[0];
|
|
184
|
+
ctx.addSystemMessage([
|
|
185
|
+
`Provider: ${activeProvider?.name ?? 'not configured'}`,
|
|
186
|
+
`Model: ${ctx.settings.model ?? 'not set'}`,
|
|
187
|
+
`Base URL: ${activeProvider?.url ?? ctx.settings.baseURL ?? 'not configured'}`,
|
|
188
|
+
`API key: ${activeProvider && providerHasKey(ctx.settings, activeProvider) ? 'saved' : 'missing'}`,
|
|
189
|
+
`Configured providers: ${providers.map(provider => provider.name).join(', ') || 'none'}`,
|
|
190
|
+
`Context files: ${ctx.contextFiles.length ? ctx.contextFiles.map(file => file.path).join(', ') : 'none'}`,
|
|
191
|
+
].join(' | '));
|
|
17
192
|
return 'handled';
|
|
18
193
|
}
|
|
19
|
-
if (value === '/
|
|
20
|
-
ctx.
|
|
21
|
-
ctx.
|
|
194
|
+
if (value === '/provider') {
|
|
195
|
+
ctx.setModelProviderFilter?.(undefined);
|
|
196
|
+
ctx.setMode('provider');
|
|
197
|
+
ctx.addSystemMessage('Choose a provider. Selecting one opens provider actions. Choose “add provider” at the bottom to add a new provider.');
|
|
22
198
|
return 'handled';
|
|
23
199
|
}
|
|
24
200
|
if (value === '/model') {
|
|
201
|
+
ctx.setModelProviderFilter?.(undefined);
|
|
25
202
|
ctx.setMode('model');
|
|
26
|
-
ctx.addSystemMessage('
|
|
203
|
+
ctx.addSystemMessage('Choose a model. Selecting a model also sets its provider.');
|
|
204
|
+
return 'handled';
|
|
205
|
+
}
|
|
206
|
+
if (value === '/model list') {
|
|
207
|
+
const providers = configuredProviders(ctx.settings);
|
|
208
|
+
ctx.addSystemMessage(['Configured models:', ...providers.flatMap(provider => provider.models.map(model => `- ${modelSelector(provider, model)} — ${provider.name}`))].join('\n'));
|
|
27
209
|
return 'handled';
|
|
28
210
|
}
|
|
29
211
|
if (value.startsWith('/model ')) {
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
212
|
+
const selector = value.slice('/model '.length).trim();
|
|
213
|
+
const resolved = resolveModelSelector(ctx.settings, selector);
|
|
214
|
+
if (resolved.status === 'ambiguous') {
|
|
215
|
+
ctx.addSystemMessage(`Model ${resolved.model} exists on multiple providers: ${resolved.providers.map(provider => modelSelector(provider, resolved.model)).join(', ')}`);
|
|
216
|
+
return 'handled';
|
|
217
|
+
}
|
|
218
|
+
if (resolved.status === 'missing') {
|
|
219
|
+
const provider = activeProvider(ctx.settings);
|
|
220
|
+
const nextProvider = provider.models.includes(selector) ? provider : { ...provider, models: [...provider.models, selector] };
|
|
221
|
+
await ctx.updateSettings({ provider: provider.name, model: selector, providers: upsertProvider(ctx.settings, nextProvider) });
|
|
222
|
+
ctx.addSystemMessage(`Model set to ${selector} on ${provider.name}. Saved to ~/.haze/settings.json.`);
|
|
223
|
+
return 'handled';
|
|
224
|
+
}
|
|
225
|
+
await ctx.updateSettings({ provider: resolved.provider.name, model: resolved.model });
|
|
226
|
+
ctx.addSystemMessage(`Model set to ${resolved.model} on ${resolved.provider.name}. Saved to ~/.haze/settings.json.`);
|
|
34
227
|
return 'handled';
|
|
35
228
|
}
|
|
36
229
|
if (value === '/init') {
|
|
@@ -38,6 +231,22 @@ export async function handleSlashCommand(value, ctx) {
|
|
|
38
231
|
await ctx.refreshContextFiles();
|
|
39
232
|
return 'handled';
|
|
40
233
|
}
|
|
234
|
+
if (value === '/skills')
|
|
235
|
+
return await handleSkillCommand('/skill help', ctx);
|
|
236
|
+
if (value === '/list-skills')
|
|
237
|
+
return await handleSkillCommand('/skill list', ctx);
|
|
238
|
+
if (value === '/create-skill' || value.startsWith('/create-skill '))
|
|
239
|
+
return await handleSkillCommand(`/skill create${value.slice('/create-skill'.length)}`, ctx);
|
|
240
|
+
if (value === '/skill-info' || value.startsWith('/skill-info '))
|
|
241
|
+
return await handleSkillCommand(`/skill info${value.slice('/skill-info'.length)}`, ctx);
|
|
242
|
+
if (value === '/validate-skill' || value.startsWith('/validate-skill '))
|
|
243
|
+
return await handleSkillCommand(`/skill validate${value.slice('/validate-skill'.length)}`, ctx);
|
|
244
|
+
if (value === '/remove-skill' || value.startsWith('/remove-skill '))
|
|
245
|
+
return await handleSkillCommand(`/skill remove${value.slice('/remove-skill'.length)}`, ctx);
|
|
246
|
+
if (value === '/skill' || value.startsWith('/skill ') || value.startsWith('/skills ')) {
|
|
247
|
+
const normalized = value.replace(/^\/skills\b/, '/skill');
|
|
248
|
+
return await handleSkillCommand(normalized, ctx);
|
|
249
|
+
}
|
|
41
250
|
if (value.startsWith('/')) {
|
|
42
251
|
ctx.addSystemMessage(`Unknown command: ${value}. Bold start.`);
|
|
43
252
|
return 'handled';
|
|
@@ -17,7 +17,7 @@ export function toolCallSummary(toolName, input) {
|
|
|
17
17
|
const data = input;
|
|
18
18
|
if (toolName === 'bash' && typeof data?.command === 'string') {
|
|
19
19
|
const timeout = typeof data.timeoutSeconds === 'number' ? ` (timeout ${data.timeoutSeconds}s)` : '';
|
|
20
|
-
return
|
|
20
|
+
return `bash $ ${data.command}${timeout}`;
|
|
21
21
|
}
|
|
22
22
|
if (toolName === 'listFiles' && typeof data?.path === 'string')
|
|
23
23
|
return `listFiles ${data.path}`;
|
|
@@ -35,12 +35,32 @@ export function toolResultSummary(event) {
|
|
|
35
35
|
if (!event.success)
|
|
36
36
|
return `failed: ${compact(event.error)}`;
|
|
37
37
|
const output = event.output;
|
|
38
|
+
if (output?.duplicateSkipped === true)
|
|
39
|
+
return 'skipped duplicate';
|
|
38
40
|
if (typeof output?.code === 'number')
|
|
39
41
|
return `exited with code ${output.code}`;
|
|
40
|
-
if (typeof output?.ok === 'boolean')
|
|
41
|
-
|
|
42
|
+
if (typeof output?.ok === 'boolean') {
|
|
43
|
+
if (output.ok)
|
|
44
|
+
return 'completed';
|
|
45
|
+
return typeof output.error === 'string' ? `failed: ${compact(output.error)}` : 'failed';
|
|
46
|
+
}
|
|
42
47
|
return 'completed';
|
|
43
48
|
}
|
|
44
49
|
export function formatSeconds(milliseconds) {
|
|
45
50
|
return `${(milliseconds / 1000).toFixed(1)}s`;
|
|
46
51
|
}
|
|
52
|
+
export function toolOutputDetails(value) {
|
|
53
|
+
if (!value || typeof value !== 'object')
|
|
54
|
+
return '';
|
|
55
|
+
const output = value;
|
|
56
|
+
const stdout = output.stdout?.text?.trim();
|
|
57
|
+
const stderr = output.stderr?.text?.trim();
|
|
58
|
+
const parts = [
|
|
59
|
+
stdout ? `stdout:\n${compact(stdout, 1200)}` : '',
|
|
60
|
+
stderr ? `stderr:\n${compact(stderr, 1200)}` : '',
|
|
61
|
+
].filter(Boolean);
|
|
62
|
+
if (parts.length === 0)
|
|
63
|
+
return '';
|
|
64
|
+
const truncated = output.stdout?.truncated || output.stderr?.truncated;
|
|
65
|
+
return `${parts.join('\n\n')}${truncated ? '\n… output truncated' : ''}`;
|
|
66
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export declare function listSkills(): Promise<void>;
|
|
2
2
|
export declare function infoSkill(name: string): Promise<void>;
|
|
3
3
|
export declare function removeSkill(name: string): Promise<void>;
|
|
4
|
-
export declare function validateSkill(
|
|
4
|
+
export declare function validateSkill(target: string): Promise<void>;
|
|
@@ -3,19 +3,20 @@ import { render, Box, Text } from 'ink';
|
|
|
3
3
|
import fs from 'fs-extra';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { confirm } from '@inquirer/prompts';
|
|
6
|
+
import { GLOBAL_SKILLS_DIR } from '../../config/paths.js';
|
|
6
7
|
import { loadSkillRegistry } from '../../skills/SkillRegistry.js';
|
|
7
8
|
import { Header } from '../../ui/components/Header.js';
|
|
8
9
|
import { theme } from '../../ui/theme.js';
|
|
9
10
|
export async function listSkills() {
|
|
10
11
|
const registry = await loadSkillRegistry();
|
|
11
|
-
render(_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, { subtitle: "Installed skills" }), [...registry.skills.values()].map(s => _jsxs(Text, { children: [_jsx(Text, { color: theme.purple, children: s.
|
|
12
|
+
render(_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, { subtitle: "Installed skills" }), [...registry.skills.values()].map(s => _jsxs(Text, { children: [_jsx(Text, { color: theme.purple, children: s.name }), " \u2014 ", s.description] }, s.name))] }));
|
|
12
13
|
}
|
|
13
14
|
export async function infoSkill(name) {
|
|
14
15
|
const registry = await loadSkillRegistry();
|
|
15
16
|
const skill = registry.skills.get(name);
|
|
16
17
|
if (!skill)
|
|
17
18
|
throw new Error(`No skill named ${name}`);
|
|
18
|
-
render(_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, { subtitle: `Skill: ${name}` }), _jsx(Text, { children: skill.
|
|
19
|
+
render(_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, { subtitle: `Skill: ${name}` }), _jsx(Text, { children: skill.description }), _jsx(Text, { color: theme.violet, children: "References" }), skill.references.map(r => _jsxs(Text, { children: [" ", r.path] }, r.path)), _jsx(Text, { color: theme.violet, children: "Path" }), _jsx(Text, { children: skill.dir })] }));
|
|
19
20
|
}
|
|
20
21
|
export async function removeSkill(name) {
|
|
21
22
|
const registry = await loadSkillRegistry();
|
|
@@ -28,8 +29,10 @@ export async function removeSkill(name) {
|
|
|
28
29
|
await fs.remove(skill.dir);
|
|
29
30
|
console.log(`Removed ${name}. A rare case of subtraction as progress.`);
|
|
30
31
|
}
|
|
31
|
-
export async function validateSkill(
|
|
32
|
+
export async function validateSkill(target) {
|
|
32
33
|
const { loadSkill } = await import('../../skills/SkillLoader.js');
|
|
33
|
-
const
|
|
34
|
-
|
|
34
|
+
const direct = path.resolve(target);
|
|
35
|
+
const dir = await fs.pathExists(path.join(direct, 'SKILL.md')) ? direct : path.join(GLOBAL_SKILLS_DIR, target);
|
|
36
|
+
const skill = await loadSkill(dir, 'global');
|
|
37
|
+
console.log(skill ? `Valid: ${skill.name}` : 'No SKILL.md found');
|
|
35
38
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { type ModelMessage } from 'ai';
|
|
2
2
|
import type { ContextFile } from '../../config/contextFiles.js';
|
|
3
|
+
import { type AgentEventSink } from '../../core/agent/events.js';
|
|
3
4
|
export type Message = {
|
|
4
5
|
id?: string;
|
|
5
6
|
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
6
7
|
text: string;
|
|
7
8
|
streaming?: boolean;
|
|
9
|
+
hidden?: boolean;
|
|
8
10
|
};
|
|
9
11
|
export interface StreamCallbacks {
|
|
10
12
|
addMessage: (msg: Message) => void;
|
|
@@ -15,5 +17,9 @@ export interface StreamCallbacks {
|
|
|
15
17
|
getConversation: () => ModelMessage[];
|
|
16
18
|
getLastAssistantText: () => string;
|
|
17
19
|
setLastAssistantText: (text: string) => void;
|
|
20
|
+
setAbortController?: (controller: AbortController | null) => void;
|
|
21
|
+
setGoalStatus?: (status: string | undefined) => void;
|
|
22
|
+
onEvent?: AgentEventSink;
|
|
23
|
+
compactConversation?: (instructions?: string) => boolean;
|
|
18
24
|
}
|
|
19
|
-
export declare function runAgentTurn(value: string, displayValue: string | undefined, contextFiles: ContextFile[], callbacks: StreamCallbacks): Promise<void>;
|
|
25
|
+
export declare function runAgentTurn(value: string, displayValue: string | undefined, contextFiles: ContextFile[], callbacks: StreamCallbacks, retryAttempt?: number, retryingExistingRequest?: boolean, contextOverflowRecovered?: boolean): Promise<void>;
|