codebot-ai 2.0.2 → 2.1.1

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/dist/banner.d.ts CHANGED
@@ -2,18 +2,51 @@
2
2
  * CodeBot AI mascot and CLI banner.
3
3
  *
4
4
  * Mascot name: Codi
5
- * Three designs: Pixel Bot, Monitor Bot, Visor Helmet
5
+ * Three designs: Neural Core, Terminal Shield, Sentinel
6
+ * See BRANDING.md for full identity guide.
7
+ *
8
+ * Design philosophy: Enterprise-grade. Clean geometry.
9
+ * No crayon vibes — precision engineering.
6
10
  */
7
- export declare const MASCOT_1 = "\n \u2588\u2588\n \u2584\u2584\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584\u2584\n \u2588 \u2588\n \u2588 \u2584\u2588\u2588\u2584 \u2584\u2588\u2588\u2584 \u2588\n \u2588 \u2580\u2588\u2588\u2580 \u2580\u2588\u2588\u2580 \u2588\n \u2588 \u2588\n \u2588 \u2580\u2588\u2588\u2588\u2588\u2588\u2588\u2580 \u2588\n \u2580\u2580\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2580\u2580\n";
11
+ export type CodiMood = 'ready' | 'working' | 'success' | 'error' | 'thinking' | 'idle' | 'alert';
12
+ export declare const MASCOT_1 = "\n \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 \u250C\u2500\u2500\u2510 \u250C\u2500\u2500\u2510 \u2502\n \u2502 \u2502\u2593\u2593\u2502 \u2502\u2593\u2593\u2502 \u2502\n \u2502 \u2514\u2500\u2500\u2518 \u2514\u2500\u2500\u2518 \u2502\n \u2576\u2500\u2500\u2500\u2500\u2524 \u251C\u2500\u2500\u2500\u2500\u2574\n \u2502 \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F \u2502\n \u2502 \u2502\n \u2514\u2500\u2500\u252C\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u252C\u2500\u2500\u2518\n \u2502 \u2502 \u2502 \u2502\n";
8
13
  export declare const BANNER_1: (version: string, model: string, provider: string, session: string, autonomous: boolean) => string;
9
- export declare const MASCOT_2 = "\n \u2554\u2557 \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557 \u2554\u2557\n \u2551\u2551 \u2551 \u2551 \u2551\u2551\n \u2551\u2551 \u2551 \u25CF \u25CF \u2551 \u2551\u2551\n \u2551\u2551 \u2551 \u2551 \u2551\u2551\n \u2551\u2551 \u2551 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2551 \u2551\u2551\n \u2551\u2551 \u2551 \u2551 \u2551\u2551\n \u255A\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u255D\n";
14
+ export declare const MASCOT_2 = "\n \u250C\u2500\u2510 \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557 \u250C\u2500\u2510\n \u2502\u2591\u2502 \u2551 \u25C9 \u25C9 \u2551 \u2502\u2591\u2502\n \u2502\u2591\u2502 \u2551 \u2551 \u2502\u2591\u2502\n \u2502\u2591\u2502 \u2551 \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F \u2551 \u2502\u2591\u2502\n \u2502\u2591\u2502 \u2551 \u2551 \u2502\u2591\u2502\n \u2514\u2500\u2518 \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u2514\u2500\u2518\n \u25AA \u25AA \u25AA \u25AA \u25AA \u25AA \u25AA \u25AA\n";
10
15
  export declare const BANNER_2: (version: string, model: string, provider: string, session: string, autonomous: boolean) => string;
11
- export declare const MASCOT_3 = "\n \u2584\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584\n \u2588\u2580 \u2580\u2588\n \u2588 \u2591\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591 \u2588\n \u2588 \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 \u2588\n \u2588\u2584 \u2584\u2588\n \u2580\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2580\n";
16
+ export declare const MASCOT_3 = "\n \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n \u2554\u255D \u255A\u2557\n \u2551 \u2591\u2591\u2591\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591 \u2551\n \u2551 \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 \u2551\n \u255A\u2557 \u2554\u255D\n \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n \u2551 \u2551 \u2551 \u2551\n";
12
17
  export declare const BANNER_3: (version: string, model: string, provider: string, session: string, autonomous: boolean) => string;
13
18
  export declare const banner: (version: string, model: string, provider: string, session: string, autonomous: boolean) => string;
