kernelbot 1.0.30 → 1.0.32

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 (63) hide show
  1. package/.env.example +0 -0
  2. package/README.md +0 -0
  3. package/bin/kernel.js +56 -2
  4. package/config.example.yaml +31 -0
  5. package/package.json +1 -1
  6. package/src/agent.js +150 -20
  7. package/src/automation/automation-manager.js +0 -0
  8. package/src/automation/automation.js +0 -0
  9. package/src/automation/index.js +0 -0
  10. package/src/automation/scheduler.js +0 -0
  11. package/src/bot.js +303 -4
  12. package/src/claude-auth.js +0 -0
  13. package/src/coder.js +0 -0
  14. package/src/conversation.js +0 -0
  15. package/src/intents/detector.js +0 -0
  16. package/src/intents/index.js +0 -0
  17. package/src/intents/planner.js +0 -0
  18. package/src/life/codebase.js +388 -0
  19. package/src/life/engine.js +1317 -0
  20. package/src/life/evolution.js +244 -0
  21. package/src/life/improvements.js +81 -0
  22. package/src/life/journal.js +109 -0
  23. package/src/life/memory.js +283 -0
  24. package/src/life/share-queue.js +136 -0
  25. package/src/persona.js +0 -0
  26. package/src/prompts/orchestrator.js +19 -1
  27. package/src/prompts/persona.md +0 -0
  28. package/src/prompts/system.js +0 -0
  29. package/src/prompts/workers.js +10 -9
  30. package/src/providers/anthropic.js +0 -0
  31. package/src/providers/base.js +0 -0
  32. package/src/providers/index.js +0 -0
  33. package/src/providers/models.js +8 -1
  34. package/src/providers/openai-compat.js +0 -0
  35. package/src/security/audit.js +0 -0
  36. package/src/security/auth.js +0 -0
  37. package/src/security/confirm.js +0 -0
  38. package/src/self.js +0 -0
  39. package/src/services/stt.js +0 -0
  40. package/src/services/tts.js +0 -0
  41. package/src/skills/catalog.js +0 -0
  42. package/src/skills/custom.js +0 -0
  43. package/src/swarm/job-manager.js +0 -0
  44. package/src/swarm/job.js +0 -0
  45. package/src/swarm/worker-registry.js +0 -0
  46. package/src/tools/browser.js +0 -0
  47. package/src/tools/categories.js +0 -0
  48. package/src/tools/coding.js +1 -1
  49. package/src/tools/docker.js +0 -0
  50. package/src/tools/git.js +0 -0
  51. package/src/tools/github.js +0 -0
  52. package/src/tools/index.js +0 -0
  53. package/src/tools/jira.js +0 -0
  54. package/src/tools/monitor.js +0 -0
  55. package/src/tools/network.js +0 -0
  56. package/src/tools/orchestrator-tools.js +18 -3
  57. package/src/tools/os.js +0 -0
  58. package/src/tools/persona.js +0 -0
  59. package/src/tools/process.js +0 -0
  60. package/src/utils/config.js +0 -0
  61. package/src/utils/display.js +0 -0
  62. package/src/utils/logger.js +0 -0
  63. package/src/worker.js +10 -8
package/src/bot.js CHANGED
@@ -53,7 +53,8 @@ class ChatQueue {
53
53
  }
54
54
  }
55
55
 
56
- export function startBot(config, agent, conversationManager, jobManager, automationManager) {
56
+ export function startBot(config, agent, conversationManager, jobManager, automationManager, lifeDeps = {}) {
57
+ const { lifeEngine, memoryManager, journalManager, shareQueue, evolutionTracker, codebaseKnowledge } = lifeDeps;
57
58
  const logger = getLogger();
58
59
  const bot = new TelegramBot(config.telegram.bot_token, { polling: true });
59
60
  const chatQueue = new ChatQueue();
@@ -87,6 +88,10 @@ export function startBot(config, agent, conversationManager, jobManager, automat
87
88
  { command: 'jobs', description: 'List running and recent jobs' },
88
89
  { command: 'cancel', description: 'Cancel running job(s)' },
89
90
  { command: 'auto', description: 'Manage recurring automations' },
91
+ { command: 'life', description: 'Inner life engine status and control' },
92
+ { command: 'journal', description: 'View today\'s journal or a past date' },
93
+ { command: 'memories', description: 'View recent memories or search' },
94
+ { command: 'evolution', description: 'Self-evolution status, history, and lessons' },
90
95
  { command: 'context', description: 'Show all models, auth, and context info' },
91
96
  { command: 'clean', description: 'Clear conversation and start fresh' },
92
97
  { command: 'history', description: 'Show message count in memory' },
@@ -125,7 +130,7 @@ export function startBot(config, agent, conversationManager, jobManager, automat
125
130
  });
126
131
  return edited.message_id;
127
132
  } catch {
128
- return opts.editMessageId;
133
+ // Edit failed — fall through to send new message
129
134
  }
130
135
  }
