@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 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 requested = resolveAttachmentPath(cwd, requestedPath);
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("\\")) return true;
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.5",
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 ? "e9d5bdd60b06f2ee8d2d28f0d53b13d68298ae6b" : "development";
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 readdir3, unlink as unlink3, writeFile as writeFile6 } from "fs/promises";
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 readdir3(promptsDir);
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 readdir4 } from "fs/promises";
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 readdir4(root, { withFileTypes: true }).catch(() => []);
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((error) => {
10531
- notice("error", error instanceof Error ? error.message : String(error));
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) && await tryQueueAutomaticAttachment(text)) {
10585
- if (!detachedInput) setInput("");
10586
- return;
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) {