@cli-use/tui 0.1.0 → 0.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/README.md CHANGED
@@ -1,40 +1,75 @@
1
1
  # cli-use
2
2
 
3
- > Build beautiful terminal user interfaces with Ink
3
+ > Build beautiful terminal user interfaces with React & Native Rust
4
4
 
5
- A powerful TUI (Terminal User Interface) framework using **Ink** (React for CLIs). Create stunning terminal interfaces with tables, lists, markdown rendering, custom styles, and flex-like layouts.
5
+ **cli-use** is a powerful framework for building stunning terminal applications. It combines the ease of **React** for standard TUIs with a high-performance **Native Rust/Ratatui** engine for advanced, AI-powered interfaces.
6
6
 
7
7
  ## 🎯 Overview
8
8
 
9
- `cli-use` lets you build beautiful terminal applications using **Ink** - the most popular React-based TUI framework. Create tables, lists, markdown rendering, custom styles, and flex-like layouts - all with React components you already know.
9
+ - **React**: Build interactive CLIs using React components (Tables, Lists, Markdown, Flexbox).
10
+ - **Rust/Ratatui**: Experience ultra-fast, native TUI performance for specialized tools like our AI terminal.
10
11
 
11
12
  ## ✨ Features
12
13
 
13
- - **🎨 Beautiful Styling** - CSS-like properties for stunning interfaces
14
- - **📊 Tables** - Render beautiful tables with borders, colors, and alignment
15
- - **📝 Lists** - Create interactive lists with selection states and custom enumerators
16
- - **📖 Markdown** - Render markdown with themes
17
- - **📐 Layouts** - Flex-like horizontal/vertical layouts
18
- - **🔧 TypeScript** - Full type safety and excellent IDE support
19
- - **⚡ Cross-Platform** - Works on macOS, Linux, and Windows
14
+ - **🤖 AI-Powered Terminal** - Integrated Google Gemini AI chat client (Native Rust).
15
+ - **🎨 Beautiful Styling** - CSS-like properties for stunning interfaces.
16
+ - **📊 Rich Components** - Tables, Lists, Markdown, and Layouts out of the box.
17
+ - **⚡ Hybrid Architecture** - Uses Node.js for flexibility and Rust for raw TUI performance.
18
+ - **🔧 TypeScript** - Full type safety and excellent IDE support.
20
19
 
21
20
  ## 🚀 Quick Start
22
21
 
