codebot-ai 2.1.1 → 2.1.3

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,37 +2,24 @@
2
2
  * CodeBot AI mascot and CLI banner.
3
3
  *
4
4
  * Mascot name: Codi
5
- * Three designs: Neural Core, Terminal Shield, Sentinel
5
+ * Three designs: Core, Terminal, Sentinel
6
6
  * See BRANDING.md for full identity guide.
7
- *
8
- * Design philosophy: Enterprise-grade. Clean geometry.
9
- * No crayon vibes — precision engineering.
10
7
  */
11
8
  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";
9
+ export declare const MASCOT_1 = "\n \u2584\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584\n \u2588\u2588 \u2588\u2588\n \u2588\u2588 \u2584\u2588\u2588\u2584 \u2584\u2588\u2588\u2584 \u2588\u2588\n \u2588\u2588 \u2580\u2588\u2588\u2580 \u2580\u2588\u2588\u2580 \u2588\u2588\n \u2588\u2588 \u2588\u2588\n \u2588\u2588 \u2580\u2588\u2588\u2588\u2588\u2588\u2588\u2580 \u2588\u2588\n \u2580\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2580\n";
13
10
  export declare const BANNER_1: (version: string, model: string, provider: string, session: string, autonomous: boolean) => string;
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";
11
+ export declare const MASCOT_2 = "\n \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n \u2551 \u2551\n \u2551 \u25CF \u25CF \u2551\n \u2551 \u2551\n \u2551 \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F \u2551\n \u2551 \u2551\n \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n";
15
12
  export declare const BANNER_2: (version: string, model: string, provider: string, session: string, autonomous: boolean) => string;
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";
13
+ export declare const MASCOT_3 = "\n \u2584\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584\n \u2584\u2588\u2580 \u2580\u2588\u2584\n \u2588\u2580 \u2591\u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591\u2591 \u2580\u2588\n \u2588\u2584 \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 \u2584\u2588\n \u2580\u2588\u2584 \u2584\u2588\u2580\n \u2580\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2580\n";
17
14
  export declare const BANNER_3: (version: string, model: string, provider: string, session: string, autonomous: boolean) => string;
18
15
  export declare const banner: (version: string, model: string, provider: string, session: string, autonomous: boolean) => string;
19
16
  export declare const CODI_FACE: Record<CodiMood, string>;
20
- /**
21
- * Random startup greeting from Codi.
22
- */
23
17
  export declare function randomGreeting(mood?: string): string;
24
18
  export interface CodiReaction {
25
19
  face: string;
26
20
  message: string;
27
21
  }
28
- /**
29
- * Get a context-aware reaction from Codi.
30
- * Returns a face expression + message pair.
31
- */
32
22
  export declare function codiReact(event: string): CodiReaction;
33
- /**
34
- * Format a Codi reaction as a styled CLI string.
35
- */
36
23
  export declare function formatReaction(event: string): string;
