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.
Files changed (61) hide show
  1. package/.env.example +4 -0
  2. package/README.md +198 -124
  3. package/bin/kernel.js +208 -4
  4. package/config.example.yaml +14 -1
  5. package/package.json +1 -1
  6. package/src/agent.js +839 -209
  7. package/src/automation/automation-manager.js +377 -0
  8. package/src/automation/automation.js +79 -0
  9. package/src/automation/index.js +2 -0
  10. package/src/automation/scheduler.js +141 -0
  11. package/src/bot.js +1001 -18
  12. package/src/claude-auth.js +93 -0
  13. package/src/coder.js +48 -6
  14. package/src/conversation.js +33 -0
  15. package/src/intents/detector.js +50 -0
  16. package/src/intents/index.js +2 -0
  17. package/src/intents/planner.js +58 -0
  18. package/src/persona.js +68 -0
  19. package/src/prompts/orchestrator.js +124 -0
  20. package/src/prompts/persona.md +21 -0
  21. package/src/prompts/system.js +59 -6
  22. package/src/prompts/workers.js +148 -0
  23. package/src/providers/anthropic.js +23 -16
  24. package/src/providers/base.js +76 -2
  25. package/src/providers/index.js +1 -0
  26. package/src/providers/models.js +2 -1
  27. package/src/providers/openai-compat.js +5 -3
  28. package/src/security/audit.js +0 -0
  29. package/src/security/auth.js +0 -0
  30. package/src/security/confirm.js +7 -2
  31. package/src/self.js +122 -0
  32. package/src/services/stt.js +139 -0
  33. package/src/services/tts.js +124 -0
  34. package/src/skills/catalog.js +506 -0
  35. package/src/skills/custom.js +128 -0
  36. package/src/swarm/job-manager.js +216 -0
  37. package/src/swarm/job.js +85 -0
  38. package/src/swarm/worker-registry.js +79 -0
  39. package/src/tools/browser.js +458 -335
  40. package/src/tools/categories.js +3 -3
  41. package/src/tools/coding.js +5 -0
  42. package/src/tools/docker.js +0 -0
  43. package/src/tools/git.js +0 -0
  44. package/src/tools/github.js +0 -0
  45. package/src/tools/index.js +3 -0
  46. package/src/tools/jira.js +0 -0
  47. package/src/tools/monitor.js +0 -0
  48. package/src/tools/network.js +0 -0
  49. package/src/tools/orchestrator-tools.js +428 -0
  50. package/src/tools/os.js +14 -1
  51. package/src/tools/persona.js +32 -0
  52. package/src/tools/process.js +0 -0
  53. package/src/utils/config.js +153 -15
  54. package/src/utils/display.js +0 -0
  55. package/src/utils/logger.js +0 -0
  56. package/src/worker.js +396 -0
  57. package/.agents/skills/interface-design/SKILL.md +0 -391
  58. package/.agents/skills/interface-design/references/critique.md +0 -67
  59. package/.agents/skills/interface-design/references/example.md +0 -86
  60. package/.agents/skills/interface-design/references/principles.md +0 -235
  61. 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.')} Exit`);
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(`${providerLabel} API`, async () => {
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 agent = new Agent({ config, conversationManager });
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:
@@ -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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kernelbot",
3
- "version": "1.0.26",
3
+ "version": "1.0.30",
4
4
  "description": "KernelBot — AI engineering agent with full OS control",
5
5
  "type": "module",
6
6
  "author": "Abdullah Al-Taheri <abdullah@altaheri.me>",