sarangai-cli 1.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 (3) hide show
  1. package/README.md +104 -0
  2. package/dist/index.cjs +392 -0
  3. package/package.json +43 -0
package/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # SarangAI CLI
2
+
3
+ Akses 400+ model AI unggulan (DeepSeek, Claude, GPT, Qwen, Minimax, dsb.) langsung dari terminal Anda melalui SarangAI Gateway.
4
+
5
+ ---
6
+
7
+ ## Fitur Utama
8
+
9
+ - **Streaming Teks Cepat**: Respons AI mengalir secara real-time langsung di terminal.
10
+ - **Katalog 400+ Model**: Jelajahi dan gunakan ratusan varian model AI populer.
11
+ - **Pencarian Cepat**: Filter model berdasarkan nama, provider, atau model gratis.
12
+ - **Dukungan Unix Piping**: Teruskan output perintah bash/kode program langsung ke AI.
13
+ - **Manajemen Saldo**: Cek status kredit akun langsung lewat terminal.
14
+
15
+ ---
16
+
17
+ ## Instalasi
18
+
19
+ Instal paket secara global menggunakan npm:
20
+
21
+ ```bash
22
+ npm install -g sarangai-cli
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Panduan Penggunaan
28
+
29
+ ### 1. Autentikasi
30
+ Dapatkan API Key dari dashboard akun SarangAI Anda, lalu hubungkan ke CLI:
31
+
32
+ ```bash
33
+ sarang login
34
+ ```
35
+
36
+ API Key akan disimpan di berkas konfigurasi lokal `~/.sarangairc`.
37
+
38
+ ### 2. Cek Saldo Kredit
39
+ Lihat sisa saldo kredit dan status akun:
40
+
41
+ ```bash
42
+ sarang balance
43
+ ```
44
+
45
+ ### 3. Jelajahi dan Filter Model
46
+ Melihat seluruh model yang tersedia:
47
+
48
+ ```bash
49
+ sarang models
50
+ ```
51
+
52
+ Menyaring model berdasarkan kata kunci:
53
+
54
+ ```bash
55
+ sarang models -s deepseek
56
+ sarang models -s claude
57
+ sarang models -s free
58
+ ```
59
+
60
+ ### 4. Ganti Default Model
61
+ Tentukan model yang selalu digunakan secara otomatis:
62
+
63
+ ```bash
64
+ sarang set-model minimax/minimax-m2.7
65
+ ```
66
+
67
+ ### 5. Chat & Streaming
68
+ Mengirim prompt langsung:
69
+
70
+ ```bash
71
+ sarang chat "Jelaskan konsep index di database PostgreSQL."
72
+ ```
73
+
74
+ Menggunakan model tertentu tanpa mengubah default:
75
+
76
+ ```bash
77
+ sarang chat -m anthropic/claude-sonnet-4 "Buatkan regex validasi nomor telepon Indonesia."
78
+ ```
79
+
80
+ ### 6. Integrasi Unix Piping
81
+ Membaca input langsung dari terminal atau berkas kode:
82
+
83
+ ```bash
84
+ cat main.py | sarang chat "Review potensi bug dan tingkatkan performa kode ini."
85
+ git diff | sarang chat "Buatkan pesan commit yang ringkas berdasarkan perubahan ini."
86
+ ```
87
+
88
+ ---
89
+
90
+ ## Konfigurasi Gateway
91
+
92
+ Secara default, CLI membaca konfigurasi dari `~/.sarangairc` atau environment variable `SARANGAI_BASE_URL`.
93
+
94
+ Untuk gateway self-hosted atau pengujian lokal:
95
+
96
+ ```bash
97
+ export SARANGAI_BASE_URL="http://localhost:3001"
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Lisensi
103
+
104
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,392 @@
1
+ #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+
25
+ // src/index.ts
26
+ var import_commander = require("commander");
27
+ var import_chalk = __toESM(require("chalk"));
28
+ var import_prompts = __toESM(require("prompts"));
29
+ var import_ora = __toESM(require("ora"));
30
+ var import_readline = __toESM(require("readline"));
31
+ var import_child_process = require("child_process");
32
+ var import_path2 = __toESM(require("path"));
33
+
34
+ // src/config.ts
35
+ var import_fs = __toESM(require("fs"));
36
+ var import_path = __toESM(require("path"));
37
+ var import_os = __toESM(require("os"));
38
+ var CONFIG_PATH = import_path.default.join(import_os.default.homedir(), ".sarangairc");
39
+ function getConfig() {
40
+ try {
41
+ if (import_fs.default.existsSync(CONFIG_PATH)) {
42
+ return JSON.parse(import_fs.default.readFileSync(CONFIG_PATH, "utf-8"));
43
+ }
44
+ } catch {
45
+ }
46
+ return {
47
+ baseUrl: "https://panel.idshop.or.id",
48
+ defaultModel: "openai/gpt-5-pro"
49
+ };
50
+ }
51
+ function saveConfig(cfg) {
52
+ const current = getConfig();
53
+ const next = { ...current, ...cfg };
54
+ import_fs.default.writeFileSync(CONFIG_PATH, JSON.stringify(next, null, 2), "utf-8");
55
+ }
56
+
57
+ // src/index.ts
58
+ var program = new import_commander.Command();
59
+ function resolveBaseUrl() {
60
+ const cfg = getConfig();
61
+ return process.env.SARANGAI_BASE_URL || cfg.baseUrl || "https://api.sarang.ai";
62
+ }
63
+ function getGitBranch() {
64
+ try {
65
+ return (0, import_child_process.execSync)("git branch --show-current 2>/dev/null").toString().trim() || "no-git";
66
+ } catch {
67
+ return "no-git";
68
+ }
69
+ }
70
+ function renderBanner(modelName) {
71
+ console.clear();
72
+ const banner = `
73
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557
74
+ \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551
75
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551
76
+ \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551
77
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551
78
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D
79
+ `;
80
+ console.log(import_chalk.default.cyanBright(banner));
81
+ console.log(import_chalk.default.gray(" Tips for getting started:"));
82
+ console.log(import_chalk.default.gray(" 1. Ketik pesan Anda langsung untuk chat streaming."));
83
+ console.log(import_chalk.default.gray(" 2. Perintah khusus: ") + import_chalk.default.yellow("/clear") + import_chalk.default.gray(" (bersihkan layar), ") + import_chalk.default.yellow("/model <id>") + import_chalk.default.gray(", ") + import_chalk.default.yellow("/exit") + import_chalk.default.gray("."));
84
+ console.log("");
85
+ const cwd = import_path2.default.basename(process.cwd());
86
+ const branch = getGitBranch();
87
+ const leftStatus = import_chalk.default.gray(`\u{1F4C2} ~/${cwd} `) + import_chalk.default.magenta(`(${branch})`);
88
+ const rightStatus = import_chalk.default.bgCyan.black(` ${modelName} `) + import_chalk.default.greenBright(" (ready)");
89
+ console.log(` ${leftStatus} ${rightStatus}`);
90
+ console.log(import_chalk.default.cyan(" " + "\u2500".repeat(65)));
91
+ console.log("");
92
+ }
93
+ async function startInteractiveSession(initialModel) {
94
+ const cfg = getConfig();
95
+ if (!cfg.apiKey) {
96
+ console.log(import_chalk.default.yellow("Silakan login terlebih dahulu: sarang login"));
97
+ return;
98
+ }
99
+ let currentModel = initialModel || cfg.defaultModel || "minimax/minimax-m2.7";
100
+ const baseUrl = resolveBaseUrl();
101
+ const history = [];
102
+ renderBanner(currentModel);
103
+ const rl = import_readline.default.createInterface({
104
+ input: process.stdin,
105
+ output: process.stdout
106
+ });
107
+ const ask = () => {
108
+ rl.question(import_chalk.default.cyanBright("\u276F "), async (input) => {
109
+ var _a, _b, _c, _d, _e;
110
+ const trimmed = input.trim();
111
+ if (!trimmed) {
112
+ ask();
113
+ return;
114
+ }
115
+ if (trimmed === "/exit" || trimmed === "exit" || trimmed === ":q") {
116
+ console.log(import_chalk.default.gray("\nSampai jumpa!\n"));
117
+ rl.close();
118
+ process.exit(0);
119
+ }
120
+ if (trimmed === "/clear" || trimmed === "clear") {
121
+ renderBanner(currentModel);
122
+ ask();
123
+ return;
124
+ }
125
+ if (trimmed.startsWith("/model")) {
126
+ const parts = trimmed.split(" ");
127
+ if (parts[1]) {
128
+ currentModel = parts[1].trim();
129
+ saveConfig({ defaultModel: currentModel });
130
+ console.log(import_chalk.default.green(`
131
+ \u2714 Model dialihkan ke: ${currentModel}
132
+ `));
133
+ } else {
134
+ console.log(import_chalk.default.yellow(`
135
+ Format: /model <model-id> (contoh: /model openai/gpt-4o-mini)
136
+ `));
137
+ }
138
+ ask();
139
+ return;
140
+ }
141
+ history.push({ role: "user", content: trimmed });
142
+ process.stdout.write(import_chalk.default.gray(`
143
+ [${currentModel}]
144
+ `));
145
+ try {
146
+ const res = await fetch(`${baseUrl}/api/gateway/v1/chat/completions`, {
147
+ method: "POST",
148
+ headers: {
149
+ "Content-Type": "application/json",
150
+ Authorization: `Bearer ${cfg.apiKey}`
151
+ },
152
+ body: JSON.stringify({
153
+ model: currentModel,
154
+ messages: history,
155
+ stream: true
156
+ })
157
+ });
158
+ if (!res.ok) {
159
+ const errText = await res.text();
160
+ let parsedErr;
161
+ try {
162
+ parsedErr = JSON.parse(errText);
163
+ } catch {
164
+ }
165
+ throw new Error(((_a = parsedErr == null ? void 0 : parsedErr.error) == null ? void 0 : _a.message) || `HTTP ${res.status}: ${errText.slice(0, 80)}`);
166
+ }
167
+ const reader = (_b = res.body) == null ? void 0 : _b.getReader();
168
+ const decoder = new TextDecoder();
169
+ let assistantReply = "";
170
+ if (reader) {
171
+ while (true) {
172
+ const { done, value } = await reader.read();
173
+ if (done) break;
174
+ const chunk = decoder.decode(value);
175
+ const lines = chunk.split("\n");
176
+ for (const line of lines) {
177
+ if (line.startsWith("data: ") && line !== "data: [DONE]") {
178
+ try {
179
+ const parsed = JSON.parse(line.slice(6));
180
+ const delta = (_e = (_d = (_c = parsed.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.delta) == null ? void 0 : _e.content;
181
+ if (delta) {
182
+ process.stdout.write(delta);
183
+ assistantReply += delta;
184
+ }
185
+ } catch {
186
+ }
187
+ }
188
+ }
189
+ }
190
+ console.log("\n");
191
+ history.push({ role: "assistant", content: assistantReply });
192
+ }
193
+ } catch (err) {
194
+ console.error(import_chalk.default.red(`
195
+ Error: ${err.message}
196
+ `));
197
+ }
198
+ ask();
199
+ });
200
+ };
201
+ ask();
202
+ }
203
+ program.name("sarang").description(import_chalk.default.cyanBright("SarangAI CLI \u2014 Gateway ratusan model AI langsung di terminal")).version("1.0.0").action(() => {
204
+ startInteractiveSession();
205
+ });
206
+ program.command("login").description("Hubungkan API Key SarangAI akun Anda").action(async () => {
207
+ const res = await (0, import_prompts.default)({
208
+ type: "password",
209
+ name: "key",
210
+ message: "Masukkan SarangAI API Key Anda (dari dashboard panel):"
211
+ });
212
+ if (!res.key) {
213
+ console.log(import_chalk.default.red("Login dibatalkan."));
214
+ return;
215
+ }
216
+ saveConfig({ apiKey: res.key.trim() });
217
+ console.log(import_chalk.default.green("\u2714 API Key berhasil disimpan di ~/.sarangairc"));
218
+ });
219
+ program.command("balance").description("Cek sisa saldo kredit akun SarangAI Anda").action(async () => {
220
+ const cfg = getConfig();
221
+ if (!cfg.apiKey) {
222
+ console.log(import_chalk.default.yellow("Anda belum login. Jalankan: sarang login"));
223
+ return;
224
+ }
225
+ const baseUrl = resolveBaseUrl();
226
+ const spinner = (0, import_ora.default)("Mengambil status saldo...").start();
227
+ try {
228
+ const res = await fetch(`${baseUrl}/api/gateway/v1/balance`, {
229
+ headers: { Authorization: `Bearer ${cfg.apiKey}` }
230
+ });
231
+ const rawText = await res.text();
232
+ let data = {};
233
+ try {
234
+ data = JSON.parse(rawText);
235
+ } catch {
236
+ throw new Error(`Endpoint mengembalikan respons non-JSON (${res.status}): ${rawText.slice(0, 120)}...`);
237
+ }
238
+ spinner.stop();
239
+ if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
240
+ console.log(import_chalk.default.bold("\nStatus Akun SarangAI:"));
241
+ console.log(`Credit Balance : ${import_chalk.default.greenBright(data.balance ?? 0)} CREDIT`);
242
+ console.log(`Email : ${import_chalk.default.gray(data.email || "\u2014")}
243
+ `);
244
+ } catch (err) {
245
+ spinner.fail(import_chalk.default.red(err.message));
246
+ }
247
+ });
248
+ program.command("models").option("-s, --search <keyword>", "Filter nama model (contoh: claude, deepseek, free)").description("Daftar model AI yang tersedia di SarangAI Gateway").action(async (cmd) => {
249
+ var _a;
250
+ const cfg = getConfig();
251
+ if (!cfg.apiKey) {
252
+ console.log(import_chalk.default.yellow("Anda belum login. Jalankan: sarang login"));
253
+ return;
254
+ }
255
+ const baseUrl = resolveBaseUrl();
256
+ const spinner = (0, import_ora.default)("Mengambil katalog model...").start();
257
+ try {
258
+ const res = await fetch(`${baseUrl}/api/gateway/v1/models`, {
259
+ headers: { Authorization: `Bearer ${cfg.apiKey}` }
260
+ });
261
+ const rawText = await res.text();
262
+ let data = {};
263
+ try {
264
+ data = JSON.parse(rawText);
265
+ } catch {
266
+ throw new Error(`Respons tidak valid: ${rawText.slice(0, 100)}`);
267
+ }
268
+ spinner.stop();
269
+ if (!res.ok) throw new Error(((_a = data.error) == null ? void 0 : _a.message) || data.error || `HTTP ${res.status}`);
270
+ let list = Array.isArray(data) ? data : data.data || [];
271
+ if (list.length === 0) {
272
+ console.log(import_chalk.default.yellow("Tidak ada model aktif yang ditemukan."));
273
+ return;
274
+ }
275
+ if (cmd.search) {
276
+ const query = cmd.search.toLowerCase();
277
+ list = list.filter((m) => {
278
+ const id = (m.id || m.modelId || m.name || "").toLowerCase();
279
+ return id.includes(query);
280
+ });
281
+ }
282
+ if (list.length === 0) {
283
+ console.log(import_chalk.default.yellow(`
284
+ Tidak ada model yang cocok dengan kata kunci "${cmd.search}".
285
+ `));
286
+ return;
287
+ }
288
+ console.log(import_chalk.default.bold(`
289
+ Model Tersedia (${list.length}${cmd.search ? ` cocok dengan "${cmd.search}"` : ""}):`));
290
+ console.log(import_chalk.default.gray("---------------------------------------------------------"));
291
+ list.forEach((m) => {
292
+ const id = m.id || m.modelId || m.name;
293
+ const isCurrent = id === cfg.defaultModel;
294
+ const prefix = isCurrent ? import_chalk.default.green("\u2714 [Aktif] ") : " ";
295
+ console.log(`${prefix}${import_chalk.default.cyan(id)}`);
296
+ });
297
+ console.log(import_chalk.default.gray("---------------------------------------------------------"));
298
+ console.log(import_chalk.default.dim("Ganti model default : sarang set-model <model-id>"));
299
+ console.log(import_chalk.default.dim('Chat model tertentu : sarang chat -m <model-id> "..."\n'));
300
+ } catch (err) {
301
+ spinner.fail(import_chalk.default.red(err.message));
302
+ }
303
+ });
304
+ program.command("set-model [modelId]").description("Atur model default untuk chat").action(async (modelId) => {
305
+ let target = modelId;
306
+ if (!target) {
307
+ const res = await (0, import_prompts.default)({
308
+ type: "text",
309
+ name: "model",
310
+ message: "Masukkan Model ID default baru (contoh: minimax/minimax-m2.7):"
311
+ });
312
+ target = res.model;
313
+ }
314
+ if (!target) return;
315
+ saveConfig({ defaultModel: target.trim() });
316
+ console.log(import_chalk.default.green(`\u2714 Default model berhasil diubah ke: ${target.trim()}`));
317
+ });
318
+ program.command("chat [prompt...]").option("-m, --model <modelId>", "Pilih model AI spesifik").description("Kirim instruksi / chat ke AI (Mendukung streaming teks atau Unix Pipe)").action(async (promptArr, cmd) => {
319
+ var _a, _b, _c, _d, _e;
320
+ let prompt = promptArr == null ? void 0 : promptArr.join(" ");
321
+ if (!process.stdin.isTTY) {
322
+ const chunks = [];
323
+ for await (const chunk of process.stdin) {
324
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
325
+ }
326
+ const pipedData = Buffer.concat(chunks).toString("utf-8").trim();
327
+ prompt = prompt ? `${prompt}
328
+
329
+ ${pipedData}` : pipedData;
330
+ }
331
+ if (!prompt) {
332
+ await startInteractiveSession(cmd.model);
333
+ return;
334
+ }
335
+ const cfg = getConfig();
336
+ if (!cfg.apiKey) {
337
+ console.log(import_chalk.default.yellow("Silakan login terlebih dahulu: sarang login"));
338
+ return;
339
+ }
340
+ const baseUrl = resolveBaseUrl();
341
+ const selectedModel = cmd.model || cfg.defaultModel || "minimax/minimax-m2.7";
342
+ console.log(import_chalk.default.gray(`
343
+ [Model: ${selectedModel}]`));
344
+ try {
345
+ const res = await fetch(`${baseUrl}/api/gateway/v1/chat/completions`, {
346
+ method: "POST",
347
+ headers: {
348
+ "Content-Type": "application/json",
349
+ Authorization: `Bearer ${cfg.apiKey}`
350
+ },
351
+ body: JSON.stringify({
352
+ model: selectedModel,
353
+ messages: [{ role: "user", content: prompt }],
354
+ stream: true
355
+ })
356
+ });
357
+ if (!res.ok) {
358
+ const errText = await res.text();
359
+ let parsedErr;
360
+ try {
361
+ parsedErr = JSON.parse(errText);
362
+ } catch {
363
+ }
364
+ throw new Error(((_a = parsedErr == null ? void 0 : parsedErr.error) == null ? void 0 : _a.message) || `HTTP ${res.status}: ${errText.slice(0, 80)}`);
365
+ }
366
+ const reader = (_b = res.body) == null ? void 0 : _b.getReader();
367
+ const decoder = new TextDecoder();
368
+ if (reader) {
369
+ while (true) {
370
+ const { done, value } = await reader.read();
371
+ if (done) break;
372
+ const chunk = decoder.decode(value);
373
+ const lines = chunk.split("\n");
374
+ for (const line of lines) {
375
+ if (line.startsWith("data: ") && line !== "data: [DONE]") {
376
+ try {
377
+ const parsed = JSON.parse(line.slice(6));
378
+ const content = (_e = (_d = (_c = parsed.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.delta) == null ? void 0 : _e.content;
379
+ if (content) process.stdout.write(content);
380
+ } catch {
381
+ }
382
+ }
383
+ }
384
+ }
385
+ console.log("\n");
386
+ }
387
+ } catch (err) {
388
+ console.error(import_chalk.default.red(`
389
+ Error: ${err.message}`));
390
+ }
391
+ });
392
+ program.parse(process.argv);
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "sarangai-cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI resmi SarangAI — Gateway multi-model AI langsung dari terminal Anda",
5
+ "main": "dist/index.cjs",
6
+ "bin": {
7
+ "sarang": "dist/index.cjs",
8
+ "sarangai": "dist/index.cjs"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsup",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "sarangai",
19
+ "cli",
20
+ "ai",
21
+ "llm",
22
+ "openai",
23
+ "deepseek",
24
+ "claude",
25
+ "gateway"
26
+ ],
27
+ "author": "SarangAI Team",
28
+ "license": "MIT",
29
+ "dependencies": {
30
+ "chalk": "^4.1.2",
31
+ "commander": "^12.1.0",
32
+ "ora": "^5.4.1",
33
+ "prompts": "^2.4.2",
34
+ "readline-sync": "^1.4.10"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^20.14.9",
38
+ "@types/prompts": "^2.4.9",
39
+ "@types/readline-sync": "^1.4.8",
40
+ "tsup": "^8.5.1",
41
+ "typescript": "^5.5.2"
42
+ }
43
+ }