kernelbot 1.0.38 → 1.0.39

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.
@@ -1,19 +1,34 @@
1
- import { readFileSync } from 'fs';
2
- import { join, dirname } from 'path';
3
- import { fileURLToPath } from 'url';
4
- import chalk from 'chalk';
5
- import ora from 'ora';
6
- import boxen from 'boxen';
7
- import gradient from 'gradient-string';
1
+ import { readFileSync } from "fs";
2
+ import { join, dirname } from "path";
3
+ import { fileURLToPath } from "url";
4
+ import { networkInterfaces } from "os";
5
+ import chalk from "chalk";
6
+ import ora from "ora";
7
+ import boxen from "boxen";
8
+ import gradient from "gradient-string";
9
+ import * as p from "@clack/prompts";
10
+ import { PROVIDERS } from "../providers/models.js";
11
+
12
+ export { p };
13
+
14
+ function getLocalIp() {
15
+ const nets = networkInterfaces();
16
+ for (const iface of Object.values(nets)) {
17
+ for (const info of iface) {
18
+ if (info.family === "IPv4" && !info.internal) return info.address;
19
+ }
20
+ }
21
+ return "localhost";
22
+ }
8
23
 
9
24
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
25
 
11
26
  function getVersion() {
12
27
  try {
13
- const pkg = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf-8'));
28
+ const pkg = JSON.parse(readFileSync(join(__dirname, "../../package.json"), "utf-8"));
14
29
  return pkg.version;
15
30
  } catch {
16
- return 'unknown';
31
+ return "unknown";
17
32
  }
18
33
  }
19
34
 
@@ -38,38 +53,14 @@ const LOGO = `
38
53
  `;
39
54
 
40
55
  // Green terminal gradient
41
- const monoGradient = gradient([
42
- '#00ff41',
43
- '#00cc33',
44
- '#009926',
45
- '#006619',
46
- ]);
56
+ const monoGradient = gradient(["#00ff41", "#00cc33", "#009926", "#006619"]);
47
57
 
48
58
  export function showLogo() {
49
59
  console.log(monoGradient.multiline(LOGO));
50
- console.log(chalk.dim(` AI Engineering Agent — v${getVersion()}\n`));
51
- console.log(
52
- boxen(
53
- chalk.yellow.bold('WARNING') +
54
- chalk.yellow(
55
- '\n\nKernelBot has full access to your operating system.\n' +
56
- 'It can execute commands, read/write files, manage processes,\n' +
57
- 'and interact with external services on your behalf.\n\n' +
58
- 'Only run this on machines you control.\n' +
59
- 'Set OWNER_TELEGRAM_ID in .env or allowed_users in config.yaml.',
60
- ),
61
- {
62
- padding: 1,
63
- borderStyle: 'round',
64
- borderColor: 'yellow',
65
- },
66
- ),
67
- );
68
- console.log('');
69
60
  }
70
61
 