14
- export declare function randomGreeting(): string;
19
+ export declare const CODI_FACE: Record<CodiMood, string>;
20
+ /**
21
+ * Random startup greeting from Codi.
22
+ */
23
+ export declare function randomGreeting(mood?: string): string;
24
+ export interface CodiReaction {
25
+ face: string;
26
+ message: string;
27
+ }
28
+ /**
29
+ * Get a context-aware reaction from Codi.
30
+ * Returns a face expression + message pair.
31
+ */
32
+ export declare function codiReact(event: string): CodiReaction;
33
+ /**
34
+ * Format a Codi reaction as a styled CLI string.
35
+ */
36
+ export declare function formatReaction(event: string): string;
37
+ export declare function sessionSummaryBanner(stats: {
38
+ iterations: number;
39
+ toolCalls: number;
40
+ tokensUsed: number;
41
+ cost?: number;
42
+ duration?: number;
43
+ }): string;
15
44
  /**
16
45
  * Compact single-line startup for non-TTY / piped usage.
17
46
  */
18
47
  export declare function compactBanner(version: string, model: string): string;
48
+ /**
49
+ * Pick a random banner design (for variety on startup).
50
+ */
51
+ export declare function randomBanner(): typeof BANNER_1;
19
52
  //# sourceMappingURL=banner.d.ts.map
package/dist/banner.js CHANGED
@@ -3,12 +3,20 @@
3
3
  * CodeBot AI mascot and CLI banner.
4
4
  *
5
5
  * Mascot name: Codi
6
- * Three designs: Pixel Bot, Monitor Bot, Visor Helmet
6
+ * Three designs: Neural Core, Terminal Shield, Sentinel
7
+ * See BRANDING.md for full identity guide.
8
+ *
9
+ * Design philosophy: Enterprise-grade. Clean geometry.
10
+ * No crayon vibes — precision engineering.
7
11
  */
8
12
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.banner = exports.BANNER_3 = exports.MASCOT_3 = exports.BANNER_2 = exports.MASCOT_2 = exports.BANNER_1 = exports.MASCOT_1 = void 0;
13
+ exports.CODI_FACE = exports.banner = exports.BANNER_3 = exports.MASCOT_3 = exports.BANNER_2 = exports.MASCOT_2 = exports.BANNER_1 = exports.MASCOT_1 = void 0;
10
14
  exports.randomGreeting = randomGreeting;
15
+ exports.codiReact = codiReact;
16
+ exports.formatReaction = formatReaction;
17
+ exports.sessionSummaryBanner = sessionSummaryBanner;
11
18
  exports.compactBanner = compactBanner;
