@probelabs/visor 0.1.132-ee → 0.1.137-ee

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/dist/config/config-reloader.d.ts +1 -0
  2. package/dist/config/config-reloader.d.ts.map +1 -1
  3. package/dist/config/config-watcher.d.ts +1 -0
  4. package/dist/config/config-watcher.d.ts.map +1 -1
  5. package/dist/config.d.ts +4 -0
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/docs/ai-custom-tools-usage.md +37 -0
  8. package/dist/docs/ai-custom-tools.md +43 -1
  9. package/dist/docs/custom-tools.md +70 -1
  10. package/dist/docs/script.md +542 -27
  11. package/dist/docs/testing/cookbook.md +47 -0
  12. package/dist/examples/README.md +4 -0
  13. package/dist/examples/api-tools-ai-example.yaml +63 -0
  14. package/dist/examples/api-tools-inline-overlay-example.yaml +126 -0
  15. package/dist/examples/api-tools-library.yaml +18 -0
  16. package/dist/examples/api-tools-mcp-example.yaml +55 -0
  17. package/dist/examples/openapi/profiles-overlay-rename.yaml +3 -0
  18. package/dist/examples/openapi/users-api.json +91 -0
  19. package/dist/examples/openapi/users-overlay-rename.yaml +3 -0
  20. package/dist/generated/config-schema.d.ts +223 -74
  21. package/dist/generated/config-schema.d.ts.map +1 -1
  22. package/dist/generated/config-schema.json +251 -79
  23. package/dist/index.js +45128 -25001
  24. package/dist/providers/ai-check-provider.d.ts.map +1 -1
  25. package/dist/providers/api-tool-executor.d.ts +43 -0
  26. package/dist/providers/api-tool-executor.d.ts.map +1 -0
  27. package/dist/providers/command-check-provider.d.ts.map +1 -1
  28. package/dist/providers/custom-tool-executor.d.ts +21 -0
  29. package/dist/providers/custom-tool-executor.d.ts.map +1 -1
  30. package/dist/providers/mcp-check-provider.d.ts.map +1 -1
  31. package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
  32. package/dist/providers/script-check-provider.d.ts +18 -2
  33. package/dist/providers/script-check-provider.d.ts.map +1 -1
  34. package/dist/sdk/{check-provider-registry-7TCA3NSG.mjs → check-provider-registry-SCL4KP55.mjs} +9 -8
  35. package/dist/sdk/{check-provider-registry-KUDVEKAC.mjs → check-provider-registry-ULZRI3TC.mjs} +9 -8
  36. package/dist/sdk/{chunk-27RV5RR2.mjs → chunk-BRD36I43.mjs} +3 -3
  37. package/dist/sdk/{chunk-BGBXLPLL.mjs → chunk-E2N3U5HU.mjs} +5 -5
  38. package/dist/sdk/{chunk-XGI47XIH.mjs → chunk-F4K5WFSM.mjs} +1896 -1762
  39. package/dist/sdk/chunk-F4K5WFSM.mjs.map +1 -0
  40. package/dist/sdk/{chunk-2RNTEWOA.mjs → chunk-HQIVGUSV.mjs} +1896 -1762
  41. package/dist/sdk/chunk-HQIVGUSV.mjs.map +1 -0
  42. package/dist/sdk/{chunk-U3BLLEW3.mjs → chunk-KPRFDKQX.mjs} +329 -80
  43. package/dist/sdk/chunk-KPRFDKQX.mjs.map +1 -0
  44. package/dist/sdk/{chunk-VF6XIUE4.mjs → chunk-LW3INISN.mjs} +32 -1
  45. package/dist/sdk/{chunk-VF6XIUE4.mjs.map → chunk-LW3INISN.mjs.map} +1 -1
  46. package/dist/sdk/{chunk-VG7FWDC2.mjs → chunk-QUEWQWDX.mjs} +11 -4
  47. package/dist/sdk/{chunk-VG7FWDC2.mjs.map → chunk-QUEWQWDX.mjs.map} +1 -1
  48. package/dist/sdk/chunk-XKCER23W.mjs +1490 -0
  49. package/dist/sdk/chunk-XKCER23W.mjs.map +1 -0
  50. package/dist/sdk/{chunk-XJQKTK6V.mjs → chunk-ZUEQNCKB.mjs} +2 -2
  51. package/dist/sdk/{config-FMIIATKX.mjs → config-3UIU4TMP.mjs} +3 -3
  52. package/dist/sdk/{failure-condition-evaluator-PNONVBXD.mjs → failure-condition-evaluator-B5JJFYKU.mjs} +4 -4
  53. package/dist/sdk/{github-frontend-WR4S3NG5.mjs → github-frontend-VAWVSCNX.mjs} +4 -4
  54. package/dist/sdk/{host-TROSAWTE.mjs → host-67XTJ3BN.mjs} +2 -2
  55. package/dist/sdk/{host-U7V54J2H.mjs → host-TEQ7HKKH.mjs} +2 -2
  56. package/dist/sdk/{liquid-extensions-YDIIH33Q.mjs → liquid-extensions-PLBOMRLI.mjs} +3 -3
  57. package/dist/sdk/{routing-F4FOWVKF.mjs → routing-SEQYM4N6.mjs} +6 -6
  58. package/dist/sdk/schedule-tool-2COUUTF7.mjs +18 -0
  59. package/dist/sdk/{schedule-tool-handler-ULNF7TZW.mjs → schedule-tool-handler-5BDMLHS5.mjs} +10 -9
  60. package/dist/sdk/{schedule-tool-handler-VFES42DD.mjs → schedule-tool-handler-D7XX7WM4.mjs} +10 -9
  61. package/dist/sdk/sdk.d.mts +55 -2
  62. package/dist/sdk/sdk.d.ts +55 -2
  63. package/dist/sdk/sdk.js +2424 -539
  64. package/dist/sdk/sdk.js.map +1 -1
  65. package/dist/sdk/sdk.mjs +8 -7
  66. package/dist/sdk/sdk.mjs.map +1 -1
  67. package/dist/sdk/{trace-helpers-RDPXIN4S.mjs → trace-helpers-FAAGLXBI.mjs} +2 -2
  68. package/dist/sdk/{workflow-check-provider-4NFWH6YO.mjs → workflow-check-provider-K4MQQOYQ.mjs} +10 -9
  69. package/dist/sdk/{workflow-check-provider-5XS62BCJ.mjs → workflow-check-provider-WLA7LO56.mjs} +10 -9
  70. package/dist/sdk/workflow-check-provider-WLA7LO56.mjs.map +1 -0
  71. package/dist/state-machine/dispatch/execution-invoker.d.ts.map +1 -1
  72. package/dist/state-machine-execution-engine.d.ts.map +1 -1
  73. package/dist/test-runner/core/test-execution-wrapper.d.ts.map +1 -1
  74. package/dist/test-runner/index.d.ts.map +1 -1
  75. package/dist/test-runner/validator.d.ts.map +1 -1
  76. package/dist/types/config.d.ts +55 -2
  77. package/dist/types/config.d.ts.map +1 -1
  78. package/dist/utils/config-loader.d.ts +5 -0
  79. package/dist/utils/config-loader.d.ts.map +1 -1
  80. package/dist/utils/sandbox.d.ts +8 -0
  81. package/dist/utils/sandbox.d.ts.map +1 -1
  82. package/dist/utils/script-tool-environment.d.ts +90 -0
  83. package/dist/utils/script-tool-environment.d.ts.map +1 -0
  84. package/dist/utils/tool-resolver.d.ts +18 -0
  85. package/dist/utils/tool-resolver.d.ts.map +1 -0
  86. package/package.json +11 -4
  87. package/dist/sdk/chunk-2RNTEWOA.mjs.map +0 -1
  88. package/dist/sdk/chunk-U3BLLEW3.mjs.map +0 -1
  89. package/dist/sdk/chunk-XGI47XIH.mjs.map +0 -1
  90. /package/dist/sdk/{check-provider-registry-7TCA3NSG.mjs.map → check-provider-registry-SCL4KP55.mjs.map} +0 -0
  91. /package/dist/sdk/{check-provider-registry-KUDVEKAC.mjs.map → check-provider-registry-ULZRI3TC.mjs.map} +0 -0
  92. /package/dist/sdk/{chunk-27RV5RR2.mjs.map → chunk-BRD36I43.mjs.map} +0 -0
  93. /package/dist/sdk/{chunk-BGBXLPLL.mjs.map → chunk-E2N3U5HU.mjs.map} +0 -0
  94. /package/dist/sdk/{chunk-XJQKTK6V.mjs.map → chunk-ZUEQNCKB.mjs.map} +0 -0
  95. /package/dist/sdk/{config-FMIIATKX.mjs.map → config-3UIU4TMP.mjs.map} +0 -0
  96. /package/dist/sdk/{failure-condition-evaluator-PNONVBXD.mjs.map → failure-condition-evaluator-B5JJFYKU.mjs.map} +0 -0
  97. /package/dist/sdk/{github-frontend-WR4S3NG5.mjs.map → github-frontend-VAWVSCNX.mjs.map} +0 -0
  98. /package/dist/sdk/{host-TROSAWTE.mjs.map → host-67XTJ3BN.mjs.map} +0 -0
  99. /package/dist/sdk/{host-U7V54J2H.mjs.map → host-TEQ7HKKH.mjs.map} +0 -0
  100. /package/dist/sdk/{liquid-extensions-YDIIH33Q.mjs.map → liquid-extensions-PLBOMRLI.mjs.map} +0 -0
  101. /package/dist/sdk/{routing-F4FOWVKF.mjs.map → routing-SEQYM4N6.mjs.map} +0 -0
  102. /package/dist/sdk/{schedule-tool-handler-ULNF7TZW.mjs.map → schedule-tool-2COUUTF7.mjs.map} +0 -0
  103. /package/dist/sdk/{schedule-tool-handler-VFES42DD.mjs.map → schedule-tool-handler-5BDMLHS5.mjs.map} +0 -0
  104. /package/dist/sdk/{trace-helpers-RDPXIN4S.mjs.map → schedule-tool-handler-D7XX7WM4.mjs.map} +0 -0
  105. /package/dist/sdk/{workflow-check-provider-4NFWH6YO.mjs.map → trace-helpers-FAAGLXBI.mjs.map} +0 -0
  106. /package/dist/sdk/{workflow-check-provider-5XS62BCJ.mjs.map → workflow-check-provider-K4MQQOYQ.mjs.map} +0 -0
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  init_sandbox,
8
8
  validateJsSyntax
