@theokit/sdk-tools 0.24.1 → 0.26.0

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.cjs CHANGED
@@ -13,6 +13,7 @@ var child_process = require('child_process');
13
13
  var interactive = require('@theokit/sdk/interactive');
14
14
  var promises$1 = require('dns/promises');
15
15
  var net = require('net');
16
+ var crypto = require('crypto');
16
17
 
17
18
  // src/apply-patch.ts
18
19
 
@@ -1800,19 +1801,11 @@ function createQuestionTool(opts) {
1800
1801
  }
1801
1802
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
1802
1803
  var BINARY_PROBE_BYTES = 8 * 1024;
1803
- var SENSITIVE_SEGMENTS = /* @__PURE__ */ new Set([".env", ".git", "node_modules", ".theo"]);
1804
- function isForbiddenAtAnyDepth(path) {
1805
- const segs = path.replace(/\\/g, "/").split("/").filter(Boolean);
1806
- return segs.some((s) => {
1807
- if (s === ".env.example") return false;
1808
- return SENSITIVE_SEGMENTS.has(s) || /^\.env\./.test(s);
1809
- });
1810
- }
1811
1804
  function forbiddenReadError(path$1, allowAbsolute) {
1812
1805
  if (pathSafety.isForbiddenPath(path$1)) {
1813
1806
  return JSON.stringify({ ok: false, error: "forbidden_path", path: path$1 });
1814
1807
  }
1815
- if (allowAbsolute && path.isAbsolute(path$1) && isForbiddenAtAnyDepth(path$1)) {
1808
+ if (allowAbsolute && path.isAbsolute(path$1) && ehProibidoEmQualquerProfundidade(path$1)) {
1816
1809
  return JSON.stringify({ ok: false, error: "forbidden_path", path: path$1 });
1817
1810
  }
1818
1811
  return null;
@@ -2553,24 +2546,44 @@ function createTodolistTool() {
2553
2546
  getItems: (threadId) => ops(threadId).getItems()
2554
2547
  };
2555
2548
  }
2549
+ function decodeWholeCodePoints(buf) {
2550
+ return new TextDecoder("utf-8").decode(buf, { stream: true });
2551
+ }
2556
2552
  function truncateOutput(output, opts) {
2557
2553
  const maxBytes = opts?.maxBytes ?? 3e4;
2558
2554
  const outputDir = opts?.outputDir ?? ".theocode/tool-output";
2559
- const byteLength = Buffer.byteLength(output, "utf-8");
2560
- if (byteLength <= maxBytes) {
2561
- return { content: output, truncated: false };
2555
+ const mode = opts?.mode ?? "head";
2556
+ const originalBytes = Buffer.byteLength(output, "utf-8");
2557
+ if (originalBytes <= maxBytes) {
2558
+ return { content: output, truncated: false, originalBytes };
2562
2559
  }
2563
2560
  fs.mkdirSync(outputDir, { recursive: true });
2564
- const filename = `overflow-${Date.now()}.txt`;
2561
+ const filename = `overflow-${Date.now()}-${crypto.randomUUID().slice(0, 8)}.txt`;
2565
2562
  const overflowPath = path.join(outputDir, filename);
2566
2563
  fs.writeFileSync(overflowPath, output, "utf-8");
2567
- const truncated = Buffer.from(output, "utf-8").subarray(0, maxBytes).toString("utf-8");
2564
+ const buf = Buffer.from(output, "utf-8");
2568
2565
  const trailer = `
2569
2566
 
2570
2567
  [Output truncated. Full output: ${overflowPath}]`;
2568
+ if (mode === "head-tail") {
2569
+ const half = Math.floor(maxBytes / 2);
2570
+ const head = decodeWholeCodePoints(buf.subarray(0, half));
2571
+ const tail = decodeWholeCodePoints(buf.subarray(buf.length - half));
2572
+ return {
2573
+ content: `${head}
2574
+
2575
+ [\u2026 ${String(originalBytes - maxBytes)} bytes omitted \u2026]
2576
+
2577
+ ${tail}${trailer}`,
2578
+ truncated: true,
2579
+ originalBytes,
2580
+ overflowPath
2581
+ };
2582
+ }
2571
2583
  return {
2572
- content: truncated + trailer,
2584
+ content: decodeWholeCodePoints(buf.subarray(0, maxBytes)) + trailer,
2573
2585
  truncated: true,
2586
+ originalBytes,
2574
2587
  overflowPath
2575
2588
  };
2576
2589
  }