@probelabs/visor 0.1.49 → 0.1.50

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
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- process.env.VISOR_VERSION = '0.1.49';
2
+ process.env.VISOR_VERSION = '0.1.50';
3
3
  /******/ (() => { // webpackBootstrap
4
4
  /******/ var __webpack_modules__ = ({
5
5
 
@@ -94138,11 +94138,12 @@ ${prContext}
94138
94138
  */
94139
94139
  formatPRContext(prInfo) {
94140
94140
  // Check if this is an issue (not a PR)
94141
- const isIssue = prInfo.isIssue === true;
94141
+ const prContextInfo = prInfo;
94142
+ const isIssue = prContextInfo.isIssue === true;
94142
94143
  // Check if we should include code context (diffs)
94143
- const isPRContext = prInfo.isPRContext === true;
94144
+ const isPRContext = prContextInfo.isPRContext === true;
94144
94145
  // In PR context, always include diffs. Otherwise check the flag.
94145
- const includeCodeContext = isPRContext || prInfo.includeCodeContext !== false;
94146
+ const includeCodeContext = isPRContext || prContextInfo.includeCodeContext !== false;
94146
94147
  // Log the decision for transparency
94147
94148
  const log = this.config.debug ? console.error : () => { };
94148
94149
  if (isPRContext) {
@@ -94486,12 +94487,16 @@ ${prInfo.fullDiff ? this.escapeXml(prInfo.fullDiff) : ''}
94486
94487
  if (this.config.provider) {
94487
94488
  // Map claude-code to anthropic for ProbeAgent compatibility
94488
94489
  // Map bedrock to anthropic temporarily until ProbeAgent adds bedrock type
94489
- options.provider =
94490
- this.config.provider === 'claude-code'
94491
- ? 'anthropic'
94492
- : this.config.provider === 'bedrock'
94493
- ? 'anthropic'
94494
- : this.config.provider;
94490
+ const providerOverride = this.config.provider === 'claude-code' || this.config.provider === 'bedrock'
94491
+ ? 'anthropic'
94492
+ : this.config.provider === 'anthropic' ||
94493
+ this.config.provider === 'openai' ||
94494
+ this.config.provider === 'google'
94495
+ ? this.config.provider
94496
+ : undefined;
94497
+ if (providerOverride) {
94498
+ options.provider = providerOverride;
94499
+ }
94495
94500
  }
94496
94501
  if (this.config.model) {
94497
94502
  options.model = this.config.model;
@@ -95230,7 +95235,6 @@ class CheckExecutionEngine {
95230
95235
  const result = await tasks[taskIndex]();
95231
95236
  results[taskIndex] = { status: 'fulfilled', value: result };
95232
95237
  // Check if we should stop due to fail-fast
95233
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
95234
95238
  if (failFast && this.shouldFailFast(result)) {
95235
95239
  shouldStop = true;
95236
95240
  break;
@@ -95263,7 +95267,11 @@ class CheckExecutionEngine {
95263
95267
  // Store config for use in filtering
95264
95268
  this.config = config;
95265
95269
  // Determine where to send log messages based on output format
95266
- const logFn = outputFormat === 'json' || outputFormat === 'sarif' ? console.error : console.log;
95270
+ const logFn = outputFormat === 'json' || outputFormat === 'sarif'
95271
+ ? debug
95272
+ ? console.error
95273
+ : () => { }
95274
+ : console.log;
95267
95275
  // Only output debug messages if debug mode is enabled
95268
95276
  if (debug) {
95269
95277
  logFn(`🔧 Debug: executeReviewChecks called with checks: ${JSON.stringify(checks)}`);
@@ -95385,7 +95393,11 @@ class CheckExecutionEngine {
95385
95393
  */
95386
95394
  async executeGroupedChecks(prInfo, checks, timeout, config, outputFormat, debug, maxParallelism, failFast, tagFilter) {
95387
95395
  // Determine where to send log messages based on output format
95388
- const logFn = outputFormat === 'json' || outputFormat === 'sarif' ? console.error : console.log;
95396
+ const logFn = outputFormat === 'json' || outputFormat === 'sarif'
95397
+ ? debug
95398
+ ? console.error
95399
+ : () => { }
95400
+ : console.log;
95389
95401
  // Only output debug messages if debug mode is enabled
95390
95402
  if (debug) {
95391
95403
  logFn(`🔧 Debug: executeGroupedChecks called with checks: ${JSON.stringify(checks)}`);
@@ -95465,6 +95477,7 @@ class CheckExecutionEngine {
95465
95477
  // Pass any provider-specific config
95466
95478
  ...checkConfig,
95467
95479
  };
95480
+ providerConfig.forEach = checkConfig.forEach;
95468
95481
  const result = await provider.execute(prInfo, providerConfig);
95469
95482
  // Render the check content using the appropriate template
95470
95483
  const content = await this.renderCheckContent(checkName, result, checkConfig, prInfo);
@@ -95490,6 +95503,7 @@ class CheckExecutionEngine {
95490
95503
  */
95491
95504
  async convertReviewSummaryToGroupedResults(reviewSummary, checks, config, prInfo) {
95492
95505
  const groupedResults = {};
95506
+ const contentMap = reviewSummary.__contents;
95493
95507
  // Process each check individually
95494
95508
  for (const checkName of checks) {
95495
95509
  const checkConfig = config?.checks?.[checkName];
@@ -95502,6 +95516,10 @@ class CheckExecutionEngine {
95502
95516
  issues: checkIssues,
95503
95517
  debug: reviewSummary.debug,
95504
95518
  };
95519
+ if (contentMap?.[checkName]) {
95520
+ const summaryWithContent = checkSummary;
95521
+ summaryWithContent.content = contentMap[checkName];
95522
+ }
95505
95523
  // Render content for this check
95506
95524
  const content = await this.renderCheckContent(checkName, checkSummary, checkConfig, prInfo);
95507
95525
  const checkResult = {
@@ -95583,6 +95601,10 @@ class CheckExecutionEngine {
95583
95601
  * Render check content using the appropriate template
95584
95602
  */
95585
95603
  async renderCheckContent(checkName, reviewSummary, checkConfig, _prInfo) {
95604
+ const directContent = reviewSummary.content;
95605
+ if (typeof directContent === 'string' && directContent.trim()) {
95606
+ return directContent.trim();
95607
+ }
95586
95608
  // Import the liquid template system
95587
95609
  const { Liquid } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(48694)));
95588
95610
  const fs = await Promise.resolve().then(() => __importStar(__nccwpck_require__(91943)));
@@ -95768,6 +95790,7 @@ class CheckExecutionEngine {
95768
95790
  const provider = this.providerRegistry.getProviderOrThrow(providerType);
95769
95791
  this.setProviderWebhookContext(provider);
95770
95792
  // Create provider config for this specific check
95793
+ const extendedCheckConfig = checkConfig;
95771
95794
  const providerConfig = {
95772
95795
  type: providerType,
95773
95796
  prompt: checkConfig.prompt,
@@ -95778,9 +95801,11 @@ class CheckExecutionEngine {
95778
95801
  checkName: checkName, // Add checkName for sessionID
95779
95802
  eventContext: prInfo.eventContext, // Pass event context for templates
95780
95803
  transform: checkConfig.transform,
95781
- level: checkConfig.level,
95782
- message: checkConfig.message,
95804
+ transform_js: checkConfig.transform_js,
95805
+ level: extendedCheckConfig.level,
95806
+ message: extendedCheckConfig.message,
95783
95807
  env: checkConfig.env,
95808
+ forEach: checkConfig.forEach,
95784
95809
  ai: {
95785
95810
  timeout: timeout || 600000,
95786
95811
  debug: debug,
@@ -95797,9 +95822,10 @@ class CheckExecutionEngine {
95797
95822
  const depResult = results.get(depId);
95798
95823
  dependencyResults.set(depId, depResult);
95799
95824
  // Check if this dependency has forEach enabled
95800
- if (depResult.isForEach && depResult.forEachItems) {
95825
+ const depForEachResult = depResult;
95826
+ if (depForEachResult.isForEach && Array.isArray(depForEachResult.forEachItems)) {
95801
95827
  isForEachDependent = true;
95802
- forEachItems = depResult.forEachItems;
95828
+ forEachItems = depForEachResult.forEachItems;
95803
95829
  forEachParentName = depId;
95804
95830
  }
95805
95831
  }
@@ -95836,17 +95862,22 @@ class CheckExecutionEngine {
95836
95862
  log(`🔄 Debug: Check "${checkName}" depends on forEach check "${forEachParentName}", executing ${forEachItems.length} times`);
95837
95863
  const allIssues = [];
95838
95864
  const allOutputs = [];
95839
- // Execute check for each item in the forEach array
95840
- for (let itemIndex = 0; itemIndex < forEachItems.length; itemIndex++) {
95841
- const item = forEachItems[itemIndex];
95865
+ const aggregatedContents = [];
95866
+ const itemTasks = forEachItems.map((item, itemIndex) => async () => {
95842
95867
  // Create modified dependency results with current item
95843
95868
  const forEachDependencyResults = new Map();
95844
95869
  for (const [depName, depResult] of dependencyResults) {
95845
95870
  if (depName === forEachParentName) {
95846
- // Replace the entire forEach parent result with just the current item
95847
- // This ensures that outputs.fetch-tickets contains the individual item
95848
- const modifiedResult = item;
95871
+ const modifiedResult = {
95872
+ issues: [],
95873
+ output: item,
95874
+ };
95849
95875
  forEachDependencyResults.set(depName, modifiedResult);
95876
+ const rawResult = {
95877
+ issues: [],
95878
+ output: forEachItems,
95879
+ };
95880
+ forEachDependencyResults.set(`${depName}-raw`, rawResult);
95850
95881
  }
95851
95882
  else {
95852
95883
  forEachDependencyResults.set(depName, depResult);
@@ -95854,24 +95885,49 @@ class CheckExecutionEngine {
95854
95885
  }
95855
95886
  log(`🔄 Debug: Executing check "${checkName}" for item ${itemIndex + 1}/${forEachItems.length}`);
95856
95887
  const itemResult = await provider.execute(prInfo, providerConfig, forEachDependencyResults, sessionInfo);
95857
- // Collect issues from each iteration
95888
+ return { index: itemIndex, itemResult };
95889
+ });
95890
+ const forEachConcurrency = Math.max(1, Math.min(forEachItems.length, effectiveMaxParallelism));
95891
+ if (debug && forEachConcurrency > 1) {
95892
+ log(`🔄 Debug: Limiting forEach concurrency for check "${checkName}" to ${forEachConcurrency}`);
95893
+ }
95894
+ const forEachResults = await this.executeWithLimitedParallelism(itemTasks, forEachConcurrency, false);
95895
+ for (const result of forEachResults) {
95896
+ if (result.status === 'rejected') {
95897
+ throw result.reason;
95898
+ }
95899
+ const { itemResult } = result.value;
95858
95900
  if (itemResult.issues) {
95859
95901
  allIssues.push(...itemResult.issues);
95860
95902
  }
95861
- // Collect outputs from each iteration
95862
- if (itemResult.output) {
95863
- allOutputs.push(itemResult.output);
95903
+ const resultWithOutput = itemResult;
95904
+ if (resultWithOutput.output !== undefined) {
95905
+ allOutputs.push(resultWithOutput.output);
95906
+ }
95907
+ const itemContent = resultWithOutput.content;
95908
+ if (typeof itemContent === 'string' && itemContent.trim()) {
95909
+ aggregatedContents.push(itemContent.trim());
95864
95910
  }
95865
95911
  }
95912
+ const finalOutput = allOutputs.length > 0 ? allOutputs : undefined;
95866
95913
  finalResult = {
95867
95914
  issues: allIssues,
95868
- output: allOutputs.length > 0 ? allOutputs : undefined,
95915
+ ...(finalOutput !== undefined ? { output: finalOutput } : {}),
95869
95916
  };
95917
+ if (aggregatedContents.length > 0) {
95918
+ finalResult.content =
95919
+ aggregatedContents.join('\n');
95920
+ }
95870
95921
  log(`🔄 Debug: Completed forEach execution for check "${checkName}", total issues: ${allIssues.length}`);
95871
95922
  }
95872
95923
  else {
95873
95924
  // Normal single execution
95874
95925
  finalResult = await provider.execute(prInfo, providerConfig, dependencyResults, sessionInfo);
95926
+ if (process.env.DEBUG && checkConfig.forEach) {
95927
+ const finalResultWithOutput = finalResult;
95928
+ const outputPreview = JSON.stringify(finalResultWithOutput.output).slice(0, 200);
95929
+ console.log(`🔧 Debug: Check "${checkName}" provider returned:`, outputPreview);
95930
+ }
95875
95931
  log(`🔧 Debug: Completed check: ${checkName}, issues found: ${(finalResult.issues || []).length}`);
95876
95932
  }
95877
95933
  // Add group, schema, template info and timestamp to issues from config
@@ -95913,28 +95969,39 @@ class CheckExecutionEngine {
95913
95969
  if (result.status === 'fulfilled' && result.value.result && !result.value.error) {
95914
95970
  const reviewResult = result.value.result;
95915
95971
  // Handle forEach logic - process array outputs
95916
- if (checkConfig?.forEach && reviewResult.output) {
95917
- let outputArray = reviewResult.output;
95918
- // Ensure output is an array
95919
- if (!Array.isArray(outputArray)) {
95920
- // Try to parse as JSON if it's a string
95921
- if (typeof outputArray === 'string') {
95922
- try {
95923
- const parsed = JSON.parse(outputArray);
95924
- outputArray = Array.isArray(parsed) ? parsed : [parsed];
95925
- }
95926
- catch {
95927
- outputArray = [outputArray];
95928
- }
95972
+ const reviewSummaryWithOutput = reviewResult;
95973
+ if (checkConfig?.forEach && reviewSummaryWithOutput.output !== undefined) {
95974
+ if (process.env.DEBUG) {
95975
+ console.log(`🔧 Debug: Raw output for forEach check ${checkName}:`, Array.isArray(reviewSummaryWithOutput.output)
95976
+ ? `array(${reviewSummaryWithOutput.output.length})`
95977
+ : typeof reviewSummaryWithOutput.output);
95978
+ }
95979
+ const rawOutput = reviewSummaryWithOutput.output;
95980
+ let normalizedOutput;
95981
+ if (Array.isArray(rawOutput)) {
95982
+ normalizedOutput = rawOutput;
95983
+ }
95984
+ else if (typeof rawOutput === 'string') {
95985
+ try {
95986
+ const parsed = JSON.parse(rawOutput);
95987
+ normalizedOutput = Array.isArray(parsed) ? parsed : [parsed];
95929
95988
  }
95930
- else {
95931
- outputArray = [outputArray];
95989
+ catch {
95990
+ normalizedOutput = [rawOutput];
95932
95991
  }
95933
95992
  }
95934
- log(`🔄 Debug: Check "${checkName}" has forEach enabled, processing ${outputArray.length} items`);
95993
+ else if (rawOutput === undefined || rawOutput === null) {
95994
+ normalizedOutput = [];
95995
+ }
95996
+ else {
95997
+ normalizedOutput = [rawOutput];
95998
+ }
95999
+ if (process.env.DEBUG) {
96000
+ console.log(`🔧 Debug: Check "${checkName}" forEach output:`, JSON.stringify(normalizedOutput).slice(0, 200));
96001
+ }
95935
96002
  // Store the array for iteration by dependent checks
95936
- reviewResult.forEachItems = outputArray;
95937
- reviewResult.isForEach = true;
96003
+ reviewSummaryWithOutput.forEachItems = normalizedOutput;
96004
+ reviewSummaryWithOutput.isForEach = true;
95938
96005
  }
95939
96006
  results.set(checkName, reviewResult);
95940
96007
  }
@@ -96177,6 +96244,7 @@ class CheckExecutionEngine {
96177
96244
  aggregateDependencyAwareResults(results, dependencyGraph, debug, stoppedEarly) {
96178
96245
  const aggregatedIssues = [];
96179
96246
  const debugInfo = [];
96247
+ const contentMap = {};
96180
96248
  // Add execution plan info
96181
96249
  const stats = dependency_resolver_1.DependencyResolver.getExecutionStats(dependencyGraph);
96182
96250
  const executionInfo = [
@@ -96209,9 +96277,16 @@ class CheckExecutionEngine {
96209
96277
  }
96210
96278
  // Issues are already prefixed and enriched with group/schema info
96211
96279
  aggregatedIssues.push(...(result.issues || []));
96280
+ const resultSummary = result;
96281
+ const resultContent = resultSummary.content;
96282
+ if (typeof resultContent === 'string' && resultContent.trim()) {
96283
+ contentMap[checkName] = resultContent.trim();
96284
+ }
96212
96285
  }
96213
96286
  }
96214
- console.error(`🔧 Debug: Aggregated ${aggregatedIssues.length} issues from ${results.size} dependency-aware checks`);
96287
+ if (debug) {
96288
+ console.error(`🔧 Debug: Aggregated ${aggregatedIssues.length} issues from ${results.size} dependency-aware checks`);
96289
+ }
96215
96290
  // Apply issue suppression filtering
96216
96291
  const suppressionEnabled = this.config?.output?.suppressionEnabled !== false;
96217
96292
  const issueFilter = new issue_filter_1.IssueFilter(suppressionEnabled);
@@ -96253,10 +96328,14 @@ class CheckExecutionEngine {
96253
96328
  };
96254
96329
  }
96255
96330
  }
96256
- return {
96331
+ const summary = {
96257
96332
  issues: filteredIssues,
96258
96333
  debug: aggregatedDebug,
96259
96334
  };
96335
+ if (Object.keys(contentMap).length > 0) {
96336
+ summary.__contents = contentMap;
96337
+ }
96338
+ return summary;
96260
96339
  }
96261
96340
  /**
96262
96341
  * Aggregate results from parallel check execution (legacy method)
@@ -96326,7 +96405,9 @@ class CheckExecutionEngine {
96326
96405
  });
96327
96406
  }
96328
96407
  });
96329
- console.error(`🔧 Debug: Aggregated ${aggregatedIssues.length} issues from ${results.length} checks`);
96408
+ if (debug) {
96409
+ console.error(`🔧 Debug: Aggregated ${aggregatedIssues.length} issues from ${results.length} checks`);
96410
+ }
96330
96411
  // Apply issue suppression filtering
96331
96412
  const suppressionEnabled = this.config?.output?.suppressionEnabled !== false;
96332
96413
  const issueFilter = new issue_filter_1.IssueFilter(suppressionEnabled);
@@ -96546,14 +96627,36 @@ class CheckExecutionEngine {
96546
96627
  /**
96547
96628
  * Check if a task result should trigger fail-fast behavior
96548
96629
  */
96630
+ isFailFastCandidate(value) {
96631
+ if (typeof value !== 'object' || value === null) {
96632
+ return false;
96633
+ }
96634
+ const candidate = value;
96635
+ if (candidate.error !== undefined && typeof candidate.error !== 'string') {
96636
+ return false;
96637
+ }
96638
+ if (candidate.result !== undefined) {
96639
+ if (typeof candidate.result !== 'object' || candidate.result === null) {
96640
+ return false;
96641
+ }
96642
+ const issues = candidate.result.issues;
96643
+ if (issues !== undefined && !Array.isArray(issues)) {
96644
+ return false;
96645
+ }
96646
+ }
96647
+ return true;
96648
+ }
96549
96649
  shouldFailFast(result) {
96550
- // If the result has an error property, it's a failed check
96551
- if (result?.error) {
96650
+ if (!this.isFailFastCandidate(result)) {
96651
+ return false;
96652
+ }
96653
+ if (result.error) {
96552
96654
  return true;
96553
96655
  }
96554
96656
  // If the result has a result with critical or error issues, it should fail fast
96555
- if (result?.result?.issues) {
96556
- return (result.result.issues || []).some((issue) => issue.severity === 'error' || issue.severity === 'critical');
96657
+ const issues = result.result?.issues;
96658
+ if (Array.isArray(issues)) {
96659
+ return issues.some(issue => issue?.severity === 'error' || issue?.severity === 'critical');
96557
96660
  }
96558
96661
  return false;
96559
96662
  }
@@ -96939,6 +97042,9 @@ async function main() {
96939
97042
  const filteredArgv = process.argv.filter(arg => arg !== '--cli');
96940
97043
  // Parse arguments using the CLI class
96941
97044
  const options = cli.parseArgs(filteredArgv);
97045
+ const explicitChecks = options.checks.length > 0
97046
+ ? new Set(options.checks.map(check => check.toString()))
97047
+ : null;
96942
97048
  // Set environment variables early for proper logging in all modules
96943
97049
  process.env.VISOR_OUTPUT_FORMAT = options.output;
96944
97050
  process.env.VISOR_DEBUG = options.debug ? 'true' : 'false';
@@ -96992,7 +97098,7 @@ async function main() {
96992
97098
  .catch(() => configManager.getDefaultConfig());
96993
97099
  }
96994
97100
  // Determine checks to run and validate check types early
96995
- const checksToRun = options.checks.length > 0 ? options.checks : Object.keys(config.checks || {});
97101
+ let checksToRun = options.checks.length > 0 ? options.checks : Object.keys(config.checks || {});
96996
97102
  // Validate that all requested checks exist in the configuration
96997
97103
  const availableChecks = Object.keys(config.checks || {});
96998
97104
  const invalidChecks = checksToRun.filter(check => !availableChecks.includes(check));
@@ -97000,8 +97106,28 @@ async function main() {
97000
97106
  console.error(`❌ Error: No configuration found for check: ${invalidChecks[0]}`);
97001
97107
  process.exit(1);
97002
97108
  }
97109
+ // Include dependencies of requested checks
97110
+ const checksWithDependencies = new Set(checksToRun);
97111
+ const addDependencies = (checkName) => {
97112
+ const checkConfig = config.checks?.[checkName];
97113
+ if (checkConfig?.depends_on) {
97114
+ for (const dep of checkConfig.depends_on) {
97115
+ if (!checksWithDependencies.has(dep)) {
97116
+ checksWithDependencies.add(dep);
97117
+ addDependencies(dep); // Recursively add dependencies of dependencies
97118
+ }
97119
+ }
97120
+ }
97121
+ };
97122
+ // Add all dependencies
97123
+ for (const check of checksToRun) {
97124
+ addDependencies(check);
97125
+ }
97126
+ // Update checksToRun to include dependencies
97127
+ checksToRun = Array.from(checksWithDependencies);
97003
97128
  // Use stderr for status messages when outputting formatted results to stdout
97004
- const logFn = console.error;
97129
+ // Suppress all status messages when outputting JSON to avoid breaking parsers
97130
+ const logFn = options.output === 'json' ? () => { } : console.error;
97005
97131
  // Determine if we should include code context (diffs)
97006
97132
  // In CLI mode (local), we do smart detection. PR mode always includes context.
97007
97133
  const isPRContext = false; // This is CLI mode, not GitHub Action
@@ -97047,14 +97173,14 @@ async function main() {
97047
97173
  console.error('❌ Error: Not a git repository. Run "git init" to initialize a repository.');
97048
97174
  process.exit(1);
97049
97175
  }
97176
+ logFn('🔍 Visor - AI-powered code review tool');
97177
+ logFn(`Configuration version: ${config.version}`);
97178
+ logFn(`Configuration source: ${options.configPath || 'default search locations'}`);
97050
97179
  // Check if there are any changes to analyze (only when code context is needed)
97051
97180
  if (includeCodeContext && repositoryInfo.files.length === 0) {
97052
97181
  console.error('❌ Error: No changes to analyze. Make some file changes first.');
97053
97182
  process.exit(1);
97054
97183
  }
97055
- logFn('🔍 Visor - AI-powered code review tool');
97056
- logFn(`Configuration version: ${config.version}`);
97057
- logFn(`Configuration source: ${options.configPath || 'default search locations'}`);
97058
97184
  // Show registered providers if in debug mode
97059
97185
  if (options.debug) {
97060
97186
  const { CheckProviderRegistry } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(57140)));
@@ -97077,26 +97203,52 @@ async function main() {
97077
97203
  // Convert repository info to PRInfo format
97078
97204
  const prInfo = analyzer.toPRInfo(repositoryInfo, includeCodeContext);
97079
97205
  // Store the includeCodeContext flag in prInfo for downstream use
97080
- prInfo.includeCodeContext = includeCodeContext;
97206
+ const prInfoWithContext = prInfo;
97207
+ prInfoWithContext.includeCodeContext = includeCodeContext;
97081
97208
  // Execute checks with proper parameters
97082
97209
  const groupedResults = await engine.executeGroupedChecks(prInfo, checksToRun, options.timeout, config, options.output, options.debug || false, options.maxParallelism, options.failFast, tagFilter);
97210
+ const shouldFilterResults = explicitChecks && explicitChecks.size > 0 && !explicitChecks.has('all');
97211
+ const groupedResultsToUse = shouldFilterResults
97212
+ ? Object.fromEntries(Object.entries(groupedResults)
97213
+ .map(([group, checkResults]) => [
97214
+ group,
97215
+ checkResults.filter(check => explicitChecks.has(check.checkName)),
97216
+ ])
97217
+ .filter(([, checkResults]) => checkResults.length > 0))
97218
+ : groupedResults;
97219
+ if (shouldFilterResults) {
97220
+ for (const [group, checkResults] of Object.entries(groupedResults)) {
97221
+ for (const check of checkResults) {
97222
+ if (check.issues && check.issues.length > 0 && !explicitChecks.has(check.checkName)) {
97223
+ if (!groupedResultsToUse[group]) {
97224
+ groupedResultsToUse[group] = [];
97225
+ }
97226
+ const alreadyIncluded = groupedResultsToUse[group].some(existing => existing.checkName === check.checkName);
97227
+ if (!alreadyIncluded) {
97228
+ groupedResultsToUse[group].push(check);
97229
+ }
97230
+ }
97231
+ }
97232
+ }
97233
+ }
97234
+ const executedCheckNames = Array.from(new Set(Object.values(groupedResultsToUse).flatMap((checks) => checks.map(check => check.checkName))));
97083
97235
  // Format output based on format type
97084
97236
  let output;
97085
97237
  if (options.output === 'json') {
97086
- output = JSON.stringify(groupedResults, null, 2);
97238
+ output = JSON.stringify(groupedResultsToUse, null, 2);
97087
97239
  }
97088
97240
  else if (options.output === 'sarif') {
97089
97241
  // Build analysis result and format as SARIF
97090
97242
  const analysisResult = {
97091
97243
  repositoryInfo,
97092
97244
  reviewSummary: {
97093
- issues: Object.values(groupedResults)
97245
+ issues: Object.values(groupedResultsToUse)
97094
97246
  .flatMap((r) => r.map((check) => check.issues || []).flat())
97095
97247
  .flat(),
97096
97248
  },
97097
97249
  executionTime: 0,
97098
97250
  timestamp: new Date().toISOString(),
97099
- checksExecuted: checksToRun,
97251
+ checksExecuted: executedCheckNames,
97100
97252
  };
97101
97253
  output = output_formatters_1.OutputFormatters.formatAsSarif(analysisResult);
97102
97254
  }
@@ -97105,13 +97257,13 @@ async function main() {
97105
97257
  const analysisResult = {
97106
97258
  repositoryInfo,
97107
97259
  reviewSummary: {
97108
- issues: Object.values(groupedResults)
97260
+ issues: Object.values(groupedResultsToUse)
97109
97261
  .flatMap((r) => r.map((check) => check.issues || []).flat())
97110
97262
  .flat(),
97111
97263
  },
97112
97264
  executionTime: 0,
97113
97265
  timestamp: new Date().toISOString(),
97114
- checksExecuted: checksToRun,
97266
+ checksExecuted: executedCheckNames,
97115
97267
  };
97116
97268
  output = output_formatters_1.OutputFormatters.formatAsMarkdown(analysisResult);
97117
97269
  }
@@ -97120,19 +97272,19 @@ async function main() {
97120
97272
  const analysisResult = {
97121
97273
  repositoryInfo,
97122
97274
  reviewSummary: {
97123
- issues: Object.values(groupedResults)
97275
+ issues: Object.values(groupedResultsToUse)
97124
97276
  .flatMap((r) => r.map((check) => check.issues || []).flat())
97125
97277
  .flat(),
97126
97278
  },
97127
97279
  executionTime: 0,
97128
97280
  timestamp: new Date().toISOString(),
97129
- checksExecuted: checksToRun,
97281
+ checksExecuted: executedCheckNames,
97130
97282
  };
97131
97283
  output = output_formatters_1.OutputFormatters.formatAsTable(analysisResult, { showDetails: true });
97132
97284
  }
97133
97285
  console.log(output);
97134
97286
  // Check for critical issues
97135
- const allResults = Object.values(groupedResults).flat();
97287
+ const allResults = Object.values(groupedResultsToUse).flat();
97136
97288
  const criticalCount = allResults.reduce((sum, result) => {
97137
97289
  const issues = result.issues || [];
97138
97290
  return (sum + issues.filter((issue) => issue.severity === 'critical').length);
@@ -102243,8 +102395,10 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
102243
102395
  }
102244
102396
  }
102245
102397
  // Validate check-level MCP servers if present
102246
- if (cfg.ai_mcp_servers) {
102247
- if (!this.validateMcpServers(cfg.ai_mcp_servers)) {
102398
+ const checkLevelMcpServers = cfg
102399
+ .ai_mcp_servers;
102400
+ if (checkLevelMcpServers) {
102401
+ if (!this.validateMcpServers(checkLevelMcpServers)) {
102248
102402
  return false;
102249
102403
  }
102250
102404
  }
@@ -102262,10 +102416,10 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
102262
102416
  return false;
102263
102417
  }
102264
102418
  const config = serverConfig;
102265
- if (!config.command || typeof config.command !== 'string') {
102419
+ if (typeof config.command !== 'string') {
102266
102420
  return false;
102267
102421
  }
102268
- if (config.args && !Array.isArray(config.args)) {
102422
+ if (config.args !== undefined && !Array.isArray(config.args)) {
102269
102423
  return false;
102270
102424
  }
102271
102425
  }
@@ -102504,9 +102658,10 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
102504
102658
  outputs: dependencyResults
102505
102659
  ? Object.fromEntries(Array.from(dependencyResults.entries()).map(([checkName, result]) => [
102506
102660
  checkName,
102507
- // If the result has a direct output field, use it directly
102508
- // Otherwise, expose the entire result
102509
- result.output !== undefined ? result.output : result,
102661
+ (() => {
102662
+ const summary = result;
102663
+ return summary.output !== undefined ? summary.output : summary;
102664
+ })(),
102510
102665
  ]))
102511
102666
  : {},
102512
102667
  };
@@ -102532,7 +102687,7 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
102532
102687
  return tools;
102533
102688
  }
102534
102689
  const createSdkMcpServer = mcpModule.createSdkMcpServer || mcpModule.default?.createSdkMcpServer;
102535
- if (createSdkMcpServer) {
102690
+ if (typeof createSdkMcpServer === 'function') {
102536
102691
  for (const [serverName, serverConfig] of Object.entries(aiConfig.mcpServers)) {
102537
102692
  try {
102538
102693
  // Create MCP server instance
@@ -102543,8 +102698,8 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
102543
102698
  env: { ...process.env, ...serverConfig.env },
102544
102699
  });
102545
102700
  // Add server tools to available tools
102546
- const serverTools = await server.listTools();
102547
- tools.push(...serverTools.map((tool) => ({
102701
+ const serverTools = (await server.listTools());
102702
+ tools.push(...serverTools.map(tool => ({
102548
102703
  name: tool.name,
102549
102704
  server: serverName,
102550
102705
  })));
@@ -102615,7 +102770,7 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
102615
102770
  // Setup MCP tools from multiple configuration levels
102616
102771
  const mcpServers = {};
102617
102772
  // 1. Start with global MCP servers (from visor config root)
102618
- const globalConfig = config; // Cast to access potential global config
102773
+ const globalConfig = config;
102619
102774
  if (globalConfig.ai_mcp_servers) {
102620
102775
  Object.assign(mcpServers, globalConfig.ai_mcp_servers);
102621
102776
  }
@@ -102932,6 +103087,9 @@ const liquidjs_1 = __nccwpck_require__(48694);
102932
103087
  const promises_1 = __importDefault(__nccwpck_require__(91943));
102933
103088
  const path_1 = __importDefault(__nccwpck_require__(16928));
102934
103089
  const claude_code_types_1 = __nccwpck_require__(21710);
103090
+ function isClaudeCodeConstructor(value) {
103091
+ return typeof value === 'function';
103092
+ }
102935
103093
  /**
102936
103094
  * Error thrown when Claude Code SDK is not installed
102937
103095
  */
@@ -103026,8 +103184,8 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
103026
103184
  if (!claudeCodeModule) {
103027
103185
  throw new ClaudeCodeSDKNotInstalledError();
103028
103186
  }
103029
- const ClaudeCode = claudeCodeModule.ClaudeCode || claudeCodeModule.default?.ClaudeCode;
103030
- if (!ClaudeCode) {
103187
+ const ClaudeCodeCtor = claudeCodeModule.ClaudeCode || claudeCodeModule.default?.ClaudeCode;
103188
+ if (!isClaudeCodeConstructor(ClaudeCodeCtor)) {
103031
103189
  throw new Error('ClaudeCode class not found in @anthropic/claude-code-sdk');
103032
103190
  }
103033
103191
  // Initialize with API key from environment
@@ -103036,7 +103194,7 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
103036
103194
  throw new ClaudeCodeAPIKeyMissingError();
103037
103195
  }
103038
103196
  try {
103039
- const client = new ClaudeCode({
103197
+ const client = new ClaudeCodeCtor({
103040
103198
  apiKey,
103041
103199
  });
103042
103200
  this.claudeCodeClient = client;
@@ -103067,7 +103225,7 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
103067
103225
  return tools;
103068
103226
  }
103069
103227
  const createSdkMcpServer = mcpModule.createSdkMcpServer || mcpModule.default?.createSdkMcpServer;
103070
- if (createSdkMcpServer) {
103228
+ if (typeof createSdkMcpServer === 'function') {
103071
103229
  for (const [serverName, serverConfig] of Object.entries(config.mcpServers)) {
103072
103230
  try {
103073
103231
  // Create MCP server instance
@@ -103078,8 +103236,8 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
103078
103236
  env: { ...process.env, ...serverConfig.env },
103079
103237
  });
103080
103238
  // Add server tools to available tools
103081
- const serverTools = await server.listTools();
103082
- tools.push(...serverTools.map((tool) => ({
103239
+ const serverTools = (await server.listTools());
103240
+ tools.push(...serverTools.map(tool => ({
103083
103241
  name: tool.name,
103084
103242
  server: serverName,
103085
103243
  })));
@@ -103303,7 +103461,10 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
103303
103461
  checkName,
103304
103462
  // If the result has a direct output field, use it directly
103305
103463
  // Otherwise, expose the entire result
103306
- result.output !== undefined ? result.output : result,
103464
+ (() => {
103465
+ const summary = result;
103466
+ return summary.output !== undefined ? summary.output : summary;
103467
+ })(),
103307
103468
  ]))
103308
103469
  : {},
103309
103470
  };
@@ -103385,7 +103546,6 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
103385
103546
  }
103386
103547
  // Parse the response
103387
103548
  const result = this.parseStructuredResponse(response.content);
103388
- // Add debug information if needed by casting to any
103389
103549
  result.debug = {
103390
103550
  prompt: processedPrompt,
103391
103551
  rawResponse: response.content,
@@ -103399,7 +103559,7 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
103399
103559
  errors: [],
103400
103560
  checksExecuted: [config.checkName || 'claude-code-check'],
103401
103561
  parallelExecution: false,
103402
- timestamp: Date.now(),
103562
+ timestamp: new Date().toISOString(),
103403
103563
  // Claude Code specific debug info
103404
103564
  sessionId: response.session_id,
103405
103565
  turnCount: response.turn_count,
@@ -103652,11 +103812,17 @@ class CommandCheckProvider extends check_provider_interface_1.CheckProvider {
103652
103812
  outputs: this.buildOutputContext(dependencyResults),
103653
103813
  env: this.getSafeEnvironmentVariables(),
103654
103814
  };
103815
+ if (process.env.DEBUG) {
103816
+ console.log('🔧 Debug: Template outputs keys:', Object.keys(templateContext.outputs || {}));
103817
+ }
103655
103818
  try {
103656
103819
  // Render the command with Liquid templates if needed
103657
103820
  let renderedCommand = command;
103658
103821
  if (command.includes('{{') || command.includes('{%')) {
103659
- renderedCommand = await this.liquid.parseAndRender(command, templateContext);
103822
+ renderedCommand = await this.renderCommandTemplate(command, templateContext);
103823
+ }
103824
+ if (process.env.DEBUG) {
103825
+ console.log('🔧 Debug: Rendered command:', renderedCommand);
103660
103826
  }
103661
103827
  // Prepare environment variables - convert all to strings
103662
103828
  const scriptEnv = {};
@@ -103687,16 +103853,18 @@ class CommandCheckProvider extends check_provider_interface_1.CheckProvider {
103687
103853
  if (stderr && process.env.DEBUG) {
103688
103854
  console.error(`Command stderr: ${stderr}`);
103689
103855
  }
103690
- // Try to parse output as JSON
103691
- let output = stdout.trim();
103856
+ // Keep raw output for transforms
103857
+ const rawOutput = stdout.trim();
103858
+ // Try to parse output as JSON for default behavior
103859
+ let output = rawOutput;
103692
103860
  try {
103693
103861
  // Attempt to parse as JSON
103694
- const parsed = JSON.parse(stdout.trim());
103862
+ const parsed = JSON.parse(rawOutput);
103695
103863
  output = parsed;
103696
103864
  }
103697
103865
  catch {
103698
103866
  // If not JSON, keep as string
103699
- output = stdout.trim();
103867
+ output = rawOutput;
103700
103868
  }
103701
103869
  // Apply transform if specified (Liquid or JavaScript)
103702
103870
  let finalOutput = output;
@@ -103705,7 +103873,7 @@ class CommandCheckProvider extends check_provider_interface_1.CheckProvider {
103705
103873
  try {
103706
103874
  const transformContext = {
103707
103875
  ...templateContext,
103708
- output,
103876
+ output: output, // Use parsed output for Liquid (object if JSON, string otherwise)
103709
103877
  };
103710
103878
  const rendered = await this.liquid.parseAndRender(transform, transformContext);
103711
103879
  // Try to parse the transformed result as JSON
@@ -103734,21 +103902,55 @@ class CommandCheckProvider extends check_provider_interface_1.CheckProvider {
103734
103902
  // Then apply JavaScript transform if present
103735
103903
  if (transformJs) {
103736
103904
  try {
103905
+ // For transform_js, always use raw string output so JSON.parse() works as expected
103737
103906
  const jsContext = {
103738
- output: finalOutput,
103907
+ output: rawOutput, // Always use raw string for JavaScript transform
103739
103908
  pr: templateContext.pr,
103740
103909
  files: templateContext.files,
103741
103910
  outputs: templateContext.outputs,
103742
103911
  env: templateContext.env,
103743
- // Helper functions
103744
- JSON: JSON,
103745
103912
  };
103746
103913
  // Compile and execute the JavaScript expression
103747
- const exec = this.sandbox.compile(`
103748
- const { output, pr, files, outputs, env, JSON } = scope;
103749
- return (${transformJs.trim()});
103750
- `);
103914
+ // Use direct property access instead of destructuring to avoid syntax issues
103915
+ const trimmedTransform = transformJs.trim();
103916
+ let transformExpression;
103917
+ if (/return\s+/.test(trimmedTransform)) {
103918
+ transformExpression = `(() => {\n${trimmedTransform}\n})()`;
103919
+ }
103920
+ else {
103921
+ const lines = trimmedTransform.split('\n');
103922
+ if (lines.length > 1) {
103923
+ const lastLine = lines[lines.length - 1].trim();
103924
+ const remaining = lines.slice(0, -1).join('\n');
103925
+ if (lastLine && !lastLine.includes('}') && !lastLine.includes('{')) {
103926
+ const returnTarget = lastLine.replace(/;$/, '');
103927
+ transformExpression = `(() => {\n${remaining}\nreturn ${returnTarget};\n})()`;
103928
+ }
103929
+ else {
103930
+ transformExpression = `(${trimmedTransform})`;
103931
+ }
103932
+ }
103933
+ else {
103934
+ transformExpression = `(${trimmedTransform})`;
103935
+ }
103936
+ }
103937
+ const code = `
103938
+ const output = scope.output;
103939
+ const pr = scope.pr;
103940
+ const files = scope.files;
103941
+ const outputs = scope.outputs;
103942
+ const env = scope.env;
103943
+ return ${transformExpression};
103944
+ `;
103945
+ if (process.env.DEBUG) {
103946
+ console.log('🔧 Debug: JavaScript transform code:', code);
103947
+ console.log('🔧 Debug: JavaScript context:', jsContext);
103948
+ }
103949
+ const exec = this.sandbox.compile(code);
103751
103950
  finalOutput = exec({ scope: jsContext }).run();
103951
+ if (process.env.DEBUG) {
103952
+ console.log('🔧 Debug: transform_js result:', JSON.stringify(finalOutput).slice(0, 200));
103953
+ }
103752
103954
  }
103753
103955
  catch (error) {
103754
103956
  return {
@@ -103765,12 +103967,57 @@ class CommandCheckProvider extends check_provider_interface_1.CheckProvider {
103765
103967
  };
103766
103968
  }
103767
103969
  }
103768
- // Return the output as part of the review summary
103769
- // The output will be available to dependent checks
103770
- return {
103771
- issues: [],
103772
- output: finalOutput,
103970
+ // Extract structured issues when the command returns them (skip for forEach parents)
103971
+ let issues = [];
103972
+ let outputForDependents = finalOutput;
103973
+ let content;
103974
+ let extracted = null;
103975
+ const trimmedRawOutput = typeof rawOutput === 'string' ? rawOutput.trim() : undefined;
103976
+ const commandConfig = config;
103977
+ const isForEachParent = commandConfig.forEach === true;
103978
+ if (!isForEachParent) {
103979
+ extracted = this.extractIssuesFromOutput(finalOutput);
103980
+ if (!extracted && typeof finalOutput === 'string') {
103981
+ // Attempt to parse string output as JSON and extract issues again
103982
+ try {
103983
+ const parsed = JSON.parse(finalOutput);
103984
+ extracted = this.extractIssuesFromOutput(parsed);
103985
+ if (extracted) {
103986
+ issues = extracted.issues;
103987
+ outputForDependents = extracted.remainingOutput;
103988
+ }
103989
+ }
103990
+ catch {
103991
+ // Ignore JSON parse errors – leave output as-is
103992
+ }
103993
+ }
103994
+ else if (extracted) {
103995
+ issues = extracted.issues;
103996
+ outputForDependents = extracted.remainingOutput;
103997
+ }
103998
+ if (!issues.length && this.shouldTreatAsTextOutput(trimmedRawOutput)) {
103999
+ content = trimmedRawOutput;
104000
+ }
104001
+ else if (issues.length && typeof extracted?.remainingOutput === 'string') {
104002
+ const trimmed = extracted.remainingOutput.trim();
104003
+ if (trimmed) {
104004
+ content = trimmed;
104005
+ }
104006
+ }
104007
+ }
104008
+ if (!content && this.shouldTreatAsTextOutput(trimmedRawOutput) && !isForEachParent) {
104009
+ content = trimmedRawOutput;
104010
+ }
104011
+ // Return the output and issues as part of the review summary so dependent checks can use them
104012
+ const result = {
104013
+ issues,
104014
+ output: outputForDependents,
104015
+ ...(content ? { content } : {}),
103773
104016
  };
104017
+ if (process.env.DEBUG && transformJs) {
104018
+ console.log(`🔧 Debug: Command provider returning output:`, JSON.stringify(result.output).slice(0, 200));
104019
+ }
104020
+ return result;
103774
104021
  }
103775
104022
  catch (error) {
103776
104023
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
@@ -103796,7 +104043,8 @@ class CommandCheckProvider extends check_provider_interface_1.CheckProvider {
103796
104043
  for (const [checkName, result] of dependencyResults) {
103797
104044
  // If the result has a direct output field, use it directly
103798
104045
  // Otherwise, expose the entire result as-is
103799
- outputs[checkName] = result.output !== undefined ? result.output : result;
104046
+ const summary = result;
104047
+ outputs[checkName] = summary.output !== undefined ? summary.output : summary;
103800
104048
  }
103801
104049
  return outputs;
103802
104050
  }
@@ -103838,6 +104086,190 @@ class CommandCheckProvider extends check_provider_interface_1.CheckProvider {
103838
104086
  'Optional: Transform template for processing output',
103839
104087
  ];
103840
104088
  }
104089
+ extractIssuesFromOutput(output) {
104090
+ if (output === null || output === undefined) {
104091
+ return null;
104092
+ }
104093
+ // If output is already a string, do not treat it as issues here (caller may try parsing JSON)
104094
+ if (typeof output === 'string') {
104095
+ return null;
104096
+ }
104097
+ if (Array.isArray(output)) {
104098
+ const issues = this.normalizeIssueArray(output);
104099
+ if (issues) {
104100
+ return { issues, remainingOutput: undefined };
104101
+ }
104102
+ return null;
104103
+ }
104104
+ if (typeof output === 'object') {
104105
+ const record = output;
104106
+ if (Array.isArray(record.issues)) {
104107
+ const issues = this.normalizeIssueArray(record.issues);
104108
+ if (!issues) {
104109
+ return null;
104110
+ }
104111
+ const remaining = { ...record };
104112
+ delete remaining.issues;
104113
+ const remainingKeys = Object.keys(remaining);
104114
+ const remainingOutput = remainingKeys.length > 0 ? remaining : undefined;
104115
+ return {
104116
+ issues,
104117
+ remainingOutput,
104118
+ };
104119
+ }
104120
+ const singleIssue = this.normalizeIssue(record);
104121
+ if (singleIssue) {
104122
+ return { issues: [singleIssue], remainingOutput: undefined };
104123
+ }
104124
+ }
104125
+ return null;
104126
+ }
104127
+ shouldTreatAsTextOutput(value) {
104128
+ if (!value) {
104129
+ return false;
104130
+ }
104131
+ const trimmed = value.trim();
104132
+ if (!trimmed) {
104133
+ return false;
104134
+ }
104135
+ // Heuristic: consider it JSON-like if it starts with { or [ and ends with } or ]
104136
+ const startsJson = (trimmed.startsWith('{') && trimmed.endsWith('}')) ||
104137
+ (trimmed.startsWith('[') && trimmed.endsWith(']'));
104138
+ return !startsJson;
104139
+ }
104140
+ normalizeIssueArray(values) {
104141
+ const normalized = [];
104142
+ for (const value of values) {
104143
+ const issue = this.normalizeIssue(value);
104144
+ if (!issue) {
104145
+ return null;
104146
+ }
104147
+ normalized.push(issue);
104148
+ }
104149
+ return normalized;
104150
+ }
104151
+ normalizeIssue(raw) {
104152
+ if (!raw || typeof raw !== 'object') {
104153
+ return null;
104154
+ }
104155
+ const data = raw;
104156
+ const message = this.toTrimmedString(data.message || data.text || data.description || data.summary);
104157
+ if (!message) {
104158
+ return null;
104159
+ }
104160
+ const allowedSeverities = new Set(['info', 'warning', 'error', 'critical']);
104161
+ const severityRaw = this.toTrimmedString(data.severity || data.level || data.priority);
104162
+ let severity = 'warning';
104163
+ if (severityRaw) {
104164
+ const lower = severityRaw.toLowerCase();
104165
+ if (allowedSeverities.has(lower)) {
104166
+ severity = lower;
104167
+ }
104168
+ else if (['fatal', 'high'].includes(lower)) {
104169
+ severity = 'error';
104170
+ }
104171
+ else if (['medium', 'moderate'].includes(lower)) {
104172
+ severity = 'warning';
104173
+ }
104174
+ else if (['low', 'minor'].includes(lower)) {
104175
+ severity = 'info';
104176
+ }
104177
+ }
104178
+ const allowedCategories = new Set([
104179
+ 'security',
104180
+ 'performance',
104181
+ 'style',
104182
+ 'logic',
104183
+ 'documentation',
104184
+ ]);
104185
+ const categoryRaw = this.toTrimmedString(data.category || data.type || data.group);
104186
+ let category = 'logic';
104187
+ if (categoryRaw && allowedCategories.has(categoryRaw.toLowerCase())) {
104188
+ category = categoryRaw.toLowerCase();
104189
+ }
104190
+ const file = this.toTrimmedString(data.file || data.path || data.filename) || 'system';
104191
+ const line = this.toNumber(data.line || data.startLine || data.lineNumber) ?? 0;
104192
+ const endLine = this.toNumber(data.endLine || data.end_line || data.stopLine);
104193
+ const suggestion = this.toTrimmedString(data.suggestion);
104194
+ const replacement = this.toTrimmedString(data.replacement);
104195
+ const ruleId = this.toTrimmedString(data.ruleId || data.rule || data.id || data.check) || 'command';
104196
+ return {
104197
+ file,
104198
+ line,
104199
+ endLine: endLine ?? undefined,
104200
+ ruleId,
104201
+ message,
104202
+ severity,
104203
+ category,
104204
+ suggestion: suggestion || undefined,
104205
+ replacement: replacement || undefined,
104206
+ };
104207
+ }
104208
+ toTrimmedString(value) {
104209
+ if (typeof value === 'string') {
104210
+ const trimmed = value.trim();
104211
+ return trimmed.length > 0 ? trimmed : null;
104212
+ }
104213
+ if (value !== null && value !== undefined && typeof value.toString === 'function') {
104214
+ const converted = String(value).trim();
104215
+ return converted.length > 0 ? converted : null;
104216
+ }
104217
+ return null;
104218
+ }
104219
+ toNumber(value) {
104220
+ if (value === null || value === undefined) {
104221
+ return null;
104222
+ }
104223
+ const num = Number(value);
104224
+ if (Number.isFinite(num)) {
104225
+ return Math.trunc(num);
104226
+ }
104227
+ return null;
104228
+ }
104229
+ async renderCommandTemplate(template, context) {
104230
+ try {
104231
+ return await this.liquid.parseAndRender(template, context);
104232
+ }
104233
+ catch (error) {
104234
+ if (process.env.DEBUG) {
104235
+ console.warn('🔧 Debug: Liquid rendering failed, falling back to JS evaluation:', error);
104236
+ }
104237
+ return this.renderWithJsExpressions(template, context);
104238
+ }
104239
+ }
104240
+ renderWithJsExpressions(template, context) {
104241
+ const scope = {
104242
+ pr: context.pr,
104243
+ files: context.files,
104244
+ outputs: context.outputs,
104245
+ env: context.env,
104246
+ };
104247
+ const expressionRegex = /\{\{\s*([^{}]+?)\s*\}\}/g;
104248
+ return template.replace(expressionRegex, (_match, expr) => {
104249
+ const expression = String(expr).trim();
104250
+ if (!expression) {
104251
+ return '';
104252
+ }
104253
+ try {
104254
+ const evalCode = `
104255
+ const pr = scope.pr;
104256
+ const files = scope.files;
104257
+ const outputs = scope.outputs;
104258
+ const env = scope.env;
104259
+ return (${expression});
104260
+ `;
104261
+ const evaluator = this.sandbox.compile(evalCode);
104262
+ const result = evaluator({ scope }).run();
104263
+ return result === undefined || result === null ? '' : String(result);
104264
+ }
104265
+ catch (evaluationError) {
104266
+ if (process.env.DEBUG) {
104267
+ console.warn('🔧 Debug: Failed to evaluate expression:', expression, evaluationError);
104268
+ }
104269
+ return '';
104270
+ }
104271
+ });
104272
+ }
103841
104273
  }
103842
104274
  exports.CommandCheckProvider = CommandCheckProvider;
103843
104275
 
@@ -104542,7 +104974,8 @@ class LogCheckProvider extends check_provider_interface_1.CheckProvider {
104542
104974
  issues: result.issues || [],
104543
104975
  };
104544
104976
  // Add outputs namespace for accessing dependency results directly
104545
- outputs[checkName] = result.output !== undefined ? result.output : result;
104977
+ const summary = result;
104978
+ outputs[checkName] = summary.output !== undefined ? summary.output : summary;
104546
104979
  }
104547
104980
  context.dependencies = dependencies;
104548
104981
  context.outputs = outputs;
@@ -105248,16 +105681,16 @@ class ConfigLoader {
105248
105681
  const outputFormat = process.env.VISOR_OUTPUT_FORMAT;
105249
105682
  const logFn = outputFormat === 'json' || outputFormat === 'sarif' ? console.error : console.log;
105250
105683
  logFn(`⬇️ Fetching remote configuration from: ${url}`);
105684
+ const controller = new AbortController();
105685
+ const timeoutMs = this.options.timeout ?? 30000;
105686
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
105251
105687
  try {
105252
- const controller = new AbortController();
105253
- const timeoutId = setTimeout(() => controller.abort(), this.options.timeout || 30000);
105254
105688
  const response = await fetch(url, {
105255
105689
  signal: controller.signal,
105256
105690
  headers: {
105257
105691
  'User-Agent': 'Visor/1.0',
105258
105692
  },
105259
105693
  });
105260
- clearTimeout(timeoutId);
105261
105694
  if (!response.ok) {
105262
105695
  throw new Error(`Failed to fetch config: ${response.status} ${response.statusText}`);
105263
105696
  }
@@ -105281,12 +105714,15 @@ class ConfigLoader {
105281
105714
  catch (error) {
105282
105715
  if (error instanceof Error) {
105283
105716
  if (error.name === 'AbortError') {
105284
- throw new Error(`Timeout fetching configuration from ${url} (${this.options.timeout}ms)`);
105717
+ throw new Error(`Timeout fetching configuration from ${url} (${timeoutMs}ms)`);
105285
105718
  }
105286
105719
  throw new Error(`Failed to fetch remote configuration from ${url}: ${error.message}`);
105287
105720
  }
105288
105721
  throw error;
105289
105722
  }
105723
+ finally {
105724
+ clearTimeout(timeoutId);
105725
+ }
105290
105726
  }
105291
105727
  /**
105292
105728
  * Load bundled default configuration
@@ -125875,7 +126311,7 @@ function createMessagePreview(message, charsPerSide = 200) {
125875
126311
  const end = message.substring(message.length - charsPerSide);
125876
126312
  return `${start}...${end}`;
125877
126313
  }
125878
- var import_zod, searchSchema, querySchema, extractSchema, delegateSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, DEFAULT_VALID_TOOLS;
126314
+ var import_zod, searchSchema, querySchema, extractSchema, delegateSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, bashToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, bashDescription, DEFAULT_VALID_TOOLS;
125879
126315
  var init_common = __esm({
125880
126316
  "src/tools/common.js"() {
125881
126317
  "use strict";
@@ -125907,6 +126343,12 @@ var init_common = __esm({
125907
126343
  delegateSchema = import_zod.z.object({
125908
126344
  task: import_zod.z.string().describe("The task to delegate to a subagent. Be specific about what needs to be accomplished.")
125909
126345
  });
126346
+ bashSchema = import_zod.z.object({
126347
+ command: import_zod.z.string().describe("The bash command to execute"),
126348
+ workingDirectory: import_zod.z.string().optional().describe("Directory to execute the command in (optional)"),
126349
+ timeout: import_zod.z.number().optional().describe("Command timeout in milliseconds (optional)"),
126350
+ env: import_zod.z.record(import_zod.z.string()).optional().describe("Additional environment variables (optional)")
126351
+ });
125910
126352
  attemptCompletionSchema = {
125911
126353
  // Custom validation that requires result parameter but allows direct XML response
125912
126354
  safeParse: (params) => {
@@ -126129,11 +126571,67 @@ Usage Example:
126129
126571
  <attempt_completion>
126130
126572
  I have refactored the search module according to the requirements and verified the tests pass. The module now uses the new BM25 ranking algorithm and has improved error handling.
126131
126573
  </attempt_completion>
126574
+ `;
126575
+ bashToolDefinition = `
126576
+ ## bash
126577
+ Description: Execute bash commands for system exploration and development tasks. This tool has built-in security with allow/deny lists. By default, only safe read-only commands are allowed for code exploration.
126578
+
126579
+ Parameters:
126580
+ - command: (required) The bash command to execute
126581
+ - workingDirectory: (optional) Directory to execute the command in
126582
+ - timeout: (optional) Command timeout in milliseconds
126583
+ - env: (optional) Additional environment variables as an object
126584
+
126585
+ Security: Commands are filtered through allow/deny lists for safety:
126586
+ - Allowed by default: ls, cat, git status, npm list, find, grep, etc.
126587
+ - Denied by default: rm -rf, sudo, npm install, dangerous system commands
126588
+
126589
+ Usage Examples:
126590
+
126591
+ <examples>
126592
+
126593
+ User: What files are in the src directory?
126594
+ <bash>
126595
+ <command>ls -la src/</command>
126596
+ </bash>
126597
+
126598
+ User: Show me the git status
126599
+ <bash>
126600
+ <command>git status</command>
126601
+ </bash>
126602
+
126603
+ User: Find all TypeScript files
126604
+ <bash>
126605
+ <command>find . -name "*.ts" -type f</command>
126606
+ </bash>
126607
+
126608
+ User: Check installed npm packages
126609
+ <bash>
126610
+ <command>npm list --depth=0</command>
126611
+ </bash>
126612
+
126613
+ User: Search for TODO comments in code
126614
+ <bash>
126615
+ <command>grep -r "TODO" src/</command>
126616
+ </bash>
126617
+
126618
+ User: Show recent git commits
126619
+ <bash>
126620
+ <command>git log --oneline -10</command>
126621
+ </bash>
126622
+
126623
+ User: Check system info
126624
+ <bash>
126625
+ <command>uname -a</command>
126626
+ </bash>
126627
+
126628
+ </examples>
126132
126629
  `;
126133
126630
  searchDescription = "Search code in the repository using Elasticsearch-like query syntax. Use this tool first for any code-related questions.";
126134
126631
  queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
126135
126632
  extractDescription = "Extract code blocks from files based on file paths and optional line numbers. Use this tool to see complete context after finding relevant files.";
126136
126633
  delegateDescription = "Automatically delegate big distinct tasks to specialized probe subagents within the agentic loop. Used by AI agents to break down complex requests into focused, parallel tasks.";
126634
+ bashDescription = "Execute bash commands for system exploration and development tasks. Secure by default with built-in allow/deny lists.";
126137
126635
  DEFAULT_VALID_TOOLS = [
126138
126636
  "search",
126139
126637
  "query",
@@ -126187,7 +126685,7 @@ async function delegate({ task, timeout = 300, debug = false, currentIteration =
126187
126685
  console.error(`[DELEGATE] Using binary at: ${binaryPath}`);
126188
126686
  console.error(`[DELEGATE] Command args: ${args.join(" ")}`);
126189
126687
  }
126190
- return new Promise((resolve2, reject) => {
126688
+ return new Promise((resolve4, reject) => {
126191
126689
  const delegationSpan = tracer ? tracer.createDelegationSpan(sessionId, task) : null;
126192
126690
  const process2 = (0, import_child_process5.spawn)(binaryPath, args, {
126193
126691
  stdio: ["pipe", "pipe", "pipe"],
@@ -126252,7 +126750,7 @@ async function delegate({ task, timeout = 300, debug = false, currentIteration =
126252
126750
  delegationSpan.end();
126253
126751
  }
126254
126752
  }
126255
- resolve2(response);
126753
+ resolve4(response);
126256
126754
  } else {
126257
126755
  const errorMessage = stderr.trim() || `Delegate process failed with exit code ${code}`;
126258
126756
  if (debug) {
@@ -126448,10 +126946,10 @@ var init_vercel = __esm({
126448
126946
  let extractOptions = { path: extractPath };
126449
126947
  if (input_content) {
126450
126948
  const { writeFileSync: writeFileSync2, unlinkSync } = await Promise.resolve(/* import() */).then(__nccwpck_require__.t.bind(__nccwpck_require__, 79896, 23));
126451
- const { join: join2 } = await Promise.resolve(/* import() */).then(__nccwpck_require__.t.bind(__nccwpck_require__, 16928, 23));
126949
+ const { join: join3 } = await Promise.resolve(/* import() */).then(__nccwpck_require__.t.bind(__nccwpck_require__, 16928, 23));
126452
126950
  const { tmpdir } = await Promise.resolve(/* import() */).then(__nccwpck_require__.t.bind(__nccwpck_require__, 70857, 23));
126453
126951
  const { randomUUID: randomUUID5 } = await Promise.resolve(/* import() */).then(__nccwpck_require__.t.bind(__nccwpck_require__, 76982, 23));
126454
- tempFilePath = join2(tmpdir(), `probe-extract-${randomUUID5()}.txt`);
126952
+ tempFilePath = join3(tmpdir(), `probe-extract-${randomUUID5()}.txt`);
126455
126953
  writeFileSync2(tempFilePath, input_content);
126456
126954
  if (debug) {
126457
126955
  console.error(`Created temporary file for input content: ${tempFilePath}`);
@@ -126528,6 +127026,1248 @@ var init_vercel = __esm({
126528
127026
  }
126529
127027
  });
126530
127028
 
127029
+ // src/agent/bashDefaults.js
127030
+ var DEFAULT_ALLOW_PATTERNS, DEFAULT_DENY_PATTERNS;
127031
+ var init_bashDefaults = __esm({
127032
+ "src/agent/bashDefaults.js"() {
127033
+ "use strict";
127034
+ DEFAULT_ALLOW_PATTERNS = [
127035
+ // Basic navigation and listing
127036
+ "ls",
127037
+ "dir",
127038
+ "pwd",
127039
+ "cd",
127040
+ "cd:*",
127041
+ // File reading commands
127042
+ "cat",
127043
+ "cat:*",
127044
+ "head",
127045
+ "head:*",
127046
+ "tail",
127047
+ "tail:*",
127048
+ "less",
127049
+ "more",
127050
+ "view",
127051
+ // File information and metadata
127052
+ "file",
127053
+ "file:*",
127054
+ "stat",
127055
+ "stat:*",
127056
+ "wc",
127057
+ "wc:*",
127058
+ "du",
127059
+ "du:*",
127060
+ "df",
127061
+ "df:*",
127062
+ "realpath",
127063
+ "realpath:*",
127064
+ // Search and find commands (read-only) - find restricted to safe operations
127065
+ "find",
127066
+ "find:-name:*",
127067
+ "find:-type:*",
127068
+ "find:-size:*",
127069
+ "find:-mtime:*",
127070
+ "find:-newer:*",
127071
+ "find:-path:*",
127072
+ "find:-iname:*",
127073
+ "find:-maxdepth:*",
127074
+ "find:-mindepth:*",
127075
+ "find:-print",
127076
+ "grep",
127077
+ "grep:*",
127078
+ "egrep",
127079
+ "egrep:*",
127080
+ "fgrep",
127081
+ "fgrep:*",
127082
+ "rg",
127083
+ "rg:*",
127084
+ "ag",
127085
+ "ag:*",
127086
+ "ack",
127087
+ "ack:*",
127088
+ "which",
127089
+ "which:*",
127090
+ "whereis",
127091
+ "whereis:*",
127092
+ "locate",
127093
+ "locate:*",
127094
+ "type",
127095
+ "type:*",
127096
+ "command",
127097
+ "command:*",
127098
+ // Tree and structure visualization
127099
+ "tree",
127100
+ "tree:*",
127101
+ // Git read-only operations
127102
+ "git:status",
127103
+ "git:log",
127104
+ "git:log:*",
127105
+ "git:diff",
127106
+ "git:diff:*",
127107
+ "git:show",
127108
+ "git:show:*",
127109
+ "git:branch",
127110
+ "git:branch:*",
127111
+ "git:tag",
127112
+ "git:tag:*",
127113
+ "git:describe",
127114
+ "git:describe:*",
127115
+ "git:remote",
127116
+ "git:remote:*",
127117
+ "git:config:*",
127118
+ "git:blame",
127119
+ "git:blame:*",
127120
+ "git:shortlog",
127121
+ "git:reflog",
127122
+ "git:ls-files",
127123
+ "git:ls-tree",
127124
+ "git:rev-parse",
127125
+ "git:rev-list",
127126
+ "git:--version",
127127
+ "git:help",
127128
+ "git:help:*",
127129
+ // Package managers (information only)
127130
+ "npm:list",
127131
+ "npm:ls",
127132
+ "npm:view",
127133
+ "npm:info",
127134
+ "npm:show",
127135
+ "npm:outdated",
127136
+ "npm:audit",
127137
+ "npm:--version",
127138
+ "yarn:list",
127139
+ "yarn:info",
127140
+ "yarn:--version",
127141
+ "pnpm:list",
127142
+ "pnpm:--version",
127143
+ "pip:list",
127144
+ "pip:show",
127145
+ "pip:--version",
127146
+ "pip3:list",
127147
+ "pip3:show",
127148
+ "pip3:--version",
127149
+ "gem:list",
127150
+ "gem:--version",
127151
+ "bundle:list",
127152
+ "bundle:show",
127153
+ "bundle:--version",
127154
+ "composer:show",
127155
+ "composer:--version",
127156
+ // Language and runtime versions
127157
+ "node:--version",
127158
+ "node:-v",
127159
+ "python:--version",
127160
+ "python:-V",
127161
+ "python3:--version",
127162
+ "python3:-V",
127163
+ "ruby:--version",
127164
+ "ruby:-v",
127165
+ "go:version",
127166
+ "go:env",
127167
+ "go:list",
127168
+ "go:mod:graph",
127169
+ "rustc:--version",
127170
+ "cargo:--version",
127171
+ "cargo:tree",
127172
+ "cargo:metadata",
127173
+ "java:--version",
127174
+ "java:-version",
127175
+ "javac:--version",
127176
+ "mvn:--version",
127177
+ "gradle:--version",
127178
+ "php:--version",
127179
+ "dotnet:--version",
127180
+ "dotnet:list",
127181
+ // Database client versions (connection info only)
127182
+ "psql:--version",
127183
+ "mysql:--version",
127184
+ "redis-cli:--version",
127185
+ "mongo:--version",
127186
+ "sqlite3:--version",
127187
+ // System information
127188
+ "uname",
127189
+ "uname:*",
127190
+ "hostname",
127191
+ "whoami",
127192
+ "id",
127193
+ "groups",
127194
+ "date",
127195
+ "cal",
127196
+ "uptime",
127197
+ "w",
127198
+ "users",
127199
+ "sleep",
127200
+ "sleep:*",
127201
+ // Environment and shell
127202
+ "env",
127203
+ "printenv",
127204
+ "echo",
127205
+ "echo:*",
127206
+ "printf",
127207
+ "printf:*",
127208
+ "export",
127209
+ "export:*",
127210
+ "set",
127211
+ "unset",
127212
+ // Process information (read-only)
127213
+ "ps",
127214
+ "ps:*",
127215
+ "pgrep",
127216
+ "pgrep:*",
127217
+ "jobs",
127218
+ "top:-n:1",
127219
+ // Network information (read-only)
127220
+ "ifconfig",
127221
+ "ip:addr",
127222
+ "ip:link",
127223
+ "hostname:-I",
127224
+ "ping:-c:*",
127225
+ "traceroute",
127226
+ "nslookup",
127227
+ "dig",
127228
+ // Text processing and utilities (awk removed - too powerful)
127229
+ "sed:-n:*",
127230
+ "cut",
127231
+ "cut:*",
127232
+ "sort",
127233
+ "sort:*",
127234
+ "uniq",
127235
+ "uniq:*",
127236
+ "tr",
127237
+ "tr:*",
127238
+ "column",
127239
+ "column:*",
127240
+ "paste",
127241
+ "paste:*",
127242
+ "join",
127243
+ "join:*",
127244
+ "comm",
127245
+ "comm:*",
127246
+ "diff",
127247
+ "diff:*",
127248
+ "cmp",
127249
+ "cmp:*",
127250
+ "patch:--dry-run:*",
127251
+ // Hashing and encoding (read-only)
127252
+ "md5sum",
127253
+ "md5sum:*",
127254
+ "sha1sum",
127255
+ "sha1sum:*",
127256
+ "sha256sum",
127257
+ "sha256sum:*",
127258
+ "base64",
127259
+ "base64:-d",
127260
+ "od",
127261
+ "od:*",
127262
+ "hexdump",
127263
+ "hexdump:*",
127264
+ // Archive and compression (list/view only)
127265
+ "tar:-tf:*",
127266
+ "tar:-tzf:*",
127267
+ "unzip:-l:*",
127268
+ "zip:-l:*",
127269
+ "gzip:-l:*",
127270
+ "gunzip:-l:*",
127271
+ // Help and documentation
127272
+ "man",
127273
+ "man:*",
127274
+ "--help",
127275
+ "help",
127276
+ "info",
127277
+ "info:*",
127278
+ "whatis",
127279
+ "whatis:*",
127280
+ "apropos",
127281
+ "apropos:*",
127282
+ // Make (dry run and info)
127283
+ "make:-n",
127284
+ "make:--dry-run",
127285
+ "make:-p",
127286
+ "make:--print-data-base",
127287
+ // Docker (read-only operations)
127288
+ "docker:ps",
127289
+ "docker:images",
127290
+ "docker:version",
127291
+ "docker:info",
127292
+ "docker:logs:*",
127293
+ "docker:inspect:*",
127294
+ // Test runners (list/info only)
127295
+ "jest:--listTests",
127296
+ "mocha:--help",
127297
+ "pytest:--collect-only"
127298
+ ];
127299
+ DEFAULT_DENY_PATTERNS = [
127300
+ // Dangerous file operations
127301
+ "rm:-rf",
127302
+ "rm:-f:/",
127303
+ "rm:/",
127304
+ "rm:-rf:*",
127305
+ "rmdir",
127306
+ "chmod:777",
127307
+ "chmod:-R:777",
127308
+ "chown",
127309
+ "chgrp",
127310
+ "dd",
127311
+ "dd:*",
127312
+ "shred",
127313
+ "shred:*",
127314
+ // Dangerous find operations that can execute arbitrary commands
127315
+ "find:-exec:*",
127316
+ "find:*:-exec:*",
127317
+ "find:-execdir:*",
127318
+ "find:*:-execdir:*",
127319
+ "find:-ok:*",
127320
+ "find:*:-ok:*",
127321
+ "find:-okdir:*",
127322
+ "find:*:-okdir:*",
127323
+ // Powerful scripting tools that can execute arbitrary commands
127324
+ "awk",
127325
+ "awk:*",
127326
+ "perl",
127327
+ "perl:*",
127328
+ "python:-c:*",
127329
+ "node:-e:*",
127330
+ // System administration and modification
127331
+ "sudo:*",
127332
+ "su",
127333
+ "su:*",
127334
+ "passwd",
127335
+ "adduser",
127336
+ "useradd",
127337
+ "userdel",
127338
+ "usermod",
127339
+ "groupadd",
127340
+ "groupdel",
127341
+ "visudo",
127342
+ // Package installation and removal
127343
+ "npm:install",
127344
+ "npm:i",
127345
+ "npm:uninstall",
127346
+ "npm:publish",
127347
+ "npm:unpublish",
127348
+ "npm:link",
127349
+ "npm:update",
127350
+ "yarn:install",
127351
+ "yarn:add",
127352
+ "yarn:remove",
127353
+ "yarn:upgrade",
127354
+ "pnpm:install",
127355
+ "pnpm:add",
127356
+ "pnpm:remove",
127357
+ "pip:install",
127358
+ "pip:uninstall",
127359
+ "pip:upgrade",
127360
+ "pip3:install",
127361
+ "pip3:uninstall",
127362
+ "pip3:upgrade",
127363
+ "gem:install",
127364
+ "gem:uninstall",
127365
+ "gem:update",
127366
+ "bundle:install",
127367
+ "bundle:update",
127368
+ "composer:install",
127369
+ "composer:update",
127370
+ "composer:remove",
127371
+ "apt:*",
127372
+ "apt-get:*",
127373
+ "yum:*",
127374
+ "dnf:*",
127375
+ "zypper:*",
127376
+ "brew:install",
127377
+ "brew:uninstall",
127378
+ "brew:upgrade",
127379
+ "conda:install",
127380
+ "conda:remove",
127381
+ "conda:update",
127382
+ // Service and system control
127383
+ "systemctl:*",
127384
+ "service:*",
127385
+ "chkconfig:*",
127386
+ "initctl:*",
127387
+ "upstart:*",
127388
+ // Network operations that could be dangerous
127389
+ "curl:-d:*",
127390
+ "curl:--data:*",
127391
+ "curl:-X:POST:*",
127392
+ "curl:-X:PUT:*",
127393
+ "wget:-O:/",
127394
+ "wget:--post-data:*",
127395
+ "ssh",
127396
+ "ssh:*",
127397
+ "scp",
127398
+ "scp:*",
127399
+ "sftp",
127400
+ "sftp:*",
127401
+ "rsync:*",
127402
+ "nc",
127403
+ "nc:*",
127404
+ "netcat",
127405
+ "netcat:*",
127406
+ "telnet",
127407
+ "telnet:*",
127408
+ "ftp",
127409
+ "ftp:*",
127410
+ // Process control and termination
127411
+ "kill",
127412
+ "kill:*",
127413
+ "killall",
127414
+ "killall:*",
127415
+ "pkill",
127416
+ "pkill:*",
127417
+ "nohup:*",
127418
+ "disown:*",
127419
+ // System control and shutdown
127420
+ "shutdown",
127421
+ "shutdown:*",
127422
+ "reboot",
127423
+ "halt",
127424
+ "poweroff",
127425
+ "init",
127426
+ "telinit",
127427
+ // Kernel and module operations
127428
+ "insmod",
127429
+ "insmod:*",
127430
+ "rmmod",
127431
+ "rmmod:*",
127432
+ "modprobe",
127433
+ "modprobe:*",
127434
+ "sysctl:-w:*",
127435
+ // Dangerous git operations
127436
+ "git:push",
127437
+ "git:push:*",
127438
+ "git:force",
127439
+ "git:reset:--hard:*",
127440
+ "git:clean:-fd",
127441
+ "git:rm:*",
127442
+ "git:commit",
127443
+ "git:merge",
127444
+ "git:rebase",
127445
+ "git:cherry-pick",
127446
+ "git:stash:drop",
127447
+ // File system mounting and partitioning
127448
+ "mount",
127449
+ "mount:*",
127450
+ "umount",
127451
+ "umount:*",
127452
+ "fdisk",
127453
+ "fdisk:*",
127454
+ "parted",
127455
+ "parted:*",
127456
+ "mkfs",
127457
+ "mkfs:*",
127458
+ "fsck",
127459
+ "fsck:*",
127460
+ // Cron and scheduling
127461
+ "crontab",
127462
+ "crontab:*",
127463
+ "at",
127464
+ "at:*",
127465
+ "batch",
127466
+ "batch:*",
127467
+ // Compression with potential overwrite
127468
+ "tar:-xf:*",
127469
+ "unzip",
127470
+ "unzip:*",
127471
+ "gzip:*",
127472
+ "gunzip:*",
127473
+ // Build and compilation that might modify files
127474
+ "make",
127475
+ "make:install",
127476
+ "make:clean",
127477
+ "cargo:build",
127478
+ "cargo:install",
127479
+ "npm:run:build",
127480
+ "yarn:build",
127481
+ "mvn:install",
127482
+ "gradle:build",
127483
+ // Docker operations that could modify state
127484
+ "docker:run",
127485
+ "docker:run:*",
127486
+ "docker:exec",
127487
+ "docker:exec:*",
127488
+ "docker:build",
127489
+ "docker:build:*",
127490
+ "docker:pull",
127491
+ "docker:push",
127492
+ "docker:rm",
127493
+ "docker:rmi",
127494
+ "docker:stop",
127495
+ "docker:start",
127496
+ // Database operations
127497
+ "mysql:-e:DROP",
127498
+ "psql:-c:DROP",
127499
+ "redis-cli:FLUSHALL",
127500
+ "mongo:--eval:*",
127501
+ // Text editors that could modify files
127502
+ "vi",
127503
+ "vi:*",
127504
+ "vim",
127505
+ "vim:*",
127506
+ "nano",
127507
+ "nano:*",
127508
+ "emacs",
127509
+ "emacs:*",
127510
+ "sed:-i:*",
127511
+ "perl:-i:*",
127512
+ // Potentially dangerous utilities
127513
+ "eval",
127514
+ "eval:*",
127515
+ "exec",
127516
+ "exec:*",
127517
+ "source",
127518
+ "source:*",
127519
+ "bash:-c:*",
127520
+ "sh:-c:*",
127521
+ "zsh:-c:*"
127522
+ ];
127523
+ }
127524
+ });
127525
+
127526
+ // src/agent/bashCommandUtils.js
127527
+ function parseSimpleCommand(command) {
127528
+ if (!command || typeof command !== "string") {
127529
+ return {
127530
+ success: false,
127531
+ error: "Command must be a non-empty string",
127532
+ command: null,
127533
+ args: [],
127534
+ isComplex: false
127535
+ };
127536
+ }
127537
+ const trimmed = command.trim();
127538
+ if (!trimmed) {
127539
+ return {
127540
+ success: false,
127541
+ error: "Command cannot be empty",
127542
+ command: null,
127543
+ args: [],
127544
+ isComplex: false
127545
+ };
127546
+ }
127547
+ const complexPatterns = [
127548
+ /\|/,
127549
+ // Pipes
127550
+ /&&/,
127551
+ // Logical AND
127552
+ /\|\|/,
127553
+ // Logical OR
127554
+ /(?<!\\);/,
127555
+ // Command separator (but not escaped \;)
127556
+ /&$/,
127557
+ // Background execution
127558
+ /\$\(/,
127559
+ // Command substitution $()
127560
+ /`/,
127561
+ // Command substitution ``
127562
+ />/,
127563
+ // Redirection >
127564
+ /</,
127565
+ // Redirection <
127566
+ /\*\*/,
127567
+ // Glob patterns (potentially dangerous)
127568
+ /^\s*\{.*,.*\}|\{.*\.\.\.*\}/
127569
+ // Brace expansion like {a,b} or {1..10} (but not find {} placeholders)
127570
+ ];
127571
+ for (const pattern of complexPatterns) {
127572
+ if (pattern.test(trimmed)) {
127573
+ return {
127574
+ success: false,
127575
+ error: "Complex shell commands with pipes, operators, or redirections are not supported for security reasons",
127576
+ command: null,
127577
+ args: [],
127578
+ isComplex: true,
127579
+ detected: pattern.toString()
127580
+ };
127581
+ }
127582
+ }
127583
+ const args = [];
127584
+ let current = "";
127585
+ let inQuotes = false;
127586
+ let quoteChar = "";
127587
+ let escaped = false;
127588
+ for (let i3 = 0; i3 < trimmed.length; i3++) {
127589
+ const char = trimmed[i3];
127590
+ const nextChar = i3 + 1 < trimmed.length ? trimmed[i3 + 1] : "";
127591
+ if (escaped) {
127592
+ current += char;
127593
+ escaped = false;
127594
+ continue;
127595
+ }
127596
+ if (char === "\\" && !inQuotes) {
127597
+ escaped = true;
127598
+ continue;
127599
+ }
127600
+ if (!inQuotes && (char === '"' || char === "'")) {
127601
+ inQuotes = true;
127602
+ quoteChar = char;
127603
+ } else if (inQuotes && char === quoteChar) {
127604
+ inQuotes = false;
127605
+ quoteChar = "";
127606
+ } else if (!inQuotes && char === " ") {
127607
+ if (current.trim()) {
127608
+ args.push(current.trim());
127609
+ current = "";
127610
+ }
127611
+ } else {
127612
+ current += char;
127613
+ }
127614
+ }
127615
+ if (current.trim()) {
127616
+ args.push(current.trim());
127617
+ }
127618
+ if (inQuotes) {
127619
+ return {
127620
+ success: false,
127621
+ error: `Unclosed quote in command: ${quoteChar}`,
127622
+ command: null,
127623
+ args: [],
127624
+ isComplex: false
127625
+ };
127626
+ }
127627
+ if (args.length === 0) {
127628
+ return {
127629
+ success: false,
127630
+ error: "No command found after parsing",
127631
+ command: null,
127632
+ args: [],
127633
+ isComplex: false
127634
+ };
127635
+ }
127636
+ const [baseCommand, ...commandArgs] = args;
127637
+ return {
127638
+ success: true,
127639
+ error: null,
127640
+ command: baseCommand,
127641
+ args: commandArgs,
127642
+ fullArgs: args,
127643
+ isComplex: false,
127644
+ original: command
127645
+ };
127646
+ }
127647
+ function isComplexCommand(command) {
127648
+ const result = parseSimpleCommand(command);
127649
+ return result.isComplex;
127650
+ }
127651
+ function parseCommand(command) {
127652
+ const result = parseSimpleCommand(command);
127653
+ if (!result.success) {
127654
+ return {
127655
+ command: "",
127656
+ args: [],
127657
+ error: result.error,
127658
+ isComplex: result.isComplex
127659
+ };
127660
+ }
127661
+ return {
127662
+ command: result.command,
127663
+ args: result.args,
127664
+ error: null,
127665
+ isComplex: result.isComplex
127666
+ };
127667
+ }
127668
+ function parseCommandForExecution(command) {
127669
+ const result = parseSimpleCommand(command);
127670
+ if (!result.success) {
127671
+ return null;
127672
+ }
127673
+ return result.fullArgs;
127674
+ }
127675
+ var init_bashCommandUtils = __esm({
127676
+ "src/agent/bashCommandUtils.js"() {
127677
+ "use strict";
127678
+ }
127679
+ });
127680
+
127681
+ // src/agent/bashPermissions.js
127682
+ function matchesPattern(parsedCommand, pattern) {
127683
+ if (!parsedCommand || !pattern) return false;
127684
+ const { command, args } = parsedCommand;
127685
+ if (!command) return false;
127686
+ const patternParts = pattern.split(":");
127687
+ const commandName = patternParts[0];
127688
+ if (commandName === "*") {
127689
+ return true;
127690
+ } else if (commandName !== command) {
127691
+ return false;
127692
+ }
127693
+ if (patternParts.length === 1) {
127694
+ return true;
127695
+ }
127696
+ for (let i3 = 1; i3 < patternParts.length; i3++) {
127697
+ const patternArg = patternParts[i3];
127698
+ const argIndex = i3 - 1;
127699
+ if (patternArg === "*") {
127700
+ continue;
127701
+ }
127702
+ if (argIndex >= args.length) {
127703
+ return false;
127704
+ }
127705
+ const actualArg = args[argIndex];
127706
+ if (patternArg !== actualArg) {
127707
+ return false;
127708
+ }
127709
+ }
127710
+ return true;
127711
+ }
127712
+ function matchesAnyPattern(parsedCommand, patterns) {
127713
+ if (!patterns || patterns.length === 0) return false;
127714
+ return patterns.some((pattern) => matchesPattern(parsedCommand, pattern));
127715
+ }
127716
+ var BashPermissionChecker;
127717
+ var init_bashPermissions = __esm({
127718
+ "src/agent/bashPermissions.js"() {
127719
+ "use strict";
127720
+ init_bashDefaults();
127721
+ init_bashCommandUtils();
127722
+ BashPermissionChecker = class {
127723
+ /**
127724
+ * Create a permission checker
127725
+ * @param {Object} config - Configuration options
127726
+ * @param {string[]} [config.allow] - Additional allow patterns
127727
+ * @param {string[]} [config.deny] - Additional deny patterns
127728
+ * @param {boolean} [config.disableDefaultAllow] - Disable default allow list
127729
+ * @param {boolean} [config.disableDefaultDeny] - Disable default deny list
127730
+ * @param {boolean} [config.debug] - Enable debug logging
127731
+ */
127732
+ constructor(config = {}) {
127733
+ this.debug = config.debug || false;
127734
+ this.allowPatterns = [];
127735
+ if (!config.disableDefaultAllow) {
127736
+ this.allowPatterns.push(...DEFAULT_ALLOW_PATTERNS);
127737
+ if (this.debug) {
127738
+ console.log(`[BashPermissions] Added ${DEFAULT_ALLOW_PATTERNS.length} default allow patterns`);
127739
+ }
127740
+ }
127741
+ if (config.allow && Array.isArray(config.allow)) {
127742
+ this.allowPatterns.push(...config.allow);
127743
+ if (this.debug) {
127744
+ console.log(`[BashPermissions] Added ${config.allow.length} custom allow patterns:`, config.allow);
127745
+ }
127746
+ }
127747
+ this.denyPatterns = [];
127748
+ if (!config.disableDefaultDeny) {
127749
+ this.denyPatterns.push(...DEFAULT_DENY_PATTERNS);
127750
+ if (this.debug) {
127751
+ console.log(`[BashPermissions] Added ${DEFAULT_DENY_PATTERNS.length} default deny patterns`);
127752
+ }
127753
+ }
127754
+ if (config.deny && Array.isArray(config.deny)) {
127755
+ this.denyPatterns.push(...config.deny);
127756
+ if (this.debug) {
127757
+ console.log(`[BashPermissions] Added ${config.deny.length} custom deny patterns:`, config.deny);
127758
+ }
127759
+ }
127760
+ if (this.debug) {
127761
+ console.log(`[BashPermissions] Total patterns - Allow: ${this.allowPatterns.length}, Deny: ${this.denyPatterns.length}`);
127762
+ }
127763
+ }
127764
+ /**
127765
+ * Check if a simple command is allowed (rejects complex commands for security)
127766
+ * @param {string} command - Command to check
127767
+ * @returns {Object} Permission result
127768
+ */
127769
+ check(command) {
127770
+ if (!command || typeof command !== "string") {
127771
+ return {
127772
+ allowed: false,
127773
+ reason: "Invalid or empty command",
127774
+ command
127775
+ };
127776
+ }
127777
+ if (isComplexCommand(command)) {
127778
+ return {
127779
+ allowed: false,
127780
+ reason: "Complex shell commands with pipes, operators, or redirections are not supported for security reasons",
127781
+ command,
127782
+ isComplex: true
127783
+ };
127784
+ }
127785
+ const parsed = parseCommand(command);
127786
+ if (parsed.error) {
127787
+ return {
127788
+ allowed: false,
127789
+ reason: parsed.error,
127790
+ command
127791
+ };
127792
+ }
127793
+ if (!parsed.command) {
127794
+ return {
127795
+ allowed: false,
127796
+ reason: "No valid command found",
127797
+ command
127798
+ };
127799
+ }
127800
+ if (this.debug) {
127801
+ console.log(`[BashPermissions] Checking simple command: "${command}"`);
127802
+ console.log(`[BashPermissions] Parsed: ${parsed.command} with args: [${parsed.args.join(", ")}]`);
127803
+ }
127804
+ if (matchesAnyPattern(parsed, this.denyPatterns)) {
127805
+ const matchedPatterns = this.denyPatterns.filter((pattern) => matchesPattern(parsed, pattern));
127806
+ return {
127807
+ allowed: false,
127808
+ reason: `Command matches deny pattern: ${matchedPatterns[0]}`,
127809
+ command,
127810
+ parsed,
127811
+ matchedPatterns
127812
+ };
127813
+ }
127814
+ if (this.allowPatterns.length > 0) {
127815
+ if (!matchesAnyPattern(parsed, this.allowPatterns)) {
127816
+ return {
127817
+ allowed: false,
127818
+ reason: "Command not in allow list",
127819
+ command,
127820
+ parsed
127821
+ };
127822
+ }
127823
+ }
127824
+ const result = {
127825
+ allowed: true,
127826
+ command,
127827
+ parsed,
127828
+ isComplex: false
127829
+ };
127830
+ if (this.debug) {
127831
+ console.log(`[BashPermissions] ALLOWED - command passed all checks`);
127832
+ }
127833
+ return result;
127834
+ }
127835
+ /**
127836
+ * Get configuration summary
127837
+ * @returns {Object} Configuration info
127838
+ */
127839
+ getConfig() {
127840
+ return {
127841
+ allowPatterns: this.allowPatterns.length,
127842
+ denyPatterns: this.denyPatterns.length,
127843
+ totalPatterns: this.allowPatterns.length + this.denyPatterns.length
127844
+ };
127845
+ }
127846
+ };
127847
+ }
127848
+ });
127849
+
127850
+ // src/agent/bashExecutor.js
127851
+ async function executeBashCommand(command, options = {}) {
127852
+ const {
127853
+ workingDirectory = process.cwd(),
127854
+ timeout = 12e4,
127855
+ // 2 minutes default
127856
+ env = {},
127857
+ maxBuffer = 10 * 1024 * 1024,
127858
+ // 10MB
127859
+ debug = false
127860
+ } = options;
127861
+ let cwd = workingDirectory;
127862
+ try {
127863
+ cwd = (0, import_path4.resolve)(cwd);
127864
+ if (!(0, import_fs.existsSync)(cwd)) {
127865
+ throw new Error(`Working directory does not exist: ${cwd}`);
127866
+ }
127867
+ } catch (error2) {
127868
+ return {
127869
+ success: false,
127870
+ error: `Invalid working directory: ${error2.message}`,
127871
+ stdout: "",
127872
+ stderr: "",
127873
+ exitCode: 1,
127874
+ command,
127875
+ workingDirectory: cwd,
127876
+ duration: 0
127877
+ };
127878
+ }
127879
+ const startTime = Date.now();
127880
+ if (debug) {
127881
+ console.log(`[BashExecutor] Executing command: "${command}"`);
127882
+ console.log(`[BashExecutor] Working directory: "${cwd}"`);
127883
+ console.log(`[BashExecutor] Timeout: ${timeout}ms`);
127884
+ }
127885
+ return new Promise((resolve4, reject) => {
127886
+ const processEnv = {
127887
+ ...process.env,
127888
+ ...env
127889
+ };
127890
+ const args = parseCommandForExecution(command);
127891
+ if (!args || args.length === 0) {
127892
+ resolve4({
127893
+ success: false,
127894
+ error: "Failed to parse command",
127895
+ stdout: "",
127896
+ stderr: "",
127897
+ exitCode: 1,
127898
+ command,
127899
+ workingDirectory: cwd,
127900
+ duration: Date.now() - startTime
127901
+ });
127902
+ return;
127903
+ }
127904
+ const [cmd, ...cmdArgs] = args;
127905
+ const child = (0, import_child_process6.spawn)(cmd, cmdArgs, {
127906
+ cwd,
127907
+ env: processEnv,
127908
+ stdio: ["ignore", "pipe", "pipe"],
127909
+ // stdin ignored, capture stdout/stderr
127910
+ shell: false,
127911
+ // For security
127912
+ windowsHide: true
127913
+ });
127914
+ let stdout = "";
127915
+ let stderr = "";
127916
+ let killed = false;
127917
+ let timeoutHandle;
127918
+ if (timeout > 0) {
127919
+ timeoutHandle = setTimeout(() => {
127920
+ if (!killed) {
127921
+ killed = true;
127922
+ child.kill("SIGTERM");
127923
+ setTimeout(() => {
127924
+ if (child.exitCode === null) {
127925
+ child.kill("SIGKILL");
127926
+ }
127927
+ }, 5e3);
127928
+ }
127929
+ }, timeout);
127930
+ }
127931
+ child.stdout.on("data", (data2) => {
127932
+ const chunk = data2.toString();
127933
+ if (stdout.length + chunk.length <= maxBuffer) {
127934
+ stdout += chunk;
127935
+ } else {
127936
+ if (!killed) {
127937
+ killed = true;
127938
+ child.kill("SIGTERM");
127939
+ }
127940
+ }
127941
+ });
127942
+ child.stderr.on("data", (data2) => {
127943
+ const chunk = data2.toString();
127944
+ if (stderr.length + chunk.length <= maxBuffer) {
127945
+ stderr += chunk;
127946
+ } else {
127947
+ if (!killed) {
127948
+ killed = true;
127949
+ child.kill("SIGTERM");
127950
+ }
127951
+ }
127952
+ });
127953
+ child.on("close", (code, signal) => {
127954
+ if (timeoutHandle) {
127955
+ clearTimeout(timeoutHandle);
127956
+ }
127957
+ const duration = Date.now() - startTime;
127958
+ if (debug) {
127959
+ console.log(`[BashExecutor] Command completed - Code: ${code}, Signal: ${signal}, Duration: ${duration}ms`);
127960
+ console.log(`[BashExecutor] Stdout length: ${stdout.length}, Stderr length: ${stderr.length}`);
127961
+ }
127962
+ let success = true;
127963
+ let error2 = "";
127964
+ if (killed) {
127965
+ success = false;
127966
+ if (stdout.length + stderr.length > maxBuffer) {
127967
+ error2 = `Command output exceeded maximum buffer size (${maxBuffer} bytes)`;
127968
+ } else {
127969
+ error2 = `Command timed out after ${timeout}ms`;
127970
+ }
127971
+ } else if (code !== 0) {
127972
+ success = false;
127973
+ error2 = `Command exited with code ${code}`;
127974
+ }
127975
+ resolve4({
127976
+ success,
127977
+ error: error2,
127978
+ stdout: stdout.trim(),
127979
+ stderr: stderr.trim(),
127980
+ exitCode: code,
127981
+ signal,
127982
+ command,
127983
+ workingDirectory: cwd,
127984
+ duration,
127985
+ killed
127986
+ });
127987
+ });
127988
+ child.on("error", (error2) => {
127989
+ if (timeoutHandle) {
127990
+ clearTimeout(timeoutHandle);
127991
+ }
127992
+ if (debug) {
127993
+ console.log(`[BashExecutor] Spawn error:`, error2);
127994
+ }
127995
+ resolve4({
127996
+ success: false,
127997
+ error: `Failed to execute command: ${error2.message}`,
127998
+ stdout: "",
127999
+ stderr: "",
128000
+ exitCode: 1,
128001
+ command,
128002
+ workingDirectory: cwd,
128003
+ duration: Date.now() - startTime
128004
+ });
128005
+ });
128006
+ });
128007
+ }
128008
+ function formatExecutionResult(result, includeMetadata = false) {
128009
+ if (!result) {
128010
+ return "No result available";
128011
+ }
128012
+ let output = "";
128013
+ if (includeMetadata) {
128014
+ output += `Command: ${result.command}
128015
+ `;
128016
+ output += `Working directory: ${result.workingDirectory}
128017
+ `;
128018
+ output += `Duration: ${result.duration}ms
128019
+ `;
128020
+ output += `Exit Code: ${result.exitCode}
128021
+ `;
128022
+ if (result.signal) {
128023
+ output += `Signal: ${result.signal}
128024
+ `;
128025
+ }
128026
+ output += "\n";
128027
+ }
128028
+ if (result.stdout) {
128029
+ if (includeMetadata) {
128030
+ output += "--- STDOUT ---\n";
128031
+ }
128032
+ output += result.stdout;
128033
+ if (includeMetadata && result.stderr) {
128034
+ output += "\n";
128035
+ }
128036
+ }
128037
+ if (result.stderr) {
128038
+ if (includeMetadata) {
128039
+ if (result.stdout) output += "\n";
128040
+ output += "--- STDERR ---\n";
128041
+ } else if (result.stdout) {
128042
+ output += "\n--- STDERR ---\n";
128043
+ }
128044
+ output += result.stderr;
128045
+ }
128046
+ if (!result.success && result.error && !result.stderr) {
128047
+ if (output) output += "\n";
128048
+ output += `Error: ${result.error}`;
128049
+ }
128050
+ if (!result.success && result.exitCode !== void 0 && result.exitCode !== 0) {
128051
+ if (output) output += "\n";
128052
+ output += `Exit code: ${result.exitCode}`;
128053
+ }
128054
+ return output || (result.success ? "Command completed successfully (no output)" : "Command failed (no output)");
128055
+ }
128056
+ function validateExecutionOptions(options = {}) {
128057
+ const errors = [];
128058
+ const warnings = [];
128059
+ if (options.timeout !== void 0) {
128060
+ if (typeof options.timeout !== "number" || options.timeout < 0) {
128061
+ errors.push("timeout must be a non-negative number");
128062
+ } else if (options.timeout > 6e5) {
128063
+ warnings.push("timeout is very high (>10 minutes)");
128064
+ }
128065
+ }
128066
+ if (options.maxBuffer !== void 0) {
128067
+ if (typeof options.maxBuffer !== "number" || options.maxBuffer < 1024) {
128068
+ errors.push("maxBuffer must be at least 1024 bytes");
128069
+ } else if (options.maxBuffer > 100 * 1024 * 1024) {
128070
+ warnings.push("maxBuffer is very high (>100MB)");
128071
+ }
128072
+ }
128073
+ if (options.workingDirectory) {
128074
+ if (typeof options.workingDirectory !== "string") {
128075
+ errors.push("workingDirectory must be a string");
128076
+ } else if (!(0, import_fs.existsSync)(options.workingDirectory)) {
128077
+ errors.push(`workingDirectory does not exist: ${options.workingDirectory}`);
128078
+ }
128079
+ }
128080
+ if (options.env && typeof options.env !== "object") {
128081
+ errors.push("env must be an object");
128082
+ }
128083
+ return {
128084
+ valid: errors.length === 0,
128085
+ errors,
128086
+ warnings
128087
+ };
128088
+ }
128089
+ var import_child_process6, import_path4, import_fs;
128090
+ var init_bashExecutor = __esm({
128091
+ "src/agent/bashExecutor.js"() {
128092
+ "use strict";
128093
+ import_child_process6 = __nccwpck_require__(35317);
128094
+ import_path4 = __nccwpck_require__(16928);
128095
+ import_fs = __nccwpck_require__(79896);
128096
+ init_bashCommandUtils();
128097
+ }
128098
+ });
128099
+
128100
+ // src/tools/bash.js
128101
+ var import_ai2, import_path5, bashTool;
128102
+ var init_bash = __esm({
128103
+ "src/tools/bash.js"() {
128104
+ "use strict";
128105
+ import_ai2 = __nccwpck_require__(86619);
128106
+ import_path5 = __nccwpck_require__(16928);
128107
+ init_bashPermissions();
128108
+ init_bashExecutor();
128109
+ bashTool = (options = {}) => {
128110
+ const {
128111
+ bashConfig = {},
128112
+ debug = false,
128113
+ defaultPath,
128114
+ allowedFolders = []
128115
+ } = options;
128116
+ const permissionChecker = new BashPermissionChecker({
128117
+ allow: bashConfig.allow,
128118
+ deny: bashConfig.deny,
128119
+ disableDefaultAllow: bashConfig.disableDefaultAllow,
128120
+ disableDefaultDeny: bashConfig.disableDefaultDeny,
128121
+ debug
128122
+ });
128123
+ const getDefaultWorkingDirectory = () => {
128124
+ if (bashConfig.workingDirectory) {
128125
+ return bashConfig.workingDirectory;
128126
+ }
128127
+ if (defaultPath) {
128128
+ return defaultPath;
128129
+ }
128130
+ if (allowedFolders && allowedFolders.length > 0) {
128131
+ return allowedFolders[0];
128132
+ }
128133
+ return process.cwd();
128134
+ };
128135
+ return (0, import_ai2.tool)({
128136
+ name: "bash",
128137
+ description: `Execute bash commands for system exploration and development tasks.
128138
+
128139
+ Security: This tool has built-in security with allow/deny lists. By default, only safe read-only commands are allowed for code exploration.
128140
+
128141
+ Parameters:
128142
+ - command: (required) The bash command to execute
128143
+ - workingDirectory: (optional) Directory to execute command in
128144
+ - timeout: (optional) Command timeout in milliseconds
128145
+ - env: (optional) Additional environment variables
128146
+
128147
+ Examples of allowed commands by default:
128148
+ - File exploration: ls, cat, head, tail, find, grep
128149
+ - Git operations: git status, git log, git diff, git show
128150
+ - Package info: npm list, pip list, cargo --version
128151
+ - System info: whoami, pwd, uname, date
128152
+
128153
+ Dangerous commands are blocked by default (rm -rf, sudo, npm install, etc.)`,
128154
+ inputSchema: {
128155
+ type: "object",
128156
+ properties: {
128157
+ command: {
128158
+ type: "string",
128159
+ description: "The bash command to execute"
128160
+ },
128161
+ workingDirectory: {
128162
+ type: "string",
128163
+ description: "Directory to execute the command in (optional)"
128164
+ },
128165
+ timeout: {
128166
+ type: "number",
128167
+ description: "Command timeout in milliseconds (optional)",
128168
+ minimum: 1e3,
128169
+ maximum: 6e5
128170
+ },
128171
+ env: {
128172
+ type: "object",
128173
+ description: "Additional environment variables (optional)",
128174
+ additionalProperties: {
128175
+ type: "string"
128176
+ }
128177
+ }
128178
+ },
128179
+ required: ["command"],
128180
+ additionalProperties: false
128181
+ },
128182
+ execute: async ({ command, workingDirectory, timeout, env }) => {
128183
+ try {
128184
+ if (command === null || command === void 0 || typeof command !== "string") {
128185
+ return "Error: Command is required and must be a string";
128186
+ }
128187
+ if (command.trim().length === 0) {
128188
+ return "Error: Command cannot be empty";
128189
+ }
128190
+ const permissionResult = permissionChecker.check(command.trim());
128191
+ if (!permissionResult.allowed) {
128192
+ if (debug) {
128193
+ console.log(`[BashTool] Permission denied for command: "${command}"`);
128194
+ console.log(`[BashTool] Reason: ${permissionResult.reason}`);
128195
+ }
128196
+ return `Permission denied: ${permissionResult.reason}
128197
+
128198
+ This command is not allowed by the current security policy.
128199
+
128200
+ Common reasons:
128201
+ 1. The command is in the deny list (potentially dangerous)
128202
+ 2. The command is not in the allow list (not a recognized safe command)
128203
+
128204
+ If you believe this command should be allowed, you can:
128205
+ - Use the --bash-allow option to add specific patterns
128206
+ - Use the --no-default-bash-deny flag to remove default restrictions (not recommended)
128207
+
128208
+ For code exploration, try these safe alternatives:
128209
+ - ls, cat, head, tail for file operations
128210
+ - find, grep, rg for searching
128211
+ - git status, git log, git show for git operations
128212
+ - npm list, pip list for package information`;
128213
+ }
128214
+ const workingDir = workingDirectory || getDefaultWorkingDirectory();
128215
+ if (allowedFolders && allowedFolders.length > 0) {
128216
+ const resolvedWorkingDir = (0, import_path5.resolve)(workingDir);
128217
+ const isAllowed = allowedFolders.some((folder) => {
128218
+ const resolvedFolder = (0, import_path5.resolve)(folder);
128219
+ return resolvedWorkingDir.startsWith(resolvedFolder);
128220
+ });
128221
+ if (!isAllowed) {
128222
+ return `Error: Working directory "${workingDir}" is not within allowed folders: ${allowedFolders.join(", ")}`;
128223
+ }
128224
+ }
128225
+ const executionOptions = {
128226
+ workingDirectory: workingDir,
128227
+ timeout: timeout || bashConfig.timeout || 12e4,
128228
+ env: { ...bashConfig.env, ...env },
128229
+ maxBuffer: bashConfig.maxBuffer,
128230
+ debug
128231
+ };
128232
+ const validation = validateExecutionOptions(executionOptions);
128233
+ if (!validation.valid) {
128234
+ return `Error: Invalid execution options: ${validation.errors.join(", ")}`;
128235
+ }
128236
+ if (validation.warnings.length > 0 && debug) {
128237
+ console.log("[BashTool] Warnings:", validation.warnings);
128238
+ }
128239
+ if (debug) {
128240
+ console.log(`[BashTool] Executing command: "${command}"`);
128241
+ console.log(`[BashTool] Working directory: "${workingDir}"`);
128242
+ console.log(`[BashTool] Timeout: ${executionOptions.timeout}ms`);
128243
+ }
128244
+ const result = await executeBashCommand(command.trim(), executionOptions);
128245
+ if (debug) {
128246
+ console.log(`[BashTool] Command completed - Success: ${result.success}, Duration: ${result.duration}ms`);
128247
+ }
128248
+ const formattedResult = formatExecutionResult(result, debug);
128249
+ if (!result.success) {
128250
+ let errorInfo = `
128251
+
128252
+ Command failed with exit code ${result.exitCode}`;
128253
+ if (result.killed) {
128254
+ errorInfo += ` (${result.error})`;
128255
+ }
128256
+ return formattedResult + errorInfo;
128257
+ }
128258
+ return formattedResult;
128259
+ } catch (error2) {
128260
+ if (debug) {
128261
+ console.error("[BashTool] Execution error:", error2);
128262
+ }
128263
+ return `Error executing bash command: ${error2.message}`;
128264
+ }
128265
+ }
128266
+ });
128267
+ };
128268
+ }
128269
+ });
128270
+
126531
128271
  // src/tools/langchain.js
126532
128272
  function createSearchTool() {
126533
128273
  return {
@@ -126745,6 +128485,10 @@ __export(tools_exports, {
126745
128485
  DEFAULT_SYSTEM_MESSAGE: () => DEFAULT_SYSTEM_MESSAGE,
126746
128486
  attemptCompletionSchema: () => attemptCompletionSchema,
126747
128487
  attemptCompletionToolDefinition: () => attemptCompletionToolDefinition,
128488
+ bashDescription: () => bashDescription,
128489
+ bashSchema: () => bashSchema,
128490
+ bashTool: () => bashTool,
128491
+ bashToolDefinition: () => bashToolDefinition,
126748
128492
  createExtractTool: () => createExtractTool,
126749
128493
  createQueryTool: () => createQueryTool,
126750
128494
  createSearchTool: () => createSearchTool,
@@ -126765,16 +128509,19 @@ var init_tools = __esm({
126765
128509
  "src/tools/index.js"() {
126766
128510
  "use strict";
126767
128511
  init_vercel();
128512
+ init_bash();
126768
128513
  init_langchain();
126769
128514
  init_common();
126770
128515
  init_system_message();
126771
128516
  init_vercel();
128517
+ init_bash();
126772
128518
  init_system_message();
126773
128519
  tools = {
126774
128520
  searchTool: searchTool(),
126775
128521
  queryTool: queryTool(),
126776
128522
  extractTool: extractTool(),
126777
128523
  delegateTool: delegateTool(),
128524
+ bashTool: bashTool(),
126778
128525
  DEFAULT_SYSTEM_MESSAGE
126779
128526
  };
126780
128527
  }
@@ -126787,10 +128534,10 @@ async function listFilesByLevel(options) {
126787
128534
  maxFiles = 100,
126788
128535
  respectGitignore = true
126789
128536
  } = options;
126790
- if (!import_fs.default.existsSync(directory)) {
128537
+ if (!import_fs2.default.existsSync(directory)) {
126791
128538
  throw new Error(`Directory does not exist: ${directory}`);
126792
128539
  }
126793
- const gitDirExists = import_fs.default.existsSync(import_path4.default.join(directory, ".git"));
128540
+ const gitDirExists = import_fs2.default.existsSync(import_path6.default.join(directory, ".git"));
126794
128541
  if (gitDirExists && respectGitignore) {
126795
128542
  try {
126796
128543
  return await listFilesUsingGit(directory, maxFiles);
@@ -126805,8 +128552,8 @@ async function listFilesUsingGit(directory, maxFiles) {
126805
128552
  const { stdout } = await execAsync4("git ls-files", { cwd: directory });
126806
128553
  const files = stdout.split("\n").filter(Boolean);
126807
128554
  const sortedFiles = files.sort((a3, b3) => {
126808
- const depthA = a3.split(import_path4.default.sep).length;
126809
- const depthB = b3.split(import_path4.default.sep).length;
128555
+ const depthA = a3.split(import_path6.default.sep).length;
128556
+ const depthB = b3.split(import_path6.default.sep).length;
126810
128557
  return depthA - depthB;
126811
128558
  });
126812
128559
  return sortedFiles.slice(0, maxFiles);
@@ -126821,19 +128568,19 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
126821
128568
  while (queue.length > 0 && result.length < maxFiles) {
126822
128569
  const { dir, level } = queue.shift();
126823
128570
  try {
126824
- const entries = import_fs.default.readdirSync(dir, { withFileTypes: true });
128571
+ const entries = import_fs2.default.readdirSync(dir, { withFileTypes: true });
126825
128572
  const files = entries.filter((entry) => entry.isFile());
126826
128573
  for (const file of files) {
126827
128574
  if (result.length >= maxFiles) break;
126828
- const filePath = import_path4.default.join(dir, file.name);
126829
- const relativePath = import_path4.default.relative(directory, filePath);
128575
+ const filePath = import_path6.default.join(dir, file.name);
128576
+ const relativePath = import_path6.default.relative(directory, filePath);
126830
128577
  if (shouldIgnore(relativePath, ignorePatterns)) continue;
126831
128578
  result.push(relativePath);
126832
128579
  }
126833
128580
  const dirs = entries.filter((entry) => entry.isDirectory());
126834
128581
  for (const subdir of dirs) {
126835
- const subdirPath = import_path4.default.join(dir, subdir.name);
126836
- const relativeSubdirPath = import_path4.default.relative(directory, subdirPath);
128582
+ const subdirPath = import_path6.default.join(dir, subdir.name);
128583
+ const relativeSubdirPath = import_path6.default.relative(directory, subdirPath);
126837
128584
  if (shouldIgnore(relativeSubdirPath, ignorePatterns)) continue;
126838
128585
  if (subdir.name === "node_modules" || subdir.name === ".git") continue;
126839
128586
  queue.push({ dir: subdirPath, level: level + 1 });
@@ -126845,12 +128592,12 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
126845
128592
  return result;
126846
128593
  }
126847
128594
  function loadGitignorePatterns(directory) {
126848
- const gitignorePath = import_path4.default.join(directory, ".gitignore");
126849
- if (!import_fs.default.existsSync(gitignorePath)) {
128595
+ const gitignorePath = import_path6.default.join(directory, ".gitignore");
128596
+ if (!import_fs2.default.existsSync(gitignorePath)) {
126850
128597
  return [];
126851
128598
  }
126852
128599
  try {
126853
- const content = import_fs.default.readFileSync(gitignorePath, "utf8");
128600
+ const content = import_fs2.default.readFileSync(gitignorePath, "utf8");
126854
128601
  return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
126855
128602
  } catch (error2) {
126856
128603
  console.error(`Warning: Could not read .gitignore: ${error2.message}`);
@@ -126868,15 +128615,15 @@ function shouldIgnore(filePath, ignorePatterns) {
126868
128615
  }
126869
128616
  return false;
126870
128617
  }
126871
- var import_fs, import_path4, import_util5, import_child_process6, execAsync4;
128618
+ var import_fs2, import_path6, import_util5, import_child_process7, execAsync4;
126872
128619
  var init_file_lister = __esm({
126873
128620
  "src/utils/file-lister.js"() {
126874
128621
  "use strict";
126875
- import_fs = __toESM(__nccwpck_require__(79896), 1);
126876
- import_path4 = __toESM(__nccwpck_require__(16928), 1);
128622
+ import_fs2 = __toESM(__nccwpck_require__(79896), 1);
128623
+ import_path6 = __toESM(__nccwpck_require__(16928), 1);
126877
128624
  import_util5 = __nccwpck_require__(39023);
126878
- import_child_process6 = __nccwpck_require__(35317);
126879
- execAsync4 = (0, import_util5.promisify)(import_child_process6.exec);
128625
+ import_child_process7 = __nccwpck_require__(35317);
128626
+ execAsync4 = (0, import_util5.promisify)(import_child_process7.exec);
126880
128627
  }
126881
128628
  });
126882
128629
 
@@ -129031,7 +130778,7 @@ var require_headStream = __commonJS({
129031
130778
  if ((0, stream_type_check_1.isReadableStream)(stream)) {
129032
130779
  return (0, headStream_browser_1.headStream)(stream, bytes);
129033
130780
  }
129034
- return new Promise((resolve2, reject) => {
130781
+ return new Promise((resolve4, reject) => {
129035
130782
  const collector = new Collector();
129036
130783
  collector.limit = bytes;
129037
130784
  stream.pipe(collector);
@@ -129042,7 +130789,7 @@ var require_headStream = __commonJS({
129042
130789
  collector.on("error", reject);
129043
130790
  collector.on("finish", function() {
129044
130791
  const bytes2 = new Uint8Array(Buffer.concat(this.buffers));
129045
- resolve2(bytes2);
130792
+ resolve4(bytes2);
129046
130793
  });
129047
130794
  });
129048
130795
  };
@@ -129300,21 +131047,21 @@ var require_dist_cjs15 = __commonJS({
129300
131047
  let sendBody = true;
129301
131048
  if (expect === "100-continue") {
129302
131049
  sendBody = await Promise.race([
129303
- new Promise((resolve2) => {
129304
- timeoutId = Number(timing.setTimeout(() => resolve2(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
131050
+ new Promise((resolve4) => {
131051
+ timeoutId = Number(timing.setTimeout(() => resolve4(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
129305
131052
  }),
129306
- new Promise((resolve2) => {
131053
+ new Promise((resolve4) => {
129307
131054
  httpRequest.on("continue", () => {
129308
131055
  timing.clearTimeout(timeoutId);
129309
- resolve2(true);
131056
+ resolve4(true);
129310
131057
  });
129311
131058
  httpRequest.on("response", () => {
129312
131059
  timing.clearTimeout(timeoutId);
129313
- resolve2(false);
131060
+ resolve4(false);
129314
131061
  });
129315
131062
  httpRequest.on("error", () => {
129316
131063
  timing.clearTimeout(timeoutId);
129317
- resolve2(false);
131064
+ resolve4(false);
129318
131065
  });
129319
131066
  })
129320
131067
  ]);
@@ -129350,13 +131097,13 @@ var require_dist_cjs15 = __commonJS({
129350
131097
  constructor(options) {
129351
131098
  this.socketWarningTimestamp = 0;
129352
131099
  this.metadata = { handlerProtocol: "http/1.1" };
129353
- this.configProvider = new Promise((resolve2, reject) => {
131100
+ this.configProvider = new Promise((resolve4, reject) => {
129354
131101
  if (typeof options === "function") {
129355
131102
  options().then((_options) => {
129356
- resolve2(this.resolveDefaultConfig(_options));
131103
+ resolve4(this.resolveDefaultConfig(_options));
129357
131104
  }).catch(reject);
129358
131105
  } else {
129359
- resolve2(this.resolveDefaultConfig(options));
131106
+ resolve4(this.resolveDefaultConfig(options));
129360
131107
  }
129361
131108
  });
129362
131109
  }
@@ -129440,7 +131187,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
129440
131187
  return new Promise((_resolve, _reject) => {
129441
131188
  let writeRequestBodyPromise = void 0;
129442
131189
  const timeouts = [];
129443
- const resolve2 = /* @__PURE__ */ __name(async (arg) => {
131190
+ const resolve4 = /* @__PURE__ */ __name(async (arg) => {
129444
131191
  await writeRequestBodyPromise;
129445
131192
  timeouts.forEach(timing.clearTimeout);
129446
131193
  _resolve(arg);
@@ -129510,7 +131257,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
129510
131257
  headers: getTransformedHeaders(res.headers),
129511
131258
  body: res
129512
131259
  });
129513
- resolve2({ response: httpResponse });
131260
+ resolve4({ response: httpResponse });
129514
131261
  });
129515
131262
  req.on("error", (err) => {
129516
131263
  if (NODEJS_TIMEOUT_ERROR_CODES.includes(err.code)) {
@@ -129699,13 +131446,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
129699
131446
  constructor(options) {
129700
131447
  this.metadata = { handlerProtocol: "h2" };
129701
131448
  this.connectionManager = new NodeHttp2ConnectionManager({});
129702
- this.configProvider = new Promise((resolve2, reject) => {
131449
+ this.configProvider = new Promise((resolve4, reject) => {
129703
131450
  if (typeof options === "function") {
129704
131451
  options().then((opts) => {
129705
- resolve2(opts || {});
131452
+ resolve4(opts || {});
129706
131453
  }).catch(reject);
129707
131454
  } else {
129708
- resolve2(options || {});
131455
+ resolve4(options || {});
129709
131456
  }
129710
131457
  });
129711
131458
  }
@@ -129738,7 +131485,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
129738
131485
  return new Promise((_resolve, _reject) => {
129739
131486
  let fulfilled = false;
129740
131487
  let writeRequestBodyPromise = void 0;
129741
- const resolve2 = /* @__PURE__ */ __name(async (arg) => {
131488
+ const resolve4 = /* @__PURE__ */ __name(async (arg) => {
129742
131489
  await writeRequestBodyPromise;
129743
131490
  _resolve(arg);
129744
131491
  }, "resolve");
@@ -129794,7 +131541,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
129794
131541
  body: req
129795
131542
  });
129796
131543
  fulfilled = true;
129797
- resolve2({ response: httpResponse });
131544
+ resolve4({ response: httpResponse });
129798
131545
  if (disableConcurrentStreams) {
129799
131546
  session.close();
129800
131547
  this.connectionManager.deleteSession(authority, session);
@@ -129883,7 +131630,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
129883
131630
  if (isReadableStreamInstance(stream)) {
129884
131631
  return collectReadableStream(stream);
129885
131632
  }
129886
- return new Promise((resolve2, reject) => {
131633
+ return new Promise((resolve4, reject) => {
129887
131634
  const collector = new Collector();
129888
131635
  stream.pipe(collector);
129889
131636
  stream.on("error", (err) => {
@@ -129893,7 +131640,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
129893
131640
  collector.on("error", reject);
129894
131641
  collector.on("finish", function() {
129895
131642
  const bytes = new Uint8Array(Buffer.concat(this.bufferedBytes));
129896
- resolve2(bytes);
131643
+ resolve4(bytes);
129897
131644
  });
129898
131645
  });
129899
131646
  }, "streamCollector");
@@ -129958,7 +131705,7 @@ var require_dist_cjs16 = __commonJS({
129958
131705
  }
129959
131706
  __name(createRequest, "createRequest");
129960
131707
  function requestTimeout(timeoutInMs = 0) {
129961
- return new Promise((resolve2, reject) => {
131708
+ return new Promise((resolve4, reject) => {
129962
131709
  if (timeoutInMs) {
129963
131710
  setTimeout(() => {
129964
131711
  const timeoutError = new Error(`Request did not complete within ${timeoutInMs} ms`);
@@ -130085,7 +131832,7 @@ var require_dist_cjs16 = __commonJS({
130085
131832
  ];
130086
131833
  if (abortSignal) {
130087
131834
  raceOfPromises.push(
130088
- new Promise((resolve2, reject) => {
131835
+ new Promise((resolve4, reject) => {
130089
131836
  const onAbort = /* @__PURE__ */ __name(() => {
130090
131837
  const abortError = new Error("Request aborted");
130091
131838
  abortError.name = "AbortError";
@@ -130153,7 +131900,7 @@ var require_dist_cjs16 = __commonJS({
130153
131900
  }
130154
131901
  __name(collectStream, "collectStream");
130155
131902
  function readToBase64(blob) {
130156
- return new Promise((resolve2, reject) => {
131903
+ return new Promise((resolve4, reject) => {
130157
131904
  const reader = new FileReader();
130158
131905
  reader.onloadend = () => {
130159
131906
  if (reader.readyState !== 2) {
@@ -130162,7 +131909,7 @@ var require_dist_cjs16 = __commonJS({
130162
131909
  const result = reader.result ?? "";
130163
131910
  const commaIndex = result.indexOf(",");
130164
131911
  const dataOffset = commaIndex > -1 ? commaIndex + 1 : result.length;
130165
- resolve2(result.substring(dataOffset));
131912
+ resolve4(result.substring(dataOffset));
130166
131913
  };
130167
131914
  reader.onabort = () => reject(new Error("Read aborted"));
130168
131915
  reader.onerror = () => reject(reader.error);
@@ -130649,9 +132396,10 @@ var TypeRegistry;
130649
132396
  var init_TypeRegistry = __esm({
130650
132397
  "node_modules/@smithy/core/dist-es/submodules/schema/TypeRegistry.js"() {
130651
132398
  TypeRegistry = class _TypeRegistry {
130652
- constructor(namespace, schemas = /* @__PURE__ */ new Map()) {
132399
+ constructor(namespace, schemas = /* @__PURE__ */ new Map(), exceptions = /* @__PURE__ */ new Map()) {
130653
132400
  this.namespace = namespace;
130654
132401
  this.schemas = schemas;
132402
+ this.exceptions = exceptions;
130655
132403
  }
130656
132404
  static for(namespace) {
130657
132405
  if (!_TypeRegistry.registries.has(namespace)) {
@@ -130661,8 +132409,7 @@ var init_TypeRegistry = __esm({
130661
132409
  }
130662
132410
  register(shapeId, schema) {
130663
132411
  const qualifiedName = this.normalizeShapeId(shapeId);
130664
- const registry = _TypeRegistry.for(this.getNamespace(shapeId));
130665
- registry.schemas.set(qualifiedName, schema);
132412
+ this.schemas.set(qualifiedName, schema);
130666
132413
  }
130667
132414
  getSchema(shapeId) {
130668
132415
  const id = this.normalizeShapeId(shapeId);
@@ -130671,6 +132418,12 @@ var init_TypeRegistry = __esm({
130671
132418
  }
130672
132419
  return this.schemas.get(id);
130673
132420
  }
132421
+ registerError(errorSchema, ctor) {
132422
+ this.exceptions.set(errorSchema, ctor);
132423
+ }
132424
+ getErrorCtor(errorSchema) {
132425
+ return this.exceptions.get(errorSchema);
132426
+ }
130674
132427
  getBaseException() {
130675
132428
  for (const [id, schema] of this.schemas.entries()) {
130676
132429
  if (id.startsWith("smithy.ts.sdk.synthetic.") && id.endsWith("ServiceException")) {
@@ -130682,9 +132435,9 @@ var init_TypeRegistry = __esm({
130682
132435
  find(predicate) {
130683
132436
  return [...this.schemas.values()].find(predicate);
130684
132437
  }
130685
- destroy() {
130686
- _TypeRegistry.registries.delete(this.namespace);
132438
+ clear() {
130687
132439
  this.schemas.clear();
132440
+ this.exceptions.clear();
130688
132441
  }
130689
132442
  normalizeShapeId(shapeId) {
130690
132443
  if (shapeId.includes("#")) {
@@ -130832,7 +132585,7 @@ var init_ErrorSchema = __esm({
130832
132585
  traits,
130833
132586
  memberNames,
130834
132587
  memberList,
130835
- ctor
132588
+ ctor: null
130836
132589
  });
130837
132590
  }
130838
132591
  });
@@ -131801,11 +133554,11 @@ function __metadata(metadataKey, metadataValue) {
131801
133554
  }
131802
133555
  function __awaiter(thisArg, _arguments, P, generator) {
131803
133556
  function adopt(value) {
131804
- return value instanceof P ? value : new P(function(resolve2) {
131805
- resolve2(value);
133557
+ return value instanceof P ? value : new P(function(resolve4) {
133558
+ resolve4(value);
131806
133559
  });
131807
133560
  }
131808
- return new (P || (P = Promise))(function(resolve2, reject) {
133561
+ return new (P || (P = Promise))(function(resolve4, reject) {
131809
133562
  function fulfilled(value) {
131810
133563
  try {
131811
133564
  step(generator.next(value));
@@ -131821,7 +133574,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
131821
133574
  }
131822
133575
  }
131823
133576
  function step(result) {
131824
- result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected);
133577
+ result.done ? resolve4(result.value) : adopt(result.value).then(fulfilled, rejected);
131825
133578
  }
131826
133579
  step((generator = generator.apply(thisArg, _arguments || [])).next());
131827
133580
  });
@@ -132012,14 +133765,14 @@ function __asyncValues(o3) {
132012
133765
  }, i3);
132013
133766
  function verb(n3) {
132014
133767
  i3[n3] = o3[n3] && function(v3) {
132015
- return new Promise(function(resolve2, reject) {
132016
- v3 = o3[n3](v3), settle(resolve2, reject, v3.done, v3.value);
133768
+ return new Promise(function(resolve4, reject) {
133769
+ v3 = o3[n3](v3), settle(resolve4, reject, v3.done, v3.value);
132017
133770
  });
132018
133771
  };
132019
133772
  }
132020
- function settle(resolve2, reject, d3, v3) {
133773
+ function settle(resolve4, reject, d3, v3) {
132021
133774
  Promise.resolve(v3).then(function(v4) {
132022
- resolve2({ value: v4, done: d3 });
133775
+ resolve4({ value: v4, done: d3 });
132023
133776
  }, reject);
132024
133777
  }
132025
133778
  }
@@ -136990,16 +138743,18 @@ var init_SmithyRpcV2CborProtocol = __esm({
136990
138743
  if (dataObject.Message) {
136991
138744
  dataObject.message = dataObject.Message;
136992
138745
  }
136993
- const baseExceptionSchema = TypeRegistry.for("smithy.ts.sdk.synthetic." + namespace).getBaseException();
138746
+ const synthetic = TypeRegistry.for("smithy.ts.sdk.synthetic." + namespace);
138747
+ const baseExceptionSchema = synthetic.getBaseException();
136994
138748
  if (baseExceptionSchema) {
136995
- const ErrorCtor = baseExceptionSchema.ctor;
136996
- throw Object.assign(new ErrorCtor({ name: errorName }), errorMetadata, dataObject);
138749
+ const ErrorCtor2 = synthetic.getErrorCtor(baseExceptionSchema);
138750
+ throw Object.assign(new ErrorCtor2({ name: errorName }), errorMetadata, dataObject);
136997
138751
  }
136998
138752
  throw Object.assign(new Error(errorName), errorMetadata, dataObject);
136999
138753
  }
137000
138754
  const ns = NormalizedSchema.of(errorSchema);
138755
+ const ErrorCtor = registry.getErrorCtor(errorSchema);
137001
138756
  const message = dataObject.message ?? dataObject.Message ?? "Unknown";
137002
- const exception = new errorSchema.ctor(message);
138757
+ const exception = new ErrorCtor(message);
137003
138758
  const output = {};
137004
138759
  for (const [name14, member] of ns.structIterator()) {
137005
138760
  output[name14] = this.deserializer.readValue(member, dataObject[name14]);
@@ -142665,7 +144420,7 @@ var require_dist_cjs37 = __commonJS({
142665
144420
  );
142666
144421
  }
142667
144422
  waitForReady(socket, connectionTimeout) {
142668
- return new Promise((resolve2, reject) => {
144423
+ return new Promise((resolve4, reject) => {
142669
144424
  const timeout = setTimeout(() => {
142670
144425
  this.removeNotUsableSockets(socket.url);
142671
144426
  reject({
@@ -142676,7 +144431,7 @@ var require_dist_cjs37 = __commonJS({
142676
144431
  }, connectionTimeout);
142677
144432
  socket.onopen = () => {
142678
144433
  clearTimeout(timeout);
142679
- resolve2();
144434
+ resolve4();
142680
144435
  };
142681
144436
  });
142682
144437
  }
@@ -142685,10 +144440,10 @@ var require_dist_cjs37 = __commonJS({
142685
144440
  let socketErrorOccurred = false;
142686
144441
  let reject = /* @__PURE__ */ __name(() => {
142687
144442
  }, "reject");
142688
- let resolve2 = /* @__PURE__ */ __name(() => {
144443
+ let resolve4 = /* @__PURE__ */ __name(() => {
142689
144444
  }, "resolve");
142690
144445
  socket.onmessage = (event) => {
142691
- resolve2({
144446
+ resolve4({
142692
144447
  done: false,
142693
144448
  value: new Uint8Array(event.data)
142694
144449
  });
@@ -142704,7 +144459,7 @@ var require_dist_cjs37 = __commonJS({
142704
144459
  if (streamError) {
142705
144460
  reject(streamError);
142706
144461
  } else {
142707
- resolve2({
144462
+ resolve4({
142708
144463
  done: true,
142709
144464
  value: void 0
142710
144465
  // unchecked because done=true.
@@ -142715,7 +144470,7 @@ var require_dist_cjs37 = __commonJS({
142715
144470
  [Symbol.asyncIterator]: () => ({
142716
144471
  next: /* @__PURE__ */ __name(() => {
142717
144472
  return new Promise((_resolve, _reject) => {
142718
- resolve2 = _resolve;
144473
+ resolve4 = _resolve;
142719
144474
  reject = _reject;
142720
144475
  });
142721
144476
  }, "next")
@@ -143238,13 +144993,13 @@ var require_dist_cjs42 = __commonJS({
143238
144993
  ...data2.default && { default: data2.default }
143239
144994
  }
143240
144995
  ), "getConfigData");
143241
- var import_path9 = __nccwpck_require__(16928);
144996
+ var import_path11 = __nccwpck_require__(16928);
143242
144997
  var import_getHomeDir = require_getHomeDir();
143243
144998
  var ENV_CONFIG_PATH = "AWS_CONFIG_FILE";
143244
- var getConfigFilepath = /* @__PURE__ */ __name(() => process.env[ENV_CONFIG_PATH] || (0, import_path9.join)((0, import_getHomeDir.getHomeDir)(), ".aws", "config"), "getConfigFilepath");
144999
+ var getConfigFilepath = /* @__PURE__ */ __name(() => process.env[ENV_CONFIG_PATH] || (0, import_path11.join)((0, import_getHomeDir.getHomeDir)(), ".aws", "config"), "getConfigFilepath");
143245
145000
  var import_getHomeDir2 = require_getHomeDir();
143246
145001
  var ENV_CREDENTIALS_PATH = "AWS_SHARED_CREDENTIALS_FILE";
143247
- var getCredentialsFilepath = /* @__PURE__ */ __name(() => process.env[ENV_CREDENTIALS_PATH] || (0, import_path9.join)((0, import_getHomeDir2.getHomeDir)(), ".aws", "credentials"), "getCredentialsFilepath");
145002
+ var getCredentialsFilepath = /* @__PURE__ */ __name(() => process.env[ENV_CREDENTIALS_PATH] || (0, import_path11.join)((0, import_getHomeDir2.getHomeDir)(), ".aws", "credentials"), "getCredentialsFilepath");
143248
145003
  var import_getHomeDir3 = require_getHomeDir();
143249
145004
  var prefixKeyRegex = /^([\w-]+)\s(["'])?([\w-@\+\.%:/]+)\2$/;
143250
145005
  var profileNameBlockList = ["__proto__", "profile __proto__"];
@@ -143302,11 +145057,11 @@ var require_dist_cjs42 = __commonJS({
143302
145057
  const relativeHomeDirPrefix = "~/";
143303
145058
  let resolvedFilepath = filepath;
143304
145059
  if (filepath.startsWith(relativeHomeDirPrefix)) {
143305
- resolvedFilepath = (0, import_path9.join)(homeDir, filepath.slice(2));
145060
+ resolvedFilepath = (0, import_path11.join)(homeDir, filepath.slice(2));
143306
145061
  }
143307
145062
  let resolvedConfigFilepath = configFilepath;
143308
145063
  if (configFilepath.startsWith(relativeHomeDirPrefix)) {
143309
- resolvedConfigFilepath = (0, import_path9.join)(homeDir, configFilepath.slice(2));
145064
+ resolvedConfigFilepath = (0, import_path11.join)(homeDir, configFilepath.slice(2));
143310
145065
  }
143311
145066
  const parsedFiles = await Promise.all([
143312
145067
  (0, import_slurpFile.slurpFile)(resolvedConfigFilepath, {
@@ -143961,7 +145716,7 @@ var require_dist_cjs46 = __commonJS({
143961
145716
  this.refillTokenBucket();
143962
145717
  if (amount > this.currentCapacity) {
143963
145718
  const delay = (amount - this.currentCapacity) / this.fillRate * 1e3;
143964
- await new Promise((resolve2) => _DefaultRateLimiter.setTimeoutFn(resolve2, delay));
145719
+ await new Promise((resolve4) => _DefaultRateLimiter.setTimeoutFn(resolve4, delay));
143965
145720
  }
143966
145721
  this.currentCapacity = this.currentCapacity - amount;
143967
145722
  }
@@ -144352,7 +146107,7 @@ var require_dist_cjs47 = __commonJS({
144352
146107
  const delayFromResponse = getDelayFromRetryAfterHeader(err.$response);
144353
146108
  const delay = Math.max(delayFromResponse || 0, delayFromDecider);
144354
146109
  totalDelay += delay;
144355
- await new Promise((resolve2) => setTimeout(resolve2, delay));
146110
+ await new Promise((resolve4) => setTimeout(resolve4, delay));
144356
146111
  continue;
144357
146112
  }
144358
146113
  if (!err.$metadata) {
@@ -144512,7 +146267,7 @@ var require_dist_cjs47 = __commonJS({
144512
146267
  attempts = retryToken.getRetryCount();
144513
146268
  const delay = retryToken.getRetryDelay();
144514
146269
  totalRetryDelay += delay;
144515
- await new Promise((resolve2) => setTimeout(resolve2, delay));
146270
+ await new Promise((resolve4) => setTimeout(resolve4, delay));
144516
146271
  }
144517
146272
  }
144518
146273
  } else {
@@ -144855,7 +146610,7 @@ var require_dist_cjs49 = __commonJS({
144855
146610
  var import_buffer = __nccwpck_require__(20181);
144856
146611
  var import_http = __nccwpck_require__(58611);
144857
146612
  function httpRequest(options) {
144858
- return new Promise((resolve2, reject) => {
146613
+ return new Promise((resolve4, reject) => {
144859
146614
  const req = (0, import_http.request)({
144860
146615
  method: "GET",
144861
146616
  ...options,
@@ -144884,7 +146639,7 @@ var require_dist_cjs49 = __commonJS({
144884
146639
  chunks.push(chunk);
144885
146640
  });
144886
146641
  res.on("end", () => {
144887
- resolve2(import_buffer.Buffer.concat(chunks));
146642
+ resolve4(import_buffer.Buffer.concat(chunks));
144888
146643
  req.destroy();
144889
146644
  });
144890
146645
  });
@@ -145319,7 +147074,7 @@ var require_retry_wrapper = __commonJS({
145319
147074
  try {
145320
147075
  return await toRetry();
145321
147076
  } catch (e3) {
145322
- await new Promise((resolve2) => setTimeout(resolve2, delayMs));
147077
+ await new Promise((resolve4) => setTimeout(resolve4, delayMs));
145323
147078
  }
145324
147079
  }
145325
147080
  return await toRetry();
@@ -145763,7 +147518,7 @@ var require_dist_cjs53 = __commonJS({
145763
147518
  calculateBodyLength: () => calculateBodyLength3
145764
147519
  });
145765
147520
  module2.exports = __toCommonJS2(index_exports2);
145766
- var import_fs7 = __nccwpck_require__(79896);
147521
+ var import_fs8 = __nccwpck_require__(79896);
145767
147522
  var calculateBodyLength3 = /* @__PURE__ */ __name((body) => {
145768
147523
  if (!body) {
145769
147524
  return 0;
@@ -145777,9 +147532,9 @@ var require_dist_cjs53 = __commonJS({
145777
147532
  } else if (typeof body.start === "number" && typeof body.end === "number") {
145778
147533
  return body.end + 1 - body.start;
145779
147534
  } else if (typeof body.path === "string" || Buffer.isBuffer(body.path)) {
145780
- return (0, import_fs7.lstatSync)(body.path).size;
147535
+ return (0, import_fs8.lstatSync)(body.path).size;
145781
147536
  } else if (typeof body.fd === "number") {
145782
- return (0, import_fs7.fstatSync)(body.fd).size;
147537
+ return (0, import_fs8.fstatSync)(body.fd).size;
145783
147538
  }
145784
147539
  throw new Error(`Body Length computation failed for ${body}`);
145785
147540
  }, "calculateBodyLength");
@@ -147817,8 +149572,8 @@ var require_dist_cjs57 = __commonJS({
147817
149572
  }
147818
149573
  }, "validateTokenKey");
147819
149574
  var import_shared_ini_file_loader = require_dist_cjs42();
147820
- var import_fs7 = __nccwpck_require__(79896);
147821
- var { writeFile } = import_fs7.promises;
149575
+ var import_fs8 = __nccwpck_require__(79896);
149576
+ var { writeFile } = import_fs8.promises;
147822
149577
  var writeSSOTokenToFile = /* @__PURE__ */ __name((id, ssoToken) => {
147823
149578
  const tokenFilepath = (0, import_shared_ini_file_loader.getSSOTokenFilepath)(id);
147824
149579
  const tokenString = JSON.stringify(ssoToken, null, 2);
@@ -149460,7 +151215,7 @@ var require_dist_cjs59 = __commonJS({
149460
151215
  module2.exports = __toCommonJS2(index_exports2);
149461
151216
  var import_property_provider2 = require_dist_cjs24();
149462
151217
  var import_shared_ini_file_loader = require_dist_cjs42();
149463
- var import_child_process8 = __nccwpck_require__(35317);
151218
+ var import_child_process9 = __nccwpck_require__(35317);
149464
151219
  var import_util7 = __nccwpck_require__(39023);
149465
151220
  var import_client7 = (init_client(), __toCommonJS(client_exports));
149466
151221
  var getValidatedProcessCredentials = /* @__PURE__ */ __name((profileName, data2, profiles) => {
@@ -149497,7 +151252,7 @@ var require_dist_cjs59 = __commonJS({
149497
151252
  if (profiles[profileName]) {
149498
151253
  const credentialProcess = profile["credential_process"];
149499
151254
  if (credentialProcess !== void 0) {
149500
- const execPromise = (0, import_util7.promisify)(import_shared_ini_file_loader.externalDataInterceptor?.getTokenRecord?.().exec ?? import_child_process8.exec);
151255
+ const execPromise = (0, import_util7.promisify)(import_shared_ini_file_loader.externalDataInterceptor?.getTokenRecord?.().exec ?? import_child_process9.exec);
149501
151256
  try {
149502
151257
  const { stdout } = await execPromise(credentialProcess);
149503
151258
  let data2;
@@ -150236,7 +151991,7 @@ var require_dist_cjs64 = __commonJS({
150236
151991
  streamEnded = true;
150237
151992
  });
150238
151993
  while (!generationEnded) {
150239
- const value = await new Promise((resolve2) => setTimeout(() => resolve2(records.shift()), 0));
151994
+ const value = await new Promise((resolve4) => setTimeout(() => resolve4(records.shift()), 0));
150240
151995
  if (value) {
150241
151996
  yield value;
150242
151997
  }
@@ -153613,16 +155368,16 @@ function prepareTools(mode) {
153613
155368
  }
153614
155369
  const toolWarnings = [];
153615
155370
  const bedrockTools = [];
153616
- for (const tool2 of tools2) {
153617
- if (tool2.type === "provider-defined") {
153618
- toolWarnings.push({ type: "unsupported-tool", tool: tool2 });
155371
+ for (const tool3 of tools2) {
155372
+ if (tool3.type === "provider-defined") {
155373
+ toolWarnings.push({ type: "unsupported-tool", tool: tool3 });
153619
155374
  } else {
153620
155375
  bedrockTools.push({
153621
155376
  toolSpec: {
153622
- name: tool2.name,
153623
- description: tool2.description,
155377
+ name: tool3.name,
155378
+ description: tool3.description,
153624
155379
  inputSchema: {
153625
- json: tool2.parameters
155380
+ json: tool3.parameters
153626
155381
  }
153627
155382
  }
153628
155383
  });
@@ -154633,8 +156388,8 @@ function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
154633
156388
  function hasOtherToolTags(xmlString, validTools = []) {
154634
156389
  const defaultTools = ["search", "query", "extract", "listFiles", "searchFiles", "implement", "attempt_completion"];
154635
156390
  const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
154636
- for (const tool2 of toolsToCheck) {
154637
- if (tool2 !== "attempt_completion" && xmlString.includes(`<${tool2}`)) {
156391
+ for (const tool3 of toolsToCheck) {
156392
+ if (tool3 !== "attempt_completion" && xmlString.includes(`<${tool3}`)) {
154638
156393
  return true;
154639
156394
  }
154640
156395
  }
@@ -154662,12 +156417,16 @@ var init_xmlParsingUtils = __esm({
154662
156417
 
154663
156418
  // src/agent/tools.js
154664
156419
  function createTools(configOptions) {
154665
- return {
156420
+ const tools2 = {
154666
156421
  searchTool: searchTool(configOptions),
154667
156422
  queryTool: queryTool(configOptions),
154668
156423
  extractTool: extractTool(configOptions),
154669
156424
  delegateTool: delegateTool(configOptions)
154670
156425
  };
156426
+ if (configOptions.enableBash) {
156427
+ tools2.bashTool = bashTool(configOptions);
156428
+ }
156429
+ return tools2;
154671
156430
  }
154672
156431
  function parseXmlToolCallWithThinking(xmlString, validTools) {
154673
156432
  const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
@@ -154811,26 +156570,33 @@ function createWrappedTools(baseTools) {
154811
156570
  baseTools.delegateTool.execute
154812
156571
  );
154813
156572
  }
156573
+ if (baseTools.bashTool) {
156574
+ wrappedTools.bashToolInstance = wrapToolWithEmitter(
156575
+ baseTools.bashTool,
156576
+ "bash",
156577
+ baseTools.bashTool.execute
156578
+ );
156579
+ }
154814
156580
  return wrappedTools;
154815
156581
  }
154816
- var import_child_process7, import_util6, import_crypto4, import_events, import_fs2, import_fs3, import_path5, import_glob, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
156582
+ var import_child_process8, import_util6, import_crypto4, import_events, import_fs3, import_fs4, import_path7, import_glob, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
154817
156583
  var init_probeTool = __esm({
154818
156584
  "src/agent/probeTool.js"() {
154819
156585
  "use strict";
154820
156586
  init_index();
154821
- import_child_process7 = __nccwpck_require__(35317);
156587
+ import_child_process8 = __nccwpck_require__(35317);
154822
156588
  import_util6 = __nccwpck_require__(39023);
154823
156589
  import_crypto4 = __nccwpck_require__(76982);
154824
156590
  import_events = __nccwpck_require__(24434);
154825
- import_fs2 = __toESM(__nccwpck_require__(79896), 1);
154826
- import_fs3 = __nccwpck_require__(79896);
154827
- import_path5 = __toESM(__nccwpck_require__(16928), 1);
156591
+ import_fs3 = __toESM(__nccwpck_require__(79896), 1);
156592
+ import_fs4 = __nccwpck_require__(79896);
156593
+ import_path7 = __toESM(__nccwpck_require__(16928), 1);
154828
156594
  import_glob = __nccwpck_require__(21363);
154829
156595
  toolCallEmitter = new import_events.EventEmitter();
154830
156596
  activeToolExecutions = /* @__PURE__ */ new Map();
154831
- wrapToolWithEmitter = (tool2, toolName, baseExecute) => {
156597
+ wrapToolWithEmitter = (tool3, toolName, baseExecute) => {
154832
156598
  return {
154833
- ...tool2,
156599
+ ...tool3,
154834
156600
  // Spread schema, description etc.
154835
156601
  execute: async (params) => {
154836
156602
  const debug = process.env.DEBUG === "1";
@@ -154912,9 +156678,9 @@ var init_probeTool = __esm({
154912
156678
  execute: async (params) => {
154913
156679
  const { directory = ".", workingDirectory } = params;
154914
156680
  const baseCwd = workingDirectory || process.cwd();
154915
- const secureBaseDir = import_path5.default.resolve(baseCwd);
154916
- const targetDir = import_path5.default.resolve(secureBaseDir, directory);
154917
- if (!targetDir.startsWith(secureBaseDir + import_path5.default.sep) && targetDir !== secureBaseDir) {
156681
+ const secureBaseDir = import_path7.default.resolve(baseCwd);
156682
+ const targetDir = import_path7.default.resolve(secureBaseDir, directory);
156683
+ if (!targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
154918
156684
  throw new Error("Path traversal attempt detected. Access denied.");
154919
156685
  }
154920
156686
  try {
@@ -154937,9 +156703,9 @@ var init_probeTool = __esm({
154937
156703
  throw new Error("Pattern is required for file search");
154938
156704
  }
154939
156705
  const baseCwd = workingDirectory || process.cwd();
154940
- const secureBaseDir = import_path5.default.resolve(baseCwd);
154941
- const targetDir = import_path5.default.resolve(secureBaseDir, directory);
154942
- if (!targetDir.startsWith(secureBaseDir + import_path5.default.sep) && targetDir !== secureBaseDir) {
156706
+ const secureBaseDir = import_path7.default.resolve(baseCwd);
156707
+ const targetDir = import_path7.default.resolve(secureBaseDir, directory);
156708
+ if (!targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
154943
156709
  throw new Error("Path traversal attempt detected. Access denied.");
154944
156710
  }
154945
156711
  try {
@@ -154971,7 +156737,7 @@ function createMockProvider() {
154971
156737
  provider: "mock",
154972
156738
  // Mock the doGenerate method used by Vercel AI SDK
154973
156739
  doGenerate: async ({ messages, tools: tools2 }) => {
154974
- await new Promise((resolve2) => setTimeout(resolve2, 10));
156740
+ await new Promise((resolve4) => setTimeout(resolve4, 10));
154975
156741
  return {
154976
156742
  text: "This is a mock response for testing",
154977
156743
  toolCalls: [],
@@ -155546,7 +157312,7 @@ ${decodedContent}
155546
157312
  }
155547
157313
  if (needsQuoting(content)) {
155548
157314
  wasFixed = true;
155549
- const safeContent = content.replace(/"/g, "'");
157315
+ const safeContent = content.replace(/"/g, "&quot;").replace(/'/g, "&#39;");
155550
157316
  return `["${safeContent}"]`;
155551
157317
  }
155552
157318
  return match;
@@ -155559,7 +157325,7 @@ ${decodedContent}
155559
157325
  }
155560
157326
  if (needsQuoting(content)) {
155561
157327
  wasFixed = true;
155562
- const safeContent = content.replace(/"/g, "'");
157328
+ const safeContent = content.replace(/"/g, "&quot;").replace(/'/g, "&#39;");
155563
157329
  return `{"${safeContent}"}`;
155564
157330
  }
155565
157331
  return match;
@@ -155729,7 +157495,7 @@ ${fixedContent}
155729
157495
  }
155730
157496
  if (needsQuoting(content)) {
155731
157497
  wasFixed = true;
155732
- const safeContent = content.replace(/"/g, "'");
157498
+ const safeContent = content.replace(/"/g, "&quot;").replace(/'/g, "&#39;");
155733
157499
  return `["${safeContent}"]`;
155734
157500
  }
155735
157501
  return match;
@@ -155742,7 +157508,7 @@ ${fixedContent}
155742
157508
  }
155743
157509
  if (needsQuoting(content)) {
155744
157510
  wasFixed = true;
155745
- const safeContent = content.replace(/"/g, "'");
157511
+ const safeContent = content.replace(/"/g, "&quot;").replace(/'/g, "&#39;");
155746
157512
  return `{"${safeContent}"}`;
155747
157513
  }
155748
157514
  return match;
@@ -156142,11 +157908,11 @@ function loadMCPConfigurationFromPath(configPath) {
156142
157908
  if (!configPath) {
156143
157909
  throw new Error("Config path is required");
156144
157910
  }
156145
- if (!(0, import_fs4.existsSync)(configPath)) {
157911
+ if (!(0, import_fs5.existsSync)(configPath)) {
156146
157912
  throw new Error(`MCP configuration file not found: ${configPath}`);
156147
157913
  }
156148
157914
  try {
156149
- const content = (0, import_fs4.readFileSync)(configPath, "utf8");
157915
+ const content = (0, import_fs5.readFileSync)(configPath, "utf8");
156150
157916
  const config = JSON.parse(content);
156151
157917
  if (process.env.DEBUG === "1") {
156152
157918
  console.error(`[MCP] Loaded configuration from: ${configPath}`);
@@ -156161,19 +157927,19 @@ function loadMCPConfiguration() {
156161
157927
  // Environment variable path
156162
157928
  process.env.MCP_CONFIG_PATH,
156163
157929
  // Local project paths
156164
- (0, import_path6.join)(process.cwd(), ".mcp", "config.json"),
156165
- (0, import_path6.join)(process.cwd(), "mcp.config.json"),
157930
+ (0, import_path8.join)(process.cwd(), ".mcp", "config.json"),
157931
+ (0, import_path8.join)(process.cwd(), "mcp.config.json"),
156166
157932
  // Home directory paths
156167
- (0, import_path6.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
156168
- (0, import_path6.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
157933
+ (0, import_path8.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
157934
+ (0, import_path8.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
156169
157935
  // Claude-style config location
156170
- (0, import_path6.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
157936
+ (0, import_path8.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
156171
157937
  ].filter(Boolean);
156172
157938
  let config = null;
156173
157939
  for (const configPath of configPaths) {
156174
- if ((0, import_fs4.existsSync)(configPath)) {
157940
+ if ((0, import_fs5.existsSync)(configPath)) {
156175
157941
  try {
156176
- const content = (0, import_fs4.readFileSync)(configPath, "utf8");
157942
+ const content = (0, import_fs5.readFileSync)(configPath, "utf8");
156177
157943
  config = JSON.parse(content);
156178
157944
  if (process.env.DEBUG === "1") {
156179
157945
  console.error(`[MCP] Loaded configuration from: ${configPath}`);
@@ -156269,22 +158035,22 @@ function parseEnabledServers(config) {
156269
158035
  }
156270
158036
  return servers;
156271
158037
  }
156272
- var import_fs4, import_path6, import_os3, import_url4, __filename4, __dirname4, DEFAULT_CONFIG;
158038
+ var import_fs5, import_path8, import_os3, import_url4, __filename4, __dirname4, DEFAULT_CONFIG;
156273
158039
  var init_config = __esm({
156274
158040
  "src/agent/mcp/config.js"() {
156275
158041
  "use strict";
156276
- import_fs4 = __nccwpck_require__(79896);
156277
- import_path6 = __nccwpck_require__(16928);
158042
+ import_fs5 = __nccwpck_require__(79896);
158043
+ import_path8 = __nccwpck_require__(16928);
156278
158044
  import_os3 = __nccwpck_require__(70857);
156279
158045
  import_url4 = __nccwpck_require__(87016);
156280
158046
  __filename4 = (0, import_url4.fileURLToPath)("file:///");
156281
- __dirname4 = (0, import_path6.dirname)(__filename4);
158047
+ __dirname4 = (0, import_path8.dirname)(__filename4);
156282
158048
  DEFAULT_CONFIG = {
156283
158049
  mcpServers: {
156284
158050
  // Example probe server configuration
156285
158051
  "probe-local": {
156286
158052
  command: "node",
156287
- args: [(0, import_path6.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
158053
+ args: [(0, import_path8.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
156288
158054
  transport: "stdio",
156289
158055
  enabled: false
156290
158056
  },
@@ -156441,12 +158207,12 @@ var init_client2 = __esm({
156441
158207
  });
156442
158208
  const toolsResponse = await client.listTools();
156443
158209
  if (toolsResponse && toolsResponse.tools) {
156444
- for (const tool2 of toolsResponse.tools) {
156445
- const qualifiedName = `${name14}_${tool2.name}`;
158210
+ for (const tool3 of toolsResponse.tools) {
158211
+ const qualifiedName = `${name14}_${tool3.name}`;
156446
158212
  this.tools.set(qualifiedName, {
156447
- ...tool2,
158213
+ ...tool3,
156448
158214
  serverName: name14,
156449
- originalName: tool2.name
158215
+ originalName: tool3.name
156450
158216
  });
156451
158217
  if (this.debug) {
156452
158218
  console.error(`[MCP] Registered tool: ${qualifiedName}`);
@@ -156468,20 +158234,20 @@ var init_client2 = __esm({
156468
158234
  * @param {Object} args - Tool arguments
156469
158235
  */
156470
158236
  async callTool(toolName, args) {
156471
- const tool2 = this.tools.get(toolName);
156472
- if (!tool2) {
158237
+ const tool3 = this.tools.get(toolName);
158238
+ if (!tool3) {
156473
158239
  throw new Error(`Unknown tool: ${toolName}`);
156474
158240
  }
156475
- const clientInfo = this.clients.get(tool2.serverName);
158241
+ const clientInfo = this.clients.get(tool3.serverName);
156476
158242
  if (!clientInfo) {
156477
- throw new Error(`Server ${tool2.serverName} not connected`);
158243
+ throw new Error(`Server ${tool3.serverName} not connected`);
156478
158244
  }
156479
158245
  try {
156480
158246
  if (this.debug) {
156481
158247
  console.error(`[MCP] Calling ${toolName} with args:`, args);
156482
158248
  }
156483
158249
  const result = await clientInfo.client.callTool({
156484
- name: tool2.originalName,
158250
+ name: tool3.originalName,
156485
158251
  arguments: args
156486
158252
  });
156487
158253
  return result;
@@ -156496,11 +158262,11 @@ var init_client2 = __esm({
156496
158262
  */
156497
158263
  getTools() {
156498
158264
  const tools2 = {};
156499
- for (const [name14, tool2] of this.tools.entries()) {
158265
+ for (const [name14, tool3] of this.tools.entries()) {
156500
158266
  tools2[name14] = {
156501
- description: tool2.description,
156502
- inputSchema: tool2.inputSchema,
156503
- serverName: tool2.serverName
158267
+ description: tool3.description,
158268
+ inputSchema: tool3.inputSchema,
158269
+ serverName: tool3.serverName
156504
158270
  };
156505
158271
  }
156506
158272
  return tools2;
@@ -156511,10 +158277,10 @@ var init_client2 = __esm({
156511
158277
  */
156512
158278
  getVercelTools() {
156513
158279
  const tools2 = {};
156514
- for (const [name14, tool2] of this.tools.entries()) {
158280
+ for (const [name14, tool3] of this.tools.entries()) {
156515
158281
  tools2[name14] = {
156516
- description: tool2.description,
156517
- inputSchema: tool2.inputSchema,
158282
+ description: tool3.description,
158283
+ inputSchema: tool3.inputSchema,
156518
158284
  execute: async (args) => {
156519
158285
  const result = await this.callTool(name14, args);
156520
158286
  if (result.content && result.content[0]) {
@@ -156551,9 +158317,9 @@ var init_client2 = __esm({
156551
158317
  });
156552
158318
 
156553
158319
  // src/agent/mcp/xmlBridge.js
156554
- function mcpToolToXmlDefinition(name14, tool2) {
156555
- const description = tool2.description || "MCP tool";
156556
- const inputSchema = tool2.inputSchema || tool2.parameters || {};
158320
+ function mcpToolToXmlDefinition(name14, tool3) {
158321
+ const description = tool3.description || "MCP tool";
158322
+ const inputSchema = tool3.inputSchema || tool3.parameters || {};
156557
158323
  let paramDocs = "";
156558
158324
  if (inputSchema.properties) {
156559
158325
  paramDocs = "\n\nParameters (provide as JSON object):";
@@ -156713,8 +158479,8 @@ var init_xmlBridge = __esm({
156713
158479
  const result = await this.mcpManager.initialize(mcpConfigs);
156714
158480
  const vercelTools = this.mcpManager.getVercelTools();
156715
158481
  this.mcpTools = vercelTools;
156716
- for (const [name14, tool2] of Object.entries(vercelTools)) {
156717
- this.xmlDefinitions[name14] = mcpToolToXmlDefinition(name14, tool2);
158482
+ for (const [name14, tool3] of Object.entries(vercelTools)) {
158483
+ this.xmlDefinitions[name14] = mcpToolToXmlDefinition(name14, tool3);
156718
158484
  }
156719
158485
  if (this.debug) {
156720
158486
  console.error(`[MCP] Loaded ${Object.keys(vercelTools).length} MCP tools from ${result.connected} server(s)`);
@@ -156751,12 +158517,12 @@ var init_xmlBridge = __esm({
156751
158517
  if (this.debug) {
156752
158518
  console.error(`[MCP] Executing MCP tool: ${toolName} with params:`, params);
156753
158519
  }
156754
- const tool2 = this.mcpTools[toolName];
156755
- if (!tool2) {
158520
+ const tool3 = this.mcpTools[toolName];
158521
+ if (!tool3) {
156756
158522
  throw new Error(`Unknown MCP tool: ${toolName}`);
156757
158523
  }
156758
158524
  try {
156759
- const result = await tool2.execute(params);
158525
+ const result = await tool3.execute(params);
156760
158526
  return {
156761
158527
  success: true,
156762
158528
  toolName,
@@ -156808,7 +158574,7 @@ var ProbeAgent_exports = {};
156808
158574
  __export(ProbeAgent_exports, {
156809
158575
  ProbeAgent: () => ProbeAgent
156810
158576
  });
156811
- var import_anthropic, import_openai, import_google, import_ai2, import_crypto5, import_events2, import_fs5, import_promises, import_path7, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, SUPPORTED_IMAGE_EXTENSIONS, MAX_IMAGE_FILE_SIZE, ProbeAgent;
158577
+ var import_anthropic, import_openai, import_google, import_ai3, import_crypto5, import_events2, import_fs6, import_promises, import_path9, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, SUPPORTED_IMAGE_EXTENSIONS, MAX_IMAGE_FILE_SIZE, ProbeAgent;
156812
158578
  var init_ProbeAgent = __esm({
156813
158579
  "src/agent/ProbeAgent.js"() {
156814
158580
  "use strict";
@@ -156816,12 +158582,12 @@ var init_ProbeAgent = __esm({
156816
158582
  import_openai = __nccwpck_require__(87635);
156817
158583
  import_google = __nccwpck_require__(30260);
156818
158584
  init_dist3();
156819
- import_ai2 = __nccwpck_require__(86619);
158585
+ import_ai3 = __nccwpck_require__(86619);
156820
158586
  import_crypto5 = __nccwpck_require__(76982);
156821
158587
  import_events2 = __nccwpck_require__(24434);
156822
- import_fs5 = __nccwpck_require__(79896);
158588
+ import_fs6 = __nccwpck_require__(79896);
156823
158589
  import_promises = __nccwpck_require__(91943);
156824
- import_path7 = __nccwpck_require__(16928);
158590
+ import_path9 = __nccwpck_require__(16928);
156825
158591
  init_tokenCounter();
156826
158592
  init_tools2();
156827
158593
  init_common();
@@ -156865,6 +158631,8 @@ var init_ProbeAgent = __esm({
156865
158631
  this.outline = !!options.outline;
156866
158632
  this.maxResponseTokens = options.maxResponseTokens || parseInt(process.env.MAX_RESPONSE_TOKENS || "0", 10) || null;
156867
158633
  this.disableMermaidValidation = !!options.disableMermaidValidation;
158634
+ this.enableBash = !!options.enableBash;
158635
+ this.bashConfig = options.bashConfig || {};
156868
158636
  if (options.allowedFolders && Array.isArray(options.allowedFolders)) {
156869
158637
  this.allowedFolders = options.allowedFolders;
156870
158638
  } else if (options.path) {
@@ -156908,7 +158676,9 @@ var init_ProbeAgent = __esm({
156908
158676
  debug: this.debug,
156909
158677
  defaultPath: this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd(),
156910
158678
  allowedFolders: this.allowedFolders,
156911
- outline: this.outline
158679
+ outline: this.outline,
158680
+ enableBash: this.enableBash,
158681
+ bashConfig: this.bashConfig
156912
158682
  };
156913
158683
  const baseTools = createTools(configOptions);
156914
158684
  const wrappedTools = createWrappedTools(baseTools);
@@ -156920,6 +158690,9 @@ var init_ProbeAgent = __esm({
156920
158690
  listFiles: listFilesToolInstance,
156921
158691
  searchFiles: searchFilesToolInstance
156922
158692
  };
158693
+ if (this.enableBash && wrappedTools.bashToolInstance) {
158694
+ this.toolImplementations.bash = wrappedTools.bashToolInstance;
158695
+ }
156923
158696
  this.wrappedTools = wrappedTools;
156924
158697
  }
156925
158698
  /**
@@ -157106,13 +158879,13 @@ var init_ProbeAgent = __esm({
157106
158879
  const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
157107
158880
  let absolutePath;
157108
158881
  let isPathAllowed = false;
157109
- if ((0, import_path7.isAbsolute)(imagePath)) {
158882
+ if ((0, import_path9.isAbsolute)(imagePath)) {
157110
158883
  absolutePath = imagePath;
157111
- isPathAllowed = allowedDirs.some((dir) => absolutePath.startsWith((0, import_path7.resolve)(dir)));
158884
+ isPathAllowed = allowedDirs.some((dir) => absolutePath.startsWith((0, import_path9.resolve)(dir)));
157112
158885
  } else {
157113
158886
  for (const dir of allowedDirs) {
157114
- const resolvedPath3 = (0, import_path7.resolve)(dir, imagePath);
157115
- if (resolvedPath3.startsWith((0, import_path7.resolve)(dir))) {
158887
+ const resolvedPath3 = (0, import_path9.resolve)(dir, imagePath);
158888
+ if (resolvedPath3.startsWith((0, import_path9.resolve)(dir))) {
157116
158889
  absolutePath = resolvedPath3;
157117
158890
  isPathAllowed = true;
157118
158891
  break;
@@ -157607,7 +159380,7 @@ You are working with a repository located at: ${searchDirectory}
157607
159380
  try {
157608
159381
  const executeAIRequest = async () => {
157609
159382
  const messagesForAI = this.prepareMessagesWithImages(currentMessages);
157610
- const result = await (0, import_ai2.streamText)({
159383
+ const result = await (0, import_ai3.streamText)({
157611
159384
  model: this.provider(this.model),
157612
159385
  messages: messagesForAI,
157613
159386
  maxTokens: maxResponseTokens,
@@ -158284,12 +160057,12 @@ function initializeSimpleTelemetryFromOptions(options) {
158284
160057
  });
158285
160058
  return telemetry;
158286
160059
  }
158287
- var import_fs6, import_path8, SimpleTelemetry, SimpleAppTracer;
160060
+ var import_fs7, import_path10, SimpleTelemetry, SimpleAppTracer;
158288
160061
  var init_simpleTelemetry = __esm({
158289
160062
  "src/agent/simpleTelemetry.js"() {
158290
160063
  "use strict";
158291
- import_fs6 = __nccwpck_require__(79896);
158292
- import_path8 = __nccwpck_require__(16928);
160064
+ import_fs7 = __nccwpck_require__(79896);
160065
+ import_path10 = __nccwpck_require__(16928);
158293
160066
  SimpleTelemetry = class {
158294
160067
  constructor(options = {}) {
158295
160068
  this.serviceName = options.serviceName || "probe-agent";
@@ -158303,11 +160076,11 @@ var init_simpleTelemetry = __esm({
158303
160076
  }
158304
160077
  initializeFileExporter() {
158305
160078
  try {
158306
- const dir = (0, import_path8.dirname)(this.filePath);
158307
- if (!(0, import_fs6.existsSync)(dir)) {
158308
- (0, import_fs6.mkdirSync)(dir, { recursive: true });
160079
+ const dir = (0, import_path10.dirname)(this.filePath);
160080
+ if (!(0, import_fs7.existsSync)(dir)) {
160081
+ (0, import_fs7.mkdirSync)(dir, { recursive: true });
158309
160082
  }
158310
- this.stream = (0, import_fs6.createWriteStream)(this.filePath, { flags: "a" });
160083
+ this.stream = (0, import_fs7.createWriteStream)(this.filePath, { flags: "a" });
158311
160084
  this.stream.on("error", (error2) => {
158312
160085
  console.error(`[SimpleTelemetry] Stream error: ${error2.message}`);
158313
160086
  });
@@ -158368,20 +160141,20 @@ var init_simpleTelemetry = __esm({
158368
160141
  }
158369
160142
  async flush() {
158370
160143
  if (this.stream) {
158371
- return new Promise((resolve2) => {
158372
- this.stream.once("drain", resolve2);
160144
+ return new Promise((resolve4) => {
160145
+ this.stream.once("drain", resolve4);
158373
160146
  if (!this.stream.writableNeedDrain) {
158374
- resolve2();
160147
+ resolve4();
158375
160148
  }
158376
160149
  });
158377
160150
  }
158378
160151
  }
158379
160152
  async shutdown() {
158380
160153
  if (this.stream) {
158381
- return new Promise((resolve2) => {
160154
+ return new Promise((resolve4) => {
158382
160155
  this.stream.end(() => {
158383
160156
  console.log(`[SimpleTelemetry] File stream closed: ${this.filePath}`);
158384
- resolve2();
160157
+ resolve4();
158385
160158
  });
158386
160159
  });
158387
160160
  }
@@ -158508,6 +160281,9 @@ __export(index_exports, {
158508
160281
  SimpleTelemetry: () => SimpleTelemetry,
158509
160282
  attemptCompletionSchema: () => attemptCompletionSchema,
158510
160283
  attemptCompletionToolDefinition: () => attemptCompletionToolDefinition,
160284
+ bashSchema: () => bashSchema,
160285
+ bashTool: () => bashTool,
160286
+ bashToolDefinition: () => bashToolDefinition,
158511
160287
  delegate: () => delegate,
158512
160288
  delegateSchema: () => delegateSchema,
158513
160289
  delegateTool: () => delegateTool,
@@ -158544,6 +160320,7 @@ var init_index = __esm({
158544
160320
  init_system_message();
158545
160321
  init_common();
158546
160322
  init_vercel();
160323
+ init_bash();
158547
160324
  init_ProbeAgent();
158548
160325
  init_simpleTelemetry();
158549
160326
  }