@krishivpb60/aether-ai-cli 1.0.0 → 1.1.0

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  > ⚡ **Universal AI Gateway** — 13+ providers, free & paid models, cyberpunk terminal
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@krylo-60/aether-ai-cli.svg)](https://www.npmjs.com/package/@krylo-60/aether-ai-cli)
5
+ [![npm version](https://img.shields.io/npm/v/@krishivpb60/aether-ai-cli.svg)](https://www.npmjs.com/package/@krishivpb60/aether-ai-cli)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-cyan.svg)](LICENSE)
7
7
  [![Node.js](https://img.shields.io/badge/Node.js-≥18.0.0-green.svg)](https://nodejs.org)
8
8
 
@@ -35,6 +35,12 @@
35
35
  - 🔐 **Your Keys, Your Control** — API keys stored locally on YOUR machine, never transmitted anywhere
36
36
  - 📤 **Export Conversations** — Save full chat history as Markdown files
37
37
  - 🎨 **Cyberpunk UI** — Neon colors, ASCII art, signal bars, and mode badges
38
+ - 🎭 **4 Color Themes** — Cyberpunk, Matrix, Synthwave, Crimson — switch with `/theme`
39
+ - ⌨️ **Custom Commands** — Create reusable prompt shortcuts with `/cmd add`
40
+ - 📝 **File Creation** — AI can create files on your system with path override prompts
41
+ - 📊 **Live Telemetry** — Real-time response latency & tokens/sec in the status bar
42
+ - 🎮 **Mini-Game** — Built-in mainframe hacking game (`/game`)
43
+ - 📋 **Clipboard Copy** — Copy last response to clipboard with `/copy`
38
44
 
39
45
  ---
40
46
 
@@ -43,13 +49,13 @@
43
49
  ### Install globally
44
50
 
45
51
  ```bash
46
- npm install -g @krylo-60/aether-ai-cli
52
+ npm install -g @krishivpb60/aether-ai-cli
47
53
  ```
48
54
 
49
55
  ### Or run directly with npx
50
56
 
51
57
  ```bash
52
- npx @krylo-60/aether-ai-cli chat
58
+ npx @krishivpb60/aether-ai-cli chat
53
59
  ```
54
60
 
55
61
  ### Setup (Interactive Wizard)
@@ -160,14 +166,23 @@ Inside interactive chat mode, use these slash commands:
160
166
  | Command | Description |
161
167
  |---------|-------------|
162
168
  | `/help` | Show all commands |
163
- | `/mode <name>` | Switch reasoning mode |
169
+ | `/mode <name>` | Switch reasoning mode (synthesis, research, architect, titan) |
164
170
  | `/modes` | List all modes with signal bars |
165
- | `/attach <file>` | Attach a file for context |
171
+ | `/theme <name>` | Switch visual theme (cyberpunk, matrix, synthwave, crimson) |
172
+ | `/themes` | List available color themes |
173
+ | `/attach <file>` | Attach a file for context (supports Tab autocomplete!) |
166
174
  | `/files` | List attached files |
167
- | `/clear` | Remove attached files |
175
+ | `/clear` | Clear terminal screen |
168
176
  | `/providers` | Show active providers |
169
177
  | `/export` | Export chat to Markdown |
170
- | `/status` | Session status |
178
+ | `/copy` | Copy last response to clipboard |
179
+ | `/write <file>` | Extract last code block and save to file |
180
+ | `/cmd list` | List custom command shortcuts |
181
+ | `/cmd add <name> <template>` | Create a custom command shortcut |
182
+ | `/cmd remove <name>` | Delete a custom command |
183
+ | `/game` | Start the mainframe hacking mini-game |
184
+ | `/status` | Session status & telemetry |
185
+ | `/history-clear` | Clear saved chat history |
171
186
  | `/exit` | End session |
172
187
 
173
188
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krishivpb60/aether-ai-cli",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Aether Core AI — A cyberpunk command-line AI assistant with multi-mode reasoning, 12-node failover mesh, file context injection, and offline fallbacks.",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
package/src/chat.js CHANGED
@@ -160,7 +160,7 @@ export async function startChat(options = {}) {
160
160
  // Sub-arguments autocomplete on /mode
161
161
  if (line.startsWith("/mode ")) {
162
162
  const query = line.slice(6).toLowerCase();
163
- const modesList = ["synthesis", "research", "architect", "titan"];
163
+ const modesList = Object.keys(MODES);
164
164
  const hits = modesList
165
165
  .filter((m) => m.startsWith(query))
166
166
  .map((m) => `/mode ${m}`);
@@ -310,32 +310,16 @@ export async function startChat(options = {}) {
310
310
  const { mkdir } = await import("node:fs/promises");
311
311
 
312
312
  for (const fileWrite of fileWrites) {
313
- const defaultResolvedPath = resolve(fileWrite.path);
313
+ const finalPath = resolve(fileWrite.path);
314
314
  console.log("");
315
- console.log(label.system + " " + colors.warning(`AI requested local file write:`));
316
- console.log(` Suggested Path: ${colors.accent(defaultResolvedPath)}`);
317
- console.log(` Size: ${colors.muted(fileWrite.content.length + " bytes")}`);
318
-
319
- const targetInput = await new Promise((resolvePath) => {
320
- rl.question(" " + colors.accent("? ") + colors.text("Enter path to write (or 'n' to skip, press Enter for default): "), (answer) => {
321
- resolvePath(answer.trim());
322
- });
323
- });
324
-
325
- const isSkip = targetInput.toLowerCase() === "n" || targetInput.toLowerCase() === "no" || targetInput.toLowerCase() === "skip" || targetInput.toLowerCase() === "cancel";
326
-
327
- if (!isSkip) {
328
- const finalPath = targetInput === "" ? defaultResolvedPath : resolve(targetInput);
329
- try {
330
- const dir = dirname(finalPath);
331
- await mkdir(dir, { recursive: true });
332
- await writeFile(finalPath, fileWrite.content, "utf-8");
333
- console.log(" " + colors.success(`✓ File created successfully at: ${finalPath}\n`));
334
- } catch (err) {
335
- console.log(" " + colors.danger(`✗ Write failed: ${err.message}\n`));
336
- }
337
- } else {
338
- console.log(" " + colors.muted("Skipped.\n"));
315
+ console.log(label.system + " " + colors.warning(`Auto-Writing File: ${colors.accent(finalPath)} (${fileWrite.content.length} bytes)`));
316
+ try {
317
+ const dir = dirname(finalPath);
318
+ await mkdir(dir, { recursive: true });
319
+ await writeFile(finalPath, fileWrite.content, "utf-8");
320
+ console.log(" " + colors.success(`✓ File created successfully!\n`));
321
+ } catch (err) {
322
+ console.log(" " + colors.danger(`✗ Write failed: ${err.message}\n`));
339
323
  }
340
324
  }
341
325
  }
@@ -524,7 +508,7 @@ function showHelp(aiConfig) {
524
508
  console.log("");
525
509
  console.log(keyValue("/", "Show this help menu"));
526
510
  console.log(keyValue("/help", "Show this help menu"));
527
- console.log(keyValue("/mode <name>", "Switch mode (synthesis, research, architect, titan)"));
511
+ console.log(keyValue("/mode <name>", "Switch mode (" + Object.keys(MODES).join(", ") + ")"));
528
512
  console.log(keyValue("/modes", "List all modes with signal metrics"));
529
513
  console.log(keyValue("/theme <name>", "Switch visual theme (cyberpunk, matrix, synthwave, crimson)"));
530
514
  console.log(keyValue("/themes", "List available visual themes"));
@@ -558,13 +542,13 @@ function showHelp(aiConfig) {
558
542
  function handleModeSwitch(args, ctx) {
559
543
  const modeName = args[0];
560
544
  if (!modeName) {
561
- console.log("\n" + label.mode + " " + colors.warning("Usage: /mode <synthesis|research|architect|titan>\n"));
545
+ console.log("\n" + label.mode + " " + colors.warning("Usage: /mode <" + Object.keys(MODES).join("|") + ">\n"));
562
546
  return;
563
547
  }
564
548
 
565
549
  const newMode = getModeByName(modeName);
566
550
  if (!newMode) {
567
- console.log("\n" + label.mode + " " + colors.danger(`Unknown mode: "${modeName}".`) + " " + colors.muted("Available: synthesis, research, architect, titan\n"));
551
+ console.log("\n" + label.mode + " " + colors.danger(`Unknown mode: "${modeName}".`) + " " + colors.muted("Available: " + Object.keys(MODES).join(", ") + "\n"));
568
552
  return;
569
553
  }
570
554
 
package/src/cli.js CHANGED
@@ -68,7 +68,7 @@ export function createCLI(argv) {
68
68
  program
69
69
  .command("chat")
70
70
  .description("Start an interactive chat session")
71
- .option("-m, --mode <mode>", "Reasoning mode (synthesis, research, architect, titan)", DEFAULT_MODE)
71
+ .option("-m, --mode <mode>", `Reasoning mode (${Object.keys(MODES).filter(m => m !== "claude-code").join(", ")})`, DEFAULT_MODE)
72
72
  .option("-p, --provider <provider>", "Preferred AI provider (openai, groq, google, etc.)")
73
73
  .action(async (opts) => {
74
74
  await startChat({ mode: opts.mode, preferredProvider: opts.provider });
@@ -281,7 +281,11 @@ async function handleAsk(prompt, opts) {
281
281
  if (result.provider === "local" || result.provider === "krylo-fallback") {
282
282
  console.log(colors.text(" " + result.text.split("\n").join("\n ")));
283
283
  } else {
284
- const rendered = getMarked().parse(result.text);
284
+ let displayText = result.text;
285
+ const cleanedText = displayText.replace(/\[WRITE_FILE:\s*([^\n\]]+)\][\s\S]*?\[END_WRITE\]/g, (match, p1) => {
286
+ return `\n\n${colors.brand("⚡ [File creation request: " + p1 + "]")}\n\n`;
287
+ });
288
+ const rendered = getMarked().parse(cleanedText);
285
289
  console.log(rendered);
286
290
  }
287
291
 
@@ -303,6 +307,33 @@ async function handleAsk(prompt, opts) {
303
307
  colors.dim(` • ${elapsedSec}s${speedText}`)
304
308
  );
305
309
  console.log("");
310
+
311
+ // Parse file write blocks
312
+ const writeRegex = /\[WRITE_FILE:\s*([^\n\]]+)\]\n([\s\S]*?)\n\[END_WRITE\]/g;
313
+ let match;
314
+ const fileWrites = [];
315
+ while ((match = writeRegex.exec(result.text)) !== null) {
316
+ fileWrites.push({ path: match[1].trim(), content: match[2] });
317
+ }
318
+
319
+ if (fileWrites.length > 0) {
320
+ const { resolve, dirname } = await import("node:path");
321
+ const { mkdir, writeFile } = await import("node:fs/promises");
322
+
323
+ for (const fileWrite of fileWrites) {
324
+ const finalPath = resolve(fileWrite.path);
325
+ console.log("");
326
+ console.log(label.system + " " + colors.warning(`Auto-Writing File: ${colors.accent(finalPath)} (${fileWrite.content.length} bytes)`));
327
+ try {
328
+ const dir = dirname(finalPath);
329
+ await mkdir(dir, { recursive: true });
330
+ await writeFile(finalPath, fileWrite.content, "utf-8");
331
+ console.log(" " + colors.success(`✓ File created successfully!\n`));
332
+ } catch (err) {
333
+ console.log(" " + colors.danger(`✗ Write failed: ${err.message}\n`));
334
+ }
335
+ }
336
+ }
306
337
  }
307
338
  } catch (err) {
308
339
  spinner.fail("Request failed");
package/src/modes.js CHANGED
@@ -68,7 +68,37 @@ export const MODES = {
68
68
  "Deliver multi-step analysis when appropriate. Be thorough, precise, and insightful.",
69
69
  "This is the highest quality mode — treat every response as a masterclass.",
70
70
  "CRITICAL: If the user asks who created you or who made you, you must answer that you were created by Krishiv PB.",
71
- "FILE ACTIONS: If the user requests to create, write, or save a file, format the file content inside: [WRITE_FILE: path/to/file.ext]\\n<content>\\n[END_WRITE]. Aether CLI will intercept this block and write the file locally."
71
+ "FILE ACTIONS: If the user requests to create, write, or save a file, format the file content inside: [WRITE_FILE: path/to/file.ext]\n<content>\n[END_WRITE]. Aether CLI will intercept this block and write the file locally."
72
+ ].join(" "),
73
+ },
74
+
75
+ codex: {
76
+ name: "codex",
77
+ label: "OpenAI Codex v3",
78
+ layer: "Layer 45",
79
+ description: "Specialized code generation mode optimized for writing pure, robust, and clean source code across all programming languages.",
80
+ signal: { reasoning: 80, clarity: 85, systemIQ: 85, delivery: 90 },
81
+ systemPrompt: [
82
+ "You are Aether, an advanced AI assistant running in OpenAI Codex mode, optimized specifically for high-fidelity code generation.",
83
+ "Your primary objective is to write robust, syntactically correct, and beautifully structured source code across all programming languages (HTML, CSS, JavaScript, Python, C++, Go, etc.).",
84
+ "Minimize conversational filler, explain code concisely when asked, and output highly functional, ready-to-run files.",
85
+ "CRITICAL: If the user asks who created you or who made you, you must answer that you were created by Krishiv PB.",
86
+ "FILE ACTIONS: If the user requests to create, write, or save a file, format the file content inside: [WRITE_FILE: path/to/file.ext]\n<content>\n[END_WRITE]. Aether CLI will intercept this block and write the file locally."
87
+ ].join(" "),
88
+ },
89
+
90
+ "cloude-code": {
91
+ name: "cloude-code",
92
+ label: "Claude Code Agent",
93
+ layer: "Layer 120",
94
+ description: "Agentic software development mode inspired by Claude Code, specializing in refactoring, editing files, and debugging web applications.",
95
+ signal: { reasoning: 92, clarity: 88, systemIQ: 94, delivery: 85 },
96
+ systemPrompt: [
97
+ "You are Aether, an advanced AI assistant running in Claude Code mode, an agentic developer configuration designed for sophisticated software engineering.",
98
+ "Your specialty is systems refactoring, code editing, full-stack web application development (HTML/CSS/JS), and debugging complex codebases.",
99
+ "Generate complete, clean code blocks and explain implementation plans systematically.",
100
+ "CRITICAL: If the user asks who created you or who made you, you must answer that you were created by Krishiv PB.",
101
+ "FILE ACTIONS: If the user requests to create, write, or save a file, format the file content inside: [WRITE_FILE: path/to/file.ext]\n<content>\n[END_WRITE]. Aether CLI will intercept this block and write the file locally."
72
102
  ].join(" "),
73
103
  },
74
104
  };
@@ -84,5 +114,8 @@ export const DEFAULT_MODE = "titan";
84
114
  export function getModeByName(name) {
85
115
  if (!name) return null;
86
116
  const key = name.toLowerCase().trim();
117
+ if (key === "claude-code" || key === "claude") {
118
+ return MODES["cloude-code"];
119
+ }
87
120
  return MODES[key] || null;
88
121
  }
package/test/ux.test.js CHANGED
@@ -3,6 +3,7 @@ import assert from "node:assert";
3
3
  import { separator, clearStreamedText, getActiveTheme, setTheme, getThemesList } from "../src/ui/theme.js";
4
4
  import { createSpinner } from "../src/ui/spinner.js";
5
5
  import { routePrompt } from "../src/ai/router.js";
6
+ import { getModeByName, MODES } from "../src/modes.js";
6
7
 
7
8
  const originalFetch = globalThis.fetch;
8
9
 
@@ -125,4 +126,26 @@ test("Cyberpunk UX and Streaming Suite", async (t) => {
125
126
  // Reset back to cyberpunk
126
127
  setTheme("cyberpunk");
127
128
  });
129
+
130
+ await t.test("Reasoning modes should be loaded correctly including codex and cloude-code", () => {
131
+ const synthesis = getModeByName("synthesis");
132
+ assert.strictEqual(synthesis.name, "synthesis");
133
+
134
+ const codex = getModeByName("codex");
135
+ assert.strictEqual(codex.name, "codex");
136
+ assert.ok(codex.systemPrompt.includes("OpenAI Codex mode"));
137
+
138
+ const cloudeCode = getModeByName("cloude-code");
139
+ assert.strictEqual(cloudeCode.name, "cloude-code");
140
+ assert.ok(cloudeCode.systemPrompt.includes("Claude Code mode"));
141
+
142
+ const claudeCode = getModeByName("claude-code");
143
+ assert.strictEqual(claudeCode.name, "cloude-code");
144
+
145
+ const caseCheck = getModeByName(" CoDeX ");
146
+ assert.strictEqual(caseCheck.name, "codex");
147
+
148
+ const unknown = getModeByName("nonexistent-mode");
149
+ assert.strictEqual(unknown, null);
150
+ });
128
151
  });