9
- } from "./chunk-VF6XIUE4.mjs";
9
+ } from "./chunk-LW3INISN.mjs";
10
10
  import {
11
11
  init_logger,
12
12
  logger
@@ -44,6 +44,19 @@ var init_config_loader = __esm({
44
44
  }
45
45
  cache = /* @__PURE__ */ new Map();
46
46
  loadedConfigs = /* @__PURE__ */ new Set();
47
+ /**
48
+ * Annotate tool definitions with their source base directory.
49
+ * This is used at runtime to resolve relative tool assets (e.g., API specs).
50
+ */
51
+ annotateToolsBaseDir(config, baseDir) {
52
+ if (!config.tools || typeof config.tools !== "object") {
53
+ return;
54
+ }
55
+ for (const tool of Object.values(config.tools)) {
56
+ if (!tool || typeof tool !== "object") continue;
57
+ tool.__baseDir = tool.__baseDir || baseDir;
58
+ }
59
+ }
47
60
  /**
48
61
  * Determine the source type from a string
49
62
  */
@@ -128,6 +141,7 @@ var init_config_loader = __esm({
128
141
  config.extends = Array.isArray(inc) ? inc : [inc];
129
142
  delete config.include;
130
143
  }
144
+ this.annotateToolsBaseDir(config, path.dirname(resolvedPath));
131
145
  const previousBaseDir = this.options.baseDir;
132
146
  this.options.baseDir = path.dirname(resolvedPath);
133
147
  try {
@@ -185,6 +199,12 @@ var init_config_loader = __esm({
185
199
  if (!config || typeof config !== "object") {
186
200
  throw new Error(`Invalid YAML in remote configuration: ${url}`);
187
201
  }
202
+ try {
203
+ const parsed = new URL(url);
204
+ const baseUrl = new URL(".", parsed).toString();
205
+ this.annotateToolsBaseDir(config, baseUrl);
206
+ } catch {
207
+ }
188
208
  this.cache.set(url, {
189
209
  config,
190
210
  timestamp: Date.now(),
@@ -321,9 +341,17 @@ var init_config_loader = __esm({
321
341
  */
322
342
  validateLocalPath(resolvedPath) {
323
343
  const projectRoot = this.options.projectRoot || process.cwd();
324
- const normalizedPath = path.normalize(resolvedPath);
325
- const normalizedRoot = path.normalize(projectRoot);
326
- if (!normalizedPath.startsWith(normalizedRoot)) {
344
+ const canonicalize = (p) => {
345
+ const resolved = path.resolve(p);
346
+ try {
347
+ return path.normalize(fs.realpathSync.native(resolved));
348
+ } catch {
349
+ return path.normalize(resolved);
350
+ }
351
+ };
352
+ const normalizedPath = canonicalize(resolvedPath);
353
+ const normalizedRoot = canonicalize(projectRoot);
354
+ if (normalizedPath !== normalizedRoot && !normalizedPath.startsWith(`${normalizedRoot}${path.sep}`)) {
327
355
  throw new Error(
328
356
  `Security error: Path traversal detected. Cannot access files outside project root: ${projectRoot}`
329
357
  );
@@ -334,7 +362,7 @@ var init_config_loader = __esm({
334
362
  "/.ssh/",
335
363
  "/.aws/",
336
364
  "/.env",
337
- "/private/"
365
+ "/private/etc/"
338
366
  ];
339
367
  const lowerPath = normalizedPath.toLowerCase();
340
368
  for (const pattern of sensitivePatterns) {
@@ -608,6 +636,11 @@ var init_config_schema = __esm({
608
636
  CustomToolDefinition: {
609
637
  type: "object",
610
638
  properties: {
639
+ type: {
640
+ type: "string",
641
+ enum: ["command", "api"],
642
+ description: "Tool implementation type (defaults to 'command')"
643
+ },
611
644
  name: {
612
645
  type: "string",
613
646
  description: "Tool name - used to reference the tool in MCP blocks"
@@ -645,7 +678,7 @@ var init_config_schema = __esm({
645
678
  },
646
679
  exec: {
647
680
  type: "string",
648
- description: "Command to execute - supports Liquid template"
681
+ description: "Command to execute - supports Liquid template (required for type: 'command')"
649
682
  },
650
683
  stdin: {
651
684
  type: "string",
@@ -678,9 +711,132 @@ var init_config_schema = __esm({
678
711
  outputSchema: {
679
712
  $ref: "#/definitions/Record%3Cstring%2Cunknown%3E",
680
713
  description: "Expected output schema for validation"
714
+ },
715
+ spec: {
716
+ anyOf: [
717
+ {
718
+ type: "string"
719
+ },
720
+ {
721
+ $ref: "#/definitions/Record%3Cstring%2Cunknown%3E"
722
+ }
723
+ ],
724
+ description: "OpenAPI specification path/URL or inline object (required for type: 'api')"
725
+ },
726
+ overlays: {
727
+ anyOf: [
728
+ {
729
+ type: "string"
730
+ },
731
+ {
732
+ $ref: "#/definitions/Record%3Cstring%2Cunknown%3E"
733
+ },
734
+ {
735
+ type: "array",
736
+ items: {
737
+ anyOf: [
738
+ {
739
+ type: "string"
740
+ },
741
+ {
742
+ $ref: "#/definitions/Record%3Cstring%2Cunknown%3E"
743
+ }
744
+ ]
745
+ }
746
+ }
747
+ ],
748
+ description: "Overlay path/URL, inline object, or a mixed array applied in order"
749
+ },
750
+ targetUrl: {
751
+ type: "string",
752
+ description: "Override API base URL instead of OpenAPI servers"
753
+ },
754
+ target_url: {
755
+ type: "string",
756
+ description: "Alias for targetUrl (snake_case)"
757
+ },
758
+ whitelist: {
759
+ anyOf: [
760
+ {
761
+ type: "array",
762
+ items: {
763
+ type: "string"
764
+ }
765
+ },
766
+ {
767
+ type: "string"
768
+ }
769
+ ],
770
+ description: "Include only operations matching these glob patterns (operationId or METHOD:/path)"
771
+ },
772
+ blacklist: {
773
+ anyOf: [
774
+ {
775
+ type: "array",
776
+ items: {
777
+ type: "string"
778
+ }
779
+ },
780
+ {
781
+ type: "string"
782
+ }
783
+ ],
784
+ description: "Exclude operations matching these glob patterns (ignored when whitelist is set)"
785
+ },
786
+ headers: {
787
+ $ref: "#/definitions/Record%3Cstring%2Cstring%3E",
788
+ description: "Extra headers added to all API requests"
789
+ },
790
+ disableXMcp: {
791
+ type: "boolean",
792
+ description: "Disable X-MCP: 1 request header"
793
+ },
794
+ disable_x_mcp: {
795
+ type: "boolean",
796
+ description: "Alias for disableXMcp (snake_case)"
797
+ },
798
+ apiKey: {
799
+ type: "string",
800
+ description: "API key fallback credential used by security schemes"
801
+ },
802
+ api_key: {
803
+ type: "string",
804
+ description: "Alias for apiKey (snake_case)"
805
+ },
806
+ securitySchemeName: {
807
+ type: "string",
808
+ description: "Preferred security scheme name (optional hint)"
809
+ },
810
+ security_scheme_name: {
811
+ type: "string",
812
+ description: "Alias for securitySchemeName (snake_case)"
813
+ },
814
+ securityCredentials: {
815
+ $ref: "#/definitions/Record%3Cstring%2Cstring%3E",
816
+ description: "Credentials by OpenAPI security scheme name"
817
+ },
818
+ security_credentials: {
819
+ $ref: "#/definitions/Record%3Cstring%2Cstring%3E",
820
+ description: "Alias for securityCredentials (snake_case)"
821
+ },
822
+ namePrefix: {
823
+ type: "string",
824
+ description: "Optional prefix prepended to generated operation tool names"
825
+ },
826
+ name_prefix: {
827
+ type: "string",
828
+ description: "Alias for namePrefix (snake_case)"
829
+ },
830
+ requestTimeoutMs: {
831
+ type: "number",
832
+ description: "Request timeout in milliseconds for API calls"
833
+ },
834
+ request_timeout_ms: {
835
+ type: "number",
836
+ description: "Alias for requestTimeoutMs (snake_case)"
681
837
  }
682
838
  },
683
- required: ["name", "exec"],
839
+ required: ["name"],
684
840
  additionalProperties: false,
685
841
  description: "Custom tool definition for use in MCP blocks",
686
842
  patternProperties: {
@@ -811,6 +967,46 @@ var init_config_schema = __esm({
811
967
  type: "string",
812
968
  description: "Script content to execute for script checks"
813
969
  },
970
+ tools: {
971
+ type: "array",
972
+ items: {
973
+ anyOf: [
974
+ {
975
+ type: "string"
976
+ },
977
+ {
978
+ type: "object",
979
+ properties: {
980
+ workflow: {
981
+ type: "string"
982
+ },
983
+ args: {
984
+ $ref: "#/definitions/Record%3Cstring%2Cunknown%3E"
985
+ }
986
+ },
987
+ required: ["workflow"],
988
+ additionalProperties: false
989
+ }
990
+ ]
991
+ },
992
+ description: "Tool names to expose inside script checks (string names or workflow references)"
993
+ },
994
+ tools_js: {
995
+ type: "string",
996
+ description: "JavaScript expression to dynamically compute tools for script checks"
997
+ },
998
+ mcp_servers: {
999
+ $ref: "#/definitions/Record%3Cstring%2CMcpServerConfig%3E",
1000
+ description: "MCP servers whose tools are exposed inside script checks"
1001
+ },
1002
+ enable_fetch: {
1003
+ type: "boolean",
1004
+ description: "Enable fetch() function in script checks (default: false)"
1005
+ },
1006
+ enable_bash: {
1007
+ type: "boolean",
1008
+ description: "Enable bash() function in script checks (default: false)"
1009
+ },
814
1010
  schedule: {
815
1011
  type: "string",
816
1012
  description: 'Cron schedule expression (e.g., "0 2 * * *") - optional for any check type'
@@ -1156,7 +1352,7 @@ var init_config_schema = __esm({
1156
1352
  description: "Arguments/inputs for the workflow"
1157
1353
  },
1158
1354
  overrides: {
1159
- $ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-13489-27516-src_types_config.ts-0-51381%3E%3E",
1355
+ $ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-13489-28083-src_types_config.ts-0-53867%3E%3E",
1160
1356
  description: "Override specific step configurations in the workflow"
1161
1357
  },
1162
1358
  output_mapping: {
@@ -1172,7 +1368,7 @@ var init_config_schema = __esm({
1172
1368
  description: "Config file path - alternative to workflow ID (loads a Visor config file as workflow)"
1173
1369
  },
1174
1370
  workflow_overrides: {
1175
- $ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-13489-27516-src_types_config.ts-0-51381%3E%3E",
1371
+ $ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-13489-28083-src_types_config.ts-0-53867%3E%3E",
1176
1372
  description: "Alias for overrides - workflow step overrides (backward compatibility)"
1177
1373
  },
1178
1374
  ref: {
@@ -1278,6 +1474,72 @@ var init_config_schema = __esm({
1278
1474
  ],
1279
1475
  description: "Valid check types in configuration"
1280
1476
  },
1477
+ "Record<string,McpServerConfig>": {
1478
+ type: "object",
1479
+ additionalProperties: {
1480
+ $ref: "#/definitions/McpServerConfig"
1481
+ }
1482
+ },
1483
+ McpServerConfig: {
1484
+ type: "object",
1485
+ properties: {
1486
+ command: {
1487
+ type: "string",
1488
+ description: "Command to execute (presence indicates stdio server)"
1489
+ },
1490
+ args: {
1491
+ type: "array",
1492
+ items: {
1493
+ type: "string"
1494
+ },
1495
+ description: "Arguments to pass to the command"
1496
+ },
1497
+ env: {
1498
+ $ref: "#/definitions/Record%3Cstring%2Cstring%3E",
1499
+ description: "Environment variables for the MCP server"
1500
+ },
1501
+ url: {
1502
+ type: "string",
1503
+ description: "URL endpoint (presence indicates external server)"
1504
+ },
1505
+ transport: {
1506
+ type: "string",
1507
+ enum: ["stdio", "sse", "http"],
1508
+ description: "Transport type"
1509
+ },
1510
+ workflow: {
1511
+ type: "string",
1512
+ description: "Workflow ID or path (presence indicates workflow tool)"
1513
+ },
1514
+ inputs: {
1515
+ $ref: "#/definitions/Record%3Cstring%2Cunknown%3E",
1516
+ description: "Inputs to pass to workflow"
1517
+ },
1518
+ description: {
1519
+ type: "string",
1520
+ description: "Tool description for AI"
1521
+ },
1522
+ allowedMethods: {
1523
+ type: "array",
1524
+ items: {
1525
+ type: "string"
1526
+ },
1527
+ description: 'Whitelist specific methods from this MCP server (supports wildcards like "search_*")'
1528
+ },
1529
+ blockedMethods: {
1530
+ type: "array",
1531
+ items: {
1532
+ type: "string"
1533
+ },
1534
+ description: 'Block specific methods from this MCP server (supports wildcards like "*_delete")'
1535
+ }
1536
+ },
1537
+ additionalProperties: false,
1538
+ description: "Unified MCP server/tool entry - type detected by which properties are present\n\nDetection logic (priority order): 1. Has `command` \u2192 stdio MCP server (external process) 2. Has `url` \u2192 SSE/HTTP MCP server (external endpoint) 3. Has `workflow` \u2192 workflow tool reference 4. Empty `{}` or just key \u2192 auto-detect from `tools:` section",
1539
+ patternProperties: {
1540
+ "^x-": {}
1541
+ }
1542
+ },
1281
1543
  EventTrigger: {
1282
1544
  type: "string",
1283
1545
  enum: [
@@ -1406,72 +1668,6 @@ var init_config_schema = __esm({
1406
1668
  "^x-": {}
1407
1669
  }
1408
1670
  },
1409
- "Record<string,McpServerConfig>": {
1410
- type: "object",
1411
- additionalProperties: {
1412
- $ref: "#/definitions/McpServerConfig"
1413
- }
1414
- },
1415
- McpServerConfig: {
1416
- type: "object",
1417
- properties: {
1418
- command: {
1419
- type: "string",
1420
- description: "Command to execute (presence indicates stdio server)"
1421
- },
1422
- args: {
1423
- type: "array",
1424
- items: {
1425
- type: "string"
1426
- },
1427
- description: "Arguments to pass to the command"
1428
- },
1429
- env: {
1430
- $ref: "#/definitions/Record%3Cstring%2Cstring%3E",
1431
- description: "Environment variables for the MCP server"
1432
- },
1433
- url: {
1434
- type: "string",
1435
- description: "URL endpoint (presence indicates external server)"
1436
- },
1437
- transport: {
1438
- type: "string",
1439
- enum: ["stdio", "sse", "http"],
1440
- description: "Transport type"
1441
- },
1442
- workflow: {
1443
- type: "string",
1444
- description: "Workflow ID or path (presence indicates workflow tool)"
1445
- },
1446
- inputs: {
1447
- $ref: "#/definitions/Record%3Cstring%2Cunknown%3E",
1448
- description: "Inputs to pass to workflow"
1449
- },
1450
- description: {
1451
- type: "string",
1452
- description: "Tool description for AI"
1453
- },
1454
- allowedMethods: {
1455
- type: "array",
1456
- items: {
1457
- type: "string"
1458
- },
1459
- description: 'Whitelist specific methods from this MCP server (supports wildcards like "search_*")'
1460
- },
1461
- blockedMethods: {
1462
- type: "array",
1463
- items: {
1464
- type: "string"
1465
- },
1466
- description: 'Block specific methods from this MCP server (supports wildcards like "*_delete")'
1467
- }
1468
- },
1469
- additionalProperties: false,
1470
- description: "Unified MCP server/tool entry - type detected by which properties are present\n\nDetection logic (priority order): 1. Has `command` \u2192 stdio MCP server (external process) 2. Has `url` \u2192 SSE/HTTP MCP server (external endpoint) 3. Has `workflow` \u2192 workflow tool reference 4. Empty `{}` or just key \u2192 auto-detect from `tools:` section",
1471
- patternProperties: {
1472
- "^x-": {}
1473
- }
1474
- },
1475
1671
  AIRetryConfig: {
1476
1672
  type: "object",
1477
1673
  properties: {
@@ -1860,7 +2056,7 @@ var init_config_schema = __esm({
1860
2056
  description: "Custom output name (defaults to workflow name)"
1861
2057
  },
1862
2058
  overrides: {
1863
- $ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-13489-27516-src_types_config.ts-0-51381%3E%3E",
2059
+ $ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-13489-28083-src_types_config.ts-0-53867%3E%3E",
1864
2060
  description: "Step overrides"
1865
2061
  },
1866
2062
  output_mapping: {
@@ -1875,13 +2071,13 @@ var init_config_schema = __esm({
1875
2071
  "^x-": {}
1876
2072
  }
1877
2073
  },
1878
- "Record<string,Partial<interface-src_types_config.ts-13489-27516-src_types_config.ts-0-51381>>": {
2074
+ "Record<string,Partial<interface-src_types_config.ts-13489-28083-src_types_config.ts-0-53867>>": {
1879
2075
  type: "object",
1880
2076
  additionalProperties: {
1881
- $ref: "#/definitions/Partial%3Cinterface-src_types_config.ts-13489-27516-src_types_config.ts-0-51381%3E"
2077
+ $ref: "#/definitions/Partial%3Cinterface-src_types_config.ts-13489-28083-src_types_config.ts-0-53867%3E"
1882
2078
  }
1883
2079
  },
1884
- "Partial<interface-src_types_config.ts-13489-27516-src_types_config.ts-0-51381>": {
2080
+ "Partial<interface-src_types_config.ts-13489-28083-src_types_config.ts-0-53867>": {
1885
2081
  type: "object",
1886
2082
  additionalProperties: false
1887
2083
  },
@@ -3173,6 +3369,18 @@ var init_config = __esm({
3173
3369
  validEventTriggers = [...VALID_EVENT_TRIGGERS];
3174
3370
  validOutputFormats = ["table", "json", "markdown", "sarif"];
3175
3371
  validGroupByOptions = ["check", "file", "severity", "group"];
3372
+ /**
3373
+ * Annotate tools with the originating config directory for relative asset resolution.
3374
+ */
3375
+ annotateToolBaseDirs(config, baseDir) {
3376
+ if (!config.tools || typeof config.tools !== "object") {
3377
+ return;
3378
+ }
3379
+ for (const tool of Object.values(config.tools)) {
3380
+ if (!tool || typeof tool !== "object") continue;
3381
+ tool.__baseDir = tool.__baseDir || baseDir;
3382
+ }
3383
+ }
3176
3384
  /**
3177
3385
  * Load configuration from a file
3178
3386
  */
@@ -3225,6 +3433,7 @@ var init_config = __esm({
3225
3433
  if (parsedConfig.id && typeof parsedConfig.id === "string") {
3226
3434
  parsedConfig = await this.convertWorkflowToConfig(parsedConfig, path2.dirname(resolvedPath));
3227
3435
  }
3436
+ this.annotateToolBaseDirs(parsedConfig, path2.dirname(resolvedPath));
3228
3437
  parsedConfig = this.normalizeStepsAndChecks(parsedConfig, !!extendsValue);
3229
3438
  await this.loadWorkflows(parsedConfig, path2.dirname(resolvedPath));
3230
3439
  if (validate) {
@@ -3285,6 +3494,7 @@ var init_config = __esm({
3285
3494
  if (parsedConfig.id && typeof parsedConfig.id === "string") {
3286
3495
  parsedConfig = await this.convertWorkflowToConfig(parsedConfig, baseDir || process.cwd());
3287
3496
  }
3497
+ this.annotateToolBaseDirs(parsedConfig, baseDir || process.cwd());
3288
3498
  parsedConfig = this.normalizeStepsAndChecks(parsedConfig, !!extendsValue);
3289
3499
  await this.loadWorkflows(parsedConfig, baseDir || process.cwd());
3290
3500
  if (validate) this.validateConfig(parsedConfig);
@@ -3797,6 +4007,42 @@ ${errors}`);
3797
4007
  if (config.ai_mcp_servers) {
3798
4008
  this.validateMcpServersObject(config.ai_mcp_servers, "ai_mcp_servers", errors, warnings);
3799
4009
  }
4010
+ if (config.tools) {
4011
+ for (const [toolName, toolDef] of Object.entries(config.tools)) {
4012
+ const type = toolDef.type || "command";
4013
+ if (type === "api") {
4014
+ const spec = toolDef.spec;
4015
+ const hasStringSpec = typeof spec === "string" && spec.trim().length > 0;
4016
+ const hasInlineSpec = !!spec && typeof spec === "object" && !Array.isArray(spec);
4017
+ if (!hasStringSpec && !hasInlineSpec) {
4018
+ errors.push({
4019
+ field: `tools.${toolName}.spec`,
4020
+ message: `Invalid tool configuration for "${toolName}": missing spec field (required for type: api)`
4021
+ });
4022
+ }
4023
+ const overlays = toolDef.overlays;
4024
+ if (overlays !== void 0) {
4025
+ const isInlineOverlay = !!overlays && typeof overlays === "object" && !Array.isArray(overlays);
4026
+ const isStringOverlay = typeof overlays === "string";
4027
+ const isMixedArrayOverlay = Array.isArray(overlays) && overlays.every(
4028
+ (item) => typeof item === "string" || !!item && typeof item === "object" && !Array.isArray(item)
4029
+ );
4030
+ if (!isInlineOverlay && !isStringOverlay && !isMixedArrayOverlay) {
4031
+ errors.push({
4032
+ field: `tools.${toolName}.overlays`,
4033
+ message: `Invalid tool configuration for "${toolName}": overlays must be a string, object, or array of strings/objects`,
4034
+ value: overlays
4035
+ });
4036
+ }
4037
+ }
4038
+ } else if (!toolDef.exec || typeof toolDef.exec !== "string") {
4039
+ errors.push({
4040
+ field: `tools.${toolName}.exec`,
4041
+ message: `Invalid tool configuration for "${toolName}": missing exec field (required for command tools)`
4042
+ });
4043
+ }
4044
+ }
4045
+ }
3800
4046
  if (config.output) {
3801
4047
  this.validateOutputConfig(config.output, errors);
3802
4048
  }
@@ -4464,6 +4710,9 @@ ${errors}`);
4464
4710
  if (topLevel && allowedTopLevelKeys.has(addl)) {
4465
4711
  continue;
4466
4712
  }
4713
+ if (!topLevel && addl === "__baseDir" && pathStr.startsWith("tools.")) {
4714
+ continue;
4715
+ }
4467
4716
  if (!topLevel && addl === "sandbox" && pathStr.match(/^(checks|steps)\.[^.]+$/)) {
4468
4717
  continue;
4469
4718
  }
@@ -4669,4 +4918,4 @@ export {
4669
4918
  config_exports,
4670
4919
  init_config
4671
4920
  };
4672
- //# sourceMappingURL=chunk-U3BLLEW3.mjs.map
4921
+ //# sourceMappingURL=chunk-KPRFDKQX.mjs.map