feat: overhaul CLI with new AI commands and mole-style menu (#6)
Build / bun-build (push) Successful in 1m20s

Major CLI redesign introducing a mole-style interactive menu with grouped categories. Added new AI-powered subcommands: explain, review, changelog, and suggest. Includes streaming output, pipe support, and updated brand logo. Refactored codebase into command modules for maintainability.

Reviewed-on: #6
This commit was merged in pull request #6.
This commit is contained in:
2026-06-17 00:17:31 +08:00
parent 0d9c31ae3b
commit 586487d897
22 changed files with 2824 additions and 1242 deletions
+26 -26
View File
@@ -2,39 +2,39 @@ import { test, expect, describe } from "bun:test";
import { loadConfig } from "../src/config";
describe("config", () => {
test("loadConfig env variables override config file and defaults", async () => {
const origBase = process.env.GAI_API_BASE;
const origModel = process.env.GAI_MODEL;
test("loadConfig env variables override config file and defaults", async () => {
const origBase = process.env.GAI_API_BASE;
const origModel = process.env.GAI_MODEL;
process.env.GAI_API_BASE = "https://custom.api.com/v1";
process.env.GAI_MODEL = "custom-model";
process.env.GAI_API_BASE = "https://custom.api.com/v1";
process.env.GAI_MODEL = "custom-model";
const config = await loadConfig();
const config = await loadConfig();
expect(config.apiBase).toBe("https://custom.api.com/v1");
expect(config.model).toBe("custom-model");
expect(config.apiBase).toBe("https://custom.api.com/v1");
expect(config.model).toBe("custom-model");
if (origBase) process.env.GAI_API_BASE = origBase;
else delete process.env.GAI_API_BASE;
if (origModel) process.env.GAI_MODEL = origModel;
else delete process.env.GAI_MODEL;
});
if (origBase) process.env.GAI_API_BASE = origBase;
else delete process.env.GAI_API_BASE;
if (origModel) process.env.GAI_MODEL = origModel;
else delete process.env.GAI_MODEL;
});
test("loadConfig reads from environment variables", async () => {
const origBase = process.env.GAI_API_BASE;
const origModel = process.env.GAI_MODEL;
test("loadConfig reads from environment variables", async () => {
const origBase = process.env.GAI_API_BASE;
const origModel = process.env.GAI_MODEL;
process.env.GAI_API_BASE = "https://api.deepseek.com/v1";
process.env.GAI_MODEL = "deepseek-v4-flash";
process.env.GAI_API_BASE = "https://api.deepseek.com/v1";
process.env.GAI_MODEL = "deepseek-v4-flash";
const config = await loadConfig();
const config = await loadConfig();
expect(config.apiBase).toBe("https://api.deepseek.com/v1");
expect(config.model).toBe("deepseek-v4-flash");
expect(config.apiBase).toBe("https://api.deepseek.com/v1");
expect(config.model).toBe("deepseek-v4-flash");
if (origBase) process.env.GAI_API_BASE = origBase;
else delete process.env.GAI_API_BASE;
if (origModel) process.env.GAI_MODEL = origModel;
else delete process.env.GAI_MODEL;
});
if (origBase) process.env.GAI_API_BASE = origBase;
else delete process.env.GAI_API_BASE;
if (origModel) process.env.GAI_MODEL = origModel;
else delete process.env.GAI_MODEL;
});
});