@kernelonpanic/kitcode 1.2.5 → 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/dist/index.js +44 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
);
|
|
@@ -10527,9 +10547,8 @@ Rename the file if you want a different name.`);
|
|
|
10527
10547
|
}
|
|
10528
10548
|
notice("info", strings.attachmentAdded(attachmentLabel(block) ?? "attachment"));
|
|
10529
10549
|
return true;
|
|
10530
|
-
}).catch((
|
|
10531
|
-
|
|
10532
|
-
return true;
|
|
10550
|
+
}).catch(() => {
|
|
10551
|
+
return false;
|
|
10533
10552
|
});
|
|
10534
10553
|
automaticAttachmentTask.current = task;
|
|
10535
10554
|
void task.finally(() => {
|
|
@@ -10581,9 +10600,12 @@ Rename the file if you want a different name.`);
|
|
|
10581
10600
|
submitSlash();
|
|
10582
10601
|
return;
|
|
10583
10602
|
}
|
|
10584
|
-
if (text && looksLikeAttachmentPath(text)
|
|
10585
|
-
|
|
10586
|
-
|
|
10603
|
+
if (text && looksLikeAttachmentPath(text)) {
|
|
10604
|
+
const attached = await tryQueueAutomaticAttachment(text);
|
|
10605
|
+
if (attached) {
|
|
10606
|
+
if (!detachedInput) setInput("");
|
|
10607
|
+
return;
|
|
10608
|
+
}
|
|
10587
10609
|
}
|
|
10588
10610
|
if (text.startsWith("/")) {
|
|
10589
10611
|
submitSlash();
|
|
@@ -10618,8 +10640,11 @@ Rename the file if you want a different name.`);
|
|
|
10618
10640
|
return;
|
|
10619
10641
|
}
|
|
10620
10642
|
if (!key.escape) return;
|
|
10621
|
-
if (input !== "") {
|
|
10643
|
+
if (input !== "" || attachmentsRef.current.length > 0) {
|
|
10622
10644
|
setInput("");
|
|
10645
|
+
replaceAttachments([]);
|
|
10646
|
+
if (automaticAttachmentTask.current) automaticAttachmentTask.current = null;
|
|
10647
|
+
if (clipboardPasteTask.current) clipboardPasteTask.current = null;
|
|
10623
10648
|
return;
|
|
10624
10649
|
}
|
|
10625
10650
|
if (busy && abort.current) {
|