kernelbot 1.0.26 → 1.0.30
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/.env.example +4 -0
- package/README.md +198 -124
- package/bin/kernel.js +208 -4
- package/config.example.yaml +14 -1
- package/package.json +1 -1
- package/src/agent.js +839 -209
- package/src/automation/automation-manager.js +377 -0
- package/src/automation/automation.js +79 -0
- package/src/automation/index.js +2 -0
- package/src/automation/scheduler.js +141 -0
- package/src/bot.js +1001 -18
- package/src/claude-auth.js +93 -0
- package/src/coder.js +48 -6
- package/src/conversation.js +33 -0
- package/src/intents/detector.js +50 -0
- package/src/intents/index.js +2 -0
- package/src/intents/planner.js +58 -0
- package/src/persona.js +68 -0
- package/src/prompts/orchestrator.js +124 -0
- package/src/prompts/persona.md +21 -0
- package/src/prompts/system.js +59 -6
- package/src/prompts/workers.js +148 -0
- package/src/providers/anthropic.js +23 -16
- package/src/providers/base.js +76 -2
- package/src/providers/index.js +1 -0
- package/src/providers/models.js +2 -1
- package/src/providers/openai-compat.js +5 -3
- package/src/security/audit.js +0 -0
- package/src/security/auth.js +0 -0
- package/src/security/confirm.js +7 -2
- package/src/self.js +122 -0
- package/src/services/stt.js +139 -0
- package/src/services/tts.js +124 -0
- package/src/skills/catalog.js +506 -0
- package/src/skills/custom.js +128 -0
- package/src/swarm/job-manager.js +216 -0
- package/src/swarm/job.js +85 -0
- package/src/swarm/worker-registry.js +79 -0
- package/src/tools/browser.js +458 -335
- package/src/tools/categories.js +3 -3
- package/src/tools/coding.js +5 -0
- package/src/tools/docker.js +0 -0
- package/src/tools/git.js +0 -0
- package/src/tools/github.js +0 -0
- package/src/tools/index.js +3 -0
- package/src/tools/jira.js +0 -0
- package/src/tools/monitor.js +0 -0
- package/src/tools/network.js +0 -0
- package/src/tools/orchestrator-tools.js +428 -0
- package/src/tools/os.js +14 -1
- package/src/tools/persona.js +32 -0
- package/src/tools/process.js +0 -0
- package/src/utils/config.js +153 -15
- package/src/utils/display.js +0 -0
- package/src/utils/logger.js +0 -0
- package/src/worker.js +396 -0
- package/.agents/skills/interface-design/SKILL.md +0 -391
- package/.agents/skills/interface-design/references/critique.md +0 -67
- package/.agents/skills/interface-design/references/example.md +0 -86
- package/.agents/skills/interface-design/references/principles.md +0 -235
- package/.agents/skills/interface-design/references/validation.md +0 -48
package/bin/kernel.js
CHANGED
|
@@ -19,9 +19,19 @@ import {
|
|
|
19
19
|
} from '../src/utils/display.js';
|
|
20
20
|
import { createAuditLogger } from '../src/security/audit.js';
|
|
21
21
|
import { ConversationManager } from '../src/conversation.js';
|
|
22
|
+
import { UserPersonaManager } from '../src/persona.js';
|
|
23
|
+
import { SelfManager } from '../src/self.js';
|
|
22
24
|
import { Agent } from '../src/agent.js';
|
|
25
|
+
import { JobManager } from '../src/swarm/job-manager.js';
|
|
23
26
|
import { startBot } from '../src/bot.js';
|
|
27
|
+
import { AutomationManager } from '../src/automation/index.js';
|
|
24
28
|
import { createProvider, PROVIDERS } from '../src/providers/index.js';
|
|
29
|
+
import {
|
|
30
|
+
loadCustomSkills,
|
|
31
|
+
getCustomSkills,
|
|
32
|
+
addCustomSkill,
|
|
33
|
+
deleteCustomSkill,
|
|
34
|
+
} from '../src/skills/custom.js';
|
|
25
35
|
|
|
26
36
|
function showMenu(config) {
|
|
27
37
|
const providerDef = PROVIDERS[config.brain.provider];
|
|
@@ -37,7 +47,9 @@ function showMenu(config) {
|
|
|
37
47
|
console.log(` ${chalk.cyan('3.')} View logs`);
|
|
38
48
|
console.log(` ${chalk.cyan('4.')} View audit logs`);
|
|
39
49
|
console.log(` ${chalk.cyan('5.')} Change brain model`);
|
|
40
|
-
console.log(` ${chalk.cyan('6.')}
|
|
50
|
+
console.log(` ${chalk.cyan('6.')} Manage custom skills`);
|
|
51
|
+
console.log(` ${chalk.cyan('7.')} Manage automations`);
|
|
52
|
+
console.log(` ${chalk.cyan('8.')} Exit`);
|
|
41
53
|
console.log('');
|
|
42
54
|
}
|
|
43
55
|
|
|
@@ -114,8 +126,32 @@ async function startBotFlow(config) {
|
|
|
114
126
|
|
|
115
127
|
const checks = [];
|
|
116
128
|
|
|
129
|
+
// Orchestrator check — dynamic provider
|
|
130
|
+
const orchProviderKey = config.orchestrator.provider || 'anthropic';
|
|
131
|
+
const orchProviderDef = PROVIDERS[orchProviderKey];
|
|
132
|
+
const orchLabel = orchProviderDef ? orchProviderDef.name : orchProviderKey;
|
|
133
|
+
checks.push(
|
|
134
|
+
await showStartupCheck(`Orchestrator (${orchLabel}) API`, async () => {
|
|
135
|
+
const orchestratorKey = config.orchestrator.api_key
|
|
136
|
+
|| (orchProviderDef && process.env[orchProviderDef.envKey])
|
|
137
|
+
|| process.env.ANTHROPIC_API_KEY;
|
|
138
|
+
if (!orchestratorKey) throw new Error(`${orchProviderDef?.envKey || 'ANTHROPIC_API_KEY'} is required for the orchestrator`);
|
|
139
|
+
const provider = createProvider({
|
|
140
|
+
brain: {
|
|
141
|
+
provider: orchProviderKey,
|
|
142
|
+
model: config.orchestrator.model,
|
|
143
|
+
max_tokens: config.orchestrator.max_tokens,
|
|
144
|
+
temperature: config.orchestrator.temperature,
|
|
145
|
+
api_key: orchestratorKey,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
await provider.ping();
|
|
149
|
+
}),
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Worker brain check
|
|
117
153
|
checks.push(
|
|
118
|
-
await showStartupCheck(
|
|
154
|
+
await showStartupCheck(`Worker (${providerLabel}) API`, async () => {
|
|
119
155
|
const provider = createProvider(config);
|
|
120
156
|
await provider.ping();
|
|
121
157
|
}),
|
|
@@ -137,13 +173,175 @@ async function startBotFlow(config) {
|
|
|
137
173
|
}
|
|
138
174
|
|
|
139
175
|
const conversationManager = new ConversationManager(config);
|
|
140
|
-
const
|
|
176
|
+
const personaManager = new UserPersonaManager();
|
|
177
|
+
const selfManager = new SelfManager();
|
|
178
|
+
const jobManager = new JobManager({
|
|
179
|
+
jobTimeoutSeconds: config.swarm.job_timeout_seconds,
|
|
180
|
+
cleanupIntervalMinutes: config.swarm.cleanup_interval_minutes,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const automationManager = new AutomationManager();
|
|
184
|
+
|
|
185
|
+
const agent = new Agent({ config, conversationManager, personaManager, selfManager, jobManager, automationManager });
|
|
186
|
+
|
|
187
|
+
startBot(config, agent, conversationManager, jobManager, automationManager);
|
|
188
|
+
|
|
189
|
+
// Periodic job cleanup and timeout enforcement
|
|
190
|
+
const cleanupMs = (config.swarm.cleanup_interval_minutes || 30) * 60 * 1000;
|
|
191
|
+
setInterval(() => {
|
|
192
|
+
jobManager.cleanup();
|
|
193
|
+
jobManager.enforceTimeouts();
|
|
194
|
+
}, Math.min(cleanupMs, 60_000)); // enforce timeouts every minute at most
|
|
141
195
|
|
|
142
|
-
startBot(config, agent, conversationManager);
|
|
143
196
|
showStartupComplete();
|
|
144
197
|
return true;
|
|
145
198
|
}
|
|
146
199
|
|
|
200
|
+
async function manageCustomSkills(rl) {
|
|
201
|
+
loadCustomSkills();
|
|
202
|
+
|
|
203
|
+
let managing = true;
|
|
204
|
+
while (managing) {
|
|
205
|
+
const customs = getCustomSkills();
|
|
206
|
+
console.log('');
|
|
207
|
+
console.log(chalk.bold(' Custom Skills\n'));
|
|
208
|
+
console.log(` ${chalk.cyan('1.')} Create new skill`);
|
|
209
|
+
console.log(` ${chalk.cyan('2.')} List skills (${customs.length})`);
|
|
210
|
+
console.log(` ${chalk.cyan('3.')} Delete a skill`);
|
|
211
|
+
console.log(` ${chalk.cyan('4.')} Back`);
|
|
212
|
+
console.log('');
|
|
213
|
+
|
|
214
|
+
const choice = await ask(rl, chalk.cyan(' > '));
|
|
215
|
+
switch (choice.trim()) {
|
|
216
|
+
case '1': {
|
|
217
|
+
const name = await ask(rl, chalk.cyan(' Skill name: '));
|
|
218
|
+
if (!name.trim()) {
|
|
219
|
+
console.log(chalk.dim(' Cancelled.\n'));
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
console.log(chalk.dim(' Enter the system prompt (multi-line). Type END on a blank line to finish:\n'));
|
|
223
|
+
const lines = [];
|
|
224
|
+
while (true) {
|
|
225
|
+
const line = await ask(rl, ' ');
|
|
226
|
+
if (line.trim() === 'END') break;
|
|
227
|
+
lines.push(line);
|
|
228
|
+
}
|
|
229
|
+
const prompt = lines.join('\n').trim();
|
|
230
|
+
if (!prompt) {
|
|
231
|
+
console.log(chalk.dim(' Empty prompt — cancelled.\n'));
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
const skill = addCustomSkill({ name: name.trim(), systemPrompt: prompt });
|
|
235
|
+
console.log(chalk.green(`\n ✅ Created: ${skill.name} (${skill.id})\n`));
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
case '2': {
|
|
239
|
+
const customs = getCustomSkills();
|
|
240
|
+
if (!customs.length) {
|
|
241
|
+
console.log(chalk.dim('\n No custom skills yet.\n'));
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
console.log('');
|
|
245
|
+
for (const s of customs) {
|
|
246
|
+
const preview = s.systemPrompt.slice(0, 60).replace(/\n/g, ' ');
|
|
247
|
+
console.log(` 🛠️ ${chalk.bold(s.name)} (${s.id})`);
|
|
248
|
+
console.log(chalk.dim(` ${preview}${s.systemPrompt.length > 60 ? '...' : ''}`));
|
|
249
|
+
}
|
|
250
|
+
console.log('');
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
case '3': {
|
|
254
|
+
const customs = getCustomSkills();
|
|
255
|
+
if (!customs.length) {
|
|
256
|
+
console.log(chalk.dim('\n No custom skills to delete.\n'));
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
console.log('');
|
|
260
|
+
customs.forEach((s, i) => {
|
|
261
|
+
console.log(` ${chalk.cyan(`${i + 1}.`)} ${s.name} (${s.id})`);
|
|
262
|
+
});
|
|
263
|
+
console.log('');
|
|
264
|
+
const pick = await ask(rl, chalk.cyan(' Delete #: '));
|
|
265
|
+
const idx = parseInt(pick, 10) - 1;
|
|
266
|
+
if (idx >= 0 && idx < customs.length) {
|
|
267
|
+
const deleted = deleteCustomSkill(customs[idx].id);
|
|
268
|
+
if (deleted) console.log(chalk.green(`\n 🗑️ Deleted: ${customs[idx].name}\n`));
|
|
269
|
+
else console.log(chalk.dim(' Not found.\n'));
|
|
270
|
+
} else {
|
|
271
|
+
console.log(chalk.dim(' Cancelled.\n'));
|
|
272
|
+
}
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
case '4':
|
|
276
|
+
managing = false;
|
|
277
|
+
break;
|
|
278
|
+
default:
|
|
279
|
+
console.log(chalk.dim(' Invalid choice.\n'));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async function manageAutomations(rl) {
|
|
285
|
+
const manager = new AutomationManager();
|
|
286
|
+
|
|
287
|
+
let managing = true;
|
|
288
|
+
while (managing) {
|
|
289
|
+
const autos = manager.listAll();
|
|
290
|
+
console.log('');
|
|
291
|
+
console.log(chalk.bold(' Automations\n'));
|
|
292
|
+
console.log(` ${chalk.cyan('1.')} List all automations (${autos.length})`);
|
|
293
|
+
console.log(` ${chalk.cyan('2.')} Delete an automation`);
|
|
294
|
+
console.log(` ${chalk.cyan('3.')} Back`);
|
|
295
|
+
console.log('');
|
|
296
|
+
|
|
297
|
+
const choice = await ask(rl, chalk.cyan(' > '));
|
|
298
|
+
switch (choice.trim()) {
|
|
299
|
+
case '1': {
|
|
300
|
+
if (!autos.length) {
|
|
301
|
+
console.log(chalk.dim('\n No automations found.\n'));
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
console.log('');
|
|
305
|
+
for (const a of autos) {
|
|
306
|
+
const status = a.enabled ? chalk.green('enabled') : chalk.yellow('paused');
|
|
307
|
+
const next = a.nextRun ? new Date(a.nextRun).toLocaleString() : 'not scheduled';
|
|
308
|
+
console.log(` ${chalk.bold(a.name)} (${a.id}) — chat ${a.chatId}`);
|
|
309
|
+
console.log(chalk.dim(` Status: ${status} | Runs: ${a.runCount} | Next: ${next}`));
|
|
310
|
+
console.log(chalk.dim(` Task: ${a.description.slice(0, 80)}${a.description.length > 80 ? '...' : ''}`));
|
|
311
|
+
}
|
|
312
|
+
console.log('');
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
case '2': {
|
|
316
|
+
if (!autos.length) {
|
|
317
|
+
console.log(chalk.dim('\n No automations to delete.\n'));
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
console.log('');
|
|
321
|
+
autos.forEach((a, i) => {
|
|
322
|
+
console.log(` ${chalk.cyan(`${i + 1}.`)} ${a.name} (${a.id}) — chat ${a.chatId}`);
|
|
323
|
+
});
|
|
324
|
+
console.log('');
|
|
325
|
+
const pick = await ask(rl, chalk.cyan(' Delete #: '));
|
|
326
|
+
const idx = parseInt(pick, 10) - 1;
|
|
327
|
+
if (idx >= 0 && idx < autos.length) {
|
|
328
|
+
const deleted = manager.delete(autos[idx].id);
|
|
329
|
+
if (deleted) console.log(chalk.green(`\n 🗑️ Deleted: ${autos[idx].name}\n`));
|
|
330
|
+
else console.log(chalk.dim(' Not found.\n'));
|
|
331
|
+
} else {
|
|
332
|
+
console.log(chalk.dim(' Cancelled.\n'));
|
|
333
|
+
}
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
case '3':
|
|
337
|
+
managing = false;
|
|
338
|
+
break;
|
|
339
|
+
default:
|
|
340
|
+
console.log(chalk.dim(' Invalid choice.\n'));
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
147
345
|
async function main() {
|
|
148
346
|
showLogo();
|
|
149
347
|
|
|
@@ -177,6 +375,12 @@ async function main() {
|
|
|
177
375
|
await changeBrainModel(config, rl);
|
|
178
376
|
break;
|
|
179
377
|
case '6':
|
|
378
|
+
await manageCustomSkills(rl);
|
|
379
|
+
break;
|
|
380
|
+
case '7':
|
|
381
|
+
await manageAutomations(rl);
|
|
382
|
+
break;
|
|
383
|
+
case '8':
|
|
180
384
|
running = false;
|
|
181
385
|
break;
|
|
182
386
|
default:
|
package/config.example.yaml
CHANGED
|
@@ -5,16 +5,22 @@ bot:
|
|
|
5
5
|
name: KernelBot
|
|
6
6
|
description: AI engineering agent with full OS control
|
|
7
7
|
|
|
8
|
+
orchestrator:
|
|
9
|
+
provider: anthropic # anthropic | openai | google | groq — switchable via /orchestrator
|
|
10
|
+
# model: claude-opus-4-6
|
|
11
|
+
|
|
8
12
|
brain:
|
|
9
|
-
provider: anthropic # anthropic | openai | google | groq
|
|
13
|
+
provider: anthropic # anthropic | openai | google | groq — switchable via /brain
|
|
10
14
|
model: claude-sonnet-4-20250514
|
|
11
15
|
max_tokens: 8192
|
|
12
16
|
temperature: 0.3
|
|
13
17
|
max_tool_depth: 25
|
|
14
18
|
|
|
15
19
|
claude_code:
|
|
20
|
+
# model: claude-opus-4-6 # switchable via /claudemodel
|
|
16
21
|
max_turns: 50
|
|
17
22
|
timeout_seconds: 600
|
|
23
|
+
# auth_mode: system # system | api_key | oauth_token — switchable via /claude
|
|
18
24
|
# workspace_dir: /tmp/kernelbot-workspaces # default: ~/.kernelbot/workspaces
|
|
19
25
|
|
|
20
26
|
github:
|
|
@@ -43,3 +49,10 @@ logging:
|
|
|
43
49
|
|
|
44
50
|
conversation:
|
|
45
51
|
max_history: 50
|
|
52
|
+
|
|
53
|
+
# Voice — ElevenLabs TTS & STT
|
|
54
|
+
# Requires ELEVENLABS_API_KEY in .env
|
|
55
|
+
voice:
|
|
56
|
+
tts_enabled: true # Send voice replies alongside text (default: true if API key present)
|
|
57
|
+
stt_enabled: true # Transcribe user voice messages (default: true if API key present)
|
|
58
|
+
# voice_id: JBFqnCBsd6RMkjVDRZzb # ElevenLabs voice ID (override ELEVENLABS_VOICE_ID env var)
|