bashkit 0.3.0 → 0.3.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/dist/index.js CHANGED
@@ -65,8 +65,25 @@ function createLazySingleton(factory) {
65
65
  };
66
66
  }
67
67
 
68
+ // src/sandbox/ripgrep.ts
69
+ async function getBundledRgPath() {
70
+ try {
71
+ const { rgPath } = await import("@vscode/ripgrep");
72
+ return rgPath;
73
+ } catch {
74
+ return;
75
+ }
76
+ }
77
+ function getBundledRgPathSync() {
78
+ try {
79
+ const { rgPath } = __require("@vscode/ripgrep");
80
+ return rgPath;
81
+ } catch {
82
+ return;
83
+ }
84
+ }
85
+
68
86
  // src/sandbox/ensure-tools.ts
69
- import { rgPath as bundledRgPath } from "@vscode/ripgrep";
70
87
  var RIPGREP_VERSION = "14.1.0";
71
88
  var ARCH_MAP = {
72
89
  x86_64: "x86_64-unknown-linux-musl",
@@ -74,10 +91,13 @@ var ARCH_MAP = {
74
91
  arm64: "aarch64-unknown-linux-gnu"
75
92
  };
76
93
  async function ensureSandboxTools(sandbox) {
77
- const bundledCheck = await sandbox.exec(`test -x "${bundledRgPath}" && echo found`);
78
- if (bundledCheck.stdout.includes("found")) {
79
- sandbox.rgPath = bundledRgPath;
80
- return;
94
+ const bundledRgPath = await getBundledRgPath();
95
+ if (bundledRgPath) {
96
+ const bundledCheck = await sandbox.exec(`test -x "${bundledRgPath}" && echo found`);
97
+ if (bundledCheck.stdout.includes("found")) {
98
+ sandbox.rgPath = bundledRgPath;
99
+ return;
100
+ }
81
101
  }
82
102
  const tmpCheck = await sandbox.exec("test -x /tmp/rg && echo found");
83
103
  if (tmpCheck.stdout.includes("found")) {
@@ -229,9 +249,9 @@ async function createE2BSandbox(config = {}) {
229
249
  }
230
250
  // src/sandbox/local.ts
231
251
  import { existsSync, mkdirSync } from "node:fs";
232
- import { rgPath as bundledRgPath2 } from "@vscode/ripgrep";
233
252
  function createLocalSandbox(config = {}) {
234
253
  const workingDirectory = config.cwd || "/tmp";
254
+ const rgPath = getBundledRgPathSync();
235
255
  if (!existsSync(workingDirectory)) {
236
256
  mkdirSync(workingDirectory, { recursive: true });
237
257
  }
@@ -271,7 +291,7 @@ function createLocalSandbox(config = {}) {
271
291
  };
272
292
  return {
273
293
  exec,
274
- rgPath: bundledRgPath2,
294
+ rgPath,
275
295
  async readFile(path) {
276
296
  const fullPath = path.startsWith("/") ? path : `${workingDirectory}/${path}`;
277
297
  const file = Bun.file(fullPath);
@@ -595,6 +615,184 @@ var DEFAULT_CONFIG = {
595
615
  // src/tools/ask-user.ts
596
616
  import { tool, zodSchema } from "ai";
597
617
  import { z } from "zod";
618
+
619
+ // src/utils/debug.ts
620
+ import { appendFileSync } from "node:fs";
621
+ var state = {
622
+ mode: "off",
623
+ logs: [],
624
+ counters: new Map,
625
+ parentStack: []
626
+ };
627
+ var MAX_STRING_LENGTH = 1000;
628
+ var MAX_ARRAY_ITEMS = 10;
629
+ function initDebugMode() {
630
+ const envValue = process.env.BASHKIT_DEBUG;
631
+ if (!envValue) {
632
+ state.mode = "off";
633
+ return;
634
+ }
635
+ if (envValue === "1" || envValue === "stderr") {
636
+ state.mode = "stderr";
637
+ } else if (envValue === "json") {
638
+ state.mode = "json";
639
+ } else if (envValue === "memory") {
640
+ state.mode = "memory";
641
+ } else if (envValue.startsWith("file:")) {
642
+ state.mode = "file";
643
+ state.filePath = envValue.slice(5);
644
+ } else {
645
+ state.mode = "stderr";
646
+ }
647
+ }
648
+ initDebugMode();
649
+ function isDebugEnabled() {
650
+ return state.mode !== "off";
651
+ }
652
+ function generateId(tool) {
653
+ const count = (state.counters.get(tool) || 0) + 1;
654
+ state.counters.set(tool, count);
655
+ return `${tool}-${count}`;
656
+ }
657
+ function truncateString(str) {
658
+ if (str.length <= MAX_STRING_LENGTH)
659
+ return str;
660
+ return `${str.slice(0, MAX_STRING_LENGTH)}... [truncated, ${str.length - MAX_STRING_LENGTH} more chars]`;
661
+ }
662
+ function summarize(data, depth = 0) {
663
+ if (depth > 5)
664
+ return "[nested object]";
665
+ if (data === null || data === undefined)
666
+ return data;
667
+ if (typeof data === "string") {
668
+ return truncateString(data);
669
+ }
670
+ if (typeof data === "number" || typeof data === "boolean") {
671
+ return data;
672
+ }
673
+ if (Array.isArray(data)) {
674
+ const truncated = data.length > MAX_ARRAY_ITEMS;
675
+ const items = data.slice(0, MAX_ARRAY_ITEMS).map((item) => summarize(item, depth + 1));
676
+ if (truncated) {
677
+ return [...items, `[${data.length - MAX_ARRAY_ITEMS} more items]`];
678
+ }
679
+ return items;
680
+ }
681
+ if (typeof data === "object") {
682
+ const result = {};
683
+ for (const [key, value] of Object.entries(data)) {
684
+ result[key] = summarize(value, depth + 1);
685
+ }
686
+ return result;
687
+ }
688
+ return String(data);
689
+ }
690
+ function emitEvent(event) {
691
+ if (state.mode === "off")
692
+ return;
693
+ switch (state.mode) {
694
+ case "memory":
695
+ state.logs.push(event);
696
+ break;
697
+ case "json":
698
+ process.stderr.write(`${JSON.stringify(event)}
699
+ `);
700
+ break;
701
+ case "file":
702
+ if (state.filePath) {
703
+ appendFileSync(state.filePath, `${JSON.stringify(event)}
704
+ `);
705
+ }
706
+ break;
707
+ case "stderr":
708
+ default:
709
+ formatHumanReadable(event);
710
+ break;
711
+ }
712
+ }
713
+ function formatHumanReadable(event) {
714
+ const indent = " ".repeat(state.parentStack.length);
715
+ if (event.event === "start") {
716
+ const inputSummary = event.input ? Object.entries(event.input).map(([k, v]) => `${k}=${JSON.stringify(v)}`).slice(0, 3).join(" ") : "";
717
+ process.stderr.write(`${indent}[bashkit:${event.tool}] → ${inputSummary}
718
+ `);
719
+ } else if (event.event === "end") {
720
+ const summaryStr = event.summary ? Object.entries(event.summary).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(" ") : "";
721
+ process.stderr.write(`${indent}[bashkit:${event.tool}] ← ${event.duration_ms}ms ${summaryStr}
722
+ `);
723
+ } else if (event.event === "error") {
724
+ process.stderr.write(`${indent}[bashkit:${event.tool}] ✗ ${event.error}
725
+ `);
726
+ }
727
+ }
728
+ function debugStart(tool, input) {
729
+ if (state.mode === "off")
730
+ return "";
731
+ const id = generateId(tool);
732
+ const parent = state.parentStack.length > 0 ? state.parentStack[state.parentStack.length - 1] : undefined;
733
+ const event = {
734
+ id,
735
+ ts: Date.now(),
736
+ tool,
737
+ event: "start",
738
+ input: input ? summarize(input) : undefined,
739
+ parent
740
+ };
741
+ emitEvent(event);
742
+ return id;
743
+ }
744
+ function debugEnd(id, tool, options) {
745
+ if (state.mode === "off" || !id)
746
+ return;
747
+ const event = {
748
+ id,
749
+ ts: Date.now(),
750
+ tool,
751
+ event: "end",
752
+ output: options.output ? summarize(options.output) : undefined,
753
+ summary: options.summary,
754
+ duration_ms: options.duration_ms
755
+ };
756
+ emitEvent(event);
757
+ }
758
+ function debugError(id, tool, error) {
759
+ if (state.mode === "off" || !id)
760
+ return;
761
+ const event = {
762
+ id,
763
+ ts: Date.now(),
764
+ tool,
765
+ event: "error",
766
+ error: error instanceof Error ? error.message : error
767
+ };
768
+ emitEvent(event);
769
+ }
770
+ function pushParent(id) {
771
+ if (state.mode === "off" || !id)
772
+ return;
773
+ state.parentStack.push(id);
774
+ }
775
+ function popParent() {
776
+ if (state.mode === "off")
777
+ return;
778
+ state.parentStack.pop();
779
+ }
780
+ function getDebugLogs() {
781
+ return [...state.logs];
782
+ }
783
+ function clearDebugLogs() {
784
+ state.logs = [];
785
+ state.counters.clear();
786
+ state.parentStack = [];
787
+ }
788
+ function reinitDebugMode() {
789
+ state.logs = [];
790
+ state.counters.clear();
791
+ state.parentStack = [];
792
+ initDebugMode();
793
+ }
794
+
795
+ // src/tools/ask-user.ts
598
796
  var questionOptionSchema = z.object({
599
797
  label: z.string().describe("The display text for this option. Should be concise (1-5 words). Add '(Recommended)' suffix for suggested options."),
600
798
  description: z.string().optional().describe("Explanation of what this option means or its implications.")
@@ -644,22 +842,46 @@ function createAskUserTool(config) {
644
842
  description: ASK_USER_DESCRIPTION,
645
843
  inputSchema: zodSchema(askUserInputSchema),
646
844
  execute: async (input) => {
845
+ const startTime = performance.now();
846
+ const debugId = isDebugEnabled() ? debugStart("ask-user", {
847
+ hasQuestion: !!input.question,
848
+ questionCount: input.questions?.length ?? 0,
849
+ question: input.question ? input.question.length > 100 ? `${input.question.slice(0, 100)}...` : input.question : undefined
850
+ }) : "";
647
851
  try {
648
852
  if (!input.question && !input.questions) {
649
- return {
650
- error: "Either 'question' or 'questions' must be provided"
651
- };
853
+ const error2 = "Either 'question' or 'questions' must be provided";
854
+ if (debugId)
855
+ debugError(debugId, "ask-user", error2);
856
+ return { error: error2 };
652
857
  }
653
858
  if (input.questions && input.questions.length > 0) {
654
859
  if (normalizedConfig.onStructuredQuestions) {
655
860
  const answers = await normalizedConfig.onStructuredQuestions(input.questions);
656
861
  const firstKey = Object.keys(answers)[0];
657
862
  const firstAnswer = answers[firstKey];
863
+ const durationMs2 = Math.round(performance.now() - startTime);
864
+ if (debugId) {
865
+ debugEnd(debugId, "ask-user", {
866
+ summary: {
867
+ type: "structured",
868
+ answerCount: Object.keys(answers).length
869
+ },
870
+ duration_ms: durationMs2
871
+ });
872
+ }
658
873
  return {
659
874
  answer: Array.isArray(firstAnswer) ? firstAnswer.join(", ") : firstAnswer,
660
875
  answers
661
876
  };
662
877
  }
878
+ const durationMs = Math.round(performance.now() - startTime);
879
+ if (debugId) {
880
+ debugEnd(debugId, "ask-user", {
881
+ summary: { type: "structured", awaiting: true },
882
+ duration_ms: durationMs
883
+ });
884
+ }
663
885
  return {
664
886
  questions: input.questions,
665
887
  awaiting_response: true
@@ -668,18 +890,36 @@ function createAskUserTool(config) {
668
890
  if (input.question) {
669
891
  if (normalizedConfig.onQuestion) {
670
892
  const answer = await normalizedConfig.onQuestion(input.question);
893
+ const durationMs2 = Math.round(performance.now() - startTime);
894
+ if (debugId) {
895
+ debugEnd(debugId, "ask-user", {
896
+ summary: { type: "simple", hasAnswer: true },
897
+ duration_ms: durationMs2
898
+ });
899
+ }
671
900
  return { answer };
672
901
  }
902
+ const durationMs = Math.round(performance.now() - startTime);
903
+ if (debugId) {
904
+ debugEnd(debugId, "ask-user", {
905
+ summary: { type: "simple", awaiting: true },
906
+ duration_ms: durationMs
907
+ });
908
+ }
673
909
  return {
674
910
  question: input.question,
675
911
  awaiting_response: true
676
912
  };
677
913
  }
678
- return { error: "No question provided" };
914
+ const error = "No question provided";
915
+ if (debugId)
916
+ debugError(debugId, "ask-user", error);
917
+ return { error };
679
918
  } catch (error) {
680
- return {
681
- error: error instanceof Error ? error.message : "Unknown error"
682
- };
919
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
920
+ if (debugId)
921
+ debugError(debugId, "ask-user", errorMessage);
922
+ return { error: errorMessage };
683
923
  }
684
924
  }
685
925
  });
@@ -743,12 +983,18 @@ function createBashTool(sandbox, config) {
743
983
  description: _description,
744
984
  run_in_background: _run_in_background
745
985
  }) => {
986
+ const startTime = performance.now();
987
+ const debugId = isDebugEnabled() ? debugStart("bash", {
988
+ command: command.length > 200 ? `${command.slice(0, 200)}...` : command,
989
+ timeout
990
+ }) : "";
746
991
  if (config?.blockedCommands) {
747
992
  for (const blocked of config.blockedCommands) {
748
993
  if (command.includes(blocked)) {
749
- return {
750
- error: `Command blocked: contains '${blocked}'`
751
- };
994
+ const error = `Command blocked: contains '${blocked}'`;
995
+ if (debugId)
996
+ debugError(debugId, "bash", error);
997
+ return { error };
752
998
  }
753
999
  }
754
1000
  }
@@ -767,6 +1013,18 @@ function createBashTool(sandbox, config) {
767
1013
  stderr = stderr.slice(0, maxOutputLength) + `
768
1014
  [output truncated, ${stderr.length - maxOutputLength} chars omitted]`;
769
1015
  }
1016
+ const durationMs = Math.round(performance.now() - startTime);
1017
+ if (debugId) {
1018
+ debugEnd(debugId, "bash", {
1019
+ summary: {
1020
+ exitCode: result.exitCode,
1021
+ stdoutLen: result.stdout.length,
1022
+ stderrLen: result.stderr.length,
1023
+ interrupted: result.interrupted
1024
+ },
1025
+ duration_ms: durationMs
1026
+ });
1027
+ }
770
1028
  return {
771
1029
  stdout,
772
1030
  stderr,
@@ -775,9 +1033,10 @@ function createBashTool(sandbox, config) {
775
1033
  duration_ms: result.durationMs
776
1034
  };
777
1035
  } catch (error) {
778
- return {
779
- error: error instanceof Error ? error.message : "Unknown error"
780
- };
1036
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1037
+ if (debugId)
1038
+ debugError(debugId, "bash", errorMessage);
1039
+ return { error: errorMessage };
781
1040
  }
782
1041
  }
783
1042
  });
@@ -822,29 +1081,48 @@ function createEditTool(sandbox, config) {
822
1081
  new_string,
823
1082
  replace_all = false
824
1083
  }) => {
1084
+ const startTime = performance.now();
1085
+ const debugId = isDebugEnabled() ? debugStart("edit", {
1086
+ file_path,
1087
+ old_string: old_string.length > 100 ? `${old_string.slice(0, 100)}...` : old_string,
1088
+ replace_all
1089
+ }) : "";
825
1090
  if (old_string === new_string) {
826
- return { error: "old_string and new_string must be different" };
1091
+ const error = "old_string and new_string must be different";
1092
+ if (debugId)
1093
+ debugError(debugId, "edit", error);
1094
+ return { error };
827
1095
  }
828
1096
  if (config?.allowedPaths) {
829
1097
  const isAllowed = config.allowedPaths.some((allowed) => file_path.startsWith(allowed));
830
1098
  if (!isAllowed) {
831
- return { error: `Path not allowed: ${file_path}` };
1099
+ const error = `Path not allowed: ${file_path}`;
1100
+ if (debugId)
1101
+ debugError(debugId, "edit", error);
1102
+ return { error };
832
1103
  }
833
1104
  }
834
1105
  try {
835
1106
  const exists = await sandbox.fileExists(file_path);
836
1107
  if (!exists) {
837
- return { error: `File not found: ${file_path}` };
1108
+ const error = `File not found: ${file_path}`;
1109
+ if (debugId)
1110
+ debugError(debugId, "edit", error);
1111
+ return { error };
838
1112
  }
839
1113
  const content = await sandbox.readFile(file_path);
840
1114
  const occurrences = content.split(old_string).length - 1;
841
1115
  if (occurrences === 0) {
842
- return { error: `String not found in file: "${old_string}"` };
1116
+ const error = `String not found in file: "${old_string}"`;
1117
+ if (debugId)
1118
+ debugError(debugId, "edit", error);
1119
+ return { error };
843
1120
  }
844
1121
  if (!replace_all && occurrences > 1) {
845
- return {
846
- error: `String appears ${occurrences} times in file. Use replace_all=true to replace all, or provide a more unique string.`
847
- };
1122
+ const error = `String appears ${occurrences} times in file. Use replace_all=true to replace all, or provide a more unique string.`;
1123
+ if (debugId)
1124
+ debugError(debugId, "edit", error);
1125
+ return { error };
848
1126
  }
849
1127
  let newContent;
850
1128
  let replacements;
@@ -856,15 +1134,23 @@ function createEditTool(sandbox, config) {
856
1134
  replacements = 1;
857
1135
  }
858
1136
  await sandbox.writeFile(file_path, newContent);
1137
+ const durationMs = Math.round(performance.now() - startTime);
1138
+ if (debugId) {
1139
+ debugEnd(debugId, "edit", {
1140
+ summary: { replacements },
1141
+ duration_ms: durationMs
1142
+ });
1143
+ }
859
1144
  return {
860
1145
  message: `Successfully edited ${file_path}`,
861
1146
  file_path,
862
1147
  replacements
863
1148
  };
864
1149
  } catch (error) {
865
- return {
866
- error: error instanceof Error ? error.message : "Unknown error"
867
- };
1150
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1151
+ if (debugId)
1152
+ debugError(debugId, "edit", errorMessage);
1153
+ return { error: errorMessage };
868
1154
  }
869
1155
  }
870
1156
  });
@@ -931,33 +1217,44 @@ In plan mode, you'll:
931
1217
  - This tool REQUIRES user approval - they must consent to entering plan mode
932
1218
  - If unsure whether to use it, err on the side of planning - it's better to get alignment upfront than to redo work
933
1219
  - Users appreciate being consulted before significant changes`;
934
- function createEnterPlanModeTool(state, onEnter) {
1220
+ function createEnterPlanModeTool(state2, onEnter) {
935
1221
  return tool4({
936
1222
  description: ENTER_PLAN_MODE_DESCRIPTION,
937
1223
  inputSchema: zodSchema4(enterPlanModeInputSchema),
938
1224
  execute: async ({
939
1225
  reason
940
1226
  }) => {
1227
+ const startTime = performance.now();
1228
+ const debugId = isDebugEnabled() ? debugStart("enter-plan-mode", { reason }) : "";
941
1229
  try {
942
- if (state.isActive) {
943
- return {
944
- error: "Already in planning mode. Use ExitPlanMode to exit."
945
- };
1230
+ if (state2.isActive) {
1231
+ const error = "Already in planning mode. Use ExitPlanMode to exit.";
1232
+ if (debugId)
1233
+ debugError(debugId, "enter-plan-mode", error);
1234
+ return { error };
946
1235
  }
947
- state.isActive = true;
948
- state.enteredAt = new Date;
949
- state.reason = reason;
1236
+ state2.isActive = true;
1237
+ state2.enteredAt = new Date;
1238
+ state2.reason = reason;
950
1239
  if (onEnter) {
951
1240
  await onEnter(reason);
952
1241
  }
1242
+ const durationMs = Math.round(performance.now() - startTime);
1243
+ if (debugId) {
1244
+ debugEnd(debugId, "enter-plan-mode", {
1245
+ summary: { mode: "planning" },
1246
+ duration_ms: durationMs
1247
+ });
1248
+ }
953
1249
  return {
954
1250
  message: `Entered planning mode: ${reason}. Use Read, Grep, and Glob to explore. Call ExitPlanMode when ready with a plan.`,
955
1251
  mode: "planning"
956
1252
  };
957
1253
  } catch (error) {
958
- return {
959
- error: error instanceof Error ? error.message : "Unknown error"
960
- };
1254
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1255
+ if (debugId)
1256
+ debugError(debugId, "enter-plan-mode", errorMessage);
1257
+ return { error: errorMessage };
961
1258
  }
962
1259
  }
963
1260
  });
@@ -997,19 +1294,32 @@ function createExitPlanModeTool(onPlanSubmit) {
997
1294
  execute: async ({
998
1295
  plan
999
1296
  }) => {
1297
+ const startTime = performance.now();
1298
+ const debugId = isDebugEnabled() ? debugStart("exit-plan-mode", {
1299
+ planLength: plan.length,
1300
+ planPreview: plan.length > 200 ? `${plan.slice(0, 200)}...` : plan
1301
+ }) : "";
1000
1302
  try {
1001
1303
  let approved;
1002
1304
  if (onPlanSubmit) {
1003
1305
  approved = await onPlanSubmit(plan);
1004
1306
  }
1307
+ const durationMs = Math.round(performance.now() - startTime);
1308
+ if (debugId) {
1309
+ debugEnd(debugId, "exit-plan-mode", {
1310
+ summary: { approved },
1311
+ duration_ms: durationMs
1312
+ });
1313
+ }
1005
1314
  return {
1006
1315
  message: approved ? "Plan approved, proceeding with execution" : "Plan submitted for review",
1007
1316
  approved
1008
1317
  };
1009
1318
  } catch (error) {
1010
- return {
1011
- error: error instanceof Error ? error.message : "Unknown error"
1012
- };
1319
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1320
+ if (debugId)
1321
+ debugError(debugId, "exit-plan-mode", errorMessage);
1322
+ return { error: errorMessage };
1013
1323
  }
1014
1324
  }
1015
1325
  });
@@ -1042,28 +1352,47 @@ function createGlobTool(sandbox, config) {
1042
1352
  path
1043
1353
  }) => {
1044
1354
  const searchPath = path || ".";
1355
+ const startTime = performance.now();
1356
+ const debugId = isDebugEnabled() ? debugStart("glob", { pattern, path: searchPath }) : "";
1045
1357
  if (config?.allowedPaths) {
1046
1358
  const isAllowed = config.allowedPaths.some((allowed) => searchPath.startsWith(allowed));
1047
1359
  if (!isAllowed) {
1048
- return { error: `Path not allowed: ${searchPath}` };
1360
+ const error = `Path not allowed: ${searchPath}`;
1361
+ if (debugId)
1362
+ debugError(debugId, "glob", error);
1363
+ return { error };
1049
1364
  }
1050
1365
  }
1051
1366
  try {
1052
- const result = await sandbox.exec(`find ${searchPath} -type f -name "${pattern}" 2>/dev/null | head -1000`, { timeout: config?.timeout });
1367
+ const findFlag = pattern.includes("/") ? "-path" : "-name";
1368
+ const findPattern = pattern.includes("/") && !pattern.startsWith("*") ? `*/${pattern}` : pattern;
1369
+ const result = await sandbox.exec(`find ${searchPath} -type f ${findFlag} "${findPattern}" 2>/dev/null | head -1000`, { timeout: config?.timeout });
1053
1370
  if (result.exitCode !== 0 && result.stderr) {
1054
- return { error: result.stderr };
1371
+ const error = result.stderr;
1372
+ if (debugId)
1373
+ debugError(debugId, "glob", error);
1374
+ return { error };
1055
1375
  }
1056
1376
  const matches = result.stdout.split(`
1057
1377
  `).filter(Boolean).map((p) => p.trim());
1378
+ const durationMs = Math.round(performance.now() - startTime);
1379
+ if (debugId) {
1380
+ debugEnd(debugId, "glob", {
1381
+ summary: { count: matches.length },
1382
+ output: matches.slice(0, 10),
1383
+ duration_ms: durationMs
1384
+ });
1385
+ }
1058
1386
  return {
1059
1387
  matches,
1060
1388
  count: matches.length,
1061
1389
  search_path: searchPath
1062
1390
  };
1063
1391
  } catch (error) {
1064
- return {
1065
- error: error instanceof Error ? error.message : "Unknown error"
1066
- };
1392
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1393
+ if (debugId)
1394
+ debugError(debugId, "glob", errorMessage);
1395
+ return { error: errorMessage };
1067
1396
  }
1068
1397
  }
1069
1398
  });
@@ -1130,17 +1459,31 @@ function createGrepTool(sandbox, config) {
1130
1459
  multiline
1131
1460
  } = input;
1132
1461
  const searchPath = path || ".";
1462
+ const startTime = performance.now();
1463
+ const debugId = isDebugEnabled() ? debugStart("grep", {
1464
+ pattern,
1465
+ path: searchPath,
1466
+ output_mode,
1467
+ glob,
1468
+ type,
1469
+ caseInsensitive,
1470
+ multiline
1471
+ }) : "";
1133
1472
  if (config?.allowedPaths) {
1134
1473
  const isAllowed = config.allowedPaths.some((allowed) => searchPath.startsWith(allowed));
1135
1474
  if (!isAllowed) {
1136
- return { error: `Path not allowed: ${searchPath}` };
1475
+ const error = `Path not allowed: ${searchPath}`;
1476
+ if (debugId)
1477
+ debugError(debugId, "grep", error);
1478
+ return { error };
1137
1479
  }
1138
1480
  }
1139
1481
  try {
1140
1482
  if (!sandbox.rgPath) {
1141
- return {
1142
- error: "Ripgrep not available. Call ensureSandboxTools(sandbox) before using Grep with remote sandboxes."
1143
- };
1483
+ const error = "Ripgrep not available. Call ensureSandboxTools(sandbox) before using Grep with remote sandboxes.";
1484
+ if (debugId)
1485
+ debugError(debugId, "grep", error);
1486
+ return { error };
1144
1487
  }
1145
1488
  const cmd = buildRipgrepCommand({
1146
1489
  rgPath: sandbox.rgPath,
@@ -1156,17 +1499,48 @@ function createGrepTool(sandbox, config) {
1156
1499
  multiline
1157
1500
  });
1158
1501
  const result = await sandbox.exec(cmd, { timeout: config?.timeout });
1502
+ const durationMs = Math.round(performance.now() - startTime);
1503
+ let output;
1159
1504
  if (output_mode === "files_with_matches") {
1160
- return parseFilesOutput(result.stdout);
1505
+ output = parseFilesOutput(result.stdout);
1506
+ if (debugId) {
1507
+ debugEnd(debugId, "grep", {
1508
+ summary: {
1509
+ fileCount: output.count,
1510
+ exitCode: result.exitCode
1511
+ },
1512
+ duration_ms: durationMs
1513
+ });
1514
+ }
1161
1515
  } else if (output_mode === "count") {
1162
- return parseCountOutput(result.stdout);
1516
+ output = parseCountOutput(result.stdout);
1517
+ if (debugId) {
1518
+ debugEnd(debugId, "grep", {
1519
+ summary: {
1520
+ total: output.total,
1521
+ exitCode: result.exitCode
1522
+ },
1523
+ duration_ms: durationMs
1524
+ });
1525
+ }
1163
1526
  } else {
1164
- return parseContentOutput(result.stdout, head_limit, offset);
1527
+ output = parseContentOutput(result.stdout, head_limit, offset);
1528
+ if (debugId) {
1529
+ debugEnd(debugId, "grep", {
1530
+ summary: {
1531
+ matchCount: output.total_matches,
1532
+ exitCode: result.exitCode
1533
+ },
1534
+ duration_ms: durationMs
1535
+ });
1536
+ }
1165
1537
  }
1538
+ return output;
1166
1539
  } catch (error) {
1167
- return {
1168
- error: error instanceof Error ? error.message : "Unknown error"
1169
- };
1540
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1541
+ if (debugId)
1542
+ debugError(debugId, "grep", errorMessage);
1543
+ return { error: errorMessage };
1170
1544
  }
1171
1545
  }
1172
1546
  });
@@ -1357,20 +1731,35 @@ function createReadTool(sandbox, config) {
1357
1731
  offset,
1358
1732
  limit
1359
1733
  }) => {
1734
+ const startTime = performance.now();
1735
+ const debugId = isDebugEnabled() ? debugStart("read", { file_path, offset, limit }) : "";
1360
1736
  if (config?.allowedPaths) {
1361
1737
  const isAllowed = config.allowedPaths.some((allowed) => file_path.startsWith(allowed));
1362
1738
  if (!isAllowed) {
1363
- return { error: `Path not allowed: ${file_path}` };
1739
+ const error = `Path not allowed: ${file_path}`;
1740
+ if (debugId)
1741
+ debugError(debugId, "read", error);
1742
+ return { error };
1364
1743
  }
1365
1744
  }
1366
1745
  try {
1367
1746
  const exists = await sandbox.fileExists(file_path);
1368
1747
  if (!exists) {
1369
- return { error: `Path not found: ${file_path}` };
1748
+ const error = `Path not found: ${file_path}`;
1749
+ if (debugId)
1750
+ debugError(debugId, "read", error);
1751
+ return { error };
1370
1752
  }
1371
1753
  const isDir = await sandbox.isDirectory(file_path);
1372
1754
  if (isDir) {
1373
1755
  const entries = await sandbox.readDir(file_path);
1756
+ const durationMs2 = Math.round(performance.now() - startTime);
1757
+ if (debugId) {
1758
+ debugEnd(debugId, "read", {
1759
+ summary: { type: "directory", count: entries.length },
1760
+ duration_ms: durationMs2
1761
+ });
1762
+ }
1374
1763
  return {
1375
1764
  type: "directory",
1376
1765
  entries,
@@ -1396,9 +1785,10 @@ function createReadTool(sandbox, config) {
1396
1785
  "dylib"
1397
1786
  ];
1398
1787
  if (binaryExtensions.includes(ext || "")) {
1399
- return {
1400
- error: `Cannot read binary file: ${file_path} (file exists, ${content.length} bytes). Use appropriate tools to process ${ext?.toUpperCase()} files (e.g., Python scripts for PDFs).`
1401
- };
1788
+ const error = `Cannot read binary file: ${file_path} (file exists, ${content.length} bytes). Use appropriate tools to process ${ext?.toUpperCase()} files (e.g., Python scripts for PDFs).`;
1789
+ if (debugId)
1790
+ debugError(debugId, "read", error);
1791
+ return { error };
1402
1792
  }
1403
1793
  }
1404
1794
  const allLines = content.split(`
@@ -1406,9 +1796,10 @@ function createReadTool(sandbox, config) {
1406
1796
  const totalLines = allLines.length;
1407
1797
  const maxLinesWithoutLimit = config?.maxFileSize || 500;
1408
1798
  if (!limit && totalLines > maxLinesWithoutLimit) {
1409
- return {
1410
- error: `File is large (${totalLines} lines). Use 'offset' and 'limit' to read in chunks. Example: offset=1, limit=100 for first 100 lines.`
1411
- };
1799
+ const error = `File is large (${totalLines} lines). Use 'offset' and 'limit' to read in chunks. Example: offset=1, limit=100 for first 100 lines.`;
1800
+ if (debugId)
1801
+ debugError(debugId, "read", error);
1802
+ return { error };
1412
1803
  }
1413
1804
  const startLine = offset ? offset - 1 : 0;
1414
1805
  const endLine = limit ? startLine + limit : allLines.length;
@@ -1417,6 +1808,18 @@ function createReadTool(sandbox, config) {
1417
1808
  line_number: startLine + i + 1,
1418
1809
  content: line
1419
1810
  }));
1811
+ const durationMs = Math.round(performance.now() - startTime);
1812
+ if (debugId) {
1813
+ debugEnd(debugId, "read", {
1814
+ summary: {
1815
+ type: "text",
1816
+ totalLines,
1817
+ returnedLines: lines.length,
1818
+ bytes: content.length
1819
+ },
1820
+ duration_ms: durationMs
1821
+ });
1822
+ }
1420
1823
  return {
1421
1824
  type: "text",
1422
1825
  content: selectedLines.join(`
@@ -1425,9 +1828,10 @@ function createReadTool(sandbox, config) {
1425
1828
  total_lines: totalLines
1426
1829
  };
1427
1830
  } catch (error) {
1428
- return {
1429
- error: error instanceof Error ? error.message : "Unknown error"
1430
- };
1831
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1832
+ if (debugId)
1833
+ debugError(debugId, "read", errorMessage);
1834
+ return { error: errorMessage };
1431
1835
  }
1432
1836
  }
1433
1837
  });
@@ -1461,22 +1865,29 @@ function createSkillTool(config) {
1461
1865
  execute: async ({
1462
1866
  name
1463
1867
  }) => {
1868
+ const startTime = performance.now();
1869
+ const debugId = isDebugEnabled() ? debugStart("skill", { name, availableSkills: Object.keys(skills) }) : "";
1464
1870
  try {
1465
1871
  const skill = skills[name];
1466
1872
  if (!skill) {
1467
1873
  const available = Object.keys(skills);
1468
1874
  if (available.length === 0) {
1469
- return { error: "No skills are available." };
1875
+ const error2 = "No skills are available.";
1876
+ if (debugId)
1877
+ debugError(debugId, "skill", error2);
1878
+ return { error: error2 };
1470
1879
  }
1471
- return {
1472
- error: `Skill '${name}' not found. Available skills: ${available.join(", ")}`
1473
- };
1880
+ const error = `Skill '${name}' not found. Available skills: ${available.join(", ")}`;
1881
+ if (debugId)
1882
+ debugError(debugId, "skill", error);
1883
+ return { error };
1474
1884
  }
1475
1885
  let instructions;
1476
1886
  if (!sandbox) {
1477
- return {
1478
- error: `Cannot load skill '${name}': no sandbox provided to read ${skill.path}`
1479
- };
1887
+ const error = `Cannot load skill '${name}': no sandbox provided to read ${skill.path}`;
1888
+ if (debugId)
1889
+ debugError(debugId, "skill", error);
1890
+ return { error };
1480
1891
  }
1481
1892
  const content = await sandbox.readFile(skill.path);
1482
1893
  const frontmatterEnd = content.indexOf(`
@@ -1489,6 +1900,17 @@ function createSkillTool(config) {
1489
1900
  if (onActivate) {
1490
1901
  await onActivate(skill, instructions);
1491
1902
  }
1903
+ const durationMs = Math.round(performance.now() - startTime);
1904
+ if (debugId) {
1905
+ debugEnd(debugId, "skill", {
1906
+ summary: {
1907
+ skillName: skill.name,
1908
+ instructionLength: instructions.length,
1909
+ hasAllowedTools: !!skill.allowedTools
1910
+ },
1911
+ duration_ms: durationMs
1912
+ });
1913
+ }
1492
1914
  return {
1493
1915
  name: skill.name,
1494
1916
  instructions,
@@ -1496,9 +1918,10 @@ function createSkillTool(config) {
1496
1918
  message: skill.allowedTools ? `Skill '${name}' activated. Restricted to tools: ${skill.allowedTools.join(", ")}` : `Skill '${name}' activated. Follow the instructions below.`
1497
1919
  };
1498
1920
  } catch (error) {
1499
- return {
1500
- error: error instanceof Error ? error.message : "Unknown error"
1501
- };
1921
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1922
+ if (debugId)
1923
+ debugError(debugId, "skill", errorMessage);
1924
+ return { error: errorMessage };
1502
1925
  }
1503
1926
  }
1504
1927
  });
@@ -1593,6 +2016,11 @@ function createWebFetchTool(config) {
1593
2016
  providerOptions,
1594
2017
  execute: async (input) => {
1595
2018
  const { url, prompt } = input;
2019
+ const startTime = performance.now();
2020
+ const debugId = isDebugEnabled() ? debugStart("web-fetch", {
2021
+ url,
2022
+ prompt: prompt.length > 200 ? `${prompt.slice(0, 200)}...` : prompt
2023
+ }) : "";
1596
2024
  try {
1597
2025
  const { content, finalUrl } = await fetchContent(url, apiKey, provider);
1598
2026
  const result = await generateText({
@@ -1603,6 +2031,16 @@ Content from ${url}:
1603
2031
 
1604
2032
  ${content}`
1605
2033
  });
2034
+ const durationMs = Math.round(performance.now() - startTime);
2035
+ if (debugId) {
2036
+ debugEnd(debugId, "web-fetch", {
2037
+ summary: {
2038
+ contentLength: content.length,
2039
+ responseLength: result.text.length
2040
+ },
2041
+ duration_ms: durationMs
2042
+ });
2043
+ }
1606
2044
  return {
1607
2045
  response: result.text,
1608
2046
  url,
@@ -1612,15 +2050,18 @@ ${content}`
1612
2050
  if (error && typeof error === "object" && "status" in error) {
1613
2051
  const statusCode = error.status;
1614
2052
  const message = error.message || "API request failed";
2053
+ if (debugId)
2054
+ debugError(debugId, "web-fetch", `${message} (status: ${statusCode})`);
1615
2055
  return {
1616
2056
  error: message,
1617
2057
  status_code: statusCode,
1618
2058
  retryable: RETRYABLE_STATUS_CODES.includes(statusCode)
1619
2059
  };
1620
2060
  }
1621
- return {
1622
- error: error instanceof Error ? error.message : "Unknown error"
1623
- };
2061
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
2062
+ if (debugId)
2063
+ debugError(debugId, "web-fetch", errorMessage);
2064
+ return { error: errorMessage };
1624
2065
  }
1625
2066
  }
1626
2067
  });
@@ -1716,12 +2157,22 @@ function createWebSearchTool(config) {
1716
2157
  providerOptions,
1717
2158
  execute: async (input) => {
1718
2159
  const { query, allowed_domains, blocked_domains } = input;
2160
+ const startTime = performance.now();
2161
+ const debugId = isDebugEnabled() ? debugStart("web-search", { query, allowed_domains, blocked_domains }) : "";
1719
2162
  try {
1720
2163
  const results = await searchContent(apiKey, provider, {
1721
2164
  query,
1722
2165
  allowedDomains: allowed_domains,
1723
2166
  blockedDomains: blocked_domains
1724
2167
  });
2168
+ const durationMs = Math.round(performance.now() - startTime);
2169
+ if (debugId) {
2170
+ debugEnd(debugId, "web-search", {
2171
+ summary: { resultCount: results.length },
2172
+ output: results.slice(0, 5).map((r) => ({ title: r.title, url: r.url })),
2173
+ duration_ms: durationMs
2174
+ });
2175
+ }
1725
2176
  return {
1726
2177
  results,
1727
2178
  total_results: results.length,
@@ -1731,15 +2182,18 @@ function createWebSearchTool(config) {
1731
2182
  if (error && typeof error === "object" && "status" in error) {
1732
2183
  const statusCode = error.status;
1733
2184
  const message = error.message || "API request failed";
2185
+ if (debugId)
2186
+ debugError(debugId, "web-search", `${message} (status: ${statusCode})`);
1734
2187
  return {
1735
2188
  error: message,
1736
2189
  status_code: statusCode,
1737
2190
  retryable: RETRYABLE_STATUS_CODES.includes(statusCode)
1738
2191
  };
1739
2192
  }
1740
- return {
1741
- error: error instanceof Error ? error.message : "Unknown error"
1742
- };
2193
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
2194
+ if (debugId)
2195
+ debugError(debugId, "web-search", errorMessage);
2196
+ return { error: errorMessage };
1743
2197
  }
1744
2198
  }
1745
2199
  });
@@ -1775,29 +2229,43 @@ function createWriteTool(sandbox, config) {
1775
2229
  file_path,
1776
2230
  content
1777
2231
  }) => {
2232
+ const startTime = performance.now();
1778
2233
  const byteLength = Buffer.byteLength(content, "utf-8");
2234
+ const debugId = isDebugEnabled() ? debugStart("write", { file_path, contentLength: byteLength }) : "";
1779
2235
  if (config?.maxFileSize && byteLength > config.maxFileSize) {
1780
- return {
1781
- error: `File content exceeds maximum size of ${config.maxFileSize} bytes (got ${byteLength})`
1782
- };
2236
+ const error = `File content exceeds maximum size of ${config.maxFileSize} bytes (got ${byteLength})`;
2237
+ if (debugId)
2238
+ debugError(debugId, "write", error);
2239
+ return { error };
1783
2240
  }
1784
2241
  if (config?.allowedPaths) {
1785
2242
  const isAllowed = config.allowedPaths.some((allowed) => file_path.startsWith(allowed));
1786
2243
  if (!isAllowed) {
1787
- return { error: `Path not allowed: ${file_path}` };
2244
+ const error = `Path not allowed: ${file_path}`;
2245
+ if (debugId)
2246
+ debugError(debugId, "write", error);
2247
+ return { error };
1788
2248
  }
1789
2249
  }
1790
2250
  try {
1791
2251
  await sandbox.writeFile(file_path, content);
2252
+ const durationMs = Math.round(performance.now() - startTime);
2253
+ if (debugId) {
2254
+ debugEnd(debugId, "write", {
2255
+ summary: { bytes_written: byteLength },
2256
+ duration_ms: durationMs
2257
+ });
2258
+ }
1792
2259
  return {
1793
2260
  message: `Successfully wrote to ${file_path}`,
1794
2261
  bytes_written: byteLength,
1795
2262
  file_path
1796
2263
  };
1797
2264
  } catch (error) {
1798
- return {
1799
- error: error instanceof Error ? error.message : "Unknown error"
1800
- };
2265
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
2266
+ if (debugId)
2267
+ debugError(debugId, "write", errorMessage);
2268
+ return { error: errorMessage };
1801
2269
  }
1802
2270
  }
1803
2271
  });
@@ -1844,16 +2312,22 @@ var eventCounter = 0;
1844
2312
  function generateEventId() {
1845
2313
  return `subagent-${Date.now()}-${++eventCounter}`;
1846
2314
  }
1847
- function filterTools(allTools, allowedTools) {
1848
- if (!allowedTools)
1849
- return allTools;
1850
- const filtered = {};
1851
- for (const name of allowedTools) {
1852
- if (allTools[name]) {
1853
- filtered[name] = allTools[name];
2315
+ function filterTools(allTools, allowedTools, additionalTools) {
2316
+ let result;
2317
+ if (allowedTools) {
2318
+ result = {};
2319
+ for (const name of allowedTools) {
2320
+ if (allTools[name]) {
2321
+ result[name] = allTools[name];
2322
+ }
1854
2323
  }
2324
+ } else {
2325
+ result = allTools;
1855
2326
  }
1856
- return filtered;
2327
+ if (additionalTools) {
2328
+ result = { ...result, ...additionalTools };
2329
+ }
2330
+ return result;
1857
2331
  }
1858
2332
  function createTaskTool(config) {
1859
2333
  const {
@@ -1875,10 +2349,20 @@ function createTaskTool(config) {
1875
2349
  tools: customTools
1876
2350
  }) => {
1877
2351
  const startTime = performance.now();
2352
+ const typeConfig = subagentTypes[subagent_type] || {};
2353
+ const debugId = isDebugEnabled() ? debugStart("task", {
2354
+ subagent_type,
2355
+ description,
2356
+ tools: [
2357
+ ...customTools ?? typeConfig.tools ?? Object.keys(allTools),
2358
+ ...Object.keys(typeConfig.additionalTools ?? {})
2359
+ ]
2360
+ }) : "";
2361
+ if (debugId)
2362
+ pushParent(debugId);
1878
2363
  try {
1879
- const typeConfig = subagentTypes[subagent_type] || {};
1880
2364
  const model = typeConfig.model || defaultModel;
1881
- const tools = filterTools(allTools, customTools ?? typeConfig.tools);
2365
+ const tools = filterTools(allTools, customTools ?? typeConfig.tools, typeConfig.additionalTools);
1882
2366
  const systemPrompt = system_prompt ?? typeConfig.systemPrompt;
1883
2367
  const commonOptions = {
1884
2368
  model,
@@ -1949,6 +2433,19 @@ function createTaskTool(config) {
1949
2433
  }
1950
2434
  });
1951
2435
  const durationMs2 = Math.round(performance.now() - startTime);
2436
+ if (debugId) {
2437
+ popParent();
2438
+ debugEnd(debugId, "task", {
2439
+ summary: {
2440
+ tokens: {
2441
+ input: usage2.inputTokens,
2442
+ output: usage2.outputTokens
2443
+ },
2444
+ steps: response.messages?.length
2445
+ },
2446
+ duration_ms: durationMs2
2447
+ });
2448
+ }
1952
2449
  return {
1953
2450
  result: text,
1954
2451
  usage: usage2.inputTokens !== undefined && usage2.outputTokens !== undefined ? {
@@ -1976,6 +2473,19 @@ function createTaskTool(config) {
1976
2473
  input_tokens: result.usage.inputTokens,
1977
2474
  output_tokens: result.usage.outputTokens
1978
2475
  } : undefined;
2476
+ if (debugId) {
2477
+ popParent();
2478
+ debugEnd(debugId, "task", {
2479
+ summary: {
2480
+ tokens: {
2481
+ input: result.usage.inputTokens,
2482
+ output: result.usage.outputTokens
2483
+ },
2484
+ steps: result.steps?.length
2485
+ },
2486
+ duration_ms: durationMs
2487
+ });
2488
+ }
1979
2489
  return {
1980
2490
  result: result.text,
1981
2491
  usage,
@@ -1985,6 +2495,10 @@ function createTaskTool(config) {
1985
2495
  };
1986
2496
  } catch (error) {
1987
2497
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
2498
+ if (debugId) {
2499
+ popParent();
2500
+ debugError(debugId, "task", errorMessage);
2501
+ }
1988
2502
  return { error: errorMessage };
1989
2503
  }
1990
2504
  }
@@ -2032,15 +2546,22 @@ var TODO_WRITE_DESCRIPTION = `Use this tool to create and manage a structured ta
2032
2546
  - Keep exactly ONE task in_progress at any time
2033
2547
  - ONLY mark completed when FULLY accomplished
2034
2548
  - If blocked/errors, keep in_progress and create new task for the blocker`;
2035
- function createTodoWriteTool(state, onUpdate) {
2549
+ function createTodoWriteTool(state2, onUpdate) {
2036
2550
  return tool14({
2037
2551
  description: TODO_WRITE_DESCRIPTION,
2038
2552
  inputSchema: zodSchema14(todoWriteInputSchema),
2039
2553
  execute: async ({
2040
2554
  todos
2041
2555
  }) => {
2556
+ const startTime = performance.now();
2557
+ const debugId = isDebugEnabled() ? debugStart("todo-write", {
2558
+ todoCount: todos.length,
2559
+ pending: todos.filter((t) => t.status === "pending").length,
2560
+ in_progress: todos.filter((t) => t.status === "in_progress").length,
2561
+ completed: todos.filter((t) => t.status === "completed").length
2562
+ }) : "";
2042
2563
  try {
2043
- state.todos = todos;
2564
+ state2.todos = todos;
2044
2565
  if (onUpdate) {
2045
2566
  onUpdate(todos);
2046
2567
  }
@@ -2050,14 +2571,22 @@ function createTodoWriteTool(state, onUpdate) {
2050
2571
  in_progress: todos.filter((t) => t.status === "in_progress").length,
2051
2572
  completed: todos.filter((t) => t.status === "completed").length
2052
2573
  };
2574
+ const durationMs = Math.round(performance.now() - startTime);
2575
+ if (debugId) {
2576
+ debugEnd(debugId, "todo-write", {
2577
+ summary: stats,
2578
+ duration_ms: durationMs
2579
+ });
2580
+ }
2053
2581
  return {
2054
2582
  message: "Todo list updated successfully",
2055
2583
  stats
2056
2584
  };
2057
2585
  } catch (error) {
2058
- return {
2059
- error: error instanceof Error ? error.message : "Unknown error"
2060
- };
2586
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
2587
+ if (debugId)
2588
+ debugError(debugId, "todo-write", errorMessage);
2589
+ return { error: errorMessage };
2061
2590
  }
2062
2591
  }
2063
2592
  });
@@ -2306,20 +2835,20 @@ function pruneMessagesByTokens(messages, config) {
2306
2835
  }
2307
2836
 
2308
2837
  // src/utils/compact-conversation.ts
2309
- async function compactConversation(messages, config, state = { conversationSummary: "" }) {
2838
+ async function compactConversation(messages, config, state2 = { conversationSummary: "" }) {
2310
2839
  const currentTokens = estimateMessagesTokens(messages);
2311
2840
  const threshold = config.compactionThreshold ?? 0.85;
2312
2841
  const limit = config.maxTokens * threshold;
2313
2842
  if (currentTokens < limit) {
2314
- return { messages, state, didCompact: false };
2843
+ return { messages, state: state2, didCompact: false };
2315
2844
  }
2316
2845
  const protectCount = config.protectRecentMessages ?? 10;
2317
2846
  const recentMessages = messages.slice(-protectCount);
2318
2847
  const oldMessages = messages.slice(0, -protectCount);
2319
2848
  if (oldMessages.length === 0) {
2320
- return { messages, state, didCompact: false };
2849
+ return { messages, state: state2, didCompact: false };
2321
2850
  }
2322
- const newSummary = await summarizeMessages(oldMessages, config.summarizerModel, config.taskContext, state.conversationSummary);
2851
+ const newSummary = await summarizeMessages(oldMessages, config.summarizerModel, config.taskContext, state2.conversationSummary);
2323
2852
  const compactedMessages = [
2324
2853
  {
2325
2854
  role: "user",
@@ -2854,10 +3383,13 @@ async function createDirectory(sandbox, path) {
2854
3383
  export {
2855
3384
  skillsToXml,
2856
3385
  setupAgentEnvironment,
3386
+ reinitDebugMode,
2857
3387
  pruneMessagesByTokens,
2858
3388
  parseSkillMetadata,
2859
3389
  loadSkillBundles,
2860
3390
  loadSkillBundle,
3391
+ isDebugEnabled,
3392
+ getDebugLogs,
2861
3393
  getContextStatus,
2862
3394
  fetchSkills,
2863
3395
  fetchSkill,
@@ -2889,6 +3421,7 @@ export {
2889
3421
  contextNeedsCompaction,
2890
3422
  contextNeedsAttention,
2891
3423
  compactConversation,
3424
+ clearDebugLogs,
2892
3425
  cached,
2893
3426
  anthropicPromptCacheMiddlewareV2,
2894
3427
  anthropicPromptCacheMiddleware,