131
136
  }
@@ -1100,6 +1105,296 @@ export function startBot(config, agent, conversationManager, jobManager, automat
1100
1105
  return;
1101
1106
  }
1102
1107
 
1108
+ // ── /life command ──────────────────────────────────────────────
1109
+ if (text === '/life' || text.startsWith('/life ')) {
1110
+ logger.info(`[Bot] /life command from ${username} (${userId}) in chat ${chatId}`);
1111
+ const args = text.slice('/life'.length).trim();
1112
+
1113
+ if (!lifeEngine) {
1114
+ await bot.sendMessage(chatId, 'Life engine is not available.');
1115
+ return;
1116
+ }
1117
+
1118
+ if (args === 'pause') {
1119
+ lifeEngine.pause();
1120
+ await bot.sendMessage(chatId, '⏸️ Inner life paused. Use `/life resume` to restart.', { parse_mode: 'Markdown' });
1121
+ return;
1122
+ }
1123
+ if (args === 'resume') {
1124
+ lifeEngine.resume();
1125
+ await bot.sendMessage(chatId, '▶️ Inner life resumed!');
1126
+ return;
1127
+ }
1128
+ if (args.startsWith('trigger')) {
1129
+ const activityType = args.split(/\s+/)[1] || null;
1130
+ const validTypes = ['think', 'browse', 'journal', 'create', 'self_code', 'code_review', 'reflect'];
1131
+ if (activityType && !validTypes.includes(activityType)) {
1132
+ await bot.sendMessage(chatId, `Unknown activity type. Available: ${validTypes.join(', ')}`);
1133
+ return;
1134
+ }
1135
+ await bot.sendMessage(chatId, `⚡ Triggering ${activityType || 'random'} activity...`);
1136
+ lifeEngine.triggerNow(activityType).catch(err => {
1137
+ logger.error(`[Bot] Life trigger failed: ${err.message}`);
1138
+ });
1139
+ return;
1140
+ }
1141
+ if (args === 'review') {
1142
+ if (evolutionTracker) {
1143
+ const active = evolutionTracker.getActiveProposal();
1144
+ const openPRs = evolutionTracker.getPRsToCheck();
1145
+ const lines = ['*Evolution Status*', ''];
1146
+ if (active) {
1147
+ lines.push(`Active: \`${active.id}\` — ${active.status}`);
1148
+ lines.push(` ${(active.triggerContext || '').slice(0, 150)}`);
1149
+ } else {
1150
+ lines.push('_No active proposals._');
1151
+ }
1152
+ if (openPRs.length > 0) {
1153
+ lines.push('', '*Open PRs:*');
1154
+ for (const p of openPRs) {
1155
+ lines.push(` • PR #${p.prNumber}: ${p.prUrl || 'no URL'}`);
1156
+ }
1157
+ }
1158
+ lines.push('', '_Use `/evolution` for full evolution status._');
1159
+ await bot.sendMessage(chatId, lines.join('\n'), { parse_mode: 'Markdown' });
1160
+ } else {
1161
+ await bot.sendMessage(chatId, 'Evolution system not available. Use `/evolution` for details.', { parse_mode: 'Markdown' });
1162
+ }
1163
+ return;
1164
+ }
1165
+
1166
+ // Default: show status
1167
+ const status = lifeEngine.getStatus();
1168
+ const lines = [
1169
+ '🌱 *Inner Life*',
1170
+ '',
1171
+ `*Status:* ${status.paused ? '⏸️ Paused' : status.status === 'active' ? '🟢 Active' : '⚪ Idle'}`,
1172
+ `*Total activities:* ${status.totalActivities}`,
1173
+ `*Last activity:* ${status.lastActivity || 'none'} (${status.lastActivityAgo})`,
1174
+ `*Last wake-up:* ${status.lastWakeUpAgo}`,
1175
+ '',
1176
+ '*Activity counts:*',
1177
+ ` 💭 Think: ${status.activityCounts.think || 0}`,
1178
+ ` 🌐 Browse: ${status.activityCounts.browse || 0}`,
1179
+ ` 📓 Journal: ${status.activityCounts.journal || 0}`,
1180
+ ` 🎨 Create: ${status.activityCounts.create || 0}`,
1181
+ ` 🔧 Self-code: ${status.activityCounts.self_code || 0}`,
1182
+ ` 🔍 Code review: ${status.activityCounts.code_review || 0}`,
1183
+ ` 🪞 Reflect: ${status.activityCounts.reflect || 0}`,
1184
+ '',
1185
+ '_Commands:_',
1186
+ '`/life pause` — Pause activities',
1187
+ '`/life resume` — Resume activities',
1188
+ '`/life trigger [think|browse|journal|create|self_code|code_review|reflect]` — Trigger now',
1189
+ ];
1190
+ await bot.sendMessage(chatId, lines.join('\n'), { parse_mode: 'Markdown' });
1191
+ return;
1192
+ }
1193
+
1194
+ // ── /journal command ─────────────────────────────────────────
1195
+ if (text === '/journal' || text.startsWith('/journal ')) {
1196
+ logger.info(`[Bot] /journal command from ${username} (${userId}) in chat ${chatId}`);
1197
+
1198
+ if (!journalManager) {
1199
+ await bot.sendMessage(chatId, 'Journal system is not available.');
1200
+ return;
1201
+ }
1202
+
1203
+ const args = text.slice('/journal'.length).trim();
1204
+
1205
+ if (args && /^\d{4}-\d{2}-\d{2}$/.test(args)) {
1206
+ const entry = journalManager.getEntry(args);
1207
+ if (!entry) {
1208
+ await bot.sendMessage(chatId, `No journal entry for ${args}.`);
1209
+ return;
1210
+ }
1211
+ const chunks = splitMessage(entry);
1212
+ for (const chunk of chunks) {
1213
+ try { await bot.sendMessage(chatId, chunk, { parse_mode: 'Markdown' }); }
1214
+ catch { await bot.sendMessage(chatId, chunk); }
1215
+ }
1216
+ return;
1217
+ }
1218
+
1219
+ if (args === 'list') {
1220
+ const dates = journalManager.list(15);
1221
+ if (dates.length === 0) {
1222
+ await bot.sendMessage(chatId, 'No journal entries yet.');
1223
+ return;
1224
+ }
1225
+ const lines = ['📓 *Journal Entries*', '', ...dates.map(d => ` • \`${d}\``)];
1226
+ lines.push('', '_Use `/journal YYYY-MM-DD` to read an entry._');
1227
+ await bot.sendMessage(chatId, lines.join('\n'), { parse_mode: 'Markdown' });
1228
+ return;
1229
+ }
1230
+
1231
+ // Default: show today's journal
1232
+ const today = journalManager.getToday();
1233
+ if (!today) {
1234
+ await bot.sendMessage(chatId, '📓 No journal entries today yet.\n\n_Use `/journal list` to see past entries._', { parse_mode: 'Markdown' });
1235
+ return;
1236
+ }
1237
+ const chunks = splitMessage(today);
1238
+ for (const chunk of chunks) {
1239
+ try { await bot.sendMessage(chatId, chunk, { parse_mode: 'Markdown' }); }
1240
+ catch { await bot.sendMessage(chatId, chunk); }
1241
+ }
1242
+ return;
1243
+ }
1244
+
1245
+ // ── /memories command ────────────────────────────────────────
1246
+ if (text === '/memories' || text.startsWith('/memories ')) {
1247
+ logger.info(`[Bot] /memories command from ${username} (${userId}) in chat ${chatId}`);
1248
+
1249
+ if (!memoryManager) {
1250
+ await bot.sendMessage(chatId, 'Memory system is not available.');
1251
+ return;
1252
+ }
1253
+
1254
+ const args = text.slice('/memories'.length).trim();
1255
+
1256
+ if (args.startsWith('about ')) {
1257
+ const query = args.slice('about '.length).trim();
1258
+ const results = memoryManager.searchEpisodic(query, 10);
1259
+ if (results.length === 0) {
1260
+ await bot.sendMessage(chatId, `No memories matching "${query}".`);
1261
+ return;
1262
+ }
1263
+ const lines = [`🧠 *Memories about "${query}"*`, ''];
1264
+ for (const m of results) {
1265
+ const date = new Date(m.timestamp).toLocaleDateString();
1266
+ lines.push(`• ${m.summary} _(${date}, importance: ${m.importance})_`);
1267
+ }
1268
+ await bot.sendMessage(chatId, lines.join('\n'), { parse_mode: 'Markdown' });
1269
+ return;
1270
+ }
1271
+
1272
+ // Default: show last 10 memories
1273
+ const recent = memoryManager.getRecentEpisodic(168, 10); // last 7 days
1274
+ if (recent.length === 0) {
1275
+ await bot.sendMessage(chatId, '🧠 No memories yet.');
1276
+ return;
1277
+ }
1278
+ const lines = ['🧠 *Recent Memories*', ''];
1279
+ for (const m of recent) {
1280
+ const ago = Math.round((Date.now() - m.timestamp) / 60000);
1281
+ const timeLabel = ago < 60 ? `${ago}m ago` : ago < 1440 ? `${Math.round(ago / 60)}h ago` : `${Math.round(ago / 1440)}d ago`;
1282
+ const icon = { interaction: '💬', discovery: '🔍', thought: '💭', creation: '🎨' }[m.type] || '•';
1283
+ lines.push(`${icon} ${m.summary} _(${timeLabel})_`);
1284
+ }
1285
+ lines.push('', '_Use `/memories about <topic>` to search._');
1286
+ await bot.sendMessage(chatId, lines.join('\n'), { parse_mode: 'Markdown' });
1287
+ return;
1288
+ }
1289
+
1290
+ // ── /evolution command ──────────────────────────────────────────
1291
+ if (text === '/evolution' || text.startsWith('/evolution ')) {
1292
+ logger.info(`[Bot] /evolution command from ${username} (${userId}) in chat ${chatId}`);
1293
+ const args = text.slice('/evolution'.length).trim();
1294
+
1295
+ if (!evolutionTracker) {
1296
+ await bot.sendMessage(chatId, 'Evolution system is not available.');
1297
+ return;
1298
+ }
1299
+
1300
+ if (args === 'history') {
1301
+ const proposals = evolutionTracker.getRecentProposals(10);
1302
+ if (proposals.length === 0) {
1303
+ await bot.sendMessage(chatId, 'No evolution proposals yet.');
1304
+ return;
1305
+ }
1306
+ const lines = ['*Evolution History*', ''];
1307
+ for (const p of proposals.reverse()) {
1308
+ const statusIcon = { research: '🔬', planned: '📋', coding: '💻', pr_open: '🔄', merged: '✅', rejected: '❌', failed: '💥' }[p.status] || '•';
1309
+ const age = Math.round((Date.now() - p.createdAt) / 3600_000);
1310
+ const ageLabel = age < 24 ? `${age}h ago` : `${Math.round(age / 24)}d ago`;
1311
+ lines.push(`${statusIcon} \`${p.id}\` — ${p.status} (${ageLabel})`);
1312
+ lines.push(` ${(p.triggerContext || '').slice(0, 100)}`);
1313
+ if (p.prUrl) lines.push(` PR: ${p.prUrl}`);
1314
+ lines.push('');
1315
+ }
1316
+ await bot.sendMessage(chatId, lines.join('\n'), { parse_mode: 'Markdown' });
1317
+ return;
1318
+ }
1319
+
1320
+ if (args === 'lessons') {
1321
+ const lessons = evolutionTracker.getRecentLessons(15);
1322
+ if (lessons.length === 0) {
1323
+ await bot.sendMessage(chatId, 'No evolution lessons learned yet.');
1324
+ return;
1325
+ }
1326
+ const lines = ['*Evolution Lessons*', ''];
1327
+ for (const l of lessons.reverse()) {
1328
+ lines.push(`• [${l.category}] ${l.lesson}`);
1329
+ if (l.fromProposal) lines.push(` _from ${l.fromProposal}_`);
1330
+ lines.push('');
1331
+ }
1332
+ await bot.sendMessage(chatId, lines.join('\n'), { parse_mode: 'Markdown' });
1333
+ return;
1334
+ }
1335
+
1336
+ if (args === 'trigger') {
1337
+ if (!lifeEngine) {
1338
+ await bot.sendMessage(chatId, 'Life engine is not available.');
1339
+ return;
1340
+ }
1341
+ await bot.sendMessage(chatId, '⚡ Triggering evolution cycle...');
1342
+ lifeEngine.triggerNow('self_code').catch(err => {
1343
+ logger.error(`[Bot] Evolution trigger failed: ${err.message}`);
1344
+ });
1345
+ return;
1346
+ }
1347
+
1348
+ if (args === 'scan') {
1349
+ if (!codebaseKnowledge) {
1350
+ await bot.sendMessage(chatId, 'Codebase knowledge is not available.');
1351
+ return;
1352
+ }
1353
+ await bot.sendMessage(chatId, '🔍 Scanning codebase...');
1354
+ codebaseKnowledge.scanChanged().then(count => {
1355
+ bot.sendMessage(chatId, `✅ Scanned ${count} changed files.`).catch(() => {});
1356
+ }).catch(err => {
1357
+ bot.sendMessage(chatId, `Failed: ${err.message}`).catch(() => {});
1358
+ });
1359
+ return;
1360
+ }
1361
+
1362
+ // Default: show status
1363
+ const active = evolutionTracker.getActiveProposal();
1364
+ const stats = evolutionTracker.getStats();
1365
+ const openPRs = evolutionTracker.getPRsToCheck();
1366
+
1367
+ const lines = [
1368
+ '🧬 *Self-Evolution*',
1369
+ '',
1370
+ `*Stats:* ${stats.totalProposals} total | ${stats.merged} merged | ${stats.rejected} rejected | ${stats.failed} failed`,
1371
+ `*Success rate:* ${stats.successRate}%`,
1372
+ `*Open PRs:* ${openPRs.length}`,
1373
+ ];
1374
+
1375
+ if (active) {
1376
+ const statusIcon = { research: '🔬', planned: '📋', coding: '💻', pr_open: '🔄' }[active.status] || '•';
1377
+ lines.push('');
1378
+ lines.push(`*Active proposal:* ${statusIcon} \`${active.id}\` — ${active.status}`);
1379
+ lines.push(` ${(active.triggerContext || '').slice(0, 120)}`);
1380
+ if (active.prUrl) lines.push(` PR: ${active.prUrl}`);
1381
+ } else {
1382
+ lines.push('', '_No active proposal_');
1383
+ }
1384
+
1385
+ lines.push(
1386
+ '',
1387
+ '_Commands:_',
1388
+ '`/evolution history` — Recent proposals',
1389
+ '`/evolution lessons` — Learned lessons',
1390
+ '`/evolution trigger` — Trigger evolution now',
1391
+ '`/evolution scan` — Scan codebase',
1392
+ );
1393
+
1394
+ await bot.sendMessage(chatId, lines.join('\n'), { parse_mode: 'Markdown' });
1395
+ return;
1396
+ }
1397
+
1103
1398
  if (text === '/help') {
1104
1399
  const activeSkill = agent.getActiveSkill(chatId);
1105
1400
  const skillLine = activeSkill
@@ -1117,6 +1412,10 @@ export function startBot(config, agent, conversationManager, jobManager, automat
1117
1412
  '/jobs — List running and recent jobs',
1118
1413
  '/cancel — Cancel running job(s)',
1119
1414
  '/auto — Manage recurring automations',
1415
+ '/life — Inner life engine status & control',
1416
+ '/journal — View today\'s journal or a past date',
1417
+ '/memories — View recent memories or search',
1418
+ '/evolution — Self-evolution status, history, lessons',
1120
1419
  '/context — Show all models, auth, and context info',
1121
1420
  '/clean — Clear conversation and start fresh',
1122
1421
  '/history — Show message count in memory',
@@ -1293,12 +1592,12 @@ export function startBot(config, agent, conversationManager, jobManager, automat
1293
1592
  });
1294
1593
  return edited.message_id;
1295
1594
  } catch {
1296
- return opts.editMessageId;
1595
+ // Edit failed — fall through to send new message
1297
1596
  }
1298
1597
  }
1299
1598
  }
1300
1599
 
1301
- // Send new message(s)
1600
+ // Send new message(s) — also reached when edit fails
1302
1601
  const parts = splitMessage(update);
1303
1602
  let lastMsgId = null;
1304
1603
  for (const part of parts) {
File without changes
package/src/coder.js CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes