@krishivpb60/aether-ai-cli 1.3.10 → 1.4.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/HIGHLIGHTS.md +17 -0
- package/package.json +1 -1
- package/src/chat.js +18 -4
- package/src/config.js +1 -1
- package/src/ui/banner.js +6 -6
- package/src/ui/dashboard.html +1 -1
- package/src/ui/theme.js +26 -0
- package/test/config.test.js +1 -0
- package/test/ux.test.js +17 -1
package/HIGHLIGHTS.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
# Aether CLI v1.4.0 Highlights
|
|
2
|
+
- **Microphone Audio Input & Dynamic Nerd Font Glyphs (`/mic`)**:
|
|
3
|
+
- Adds `/mic` voice command to record audio directly from your microphone inside the terminal session.
|
|
4
|
+
- Implements native zero-dependency audio recording on Windows using the WinMM Multimedia Control Interface (MCI) via PowerShell.
|
|
5
|
+
- Automatically transcribes speech using Google Gemini (base64 inlineData), Groq Whisper, or OpenAI Whisper.
|
|
6
|
+
- Fixes readline interface raw mode pausing blockages to ensure Enter keypress resolves transcription correctly.
|
|
7
|
+
- Introduces dynamic `getIcon` helper supporting high-definition vector icons in the terminal.
|
|
8
|
+
- Adds optional `"NERD_FONTS"` configuration parameter (`aether config set NERD_FONTS true`) to automatically switch between standard emojis and Nerd Font glyphs (like FontAwesome microphones, folders, gears, and branch trees) based on your preferences.
|
|
9
|
+
|
|
10
|
+
# Aether CLI v1.3.11 Highlights
|
|
11
|
+
- **Microphone Audio Input Non-TTY Safety & Transcription (`/mic`)**:
|
|
12
|
+
- Adds `/mic` voice command to record audio directly from your microphone inside the terminal session.
|
|
13
|
+
- Implements native zero-dependency audio recording on Windows using the WinMM Multimedia Control Interface (MCI) via PowerShell.
|
|
14
|
+
- Automatically transcribes speech using Google Gemini (base64 inlineData), Groq Whisper, or OpenAI Whisper.
|
|
15
|
+
- Adds safeguards to prevent setRawMode crashes in non-TTY environments (like tests or piped runs).
|
|
16
|
+
- Populates the active readline prompt buffer directly with the transcribed text so you can review, edit, and send it.
|
|
17
|
+
|
|
1
18
|
# Aether CLI v1.3.10 Highlights
|
|
2
19
|
- **Microphone Audio Input Fixes & Transcription (`/mic`)**:
|
|
3
20
|
- Adds `/mic` voice command to record audio directly from your microphone inside the terminal session.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@krishivpb60/aether-ai-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.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
|
@@ -25,7 +25,8 @@ import {
|
|
|
25
25
|
getActiveTheme,
|
|
26
26
|
setTheme,
|
|
27
27
|
getThemesList,
|
|
28
|
-
interactiveMenu
|
|
28
|
+
interactiveMenu,
|
|
29
|
+
getIcon
|
|
29
30
|
} from "./ui/theme.js";
|
|
30
31
|
import { createSpinner } from "./ui/spinner.js";
|
|
31
32
|
import { showBanner } from "./ui/banner.js";
|
|
@@ -2256,7 +2257,7 @@ export async function handleMicInput(ctx) {
|
|
|
2256
2257
|
return;
|
|
2257
2258
|
}
|
|
2258
2259
|
|
|
2259
|
-
console.log("\n" + label.system + " " + colors.brand("
|
|
2260
|
+
console.log("\n" + label.system + " " + colors.brand(getIcon("mic", ctx.aiConfig) + "AUDIO VOICE INPUT"));
|
|
2260
2261
|
console.log(separator("─"));
|
|
2261
2262
|
console.log(colors.accent(" Recording started..."));
|
|
2262
2263
|
console.log(" " + colors.muted("Speak into your microphone."));
|
|
@@ -2267,13 +2268,24 @@ export async function handleMicInput(ctx) {
|
|
|
2267
2268
|
|
|
2268
2269
|
const stdin = process.stdin;
|
|
2269
2270
|
const wasRaw = stdin.isRaw;
|
|
2270
|
-
stdin.setRawMode
|
|
2271
|
+
const isTTY = typeof stdin.setRawMode === "function";
|
|
2272
|
+
|
|
2273
|
+
if (isTTY) {
|
|
2274
|
+
stdin.setRawMode(true);
|
|
2275
|
+
}
|
|
2271
2276
|
stdin.resume();
|
|
2272
2277
|
stdin.setEncoding("utf8");
|
|
2273
2278
|
|
|
2274
2279
|
let aborted = false;
|
|
2275
2280
|
await new Promise((resolve) => {
|
|
2276
2281
|
function onData(chunk) {
|
|
2282
|
+
if (!isTTY) {
|
|
2283
|
+
if (chunk.includes("\n") || chunk.includes("\r")) {
|
|
2284
|
+
stdin.removeListener("data", onData);
|
|
2285
|
+
resolve();
|
|
2286
|
+
}
|
|
2287
|
+
return;
|
|
2288
|
+
}
|
|
2277
2289
|
if (chunk === "\u0003") {
|
|
2278
2290
|
aborted = true;
|
|
2279
2291
|
stdin.removeListener("data", onData);
|
|
@@ -2288,7 +2300,9 @@ export async function handleMicInput(ctx) {
|
|
|
2288
2300
|
stdin.on("data", onData);
|
|
2289
2301
|
});
|
|
2290
2302
|
|
|
2291
|
-
|
|
2303
|
+
if (isTTY) {
|
|
2304
|
+
stdin.setRawMode(wasRaw);
|
|
2305
|
+
}
|
|
2292
2306
|
ctx.rl.resume();
|
|
2293
2307
|
|
|
2294
2308
|
if (aborted) {
|
package/src/config.js
CHANGED
|
@@ -176,7 +176,7 @@ export function isValidConfigKey(key) {
|
|
|
176
176
|
const allowedSpecialKeys = [
|
|
177
177
|
"THEME", "CUSTOM_COMMANDS", "AUTOPILOT",
|
|
178
178
|
"AUTO_UPDATE", "SHOW_HIGHLIGHTS", "LAST_UPDATE_CHECK", "LAST_NOTIFIED_VERSION",
|
|
179
|
-
"SHOW_TOKENS", "DIAGNOSE_CMD"
|
|
179
|
+
"SHOW_TOKENS", "DIAGNOSE_CMD", "NERD_FONTS"
|
|
180
180
|
];
|
|
181
181
|
if (upper.endsWith("_API_KEY") || upper.endsWith("_API_KEYS") || upper.endsWith("_MODEL") || allowedSpecialKeys.includes(upper)) {
|
|
182
182
|
return true;
|
package/src/ui/banner.js
CHANGED
|
@@ -7,7 +7,7 @@ import { readFileSync, existsSync } from "node:fs";
|
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { homedir } from "node:os";
|
|
9
9
|
import chalk from "chalk";
|
|
10
|
-
import { colors, separator, modeBadge } from "./theme.js";
|
|
10
|
+
import { colors, separator, modeBadge, getIcon } from "./theme.js";
|
|
11
11
|
import { getActiveProviders } from "../ai/providers.js";
|
|
12
12
|
import { MODES } from "../modes.js";
|
|
13
13
|
|
|
@@ -137,11 +137,11 @@ export function showBanner(currentMode = "titan") {
|
|
|
137
137
|
: "npm (@krishivpb60/aether-ai-cli)";
|
|
138
138
|
|
|
139
139
|
const rows = [
|
|
140
|
-
formatRow(` ${colors.muted("
|
|
141
|
-
formatRow(` ${colors.muted("
|
|
142
|
-
formatRow(` ${colors.muted("
|
|
143
|
-
formatRow(` ${colors.muted("
|
|
144
|
-
formatRow(` ${colors.muted("
|
|
140
|
+
formatRow(` ${colors.muted(getIcon("workspace", config) + "Workspace")}`, colors.text(workspaceValue)),
|
|
141
|
+
formatRow(` ${colors.muted(getIcon("mode", config) + "Mode")}`, modeRowValue),
|
|
142
|
+
formatRow(` ${colors.muted(getIcon("network", config) + "Network")}`, meshStatusText),
|
|
143
|
+
formatRow(` ${colors.muted(getIcon("engine", config) + "Engine")}`, colors.text(engineValue)),
|
|
144
|
+
formatRow(` ${colors.muted(getIcon("package", config) + "Packager")}`, colors.text(packagerText)),
|
|
145
145
|
];
|
|
146
146
|
|
|
147
147
|
console.log(`\n ⚡ ${colors.brand("AETHER COMMAND STATION v" + version)} • Welcome back, ${colors.accent(username)}`);
|
package/src/ui/dashboard.html
CHANGED
package/src/ui/theme.js
CHANGED
|
@@ -486,3 +486,29 @@ export async function interactiveMenu(headerText, items) {
|
|
|
486
486
|
stdin.on("data", handleKey);
|
|
487
487
|
});
|
|
488
488
|
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Returns either a premium Nerd Font glyph or a standard Unicode emoji fallback
|
|
492
|
+
* depending on whether NERD_FONTS is enabled in the configuration.
|
|
493
|
+
* @param {string} name - Icon name
|
|
494
|
+
* @param {object} config - Active configuration object
|
|
495
|
+
* @returns {string}
|
|
496
|
+
*/
|
|
497
|
+
export function getIcon(name, config) {
|
|
498
|
+
const useNerd = config?.NERD_FONTS === true || config?.NERD_FONTS === "true";
|
|
499
|
+
|
|
500
|
+
const icons = {
|
|
501
|
+
workspace: useNerd ? "\uf07c " : "📂 ",
|
|
502
|
+
mode: useNerd ? "\uf0e0 " : "🧠 ", // brain / envelope-like modes icon
|
|
503
|
+
network: useNerd ? "\uf6ff " : "🟢 ", // network icon
|
|
504
|
+
engine: useNerd ? "\uf013 " : "⚙️ ", // gear icon
|
|
505
|
+
package: useNerd ? "\uf1b2 " : "📦 ", // package icon
|
|
506
|
+
mic: useNerd ? "\uf130 " : "🎤 ", // microphone icon
|
|
507
|
+
git: useNerd ? "\uf113 " : "🌿 ", // git/leaf icon
|
|
508
|
+
dashboard: useNerd ? "\uf201 " : "📊 ", // chart icon
|
|
509
|
+
bolt: useNerd ? "\uf0e7 " : "⚡ ", // lightning bolt icon
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
return icons[name] || "";
|
|
513
|
+
}
|
|
514
|
+
|
package/test/config.test.js
CHANGED
|
@@ -148,6 +148,7 @@ test("Configuration Loading Suite", async (t) => {
|
|
|
148
148
|
assert.strictEqual(isValidConfigKey("GOOGLE_API_KEYS"), true);
|
|
149
149
|
assert.strictEqual(isValidConfigKey("THEME"), true);
|
|
150
150
|
assert.strictEqual(isValidConfigKey("CUSTOM_COMMANDS"), true);
|
|
151
|
+
assert.strictEqual(isValidConfigKey("NERD_FONTS"), true);
|
|
151
152
|
assert.strictEqual(isValidConfigKey("INVALID_KEY_NAME"), false);
|
|
152
153
|
});
|
|
153
154
|
|
package/test/ux.test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { test, beforeEach, afterEach } from "node:test";
|
|
2
2
|
import assert from "node:assert";
|
|
3
3
|
import { ReadableStream } from "node:stream/web";
|
|
4
|
-
import { separator, clearStreamedText, StreamFilter, stripCodeFences, getActiveTheme, setTheme, getThemesList } from "../src/ui/theme.js";
|
|
4
|
+
import { separator, clearStreamedText, StreamFilter, stripCodeFences, getActiveTheme, setTheme, getThemesList, getIcon } from "../src/ui/theme.js";
|
|
5
5
|
import { createSpinner } from "../src/ui/spinner.js";
|
|
6
6
|
import { routePrompt } from "../src/ai/router.js";
|
|
7
7
|
import { getModeByName, MODES } from "../src/modes.js";
|
|
@@ -183,4 +183,20 @@ test("Cyberpunk UX and Streaming Suite", async (t) => {
|
|
|
183
183
|
const noFenceBlock = "console.log('hi');";
|
|
184
184
|
assert.strictEqual(stripCodeFences(noFenceBlock), "console.log('hi');");
|
|
185
185
|
});
|
|
186
|
+
|
|
187
|
+
await t.test("getIcon returns Nerd Font glyphs if enabled, else defaults to emojis", () => {
|
|
188
|
+
const nerdConfig = { NERD_FONTS: true };
|
|
189
|
+
const emojiConfig = { NERD_FONTS: false };
|
|
190
|
+
const defaultConfig = {};
|
|
191
|
+
|
|
192
|
+
// 1. Nerd Font Enabled
|
|
193
|
+
assert.strictEqual(getIcon("mic", nerdConfig), "\uf130 ");
|
|
194
|
+
assert.strictEqual(getIcon("git", nerdConfig), "\uf113 ");
|
|
195
|
+
assert.strictEqual(getIcon("dashboard", nerdConfig), "\uf201 ");
|
|
196
|
+
|
|
197
|
+
// 2. Nerd Font Disabled / Empty
|
|
198
|
+
assert.strictEqual(getIcon("mic", emojiConfig), "🎤 ");
|
|
199
|
+
assert.strictEqual(getIcon("git", emojiConfig), "🌿 ");
|
|
200
|
+
assert.strictEqual(getIcon("mic", defaultConfig), "🎤 ");
|
|
201
|
+
});
|
|
186
202
|
});
|