71
62
  export async function showStartupCheck(label, checkFn) {
72
- const spinner = ora({ text: label, color: 'cyan' }).start();
63
+ const spinner = ora({ text: label, color: "cyan" }).start();
73
64
  try {
74
65
  await checkFn();
75
66
  spinner.succeed(chalk.green(label));
@@ -82,11 +73,11 @@ export async function showStartupCheck(label, checkFn) {
82
73
 
83
74
  export function showStartupComplete() {
84
75
  console.log(
85
- boxen(chalk.green.bold('KernelBot is live'), {
76
+ boxen(chalk.green.bold("KernelBot is live"), {
86
77
  padding: 1,
87
78
  margin: { top: 1 },
88
- borderStyle: 'round',
89
- borderColor: 'green',
79
+ borderStyle: "round",
80
+ borderColor: "green",
90
81
  }),
91
82
  );
92
83
  }
@@ -95,8 +86,8 @@ export function showSuccess(msg) {
95
86
  console.log(
96
87
  boxen(chalk.green(msg), {
97
88
  padding: 1,
98
- borderStyle: 'round',
99
- borderColor: 'green',
89
+ borderStyle: "round",
90
+ borderColor: "green",
100
91
  }),
101
92
  );
102
93
  }
@@ -105,14 +96,14 @@ export function showError(msg) {
105
96
  console.log(
106
97
  boxen(chalk.red(msg), {
107
98
  padding: 1,
108
- borderStyle: 'round',
109
- borderColor: 'red',
99
+ borderStyle: "round",
100
+ borderColor: "red",
110
101
  }),
111
102
  );
112
103
  }
113
104
 
114
105
  export function createSpinner(text) {
115
- return ora({ text, color: 'cyan' });
106
+ return ora({ text, color: "cyan" });
116
107
  }
117
108
 
118
109
  /**
@@ -121,47 +112,108 @@ export function createSpinner(text) {
121
112
  * @param {boolean} isActive — whether this is the currently active character
122
113
  */
123
114
  export function showCharacterCard(character, isActive = false) {
124
- const art = character.asciiArt || '';
125
- const activeTag = isActive ? chalk.green(' (active)') : '';
115
+ const art = character.asciiArt || "";
116
+ const activeTag = isActive ? chalk.green(" (active)") : "";
126
117
  const content = [
127
118
  `${character.emoji} ${chalk.bold(character.name)}${activeTag}`,
128
119
  chalk.dim(`"${character.tagline}"`),
129
- '',
130
- ...(art ? art.split('\n').map(line => chalk.cyan(line)) : []),
131
- '',
132
- chalk.dim(`Origin: ${character.origin || 'Unknown'}`),
133
- chalk.dim(`Style: ${character.age || 'Unknown'}`),
134
- ].join('\n');
120
+ "",
121
+ ...(art ? art.split("\n").map((line) => chalk.cyan(line)) : []),
122
+ "",
123
+ chalk.dim(`Origin: ${character.origin || "Unknown"}`),
124
+ chalk.dim(`Style: ${character.age || "Unknown"}`),
125
+ ].join("\n");
135
126
 
136
127
  console.log(
137
128
  boxen(content, {
138
129
  padding: 1,
139
- borderStyle: 'round',
140
- borderColor: isActive ? 'green' : 'cyan',
130
+ borderStyle: "round",
131
+ borderColor: isActive ? "green" : "cyan",
141
132
  }),
142
133
  );
143
134
  }
144
135
 
145
136
  /**
146
- * Display the full character gallery for CLI selection.
147
- * @param {object[]} charactersarray of character profiles
148
- * @param {string|null} activeId — ID of the currently active character
137
+ * Format "Provider / model" label for a config section.
138
+ * @param {object} configfull config
139
+ * @param {'brain'|'orchestrator'} section
140
+ */
141
+ export function formatProviderLabel(config, section) {
142
+ const sec = config[section];
143
+ const providerDef = PROVIDERS[sec.provider];
144
+ const name = providerDef ? providerDef.name : sec.provider;
145
+ return `${name} / ${sec.model}`;
146
+ }
147
+
148
+ /**
149
+ * Centralized cancel handler for @clack/prompts.
150
+ * Call after every prompt — exits gracefully on Ctrl+C.
151
+ */
152
+ export function handleCancel(value) {
153
+ if (p.isCancel(value)) {
154
+ p.cancel("Cancelled.");
155
+ return true;
156
+ }
157
+ return false;
158
+ }
159
+
160
+ /**
161
+ * Claude Code-inspired info box shown after the logo.
149
162
  */
163
+ export function showWelcomeScreen(config, characterManager) {
164
+ const version = getVersion();
165
+
166
+ const orchLabel = formatProviderLabel(config, "orchestrator");
167
+ const brainLabel = formatProviderLabel(config, "brain");
168
+
169
+ let charLabel = "None";
170
+ if (characterManager) {
171
+ const activeId = characterManager.getActiveCharacterId();
172
+ const active = characterManager.getCharacter(activeId);
173
+ if (active) charLabel = `${active.emoji} ${active.name}`;
174
+ }
175
+
176
+ const lifeEnabled = config.life?.enabled !== false;
177
+ const dashPort = config.dashboard?.port || 3000;
178
+ const dashEnabled = config.dashboard?.enabled;
179
+
180
+ const pad = (label, width = 18) => label.padEnd(width);
181
+
182
+ const lines = [
183
+ "",
184
+ ` ${chalk.dim(pad("Orchestrator"))}${orchLabel}`,
185
+ ` ${chalk.dim(pad("Brain"))}${brainLabel}`,
186
+ ` ${chalk.dim(pad("Character"))}${charLabel}`,
187
+ ` ${chalk.dim(pad("Life Engine"))}${lifeEnabled ? chalk.green("enabled") : chalk.yellow("disabled")}`,
188
+ ` ${chalk.dim(pad("Dashboard"))}${dashEnabled ? chalk.green(`http://${getLocalIp()}:${dashPort}/`) : chalk.yellow("off")}`,
189
+ "",
190
+ chalk.dim(" ↑↓ Navigate · Enter Select · Ctrl+C Cancel"),
191
+ ];
192
+
193
+ console.log(
194
+ boxen(lines.join("\n"), {
195
+ title: `KERNEL Bot v${version}`,
196
+ titleAlignment: "left",
197
+ padding: { top: 0, bottom: 0, left: 0, right: 2 },
198
+ borderStyle: "round",
199
+ borderColor: "green",
200
+ }),
201
+ );
202
+ }
203
+
150
204
  export function showCharacterGallery(characters, activeId = null) {
151
- console.log('');
205
+ console.log("");
152
206
  console.log(
153
- gradient(['#ff6b6b', '#feca57', '#48dbfb', '#ff9ff3']).multiline(
154
- ' ═══════════════════════════════\n' +
155
- ' CHOOSE YOUR CHARACTER\n' +
156
- ' ═══════════════════════════════',
207
+ gradient(["#ff6b6b", "#feca57", "#48dbfb", "#ff9ff3"]).multiline(
208
+ " ═══════════════════════════════\n" + " CHOOSE YOUR CHARACTER\n" + " ═══════════════════════════════",
157
209
  ),
158
210
  );
159
- console.log('');
160
- console.log(chalk.dim(' Each character has their own personality,'));
161
- console.log(chalk.dim(' memories, and story that evolves with you.'));
162
- console.log('');
211
+ console.log("");
212
+ console.log(chalk.dim(" Each character has their own personality,"));
213
+ console.log(chalk.dim(" memories, and story that evolves with you."));
214
+ console.log("");
163
215
 
164
216
  for (const c of characters) {
165
217
  showCharacterCard(c, c.id === activeId);
166
218
  }
167
- }
219
+ }