@probelabs/probe 0.6.0-rc238 → 0.6.0-rc240

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.
Files changed (33) hide show
  1. package/bin/binaries/probe-v0.6.0-rc240-aarch64-apple-darwin.tar.gz +0 -0
  2. package/bin/binaries/probe-v0.6.0-rc240-aarch64-unknown-linux-musl.tar.gz +0 -0
  3. package/bin/binaries/probe-v0.6.0-rc240-x86_64-apple-darwin.tar.gz +0 -0
  4. package/bin/binaries/{probe-v0.6.0-rc238-x86_64-pc-windows-msvc.zip → probe-v0.6.0-rc240-x86_64-pc-windows-msvc.zip} +0 -0
  5. package/bin/binaries/probe-v0.6.0-rc240-x86_64-unknown-linux-musl.tar.gz +0 -0
  6. package/build/agent/ProbeAgent.js +20 -2
  7. package/build/agent/dsl/runtime.js +3 -16
  8. package/build/agent/dsl/validator.js +5 -4
  9. package/build/agent/index.js +127 -24
  10. package/build/agent/probeTool.js +9 -0
  11. package/build/agent/schemaUtils.js +34 -10
  12. package/build/agent/tools.js +9 -0
  13. package/build/index.js +5 -1
  14. package/build/tools/common.js +6 -0
  15. package/build/tools/executePlan.js +100 -2
  16. package/build/tools/index.js +3 -2
  17. package/cjs/agent/ProbeAgent.cjs +127 -24
  18. package/cjs/index.cjs +136 -24
  19. package/package.json +1 -1
  20. package/src/agent/ProbeAgent.js +20 -2
  21. package/src/agent/dsl/runtime.js +3 -16
  22. package/src/agent/dsl/validator.js +5 -4
  23. package/src/agent/probeTool.js +9 -0
  24. package/src/agent/schemaUtils.js +34 -10
  25. package/src/agent/tools.js +9 -0
  26. package/src/index.js +5 -1
  27. package/src/tools/common.js +6 -0
  28. package/src/tools/executePlan.js +100 -2
  29. package/src/tools/index.js +3 -2
  30. package/bin/binaries/probe-v0.6.0-rc238-aarch64-apple-darwin.tar.gz +0 -0
  31. package/bin/binaries/probe-v0.6.0-rc238-aarch64-unknown-linux-musl.tar.gz +0 -0
  32. package/bin/binaries/probe-v0.6.0-rc238-x86_64-apple-darwin.tar.gz +0 -0
  33. package/bin/binaries/probe-v0.6.0-rc238-x86_64-unknown-linux-musl.tar.gz +0 -0
package/cjs/index.cjs CHANGED
@@ -38518,7 +38518,7 @@ function resolveTargetPath(target, cwd) {
38518
38518
  }
38519
38519
  return filePart + suffix;
38520
38520
  }
