@kernelonpanic/kitcode 1.2.4 → 1.2.6
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/README.md +5 -1
- package/README.ru.md +7 -2
- package/dist/index.js +45 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@ http://localhost:11434/v1
|
|
|
88
88
|
| `kitcode -r <id>` | Resume a session by id. |
|
|
89
89
|
| `kitcode --cwd <path>` | Use another working directory. |
|
|
90
90
|
| `kitcode --model <provider/model>` | Start with a selected model. |
|
|
91
|
-
| `kitcode --mode <normal
|
|
91
|
+
| `kitcode --mode <normal|accept|plan>` | Select the initial agent mode. |
|
|
92
92
|
| `kitcode sessions` | List saved sessions. |
|
|
93
93
|
| `kitcode ask "question"` | Run one request without the TUI. |
|
|
94
94
|
| `kitcode add <url>` | Add a provider; the key is entered in a hidden prompt. |
|
|
@@ -112,17 +112,21 @@ Press `/` to open the command list.
|
|
|
112
112
|
| `/effort` · `/thinking` | Configure reasoning depth and output. |
|
|
113
113
|
| `/resume` · `/clear` | Resume a session or start a new one. |
|
|
114
114
|
| `/sessions` | Search sessions, then resume, rename, delete, or export one. |
|
|
115
|
+
| `/sessions list` | List all saved sessions. |
|
|
115
116
|
| `/sessions rename <id> <title>` | Give a saved session a title. |
|
|
117
|
+
| `/sessions delete <id>` | Delete a saved session. |
|
|
116
118
|
| `/sessions delete all` | Delete every saved chat after two separate confirmations. |
|
|
117
119
|
| `/sessions export <id> [path]` | Export a session to a private Markdown file (default: `.kitcode-exports/`). |
|
|
118
120
|
| `/attach <path>` · `/attach clipboard` · `/attach clear` | Manage attachments for the next message. |
|
|
119
121
|
| `/compact` | Replace older conversation context with a concise model-generated summary. |
|
|
122
|
+
| `/update` | Check npm for a newer KitCode version. |
|
|
120
123
|
| `/subagents` | Show the current number of active sub-agents. |
|
|
121
124
|
| `/undo` | Undo built-in file edits from the latest message. |
|
|
122
125
|
| `/usage` | Show tokens, requests, cost, balance/key limits, and response rate-limit headers when available. |
|
|
123
126
|
| `/checker` | Check the local setup and provider model listing without sending a paid chat request. |
|
|
124
127
|
| `/prompt` | Insert a saved prompt. |
|
|
125
128
|
| `/prompt save <name>` | Save the latest message as a prompt. |
|
|
129
|
+
| `/prompt delete <name>` | Delete a saved prompt. |
|
|
126
130
|
| `/skills` | Show discovered skills. |
|
|
127
131
|
| `/mcp add <name> <https://url>` | Add and connect a remote MCP server. |
|
|
128
132
|
| `/mcp add <name> -- <command> [args]` | Add and connect a local MCP server. |
|
package/README.ru.md
CHANGED
|
@@ -88,10 +88,10 @@ http://localhost:11434/v1
|
|
|
88
88
|
| `kitcode -r <id>` | Восстановить сессию по идентификатору. |
|
|
89
89
|
| `kitcode --cwd <path>` | Использовать другую рабочую директорию. |
|
|
90
90
|
| `kitcode --model <provider/model>` | Запуститься с выбранной моделью. |
|
|
91
|
-
| `kitcode --mode <normal
|
|
91
|
+
| `kitcode --mode <normal|accept|plan>` | Выбрать начальный режим работы. |
|
|
92
92
|
| `kitcode sessions` | Показать сохранённые сессии. |
|
|
93
93
|
| `kitcode ask "вопрос"` | Выполнить один запрос без TUI. |
|
|
94
|
-
| `kitcode add <url>` | Добавить
|
|
94
|
+
| `kitcode add <url>` | Добавить провайдера; ключ вводится в скрытом поле. |
|
|
95
95
|
| `kitcode add <url> --key-env <name>` | Прочитать ключ из переменной окружения. |
|
|
96
96
|
| `kitcode trust` | Включить конфиг и skills текущего проекта. |
|
|
97
97
|
| `kitcode config` | Показать расположение конфига и ключей. |
|
|
@@ -112,19 +112,24 @@ http://localhost:11434/v1
|
|
|
112
112
|
| `/effort` · `/thinking` | Настроить глубину и отображение reasoning. |
|
|
113
113
|
| `/resume` · `/clear` | Восстановить сессию или начать новую. |
|
|
114
114
|
| `/sessions` | Найти сессию и открыть, переименовать, удалить или экспортировать её. |
|
|
115
|
+
| `/sessions list` | Показать все сохранённые сессии. |
|
|
115
116
|
| `/sessions rename <id> <название>` | Переименовать сохранённую сессию. |
|
|
117
|
+
| `/sessions delete <id>` | Удалить сохранённую сессию. |
|
|
116
118
|
| `/sessions delete all` | Удалить все сохранённые чаты после двух отдельных подтверждений. |
|
|
117
119
|
| `/sessions export <id> [путь]` | Экспортировать сессию в приватный Markdown-файл (по умолчанию `.kitcode-exports/`). |
|
|
118
120
|
| `/attach <путь>` · `/attach clipboard` · `/attach clear` | Управлять вложениями следующего сообщения. |
|
|
119
121
|
| `/compact` | Заменить старую часть контекста краткой сводкой модели. |
|
|
122
|
+
| `/update` | Проверить новую версию KitCode в npm. |
|
|
120
123
|
| `/subagents` | Показать текущее количество активных суб-агентов. |
|
|
121
124
|
| `/undo` | Откатить встроенные правки файлов из последнего сообщения. |
|
|
122
125
|
| `/usage` | Показать токены, запросы, стоимость, доступный баланс и rate limits, если API их отдаёт. |
|
|
123
126
|
| `/checker` | Проверить настройку и список моделей без платного chat-запроса. |
|
|
124
127
|
| `/prompt` | Вставить сохранённый промт. |
|
|
125
128
|
| `/prompt save <name>` | Сохранить последнее сообщение как промт. |
|
|
129
|
+
| `/prompt delete <name>` | Удалить сохранённый промт. |
|
|
126
130
|
| `/skills` · `/mcp list` | Показать skills и состояние MCP. |
|
|
127
131
|
| `/mcp add <имя> <url>` | Добавить и сразу подключить MCP-сервер. |
|
|
132
|
+
| `/mcp add <имя> -- <команда> [аргументы]` | Добавить и подключить локальный MCP-сервер. |
|
|
128
133
|
| `/mcp enable <имя>` · `/mcp disable <имя>` | Подключить или отключить MCP без удаления. |
|
|
129
134
|
| `/mcp delete <имя>` | Отключить и удалить MCP-сервер. |
|
|
130
135
|
| `/theme` · `/lang` | Изменить тему или язык. |
|
package/dist/index.js
CHANGED
|
@@ -2467,7 +2467,7 @@ async function isFile2(file) {
|
|
|
2467
2467
|
|
|
2468
2468
|
// src/core/attachments.ts
|
|
2469
2469
|
import { execFile } from "child_process";
|
|
2470
|
-
import { lstat as lstat2, readFile as readFile6, stat as stat5 } from "fs/promises";
|
|
2470
|
+
import { lstat as lstat2, readdir as readdir3, readFile as readFile6, stat as stat5 } from "fs/promises";
|
|
2471
2471
|
import os2 from "os";
|
|
2472
2472
|
import path7 from "path";
|
|
2473
2473
|
import { fileURLToPath } from "url";
|
|
@@ -2506,15 +2506,17 @@ async function loadAttachment(cwd, requestedPath) {
|
|
|
2506
2506
|
if (error.code === "ENOENT") throw new Error(`Attachment not found: ${resolved}`);
|
|
2507
2507
|
throw error;
|
|
2508
2508
|
});
|
|
2509
|
+
if (info.isDirectory()) {
|
|
2510
|
+
const attachment = await loadFirstImageFromDirectory(resolved);
|
|
2511
|
+
if (attachment) return attachment;
|
|
2512
|
+
throw new Error(`No supported images found in directory: ${path7.basename(resolved)}`);
|
|
2513
|
+
}
|
|
2509
2514
|
if (!info.isFile()) throw new Error(`Attachment is not a regular file: ${resolved}`);
|
|
2510
2515
|
return loadResolvedAttachment(resolved, info.size);
|
|
2511
2516
|
}
|
|
2512
2517
|
async function loadAutomaticAttachment(cwd, requestedPath) {
|
|
2513
2518
|
if (!looksLikeAttachmentPath(requestedPath)) return null;
|
|
2514
|
-
const
|
|
2515
|
-
const safe = resolveInside(cwd, requested);
|
|
2516
|
-
if (!safe.ok || safe.relative === "") return null;
|
|
2517
|
-
const resolved = safe.path;
|
|
2519
|
+
const resolved = resolveAttachmentPath(cwd, requestedPath);
|
|
2518
2520
|
if (isSensitiveAutomaticPath(resolved)) {
|
|
2519
2521
|
throw new Error(
|
|
2520
2522
|
`For safety, sensitive-looking files must be attached explicitly with /attach: ${path7.basename(resolved)}`
|
|
@@ -2526,17 +2528,23 @@ async function loadAutomaticAttachment(cwd, requestedPath) {
|
|
|
2526
2528
|
if (error.code === "ENOENT" || error.code === "ENOTDIR") return null;
|
|
2527
2529
|
throw error;
|
|
2528
2530
|
});
|
|
2531
|
+
if (info?.isDirectory()) return loadFirstImageFromDirectory(resolved);
|
|
2529
2532
|
if (!info?.isFile()) return null;
|
|
2530
2533
|
return loadResolvedAttachment(resolved, info.size);
|
|
2531
2534
|
}
|
|
2535
|
+
var MAX_PATH_CHARS = 2048;
|
|
2532
2536
|
function looksLikeAttachmentPath(value) {
|
|
2533
2537
|
const trimmed = value.trim();
|
|
2534
2538
|
if (!trimmed || /[\r\n\0]/.test(trimmed)) return false;
|
|
2539
|
+
if (trimmed.length > MAX_PATH_CHARS) return false;
|
|
2535
2540
|
const candidate = normalizeInputPath(trimmed);
|
|
2536
2541
|
if (/^file:\/\//i.test(candidate)) return true;
|
|
2537
2542
|
if (path7.isAbsolute(candidate)) return true;
|
|
2538
2543
|
if (/^(?:~|\.{1,2})[\\/]/.test(candidate)) return true;
|
|
2539
|
-
if (candidate.includes("/") || candidate.includes("\\"))
|
|
2544
|
+
if (candidate.includes("/") || candidate.includes("\\")) {
|
|
2545
|
+
if (trimmed.length > 200) return false;
|
|
2546
|
+
return true;
|
|
2547
|
+
}
|
|
2540
2548
|
const basename3 = path7.basename(candidate).toLowerCase();
|
|
2541
2549
|
return path7.extname(basename3) !== "" || AUTO_PATH_NAMES.has(basename3);
|
|
2542
2550
|
}
|
|
@@ -2600,6 +2608,18 @@ async function loadResolvedAttachment(resolved, size) {
|
|
|
2600
2608
|
block: { type: "file", mediaType: textMime(resolved), text, name }
|
|
2601
2609
|
};
|
|
2602
2610
|
}
|
|
2611
|
+
async function loadFirstImageFromDirectory(dirPath) {
|
|
2612
|
+
const IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"]);
|
|
2613
|
+
const entries = await readdir3(dirPath, { withFileTypes: true }).catch(() => null);
|
|
2614
|
+
if (!entries) return null;
|
|
2615
|
+
const sorted = entries.filter((entry) => entry.isFile() && IMAGE_EXTENSIONS.has(path7.extname(entry.name).toLowerCase())).sort((a, b) => a.name.localeCompare(b.name));
|
|
2616
|
+
if (sorted.length === 0) return null;
|
|
2617
|
+
const first2 = sorted[0];
|
|
2618
|
+
const filePath = path7.join(dirPath, first2.name);
|
|
2619
|
+
const info = await stat5(filePath).catch(() => null);
|
|
2620
|
+
if (!info?.isFile()) return null;
|
|
2621
|
+
return loadResolvedAttachment(filePath, info.size);
|
|
2622
|
+
}
|
|
2603
2623
|
function resolveAttachmentPath(cwd, requestedPath) {
|
|
2604
2624
|
const cleaned = normalizeInputPath(requestedPath.trim());
|
|
2605
2625
|
if (!cleaned) throw new Error("Give a file path: /attach <path>");
|
|
@@ -3452,7 +3472,7 @@ function clip(value) {
|
|
|
3452
3472
|
// package.json
|
|
3453
3473
|
var package_default = {
|
|
3454
3474
|
name: "@kernelonpanic/kitcode",
|
|
3455
|
-
version: "1.2.
|
|
3475
|
+
version: "1.2.6",
|
|
3456
3476
|
description: "Terminal coding agent with a config you never have to write by hand",
|
|
3457
3477
|
type: "module",
|
|
3458
3478
|
license: "MIT",
|
|
@@ -3520,7 +3540,7 @@ var package_default = {
|
|
|
3520
3540
|
|
|
3521
3541
|
// src/version.ts
|
|
3522
3542
|
var KITCODE_VERSION = package_default.version;
|
|
3523
|
-
var KITCODE_COMMIT = true ? "
|
|
3543
|
+
var KITCODE_COMMIT = true ? "f40cc2cb3cebf7fa8b3c20dbbff5b14047d1e983" : "development";
|
|
3524
3544
|
|
|
3525
3545
|
// src/mcp/client.ts
|
|
3526
3546
|
var clientInfo = { name: "kitcode", version: KITCODE_VERSION };
|
|
@@ -5313,7 +5333,7 @@ function createToolRegistry(tools) {
|
|
|
5313
5333
|
}
|
|
5314
5334
|
|
|
5315
5335
|
// src/prompts/library.ts
|
|
5316
|
-
import { chmod as chmod6, readFile as readFile12, readdir as
|
|
5336
|
+
import { chmod as chmod6, readFile as readFile12, readdir as readdir4, unlink as unlink3, writeFile as writeFile6 } from "fs/promises";
|
|
5317
5337
|
import path10 from "path";
|
|
5318
5338
|
async function savePrompt(input) {
|
|
5319
5339
|
const slug = slugify(input.name);
|
|
@@ -5346,7 +5366,7 @@ async function getPrompt(slug) {
|
|
|
5346
5366
|
async function listPrompts() {
|
|
5347
5367
|
let names;
|
|
5348
5368
|
try {
|
|
5349
|
-
names = await
|
|
5369
|
+
names = await readdir4(promptsDir);
|
|
5350
5370
|
} catch (error) {
|
|
5351
5371
|
if (!isMissing(error)) throw error;
|
|
5352
5372
|
return [];
|
|
@@ -5418,7 +5438,7 @@ function parse(slug, text) {
|
|
|
5418
5438
|
}
|
|
5419
5439
|
|
|
5420
5440
|
// src/skills/library.ts
|
|
5421
|
-
import { lstat as lstat4, open as open2, readdir as
|
|
5441
|
+
import { lstat as lstat4, open as open2, readdir as readdir5 } from "fs/promises";
|
|
5422
5442
|
import path11 from "path";
|
|
5423
5443
|
var SKILL_FILE = "SKILL.md";
|
|
5424
5444
|
var FRONTMATTER_BYTES = 8192;
|
|
@@ -5430,7 +5450,7 @@ async function discoverSkills(dirs) {
|
|
|
5430
5450
|
for (const root of dirs) {
|
|
5431
5451
|
const rootInfo = await lstat4(root).catch(() => null);
|
|
5432
5452
|
if (!rootInfo?.isDirectory() || rootInfo.isSymbolicLink()) continue;
|
|
5433
|
-
const entries = await
|
|
5453
|
+
const entries = await readdir5(root, { withFileTypes: true }).catch(() => []);
|
|
5434
5454
|
const found = await Promise.all(
|
|
5435
5455
|
entries.filter((entry) => entry.isDirectory() && !entry.isSymbolicLink()).slice(0, MAX_SKILLS_PER_ROOT).map((entry) => readMeta(root, rootInfo, path11.join(root, entry.name)))
|
|
5436
5456
|
);
|
|
@@ -7569,6 +7589,7 @@ ${url}`,
|
|
|
7569
7589
|
lang: "\u0441\u043C\u0435\u043D\u0438\u0442\u044C \u044F\u0437\u044B\u043A \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430",
|
|
7570
7590
|
prompt: "\u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0438\u043B\u0438 \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u043F\u0440\u043E\u043C\u0442",
|
|
7571
7591
|
skills: "\u0441\u043F\u0438\u0441\u043E\u043A \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u044B\u0445 \u0441\u043A\u0438\u043B\u043B\u043E\u0432",
|
|
7592
|
+
"prompt delete": "\u0443\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D\u043D\u044B\u0439 \u043F\u0440\u043E\u043C\u0442",
|
|
7572
7593
|
bypass: "\u043E\u0442\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F (\u0441\u043F\u0440\u043E\u0441\u0438\u0442 \u0434\u0432\u0430\u0436\u0434\u044B)",
|
|
7573
7594
|
usage: "\u0442\u043E\u043A\u0435\u043D\u044B \u0438 \u0441\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C",
|
|
7574
7595
|
mcp: "\u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0438\u043B\u0438 \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C MCP-\u0441\u0435\u0440\u0432\u0435\u0440",
|
|
@@ -10526,9 +10547,8 @@ Rename the file if you want a different name.`);
|
|
|
10526
10547
|
}
|
|
10527
10548
|
notice("info", strings.attachmentAdded(attachmentLabel(block) ?? "attachment"));
|
|
10528
10549
|
return true;
|
|
10529
|
-
}).catch((
|
|
10530
|
-
|
|
10531
|
-
return true;
|
|
10550
|
+
}).catch(() => {
|
|
10551
|
+
return false;
|
|
10532
10552
|
});
|
|
10533
10553
|
automaticAttachmentTask.current = task;
|
|
10534
10554
|
void task.finally(() => {
|
|
@@ -10580,9 +10600,12 @@ Rename the file if you want a different name.`);
|
|
|
10580
10600
|
submitSlash();
|
|
10581
10601
|
return;
|
|
10582
10602
|
}
|
|
10583
|
-
if (text && looksLikeAttachmentPath(text)
|
|
10584
|
-
|
|
10585
|
-
|
|
10603
|
+
if (text && looksLikeAttachmentPath(text)) {
|
|
10604
|
+
const attached = await tryQueueAutomaticAttachment(text);
|
|
10605
|
+
if (attached) {
|
|
10606
|
+
if (!detachedInput) setInput("");
|
|
10607
|
+
return;
|
|
10608
|
+
}
|
|
10586
10609
|
}
|
|
10587
10610
|
if (text.startsWith("/")) {
|
|
10588
10611
|
submitSlash();
|
|
@@ -10617,8 +10640,11 @@ Rename the file if you want a different name.`);
|
|
|
10617
10640
|
return;
|
|
10618
10641
|
}
|
|
10619
10642
|
if (!key.escape) return;
|
|
10620
|
-
if (input !== "") {
|
|
10643
|
+
if (input !== "" || attachmentsRef.current.length > 0) {
|
|
10621
10644
|
setInput("");
|
|
10645
|
+
replaceAttachments([]);
|
|
10646
|
+
if (automaticAttachmentTask.current) automaticAttachmentTask.current = null;
|
|
10647
|
+
if (clipboardPasteTask.current) clipboardPasteTask.current = null;
|
|
10622
10648
|
return;
|
|
10623
10649
|
}
|
|
10624
10650
|
if (busy && abort.current) {
|