@gilangranggaid/kilua-agent 1.0.1 → 1.0.2

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 (2) hide show
  1. package/bin/kilua.mjs +48 -23
  2. package/package.json +1 -1
package/bin/kilua.mjs CHANGED
@@ -5,7 +5,7 @@ import path from "node:path";
5
5
  import os from "node:os";
6
6
  import { execSync } from "node:child_process";
7
7
 
8
- // ponytail: single-file agent CLI supporting both OpenAI & Anthropic (9router) protocols.
8
+ // ponytail: single-file agent CLI supporting OpenAI, Gemini OpenAI endpoint & Anthropic/9router.
9
9
  const KILUA_DIR = path.join(os.homedir(), ".kilua");
10
10
  const SETTINGS_PATH = path.join(KILUA_DIR, "settings.json");
11
11
  const CLAUDE_SETTINGS_PATH = path.join(os.homedir(), ".claude", "settings.json");
@@ -133,20 +133,29 @@ async function runInteractiveConfig() {
133
133
  const claudeCfg = readClaudeSettings();
134
134
 
135
135
  console.log("\x1b[35m=== KILUA CONFIG ===\x1b[0m\nPath: " + SETTINGS_PATH);
136
- console.log("1) 9Router / Claude Code Proxy (Port 20128)");
137
- console.log("2) TokenHarbor / OpenAI Compatible");
138
- console.log("3) Custom Provider\n");
136
+ console.log("1) TokenHarbor / 9Router / OpenRouter (OpenAI-compatible)");
137
+ console.log("2) Google Gemini (AI Studio Key)");
138
+ console.log("3) 9Router Local / Claude Code Proxy (Port 20128)\n");
139
139
 
140
- const choice = (await promptQuestion(rl, "Pilihan [1/2/3] (1): ")).trim() || "1";
140
+ const choice = (await promptQuestion(rl, "Pilihan [1/2/3] (default 1): ")).trim() || "1";
141
141
  let settings = {};
142
142
 
143
- if (choice === "1") {
143
+ if (choice === "2") {
144
+ const key = (await promptQuestion(rl, "Masukkan GEMINI_API_KEY: ")).trim();
145
+ const model = (await promptQuestion(rl, "Nama Model (gemini-2.5-flash): ")).trim() || "gemini-2.5-flash";
146
+ settings = {
147
+ provider: "openai",
148
+ base_url: "https://generativelanguage.googleapis.com/v1beta/openai",
149
+ api_key: key,
150
+ model
151
+ };
152
+ } else if (choice === "3") {
144
153
  const defaultUrl = claudeCfg?.base_url || "http://127.0.0.1:20128/v1";
145
154
  const defaultKey = claudeCfg?.api_key || "";
146
155
  const defaultModel = claudeCfg?.model || "harobor";
147
156
 
148
157
  const baseUrl = (await promptQuestion(rl, `Base URL (${defaultUrl}): `)).trim() || defaultUrl;
149
- const key = (await promptQuestion(rl, `API Key/Token (${defaultKey ? defaultKey.slice(0, 10) + "..." : "kosongkan jika sama"}): `)).trim() || defaultKey;
158
+ const key = (await promptQuestion(rl, `API Key/Token (${defaultKey ? defaultKey.slice(0, 10) + "..." : "masukkan token"}): `)).trim() || defaultKey;
150
159
  const model = (await promptQuestion(rl, `Model (${defaultModel}): `)).trim() || defaultModel;
151
160
 
152
161
  settings = {
@@ -155,34 +164,37 @@ async function runInteractiveConfig() {
155
164
  api_key: key,
156
165
  model
157
166
  };
158
- } else if (choice === "2") {
167
+ } else {
168
+ console.log("Contoh Base URL: https://tokenharbor.ai/v1 atau https://api.9router.com/v1");
159
169
  const baseUrl = (await promptQuestion(rl, "Base URL (https://tokenharbor.ai/v1): ")).trim() || "https://tokenharbor.ai/v1";
160
170
  const key = (await promptQuestion(rl, "API Key: ")).trim();
161
171
  const model = (await promptQuestion(rl, "Model (deepseek-v4.1-flash:free): ")).trim() || "deepseek-v4.1-flash:free";
162
- settings = { provider: "openai", api_key: key, base_url: baseUrl.replace(/\/+$/, ""), model };
163
- } else {
164
- const provider = (await promptQuestion(rl, "Tipe API [openai/anthropic] (openai): ")).trim() || "openai";
165
- const baseUrl = (await promptQuestion(rl, "Base URL: ")).trim();
166
- const key = (await promptQuestion(rl, "API Key: ")).trim();
167
- const model = (await promptQuestion(rl, "Model: ")).trim();
168
- settings = { provider, api_key: key, base_url: baseUrl.replace(/\/+$/, ""), model };
172
+ settings = {
173
+ provider: "openai",
174
+ api_key: key,
175
+ base_url: baseUrl.replace(/\/+$/, ""),
176
+ model
177
+ };
169
178
  }
170
179
 
171
180
  saveSettings(settings);
172
181
  rl.close();
173
- console.log("\x1b[32m✓ Saved to " + SETTINGS_PATH + "\x1b[0m\n");
182
+ console.log("\x1b[32m✓ Pengaturan disimpan di " + SETTINGS_PATH + "\x1b[0m\n");
174
183
  return settings;
175
184
  }
176
185
 
177
- // Loop untuk Anthropic / 9router protocol (/v1/messages)
186
+ // Loop untuk Anthropic / 9router local (/v1/messages)
178
187
  async function runAnthropicLoop(settings, convo) {
179
188
  const SYSTEM = `Kamu KILUA, AI Coding Agent di terminal lokal. Folder: ${process.cwd()}. Gunakan tools (read_file, write_file, edit_file, list_dir, run_cmd) untuk inspeksi dan eksekusi tugas coding mandiri. Respon ringkas to the point.`;
180
189
 
190
+ let endpoint = settings.base_url.replace(/\/+$/, "");
191
+ if (!endpoint.endsWith("/messages")) endpoint += "/messages";
192
+
181
193
  for (let step = 0; step < 12; step++) {
182
194
  process.stdout.write("\r\x1b[2K\x1b[35m[KILUA Berpikir...]\x1b[0m ");
183
195
  let res;
184
196
  try {
185
- res = await fetch(`${settings.base_url}/messages`, {
197
+ res = await fetch(endpoint, {
186
198
  method: "POST",
187
199
  headers: {
188
200
  "Content-Type": "application/json",
@@ -239,17 +251,29 @@ async function runAnthropicLoop(settings, convo) {
239
251
  console.log();
240
252
  }
241
253
 
242
- // Loop untuk OpenAI / TokenHarbor protocol (/v1/chat/completions)
254
+ // Loop untuk OpenAI / TokenHarbor / Gemini OpenAI protocol
243
255
  async function runOpenAiLoop(settings, convo) {
244
256
  const SYSTEM = `Kamu KILUA, AI Coding Agent di terminal lokal. Folder: ${process.cwd()}. Gunakan tools (read_file, write_file, edit_file, list_dir, run_cmd) untuk inspeksi dan eksekusi tugas coding mandiri. Respon ringkas to the point.`;
245
257
 
258
+ let endpoint = settings.base_url.replace(/\/+$/, "");
259
+ if (endpoint.includes("generativelanguage.googleapis.com") && !endpoint.includes("/openai")) {
260
+ endpoint += "/openai";
261
+ }
262
+ if (!endpoint.endsWith("/chat/completions")) {
263
+ endpoint += "/chat/completions";
264
+ }
265
+
246
266
  for (let step = 0; step < 12; step++) {
247
267
  process.stdout.write("\r\x1b[2K\x1b[35m[KILUA Berpikir...]\x1b[0m ");
248
268
  let res;
249
269
  try {
250
- res = await fetch(`${settings.base_url}/chat/completions`, {
270
+ res = await fetch(endpoint, {
251
271
  method: "POST",
252
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${settings.api_key}` },
272
+ headers: {
273
+ "Content-Type": "application/json",
274
+ Authorization: `Bearer ${settings.api_key}`,
275
+ "x-goog-api-key": settings.api_key
276
+ },
253
277
  body: JSON.stringify({ model: settings.model, messages: [{ role: "system", content: SYSTEM }, ...convo], tools: TOOLS_OPENAI, tool_choice: "auto" })
254
278
  });
255
279
  } catch (e) {
@@ -328,10 +352,10 @@ async function main() {
328
352
 
329
353
  console.log("\x1b[1m\x1b[35m=== KILUA AI CLI AGENT ===\x1b[0m");
330
354
  console.log(`CWD : \x1b[33m${process.cwd()}\x1b[0m`);
331
- console.log(`Provider: \x1b[32m${settings.base_url}\x1b[0m (${settings.model}) [${settings.provider || "openai"}]`);
355
+ console.log(`Provider: \x1b[32m${settings.base_url}\x1b[0m (${settings.model})`);
332
356
  console.log(`Config : \x1b[90m${SETTINGS_PATH}\x1b[0m (ketik 'config' untuk ganti)\n`);
333
357
 
334
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
358
+ let rl = readline.createInterface({ input: process.stdin, output: process.stdout });
335
359
  const ask = () => {
336
360
  rl.question("\x1b[1mKAMU > \x1b[0m", async input => {
337
361
  const q = input.trim();
@@ -341,6 +365,7 @@ async function main() {
341
365
  rl.close();
342
366
  await runInteractiveConfig();
343
367
  settings = loadSettings();
368
+ rl = readline.createInterface({ input: process.stdin, output: process.stdout });
344
369
  return ask();
345
370
  }
346
371
  await runAgent(settings, q, convo);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gilangranggaid/kilua-agent",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Autonomous AI Coding Agent for your terminal and VS Code",
5
5
  "type": "module",
6
6
  "main": "bin/kilua.mjs",