22
+ ### 1. Install via NPM
23
+
24
+ ```bash
25
+ npm install -g cli-use
26
+ ```
27
+
28
+ ### 2. Configure AI (Optional)
29
+
30
+ To use the AI features (`cli-use code`), you need to set your Google Gemini API key.
31
+
32
+ 1. Get a [Google AI Studio API Key](https://aistudio.google.com/app/apikey).
33
+ 2. Set it in your environment:
34
+
23
35
  ```bash
24
- # Install
25
- npm install cli-use
36
+ # Set in your current session
37
+ export GOOGLE_API_KEY=your_key_here
26
38
 
27
- # Run the demo
28
- npm run example:ink-demo
39
+ # OR create a .env file in the directory where you run the command
40
+ echo "GOOGLE_API_KEY=your_key_here" > .env
29
41
  ```
30
42
 
31
- ## 💡 Examples
43
+ ### 3. Run the AI Terminal
44
+
45
+ Launch the high-performance AI chat interface:
46
+
47
+ ```bash
48
+ cli-use code
49
+ ```
50
+
51
+ ## 🤖 CLI CODE (AI Terminal)
52
+
53
+ The `cli-use code` command launches a native Rust application that integrates with **Google Gemini**.
54
+
55
+ - **Splash Screen**: Instant startup with a stylized "CLI CODE" ASCII art.
56
+ - **Instant Input**: Start typing your query immediately on the home screen.
57
+ - **Streaming Responses**: Real-time AI streaming powered by Vercel AI SDK (Node.js) and Ratatui (Rust).
58
+ - **Performance**: Zero-latency UI rendering thanks to the native Rust backend.
59
+
60
+ **Prerequisites for Native Features:**
61
+
62
+ - [Rust installed](https://rustup.rs/) (automatically detected and built during install).
63
+
64
+ ## 💡 React Examples
65
+
66
+ You can also build standard React-based CLIs.
32
67
 
33
68
  ### Basic App
34
69
 
35
70
  ```tsx
36
71
  import React from 'react';
37
- import { render, Box, Text } from 'ink';
72
+ import { render, Box, Text } from 'cli-use';
38
73
 
39
74
  const App = () => (
40
75
  <Box borderStyle="round" padding={1}>
@@ -49,13 +84,13 @@ render(<App />);
49
84
 
50
85
  ```tsx
51
86
  import React, { useState } from 'react';
52
- import { render, Box, Text, useInput } from 'ink';
87
+ import { render, Box, Text, useInput } from 'cli-use';
53
88
 
54
89
  const Counter = () => {
55
90
  const [count, setCount] = useState(0);
56
91
 
57
92
  useInput((input, key) => {
58
- if (key.return) setCount(c => c + 1);
93
+ if (key.return) setCount((c) => c + 1);
59
94
  });
60
95
 
61
96
  return (
@@ -75,7 +110,7 @@ render(<Counter />);
75
110
 
76
111
  - **`Box`** - Container component for layout and styling
77
112
  - **`Text`** - Text rendering with colors and styles
78
- - **`render()`** - Render Ink apps to terminal
113
+ - **`render()`** - Render cli-use apps to terminal
79
114
  - **`useInput()`** - Handle keyboard input
80
115
  - **`useApp()`** - App instance management
81
116
 
@@ -85,30 +120,30 @@ render(<Counter />);
85
120
  # Install dependencies
86
121
  npm install
87
122
 
88
- # Build
123
+ # Build the project (including Rust native binary)
89
124
  npm run build
90
125
 
91
- # Run tests
92
- npm run test:unit
93
-
94
- # Type check
95
- npm run typecheck
126
+ # Run the AI Terminal (Dev Mode)
127
+ npm run demo:rust
96
128
 
97
- # Run demo
98
- npm run example:ink-demo
129
+ # Run React Examples
130
+ npm run demo:cli-use
99
131
  ```
100
132
 
101
133
  ## 📁 Project Structure
102
134
 
103
135
  ```
104
136
  cli-use/
137
+ ├── native/ # Rust/Ratatui source code
138
+ │ └── src/
139
+ │ └── main.rs # Native TUI entry point
105
140
  ├── src/
106
- │ ├── renderer/
107
- │ └── terminal.ts # Terminal handling
108
- └── examples/
109
- └── ink-demo.tsx # Interactive demo
141
+ │ ├── ai-worker.ts # Node.js AI Bridge (Vercel AI SDK)
142
+ ├── cli/ # CLI Entry point
143
+ ├── components/ # React components
144
+ │ └── examples/ # Example apps
145
+ │ └── cli-use-demo.tsx # React/cli-use Demo
110
146
  ├── package.json
111
- ├── tsconfig.json
112
147
  └── README.md
113
148
  ```
114
149
 
@@ -122,4 +157,4 @@ MIT © 2025 cli-use contributors
122
157
 
123
158
  ---
124
159
 
125
- **Built with ❤️ and Ink**
160
+ **Built with ❤️, React, and Rust**
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @license MIT
3
+ * cli-use - React-based Terminal UI Framework
4
+ * Inspired by Ratatui (https://ratatui.rs)
5
+ */
6
+ "use strict";
7
+ var __create = Object.create;
8
+ var __defProp = Object.defineProperty;
9
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
10
+ var __getOwnPropNames = Object.getOwnPropertyNames;
11
+ var __getProtoOf = Object.getPrototypeOf;
12
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+
30
+ // src/ai-worker.ts
31
+ var import_google = require("@ai-sdk/google");
32
+ var import_ai = require("ai");
33
+ var import_dotenv = __toESM(require("dotenv"), 1);
34
+ var import_readline = __toESM(require("readline"), 1);
35
+ import_dotenv.default.config();
36
+ var apiKey = process.env.GOOGLE_GENERATIVE_AI_API_KEY || process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
37
+ if (!apiKey) {
38
+ console.error(
39
+ "Error: No API Key found. Set GOOGLE_GENERATIVE_AI_API_KEY or GEMINI_API_KEY in .env"
40
+ );
41
+ process.exit(1);
42
+ }
43
+ var google = (0, import_google.createGoogleGenerativeAI)({
44
+ apiKey
45
+ });
46
+ var rl = import_readline.default.createInterface({
47
+ input: process.stdin,
48
+ output: process.stdout,
49
+ terminal: false
50
+ });
51
+ rl.on("line", async (line) => {
52
+ const prompt = line.trim();
53
+ if (!prompt) return;
54
+ try {
55
+ const { text } = await (0, import_ai.generateText)({
56
+ model: google("models/gemini-2.0-flash"),
57
+ // Updated to available model
58
+ prompt
59
+ });
60
+ console.log(text.replace(/\n/g, "\\n"));
61
+ } catch (error) {
62
+ console.error("AI Error:", error);
63
+ }
64
+ });
65
+ //# sourceMappingURL=ai-worker.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ai-worker.ts"],"sourcesContent":["import { createGoogleGenerativeAI } from '@ai-sdk/google';\nimport { generateText } from 'ai';\nimport dotenv from 'dotenv';\nimport readline from 'readline';\n\ndotenv.config();\n\n// Support multiple potential env var names for flexibility\nconst apiKey =\n process.env.GOOGLE_GENERATIVE_AI_API_KEY ||\n process.env.GEMINI_API_KEY ||\n process.env.GOOGLE_API_KEY;\n\nif (!apiKey) {\n console.error(\n 'Error: No API Key found. Set GOOGLE_GENERATIVE_AI_API_KEY or GEMINI_API_KEY in .env'\n );\n process.exit(1);\n}\n\nconst google = createGoogleGenerativeAI({\n apiKey: apiKey,\n});\n\nconst rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n terminal: false,\n});\n\nrl.on('line', async (line) => {\n const prompt = line.trim();\n if (!prompt) return;\n\n try {\n const { text } = await generateText({\n model: google('models/gemini-2.0-flash'), // Updated to available model\n prompt: prompt,\n });\n\n // Output text handling for Rust consumption\n console.log(text.replace(/\\n/g, '\\\\n'));\n } catch (error) {\n console.error('AI Error:', error);\n }\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oBAAyC;AACzC,gBAA6B;AAC7B,oBAAmB;AACnB,sBAAqB;AAErB,cAAAA,QAAO,OAAO;AAGd,IAAM,SACJ,QAAQ,IAAI,gCACZ,QAAQ,IAAI,kBACZ,QAAQ,IAAI;AAEd,IAAI,CAAC,QAAQ;AACX,UAAQ;AAAA,IACN;AAAA,EACF;AACA,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,aAAS,wCAAyB;AAAA,EACtC;AACF,CAAC;AAED,IAAM,KAAK,gBAAAC,QAAS,gBAAgB;AAAA,EAClC,OAAO,QAAQ;AAAA,EACf,QAAQ,QAAQ;AAAA,EAChB,UAAU;AACZ,CAAC;AAED,GAAG,GAAG,QAAQ,OAAO,SAAS;AAC5B,QAAM,SAAS,KAAK,KAAK;AACzB,MAAI,CAAC,OAAQ;AAEb,MAAI;AACF,UAAM,EAAE,KAAK,IAAI,UAAM,wBAAa;AAAA,MAClC,OAAO,OAAO,yBAAyB;AAAA;AAAA,MACvC;AAAA,IACF,CAAC;AAGD,YAAQ,IAAI,KAAK,QAAQ,OAAO,KAAK,CAAC;AAAA,EACxC,SAAS,OAAO;AACd,YAAQ,MAAM,aAAa,KAAK;AAAA,EAClC;AACF,CAAC;","names":["dotenv","readline"]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @license MIT
3
+ * cli-use - React-based Terminal UI Framework
4
+ * Inspired by Ratatui (https://ratatui.rs)
5
+ */
6
+
7
+ // src/ai-worker.ts
8
+ import { createGoogleGenerativeAI } from "@ai-sdk/google";
9
+ import { generateText } from "ai";
10
+ import dotenv from "dotenv";
11
+ import readline from "readline";
12
+ dotenv.config();
13
+ var apiKey = process.env.GOOGLE_GENERATIVE_AI_API_KEY || process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
14
+ if (!apiKey) {
15
+ console.error(
16
+ "Error: No API Key found. Set GOOGLE_GENERATIVE_AI_API_KEY or GEMINI_API_KEY in .env"
17
+ );
18
+ process.exit(1);
19
+ }
20
+ var google = createGoogleGenerativeAI({
21
+ apiKey
22
+ });
23
+ var rl = readline.createInterface({
24
+ input: process.stdin,
25
+ output: process.stdout,
26
+ terminal: false
27
+ });
28
+ rl.on("line", async (line) => {
29
+ const prompt = line.trim();
30
+ if (!prompt) return;
31
+ try {
32
+ const { text } = await generateText({
33
+ model: google("models/gemini-2.0-flash"),
34
+ // Updated to available model
35
+ prompt
36
+ });
37
+ console.log(text.replace(/\n/g, "\\n"));
38
+ } catch (error) {
39
+ console.error("AI Error:", error);
40
+ }
41
+ });
42
+ //# sourceMappingURL=ai-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ai-worker.ts"],"sourcesContent":["import { createGoogleGenerativeAI } from '@ai-sdk/google';\nimport { generateText } from 'ai';\nimport dotenv from 'dotenv';\nimport readline from 'readline';\n\ndotenv.config();\n\n// Support multiple potential env var names for flexibility\nconst apiKey =\n process.env.GOOGLE_GENERATIVE_AI_API_KEY ||\n process.env.GEMINI_API_KEY ||\n process.env.GOOGLE_API_KEY;\n\nif (!apiKey) {\n console.error(\n 'Error: No API Key found. Set GOOGLE_GENERATIVE_AI_API_KEY or GEMINI_API_KEY in .env'\n );\n process.exit(1);\n}\n\nconst google = createGoogleGenerativeAI({\n apiKey: apiKey,\n});\n\nconst rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n terminal: false,\n});\n\nrl.on('line', async (line) => {\n const prompt = line.trim();\n if (!prompt) return;\n\n try {\n const { text } = await generateText({\n model: google('models/gemini-2.0-flash'), // Updated to available model\n prompt: prompt,\n });\n\n // Output text handling for Rust consumption\n console.log(text.replace(/\\n/g, '\\\\n'));\n } catch (error) {\n console.error('AI Error:', error);\n }\n});\n"],"mappings":";;;;;;;AAAA,SAAS,gCAAgC;AACzC,SAAS,oBAAoB;AAC7B,OAAO,YAAY;AACnB,OAAO,cAAc;AAErB,OAAO,OAAO;AAGd,IAAM,SACJ,QAAQ,IAAI,gCACZ,QAAQ,IAAI,kBACZ,QAAQ,IAAI;AAEd,IAAI,CAAC,QAAQ;AACX,UAAQ;AAAA,IACN;AAAA,EACF;AACA,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,SAAS,yBAAyB;AAAA,EACtC;AACF,CAAC;AAED,IAAM,KAAK,SAAS,gBAAgB;AAAA,EAClC,OAAO,QAAQ;AAAA,EACf,QAAQ,QAAQ;AAAA,EAChB,UAAU;AACZ,CAAC;AAED,GAAG,GAAG,QAAQ,OAAO,SAAS;AAC5B,QAAM,SAAS,KAAK,KAAK;AACzB,MAAI,CAAC,OAAQ;AAEb,MAAI;AACF,UAAM,EAAE,KAAK,IAAI,MAAM,aAAa;AAAA,MAClC,OAAO,OAAO,yBAAyB;AAAA;AAAA,MACvC;AAAA,IACF,CAAC;AAGD,YAAQ,IAAI,KAAK,QAAQ,OAAO,KAAK,CAAC;AAAA,EACxC,SAAS,OAAO;AACd,YAAQ,MAAM,aAAa,KAAK;AAAA,EAClC;AACF,CAAC;","names":[]}
Binary file
@@ -41,47 +41,132 @@ var init_cjs_shims = __esm({
41
41
  }
42
42
  });
43
43
 
44
- // src/examples/ink-demo.tsx
45
- var ink_demo_exports = {};
46
- var import_react, import_ink, import_jsx_runtime, Counter;
47
- var init_ink_demo = __esm({
48
- "src/examples/ink-demo.tsx"() {
44
+ // src/examples/cli-use-demo.tsx
45
+ var cli_use_demo_exports = {};
46
+ var import_react, import_ink, import_jsx_runtime, CLAUDE_ORANGE, FOOTER_TEXT, FOOTER_HIGHLIGHT, LOGO_TEXT, Splash, Chat, App;
47
+ var init_cli_use_demo = __esm({
48
+ "src/examples/cli-use-demo.tsx"() {
49
49
  "use strict";
50
50
  init_cjs_shims();
51
51
  import_react = require("react");
52
52
  import_ink = require("ink");
53
53
  import_jsx_runtime = require("react/jsx-runtime");
54
- Counter = () => {
55
- const [count, setCount] = (0, import_react.useState)(0);
56
- (0, import_ink.useInput)((input, key) => {
57
- if (key.escape || key.ctrl("c")) {
54
+ CLAUDE_ORANGE = "#D97757";
55
+ FOOTER_TEXT = "#708090";
56
+ FOOTER_HIGHLIGHT = "#FFFFFF";
57
+ LOGO_TEXT = `
58
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557
59
+ \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551
60
+ \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
61
+ \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
62
+ \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551
63
+ \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D
64
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
65
+ \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
66
+ \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557
67
+ \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D
68
+ \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
69
+ \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D
70
+ `;
71
+ Splash = ({ input }) => {
72
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", alignItems: "center", height: "100%", justifyContent: "space-between", children: [
73
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { marginTop: 2, marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { borderStyle: "round", borderColor: CLAUDE_ORANGE, paddingX: 2, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: CLAUDE_ORANGE, bold: true, children: "Welcome to the Claude Code research preview!" }) }) }),
74
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { marginBottom: 2, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: CLAUDE_ORANGE, children: LOGO_TEXT }) }),
75
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
76
+ import_ink.Box,
77
+ {
78
+ width: "100%",
79
+ borderStyle: "single",
80
+ borderColor: "gray",
81
+ paddingX: 1,
82
+ marginBottom: 1,
83
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", bold: true, children: [
84
+ ">",
85
+ " ",
86
+ input,
87
+ "_"
88
+ ] })
89
+ }
90
+ ),
91
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { marginBottom: 2, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: FOOTER_TEXT, children: [
92
+ "\u{1F389} Login successful. Press",
93
+ " ",
94
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: FOOTER_HIGHLIGHT, bold: true, children: "Enter" }),
95
+ " ",
96
+ "to continue"
97
+ ] }) })
98
+ ] });
99
+ };
100
+ Chat = ({ messages, input }) => {
101
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", height: "100%", children: [
102
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { flexDirection: "column", flexGrow: 1, children: messages.map((msg, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { flexDirection: "column", marginLeft: msg.type === "output" ? 2 : 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { children: [
103
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
104
+ import_ink.Text,
105
+ {
106
+ color: msg.type === "user" ? "cyan" : msg.type === "thinking" ? "yellow" : msg.type === "tool" ? "blue" : msg.type === "system" ? "magenta" : "gray",
107
+ bold: msg.type === "user",
108
+ children: msg.symbol
109
+ }
110
+ ),
111
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: msg.type === "output" ? "gray" : "white", children: [
112
+ " ",
113
+ msg.content
114
+ ] })
115
+ ] }) }, i)) }),
116
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", bold: true, children: [
117
+ ">",
118
+ " ",
119
+ input,
120
+ "_"
121
+ ] }) })
122
+ ] });
123
+ };
124
+ App = () => {
125
+ const [mode, setMode] = (0, import_react.useState)("splash");
126
+ const [input, setInput] = (0, import_react.useState)("");
127
+ const [messages, setMessages] = (0, import_react.useState)([
128
+ { type: "system", symbol: "*", content: "Welcome to CLI CODE." },
129
+ { type: "system", symbol: "*", content: "I am ready to assist. Type anything to chat." }
130
+ ]);
131
+ (0, import_ink.useInput)((keyInput, key) => {
132
+ if (key.escape || key.ctrl && keyInput === "c") {
58
133
  process.exit(0);
59
134
  }
60
135
  if (key.return) {
61
- setCount((c) => c + 1);
136
+ if (mode === "splash") {
137
+ setMode("chat");
138
+ if (input.trim()) {
139
+ addMessage("user", ">", input);
140
+ addMessage("thinking", "\u23FA", "Processing...");
141
+ setTimeout(() => {
142
+ addMessage("output", "\u23BF", "This is a simulated response in the cli-use demo.");
143
+ }, 1e3);
144
+ setInput("");
145
+ }
146
+ } else {
147
+ if (input.trim()) {
148
+ addMessage("user", ">", input);
149
+ addMessage("thinking", "\u23FA", "Processing...");
150
+ setTimeout(() => {
151
+ addMessage("output", "\u23BF", "This is a simulated response in the cli-use demo.");
152
+ }, 1e3);
153
+ setInput("");
154
+ }
155
+ }
156
+ return;
157
+ }
158
+ if (key.delete || key.backspace) {
159
+ setInput((prev) => prev.slice(0, -1));
160
+ } else {
161
+ setInput((prev) => prev + keyInput);
62
162
  }
63
163
  });
64
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", padding: 1, children: [
65
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { borderStyle: "double", borderColor: "cyan", padding: 1, marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { bold: true, color: "magenta", children: "\u2728 cli-use Demo - Beautiful Terminal UIs (Ink)" }) }),
66
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { borderStyle: "single", borderColor: "blue", padding: 1, marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", gap: 1, children: [
67
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { bold: true, children: "Features:" }),
68
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: "\u2022 Cross-platform (macOS, Linux, Windows)" }),
69
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: "\u2022 React-based components" }),
70
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: "\u2022 Beautiful styling out of the box" }),
71
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: "\u2022 TypeScript support" })
72
- ] }) }),
73
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { borderStyle: "round", borderColor: "green", padding: 1, marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", alignItems: "center", gap: 1, children: [
74
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { bold: true, color: "green", children: "\u{1F522} Interactive Counter" }),
75
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { children: [
76
- "Count: ",
77
- count
78
- ] }),
79
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { dim: true, children: "Press Enter to increment, ESC to exit" })
80
- ] }) }),
81
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { dim: true, color: "gray", children: "Built with \u2764\uFE0F for beautiful terminal interfaces" }) })
82
- ] });
164
+ const addMessage = (type, symbol, content) => {
165
+ setMessages((prev) => [...prev, { type, symbol, content }]);
166
+ };
167
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { flexDirection: "column", minHeight: 20, children: mode === "splash" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Splash, { input, onEnter: () => setMode("chat") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chat, { messages, input }) });
83
168
  };
84
- (0, import_ink.render)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Counter, {}));
169
+ (0, import_ink.render)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(App, {}));
85
170
  }
86
171
  });
87
172
 
@@ -89,11 +174,10 @@ var init_ink_demo = __esm({
89
174
  init_cjs_shims();
90
175
  var import_commander = require("commander");
91
176
  var import_chalk = __toESM(require("chalk"), 1);
92
- var import_module = require("module");
93
177
  var import_child_process = require("child_process");
94
178
  var import_url = require("url");
95
179
  var import_path = __toESM(require("path"), 1);
96
- var require2 = (0, import_module.createRequire)(importMetaUrl);
180
+ var import_fs = __toESM(require("fs"), 1);
97
181
  var __filename2 = (0, import_url.fileURLToPath)(importMetaUrl);
98
182
  var __dirname = import_path.default.dirname(__filename2);
99
183
  var program = new import_commander.Command();
@@ -117,11 +201,14 @@ program.command("run <example>").description("Run an example application").actio
117
201
  program.command("examples").description("List available examples").action(() => {
118
202
  showExamplesTUI();
119
203
  });
120
- program.option("-d, --demo", "Run the ink demo").action(() => {
204
+ program.command("code").description("Launch the AI-powered CLI Code interface").action(() => {
205
+ showRustDemo();
206
+ });
207
+ program.option("-d, --demo", "Run the cli-use demo").action(() => {
121
208
  });
122
209
  var options = program.parse(process.argv);
123
210
  if (options.opts().demo) {
124
- Promise.resolve().then(() => (init_ink_demo(), ink_demo_exports)).catch((err) => {
211
+ Promise.resolve().then(() => (init_cli_use_demo(), cli_use_demo_exports)).catch((err) => {
125
212
  console.error("Failed to run demo:", err);
126
213
  process.exit(1);
127
214
  });
@@ -129,12 +216,15 @@ if (options.opts().demo) {
129
216
  function showRustDemo() {
130
217
  const isWindows = process.platform === "win32";
131
218
  const extension = isWindows ? ".exe" : "";
132
- const binaryPath = import_path.default.resolve(
219
+ const prodBinaryPath = import_path.default.resolve(__dirname, `../bin/ratatui-demo${extension}`);
220
+ const devBinaryPath = import_path.default.resolve(
133
221
  __dirname,
134
222
  `../../native/target/release/ratatui-demo${extension}`
135
223
  );
224
+ const binaryPath = import_fs.default.existsSync(prodBinaryPath) ? prodBinaryPath : devBinaryPath;
225
+ const workerPath = import_path.default.resolve(__dirname, "../ai-worker.js");
136
226
  console.log(import_chalk.default.cyan("Starting Ratatui Demo..."));
137
- const child = (0, import_child_process.spawn)(binaryPath, [], {
227
+ const child = (0, import_child_process.spawn)(binaryPath, [workerPath], {
138
228
  stdio: "inherit"
139
229
  });
140
230
  child.on("error", (err) => {