19
+ exports.randomBanner = randomBanner;
12
20
  const C = {
13
21
  reset: '\x1b[0m',
14
22
  bold: '\x1b[1m',
@@ -25,119 +33,286 @@ const C = {
25
33
  brightYellow: '\x1b[93m',
26
34
  brightMagenta: '\x1b[95m',
27
35
  brightWhite: '\x1b[97m',
36
+ brightRed: '\x1b[91m',
37
+ brightBlue: '\x1b[94m',
28
38
  };
29
- // ─────────────────────────────────────────────────────
30
- // DESIGN 1: "Pixel Bot" — Half-block pixel art robot head
31
- // Retro-modern pixel aesthetic. The signature look.
32
- // ─────────────────────────────────────────────────────
39
+ // ─────────────────────────────────────────────────────────────
40
+ // DESIGN 1: "Neural Core" — Precision-engineered AI processor
41
+ // Clean, symmetric, enterprise. The signature look.
42
+ // ─────────────────────────────────────────────────────────────
33
43
  exports.MASCOT_1 = `
34
- ██
35
- ▄▄████████████▄▄
36
- █ █
37
- █ ▄██▄ ▄██▄ █
38
- ▀██▀ ▀██▀ █
39
- █ █
40
- █ ▀██████▀ █
41
- ▀▀████████████▀▀
44
+ ┌─────────────────────┐
45
+ │ ┌──┐ ┌──┐ │
46
+ │ │▓▓│ │▓▓│ │
47
+ │ └──┘ └──┘ │
48
+ ╶────┤ ├────╴
49
+ │ ╰─────────╯ │
50
+ │ │
51
+ └──┬──┬───────┬──┬──┘
52
+ │ │ │ │
42
53
  `;
43
54
  const BANNER_1 = (version, model, provider, session, autonomous) => {
55
+ const a = C.cyan; // frame
56
+ const e = C.brightGreen; // eyes
57
+ const m = C.brightCyan; // mouth
58
+ const d = C.dim; // connectors
59
+ const r = C.reset;
44
60
  const lines = [
45
61
  '',
46
- `${C.brightGreen} ██${C.reset}`,
47
- `${C.cyan} ▄▄████████████▄▄${C.reset}`,
48
- `${C.cyan} █${C.reset} ${C.cyan}█${C.reset} ${C.bold}${C.brightCyan}CodeBot AI${C.reset} ${C.dim}v${version}${C.reset}`,
49
- `${C.cyan} ${C.brightGreen}▄██▄${C.reset} ${C.brightGreen}▄██▄${C.reset} ${C.cyan}█${C.reset} ${C.dim}Think local. Code global.${C.reset}`,
50
- `${C.cyan} ${C.brightGreen}▀██▀${C.reset} ${C.brightGreen}▀██▀${C.reset} ${C.cyan}█${C.reset}`,
51
- `${C.cyan} █${C.reset} ${C.cyan}█${C.reset} ${C.dim}Model: ${C.white}${model}${C.reset}`,
52
- `${C.cyan} █ ${C.brightCyan}▀██████▀${C.reset} ${C.cyan}█${C.reset} ${C.dim}Provider: ${C.white}${provider}${C.reset}`,
53
- `${C.cyan} ▀▀████████████▀▀${C.reset} ${C.dim}Session: ${C.white}${session}${C.reset}`,
54
- autonomous ? ` ${C.brightYellow}${C.bold}⚡ AUTONOMOUS${C.reset}` : '',
62
+ `${a} ┌─────────────────────┐${r}`,
63
+ `${a} │${r} ${e}┌──┐${r} ${e}┌──┐${r} ${a}│${r}`,
64
+ `${a} │${r} ${e}│▓▓│${r} ${e}│▓▓│${r} ${a}│${r} ${C.bold}${C.brightCyan}CodeBot AI${r} ${d}v${version}${r}`,
65
+ `${a} │${r} ${e}└──┘${r} ${e}└──┘${r} ${a}│${r} ${d}Think local. Code global.${r}`,
66
+ `${d} ╶────${a}┤${r} ${a}├${d}────╴${r}`,
67
+ `${a} │${r} ${m}╰─────────╯${r} ${a}│${r} ${d}Model: ${C.white}${model}${r}`,
68
+ `${a} │${r} ${a}│${r} ${d}Provider: ${C.white}${provider}${r}`,
69
+ `${a} └──┬──┬───────┬──┬──┘${r} ${d}Session: ${C.white}${session}${r}`,
70
+ `${d} │ │ │ │${r}` + (autonomous ? ` ${C.brightYellow}${C.bold}⚡ AUTONOMOUS${r}` : ''),
55
71
  '',
56
72
  ];
57
73
  return lines.join('\n');
58
74
  };
59
75
  exports.BANNER_1 = BANNER_1;
60
- // ─────────────────────────────────────────────────────
61
- // DESIGN 2: "Monitor Bot" — Screen face with side panels
62
- // Clean technical look. Like a friendly terminal display.
63
- // ─────────────────────────────────────────────────────
76
+ // ─────────────────────────────────────────────────────────────
77
+ // DESIGN 2: "Terminal Shield" — Secure terminal with status LEDs
78
+ // Enterprise security aesthetic. Trust indicator built in.
79
+ // ─────────────────────────────────────────────────────────────
64
80
  exports.MASCOT_2 = `
65
- ╔╗ ╔════════════════╗ ╔╗
66
- ║║ ║║
67
- ║║ ● ● ║║
68
- ║║ ║║
69
- ║║ └──────┘ ║║
70
- ║║ ║ ║ ║║
71
- ╚╝ ╚════════════════╝ ╚╝
81
+ ┌─┐ ╔═══════════════════╗ ┌─┐
82
+ │░│ ◉ ◉ │░│
83
+ │░│ │░│
84
+ │░│ ╰───────────╯ │░│
85
+ │░│ │░│
86
+ └─┘ ╚═══════════════════╝ └─┘
87
+ ▪ ▪ ▪ ▪ ▪ ▪
72
88
  `;
73
89
  const BANNER_2 = (version, model, provider, session, autonomous) => {
90
+ const f = C.cyan; // frame
91
+ const s = C.dim; // side panels
92
+ const e = C.brightGreen; // eyes
93
+ const m = C.brightCyan; // mouth
94
+ const r = C.reset;
95
+ const led = C.brightGreen;
74
96
  const lines = [
75
97
  '',
76
- `${C.dim} ╔╗${C.reset} ${C.cyan}╔════════════════╗${C.reset} ${C.dim}╔╗${C.reset}`,
77
- `${C.dim} ║║${C.reset} ${C.cyan}║${C.reset} ${C.cyan}║${C.reset} ${C.dim}║║${C.reset}`,
78
- `${C.dim} ║║${C.reset} ${C.cyan}║${C.reset} ${C.brightGreen}●${C.reset} ${C.brightGreen}●${C.reset} ${C.cyan}║${C.reset} ${C.dim}║║${C.reset} ${C.bold}${C.brightCyan}CodeBot AI${C.reset} ${C.dim}v${version}${C.reset}`,
79
- `${C.dim} ║║${C.reset} ${C.cyan}║${C.reset} ${C.cyan}║${C.reset} ${C.dim}║║${C.reset} ${C.dim}Think local. Code global.${C.reset}`,
80
- `${C.dim} ║║${C.reset} ${C.cyan}║${C.reset} ${C.brightCyan}└──────┘${C.reset} ${C.cyan}║${C.reset} ${C.dim}║║${C.reset}`,
81
- `${C.dim} ║║${C.reset} ${C.cyan}║${C.reset} ${C.cyan}║${C.reset} ${C.dim}║║${C.reset} ${C.dim}Model: ${C.white}${model}${C.reset}`,
82
- `${C.dim} ╚╝${C.reset} ${C.cyan}╚════════════════╝${C.reset} ${C.dim}╚╝${C.reset} ${C.dim}Provider: ${C.white}${provider}${C.reset}`,
83
- ` ${C.dim}Session: ${C.white}${session}${C.reset}`,
84
- autonomous ? ` ${C.brightYellow}${C.bold}⚡ AUTONOMOUS${C.reset}` : '',
98
+ `${s} ┌─┐${r} ${f}╔═══════════════════╗${r} ${s}┌─┐${r}`,
99
+ `${s} │░│${r} ${f}║${r} ${e}◉${r} ${e}◉${r} ${f}║${r} ${s}│░│${r} ${C.bold}${C.brightCyan}CodeBot AI${r} ${C.dim}v${version}${r}`,
100
+ `${s} │░│${r} ${f}║${r} ${f}║${r} ${s}│░│${r} ${C.dim}Think local. Code global.${r}`,
101
+ `${s} │░│${r} ${f}║${r} ${m}╰───────────╯${r} ${f}║${r} ${s}│░│${r}`,
102
+ `${s} │░│${r} ${f}║${r} ${f}║${r} ${s}│░│${r} ${C.dim}Model: ${C.white}${model}${r}`,
103
+ `${s} └─┘${r} ${f}╚═══════════════════╝${r} ${s}└─┘${r} ${C.dim}Provider: ${C.white}${provider}${r}`,
104
+ ` ${led} ▪ ▪ ▪ ▪ ▪ ▪ ▪${r} ${C.dim}Session: ${C.white}${session}${r}`,
105
+ autonomous ? ` ${C.brightYellow}${C.bold}⚡ AUTONOMOUS${r}` : '',
85
106
  '',
86
107
  ];
87
108
  return lines.join('\n');
88
109
  };
89
110
  exports.BANNER_2 = BANNER_2;
90
- // ─────────────────────────────────────────────────────
91
- // DESIGN 3: "Visor Helmet" — Daft Punk style with glowing visor
92
- // Sleek, aggressive, cyberpunk. Diamond silhouette.
93
- // ─────────────────────────────────────────────────────
111
+ // ─────────────────────────────────────────────────────────────
112
+ // DESIGN 3: "Sentinel" — Armored visor. Threat detection mode.
113
+ // Cybersecurity aesthetic. Used in autonomous/scanning contexts.
114
+ // ─────────────────────────────────────────────────────────────
94
115
  exports.MASCOT_3 = `
95
- ▄████████▄
96
- █▀ ▀█
97
- █ ░░██████░░ █
98
- █ ░░░░░░░░░░ █
99
- █▄ ▄█
100
- ▀████████▀
116
+ ╔═══════════╗
117
+ ╔╝ ╚╗
118
+ ║ ░░░█████░░░ ║
119
+ ║ ░░░░░░░░░░░ ║
120
+ ╚╗ ╔╝
121
+ ╚═══════════╝
122
+ ║ ║ ║ ║
101
123
  `;
102
124
  const BANNER_3 = (version, model, provider, session, autonomous) => {
125
+ const f = C.cyan; // frame
126
+ const v = C.brightCyan; // visor glow
127
+ const g = C.brightGreen; // visor core
128
+ const d = C.dim;
129
+ const r = C.reset;
103
130
  const lines = [
104
131
  '',
105
- `${C.cyan} ▄████████▄${C.reset}`,
106
- `${C.cyan} █▀${C.reset} ${C.cyan}▀█${C.reset} ${C.bold}${C.brightCyan}CodeBot AI${C.reset} ${C.dim}v${version}${C.reset}`,
107
- `${C.cyan}${C.brightCyan}░░${C.brightGreen}██████${C.brightCyan}░░${C.cyan} █${C.reset} ${C.dim}Think local. Code global.${C.reset}`,
108
- `${C.cyan}${C.dim}░░░░░░░░░░${C.cyan} █${C.reset}`,
109
- `${C.cyan} █▄${C.reset} ${C.cyan}▄█${C.reset} ${C.dim}Model: ${C.white}${model}${C.reset}`,
110
- `${C.cyan} ▀████████▀${C.reset} ${C.dim}Provider: ${C.white}${provider}${C.reset}`,
111
- ` ${C.dim}Session: ${C.white}${session}${C.reset}`,
112
- autonomous ? ` ${C.brightYellow}${C.bold}⚡ AUTONOMOUS${C.reset}` : '',
132
+ `${f} ╔═══════════╗${r}`,
133
+ `${f} ╔╝${r} ${f}╚╗${r} ${C.bold}${C.brightCyan}CodeBot AI${r} ${d}v${version}${r}`,
134
+ `${f} ║${r} ${v}░░░${g}█████${v}░░░${r} ${f}║${r} ${d}Think local. Code global.${r}`,
135
+ `${f} ║${r} ${d}░░░░░░░░░░░${r} ${f}║${r}`,
136
+ `${f} ╚╗${r} ${f}╔╝${r} ${d}Model: ${C.white}${model}${r}`,
137
+ `${f} ╚═══════════╝${r} ${d}Provider: ${C.white}${provider}${r}`,
138
+ `${d} ║ ║ ║ ║${r} ${d}Session: ${C.white}${session}${r}`,
139
+ autonomous ? ` ${C.brightYellow}${C.bold}⚡ AUTONOMOUS${r}` : '',
113
140
  '',
114
141
  ];
115
142
  return lines.join('\n');
116
143
  };
117
144
  exports.BANNER_3 = BANNER_3;
118
- // ─────────────────────────────────────────────────────
119
- // Default banner (Design 1 — Pixel Bot)
120
- // ─────────────────────────────────────────────────────
145
+ // ─────────────────────────────────────────────────────────────
146
+ // Default banner (Design 1 — Neural Core)
147
+ // ─────────────────────────────────────────────────────────────
121
148
  exports.banner = exports.BANNER_1;
149
+ // ─────────────────────────────────────────────────────────────
150
+ // Codi's Expressions — Compact inline status indicators
151
+ // Enterprise-grade: no emoji, no cartoon. Clean symbols.
152
+ // ─────────────────────────────────────────────────────────────
153
+ exports.CODI_FACE = {
154
+ ready: `${C.cyan}[${C.brightGreen}◉ ◉${C.cyan}]${C.reset}`,
155
+ working: `${C.cyan}[${C.brightCyan}◎ ◎${C.cyan}]${C.reset}`,
156
+ success: `${C.cyan}[${C.brightGreen}● ●${C.cyan}]${C.reset}`,
157
+ error: `${C.cyan}[${C.brightRed}✕ ✕${C.cyan}]${C.reset}`,
158
+ thinking: `${C.cyan}[${C.brightYellow}◉ ${C.dim}·${C.cyan}]${C.reset}`,
159
+ idle: `${C.cyan}[${C.dim}· ·${C.cyan}]${C.reset}`,
160
+ alert: `${C.cyan}[${C.brightYellow}▲ ▲${C.cyan}]${C.reset}`,
161
+ };
162
+ // ─────────────────────────────────────────────────────────────
163
+ // Greeting System — Mood-categorized randomized greetings
164
+ // ─────────────────────────────────────────────────────────────
165
+ const GREETINGS_BY_MOOD = {
166
+ confident: [
167
+ "Systems online. Let's ship.",
168
+ "All circuits green. Ready to code.",
169
+ "No cloud. No limits. Let's go.",
170
+ "Standing by. Say the word.",
171
+ "Initialized. Awaiting instructions.",
172
+ "Signal locked. Ready to transmit.",
173
+ "Provider connected. Model hot. Let's go.",
174
+ ],
175
+ playful: [
176
+ "What are we building today?",
177
+ "I read your codebase. We need to talk.",
178
+ "Your code, your machine, your move.",
179
+ "Another day, another deploy.",
180
+ "Booted up. Zero dependencies loaded.",
181
+ "Local power, global ambitions.",
182
+ "Scanned your repo. I have thoughts.",
183
+ ],
184
+ security: [
185
+ "Eight security layers active. You're safe.",
186
+ "Hash chain intact. Trust verified.",
187
+ "Sandbox locked. Creativity unlocked.",
188
+ "Audit trail recording. Every move counts.",
189
+ "Policy loaded. Rules are rules.",
190
+ "Risk score: 0. Let's keep it that way.",
191
+ ],
192
+ resuming: [
193
+ "Memory loaded. I remember everything.",
194
+ "Picking up where we left off.",
195
+ "Context restored. Continuity maintained.",
196
+ "Back online. Nothing lost.",
197
+ "Session recovered. Let's continue.",
198
+ ],
199
+ };
200
+ /** All greetings flattened for random selection */
201
+ const ALL_GREETINGS = Object.values(GREETINGS_BY_MOOD).flat();
122
202
  /**
123
203
  * Random startup greeting from Codi.
124
204
  */
125
- const GREETINGS = [
126
- "Systems online. Let's ship.",
127
- "All circuits green. Ready to code.",
128
- "What are we building today?",
129
- "I read your codebase. We need to talk.",
130
- "Local power, global ambitions.",
131
- "No cloud. No limits. Let's go.",
132
- "Standing by. Say the word.",
133
- "Initialized. Awaiting instructions.",
134
- "Your code, your machine, your move.",
135
- "Another day, another deploy.",
136
- "Signal locked. Ready to transmit.",
137
- "Booted up. Zero dependencies loaded.",
138
- ];
139
- function randomGreeting() {
140
- return GREETINGS[Math.floor(Math.random() * GREETINGS.length)];
205
+ function randomGreeting(mood) {
206
+ const pool = mood && GREETINGS_BY_MOOD[mood]
207
+ ? GREETINGS_BY_MOOD[mood]
208
+ : ALL_GREETINGS;
209
+ return pool[Math.floor(Math.random() * pool.length)];
210
+ }
211
+ const REACTIONS = {
212
+ tool_success: [
213
+ "Done.",
214
+ "Clean.",
215
+ "Handled.",
216
+ "Next?",
217
+ "Complete.",
218
+ ],
219
+ tool_error: [
220
+ "That broke. Fixing.",
221
+ "Error caught. Adjusting.",
222
+ "Not ideal. Recovering.",
223
+ "Blocked. Finding another way.",
224
+ "Retrying with different approach.",
225
+ ],
226
+ security_block: [
227
+ "Blocked. Policy violation.",
228
+ "Access denied. Security boundary hit.",
229
+ "Risk threshold exceeded. Skipping.",
230
+ "Denied. Policy enforced.",
231
+ "Path restricted. Cannot proceed.",
232
+ ],
233
+ session_end: [
234
+ "Session complete. Audit trail sealed.",
235
+ "Signing off. All changes persisted.",
236
+ "Done. Metrics saved.",
237
+ "Session closed. Everything committed.",
238
+ "Shutting down cleanly.",
239
+ ],
240
+ thinking: [
241
+ "Analyzing...",
242
+ "Processing...",
243
+ "Evaluating options...",
244
+ "Computing...",
245
+ "Working through it...",
246
+ ],
247
+ cost_warning: [
248
+ "Token usage elevated.",
249
+ "Cost accumulating. Monitor budget.",
250
+ "High token throughput detected.",
251
+ "Budget advisory: cost climbing.",
252
+ ],
253
+ autonomous_start: [
254
+ "Autonomous mode engaged.",
255
+ "Full automation active. No prompts.",
256
+ "Auto-pilot initialized.",
257
+ "Running unattended. All tools approved.",
258
+ "Autonomous. Maximum throughput.",
259
+ ],
260
+ };
261
+ /**
262
+ * Get a context-aware reaction from Codi.
263
+ * Returns a face expression + message pair.
264
+ */
265
+ function codiReact(event) {
266
+ let mood = 'ready';
267
+ if (event === 'tool_success' || event === 'session_end')
268
+ mood = 'success';
269
+ else if (event === 'tool_error')
270
+ mood = 'error';
271
+ else if (event === 'security_block')
272
+ mood = 'alert';
273
+ else if (event === 'thinking')
274
+ mood = 'thinking';
275
+ else if (event === 'cost_warning')
276
+ mood = 'alert';
277
+ else if (event === 'autonomous_start')
278
+ mood = 'working';
279
+ const messages = REACTIONS[event] || REACTIONS.tool_success;
280
+ const message = messages[Math.floor(Math.random() * messages.length)];
281
+ return {
282
+ face: exports.CODI_FACE[mood],
283
+ message,
284
+ };
285
+ }
286
+ /**
287
+ * Format a Codi reaction as a styled CLI string.
288
+ */
289
+ function formatReaction(event) {
290
+ const reaction = codiReact(event);
291
+ return ` ${reaction.face} ${C.dim}${reaction.message}${C.reset}`;
292
+ }
293
+ // ─────────────────────────────────────────────────────────────
294
+ // Session Summary Banner — Clean end-of-session report
295
+ // ─────────────────────────────────────────────────────────────
296
+ function sessionSummaryBanner(stats) {
297
+ const durationStr = stats.duration !== undefined
298
+ ? `${Math.floor(stats.duration / 60)}m ${Math.round(stats.duration % 60)}s`
299
+ : 'N/A';
300
+ const costStr = stats.cost !== undefined ? `$${stats.cost.toFixed(4)}` : 'N/A';
301
+ const lines = [
302
+ '',
303
+ `${C.dim}${'─'.repeat(50)}${C.reset}`,
304
+ `${exports.CODI_FACE.success} ${C.bold}${C.brightCyan}Session Complete${C.reset}`,
305
+ `${C.dim}${'─'.repeat(50)}${C.reset}`,
306
+ ` ${C.dim}Iterations:${C.reset} ${stats.iterations}`,
307
+ ` ${C.dim}Tool calls:${C.reset} ${stats.toolCalls}`,
308
+ ` ${C.dim}Tokens:${C.reset} ${stats.tokensUsed.toLocaleString()}`,
309
+ ` ${C.dim}Cost:${C.reset} ${costStr}`,
310
+ ` ${C.dim}Duration:${C.reset} ${durationStr}`,
311
+ `${C.dim}${'─'.repeat(50)}${C.reset}`,
312
+ ` ${C.dim}${randomGreeting('confident')}${C.reset}`,
313
+ '',
314
+ ];
315
+ return lines.join('\n');
141
316
  }
142
317
  /**
143
318
  * Compact single-line startup for non-TTY / piped usage.
@@ -145,4 +320,11 @@ function randomGreeting() {
145
320
  function compactBanner(version, model) {
146
321
  return `${C.bold}${C.brightCyan}CodeBot AI${C.reset} ${C.dim}v${version}${C.reset} ${C.dim}[${model}]${C.reset}`;
147
322
  }
323
+ /**
324
+ * Pick a random banner design (for variety on startup).
325
+ */
326
+ function randomBanner() {
327
+ const banners = [exports.BANNER_1, exports.BANNER_2, exports.BANNER_3];
328
+ return banners[Math.floor(Math.random() * banners.length)];
329
+ }
148
330
  //# sourceMappingURL=banner.js.map
package/dist/cli.js CHANGED
@@ -52,7 +52,7 @@ const sandbox_1 = require("./sandbox");
52
52
  const replay_1 = require("./replay");
53
53
  const risk_1 = require("./risk");
54
54
  const sarif_1 = require("./sarif");
55
- const VERSION = '2.0.0';
55
+ const VERSION = '2.1.1';
56
56
  const C = {
57
57
  reset: '\x1b[0m',
58
58
  bold: '\x1b[1m',
@@ -272,9 +272,15 @@ async function main() {
272
272
  const sessionShort = session.getId().substring(0, 8);
273
273
  console.log((0, banner_1.banner)(VERSION, config.model, `${config.provider} @ ${config.baseUrl}`, `${sessionShort}...`, !!config.autoApprove));
274
274
  if (resumeId) {
275
- console.log(c(` Resuming session...`, 'green'));
275
+ console.log(c(` ${(0, banner_1.randomGreeting)('resuming')}`, 'green'));
276
+ }
277
+ else if (config.autoApprove) {
278
+ console.log(c(` ${(0, banner_1.randomGreeting)('confident')}`, 'dim'));
279
+ console.log((0, banner_1.formatReaction)('autonomous_start'));
280
+ }
281
+ else {
282
+ console.log(c(` ${(0, banner_1.randomGreeting)()}\n`, 'dim'));
276
283
  }
277
- console.log(c(` ${(0, banner_1.randomGreeting)()}\n`, 'dim'));
278
284
  const agent = new agent_1.Agent({
279
285
  provider,
280
286
  model: config.model,
@@ -347,6 +353,13 @@ function printSessionSummary(agent) {
347
353
  if (riskScorer.getHistory().length > 0) {
348
354
  console.log(` Risk: avg ${riskAvg}/100`);
349
355
  }
356
+ // Codi's session summary banner
357
+ console.log((0, banner_1.sessionSummaryBanner)({
358
+ iterations: summary.requestCount,
359
+ toolCalls: summary.toolCalls,
360
+ tokensUsed: summary.totalInputTokens + summary.totalOutputTokens,
361
+ duration,
362
+ }));
350
363
  // Save metrics
351
364
  metrics.save();
352
365
  metrics.exportOtel();
@@ -397,7 +410,7 @@ async function repl(agent, config, session) {
397
410
  });
398
411
  rl.on('close', () => {
399
412
  printSessionSummary(agent);
400
- console.log(c('\nBye!', 'dim'));
413
+ console.log((0, banner_1.formatReaction)('session_end'));
401
414
  process.exit(0);
402
415
  });
403
416
  }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Encryption at rest for CodeBot v2.1.0
3
+ *
4
+ * Provides AES-256-GCM encryption for audit logs, session files, and memory.
5
+ * Key derivation uses PBKDF2 from a user-supplied passphrase or machine identity.
6
+ *
7
+ * Encryption is opt-in: set CODEBOT_ENCRYPTION_KEY env var or
8
+ * configure encryption.passphrase in policy.json.
9
+ *
10
+ * NEVER throws — encryption failures fall back to plaintext with a warning.
11
+ */
12
+ export interface EncryptionConfig {
13
+ /** Enable encryption at rest */
14
+ enabled: boolean;
15
+ /** Passphrase for key derivation (or use CODEBOT_ENCRYPTION_KEY env var) */
16
+ passphrase?: string;
17
+ }
18
+ /**
19
+ * Derives an AES-256 key from a passphrase using PBKDF2-SHA512.
20
+ * The salt is generated randomly and prepended to the output.
21
+ */
22
+ export declare function deriveKey(passphrase: string, salt?: Buffer): {
23
+ key: Buffer;
24
+ salt: Buffer;
25
+ };
26
+ /**
27
+ * Get the encryption passphrase from environment or config.
28
+ * Returns null if encryption is not configured.
29
+ */
30
+ export declare function getPassphrase(config?: EncryptionConfig): string | null;
31
+ /**
32
+ * Check if encryption is enabled (passphrase available).
33
+ */
34
+ export declare function isEncryptionEnabled(config?: EncryptionConfig): boolean;
35
+ /**
36
+ * Encrypt plaintext using AES-256-GCM.
37
+ *
38
+ * Output format: HEADER(4) + salt(32) + iv(16) + tag(16) + ciphertext(...)
39
+ * All binary, base64-encoded as a string for storage.
40
+ *
41
+ * Returns null on failure (never throws).
42
+ */
43
+ export declare function encrypt(plaintext: string, passphrase: string): string | null;
44
+ /**
45
+ * Decrypt a base64-encoded ciphertext produced by encrypt().
46
+ * Returns null on failure (wrong key, tampered data, not encrypted).
47
+ */
48
+ export declare function decrypt(encoded: string, passphrase: string): string | null;
49
+ /**
50
+ * Encrypt a JSONL line for file storage.
51
+ * If encryption is not configured, returns the original line unchanged.
52
+ */
53
+ export declare function encryptLine(line: string, config?: EncryptionConfig): string;
54
+ /**
55
+ * Decrypt a JSONL line from file storage.
56
+ * Auto-detects encrypted vs plaintext lines.
57
+ */
58
+ export declare function decryptLine(line: string, config?: EncryptionConfig): string;
59
+ /**
60
+ * Encrypt an entire file's content (for memory files which are Markdown, not JSONL).
61
+ */
62
+ export declare function encryptContent(content: string, config?: EncryptionConfig): string;
63
+ /**
64
+ * Decrypt file content. Auto-detects encrypted vs plaintext.
65
+ */
66
+ export declare function decryptContent(content: string, config?: EncryptionConfig): string;
67
+ //# sourceMappingURL=encryption.d.ts.map