38521
- var import_path6, searchSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, bashSchema, analyzeAllSchema, executePlanSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, analyzeAllToolDefinition, bashToolDefinition, googleSearchToolDefinition, urlContextToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, bashDescription, analyzeAllDescription, DEFAULT_VALID_TOOLS;
38521
+ var import_path6, searchSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, analyzeAllToolDefinition, bashToolDefinition, googleSearchToolDefinition, urlContextToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, bashDescription, analyzeAllDescription, DEFAULT_VALID_TOOLS;
38522
38522
  var init_common2 = __esm({
38523
38523
  "src/tools/common.js"() {
38524
38524
  "use strict";
@@ -38567,6 +38567,10 @@ var init_common2 = __esm({
38567
38567
  code: external_exports.string().min(1).describe("JavaScript DSL code to execute. All function calls look synchronous \u2014 do NOT use async/await. Use map(items, fn) for batch operations. Use LLM(instruction, data) for AI processing."),
38568
38568
  description: external_exports.string().optional().describe("Human-readable description of what this plan does, for logging.")
38569
38569
  });
38570
+ cleanupExecutePlanSchema = external_exports.object({
38571
+ clearOutputBuffer: external_exports.boolean().optional().default(true).describe("Clear the output buffer from previous execute_plan calls"),
38572
+ clearSessionStore: external_exports.boolean().optional().default(false).describe("Clear the session store (persisted data across execute_plan calls)")
38573
+ });
38570
38574
  attemptCompletionSchema = {
38571
38575
  // Custom validation that requires result parameter but allows direct XML response
38572
38576
  safeParse: (params) => {
@@ -38915,6 +38919,7 @@ Capabilities:
38915
38919
  "delegate",
38916
38920
  "analyze_all",
38917
38921
  "execute_plan",
38922
+ "cleanup_execute_plan",
38918
38923
  "listSkills",
38919
38924
  "useSkill",
38920
38925
  "listFiles",
@@ -39560,6 +39565,9 @@ function createTools(configOptions) {
39560
39565
  }
39561
39566
  if (configOptions.enableExecutePlan && isToolAllowed("execute_plan")) {
39562
39567
  tools2.executePlanTool = createExecutePlanTool(configOptions);
39568
+ if (isToolAllowed("cleanup_execute_plan")) {
39569
+ tools2.cleanupExecutePlanTool = createCleanupExecutePlanTool(configOptions);
39570
+ }
39563
39571
  } else if (isToolAllowed("analyze_all")) {
39564
39572
  tools2.analyzeAllTool = analyzeAllTool(configOptions);
39565
39573
  }
@@ -46478,6 +46486,13 @@ function createWrappedTools(baseTools) {
46478
46486
  baseTools.executePlanTool.execute
46479
46487
  );
46480
46488
  }
46489
+ if (baseTools.cleanupExecutePlanTool) {
46490
+ wrappedTools.cleanupExecutePlanToolInstance = wrapToolWithEmitter(
46491
+ baseTools.cleanupExecutePlanTool,
46492
+ "cleanup_execute_plan",
46493
+ baseTools.cleanupExecutePlanTool.execute
46494
+ );
46495
+ }
46481
46496
  if (baseTools.bashTool) {
46482
46497
  wrappedTools.bashToolInstance = wrapToolWithEmitter(
46483
46498
  baseTools.bashTool,
@@ -83956,15 +83971,31 @@ function isSimpleTextWrapperSchema(schema) {
83956
83971
  return null;
83957
83972
  }
83958
83973
  const trimmed = schema.trim();
83959
- const simplePatterns = [
83960
- /^\{\s*["']?(\w+)["']?\s*:\s*["']?string["']?\s*\}$/i,
83961
- /^\{\s*["']?type["']?\s*:\s*["']?object["']?\s*,\s*["']?properties["']?\s*:\s*\{\s*["']?(\w+)["']?\s*:\s*\{\s*["']?type["']?\s*:\s*["']?string["']?\s*\}\s*\}\s*\}$/i
83962
- ];
83963
- for (const pattern of simplePatterns) {
83964
- const match2 = trimmed.match(pattern);
83965
- if (match2) {
83966
- return { fieldName: match2[1] };
83974
+ try {
83975
+ const parsed = JSON.parse(trimmed);
83976
+ if (typeof parsed !== "object" || parsed === null) {
83977
+ } else {
83978
+ const keys2 = Object.keys(parsed);
83979
+ if (keys2.length === 1 && parsed[keys2[0]] === "string") {
83980
+ return { fieldName: keys2[0] };
83981
+ }
83982
+ if (parsed.type === "object" && parsed.properties) {
83983
+ const propKeys = Object.keys(parsed.properties);
83984
+ if (propKeys.length === 1) {
83985
+ const prop = parsed.properties[propKeys[0]];
83986
+ if (prop && prop.type === "string") {
83987
+ return { fieldName: propKeys[0] };
83988
+ }
83989
+ }
83990
+ }
83991
+ return null;
83967
83992
  }
83993
+ } catch {
83994
+ }
83995
+ const simplePattern = /^\{\s*["']?(\w+)["']?\s*:\s*["']?string["']?\s*\}$/i;
83996
+ const match2 = trimmed.match(simplePattern);
83997
+ if (match2) {
83998
+ return { fieldName: match2[1] };
83968
83999
  }
83969
84000
  return null;
83970
84001
  }
@@ -96826,6 +96857,9 @@ var init_ProbeAgent = __esm({
96826
96857
  }
96827
96858
  if (this.enableExecutePlan && wrappedTools.executePlanToolInstance && isToolAllowed("execute_plan")) {
96828
96859
  this.toolImplementations.execute_plan = wrappedTools.executePlanToolInstance;
96860
+ if (wrappedTools.cleanupExecutePlanToolInstance && isToolAllowed("cleanup_execute_plan")) {
96861
+ this.toolImplementations.cleanup_execute_plan = wrappedTools.cleanupExecutePlanToolInstance;
96862
+ }
96829
96863
  } else if (wrappedTools.analyzeAllToolInstance && isToolAllowed("analyze_all")) {
96830
96864
  this.toolImplementations.analyze_all = wrappedTools.analyzeAllToolInstance;
96831
96865
  }
@@ -98199,6 +98233,10 @@ Workspace: ${this.allowedFolders.join(", ")}`;
98199
98233
  if (this.enableBash && isToolAllowed("bash")) dslFunctions.push("bash");
98200
98234
  toolDefinitions += `${getExecutePlanToolDefinition(dslFunctions)}
98201
98235
  `;
98236
+ if (isToolAllowed("cleanup_execute_plan")) {
98237
+ toolDefinitions += `${getCleanupExecutePlanToolDefinition()}
98238
+ `;
98239
+ }
98202
98240
  } else if (isToolAllowed("analyze_all")) {
98203
98241
  toolDefinitions += `${analyzeAllToolDefinition}
98204
98242
  `;
@@ -98274,6 +98312,9 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
98274
98312
  }
98275
98313
  if (this.enableExecutePlan && isToolAllowed("execute_plan")) {
98276
98314
  availableToolsList += '- execute_plan: Execute a DSL program to orchestrate tool calls. ALWAYS use this for: questions containing "all"/"every"/"comprehensive"/"complete inventory", multi-topic analysis, open-ended discovery questions, or any task requiring full codebase coverage.\n';
98315
+ if (isToolAllowed("cleanup_execute_plan")) {
98316
+ availableToolsList += "- cleanup_execute_plan: Clean up output buffer and session store from previous execute_plan calls.\n";
98317
+ }
98277
98318
  } else if (isToolAllowed("analyze_all")) {
98278
98319
  availableToolsList += "- analyze_all: Process ALL data matching a query using map-reduce (for aggregate questions needing 100% coverage).\n";
98279
98320
  }
@@ -98500,7 +98541,7 @@ You are working with a workspace. Available paths: ${workspaceDesc}
98500
98541
  }
98501
98542
  try {
98502
98543
  const oldHistoryLength = this.history.length;
98503
- if (this._outputBuffer) {
98544
+ if (this._outputBuffer && !options?._schemaFormatted) {
98504
98545
  this._outputBuffer.items = [];
98505
98546
  }
98506
98547
  if (this.enableTasks) {
@@ -98860,6 +98901,9 @@ You are working with a workspace. Available paths: ${workspaceDesc}
98860
98901
  }
98861
98902
  if (this.enableExecutePlan && this.allowedTools.isEnabled("execute_plan")) {
98862
98903
  validTools.push("execute_plan");
98904
+ if (this.allowedTools.isEnabled("cleanup_execute_plan")) {
98905
+ validTools.push("cleanup_execute_plan");
98906
+ }
98863
98907
  } else if (this.allowedTools.isEnabled("analyze_all")) {
98864
98908
  validTools.push("analyze_all");
98865
98909
  }
@@ -112363,9 +112407,6 @@ function validateDSL(code) {
112363
112407
  if (node.type === "FunctionExpression" && node.generator) {
112364
112408
  errors.push(`Generator functions are not allowed at position ${node.start}`);
112365
112409
  }
112366
- if (node.type === "Literal" && node.regex) {
112367
- errors.push(`Regex literals are not supported at position ${node.start}. Use String methods like indexOf(), includes(), startsWith() instead.`);
112368
- }
112369
112410
  if (node.type === "Identifier" && BLOCKED_IDENTIFIERS.has(node.name)) {
112370
112411
  errors.push(`Blocked identifier: '${node.name}' at position ${node.start}`);
112371
112412
  }
@@ -112404,18 +112445,23 @@ var init_validator = __esm({
112404
112445
  "BlockStatement",
112405
112446
  "VariableDeclaration",
112406
112447
  "VariableDeclarator",
112448
+ "FunctionDeclaration",
112407
112449
  "ArrowFunctionExpression",
112408
112450
  "FunctionExpression",
112409
112451
  "CallExpression",
112452
+ "NewExpression",
112410
112453
  "MemberExpression",
112411
112454
  "Identifier",
112412
112455
  "Literal",
112413
112456
  "TemplateLiteral",
112414
112457
  "TemplateElement",
112458
+ "TaggedTemplateExpression",
112415
112459
  "ArrayExpression",
112416
112460
  "ObjectExpression",
112417
112461
  "SpreadElement",
112418
112462
  "IfStatement",
112463
+ "SwitchStatement",
112464
+ "SwitchCase",
112419
112465
  "ConditionalExpression",
112420
112466
  "ForOfStatement",
112421
112467
  "ForInStatement",
@@ -112877,7 +112923,6 @@ function createDSLRuntime(options) {
112877
112923
  mcpTools = {},
112878
112924
  llmCall,
112879
112925
  mapConcurrency = 3,
112880
- timeoutMs = 12e4,
112881
112926
  maxLoopIterations = 5e3,
112882
112927
  tracer = null,
112883
112928
  sessionStore = {},
@@ -112932,7 +112977,6 @@ ${validation.errors.join("\n")}`,
112932
112977
  };
112933
112978
  }
112934
112979
  tracer?.addEvent?.("dsl.phase.execute_start", {
112935
- "dsl.timeout_ms": timeoutMs,
112936
112980
  "dsl.max_loop_iterations": maxLoopIterations
112937
112981
  });
112938
112982
  try {
@@ -112960,18 +113004,10 @@ ${validation.errors.join("\n")}`,
112960
113004
  escapedError = reason;
112961
113005
  };
112962
113006
  process.on("unhandledRejection", rejectionHandler);
112963
- let timeoutHandle;
112964
- const executionPromise = exec6().run();
112965
- const timeoutPromise = new Promise((_, reject2) => {
112966
- timeoutHandle = setTimeout(() => {
112967
- reject2(new Error(`Execution timed out after ${Math.round(timeoutMs / 1e3)}s. Script took too long \u2014 reduce the amount of work (fewer items, smaller data) or increase timeout.`));
112968
- }, timeoutMs);
112969
- });
112970
113007
  let result;
112971
113008
  try {
112972
- result = await Promise.race([executionPromise, timeoutPromise]);
113009
+ result = await exec6().run();
112973
113010
  } finally {
112974
- clearTimeout(timeoutHandle);
112975
113011
  setTimeout(() => {
112976
113012
  process.removeListener("unhandledRejection", rejectionHandler);
112977
113013
  }, 500);
@@ -113274,6 +113310,14 @@ Logs: ${result.logs.join(" | ")}` : "";
113274
113310
  "dsl.error": lastError.substring(0, 1e3)
113275
113311
  });
113276
113312
  }
113313
+ if (outputBuffer && outputBuffer.items && outputBuffer.items.length > 0) {
113314
+ const clearedChars = outputBuffer.items.reduce((sum, item) => sum + item.length, 0);
113315
+ outputBuffer.items = [];
113316
+ planSpan?.addEvent?.("dsl.auto_cleanup", {
113317
+ "cleanup.chars_cleared": clearedChars,
113318
+ "cleanup.reason": "all_retries_exhausted"
113319
+ });
113320
+ }
113277
113321
  finalOutput = `Plan execution failed after ${maxRetries} retries.
113278
113322
 
113279
113323
  Last error: ${lastError}`;
@@ -113286,6 +113330,9 @@ Last error: ${lastError}`;
113286
113330
  planSpan?.end?.();
113287
113331
  return finalOutput;
113288
113332
  } catch (e5) {
113333
+ if (outputBuffer && outputBuffer.items && outputBuffer.items.length > 0) {
113334
+ outputBuffer.items = [];
113335
+ }
113289
113336
  planSpan?.setStatus?.("ERROR");
113290
113337
  planSpan?.addEvent?.("exception", {
113291
113338
  "exception.message": e5.message,
@@ -113729,6 +113776,62 @@ output(table);
113729
113776
  return "Generated table with " + results.length + " items.";
113730
113777
  \`\`\``;
113731
113778
  }
113779
+ function createCleanupExecutePlanTool(options) {
113780
+ const { outputBuffer, sessionStore, tracer } = options;
113781
+ return (0, import_ai6.tool)({
113782
+ description: "Clean up output buffer and session store from previous execute_plan calls. Use this when a previous execute_plan failed and left stale data, or before starting a fresh analysis.",
113783
+ parameters: cleanupExecutePlanSchema,
113784
+ execute: async ({ clearOutputBuffer = true, clearSessionStore = false }) => {
113785
+ const span = tracer?.createToolSpan?.("cleanup_execute_plan", {
113786
+ "cleanup.clear_output_buffer": clearOutputBuffer,
113787
+ "cleanup.clear_session_store": clearSessionStore
113788
+ }) || null;
113789
+ const results = [];
113790
+ try {
113791
+ if (clearOutputBuffer && outputBuffer) {
113792
+ const itemCount = outputBuffer.items?.length || 0;
113793
+ const charCount = outputBuffer.items?.reduce((sum, item) => sum + item.length, 0) || 0;
113794
+ outputBuffer.items = [];
113795
+ results.push(`Output buffer cleared (${itemCount} items, ${charCount} chars)`);
113796
+ }
113797
+ if (clearSessionStore && sessionStore) {
113798
+ const keyCount = Object.keys(sessionStore).length;
113799
+ for (const key of Object.keys(sessionStore)) {
113800
+ delete sessionStore[key];
113801
+ }
113802
+ results.push(`Session store cleared (${keyCount} keys)`);
113803
+ }
113804
+ const output = results.length > 0 ? `Cleanup complete:
113805
+ - ${results.join("\n- ")}` : "Nothing to clean up";
113806
+ span?.setAttributes?.({
113807
+ "cleanup.result": output,
113808
+ "cleanup.success": true
113809
+ });
113810
+ span?.setStatus?.("OK");
113811
+ span?.end?.();
113812
+ return output;
113813
+ } catch (e5) {
113814
+ span?.setStatus?.("ERROR");
113815
+ span?.addEvent?.("exception", { "exception.message": e5.message });
113816
+ span?.end?.();
113817
+ return `Cleanup failed: ${e5.message}`;
113818
+ }
113819
+ }
113820
+ });
113821
+ }
113822
+ function getCleanupExecutePlanToolDefinition() {
113823
+ return `## cleanup_execute_plan
113824
+ Description: Clean up output buffer and session store from previous execute_plan calls. Use when a previous execute_plan failed and left stale data, or before starting a fresh analysis.
113825
+
113826
+ Parameters:
113827
+ - clearOutputBuffer: (optional, default: true) Clear the output buffer from previous execute_plan calls
113828
+ - clearSessionStore: (optional, default: false) Clear the session store (persisted data across execute_plan calls)
113829
+
113830
+ Example:
113831
+ <cleanup_execute_plan>
113832
+ <clearOutputBuffer>true</clearOutputBuffer>
113833
+ </cleanup_execute_plan>`;
113834
+ }
113732
113835
  var import_ai6;
113733
113836
  var init_executePlan = __esm({
113734
113837
  "src/tools/executePlan.js"() {
@@ -113887,6 +113990,8 @@ __export(tools_exports, {
113887
113990
  bashTool: () => bashTool,
113888
113991
  bashToolDefinition: () => bashToolDefinition,
113889
113992
  buildToolTagPattern: () => buildToolTagPattern,
113993
+ cleanupExecutePlanSchema: () => cleanupExecutePlanSchema,
113994
+ createCleanupExecutePlanTool: () => createCleanupExecutePlanTool,
113890
113995
  createDescription: () => createDescription,
113891
113996
  createExecutePlanTool: () => createExecutePlanTool,
113892
113997
  createExtractTool: () => createExtractTool,
@@ -113906,6 +114011,7 @@ __export(tools_exports, {
113906
114011
  executePlanSchema: () => executePlanSchema,
113907
114012
  extractSchema: () => extractSchema,
113908
114013
  extractTool: () => extractTool,
114014
+ getCleanupExecutePlanToolDefinition: () => getCleanupExecutePlanToolDefinition,
113909
114015
  getExecutePlanToolDefinition: () => getExecutePlanToolDefinition,
113910
114016
  parseAndResolvePaths: () => parseAndResolvePaths,
113911
114017
  querySchema: () => querySchema,
@@ -114530,6 +114636,8 @@ __export(index_exports, {
114530
114636
  bashSchema: () => bashSchema,
114531
114637
  bashTool: () => bashTool,
114532
114638
  bashToolDefinition: () => bashToolDefinition,
114639
+ cleanupExecutePlanSchema: () => cleanupExecutePlanSchema,
114640
+ createCleanupExecutePlanTool: () => createCleanupExecutePlanTool,
114533
114641
  createExecutePlanTool: () => createExecutePlanTool,
114534
114642
  createSchema: () => createSchema,
114535
114643
  createTaskTool: () => createTaskTool,
@@ -114548,6 +114656,7 @@ __export(index_exports, {
114548
114656
  extractTool: () => extractTool,
114549
114657
  extractToolDefinition: () => extractToolDefinition,
114550
114658
  getBinaryPath: () => getBinaryPath,
114659
+ getCleanupExecutePlanToolDefinition: () => getCleanupExecutePlanToolDefinition,
114551
114660
  getExecutePlanToolDefinition: () => getExecutePlanToolDefinition,
114552
114661
  googleSearchToolDefinition: () => googleSearchToolDefinition,
114553
114662
  grep: () => grep,
@@ -114620,6 +114729,8 @@ init_index();
114620
114729
  bashSchema,
114621
114730
  bashTool,
114622
114731
  bashToolDefinition,
114732
+ cleanupExecutePlanSchema,
114733
+ createCleanupExecutePlanTool,
114623
114734
  createExecutePlanTool,
114624
114735
  createSchema,
114625
114736
  createTaskTool,
@@ -114638,6 +114749,7 @@ init_index();
114638
114749
  extractTool,
114639
114750
  extractToolDefinition,
114640
114751
  getBinaryPath,
114752
+ getCleanupExecutePlanToolDefinition,
114641
114753
  getExecutePlanToolDefinition,
114642
114754
  googleSearchToolDefinition,
114643
114755
  grep,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@probelabs/probe",
3
- "version": "0.6.0-rc238",
3
+ "version": "0.6.0-rc240",
4
4
  "description": "Node.js wrapper for the probe code search tool",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -49,6 +49,7 @@ import {
49
49
  delegateToolDefinition,
50
50
  analyzeAllToolDefinition,
51
51
  getExecutePlanToolDefinition,
52
+ getCleanupExecutePlanToolDefinition,
52
53
  bashToolDefinition,
53
54
  listFilesToolDefinition,
54
55
  searchFilesToolDefinition,
@@ -870,6 +871,10 @@ export class ProbeAgent {
870
871
  }
871
872
  if (this.enableExecutePlan && wrappedTools.executePlanToolInstance && isToolAllowed('execute_plan')) {
872
873
  this.toolImplementations.execute_plan = wrappedTools.executePlanToolInstance;
874
+ // cleanup_execute_plan is enabled together with execute_plan
875
+ if (wrappedTools.cleanupExecutePlanToolInstance && isToolAllowed('cleanup_execute_plan')) {
876
+ this.toolImplementations.cleanup_execute_plan = wrappedTools.cleanupExecutePlanToolInstance;
877
+ }
873
878
  } else if (wrappedTools.analyzeAllToolInstance && isToolAllowed('analyze_all')) {
874
879
  // analyze_all is fallback when execute_plan is not enabled
875
880
  this.toolImplementations.analyze_all = wrappedTools.analyzeAllToolInstance;
@@ -2582,6 +2587,10 @@ ${extractGuidance}
2582
2587
  if (isToolAllowed('listFiles')) dslFunctions.push('listFiles');
2583
2588
  if (this.enableBash && isToolAllowed('bash')) dslFunctions.push('bash');
2584
2589
  toolDefinitions += `${getExecutePlanToolDefinition(dslFunctions)}\n`;
2590
+ // cleanup_execute_plan is enabled together with execute_plan
2591
+ if (isToolAllowed('cleanup_execute_plan')) {
2592
+ toolDefinitions += `${getCleanupExecutePlanToolDefinition()}\n`;
2593
+ }
2585
2594
  } else if (isToolAllowed('analyze_all')) {
2586
2595
  // Fallback: only register analyze_all if execute_plan is not available
2587
2596
  toolDefinitions += `${analyzeAllToolDefinition}\n`;
@@ -2661,6 +2670,9 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
2661
2670
  }
2662
2671
  if (this.enableExecutePlan && isToolAllowed('execute_plan')) {
2663
2672
  availableToolsList += '- execute_plan: Execute a DSL program to orchestrate tool calls. ALWAYS use this for: questions containing "all"/"every"/"comprehensive"/"complete inventory", multi-topic analysis, open-ended discovery questions, or any task requiring full codebase coverage.\n';
2673
+ if (isToolAllowed('cleanup_execute_plan')) {
2674
+ availableToolsList += '- cleanup_execute_plan: Clean up output buffer and session store from previous execute_plan calls.\n';
2675
+ }
2664
2676
  } else if (isToolAllowed('analyze_all')) {
2665
2677
  availableToolsList += '- analyze_all: Process ALL data matching a query using map-reduce (for aggregate questions needing 100% coverage).\n';
2666
2678
  }
@@ -2891,8 +2903,10 @@ Follow these instructions carefully:
2891
2903
  // Track initial history length for storage
2892
2904
  const oldHistoryLength = this.history.length;
2893
2905
 
2894
- // Reset output buffer for this answer() call
2895
- if (this._outputBuffer) {
2906
+ // Reset output buffer for this answer() call — but NOT during schema correction recursion
2907
+ // When _schemaFormatted is true, this is a recursive call to fix JSON formatting,
2908
+ // and we must preserve the output buffer so the parent call can append it
2909
+ if (this._outputBuffer && !options?._schemaFormatted) {
2896
2910
  this._outputBuffer.items = [];
2897
2911
  }
2898
2912
 
@@ -3411,6 +3425,10 @@ Follow these instructions carefully:
3411
3425
  // Execute Plan tool (requires enableExecutePlan flag, supersedes analyze_all)
3412
3426
  if (this.enableExecutePlan && this.allowedTools.isEnabled('execute_plan')) {
3413
3427
  validTools.push('execute_plan');
3428
+ // cleanup_execute_plan is enabled together with execute_plan
3429
+ if (this.allowedTools.isEnabled('cleanup_execute_plan')) {
3430
+ validTools.push('cleanup_execute_plan');
3431
+ }
3414
3432
  } else if (this.allowedTools.isEnabled('analyze_all')) {
3415
3433
  validTools.push('analyze_all');
3416
3434
  }
@@ -4,7 +4,7 @@
4
4
  * Orchestrates the full pipeline:
5
5
  * 1. Validate (AST whitelist)
6
6
  * 2. Transform (inject await, wrap in async IIFE)
7
- * 3. Execute in SandboxJS with tool globals + timeout
7
+ * 3. Execute in SandboxJS with tool globals
8
8
  *
9
9
  * Returns the result or a structured error.
10
10
  */
@@ -25,7 +25,6 @@ const Sandbox = SandboxModule.default || SandboxModule;
25
25
  * @param {Object} [options.mcpTools={}] - MCP tool metadata
26
26
  * @param {Function} options.llmCall - Function for LLM() calls: (instruction, data, options?) => Promise<any>
27
27
  * @param {number} [options.mapConcurrency=3] - Concurrency limit for map()
28
- * @param {number} [options.timeoutMs=120000] - Execution timeout in milliseconds (default 2 min)
29
28
  * @param {number} [options.maxLoopIterations=5000] - Max iterations for while/for loops
30
29
  * @param {Object} [options.tracer=null] - SimpleAppTracer instance for OTEL telemetry
31
30
  * @returns {Object} Runtime with execute() method
@@ -37,7 +36,6 @@ export function createDSLRuntime(options) {
37
36
  mcpTools = {},
38
37
  llmCall,
39
38
  mapConcurrency = 3,
40
- timeoutMs = 120000,
41
39
  maxLoopIterations = 5000,
42
40
  tracer = null,
43
41
  sessionStore = {},
@@ -108,9 +106,8 @@ export function createDSLRuntime(options) {
108
106
  };
109
107
  }
110
108
 
111
- // Step 3: Execute in SandboxJS with timeout
109
+ // Step 3: Execute in SandboxJS
112
110
  tracer?.addEvent?.('dsl.phase.execute_start', {
113
- 'dsl.timeout_ms': timeoutMs,
114
111
  'dsl.max_loop_iterations': maxLoopIterations,
115
112
  });
116
113
 
@@ -147,20 +144,10 @@ export function createDSLRuntime(options) {
147
144
  };
148
145
  process.on('unhandledRejection', rejectionHandler);
149
146
 
150
- // Race execution against timeout
151
- let timeoutHandle;
152
- const executionPromise = exec().run();
153
- const timeoutPromise = new Promise((_, reject) => {
154
- timeoutHandle = setTimeout(() => {
155
- reject(new Error(`Execution timed out after ${Math.round(timeoutMs / 1000)}s. Script took too long — reduce the amount of work (fewer items, smaller data) or increase timeout.`));
156
- }, timeoutMs);
157
- });
158
-
159
147
  let result;
160
148
  try {
161
- result = await Promise.race([executionPromise, timeoutPromise]);
149
+ result = await exec().run();
162
150
  } finally {
163
- clearTimeout(timeoutHandle);
164
151
  // Delay handler removal — SandboxJS can throw async errors after execution completes
165
152
  setTimeout(() => {
166
153
  process.removeListener('unhandledRejection', rejectionHandler);
@@ -16,18 +16,23 @@ const ALLOWED_NODE_TYPES = new Set([
16
16
  'BlockStatement',
17
17
  'VariableDeclaration',
18
18
  'VariableDeclarator',
19
+ 'FunctionDeclaration',
19
20
  'ArrowFunctionExpression',
20
21
  'FunctionExpression',
21
22
  'CallExpression',
23
+ 'NewExpression',
22
24
  'MemberExpression',
23
25
  'Identifier',
24
26
  'Literal',
25
27
  'TemplateLiteral',
26
28
  'TemplateElement',
29
+ 'TaggedTemplateExpression',
27
30
  'ArrayExpression',
28
31
  'ObjectExpression',
29
32
  'SpreadElement',
30
33
  'IfStatement',
34
+ 'SwitchStatement',
35
+ 'SwitchCase',
31
36
  'ConditionalExpression',
32
37
  'ForOfStatement',
33
38
  'ForInStatement',
@@ -127,10 +132,6 @@ export function validateDSL(code) {
127
132
  errors.push(`Generator functions are not allowed at position ${node.start}`);
128
133
  }
129
134
 
130
- // Block regex literals — SandboxJS doesn't support them
131
- if (node.type === 'Literal' && node.regex) {
132
- errors.push(`Regex literals are not supported at position ${node.start}. Use String methods like indexOf(), includes(), startsWith() instead.`);
133
- }
134
135
 
135
136
  // Check identifiers against blocklist
136
137
  if (node.type === 'Identifier' && BLOCKED_IDENTIFIERS.has(node.name)) {
@@ -220,6 +220,15 @@ export function createWrappedTools(baseTools) {
220
220
  );
221
221
  }
222
222
 
223
+ // Wrap cleanup_execute_plan tool
224
+ if (baseTools.cleanupExecutePlanTool) {
225
+ wrappedTools.cleanupExecutePlanToolInstance = wrapToolWithEmitter(
226
+ baseTools.cleanupExecutePlanTool,
227
+ 'cleanup_execute_plan',
228
+ baseTools.cleanupExecutePlanTool.execute
229
+ );
230
+ }
231
+
223
232
  // Wrap bash tool
224
233
  if (baseTools.bashTool) {
225
234
  wrappedTools.bashToolInstance = wrapToolWithEmitter(
@@ -784,18 +784,42 @@ export function isSimpleTextWrapperSchema(schema) {
784
784
 
785
785
  const trimmed = schema.trim();
786
786
 
787
- // Match patterns like: {text: string}, {"text": "string"}, {response: string}, etc.
788
- // These are simple wrappers that just need a single text field
789
- const simplePatterns = [
790
- /^\{\s*["']?(\w+)["']?\s*:\s*["']?string["']?\s*\}$/i,
791
- /^\{\s*["']?type["']?\s*:\s*["']?object["']?\s*,\s*["']?properties["']?\s*:\s*\{\s*["']?(\w+)["']?\s*:\s*\{\s*["']?type["']?\s*:\s*["']?string["']?\s*\}\s*\}\s*\}$/i
792
- ];
787
+ // First, try parsing as JSON for full JSON Schema format
788
+ try {
789
+ const parsed = JSON.parse(trimmed);
790
+ if (typeof parsed !== 'object' || parsed === null) {
791
+ // Fall through to regex matching
792
+ } else {
793
+ // Shorthand JSON format: {"text": "string"} or {"fieldName": "string"}
794
+ const keys = Object.keys(parsed);
795
+ if (keys.length === 1 && parsed[keys[0]] === 'string') {
796
+ return { fieldName: keys[0] };
797
+ }
793
798
 
794
- for (const pattern of simplePatterns) {
795
- const match = trimmed.match(pattern);
796
- if (match) {
797
- return { fieldName: match[1] };
799
+ // Full JSON Schema format: {"type":"object","properties":{"text":{"type":"string",...}}}
800
+ // Handles schemas with "required", "description", and other extra fields
801
+ if (parsed.type === 'object' && parsed.properties) {
802
+ const propKeys = Object.keys(parsed.properties);
803
+ if (propKeys.length === 1) {
804
+ const prop = parsed.properties[propKeys[0]];
805
+ if (prop && prop.type === 'string') {
806
+ return { fieldName: propKeys[0] };
807
+ }
808
+ }
809
+ }
810
+
811
+ // Valid JSON but not a simple wrapper
812
+ return null;
798
813
  }
814
+ } catch {
815
+ // Not valid JSON, fall through to regex matching
816
+ }
817
+
818
+ // Fallback: regex matching for shorthand formats like {text: string}, {'text': 'string'}
819
+ const simplePattern = /^\{\s*["']?(\w+)["']?\s*:\s*["']?string["']?\s*\}$/i;
820
+ const match = trimmed.match(simplePattern);
821
+ if (match) {
822
+ return { fieldName: match[1] };
799
823
  }
800
824
 
801
825
  return null;
@@ -6,6 +6,7 @@ import {
6
6
  delegateTool,
7
7
  analyzeAllTool,
8
8
  createExecutePlanTool,
9
+ createCleanupExecutePlanTool,
9
10
  bashTool,
10
11
  editTool,
11
12
  createTool,
@@ -18,6 +19,7 @@ import {
18
19
  delegateSchema,
19
20
  analyzeAllSchema,
20
21
  executePlanSchema,
22
+ cleanupExecutePlanSchema,
21
23
  bashSchema,
22
24
  editSchema,
23
25
  createSchema,
@@ -27,6 +29,7 @@ import {
27
29
  delegateToolDefinition,
28
30
  analyzeAllToolDefinition,
29
31
  getExecutePlanToolDefinition,
32
+ getCleanupExecutePlanToolDefinition,
30
33
  bashToolDefinition,
31
34
  editToolDefinition,
32
35
  createToolDefinition,
@@ -63,6 +66,10 @@ export function createTools(configOptions) {
63
66
  }
64
67
  if (configOptions.enableExecutePlan && isToolAllowed('execute_plan')) {
65
68
  tools.executePlanTool = createExecutePlanTool(configOptions);
69
+ // cleanup_execute_plan is enabled together with execute_plan
70
+ if (isToolAllowed('cleanup_execute_plan')) {
71
+ tools.cleanupExecutePlanTool = createCleanupExecutePlanTool(configOptions);
72
+ }
66
73
  } else if (isToolAllowed('analyze_all')) {
67
74
  // analyze_all is fallback when execute_plan is not enabled
68
75
  tools.analyzeAllTool = analyzeAllTool(configOptions);
@@ -104,6 +111,7 @@ export {
104
111
  delegateSchema,
105
112
  analyzeAllSchema,
106
113
  executePlanSchema,
114
+ cleanupExecutePlanSchema,
107
115
  bashSchema,
108
116
  editSchema,
109
117
  createSchema,
@@ -114,6 +122,7 @@ export {
114
122
  delegateToolDefinition,
115
123
  analyzeAllToolDefinition,
116
124
  getExecutePlanToolDefinition,
125
+ getCleanupExecutePlanToolDefinition,
117
126
  bashToolDefinition,
118
127
  editToolDefinition,
119
128
  createToolDefinition,
package/src/index.js CHANGED
@@ -27,6 +27,7 @@ import {
27
27
  delegateSchema,
28
28
  analyzeAllSchema,
29
29
  executePlanSchema,
30
+ cleanupExecutePlanSchema,
30
31
  attemptCompletionSchema,
31
32
  bashSchema,
32
33
  searchToolDefinition,
@@ -47,7 +48,7 @@ import {
47
48
  createToolDefinition
48
49
  } from './tools/edit.js';
49
50
  import { searchTool, queryTool, extractTool, delegateTool, analyzeAllTool } from './tools/vercel.js';
50
- import { createExecutePlanTool, getExecutePlanToolDefinition } from './tools/executePlan.js';
51
+ import { createExecutePlanTool, getExecutePlanToolDefinition, createCleanupExecutePlanTool, getCleanupExecutePlanToolDefinition } from './tools/executePlan.js';
51
52
  import { bashTool } from './tools/bash.js';
52
53
  import { editTool, createTool } from './tools/edit.js';
53
54
  import { ProbeAgent } from './agent/ProbeAgent.js';
@@ -93,6 +94,7 @@ export {
93
94
  delegateTool,
94
95
  analyzeAllTool,
95
96
  createExecutePlanTool,
97
+ createCleanupExecutePlanTool,
96
98
  bashTool,
97
99
  editTool,
98
100
  createTool,
@@ -106,6 +108,7 @@ export {
106
108
  delegateSchema,
107
109
  analyzeAllSchema,
108
110
  executePlanSchema,
111
+ cleanupExecutePlanSchema,
109
112
  attemptCompletionSchema,
110
113
  bashSchema,
111
114
  editSchema,
@@ -117,6 +120,7 @@ export {
117
120
  delegateToolDefinition,
118
121
  analyzeAllToolDefinition,
119
122
  getExecutePlanToolDefinition,
123
+ getCleanupExecutePlanToolDefinition,
120
124
  attemptCompletionToolDefinition,
121
125
  bashToolDefinition,
122
126
  editToolDefinition,