37
24
  export declare function sessionSummaryBanner(stats: {
38
25
  iterations: number;
@@ -41,12 +28,37 @@ export declare function sessionSummaryBanner(stats: {
41
28
  cost?: number;
42
29
  duration?: number;
43
30
  }): string;
44
- /**
45
- * Compact single-line startup for non-TTY / piped usage.
46
- */
47
31
  export declare function compactBanner(version: string, model: string): string;
48
- /**
49
- * Pick a random banner design (for variety on startup).
50
- */
51
32
  export declare function randomBanner(): typeof BANNER_1;
33
+ export type AnimationWriter = (text: string) => void;
34
+ export type AnimationSpeed = 'fast' | 'normal' | 'slow';
35
+ export interface AnimationOptions {
36
+ speed?: AnimationSpeed;
37
+ writer?: AnimationWriter;
38
+ }
39
+ export declare function animateReveal(bannerFn: typeof BANNER_1, version: string, model: string, provider: string, session: string, autonomous: boolean, speed?: AnimationSpeed, opts?: {
40
+ writer?: AnimationWriter;
41
+ }): Promise<void>;
42
+ export declare function animateVisorScan(sweeps?: number, speed?: AnimationSpeed, opts?: {
43
+ writer?: AnimationWriter;
44
+ }): Promise<void>;
45
+ export declare function animateEyeBoot(speed?: AnimationSpeed, opts?: {
46
+ writer?: AnimationWriter;
47
+ }): Promise<void>;
48
+ export declare function animateBootSequence(bannerFn: typeof BANNER_1, version: string, model: string, provider: string, session: string, autonomous: boolean, speed?: AnimationSpeed, opts?: {
49
+ writer?: AnimationWriter;
50
+ }): Promise<void>;
51
+ export declare function animateTyping(text: string, color?: string, speed?: AnimationSpeed, opts?: {
52
+ writer?: AnimationWriter;
53
+ }): Promise<void>;
54
+ export declare function animateSessionEnd(stats: {
55
+ iterations: number;
56
+ toolCalls: number;
57
+ tokensUsed: number;
58
+ cost?: number;
59
+ duration?: number;
60
+ }, speed?: AnimationSpeed, opts?: {
61
+ writer?: AnimationWriter;
62
+ }): Promise<void>;
63
+ export declare function shouldAnimate(): boolean;
52
64
  //# sourceMappingURL=banner.d.ts.map
package/dist/banner.js CHANGED
@@ -3,11 +3,8 @@
3
3
  * CodeBot AI mascot and CLI banner.
4
4
  *
5
5
  * Mascot name: Codi
6
- * Three designs: Neural Core, Terminal Shield, Sentinel
6
+ * Three designs: Core, Terminal, Sentinel
7
7
  * See BRANDING.md for full identity guide.
8
- *
9
- * Design philosophy: Enterprise-grade. Clean geometry.
10
- * No crayon vibes — precision engineering.
11
8
  */
12
9
  Object.defineProperty(exports, "__esModule", { value: true });
13
10
  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;
@@ -17,6 +14,13 @@ exports.formatReaction = formatReaction;
17
14
  exports.sessionSummaryBanner = sessionSummaryBanner;
18
15
  exports.compactBanner = compactBanner;
19
16
  exports.randomBanner = randomBanner;
17
+ exports.animateReveal = animateReveal;
18
+ exports.animateVisorScan = animateVisorScan;
19
+ exports.animateEyeBoot = animateEyeBoot;
20
+ exports.animateBootSequence = animateBootSequence;
21
+ exports.animateTyping = animateTyping;
22
+ exports.animateSessionEnd = animateSessionEnd;
23
+ exports.shouldAnimate = shouldAnimate;
20
24
  const C = {
21
25
  reset: '\x1b[0m',
22
26
  bold: '\x1b[1m',
@@ -37,118 +41,114 @@ const C = {
37
41
  brightBlue: '\x1b[94m',
38
42
  };
39
43
  // ─────────────────────────────────────────────────────────────
40
- // DESIGN 1: "Neural Core" — Precision-engineered AI processor
41
- // Clean, symmetric, enterprise. The signature look.
44
+ // DESIGN 1: "Core" — Solid block-character robot head
45
+ // Double-thick walls. Heavy, industrial, enterprise.
42
46
  // ─────────────────────────────────────────────────────────────
43
47
  exports.MASCOT_1 = `
44
- ┌─────────────────────┐
45
- │ ┌──┐ ┌──┐ │
46
- │▓▓│ │▓▓│ │
47
- └──┘ └──┘ │
48
- ╶────┤ ├────╴
49
- ╰─────────╯
50
- │ │
51
- └──┬──┬───────┬──┬──┘
52
- │ │ │ │
48
+ ▄██████████████████▄
49
+ ██ ██
50
+ ██ ▄██▄ ▄██▄ ██
51
+ ██ ▀██▀ ▀██▀ ██
52
+ ██ ██
53
+ ██ ▀██████▀ ██
54
+ ▀██████████████████▀
53
55
  `;
54
56
  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
57
+ const f = C.cyan;
58
+ const e = C.brightGreen;
59
+ const m = C.brightCyan;
60
+ const d = C.dim;
59
61
  const r = C.reset;
60
62
  const lines = [
61
63
  '',
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}` : ''),
64
+ `${f} ▄██████████████████▄${r}`,
65
+ `${f} ██${r} ${f}██${r}`,
66
+ `${f} ██${r} ${e}▄██▄${r} ${e}▄██▄${r} ${f}██${r} ${C.bold}${C.brightCyan}CodeBot AI${r} ${d}v${version}${r}`,
67
+ `${f} ██${r} ${e}▀██▀${r} ${e}▀██▀${r} ${f}██${r} ${d}Think local. Code global.${r}`,
68
+ `${f} ██${r} ${f}██${r}`,
69
+ `${f} ██${r} ${m}▀██████▀${r} ${f}██${r} ${d}Model: ${C.white}${model}${r}`,
70
+ `${f} ▀██████████████████▀${r} ${d}Provider: ${C.white}${provider}${r}`,
71
+ ` ${d}Session: ${C.white}${session}${r}`,
72
+ autonomous ? ` ${C.brightYellow}${C.bold}⚡ AUTONOMOUS${r}` : '',
71
73
  '',
72
74
  ];
73
75
  return lines.join('\n');
74
76
  };
75
77
  exports.BANNER_1 = BANNER_1;
76
78
  // ─────────────────────────────────────────────────────────────
77
- // DESIGN 2: "Terminal Shield" — Secure terminal with status LEDs
78
- // Enterprise security aesthetic. Trust indicator built in.
79
+ // DESIGN 2: "Terminal" — Clean double-line border monitor
80
+ // Formal, corporate. Minimal decoration.
79
81
  // ─────────────────────────────────────────────────────────────
80
82
  exports.MASCOT_2 = `
81
- ┌─┐ ╔═══════════════════╗ ┌─┐
82
- │░│ ◉ ◉ │░│
83
- │░│ │░│
84
- │░│ ╰───────────╯ │░│
85
- │░│ │░│
86
- └─┘ ╚═══════════════════╝ └─┘
87
- ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪
83
+ ╔══════════════════════╗
84
+
85
+ ● ●
86
+
87
+ ╰────────╯
88
+ ║ ║
89
+ ╚══════════════════════╝
88
90
  `;
89
91
  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
92
+ const f = C.cyan;
93
+ const e = C.brightGreen;
94
+ const m = C.brightCyan;
95
+ const d = C.dim;
94
96
  const r = C.reset;
95
- const led = C.brightGreen;
96
97
  const lines = [
97
98
  '',
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}` : '',
99
+ `${f} ╔══════════════════════╗${r}`,
100
+ `${f} ║${r} ${f}║${r}`,
101
+ `${f} ║${r} ${e}●${r} ${e}●${r} ${f}║${r} ${C.bold}${C.brightCyan}CodeBot AI${r} ${d}v${version}${r}`,
102
+ `${f} ║${r} ${f}║${r} ${d}Think local. Code global.${r}`,
103
+ `${f} ║${r} ${m}╰────────╯${r} ${f}║${r}`,
104
+ `${f} ║${r} ${f}║${r} ${d}Model: ${C.white}${model}${r}`,
105
+ `${f} ╚══════════════════════╝${r} ${d}Provider: ${C.white}${provider}${r}`,
106
+ ` ${d}Session: ${C.white}${session}${r}`,
107
+ autonomous ? ` ${C.brightYellow}${C.bold}⚡ AUTONOMOUS${r}` : '',
106
108
  '',
107
109
  ];
108
110
  return lines.join('\n');
109
111
  };
110
112
  exports.BANNER_2 = BANNER_2;
111
113
  // ─────────────────────────────────────────────────────────────
112
- // DESIGN 3: "Sentinel" — Armored visor. Threat detection mode.
113
- // Cybersecurity aesthetic. Used in autonomous/scanning contexts.
114
+ // DESIGN 3: "Sentinel" — Visor helmet with gradient scan bar
115
+ // Sleek armor plating. Diamond silhouette.
114
116
  // ─────────────────────────────────────────────────────────────
115
117
  exports.MASCOT_3 = `
116
- ╔═══════════╗
117
- ╔╝ ╚╗
118
- ║ ░░░█████░░░ ║
119
- ║ ░░░░░░░░░░░ ║
120
- ╚╗ ╔╝
121
- ╚═══════════╝
122
- ║ ║ ║ ║
118
+ ▄████████████▄
119
+ ▄█▀ ▀█▄
120
+ █▀ ░░▒▓██████▓▒░░ ▀█
121
+ █▄ ░░░░░░░░░░░░░░ ▄█
122
+ ▀█▄ ▄█▀
123
+ ▀████████████▀
123
124
  `;
124
125
  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
126
+ const f = C.cyan;
127
+ const v = C.brightCyan;
128
+ const g = C.brightGreen;
128
129
  const d = C.dim;
129
130
  const r = C.reset;
130
131
  const lines = [
131
132
  '',
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}` : '',
133
+ `${f} ▄████████████▄${r}`,
134
+ `${f} ▄█▀${r} ${f}▀█▄${r} ${C.bold}${C.brightCyan}CodeBot AI${r} ${d}v${version}${r}`,
135
+ `${f} █▀${r} ${v}░░▒▓${g}██████${v}▓▒░░${r} ${f}▀█${r} ${d}Think local. Code global.${r}`,
136
+ `${f} █▄${r} ${d}░░░░░░░░░░░░░░${r} ${f}▄█${r}`,
137
+ `${f} ▀█▄${r} ${f}▄█▀${r} ${d}Model: ${C.white}${model}${r}`,
138
+ `${f} ▀████████████▀${r} ${d}Provider: ${C.white}${provider}${r}`,
139
+ ` ${d}Session: ${C.white}${session}${r}`,
140
+ autonomous ? ` ${C.brightYellow}${C.bold}⚡ AUTONOMOUS${r}` : '',
140
141
  '',
141
142
  ];
142
143
  return lines.join('\n');
143
144
  };
144
145
  exports.BANNER_3 = BANNER_3;
145
146
  // ─────────────────────────────────────────────────────────────
146
- // Default banner (Design 1 — Neural Core)
147
+ // Default banner (Design 1 — Core)
147
148
  // ─────────────────────────────────────────────────────────────
148
149
  exports.banner = exports.BANNER_1;
149
150
  // ─────────────────────────────────────────────────────────────
150
- // Codi's Expressions — Compact inline status indicators
151
- // Enterprise-grade: no emoji, no cartoon. Clean symbols.
151
+ // Inline status indicators
152
152
  // ─────────────────────────────────────────────────────────────
153
153
  exports.CODI_FACE = {
154
154
  ready: `${C.cyan}[${C.brightGreen}◉ ◉${C.cyan}]${C.reset}`,
@@ -160,7 +160,7 @@ exports.CODI_FACE = {
160
160
  alert: `${C.cyan}[${C.brightYellow}▲ ▲${C.cyan}]${C.reset}`,
161
161
  };
162
162
  // ─────────────────────────────────────────────────────────────
163
- // Greeting System — Mood-categorized randomized greetings
163
+ // Greeting System
164
164
  // ─────────────────────────────────────────────────────────────
165
165
  const GREETINGS_BY_MOOD = {
166
166
  confident: [
@@ -197,11 +197,7 @@ const GREETINGS_BY_MOOD = {
197
197
  "Session recovered. Let's continue.",
198
198
  ],
199
199
  };
200
- /** All greetings flattened for random selection */
201
200
  const ALL_GREETINGS = Object.values(GREETINGS_BY_MOOD).flat();
202
- /**
203
- * Random startup greeting from Codi.
204
- */
205
201
  function randomGreeting(mood) {
206
202
  const pool = mood && GREETINGS_BY_MOOD[mood]
207
203
  ? GREETINGS_BY_MOOD[mood]
@@ -258,10 +254,6 @@ const REACTIONS = {
258
254
  "Autonomous. Maximum throughput.",
259
255
  ],
260
256
  };
261
- /**
262
- * Get a context-aware reaction from Codi.
263
- * Returns a face expression + message pair.
264
- */
265
257
  function codiReact(event) {
266
258
  let mood = 'ready';
267
259
  if (event === 'tool_success' || event === 'session_end')
@@ -278,20 +270,14 @@ function codiReact(event) {
278
270
  mood = 'working';
279
271
  const messages = REACTIONS[event] || REACTIONS.tool_success;
280
272
  const message = messages[Math.floor(Math.random() * messages.length)];
281
- return {
282
- face: exports.CODI_FACE[mood],
283
- message,
284
- };
273
+ return { face: exports.CODI_FACE[mood], message };
285
274
  }
286
- /**
287
- * Format a Codi reaction as a styled CLI string.
288
- */
289
275
  function formatReaction(event) {
290
276
  const reaction = codiReact(event);
291
277
  return ` ${reaction.face} ${C.dim}${reaction.message}${C.reset}`;
292
278
  }
293
279
  // ─────────────────────────────────────────────────────────────
294
- // Session Summary Banner — Clean end-of-session report
280
+ // Session Summary Banner
295
281
  // ─────────────────────────────────────────────────────────────
296
282
  function sessionSummaryBanner(stats) {
297
283
  const durationStr = stats.duration !== undefined
@@ -314,17 +300,292 @@ function sessionSummaryBanner(stats) {
314
300
  ];
315
301
  return lines.join('\n');
316
302
  }
317
- /**
318
- * Compact single-line startup for non-TTY / piped usage.
319
- */
320
303
  function compactBanner(version, model) {
321
304
  return `${C.bold}${C.brightCyan}CodeBot AI${C.reset} ${C.dim}v${version}${C.reset} ${C.dim}[${model}]${C.reset}`;
322
305
  }
323
- /**
324
- * Pick a random banner design (for variety on startup).
325
- */
326
306
  function randomBanner() {
327
307
  const banners = [exports.BANNER_1, exports.BANNER_2, exports.BANNER_3];
328
308
  return banners[Math.floor(Math.random() * banners.length)];
329
309
  }
310
+ // ─────────────────────────────────────────────────────────────
311
+ // Terminal Animation System
312
+ // ─────────────────────────────────────────────────────────────
313
+ const ANSI = {
314
+ hideCursor: '\x1b[?25l',
315
+ showCursor: '\x1b[?25h',
316
+ clearLine: '\x1b[2K',
317
+ moveUp: (n) => `\x1b[${n}A`,
318
+ moveDown: (n) => `\x1b[${n}B`,
319
+ moveToCol: (n) => `\x1b[${n}G`,
320
+ saveCursor: '\x1b7',
321
+ restoreCursor: '\x1b8',
322
+ };
323
+ function sleep(ms) {
324
+ return new Promise(resolve => setTimeout(resolve, ms));
325
+ }
326
+ function defaultWriter(text) {
327
+ process.stdout.write(text);
328
+ }
329
+ function getDelay(speed) {
330
+ switch (speed) {
331
+ case 'fast': return { line: 25, char: 8, pause: 80, frame: 40 };
332
+ case 'normal': return { line: 50, char: 15, pause: 150, frame: 60 };
333
+ case 'slow': return { line: 80, char: 25, pause: 250, frame: 90 };
334
+ }
335
+ }
336
+ /**
337
+ * Strip ANSI escape codes from a string.
338
+ */
339
+ function stripAnsi(s) {
340
+ return s.replace(/\x1b\[[0-9;]*m/g, '');
341
+ }
342
+ // ─────────────────────────────────────────────────────────────
343
+ // Animation 1: Line-by-line reveal
344
+ // Renders the banner one line at a time with a delay.
345
+ // ─────────────────────────────────────────────────────────────
346
+ async function animateReveal(bannerFn, version, model, provider, session, autonomous, speed = 'normal', opts) {
347
+ const w = opts?.writer ?? defaultWriter;
348
+ const delay = getDelay(speed);
349
+ const output = bannerFn(version, model, provider, session, autonomous);
350
+ const lines = output.split('\n');
351
+ w(ANSI.hideCursor);
352
+ try {
353
+ for (const line of lines) {
354
+ w(line + '\n');
355
+ if (stripAnsi(line).trim().length > 0) {
356
+ await sleep(delay.line);
357
+ }
358
+ }
359
+ }
360
+ finally {
361
+ w(ANSI.showCursor);
362
+ }
363
+ }
364
+ // ─────────────────────────────────────────────────────────────
365
+ // Animation 2: Sentinel visor scan
366
+ // The gradient highlight sweeps across the visor bar.
367
+ // ─────────────────────────────────────────────────────────────
368
+ const VISOR_WIDTH = 14; // character width of the visor zone
369
+ function renderVisorFrame(position) {
370
+ const chars = [];
371
+ for (let i = 0; i < VISOR_WIDTH; i++) {
372
+ const dist = Math.abs(i - position);
373
+ if (dist === 0)
374
+ chars.push(`${C.brightGreen}██${C.reset}`);
375
+ else if (dist === 1)
376
+ chars.push(`${C.brightCyan}▓▓${C.reset}`);
377
+ else if (dist === 2)
378
+ chars.push(`${C.cyan}▒▒${C.reset}`);
379
+ else if (dist === 3)
380
+ chars.push(`${C.dim}░░${C.reset}`);
381
+ else
382
+ chars.push(`${C.dim}░░${C.reset}`);
383
+ }
384
+ return chars.join('').replace(/(░░)+$/, m => `${C.dim}${m}${C.reset}`);
385
+ }
386
+ async function animateVisorScan(sweeps = 2, speed = 'normal', opts) {
387
+ const w = opts?.writer ?? defaultWriter;
388
+ const delay = getDelay(speed);
389
+ const f = C.cyan;
390
+ const r = C.reset;
391
+ // Render the static sentinel frame first
392
+ const staticLines = [
393
+ '',
394
+ `${f} ▄████████████▄${r}`,
395
+ `${f} ▄█▀${r} ${f}▀█▄${r}`,
396
+ '', // visor line — will be animated
397
+ `${f} █▄${r} ${C.dim}░░░░░░░░░░░░░░${r} ${f}▄█${r}`,
398
+ `${f} ▀█▄${r} ${f}▄█▀${r}`,
399
+ `${f} ▀████████████▀${r}`,
400
+ '',
401
+ ];
402
+ w(ANSI.hideCursor);
403
+ try {
404
+ // Print static lines, inserting placeholder for visor
405
+ for (let i = 0; i < staticLines.length; i++) {
406
+ if (i === 3) {
407
+ w(`${f} █▀${r} ${C.dim}░░░░░░░░░░░░░░░░░░░░░░░░░░░░${r} ${f}▀█${r}\n`);
408
+ }
409
+ else {
410
+ w(staticLines[i] + '\n');
411
+ }
412
+ }
413
+ // Now animate the visor line (line index 3, which is 5 lines up from bottom)
414
+ const linesBelow = staticLines.length - 3 - 1; // lines printed after the visor line
415
+ for (let sweep = 0; sweep < sweeps; sweep++) {
416
+ // Sweep right
417
+ for (let pos = 0; pos <= 6; pos++) {
418
+ w(ANSI.moveUp(linesBelow + 1));
419
+ w('\r' + ANSI.clearLine);
420
+ const visor = renderVisorFrame(pos);
421
+ w(`${f} █▀${r} ${visor} ${f}▀█${r}`);
422
+ w('\n' + ANSI.moveDown(linesBelow));
423
+ await sleep(delay.frame);
424
+ }
425
+ // Sweep left
426
+ for (let pos = 6; pos >= 0; pos--) {
427
+ w(ANSI.moveUp(linesBelow + 1));
428
+ w('\r' + ANSI.clearLine);
429
+ const visor = renderVisorFrame(pos);
430
+ w(`${f} █▀${r} ${visor} ${f}▀█${r}`);
431
+ w('\n' + ANSI.moveDown(linesBelow));
432
+ await sleep(delay.frame);
433
+ }
434
+ }
435
+ // Final state — render the standard visor
436
+ w(ANSI.moveUp(linesBelow + 1));
437
+ w('\r' + ANSI.clearLine);
438
+ const v = C.brightCyan;
439
+ const g = C.brightGreen;
440
+ w(`${f} █▀${r} ${v}░░▒▓${g}██████${v}▓▒░░${r} ${f}▀█${r}`);
441
+ w('\n' + ANSI.moveDown(linesBelow));
442
+ }
443
+ finally {
444
+ w(ANSI.showCursor);
445
+ }
446
+ }
447
+ // ─────────────────────────────────────────────────────────────
448
+ // Animation 3: Core eye boot sequence
449
+ // Eyes power on: dim → medium → bright
450
+ // ─────────────────────────────────────────────────────────────
451
+ async function animateEyeBoot(speed = 'normal', opts) {
452
+ const w = opts?.writer ?? defaultWriter;
453
+ const delay = getDelay(speed);
454
+ const f = C.cyan;
455
+ const r = C.reset;
456
+ // Phase frames for the eyes powering on
457
+ const eyeFrames = [
458
+ // Phase 0: Dark — no eyes
459
+ { top: `${C.dim}· ·${r} ${C.dim}· ·${r}`, bot: `${C.dim}· ·${r} ${C.dim}· ·${r}` },
460
+ // Phase 1: Dim blocks
461
+ { top: `${C.dim}▄██▄${r} ${C.dim}▄██▄${r}`, bot: `${C.dim}▀██▀${r} ${C.dim}▀██▀${r}` },
462
+ // Phase 2: Cyan glow
463
+ { top: `${C.cyan}▄██▄${r} ${C.cyan}▄██▄${r}`, bot: `${C.cyan}▀██▀${r} ${C.cyan}▀██▀${r}` },
464
+ // Phase 3: Bright green — fully online
465
+ { top: `${C.brightGreen}▄██▄${r} ${C.brightGreen}▄██▄${r}`, bot: `${C.brightGreen}▀██▀${r} ${C.brightGreen}▀██▀${r}` },
466
+ ];
467
+ // Print the Core mascot with blank eyes first
468
+ const lines = [
469
+ '',
470
+ `${f} ▄██████████████████▄${r}`,
471
+ `${f} ██${r} ${f}██${r}`,
472
+ `${f} ██${r} ${eyeFrames[0].top} ${f}██${r}`,
473
+ `${f} ██${r} ${eyeFrames[0].bot} ${f}██${r}`,
474
+ `${f} ██${r} ${f}██${r}`,
475
+ `${f} ██${r} ${C.dim}· · · ·${r} ${f}██${r}`,
476
+ `${f} ▀██████████████████▀${r}`,
477
+ '',
478
+ ];
479
+ w(ANSI.hideCursor);
480
+ try {
481
+ for (const line of lines) {
482
+ w(line + '\n');
483
+ }
484
+ await sleep(delay.pause * 2);
485
+ // Animate eye phases
486
+ for (let phase = 1; phase < eyeFrames.length; phase++) {
487
+ const frame = eyeFrames[phase];
488
+ w(ANSI.moveUp(6));
489
+ w('\r' + ANSI.clearLine);
490
+ w(`${f} ██${r} ${frame.top} ${f}██${r}`);
491
+ w('\n' + ANSI.clearLine);
492
+ w(`${f} ██${r} ${frame.bot} ${f}██${r}`);
493
+ w('\n' + ANSI.moveDown(4));
494
+ if (phase === eyeFrames.length - 1) {
495
+ // Also light up the mouth
496
+ w(ANSI.moveUp(3));
497
+ w('\r' + ANSI.clearLine);
498
+ w(`${f} ██${r} ${C.brightCyan}▀██████▀${r} ${f}██${r}`);
499
+ w('\n' + ANSI.moveDown(2));
500
+ }
501
+ await sleep(delay.pause);
502
+ }
503
+ }
504
+ finally {
505
+ w(ANSI.showCursor);
506
+ }
507
+ }
508
+ // ─────────────────────────────────────────────────────────────
509
+ // Animation 4: Full boot sequence
510
+ // Combines: scanline effect → mascot build → info fade-in
511
+ // ─────────────────────────────────────────────────────────────
512
+ async function animateBootSequence(bannerFn, version, model, provider, session, autonomous, speed = 'normal', opts) {
513
+ const w = opts?.writer ?? defaultWriter;
514
+ const delay = getDelay(speed);
515
+ const output = bannerFn(version, model, provider, session, autonomous);
516
+ const lines = output.split('\n');
517
+ const r = C.reset;
518
+ w(ANSI.hideCursor);
519
+ try {
520
+ // Phase 1: Scanline — print each line dim first, then brighten
521
+ for (const line of lines) {
522
+ const stripped = stripAnsi(line).trim();
523
+ if (stripped.length === 0) {
524
+ w('\n');
525
+ continue;
526
+ }
527
+ // Print dim version first
528
+ w(`${C.dim}${stripAnsi(line)}${r}`);
529
+ await sleep(delay.line / 2);
530
+ // Overwrite with full color
531
+ w('\r' + ANSI.clearLine + line + '\n');
532
+ await sleep(delay.line / 2);
533
+ }
534
+ await sleep(delay.pause);
535
+ // Phase 2: Greeting
536
+ const greeting = randomGreeting('confident');
537
+ // Type out the greeting character by character
538
+ w(' ' + exports.CODI_FACE.ready + ' ' + C.dim);
539
+ for (const ch of greeting) {
540
+ w(ch);
541
+ await sleep(delay.char);
542
+ }
543
+ w(r + '\n');
544
+ }
545
+ finally {
546
+ w(ANSI.showCursor);
547
+ }
548
+ }
549
+ // ─────────────────────────────────────────────────────────────
550
+ // Animation 5: Terminal typing effect
551
+ // Types out text character by character.
552
+ // ─────────────────────────────────────────────────────────────
553
+ async function animateTyping(text, color = C.dim, speed = 'normal', opts) {
554
+ const w = opts?.writer ?? defaultWriter;
555
+ const delay = getDelay(speed);
556
+ w(color);
557
+ for (const ch of text) {
558
+ w(ch);
559
+ await sleep(delay.char);
560
+ }
561
+ w(C.reset);
562
+ }
563
+ // ─────────────────────────────────────────────────────────────
564
+ // Animation 6: Session end — fade out with status
565
+ // ─────────────────────────────────────────────────────────────
566
+ async function animateSessionEnd(stats, speed = 'normal', opts) {
567
+ const w = opts?.writer ?? defaultWriter;
568
+ const delay = getDelay(speed);
569
+ const summaryText = sessionSummaryBanner(stats);
570
+ const lines = summaryText.split('\n');
571
+ w(ANSI.hideCursor);
572
+ try {
573
+ for (const line of lines) {
574
+ w(line + '\n');
575
+ if (stripAnsi(line).trim().length > 0) {
576
+ await sleep(delay.line);
577
+ }
578
+ }
579
+ }
580
+ finally {
581
+ w(ANSI.showCursor);
582
+ }
583
+ }
584
+ // ─────────────────────────────────────────────────────────────
585
+ // Utility: Check if animations should run
586
+ // Only animate in interactive TTY terminals.
587
+ // ─────────────────────────────────────────────────────────────
588
+ function shouldAnimate() {
589
+ return !!(process.stdout.isTTY) && process.env.TERM !== 'dumb' && !process.env.CI;
590
+ }
330
591
  //# 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.1.1';
55
+ const VERSION = '2.1.3';
56
56
  const C = {
57
57
  reset: '\x1b[0m',
58
58
  bold: '\x1b[1m',
@@ -270,16 +270,30 @@ async function main() {
270
270
  }
271
271
  const session = new history_1.SessionManager(config.model, resumeId);
272
272
  const sessionShort = session.getId().substring(0, 8);
273
- console.log((0, banner_1.banner)(VERSION, config.model, `${config.provider} @ ${config.baseUrl}`, `${sessionShort}...`, !!config.autoApprove));
274
- if (resumeId) {
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'));
273
+ const providerLabel = `${config.provider} @ ${config.baseUrl}`;
274
+ const isAuto = !!config.autoApprove;
275
+ const noAnimate = args['no-animate'] === true || args['no-animation'] === true;
276
+ if ((0, banner_1.shouldAnimate)() && !noAnimate) {
277
+ await (0, banner_1.animateBootSequence)(banner_1.banner, VERSION, config.model, providerLabel, `${sessionShort}...`, isAuto, 'fast');
278
+ if (resumeId) {
279
+ console.log(c(` ${(0, banner_1.randomGreeting)('resuming')}`, 'green'));
280
+ }
281
+ else if (isAuto) {
282
+ console.log((0, banner_1.formatReaction)('autonomous_start'));
283
+ }
280
284
  }
281
285
  else {
282
- console.log(c(` ${(0, banner_1.randomGreeting)()}\n`, 'dim'));
286
+ console.log((0, banner_1.banner)(VERSION, config.model, providerLabel, `${sessionShort}...`, isAuto));
287
+ if (resumeId) {
288
+ console.log(c(` ${(0, banner_1.randomGreeting)('resuming')}`, 'green'));
289
+ }
290
+ else if (isAuto) {
291
+ console.log(c(` ${(0, banner_1.randomGreeting)('confident')}`, 'dim'));
292
+ console.log((0, banner_1.formatReaction)('autonomous_start'));
293
+ }
294
+ else {
295
+ console.log(c(` ${(0, banner_1.randomGreeting)()}\n`, 'dim'));
296
+ }
283
297
  }
284
298
  const agent = new agent_1.Agent({
285
299
  provider,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const VERSION = "2.1.1";
1
+ export declare const VERSION = "2.1.3";
2
2
  export { Agent } from './agent';
3
3
  export { OpenAIProvider } from './providers/openai';
4
4
  export { AnthropicProvider } from './providers/anthropic';
@@ -28,7 +28,7 @@ export { PolicyEnforcer, loadPolicy, generateDefaultPolicyFile } from './policy'
28
28
  export type { Policy, PolicyRbac, PolicyRole } from './policy';
29
29
  export { encrypt, decrypt, encryptLine, decryptLine, encryptContent, decryptContent, isEncryptionEnabled, deriveKey, getPassphrase } from './encryption';
30
30
  export type { EncryptionConfig } from './encryption';
31
- export { banner, randomGreeting, compactBanner, formatReaction, codiReact, sessionSummaryBanner, randomBanner, CODI_FACE, BANNER_1, BANNER_2, BANNER_3 } from './banner';
32
- export type { CodiMood, CodiReaction } from './banner';
31
+ export { banner, randomGreeting, compactBanner, formatReaction, codiReact, sessionSummaryBanner, randomBanner, CODI_FACE, BANNER_1, BANNER_2, BANNER_3, animateReveal, animateVisorScan, animateEyeBoot, animateBootSequence, animateTyping, animateSessionEnd, shouldAnimate } from './banner';
32
+ export type { CodiMood, CodiReaction, AnimationSpeed, AnimationWriter, AnimationOptions } from './banner';
33
33
  export * from './types';
34
34
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -15,8 +15,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.BANNER_1 = exports.CODI_FACE = exports.randomBanner = exports.sessionSummaryBanner = exports.codiReact = exports.formatReaction = exports.compactBanner = exports.randomGreeting = exports.banner = exports.getPassphrase = exports.deriveKey = exports.isEncryptionEnabled = exports.decryptContent = exports.encryptContent = exports.decryptLine = exports.encryptLine = exports.decrypt = exports.encrypt = exports.generateDefaultPolicyFile = exports.loadPolicy = exports.PolicyEnforcer = exports.sarifToString = exports.exportSarif = exports.RiskScorer = exports.MetricsCollector = exports.listReplayableSessions = exports.compareOutputs = exports.loadSessionForReplay = exports.ReplayProvider = exports.verifyMessages = exports.verifyMessage = exports.signMessage = exports.deriveSessionKey = exports.CapabilityChecker = exports.detectProvider = exports.getModelInfo = exports.PROVIDER_DEFAULTS = exports.MODEL_REGISTRY = exports.loadMCPTools = exports.loadPlugins = exports.parseToolCalls = exports.MemoryManager = exports.SessionManager = exports.buildRepoMap = exports.ContextManager = exports.ToolRegistry = exports.AnthropicProvider = exports.OpenAIProvider = exports.Agent = exports.VERSION = void 0;
18
- exports.BANNER_3 = exports.BANNER_2 = void 0;
19
- exports.VERSION = '2.1.1';
18
+ exports.shouldAnimate = exports.animateSessionEnd = exports.animateTyping = exports.animateBootSequence = exports.animateEyeBoot = exports.animateVisorScan = exports.animateReveal = exports.BANNER_3 = exports.BANNER_2 = void 0;
19
+ exports.VERSION = '2.1.3';
20
20
  var agent_1 = require("./agent");
21
21
  Object.defineProperty(exports, "Agent", { enumerable: true, get: function () { return agent_1.Agent; } });
22
22
  var openai_1 = require("./providers/openai");
@@ -89,5 +89,12 @@ Object.defineProperty(exports, "CODI_FACE", { enumerable: true, get: function ()
89
89
  Object.defineProperty(exports, "BANNER_1", { enumerable: true, get: function () { return banner_1.BANNER_1; } });
90
90
  Object.defineProperty(exports, "BANNER_2", { enumerable: true, get: function () { return banner_1.BANNER_2; } });
91
91
  Object.defineProperty(exports, "BANNER_3", { enumerable: true, get: function () { return banner_1.BANNER_3; } });
92
+ Object.defineProperty(exports, "animateReveal", { enumerable: true, get: function () { return banner_1.animateReveal; } });
93
+ Object.defineProperty(exports, "animateVisorScan", { enumerable: true, get: function () { return banner_1.animateVisorScan; } });
94
+ Object.defineProperty(exports, "animateEyeBoot", { enumerable: true, get: function () { return banner_1.animateEyeBoot; } });
95
+ Object.defineProperty(exports, "animateBootSequence", { enumerable: true, get: function () { return banner_1.animateBootSequence; } });
96
+ Object.defineProperty(exports, "animateTyping", { enumerable: true, get: function () { return banner_1.animateTyping; } });
97
+ Object.defineProperty(exports, "animateSessionEnd", { enumerable: true, get: function () { return banner_1.animateSessionEnd; } });
98
+ Object.defineProperty(exports, "shouldAnimate", { enumerable: true, get: function () { return banner_1.shouldAnimate; } });
92
99
  __exportStar(require("./types"), exports);
93
100
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebot-ai",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "Zero-dependency autonomous AI agent. Code, browse, search, automate. Works with any LLM — Ollama, Claude, GPT, Gemini, DeepSeek, Groq, Mistral, Grok.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",