@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.
- package/bin/kilua.mjs +48 -23
- 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
|
|
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)
|
|
137
|
-
console.log("2)
|
|
138
|
-
console.log("3)
|
|
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 === "
|
|
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) + "..." : "
|
|
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
|
|
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 = {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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✓
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
270
|
+
res = await fetch(endpoint, {
|
|
251
271
|
method: "POST",
|
|
252
|
-
headers: {
|
|
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})
|
|
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
|
-
|
|
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);
|