@mathzdevolper/phantomcode-cli 1.0.0 → 2.0.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.
Files changed (52) hide show
  1. package/bin/phantomcode.js +2 -0
  2. package/package.json +6 -26
  3. package/src/cli.js +65 -0
  4. package/src/commands/chat.js +50 -0
  5. package/src/commands/config.js +35 -0
  6. package/src/commands/interactive.js +87 -0
  7. package/src/commands/models.js +35 -0
  8. package/src/config.js +135 -0
  9. package/src/hf.js +67 -0
  10. package/src/logger.js +84 -0
  11. package/src/models.js +49 -0
  12. package/dist/commands/chat.d.ts +0 -9
  13. package/dist/commands/chat.js +0 -68
  14. package/dist/commands/chat.js.map +0 -1
  15. package/dist/commands/config.d.ts +0 -1
  16. package/dist/commands/config.js +0 -57
  17. package/dist/commands/config.js.map +0 -1
  18. package/dist/commands/interactive.d.ts +0 -7
  19. package/dist/commands/interactive.js +0 -155
  20. package/dist/commands/interactive.js.map +0 -1
  21. package/dist/commands/models.d.ts +0 -5
  22. package/dist/commands/models.js +0 -38
  23. package/dist/commands/models.js.map +0 -1
  24. package/dist/commands/session.d.ts +0 -1
  25. package/dist/commands/session.js +0 -77
  26. package/dist/commands/session.js.map +0 -1
  27. package/dist/config/manager.d.ts +0 -14
  28. package/dist/config/manager.js +0 -49
  29. package/dist/config/manager.js.map +0 -1
  30. package/dist/index.d.ts +0 -2
  31. package/dist/index.js +0 -90
  32. package/dist/index.js.map +0 -1
  33. package/dist/provider/dogrouter.d.ts +0 -28
  34. package/dist/provider/dogrouter.js +0 -58
  35. package/dist/provider/dogrouter.js.map +0 -1
  36. package/dist/session/manager.d.ts +0 -20
  37. package/dist/session/manager.js +0 -112
  38. package/dist/session/manager.js.map +0 -1
  39. package/dist/tui/colors.d.ts +0 -15
  40. package/dist/tui/colors.js +0 -47
  41. package/dist/tui/colors.js.map +0 -1
  42. package/src/commands/chat.ts +0 -81
  43. package/src/commands/config.ts +0 -74
  44. package/src/commands/interactive.ts +0 -140
  45. package/src/commands/models.ts +0 -41
  46. package/src/commands/session.ts +0 -93
  47. package/src/config/manager.ts +0 -49
  48. package/src/index.ts +0 -109
  49. package/src/provider/dogrouter.ts +0 -82
  50. package/src/session/manager.ts +0 -93
  51. package/src/tui/colors.ts +0 -43
  52. package/tsconfig.json +0 -17
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("../src/cli");
package/package.json CHANGED
@@ -1,34 +1,14 @@
1
1
  {
2
2
  "name": "@mathzdevolper/phantomcode-cli",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "PhantomCode - CLI para DogRouter AI Integration Platform",
5
- "main": "dist/index.js",
5
+ "main": "src/cli.js",
6
6
  "bin": {
7
- "phantomcode": "dist/index.js"
7
+ "phantomcode": "bin/phantomcode.js"
8
8
  },
9
- "scripts": {
10
- "build": "tsc",
11
- "start": "node dist/index.js",
12
- "dev": "ts-node src/index.ts",
13
- "prepublishOnly": "npm run build"
14
- },
15
- "keywords": ["dogrouter", "cli", "ai", "phantomcode"],
16
- "author": "",
17
- "license": "MIT",
18
9
  "type": "commonjs",
19
- "dependencies": {
20
- "chalk": "^4.1.2",
21
- "conf": "^15.1.0",
22
- "openai": "^6.42.0",
23
- "ora": "^5.4.1",
24
- "uuid": "^11.1.0",
25
- "yargs": "^17.7.2"
10
+ "engines": {
11
+ "node": ">=18"
26
12
  },
27
- "devDependencies": {
28
- "@types/node": "^22.12.0",
29
- "@types/uuid": "^10.0.0",
30
- "@types/yargs": "^17.0.33",
31
- "ts-node": "^10.9.2",
32
- "typescript": "^5.7.3"
33
- }
13
+ "license": "MIT"
34
14
  }
package/src/cli.js ADDED
@@ -0,0 +1,65 @@
1
+ const { chatCommand } = require("./commands/chat");
2
+ const { configSetCommand, configGetCommand, configResetCommand, configSetModelCommand } = require("./commands/config");
3
+ const { modelsCommand } = require("./commands/models");
4
+ const { interactiveCommand } = require("./commands/interactive");
5
+ const { banner, box, gray, green, red, cyan, bold, yellow } = require("./logger");
6
+
7
+ const pkg = require("../package.json");
8
+
9
+ function help() {
10
+ console.log(`
11
+ ${gray("Usage:")}
12
+ phantomcode chat [model] <message> ${gray("Send a message")}
13
+ phantomcode interactive [model] ${gray("Interactive mode")}
14
+ phantomcode models ${gray("List available models")}
15
+ phantomcode config set <api-key> ${gray("Set API key")}
16
+ phantomcode config get ${gray("Show config")}
17
+ phantomcode config reset ${gray("Remove API key")}
18
+ phantomcode config set-model <model> ${gray("Set default model")}
19
+ phantomcode -v, --version ${gray("Show version")}
20
+ phantomcode -h, --help ${gray("Show help")}
21
+
22
+ ${gray("Examples:")}
23
+ phantomcode config set sk-xxxxx
24
+ phantomcode chat gpt-5.5 "hello world"
25
+ phantomcode interactive deepseek-v4-pro
26
+ `);
27
+ }
28
+
29
+ async function main() {
30
+ const [, , cmdRaw, ...args] = process.argv;
31
+ const cmd = String(cmdRaw || "").trim().toLowerCase();
32
+
33
+ if (!cmd || cmd === "-h" || cmd === "--help" || cmd === "help") {
34
+ console.log(banner());
35
+ help();
36
+ return;
37
+ }
38
+
39
+ if (cmd === "-v" || cmd === "--version" || cmd === "version") {
40
+ console.log(`PhantomCode v${pkg.version}`);
41
+ return;
42
+ }
43
+
44
+ if (cmd === "chat") return chatCommand(args);
45
+ if (cmd === "interactive" || cmd === "i") return interactiveCommand(args);
46
+ if (cmd === "models") return modelsCommand();
47
+
48
+ if (cmd === "config") {
49
+ const sub = String(args[0] || "").toLowerCase();
50
+ if (sub === "set") return configSetCommand(args.slice(1).join(" "));
51
+ if (sub === "get") return configGetCommand();
52
+ if (sub === "reset") return configResetCommand();
53
+ if (sub === "set-model") return configSetModelCommand(args.slice(1).join(" "));
54
+ console.log(red("[-] Use: phantomcode config set/get/reset/set-model"));
55
+ return;
56
+ }
57
+
58
+ console.log(red(`[-] Unknown command: ${cmd}`));
59
+ help();
60
+ }
61
+
62
+ main().catch((err) => {
63
+ console.error(red("Fatal error:"), err);
64
+ process.exit(1);
65
+ });
@@ -0,0 +1,50 @@
1
+ const { getApiKey, getDefaultModel, createSession, addMessage, getSession } = require("../config");
2
+ const { drChat } = require("../hf");
3
+ const { banner, gray, green, red, cyan, yellow } = require("../logger");
4
+
5
+ async function chatCommand(args) {
6
+ console.log(banner());
7
+
8
+ let apiKey;
9
+ try {
10
+ apiKey = getApiKey();
11
+ } catch {
12
+ console.log(red("[-] API key nao configurada"));
13
+ console.log(gray(" Execute: phantomcode config set <sua-api-key>"));
14
+ return;
15
+ }
16
+
17
+ const model = args[0] || getDefaultModel();
18
+ const message = args.slice(1).join(" ");
19
+
20
+ if (!message) {
21
+ console.log(red("[-] Use: phantomcode chat <model> <mensagem>"));
22
+ return;
23
+ }
24
+
25
+ const messages = [];
26
+ messages.push({ role: "user", content: message });
27
+
28
+ console.log(gray(`model: ${model}`));
29
+ console.log(gray(`Você: ${message}`));
30
+ console.log();
31
+
32
+ try {
33
+ const response = await drChat({ apiKey, model, messages });
34
+
35
+ console.log(cyan(`Phantom: ${response.content}`));
36
+
37
+ if (response.usage) {
38
+ console.log(gray(`model: ${response.model} | tokens: ${response.usage.promptTokens}→${response.usage.completionTokens} (${response.usage.totalTokens})`));
39
+ }
40
+
41
+ const session = createSession(model, message);
42
+ addMessage(session.id, "user", message);
43
+ addMessage(session.id, "assistant", response.content);
44
+ console.log(gray(`session: ${session.id}`));
45
+ } catch (err) {
46
+ console.log(red(`[-] ${err.message || "Erro"}`));
47
+ }
48
+ }
49
+
50
+ module.exports = { chatCommand };
@@ -0,0 +1,35 @@
1
+ const { loadConfig, saveConfig, getApiKey, setApiKey, removeApiKey, hasApiKey, getDefaultModel, setDefaultModel } = require("../config");
2
+ const { banner, box, gray, green, red, cyan, yellow } = require("../logger");
3
+
4
+ async function configSetCommand(key) {
5
+ if (!key) {
6
+ console.log(red("[-] Use: phantomcode config set <api-key>"));
7
+ return;
8
+ }
9
+ setApiKey(key);
10
+ console.log(green("[+] API key configurada com sucesso"));
11
+ }
12
+
13
+ async function configGetCommand() {
14
+ const cfg = loadConfig();
15
+ console.log(box("Config", [
16
+ `API Key: ${cfg.apiKey ? cyan(cfg.apiKey.slice(0, 12) + "...") : gray("nao definida")}`,
17
+ `Default Model: ${cyan(cfg.defaultModel || "dogrouter/auto")}`,
18
+ ].join("\n")));
19
+ }
20
+
21
+ async function configResetCommand() {
22
+ removeApiKey();
23
+ console.log(yellow("[!] API key removida"));
24
+ }
25
+
26
+ async function configSetModelCommand(model) {
27
+ if (!model) {
28
+ console.log(red("[-] Use: phantomcode config set-model <model>"));
29
+ return;
30
+ }
31
+ setDefaultModel(model);
32
+ console.log(green(`[+] Modelo padrao: ${cyan(model)}`));
33
+ }
34
+
35
+ module.exports = { configSetCommand, configGetCommand, configResetCommand, configSetModelCommand };
@@ -0,0 +1,87 @@
1
+ const readline = require("readline/promises");
2
+ const { stdin, stdout } = require("process");
3
+ const { getApiKey, getDefaultModel, createSession, addMessage, getSession } = require("../config");
4
+ const { drChat } = require("../hf");
5
+ const { banner, gray, green, red, cyan, yellow } = require("../logger");
6
+
7
+ async function ask(question) {
8
+ const rl = readline.createInterface({ input: stdin, output: stdout });
9
+ try {
10
+ return (await rl.question(question)).trim();
11
+ } finally {
12
+ rl.close();
13
+ }
14
+ }
15
+
16
+ async function interactiveCommand(args) {
17
+ console.log(banner());
18
+
19
+ let apiKey;
20
+ try {
21
+ apiKey = getApiKey();
22
+ } catch {
23
+ console.log(red("[-] API key nao configurada"));
24
+ console.log(gray(" Execute: phantomcode config set <sua-api-key>"));
25
+ return;
26
+ }
27
+
28
+ const model = args[0] || getDefaultModel();
29
+ let sessionId = null;
30
+ const messages = [];
31
+
32
+ console.log(gray(`model: ${model}`));
33
+ console.log(gray("Comandos: /exit /clear /new /help"));
34
+ console.log();
35
+
36
+ while (true) {
37
+ const input = await ask(cyan("» "));
38
+
39
+ if (!input || input === "/exit" || input === "/quit") break;
40
+
41
+ if (input === "/help") {
42
+ console.log(gray(" /exit /quit — Sair"));
43
+ console.log(gray(" /clear — Limpar tela"));
44
+ console.log(gray(" /new — Nova conversa"));
45
+ console.log(gray(" /help — Ajuda"));
46
+ continue;
47
+ }
48
+
49
+ if (input === "/clear") {
50
+ console.clear();
51
+ console.log(banner());
52
+ console.log(gray(`model: ${model}`));
53
+ continue;
54
+ }
55
+
56
+ if (input === "/new") {
57
+ messages.length = 0;
58
+ sessionId = null;
59
+ console.log(green("[+] Nova conversa"));
60
+ continue;
61
+ }
62
+
63
+ messages.push({ role: "user", content: input });
64
+
65
+ try {
66
+ const response = await drChat({ apiKey, model, messages });
67
+ console.log(`\n${cyan("Phantom:")} ${response.content}\n`);
68
+ messages.push({ role: "assistant", content: response.content });
69
+
70
+ if (sessionId) {
71
+ addMessage(sessionId, "user", input);
72
+ addMessage(sessionId, "assistant", response.content);
73
+ } else {
74
+ const session = createSession(model, input);
75
+ sessionId = session.id;
76
+ addMessage(sessionId, "user", input);
77
+ addMessage(sessionId, "assistant", response.content);
78
+ }
79
+ } catch (err) {
80
+ console.log(red(`[-] ${err.message || "Erro"}`));
81
+ }
82
+ }
83
+
84
+ console.log(gray(`\nSession: ${sessionId || "none"}`));
85
+ }
86
+
87
+ module.exports = { interactiveCommand };
@@ -0,0 +1,35 @@
1
+ const { getApiKey } = require("../config");
2
+ const { drListModels } = require("../hf");
3
+ const { buildModelCatalog } = require("../models");
4
+ const { banner, box, gray, green, red, cyan } = require("../logger");
5
+
6
+ async function modelsCommand() {
7
+ console.log(banner());
8
+
9
+ let apiKey;
10
+ try {
11
+ apiKey = getApiKey();
12
+ } catch {
13
+ console.log(red("[-] API key nao configurada"));
14
+ console.log(gray(" Execute: phantomcode config set <sua-api-key>"));
15
+ return;
16
+ }
17
+
18
+ let live = [];
19
+ try {
20
+ const raw = await drListModels(apiKey);
21
+ live = raw.slice(0, 40).map((m) => ({
22
+ id: m.id,
23
+ label: m.id.split("/").pop(),
24
+ note: "live",
25
+ }));
26
+ } catch {}
27
+
28
+ const models = buildModelCatalog(live);
29
+ const lines = models.map((m, i) =>
30
+ `${String(i + 1).padStart(2, "0")}. ${m.label}${m.note ? " — " + m.note : ""}`
31
+ );
32
+ console.log(box(`Models (${models.length})`, lines.join("\n")));
33
+ }
34
+
35
+ module.exports = { modelsCommand };
package/src/config.js ADDED
@@ -0,0 +1,135 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const os = require("os");
4
+
5
+ const CONFIG_DIR = path.join(os.homedir(), ".phantomcode");
6
+ const CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
7
+ const SESSIONS_DIR = path.join(CONFIG_DIR, "sessions");
8
+
9
+ function ensureDir(dir) {
10
+ try {
11
+ fs.mkdirSync(dir, { recursive: true });
12
+ } catch {}
13
+ }
14
+
15
+ function loadConfig() {
16
+ ensureDir(CONFIG_DIR);
17
+ try {
18
+ return JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8"));
19
+ } catch {
20
+ return { apiKey: "", defaultModel: "dogrouter/auto" };
21
+ }
22
+ }
23
+
24
+ function saveConfig(config) {
25
+ ensureDir(CONFIG_DIR);
26
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), "utf8");
27
+ try { fs.chmodSync(CONFIG_PATH, 0o600); } catch {}
28
+ }
29
+
30
+ function getApiKey() {
31
+ const cfg = loadConfig();
32
+ if (!cfg.apiKey) throw new Error("API key nao configurada");
33
+ return cfg.apiKey;
34
+ }
35
+
36
+ function setApiKey(key) {
37
+ const cfg = loadConfig();
38
+ cfg.apiKey = key;
39
+ saveConfig(cfg);
40
+ }
41
+
42
+ function removeApiKey() {
43
+ const cfg = loadConfig();
44
+ cfg.apiKey = "";
45
+ saveConfig(cfg);
46
+ }
47
+
48
+ function hasApiKey() {
49
+ try {
50
+ return !!getApiKey();
51
+ } catch {
52
+ return false;
53
+ }
54
+ }
55
+
56
+ function getDefaultModel() {
57
+ const cfg = loadConfig();
58
+ return cfg.defaultModel || "dogrouter/auto";
59
+ }
60
+
61
+ function setDefaultModel(model) {
62
+ const cfg = loadConfig();
63
+ cfg.defaultModel = model;
64
+ saveConfig(cfg);
65
+ }
66
+
67
+ function getAll() {
68
+ return loadConfig();
69
+ }
70
+
71
+ // Session management
72
+ function sessionPath(id) {
73
+ ensureDir(SESSIONS_DIR);
74
+ return path.join(SESSIONS_DIR, `${id}.json`);
75
+ }
76
+
77
+ function createId() {
78
+ return Date.now().toString(36) + Math.random().toString(36).slice(2, 8) + Math.random().toString(36).slice(2, 6);
79
+ }
80
+
81
+ function createSession(model, title) {
82
+ ensureDir(SESSIONS_DIR);
83
+ const id = createId();
84
+
85
+ const session = { id, title: title || "Nova sessao", model, messages: [], createdAt: Date.now(), updatedAt: Date.now() };
86
+ fs.writeFileSync(sessionPath(id), JSON.stringify(session, null, 2));
87
+ return session;
88
+ }
89
+
90
+ function getSession(id) {
91
+ try {
92
+ return JSON.parse(fs.readFileSync(sessionPath(id), "utf8"));
93
+ } catch {
94
+ return null;
95
+ }
96
+ }
97
+
98
+ function listSessions() {
99
+ ensureDir(SESSIONS_DIR);
100
+ try {
101
+ const files = fs.readdirSync(SESSIONS_DIR).filter((f) => f.endsWith(".json"));
102
+ return files
103
+ .map((f) => {
104
+ try { return JSON.parse(fs.readFileSync(path.join(SESSIONS_DIR, f), "utf8")); } catch { return null; }
105
+ })
106
+ .filter(Boolean)
107
+ .sort((a, b) => b.updatedAt - a.updatedAt);
108
+ } catch {
109
+ return [];
110
+ }
111
+ }
112
+
113
+ function addMessage(sessionId, role, content) {
114
+ const session = getSession(sessionId);
115
+ if (!session) return null;
116
+ session.messages.push({ role, content, timestamp: Date.now() });
117
+ session.updatedAt = Date.now();
118
+ if (session.messages.length === 1) {
119
+ session.title = content.slice(0, 50) + (content.length > 50 ? "..." : "");
120
+ }
121
+ fs.writeFileSync(sessionPath(sessionId), JSON.stringify(session, null, 2));
122
+ return session;
123
+ }
124
+
125
+ function deleteSession(id) {
126
+ try { fs.unlinkSync(sessionPath(id)); } catch {}
127
+ }
128
+
129
+ module.exports = {
130
+ CONFIG_DIR, CONFIG_PATH, SESSIONS_DIR,
131
+ loadConfig, saveConfig,
132
+ getApiKey, setApiKey, removeApiKey, hasApiKey,
133
+ getDefaultModel, setDefaultModel, getAll,
134
+ createSession, getSession, listSessions, addMessage, deleteSession,
135
+ };
package/src/hf.js ADDED
@@ -0,0 +1,67 @@
1
+ const BASE_URL = "https://api.dogrouter.ai/v1";
2
+
3
+ async function drRequest(apiKey, endpoint, options = {}) {
4
+ const resp = await fetch(`${BASE_URL}${endpoint}`, {
5
+ ...options,
6
+ headers: {
7
+ "Content-Type": "application/json",
8
+ Authorization: `Bearer ${apiKey}`,
9
+ ...(options.headers || {}),
10
+ },
11
+ });
12
+
13
+ const text = await resp.text();
14
+
15
+ if (!resp.ok) {
16
+ const err = new Error(`${resp.status} ${resp.statusText} — ${text.slice(0, 200)}`);
17
+ err.status = resp.status;
18
+ err.body = text;
19
+ throw err;
20
+ }
21
+
22
+ return text;
23
+ }
24
+
25
+ async function drChat({ apiKey, model, messages, temperature = 0.7, max_tokens }) {
26
+ const body = { model: model || "dogrouter/auto", messages, temperature };
27
+ if (max_tokens) body.max_tokens = max_tokens;
28
+
29
+ const text = await drRequest(apiKey, "/chat/completions", {
30
+ method: "POST",
31
+ body: JSON.stringify(body),
32
+ });
33
+
34
+ let data;
35
+ try {
36
+ data = JSON.parse(text);
37
+ } catch {
38
+ const err = new Error(`Invalid JSON: ${text.slice(0, 500)}`);
39
+ err.body = text;
40
+ throw err;
41
+ }
42
+
43
+ const content = data?.choices?.[0]?.message?.content;
44
+ if (content === undefined || content === null) {
45
+ const err = new Error("DR API returned no content");
46
+ err.raw = data;
47
+ throw err;
48
+ }
49
+
50
+ return {
51
+ content,
52
+ model: data.model,
53
+ usage: data.usage ? {
54
+ promptTokens: data.usage.prompt_tokens,
55
+ completionTokens: data.usage.completion_tokens,
56
+ totalTokens: data.usage.total_tokens,
57
+ } : null,
58
+ };
59
+ }
60
+
61
+ async function drListModels(apiKey) {
62
+ const text = await drRequest(apiKey, "/models");
63
+ const data = JSON.parse(text);
64
+ return (data?.data || []).map((m) => ({ id: m.id, ownedBy: m.owned_by || "" }));
65
+ }
66
+
67
+ module.exports = { BASE_URL, drChat, drListModels };
package/src/logger.js ADDED
@@ -0,0 +1,84 @@
1
+ const A = {
2
+ reset: "\x1b[0m",
3
+ bold: "\x1b[1m",
4
+ dim: "\x1b[2m",
5
+ red: "\x1b[31m",
6
+ green: "\x1b[32m",
7
+ yellow: "\x1b[33m",
8
+ blue: "\x1b[34m",
9
+ magenta: "\x1b[35m",
10
+ cyan: "\x1b[36m",
11
+ gray: "\x1b[90m",
12
+ };
13
+
14
+ function c(code, text) {
15
+ return `${code}${text}${A.reset}`;
16
+ }
17
+
18
+ function now() {
19
+ const d = new Date();
20
+ const pad = (n) => String(n).padStart(2, "0");
21
+ return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
22
+ }
23
+
24
+ function banner() {
25
+ const logo = [
26
+ `${c(A.cyan, "██████╗ ██╗ ██╗ █████╗ ███╗ ██╗████████╗ ██████╗ ███╗ ███╗ ██████╗ ██████╗ ███████╗")}`,
27
+ `${c(A.blue, "██╔══██╗██║ ██║██╔══██╗████╗ ██║╚══██╔══╝██╔═══██╗████╗ ████║██╔════╝██╔══██╗██╔════╝")}`,
28
+ `${c(A.magenta, "██████╔╝███████║██║ ██║██╔██╗ ██║ ██║ ██║ ██║██╔████╔██║██║ ██║ ██║█████╗ ")}`,
29
+ `${c(A.gray, "██╔═══╝ ██╔══██║██║ ██║██║╚██╗██║ ██║ ██║ ██║██║╚██╔╝██║██║ ██║ ██║██╔══╝ ")}`,
30
+ `${c(A.dim, "██║ ██║ ██║╚█████╔╝██║ ╚████║ ██║ ╚██████╔╝██║ ╚═╝ ██║╚██████╗██████╔╝███████╗")}`,
31
+ `${c(A.gray, "╚═╝ ╚═╝ ╚═╝ ╚════╝ ╚═╝ ╚═══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚═════╝ ╚══════╝")}`,
32
+ `${c(A.gray, "DogRouter AI CLI")} ${c(A.dim, now())}`,
33
+ ].join("\n");
34
+ return logo;
35
+ }
36
+
37
+ function box(title, body = "") {
38
+ const lines = String(body).split("\n");
39
+ const width = Math.max(48, title.length + 8, ...lines.map((l) => l.length + 2));
40
+
41
+ const top = `┌${"─".repeat(width - 2)}┐`;
42
+ const head = `│ ${title}${" ".repeat(width - 3 - title.length)}│`;
43
+ const sep = `├${"─".repeat(width - 2)}┤`;
44
+ const content = lines.length
45
+ ? lines.map((l) => `│ ${l}${" ".repeat(width - 3 - l.length)}│`).join("\n")
46
+ : `│${" ".repeat(width - 2)}│`;
47
+ const bottom = `└${"─".repeat(width - 2)}┘`;
48
+
49
+ return [top, head, sep, content, bottom].join("\n");
50
+ }
51
+
52
+ function info(msg) {
53
+ console.log(`${c(A.cyan, "[*]")} ${msg}`);
54
+ }
55
+ function ok(msg) {
56
+ console.log(`${c(A.green, "[+]")} ${msg}`);
57
+ }
58
+ function warn(msg) {
59
+ console.log(`${c(A.yellow, "[!]")} ${msg}`);
60
+ }
61
+ function fail(msg) {
62
+ console.log(`${c(A.red, "[-]")} ${msg}`);
63
+ }
64
+
65
+ function gray(msg) {
66
+ return c(A.gray, msg);
67
+ }
68
+ function green(msg) {
69
+ return c(A.green, msg);
70
+ }
71
+ function yellow(msg) {
72
+ return c(A.yellow, msg);
73
+ }
74
+ function red(msg) {
75
+ return c(A.red, msg);
76
+ }
77
+ function cyan(msg) {
78
+ return c(A.cyan, msg);
79
+ }
80
+ function bold(msg) {
81
+ return c(A.bold, msg);
82
+ }
83
+
84
+ module.exports = { A, c, banner, box, info, ok, warn, fail, gray, green, yellow, red, cyan, bold, now };
package/src/models.js ADDED
@@ -0,0 +1,49 @@
1
+ const DEFAULT_MODELS = [
2
+ { id: "gpt-5.5", label: "GPT 5.5", kind: "code/reasoning", note: "best overall" },
3
+ { id: "deepseek-v4-pro", label: "DeepSeek V4 Pro", kind: "code/reasoning", note: "agent tasks" },
4
+ { id: "deepseek-v4-flash", label: "DeepSeek V4 Flash", kind: "fast", note: "cheap and fast" },
5
+ { id: "deepseek-chat-v3.1", label: "DeepSeek Chat V3.1", kind: "general", note: "solid all-rounder" },
6
+ { id: "deepseek-v3.2", label: "DeepSeek V3.2", kind: "general", note: "updated" },
7
+ { id: "glm-5.1", label: "GLM 5.1", kind: "general", note: "zhipu ai" },
8
+ { id: "glm-5", label: "GLM 5", kind: "general", note: "zhipu ai" },
9
+ { id: "grok-4.3", label: "Grok 4.3", kind: "general", note: "xAI model" },
10
+ { id: "qwen3.6-plus", label: "Qwen 3.6 Plus", kind: "code", note: "strong coding" },
11
+ { id: "qwen3.5-plus", label: "Qwen 3.5 Plus", kind: "code", note: "coding" },
12
+ { id: "qwen3.5-35b-a3b", label: "Qwen 3.5 35B", kind: "general", note: "efficient" },
13
+ { id: "qwen3.5-27b", label: "Qwen 3.5 27B", kind: "general", note: "balanced" },
14
+ { id: "qwen3.5-flash", label: "Qwen 3.5 Flash", kind: "fast", note: "fast" },
15
+ { id: "qwen3.5-9b", label: "Qwen 3.5 9B", kind: "fast", note: "lightweight" },
16
+ { id: "MiniMax-M2.7", label: "MiniMax M2.7", kind: "general", note: "latest minimax" },
17
+ { id: "MiniMax-M2.5", label: "MiniMax M2.5", kind: "general", note: "stable" },
18
+ { id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6", kind: "code", note: "sonnet" },
19
+ { id: "claude-opus-4-6", label: "Claude Opus 4.6", kind: "reasoning", note: "opus" },
20
+ { id: "claude-opus-4-7", label: "Claude Opus 4.7", kind: "reasoning", note: "latest opus" },
21
+ { id: "claude-opus-4-8", label: "Claude Opus 4.8", kind: "reasoning", note: "bleeding edge" },
22
+ { id: "claude-fable-5", label: "Claude Fable 5", kind: "creative", note: "creative" },
23
+ { id: "claude-jupiter-v1-p", label: "Claude Jupiter V1", kind: "reasoning", note: "jupiter preview" },
24
+ { id: "gemini-3-flash-preview", label: "Gemini 3 Flash", kind: "fast", note: "google flash" },
25
+ { id: "gemini-3.1-pro-preview", label: "Gemini 3.1 Pro", kind: "reasoning", note: "google pro" },
26
+ { id: "gpt-5.3-codex", label: "GPT 5.3 Codex", kind: "code", note: "codex" },
27
+ { id: "gpt-5.4-mini", label: "GPT 5.4 Mini", kind: "fast", note: "compact" },
28
+ { id: "kimi-k2.6", label: "Kimi K2.6", kind: "general", note: "kimi" },
29
+ { id: "kling-v3", label: "Kling V3", kind: "vision", note: "video/image" },
30
+ { id: "kling-v2-5-turbo", label: "Kling V2.5 Turbo", kind: "vision", note: "video/image" },
31
+ { id: "gpt-image-1.5", label: "GPT Image 1.5", kind: "vision", note: "image gen" },
32
+ { id: "gpt-image-1-mini", label: "GPT Image 1 Mini", kind: "vision", note: "image gen fast" },
33
+ { id: "gpt-image-2", label: "GPT Image 2", kind: "vision", note: "latest image" },
34
+ ];
35
+
36
+ function byLabel(a, b) {
37
+ return a.label.localeCompare(b.label);
38
+ }
39
+
40
+ function buildModelCatalog(extra = []) {
41
+ const map = new Map();
42
+ for (const m of [...DEFAULT_MODELS, ...extra]) {
43
+ if (!m?.id) continue;
44
+ map.set(m.id, { ...m });
45
+ }
46
+ return [...map.values()].sort(byLabel);
47
+ }
48
+
49
+ module.exports = { DEFAULT_MODELS, buildModelCatalog };
@@ -1,9 +0,0 @@
1
- interface ChatArgs {
2
- message: string;
3
- model?: string;
4
- noSave?: boolean;
5
- session?: string;
6
- system?: string;
7
- }
8
- export declare function handleChat(args: ChatArgs): Promise<void>;
9
- export {};