@probelabs/visor 0.1.129 → 0.1.130

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 (206) hide show
  1. package/README.md +23 -0
  2. package/dist/cli-main.d.ts.map +1 -1
  3. package/dist/config.d.ts +4 -0
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/docs/author-permissions.md +20 -0
  6. package/dist/docs/enterprise-policy.md +1325 -0
  7. package/dist/docs/index.md +10 -0
  8. package/dist/docs/scheduler-storage.md +433 -0
  9. package/dist/docs/scheduler.md +12 -2
  10. package/dist/enterprise/license/validator.d.ts +39 -0
  11. package/dist/enterprise/license/validator.d.ts.map +1 -0
  12. package/dist/enterprise/loader.d.ts +25 -0
  13. package/dist/enterprise/loader.d.ts.map +1 -0
  14. package/dist/enterprise/policy/opa-compiler.d.ts +37 -0
  15. package/dist/enterprise/policy/opa-compiler.d.ts.map +1 -0
  16. package/dist/enterprise/policy/opa-http-evaluator.d.ts +36 -0
  17. package/dist/enterprise/policy/opa-http-evaluator.d.ts.map +1 -0
  18. package/dist/enterprise/policy/opa-policy-engine.d.ts +48 -0
  19. package/dist/enterprise/policy/opa-policy-engine.d.ts.map +1 -0
  20. package/dist/enterprise/policy/opa-wasm-evaluator.d.ts +34 -0
  21. package/dist/enterprise/policy/opa-wasm-evaluator.d.ts.map +1 -0
  22. package/dist/enterprise/policy/policy-input-builder.d.ts +120 -0
  23. package/dist/enterprise/policy/policy-input-builder.d.ts.map +1 -0
  24. package/dist/enterprise/scheduler/knex-store.d.ts +41 -0
  25. package/dist/enterprise/scheduler/knex-store.d.ts.map +1 -0
  26. package/dist/examples/README.md +23 -0
  27. package/dist/examples/enterprise-policy/README.md +344 -0
  28. package/dist/examples/enterprise-policy/policies/capability_resolve.rego +29 -0
  29. package/dist/examples/enterprise-policy/policies/capability_resolve_test.rego +230 -0
  30. package/dist/examples/enterprise-policy/policies/check_execute.rego +71 -0
  31. package/dist/examples/enterprise-policy/policies/check_execute_test.rego +321 -0
  32. package/dist/examples/enterprise-policy/policies/deploy_production.rego +33 -0
  33. package/dist/examples/enterprise-policy/policies/deploy_production_test.rego +29 -0
  34. package/dist/examples/enterprise-policy/policies/slack_channel_gate.rego +17 -0
  35. package/dist/examples/enterprise-policy/policies/slack_tool_restrict.rego +16 -0
  36. package/dist/examples/enterprise-policy/policies/tool_invoke.rego +24 -0
  37. package/dist/examples/enterprise-policy/policies/tool_invoke_test.rego +227 -0
  38. package/dist/examples/enterprise-policy/visor.yaml +64 -0
  39. package/dist/failure-condition-evaluator.d.ts +18 -0
  40. package/dist/failure-condition-evaluator.d.ts.map +1 -1
  41. package/dist/frontends/slack-frontend.d.ts +1 -0
  42. package/dist/frontends/slack-frontend.d.ts.map +1 -1
  43. package/dist/generated/config-schema.d.ts +139 -0
  44. package/dist/generated/config-schema.d.ts.map +1 -1
  45. package/dist/index.js +12121 -7169
  46. package/dist/liquid-extensions.d.ts.map +1 -1
  47. package/dist/output/traces/{run-2026-02-08T18-16-04-160Z.ndjson → run-2026-02-11T16-20-59-999Z.ndjson} +84 -84
  48. package/dist/{traces/run-2026-02-08T18-16-51-253Z.ndjson → output/traces/run-2026-02-11T16-21-47-711Z.ndjson} +1032 -1032
  49. package/dist/policy/default-engine.d.ts +17 -0
  50. package/dist/policy/default-engine.d.ts.map +1 -0
  51. package/dist/policy/index.d.ts +4 -0
  52. package/dist/policy/index.d.ts.map +1 -0
  53. package/dist/policy/policy-check-command.d.ts +65 -0
  54. package/dist/policy/policy-check-command.d.ts.map +1 -0
  55. package/dist/policy/types.d.ts +81 -0
  56. package/dist/policy/types.d.ts.map +1 -0
  57. package/dist/providers/ai-check-provider.d.ts.map +1 -1
  58. package/dist/providers/check-provider.interface.d.ts +2 -0
  59. package/dist/providers/check-provider.interface.d.ts.map +1 -1
  60. package/dist/providers/claude-code-check-provider.d.ts.map +1 -1
  61. package/dist/providers/mcp-check-provider.d.ts.map +1 -1
  62. package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
  63. package/dist/providers/workflow-check-provider.d.ts.map +1 -1
  64. package/dist/scheduler/index.d.ts +2 -0
  65. package/dist/scheduler/index.d.ts.map +1 -1
  66. package/dist/scheduler/schedule-store.d.ts +33 -59
  67. package/dist/scheduler/schedule-store.d.ts.map +1 -1
  68. package/dist/scheduler/schedule-tool.d.ts.map +1 -1
  69. package/dist/scheduler/scheduler.d.ts +24 -3
  70. package/dist/scheduler/scheduler.d.ts.map +1 -1
  71. package/dist/scheduler/store/index.d.ts +7 -0
  72. package/dist/scheduler/store/index.d.ts.map +1 -0
  73. package/dist/scheduler/store/json-migrator.d.ts +10 -0
  74. package/dist/scheduler/store/json-migrator.d.ts.map +1 -0
  75. package/dist/scheduler/store/sqlite-store.d.ts +32 -0
  76. package/dist/scheduler/store/sqlite-store.d.ts.map +1 -0
  77. package/dist/scheduler/store/types.d.ts +127 -0
  78. package/dist/scheduler/store/types.d.ts.map +1 -0
  79. package/dist/sdk/check-provider-registry-M3Y6JMTW.mjs +28 -0
  80. package/dist/sdk/check-provider-registry-PANIXYRB.mjs +28 -0
  81. package/dist/sdk/{chunk-D5KI4YQ4.mjs → chunk-DIND4ZCV.mjs} +2 -2
  82. package/dist/sdk/{chunk-DGZPPGJJ.mjs → chunk-EUUAQBTW.mjs} +1463 -568
  83. package/dist/sdk/chunk-EUUAQBTW.mjs.map +1 -0
  84. package/dist/sdk/{chunk-XDLQ3UNF.mjs → chunk-GEW6LS32.mjs} +2 -2
  85. package/dist/sdk/{chunk-N7HO6KKC.mjs → chunk-HOKQOO3G.mjs} +11 -6
  86. package/dist/sdk/chunk-HOKQOO3G.mjs.map +1 -0
  87. package/dist/sdk/{chunk-XR7XXGL7.mjs → chunk-JL7JXCET.mjs} +2 -2
  88. package/dist/sdk/{chunk-6W75IMDC.mjs → chunk-LG4AUKHB.mjs} +2 -2
  89. package/dist/sdk/{chunk-BDGUM6BA.mjs → chunk-S6CD7GFM.mjs} +1463 -568
  90. package/dist/sdk/chunk-S6CD7GFM.mjs.map +1 -0
  91. package/dist/sdk/{chunk-PO7X5XI7.mjs → chunk-SZXICFQ3.mjs} +2 -2
  92. package/dist/sdk/{chunk-HEX3RL32.mjs → chunk-UCMJJ3IM.mjs} +5 -2
  93. package/dist/sdk/{chunk-HEX3RL32.mjs.map → chunk-UCMJJ3IM.mjs.map} +1 -1
  94. package/dist/sdk/{chunk-7YSOINAQ.mjs → chunk-UCNT3PDT.mjs} +342 -5
  95. package/dist/sdk/chunk-UCNT3PDT.mjs.map +1 -0
  96. package/dist/sdk/{chunk-R5Z7YWPB.mjs → chunk-V2IV3ILA.mjs} +7 -5
  97. package/dist/sdk/chunk-V2IV3ILA.mjs.map +1 -0
  98. package/dist/sdk/{chunk-SGS2VMEL.mjs → chunk-VMLORODQ.mjs} +107 -20
  99. package/dist/sdk/chunk-VMLORODQ.mjs.map +1 -0
  100. package/dist/sdk/{chunk-2KB35MB7.mjs → chunk-VPC3QSPW.mjs} +2 -2
  101. package/dist/sdk/{chunk-J5RGJQ53.mjs → chunk-YJRBN3XS.mjs} +2 -2
  102. package/dist/sdk/{command-executor-DVVXERLR.mjs → command-executor-TOYBBE7S.mjs} +4 -4
  103. package/dist/sdk/{config-7VTT64SQ.mjs → config-OGOS4ZU4.mjs} +4 -4
  104. package/dist/sdk/failure-condition-evaluator-HC3M5377.mjs +17 -0
  105. package/dist/sdk/{github-frontend-3N2NLO66.mjs → github-frontend-E2KJSC3Y.mjs} +7 -7
  106. package/dist/sdk/{host-ONVMEHAA.mjs → host-EE6EJ2FM.mjs} +4 -4
  107. package/dist/sdk/lazy-otel-5NH4ZJJM.mjs +24 -0
  108. package/dist/sdk/{liquid-extensions-5IZLTFSZ.mjs → liquid-extensions-E4EUOCES.mjs} +5 -5
  109. package/dist/sdk/memory-store-AAPL2MTE.mjs +12 -0
  110. package/dist/sdk/{metrics-GXQ2EDXA.mjs → metrics-I6A7IHG4.mjs} +3 -3
  111. package/dist/sdk/{prompt-state-YHGXB2OA.mjs → prompt-state-VAKKC773.mjs} +4 -4
  112. package/dist/sdk/{renderer-schema-CMXOLNIG.mjs → renderer-schema-HXEW6BRJ.mjs} +3 -3
  113. package/dist/sdk/{routing-S3Y7T2X3.mjs → routing-OZQWAGAI.mjs} +9 -8
  114. package/dist/sdk/schedule-tool-handler-B7TMSG6A.mjs +38 -0
  115. package/dist/sdk/schedule-tool-handler-IEB2VS7O.mjs +38 -0
  116. package/dist/sdk/sdk.d.mts +134 -4
  117. package/dist/sdk/sdk.d.ts +134 -4
  118. package/dist/sdk/sdk.js +2509 -1085
  119. package/dist/sdk/sdk.js.map +1 -1
  120. package/dist/sdk/sdk.mjs +14 -14
  121. package/dist/sdk/{slack-frontend-R3M2CACB.mjs → slack-frontend-LAY45IBR.mjs} +119 -29
  122. package/dist/sdk/slack-frontend-LAY45IBR.mjs.map +1 -0
  123. package/dist/sdk/{trace-helpers-YHNPC7MR.mjs → trace-helpers-PP3YHTAM.mjs} +3 -3
  124. package/dist/sdk/{tui-frontend-S546M7A7.mjs → tui-frontend-T56PZB67.mjs} +25 -16
  125. package/dist/sdk/tui-frontend-T56PZB67.mjs.map +1 -0
  126. package/dist/sdk/workflow-check-provider-2ET3SFZH.mjs +28 -0
  127. package/dist/sdk/workflow-check-provider-2ET3SFZH.mjs.map +1 -0
  128. package/dist/sdk/workflow-check-provider-HB4XTD4Z.mjs +28 -0
  129. package/dist/sdk/workflow-check-provider-HB4XTD4Z.mjs.map +1 -0
  130. package/dist/sdk/workflow-registry-AAD37XKZ.mjs +12 -0
  131. package/dist/sdk/workflow-registry-AAD37XKZ.mjs.map +1 -0
  132. package/dist/slack/client.d.ts +12 -0
  133. package/dist/slack/client.d.ts.map +1 -1
  134. package/dist/slack/slack-output-adapter.d.ts.map +1 -1
  135. package/dist/slack/socket-runner.d.ts.map +1 -1
  136. package/dist/state-machine/dispatch/execution-invoker.d.ts.map +1 -1
  137. package/dist/state-machine/dispatch/policy-gate.d.ts +28 -0
  138. package/dist/state-machine/dispatch/policy-gate.d.ts.map +1 -0
  139. package/dist/state-machine/states/level-dispatch.d.ts.map +1 -1
  140. package/dist/state-machine/states/routing.d.ts.map +1 -1
  141. package/dist/state-machine/states/wave-planning.d.ts.map +1 -1
  142. package/dist/state-machine-execution-engine.d.ts.map +1 -1
  143. package/dist/test-runner/core/flow-stage.d.ts.map +1 -1
  144. package/dist/test-runner/validator.d.ts.map +1 -1
  145. package/dist/traces/{run-2026-02-08T18-16-04-160Z.ndjson → run-2026-02-11T16-20-59-999Z.ndjson} +84 -84
  146. package/dist/{output/traces/run-2026-02-08T18-16-51-253Z.ndjson → traces/run-2026-02-11T16-21-47-711Z.ndjson} +1032 -1032
  147. package/dist/tui/chat-runner.d.ts.map +1 -1
  148. package/dist/tui/chat-state.d.ts +1 -0
  149. package/dist/tui/chat-state.d.ts.map +1 -1
  150. package/dist/tui/chat-tui.d.ts +3 -2
  151. package/dist/tui/chat-tui.d.ts.map +1 -1
  152. package/dist/tui/components/chat-box.d.ts +9 -0
  153. package/dist/tui/components/chat-box.d.ts.map +1 -1
  154. package/dist/tui/components/input-bar.d.ts +18 -1
  155. package/dist/tui/components/input-bar.d.ts.map +1 -1
  156. package/dist/tui/components/status-bar.d.ts +5 -2
  157. package/dist/tui/components/status-bar.d.ts.map +1 -1
  158. package/dist/tui/components/trace-viewer.d.ts +1 -0
  159. package/dist/tui/components/trace-viewer.d.ts.map +1 -1
  160. package/dist/tui/tui-frontend.d.ts.map +1 -1
  161. package/dist/types/config.d.ts +107 -3
  162. package/dist/types/config.d.ts.map +1 -1
  163. package/dist/types/engine.d.ts +5 -0
  164. package/dist/types/engine.d.ts.map +1 -1
  165. package/dist/types/execution.d.ts +1 -1
  166. package/dist/types/execution.d.ts.map +1 -1
  167. package/package.json +14 -4
  168. package/dist/sdk/check-provider-registry-ACRGIYOB.mjs +0 -28
  169. package/dist/sdk/check-provider-registry-VYHKFHK2.mjs +0 -28
  170. package/dist/sdk/chunk-7YSOINAQ.mjs.map +0 -1
  171. package/dist/sdk/chunk-BDGUM6BA.mjs.map +0 -1
  172. package/dist/sdk/chunk-DGZPPGJJ.mjs.map +0 -1
  173. package/dist/sdk/chunk-N7HO6KKC.mjs.map +0 -1
  174. package/dist/sdk/chunk-R5Z7YWPB.mjs.map +0 -1
  175. package/dist/sdk/chunk-SGS2VMEL.mjs.map +0 -1
  176. package/dist/sdk/failure-condition-evaluator-4WMDF4Q3.mjs +0 -17
  177. package/dist/sdk/memory-store-3N4AZCYB.mjs +0 -12
  178. package/dist/sdk/slack-frontend-R3M2CACB.mjs.map +0 -1
  179. package/dist/sdk/tui-frontend-S546M7A7.mjs.map +0 -1
  180. package/dist/sdk/workflow-check-provider-4F3432ZP.mjs +0 -28
  181. package/dist/sdk/workflow-check-provider-A44PBPG2.mjs +0 -28
  182. package/dist/sdk/workflow-registry-ZAYYXLEP.mjs +0 -12
  183. /package/dist/sdk/{check-provider-registry-ACRGIYOB.mjs.map → check-provider-registry-M3Y6JMTW.mjs.map} +0 -0
  184. /package/dist/sdk/{check-provider-registry-VYHKFHK2.mjs.map → check-provider-registry-PANIXYRB.mjs.map} +0 -0
  185. /package/dist/sdk/{chunk-D5KI4YQ4.mjs.map → chunk-DIND4ZCV.mjs.map} +0 -0
  186. /package/dist/sdk/{chunk-XDLQ3UNF.mjs.map → chunk-GEW6LS32.mjs.map} +0 -0
  187. /package/dist/sdk/{chunk-XR7XXGL7.mjs.map → chunk-JL7JXCET.mjs.map} +0 -0
  188. /package/dist/sdk/{chunk-6W75IMDC.mjs.map → chunk-LG4AUKHB.mjs.map} +0 -0
  189. /package/dist/sdk/{chunk-PO7X5XI7.mjs.map → chunk-SZXICFQ3.mjs.map} +0 -0
  190. /package/dist/sdk/{chunk-2KB35MB7.mjs.map → chunk-VPC3QSPW.mjs.map} +0 -0
  191. /package/dist/sdk/{chunk-J5RGJQ53.mjs.map → chunk-YJRBN3XS.mjs.map} +0 -0
  192. /package/dist/sdk/{command-executor-DVVXERLR.mjs.map → command-executor-TOYBBE7S.mjs.map} +0 -0
  193. /package/dist/sdk/{config-7VTT64SQ.mjs.map → config-OGOS4ZU4.mjs.map} +0 -0
  194. /package/dist/sdk/{failure-condition-evaluator-4WMDF4Q3.mjs.map → failure-condition-evaluator-HC3M5377.mjs.map} +0 -0
  195. /package/dist/sdk/{github-frontend-3N2NLO66.mjs.map → github-frontend-E2KJSC3Y.mjs.map} +0 -0
  196. /package/dist/sdk/{host-ONVMEHAA.mjs.map → host-EE6EJ2FM.mjs.map} +0 -0
  197. /package/dist/sdk/{liquid-extensions-5IZLTFSZ.mjs.map → lazy-otel-5NH4ZJJM.mjs.map} +0 -0
  198. /package/dist/sdk/{memory-store-3N4AZCYB.mjs.map → liquid-extensions-E4EUOCES.mjs.map} +0 -0
  199. /package/dist/sdk/{metrics-GXQ2EDXA.mjs.map → memory-store-AAPL2MTE.mjs.map} +0 -0
  200. /package/dist/sdk/{prompt-state-YHGXB2OA.mjs.map → metrics-I6A7IHG4.mjs.map} +0 -0
  201. /package/dist/sdk/{routing-S3Y7T2X3.mjs.map → prompt-state-VAKKC773.mjs.map} +0 -0
  202. /package/dist/sdk/{renderer-schema-CMXOLNIG.mjs.map → renderer-schema-HXEW6BRJ.mjs.map} +0 -0
  203. /package/dist/sdk/{trace-helpers-YHNPC7MR.mjs.map → routing-OZQWAGAI.mjs.map} +0 -0
  204. /package/dist/sdk/{workflow-check-provider-4F3432ZP.mjs.map → schedule-tool-handler-B7TMSG6A.mjs.map} +0 -0
  205. /package/dist/sdk/{workflow-check-provider-A44PBPG2.mjs.map → schedule-tool-handler-IEB2VS7O.mjs.map} +0 -0
  206. /package/dist/sdk/{workflow-registry-ZAYYXLEP.mjs.map → trace-helpers-PP3YHTAM.mjs.map} +0 -0
@@ -1,7 +1,15 @@
1
+ import {
2
+ getPromptStateManager,
3
+ init_prompt_state
4
+ } from "./chunk-LG4AUKHB.mjs";
1
5
  import {
2
6
  generateHumanId,
3
7
  init_human_id
4
8
  } from "./chunk-KFKHU6CM.mjs";
9
+ import {
10
+ init_tracer_init,
11
+ initializeTracer
12
+ } from "./chunk-B7BVQM5K.mjs";
5
13
  import {
6
14
  SessionRegistry,
7
15
  init_session_registry,
@@ -10,21 +18,17 @@ import {
10
18
  import {
11
19
  commandExecutor,
12
20
  init_command_executor
13
- } from "./chunk-XDLQ3UNF.mjs";
21
+ } from "./chunk-GEW6LS32.mjs";
14
22
  import {
15
23
  DependencyResolver,
16
24
  WorkflowRegistry,
17
25
  init_dependency_resolver,
18
26
  init_workflow_registry
19
- } from "./chunk-D5KI4YQ4.mjs";
27
+ } from "./chunk-DIND4ZCV.mjs";
20
28
  import {
21
29
  config_exports,
22
30
  init_config
23
- } from "./chunk-7YSOINAQ.mjs";
24
- import {
25
- getPromptStateManager,
26
- init_prompt_state
27
- } from "./chunk-6W75IMDC.mjs";
31
+ } from "./chunk-UCNT3PDT.mjs";
28
32
  import {
29
33
  ExecutionJournal,
30
34
  checkLoopBudget,
@@ -33,11 +37,11 @@ import {
33
37
  init_routing,
34
38
  init_snapshot_store,
35
39
  snapshot_store_exports
36
- } from "./chunk-SGS2VMEL.mjs";
40
+ } from "./chunk-VMLORODQ.mjs";
37
41
  import {
38
42
  FailureConditionEvaluator,
39
43
  init_failure_condition_evaluator
40
- } from "./chunk-N7HO6KKC.mjs";
44
+ } from "./chunk-HOKQOO3G.mjs";
41
45
  import {
42
46
  addEvent,
43
47
  emitNdjsonFallback,
@@ -48,15 +52,15 @@ import {
48
52
  setSpanAttributes,
49
53
  trace_helpers_exports,
50
54
  withActiveSpan
51
- } from "./chunk-J5RGJQ53.mjs";
55
+ } from "./chunk-YJRBN3XS.mjs";
52
56
  import {
53
57
  addDiagramBlock,
54
58
  init_metrics
55
- } from "./chunk-XR7XXGL7.mjs";
59
+ } from "./chunk-JL7JXCET.mjs";
56
60
  import {
57
61
  createExtendedLiquid,
58
62
  init_liquid_extensions
59
- } from "./chunk-R5Z7YWPB.mjs";
63
+ } from "./chunk-V2IV3ILA.mjs";
60
64
  import {
61
65
  createPermissionHelpers,
62
66
  detectLocalMode,
@@ -72,21 +76,18 @@ import {
72
76
  MemoryStore,
73
77
  init_memory_store,
74
78
  memory_store_exports
75
- } from "./chunk-2KB35MB7.mjs";
79
+ } from "./chunk-VPC3QSPW.mjs";
76
80
  import {
77
81
  init_logger,
78
- logger
79
- } from "./chunk-PO7X5XI7.mjs";
82
+ logger,
83
+ logger_exports
84
+ } from "./chunk-SZXICFQ3.mjs";
80
85
  import {
81
86
  context,
82
87
  init_lazy_otel,
83
88
  lazy_otel_exports,
84
89
  trace
85
- } from "./chunk-HEX3RL32.mjs";
86
- import {
87
- init_tracer_init,
88
- initializeTracer
89
- } from "./chunk-B7BVQM5K.mjs";
90
+ } from "./chunk-UCMJJ3IM.mjs";
90
91
  import {
91
92
  __commonJS,
92
93
  __esm,
@@ -115,7 +116,7 @@ async function processDiffWithOutline(diffContent) {
115
116
  }
116
117
  try {
117
118
  const originalProbePath = process.env.PROBE_PATH;
118
- const fs10 = __require("fs");
119
+ const fs11 = __require("fs");
119
120
  const possiblePaths = [
120
121
  // Relative to current working directory (most common in production)
121
122
  path.join(process.cwd(), "node_modules/@probelabs/probe/bin/probe-binary"),
@@ -126,7 +127,7 @@ async function processDiffWithOutline(diffContent) {
126
127
  ];
127
128
  let probeBinaryPath;
128
129
  for (const candidatePath of possiblePaths) {
129
- if (fs10.existsSync(candidatePath)) {
130
+ if (fs11.existsSync(candidatePath)) {
130
131
  probeBinaryPath = candidatePath;
131
132
  break;
132
133
  }
@@ -1188,8 +1189,8 @@ ${schemaString}`);
1188
1189
  }
1189
1190
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
1190
1191
  try {
1191
- const fs10 = __require("fs");
1192
- const path12 = __require("path");
1192
+ const fs11 = __require("fs");
1193
+ const path14 = __require("path");
1193
1194
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1194
1195
  const provider = this.config.provider || "auto";
1195
1196
  const model = this.config.model || "default";
@@ -1303,20 +1304,20 @@ ${"=".repeat(60)}
1303
1304
  `;
1304
1305
  readableVersion += `${"=".repeat(60)}
1305
1306
  `;
1306
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path12.join(process.cwd(), "debug-artifacts");
1307
- if (!fs10.existsSync(debugArtifactsDir)) {
1308
- fs10.mkdirSync(debugArtifactsDir, { recursive: true });
1307
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path14.join(process.cwd(), "debug-artifacts");
1308
+ if (!fs11.existsSync(debugArtifactsDir)) {
1309
+ fs11.mkdirSync(debugArtifactsDir, { recursive: true });
1309
1310
  }
1310
- const debugFile = path12.join(
1311
+ const debugFile = path14.join(
1311
1312
  debugArtifactsDir,
1312
1313
  `prompt-${_checkName || "unknown"}-${timestamp}.json`
1313
1314
  );
1314
- fs10.writeFileSync(debugFile, debugJson, "utf-8");
1315
- const readableFile = path12.join(
1315
+ fs11.writeFileSync(debugFile, debugJson, "utf-8");
1316
+ const readableFile = path14.join(
1316
1317
  debugArtifactsDir,
1317
1318
  `prompt-${_checkName || "unknown"}-${timestamp}.txt`
1318
1319
  );
1319
- fs10.writeFileSync(readableFile, readableVersion, "utf-8");
1320
+ fs11.writeFileSync(readableFile, readableVersion, "utf-8");
1320
1321
  log(`
1321
1322
  \u{1F4BE} Full debug info saved to:`);
1322
1323
  log(` JSON: ${debugFile}`);
@@ -1349,8 +1350,8 @@ ${"=".repeat(60)}
1349
1350
  log(`\u{1F4E4} Response length: ${response.length} characters`);
1350
1351
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
1351
1352
  try {
1352
- const fs10 = __require("fs");
1353
- const path12 = __require("path");
1353
+ const fs11 = __require("fs");
1354
+ const path14 = __require("path");
1354
1355
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1355
1356
  const agentAny2 = agent;
1356
1357
  let fullHistory = [];
@@ -1361,8 +1362,8 @@ ${"=".repeat(60)}
1361
1362
  } else if (agentAny2._messages) {
1362
1363
  fullHistory = agentAny2._messages;
1363
1364
  }
1364
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path12.join(process.cwd(), "debug-artifacts");
1365
- const sessionBase = path12.join(
1365
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path14.join(process.cwd(), "debug-artifacts");
1366
+ const sessionBase = path14.join(
1366
1367
  debugArtifactsDir,
1367
1368
  `session-${_checkName || "unknown"}-${timestamp}`
1368
1369
  );
@@ -1374,7 +1375,7 @@ ${"=".repeat(60)}
1374
1375
  schema: effectiveSchema,
1375
1376
  totalMessages: fullHistory.length
1376
1377
  };
1377
- fs10.writeFileSync(sessionBase + ".json", JSON.stringify(sessionData, null, 2), "utf-8");
1378
+ fs11.writeFileSync(sessionBase + ".json", JSON.stringify(sessionData, null, 2), "utf-8");
1378
1379
  let readable = `=============================================================
1379
1380
  `;
1380
1381
  readable += `COMPLETE AI SESSION HISTORY (AFTER RESPONSE)
@@ -1401,7 +1402,7 @@ ${"=".repeat(60)}
1401
1402
  `;
1402
1403
  readable += content + "\n";
1403
1404
  });
1404
- fs10.writeFileSync(sessionBase + ".summary.txt", readable, "utf-8");
1405
+ fs11.writeFileSync(sessionBase + ".summary.txt", readable, "utf-8");
1405
1406
  log(`\u{1F4BE} Complete session history saved:`);
1406
1407
  log(` - Contains ALL ${fullHistory.length} messages (prompts + responses)`);
1407
1408
  } catch (error) {
@@ -1410,11 +1411,11 @@ ${"=".repeat(60)}
1410
1411
  }
1411
1412
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
1412
1413
  try {
1413
- const fs10 = __require("fs");
1414
- const path12 = __require("path");
1414
+ const fs11 = __require("fs");
1415
+ const path14 = __require("path");
1415
1416
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1416
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path12.join(process.cwd(), "debug-artifacts");
1417
- const responseFile = path12.join(
1417
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path14.join(process.cwd(), "debug-artifacts");
1418
+ const responseFile = path14.join(
1418
1419
  debugArtifactsDir,
1419
1420
  `response-${_checkName || "unknown"}-${timestamp}.txt`
1420
1421
  );
@@ -1447,7 +1448,7 @@ ${"=".repeat(60)}
1447
1448
  `;
1448
1449
  responseContent += `${"=".repeat(60)}
1449
1450
  `;
1450
- fs10.writeFileSync(responseFile, responseContent, "utf-8");
1451
+ fs11.writeFileSync(responseFile, responseContent, "utf-8");
1451
1452
  log(`\u{1F4BE} Response saved to: ${responseFile}`);
1452
1453
  } catch (error) {
1453
1454
  log(`\u26A0\uFE0F Could not save response file: ${error}`);
@@ -1463,9 +1464,9 @@ ${"=".repeat(60)}
1463
1464
  await agentAny._telemetryConfig.shutdown();
1464
1465
  log(`\u{1F4CA} OpenTelemetry trace saved to: ${agentAny._traceFilePath}`);
1465
1466
  if (process.env.GITHUB_ACTIONS) {
1466
- const fs10 = __require("fs");
1467
- if (fs10.existsSync(agentAny._traceFilePath)) {
1468
- const stats = fs10.statSync(agentAny._traceFilePath);
1467
+ const fs11 = __require("fs");
1468
+ if (fs11.existsSync(agentAny._traceFilePath)) {
1469
+ const stats = fs11.statSync(agentAny._traceFilePath);
1469
1470
  console.log(
1470
1471
  `::notice title=AI Trace Saved::${agentAny._traceFilePath} (${stats.size} bytes)`
1471
1472
  );
@@ -1660,8 +1661,8 @@ ${schemaString}`);
1660
1661
  const model = this.config.model || "default";
1661
1662
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
1662
1663
  try {
1663
- const fs10 = __require("fs");
1664
- const path12 = __require("path");
1664
+ const fs11 = __require("fs");
1665
+ const path14 = __require("path");
1665
1666
  const os = __require("os");
1666
1667
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1667
1668
  const debugData = {
@@ -1735,18 +1736,18 @@ ${"=".repeat(60)}
1735
1736
  readableVersion += `${"=".repeat(60)}
1736
1737
  `;
1737
1738
  const tempDir = os.tmpdir();
1738
- const promptFile = path12.join(tempDir, `visor-prompt-${timestamp}.txt`);
1739
- fs10.writeFileSync(promptFile, prompt, "utf-8");
1739
+ const promptFile = path14.join(tempDir, `visor-prompt-${timestamp}.txt`);
1740
+ fs11.writeFileSync(promptFile, prompt, "utf-8");
1740
1741
  log(`
1741
1742
  \u{1F4BE} Prompt saved to: ${promptFile}`);
1742
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path12.join(process.cwd(), "debug-artifacts");
1743
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path14.join(process.cwd(), "debug-artifacts");
1743
1744
  try {
1744
- const base = path12.join(
1745
+ const base = path14.join(
1745
1746
  debugArtifactsDir,
1746
1747
  `prompt-${_checkName || "unknown"}-${timestamp}`
1747
1748
  );
1748
- fs10.writeFileSync(base + ".json", debugJson, "utf-8");
1749
- fs10.writeFileSync(base + ".summary.txt", readableVersion, "utf-8");
1749
+ fs11.writeFileSync(base + ".json", debugJson, "utf-8");
1750
+ fs11.writeFileSync(base + ".summary.txt", readableVersion, "utf-8");
1750
1751
  log(`
1751
1752
  \u{1F4BE} Full debug info saved to directory: ${debugArtifactsDir}`);
1752
1753
  } catch {
@@ -1791,8 +1792,8 @@ $ ${cliCommand}
1791
1792
  log(`\u{1F4E4} Response length: ${response.length} characters`);
1792
1793
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
1793
1794
  try {
1794
- const fs10 = __require("fs");
1795
- const path12 = __require("path");
1795
+ const fs11 = __require("fs");
1796
+ const path14 = __require("path");
1796
1797
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1797
1798
  const agentAny = agent;
1798
1799
  let fullHistory = [];
@@ -1803,8 +1804,8 @@ $ ${cliCommand}
1803
1804
  } else if (agentAny._messages) {
1804
1805
  fullHistory = agentAny._messages;
1805
1806
  }
1806
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path12.join(process.cwd(), "debug-artifacts");
1807
- const sessionBase = path12.join(
1807
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path14.join(process.cwd(), "debug-artifacts");
1808
+ const sessionBase = path14.join(
1808
1809
  debugArtifactsDir,
1809
1810
  `session-${_checkName || "unknown"}-${timestamp}`
1810
1811
  );
@@ -1816,7 +1817,7 @@ $ ${cliCommand}
1816
1817
  schema: effectiveSchema,
1817
1818
  totalMessages: fullHistory.length
1818
1819
  };
1819
- fs10.writeFileSync(sessionBase + ".json", JSON.stringify(sessionData, null, 2), "utf-8");
1820
+ fs11.writeFileSync(sessionBase + ".json", JSON.stringify(sessionData, null, 2), "utf-8");
1820
1821
  let readable = `=============================================================
1821
1822
  `;
1822
1823
  readable += `COMPLETE AI SESSION HISTORY (AFTER RESPONSE)
@@ -1843,7 +1844,7 @@ ${"=".repeat(60)}
1843
1844
  `;
1844
1845
  readable += content + "\n";
1845
1846
  });
1846
- fs10.writeFileSync(sessionBase + ".summary.txt", readable, "utf-8");
1847
+ fs11.writeFileSync(sessionBase + ".summary.txt", readable, "utf-8");
1847
1848
  log(`\u{1F4BE} Complete session history saved:`);
1848
1849
  log(` - Contains ALL ${fullHistory.length} messages (prompts + responses)`);
1849
1850
  } catch (error) {
@@ -1852,11 +1853,11 @@ ${"=".repeat(60)}
1852
1853
  }
1853
1854
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
1854
1855
  try {
1855
- const fs10 = __require("fs");
1856
- const path12 = __require("path");
1856
+ const fs11 = __require("fs");
1857
+ const path14 = __require("path");
1857
1858
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1858
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path12.join(process.cwd(), "debug-artifacts");
1859
- const responseFile = path12.join(
1859
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path14.join(process.cwd(), "debug-artifacts");
1860
+ const responseFile = path14.join(
1860
1861
  debugArtifactsDir,
1861
1862
  `response-${_checkName || "unknown"}-${timestamp}.txt`
1862
1863
  );
@@ -1889,7 +1890,7 @@ ${"=".repeat(60)}
1889
1890
  `;
1890
1891
  responseContent += `${"=".repeat(60)}
1891
1892
  `;
1892
- fs10.writeFileSync(responseFile, responseContent, "utf-8");
1893
+ fs11.writeFileSync(responseFile, responseContent, "utf-8");
1893
1894
  log(`\u{1F4BE} Response saved to: ${responseFile}`);
1894
1895
  } catch (error) {
1895
1896
  log(`\u26A0\uFE0F Could not save response file: ${error}`);
@@ -1907,9 +1908,9 @@ ${"=".repeat(60)}
1907
1908
  await telemetry.shutdown();
1908
1909
  log(`\u{1F4CA} OpenTelemetry trace saved to: ${traceFilePath}`);
1909
1910
  if (process.env.GITHUB_ACTIONS) {
1910
- const fs10 = __require("fs");
1911
- if (fs10.existsSync(traceFilePath)) {
1912
- const stats = fs10.statSync(traceFilePath);
1911
+ const fs11 = __require("fs");
1912
+ if (fs11.existsSync(traceFilePath)) {
1913
+ const stats = fs11.statSync(traceFilePath);
1913
1914
  console.log(
1914
1915
  `::notice title=AI Trace Saved::OpenTelemetry trace file size: ${stats.size} bytes`
1915
1916
  );
@@ -1947,8 +1948,8 @@ ${"=".repeat(60)}
1947
1948
  * Load schema content from schema files or inline definitions
1948
1949
  */
1949
1950
  async loadSchemaContent(schema) {
1950
- const fs10 = __require("fs").promises;
1951
- const path12 = __require("path");
1951
+ const fs11 = __require("fs").promises;
1952
+ const path14 = __require("path");
1952
1953
  if (typeof schema === "object" && schema !== null) {
1953
1954
  log("\u{1F4CB} Using inline schema object from configuration");
1954
1955
  return JSON.stringify(schema);
@@ -1961,14 +1962,14 @@ ${"=".repeat(60)}
1961
1962
  }
1962
1963
  } catch {
1963
1964
  }
1964
- if ((schema.startsWith("./") || schema.includes(".json")) && !path12.isAbsolute(schema)) {
1965
+ if ((schema.startsWith("./") || schema.includes(".json")) && !path14.isAbsolute(schema)) {
1965
1966
  if (schema.includes("..") || schema.includes("\0")) {
1966
1967
  throw new Error("Invalid schema path: path traversal not allowed");
1967
1968
  }
1968
1969
  try {
1969
- const schemaPath = path12.resolve(process.cwd(), schema);
1970
+ const schemaPath = path14.resolve(process.cwd(), schema);
1970
1971
  log(`\u{1F4CB} Loading custom schema from file: ${schemaPath}`);
1971
- const schemaContent = await fs10.readFile(schemaPath, "utf-8");
1972
+ const schemaContent = await fs11.readFile(schemaPath, "utf-8");
1972
1973
  return schemaContent.trim();
1973
1974
  } catch (error) {
1974
1975
  throw new Error(
@@ -1982,22 +1983,22 @@ ${"=".repeat(60)}
1982
1983
  }
1983
1984
  const candidatePaths = [
1984
1985
  // GitHub Action bundle location
1985
- path12.join(__dirname, "output", sanitizedSchemaName, "schema.json"),
1986
+ path14.join(__dirname, "output", sanitizedSchemaName, "schema.json"),
1986
1987
  // Historical fallback when src/output was inadvertently bundled as output1/
1987
- path12.join(__dirname, "output1", sanitizedSchemaName, "schema.json"),
1988
+ path14.join(__dirname, "output1", sanitizedSchemaName, "schema.json"),
1988
1989
  // Local dev (repo root)
1989
- path12.join(process.cwd(), "output", sanitizedSchemaName, "schema.json")
1990
+ path14.join(process.cwd(), "output", sanitizedSchemaName, "schema.json")
1990
1991
  ];
1991
1992
  for (const schemaPath of candidatePaths) {
1992
1993
  try {
1993
- const schemaContent = await fs10.readFile(schemaPath, "utf-8");
1994
+ const schemaContent = await fs11.readFile(schemaPath, "utf-8");
1994
1995
  return schemaContent.trim();
1995
1996
  } catch {
1996
1997
  }
1997
1998
  }
1998
- const distPath = path12.join(__dirname, "output", sanitizedSchemaName, "schema.json");
1999
- const distAltPath = path12.join(__dirname, "output1", sanitizedSchemaName, "schema.json");
2000
- const cwdPath = path12.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
1999
+ const distPath = path14.join(__dirname, "output", sanitizedSchemaName, "schema.json");
2000
+ const distAltPath = path14.join(__dirname, "output1", sanitizedSchemaName, "schema.json");
2001
+ const cwdPath = path14.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
2001
2002
  throw new Error(
2002
2003
  `Failed to load schema '${sanitizedSchemaName}'. Tried: ${distPath}, ${distAltPath}, and ${cwdPath}. Ensure build copies 'output/' into dist (build:cli), or provide a custom schema file/path.`
2003
2004
  );
@@ -2188,7 +2189,7 @@ ${"=".repeat(60)}
2188
2189
  * Generate mock response for testing
2189
2190
  */
2190
2191
  async generateMockResponse(_prompt, _checkName, _schema) {
2191
- await new Promise((resolve5) => setTimeout(resolve5, 500));
2192
+ await new Promise((resolve6) => setTimeout(resolve6, 500));
2192
2193
  const name = (_checkName || "").toLowerCase();
2193
2194
  if (name.includes("extract-facts")) {
2194
2195
  const arr = Array.from({ length: 6 }, (_, i) => ({
@@ -2996,7 +2997,7 @@ async function executeWorkflowAsTool(workflowId, args, context2, argsOverrides)
2996
2997
  ...args,
2997
2998
  ...argsOverrides
2998
2999
  };
2999
- const { WorkflowCheckProvider: WorkflowCheckProvider2 } = await import("./workflow-check-provider-4F3432ZP.mjs");
3000
+ const { WorkflowCheckProvider: WorkflowCheckProvider2 } = await import("./workflow-check-provider-HB4XTD4Z.mjs");
3000
3001
  const provider = new WorkflowCheckProvider2();
3001
3002
  const checkConfig = {
3002
3003
  type: "workflow",
@@ -3054,38 +3055,569 @@ var init_workflow_tool_executor = __esm({
3054
3055
  }
3055
3056
  });
3056
3057
 
3057
- // src/scheduler/schedule-store.ts
3058
- import fs2 from "fs/promises";
3058
+ // src/scheduler/store/sqlite-store.ts
3059
3059
  import path3 from "path";
3060
+ import fs2 from "fs";
3060
3061
  import { v4 as uuidv4 } from "uuid";
3062
+ function toDbRow(schedule) {
3063
+ return {
3064
+ id: schedule.id,
3065
+ creator_id: schedule.creatorId,
3066
+ creator_context: schedule.creatorContext ?? null,
3067
+ creator_name: schedule.creatorName ?? null,
3068
+ timezone: schedule.timezone,
3069
+ schedule_expr: schedule.schedule,
3070
+ run_at: schedule.runAt ?? null,
3071
+ is_recurring: schedule.isRecurring ? 1 : 0,
3072
+ original_expression: schedule.originalExpression,
3073
+ workflow: schedule.workflow ?? null,
3074
+ workflow_inputs: schedule.workflowInputs ? JSON.stringify(schedule.workflowInputs) : null,
3075
+ output_context: schedule.outputContext ? JSON.stringify(schedule.outputContext) : null,
3076
+ status: schedule.status,
3077
+ created_at: schedule.createdAt,
3078
+ last_run_at: schedule.lastRunAt ?? null,
3079
+ next_run_at: schedule.nextRunAt ?? null,
3080
+ run_count: schedule.runCount,
3081
+ failure_count: schedule.failureCount,
3082
+ last_error: schedule.lastError ?? null,
3083
+ previous_response: schedule.previousResponse ?? null
3084
+ };
3085
+ }
3086
+ function safeJsonParse(value) {
3087
+ if (!value) return void 0;
3088
+ try {
3089
+ return JSON.parse(value);
3090
+ } catch {
3091
+ return void 0;
3092
+ }
3093
+ }
3094
+ function fromDbRow(row) {
3095
+ return {
3096
+ id: row.id,
3097
+ creatorId: row.creator_id,
3098
+ creatorContext: row.creator_context ?? void 0,
3099
+ creatorName: row.creator_name ?? void 0,
3100
+ timezone: row.timezone,
3101
+ schedule: row.schedule_expr,
3102
+ runAt: row.run_at ?? void 0,
3103
+ isRecurring: row.is_recurring === 1,
3104
+ originalExpression: row.original_expression,
3105
+ workflow: row.workflow ?? void 0,
3106
+ workflowInputs: safeJsonParse(row.workflow_inputs),
3107
+ outputContext: safeJsonParse(row.output_context),
3108
+ status: row.status,
3109
+ createdAt: row.created_at,
3110
+ lastRunAt: row.last_run_at ?? void 0,
3111
+ nextRunAt: row.next_run_at ?? void 0,
3112
+ runCount: row.run_count,
3113
+ failureCount: row.failure_count,
3114
+ lastError: row.last_error ?? void 0,
3115
+ previousResponse: row.previous_response ?? void 0
3116
+ };
3117
+ }
3118
+ var SqliteStoreBackend;
3119
+ var init_sqlite_store = __esm({
3120
+ "src/scheduler/store/sqlite-store.ts"() {
3121
+ "use strict";
3122
+ init_logger();
3123
+ SqliteStoreBackend = class {
3124
+ db = null;
3125
+ dbPath;
3126
+ // In-memory locks (single-node only; SQLite doesn't support distributed locking)
3127
+ locks = /* @__PURE__ */ new Map();
3128
+ constructor(filename) {
3129
+ this.dbPath = filename || ".visor/schedules.db";
3130
+ }
3131
+ async initialize() {
3132
+ const resolvedPath = path3.resolve(process.cwd(), this.dbPath);
3133
+ const dir = path3.dirname(resolvedPath);
3134
+ fs2.mkdirSync(dir, { recursive: true });
3135
+ const { createRequire } = __require("module");
3136
+ const runtimeRequire = createRequire(__filename);
3137
+ let Database;
3138
+ try {
3139
+ Database = runtimeRequire("better-sqlite3");
3140
+ } catch (err) {
3141
+ const code = err?.code;
3142
+ if (code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND") {
3143
+ throw new Error(
3144
+ "better-sqlite3 is required for SQLite schedule storage. Install it with: npm install better-sqlite3"
3145
+ );
3146
+ }
3147
+ throw err;
3148
+ }
3149
+ this.db = new Database(resolvedPath);
3150
+ this.db.pragma("journal_mode = WAL");
3151
+ this.migrateSchema();
3152
+ logger.info(`[SqliteStore] Initialized at ${this.dbPath}`);
3153
+ }
3154
+ async shutdown() {
3155
+ if (this.db) {
3156
+ this.db.close();
3157
+ this.db = null;
3158
+ }
3159
+ this.locks.clear();
3160
+ }
3161
+ // --- Schema Migration ---
3162
+ migrateSchema() {
3163
+ const db = this.getDb();
3164
+ db.exec(`
3165
+ CREATE TABLE IF NOT EXISTS schedules (
3166
+ id VARCHAR(36) PRIMARY KEY,
3167
+ creator_id VARCHAR(255) NOT NULL,
3168
+ creator_context VARCHAR(255),
3169
+ creator_name VARCHAR(255),
3170
+ timezone VARCHAR(64) NOT NULL DEFAULT 'UTC',
3171
+ schedule_expr VARCHAR(255),
3172
+ run_at BIGINT,
3173
+ is_recurring BOOLEAN NOT NULL,
3174
+ original_expression TEXT,
3175
+ workflow VARCHAR(255),
3176
+ workflow_inputs TEXT,
3177
+ output_context TEXT,
3178
+ status VARCHAR(20) NOT NULL,
3179
+ created_at BIGINT NOT NULL,
3180
+ last_run_at BIGINT,
3181
+ next_run_at BIGINT,
3182
+ run_count INTEGER NOT NULL DEFAULT 0,
3183
+ failure_count INTEGER NOT NULL DEFAULT 0,
3184
+ last_error TEXT,
3185
+ previous_response TEXT,
3186
+ claimed_by VARCHAR(255),
3187
+ claimed_at BIGINT,
3188
+ lock_token VARCHAR(36)
3189
+ );
3190
+
3191
+ CREATE INDEX IF NOT EXISTS idx_schedules_creator_id
3192
+ ON schedules(creator_id);
3193
+
3194
+ CREATE INDEX IF NOT EXISTS idx_schedules_status
3195
+ ON schedules(status);
3196
+
3197
+ CREATE INDEX IF NOT EXISTS idx_schedules_status_next_run
3198
+ ON schedules(status, next_run_at);
3199
+
3200
+ CREATE TABLE IF NOT EXISTS scheduler_locks (
3201
+ lock_id VARCHAR(255) PRIMARY KEY,
3202
+ node_id VARCHAR(255) NOT NULL,
3203
+ lock_token VARCHAR(36) NOT NULL,
3204
+ acquired_at BIGINT NOT NULL,
3205
+ expires_at BIGINT NOT NULL
3206
+ );
3207
+ `);
3208
+ }
3209
+ // --- Helpers ---
3210
+ getDb() {
3211
+ if (!this.db) {
3212
+ throw new Error("[SqliteStore] Database not initialized. Call initialize() first.");
3213
+ }
3214
+ return this.db;
3215
+ }
3216
+ // --- CRUD ---
3217
+ async create(schedule) {
3218
+ const db = this.getDb();
3219
+ const newSchedule = {
3220
+ ...schedule,
3221
+ id: uuidv4(),
3222
+ createdAt: Date.now(),
3223
+ runCount: 0,
3224
+ failureCount: 0,
3225
+ status: "active"
3226
+ };
3227
+ const row = toDbRow(newSchedule);
3228
+ db.prepare(
3229
+ `
3230
+ INSERT INTO schedules (
3231
+ id, creator_id, creator_context, creator_name, timezone,
3232
+ schedule_expr, run_at, is_recurring, original_expression,
3233
+ workflow, workflow_inputs, output_context,
3234
+ status, created_at, last_run_at, next_run_at,
3235
+ run_count, failure_count, last_error, previous_response
3236
+ ) VALUES (
3237
+ ?, ?, ?, ?, ?,
3238
+ ?, ?, ?, ?,
3239
+ ?, ?, ?,
3240
+ ?, ?, ?, ?,
3241
+ ?, ?, ?, ?
3242
+ )
3243
+ `
3244
+ ).run(
3245
+ row.id,
3246
+ row.creator_id,
3247
+ row.creator_context,
3248
+ row.creator_name,
3249
+ row.timezone,
3250
+ row.schedule_expr,
3251
+ row.run_at,
3252
+ row.is_recurring,
3253
+ row.original_expression,
3254
+ row.workflow,
3255
+ row.workflow_inputs,
3256
+ row.output_context,
3257
+ row.status,
3258
+ row.created_at,
3259
+ row.last_run_at,
3260
+ row.next_run_at,
3261
+ row.run_count,
3262
+ row.failure_count,
3263
+ row.last_error,
3264
+ row.previous_response
3265
+ );
3266
+ logger.info(
3267
+ `[SqliteStore] Created schedule ${newSchedule.id} for user ${newSchedule.creatorId}`
3268
+ );
3269
+ return newSchedule;
3270
+ }
3271
+ async importSchedule(schedule) {
3272
+ const db = this.getDb();
3273
+ const row = toDbRow(schedule);
3274
+ db.prepare(
3275
+ `
3276
+ INSERT OR IGNORE INTO schedules (
3277
+ id, creator_id, creator_context, creator_name, timezone,
3278
+ schedule_expr, run_at, is_recurring, original_expression,
3279
+ workflow, workflow_inputs, output_context,
3280
+ status, created_at, last_run_at, next_run_at,
3281
+ run_count, failure_count, last_error, previous_response
3282
+ ) VALUES (
3283
+ ?, ?, ?, ?, ?,
3284
+ ?, ?, ?, ?,
3285
+ ?, ?, ?,
3286
+ ?, ?, ?, ?,
3287
+ ?, ?, ?, ?
3288
+ )
3289
+ `
3290
+ ).run(
3291
+ row.id,
3292
+ row.creator_id,
3293
+ row.creator_context,
3294
+ row.creator_name,
3295
+ row.timezone,
3296
+ row.schedule_expr,
3297
+ row.run_at,
3298
+ row.is_recurring,
3299
+ row.original_expression,
3300
+ row.workflow,
3301
+ row.workflow_inputs,
3302
+ row.output_context,
3303
+ row.status,
3304
+ row.created_at,
3305
+ row.last_run_at,
3306
+ row.next_run_at,
3307
+ row.run_count,
3308
+ row.failure_count,
3309
+ row.last_error,
3310
+ row.previous_response
3311
+ );
3312
+ }
3313
+ async get(id) {
3314
+ const db = this.getDb();
3315
+ const row = db.prepare("SELECT * FROM schedules WHERE id = ?").get(id);
3316
+ return row ? fromDbRow(row) : void 0;
3317
+ }
3318
+ async update(id, patch) {
3319
+ const db = this.getDb();
3320
+ const existing = db.prepare("SELECT * FROM schedules WHERE id = ?").get(id);
3321
+ if (!existing) return void 0;
3322
+ const current = fromDbRow(existing);
3323
+ const updated = { ...current, ...patch, id: current.id };
3324
+ const row = toDbRow(updated);
3325
+ db.prepare(
3326
+ `
3327
+ UPDATE schedules SET
3328
+ creator_id = ?, creator_context = ?, creator_name = ?, timezone = ?,
3329
+ schedule_expr = ?, run_at = ?, is_recurring = ?, original_expression = ?,
3330
+ workflow = ?, workflow_inputs = ?, output_context = ?,
3331
+ status = ?, last_run_at = ?, next_run_at = ?,
3332
+ run_count = ?, failure_count = ?, last_error = ?, previous_response = ?
3333
+ WHERE id = ?
3334
+ `
3335
+ ).run(
3336
+ row.creator_id,
3337
+ row.creator_context,
3338
+ row.creator_name,
3339
+ row.timezone,
3340
+ row.schedule_expr,
3341
+ row.run_at,
3342
+ row.is_recurring,
3343
+ row.original_expression,
3344
+ row.workflow,
3345
+ row.workflow_inputs,
3346
+ row.output_context,
3347
+ row.status,
3348
+ row.last_run_at,
3349
+ row.next_run_at,
3350
+ row.run_count,
3351
+ row.failure_count,
3352
+ row.last_error,
3353
+ row.previous_response,
3354
+ row.id
3355
+ );
3356
+ return updated;
3357
+ }
3358
+ async delete(id) {
3359
+ const db = this.getDb();
3360
+ const result = db.prepare("DELETE FROM schedules WHERE id = ?").run(id);
3361
+ if (result.changes > 0) {
3362
+ logger.info(`[SqliteStore] Deleted schedule ${id}`);
3363
+ return true;
3364
+ }
3365
+ return false;
3366
+ }
3367
+ // --- Queries ---
3368
+ async getByCreator(creatorId) {
3369
+ const db = this.getDb();
3370
+ const rows = db.prepare("SELECT * FROM schedules WHERE creator_id = ?").all(creatorId);
3371
+ return rows.map(fromDbRow);
3372
+ }
3373
+ async getActiveSchedules() {
3374
+ const db = this.getDb();
3375
+ const rows = db.prepare("SELECT * FROM schedules WHERE status = 'active'").all();
3376
+ return rows.map(fromDbRow);
3377
+ }
3378
+ async getDueSchedules(now) {
3379
+ const ts = now ?? Date.now();
3380
+ const db = this.getDb();
3381
+ const rows = db.prepare(
3382
+ `SELECT * FROM schedules
3383
+ WHERE status = 'active'
3384
+ AND (
3385
+ (is_recurring = 0 AND run_at IS NOT NULL AND run_at <= ?)
3386
+ OR
3387
+ (is_recurring = 1 AND next_run_at IS NOT NULL AND next_run_at <= ?)
3388
+ )`
3389
+ ).all(ts, ts);
3390
+ return rows.map(fromDbRow);
3391
+ }
3392
+ async findByWorkflow(creatorId, workflowName) {
3393
+ const db = this.getDb();
3394
+ const escaped = workflowName.toLowerCase().replace(/[%_\\]/g, "\\$&");
3395
+ const pattern = `%${escaped}%`;
3396
+ const rows = db.prepare(
3397
+ `SELECT * FROM schedules
3398
+ WHERE creator_id = ? AND status = 'active'
3399
+ AND LOWER(workflow) LIKE ? ESCAPE '\\'`
3400
+ ).all(creatorId, pattern);
3401
+ return rows.map(fromDbRow);
3402
+ }
3403
+ async getAll() {
3404
+ const db = this.getDb();
3405
+ const rows = db.prepare("SELECT * FROM schedules").all();
3406
+ return rows.map(fromDbRow);
3407
+ }
3408
+ async getStats() {
3409
+ const db = this.getDb();
3410
+ const row = db.prepare(
3411
+ `SELECT
3412
+ COUNT(*) as total,
3413
+ SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active,
3414
+ SUM(CASE WHEN status = 'paused' THEN 1 ELSE 0 END) as paused,
3415
+ SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
3416
+ SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed,
3417
+ SUM(CASE WHEN is_recurring = 1 THEN 1 ELSE 0 END) as recurring,
3418
+ SUM(CASE WHEN is_recurring = 0 THEN 1 ELSE 0 END) as one_time
3419
+ FROM schedules`
3420
+ ).get();
3421
+ return {
3422
+ total: row.total,
3423
+ active: row.active,
3424
+ paused: row.paused,
3425
+ completed: row.completed,
3426
+ failed: row.failed,
3427
+ recurring: row.recurring,
3428
+ oneTime: row.one_time
3429
+ };
3430
+ }
3431
+ async validateLimits(creatorId, isRecurring, limits) {
3432
+ const db = this.getDb();
3433
+ if (limits.maxGlobal) {
3434
+ const row = db.prepare("SELECT COUNT(*) as cnt FROM schedules").get();
3435
+ if (row.cnt >= limits.maxGlobal) {
3436
+ throw new Error(`Global schedule limit reached (${limits.maxGlobal})`);
3437
+ }
3438
+ }
3439
+ if (limits.maxPerUser) {
3440
+ const row = db.prepare("SELECT COUNT(*) as cnt FROM schedules WHERE creator_id = ?").get(creatorId);
3441
+ if (row.cnt >= limits.maxPerUser) {
3442
+ throw new Error(`You have reached the maximum number of schedules (${limits.maxPerUser})`);
3443
+ }
3444
+ }
3445
+ if (isRecurring && limits.maxRecurringPerUser) {
3446
+ const row = db.prepare("SELECT COUNT(*) as cnt FROM schedules WHERE creator_id = ? AND is_recurring = 1").get(creatorId);
3447
+ if (row.cnt >= limits.maxRecurringPerUser) {
3448
+ throw new Error(
3449
+ `You have reached the maximum number of recurring schedules (${limits.maxRecurringPerUser})`
3450
+ );
3451
+ }
3452
+ }
3453
+ }
3454
+ // --- HA Locking (in-memory for SQLite — single-node only) ---
3455
+ async tryAcquireLock(scheduleId, nodeId, ttlSeconds) {
3456
+ const now = Date.now();
3457
+ const existing = this.locks.get(scheduleId);
3458
+ if (existing && existing.expiresAt > now) {
3459
+ if (existing.nodeId === nodeId) {
3460
+ return existing.token;
3461
+ }
3462
+ return null;
3463
+ }
3464
+ const token = uuidv4();
3465
+ this.locks.set(scheduleId, {
3466
+ nodeId,
3467
+ token,
3468
+ expiresAt: now + ttlSeconds * 1e3
3469
+ });
3470
+ return token;
3471
+ }
3472
+ async releaseLock(scheduleId, lockToken) {
3473
+ const existing = this.locks.get(scheduleId);
3474
+ if (existing && existing.token === lockToken) {
3475
+ this.locks.delete(scheduleId);
3476
+ }
3477
+ }
3478
+ async renewLock(scheduleId, lockToken, ttlSeconds) {
3479
+ const existing = this.locks.get(scheduleId);
3480
+ if (!existing || existing.token !== lockToken) {
3481
+ return false;
3482
+ }
3483
+ existing.expiresAt = Date.now() + ttlSeconds * 1e3;
3484
+ return true;
3485
+ }
3486
+ async flush() {
3487
+ }
3488
+ };
3489
+ }
3490
+ });
3491
+
3492
+ // src/scheduler/store/index.ts
3493
+ async function createStoreBackend(storageConfig, haConfig) {
3494
+ const driver = storageConfig?.driver || "sqlite";
3495
+ switch (driver) {
3496
+ case "sqlite": {
3497
+ const conn = storageConfig?.connection;
3498
+ return new SqliteStoreBackend(conn?.filename);
3499
+ }
3500
+ case "postgresql":
3501
+ case "mysql":
3502
+ case "mssql": {
3503
+ try {
3504
+ const loaderPath = "../../enterprise/loader";
3505
+ const { loadEnterpriseStoreBackend } = await import(loaderPath);
3506
+ return await loadEnterpriseStoreBackend(driver, storageConfig, haConfig);
3507
+ } catch (err) {
3508
+ const msg = err instanceof Error ? err.message : String(err);
3509
+ logger.error(`[StoreFactory] Failed to load enterprise ${driver} backend: ${msg}`);
3510
+ throw new Error(
3511
+ `The ${driver} schedule storage driver requires a Visor Enterprise license. Install the enterprise package or use driver: 'sqlite' (default). Original error: ${msg}`
3512
+ );
3513
+ }
3514
+ }
3515
+ default:
3516
+ throw new Error(`Unknown schedule storage driver: ${driver}`);
3517
+ }
3518
+ }
3519
+ var init_store = __esm({
3520
+ "src/scheduler/store/index.ts"() {
3521
+ "use strict";
3522
+ init_logger();
3523
+ init_sqlite_store();
3524
+ }
3525
+ });
3526
+
3527
+ // src/scheduler/store/json-migrator.ts
3528
+ import fs3 from "fs/promises";
3529
+ import path4 from "path";
3530
+ async function migrateJsonToBackend(jsonPath, backend) {
3531
+ const resolvedPath = path4.resolve(process.cwd(), jsonPath);
3532
+ let content;
3533
+ try {
3534
+ content = await fs3.readFile(resolvedPath, "utf-8");
3535
+ } catch (err) {
3536
+ if (err.code === "ENOENT") {
3537
+ return 0;
3538
+ }
3539
+ throw err;
3540
+ }
3541
+ let data;
3542
+ try {
3543
+ data = JSON.parse(content);
3544
+ } catch {
3545
+ logger.warn(`[JsonMigrator] Failed to parse ${jsonPath}, skipping migration`);
3546
+ return 0;
3547
+ }
3548
+ const schedules = data.schedules;
3549
+ if (!Array.isArray(schedules) || schedules.length === 0) {
3550
+ logger.debug("[JsonMigrator] No schedules to migrate");
3551
+ await renameToMigrated(resolvedPath);
3552
+ return 0;
3553
+ }
3554
+ let migrated = 0;
3555
+ for (const schedule of schedules) {
3556
+ if (!schedule.id) {
3557
+ logger.warn("[JsonMigrator] Skipping schedule without ID");
3558
+ continue;
3559
+ }
3560
+ const existing = await backend.get(schedule.id);
3561
+ if (existing) {
3562
+ logger.debug(`[JsonMigrator] Schedule ${schedule.id} already exists, skipping`);
3563
+ continue;
3564
+ }
3565
+ try {
3566
+ await backend.importSchedule(schedule);
3567
+ migrated++;
3568
+ } catch (err) {
3569
+ logger.warn(
3570
+ `[JsonMigrator] Failed to migrate schedule ${schedule.id}: ${err instanceof Error ? err.message : err}`
3571
+ );
3572
+ }
3573
+ }
3574
+ await renameToMigrated(resolvedPath);
3575
+ logger.info(`[JsonMigrator] Migrated ${migrated}/${schedules.length} schedules from ${jsonPath}`);
3576
+ return migrated;
3577
+ }
3578
+ async function renameToMigrated(resolvedPath) {
3579
+ const migratedPath = `${resolvedPath}.migrated`;
3580
+ try {
3581
+ await fs3.rename(resolvedPath, migratedPath);
3582
+ logger.info(`[JsonMigrator] Backed up ${resolvedPath} \u2192 ${migratedPath}`);
3583
+ } catch (err) {
3584
+ logger.warn(
3585
+ `[JsonMigrator] Failed to rename ${resolvedPath}: ${err instanceof Error ? err.message : err}`
3586
+ );
3587
+ }
3588
+ }
3589
+ var init_json_migrator = __esm({
3590
+ "src/scheduler/store/json-migrator.ts"() {
3591
+ "use strict";
3592
+ init_logger();
3593
+ }
3594
+ });
3595
+
3596
+ // src/scheduler/schedule-store.ts
3061
3597
  var ScheduleStore;
3062
3598
  var init_schedule_store = __esm({
3063
3599
  "src/scheduler/schedule-store.ts"() {
3064
3600
  "use strict";
3065
3601
  init_logger();
3602
+ init_store();
3603
+ init_json_migrator();
3066
3604
  ScheduleStore = class _ScheduleStore {
3067
3605
  static instance;
3068
- schedules = /* @__PURE__ */ new Map();
3069
- filePath;
3070
- autoSave;
3071
- saveDebounceMs;
3606
+ backend = null;
3072
3607
  initialized = false;
3073
- saveTimeout = null;
3074
3608
  limits;
3075
- // Concurrency protection
3076
- saveLock = Promise.resolve();
3077
- pendingSave = false;
3078
- dirtyCount = 0;
3079
- // Track unsaved changes
3080
- constructor(config, limits) {
3081
- this.filePath = config?.path || ".visor/schedules.json";
3082
- this.autoSave = config?.autoSave !== false;
3083
- this.saveDebounceMs = config?.saveDebounceMs ?? 1e3;
3609
+ config;
3610
+ externalBackend = null;
3611
+ constructor(config, limits, backend) {
3612
+ this.config = config || {};
3084
3613
  this.limits = {
3085
3614
  maxPerUser: limits?.maxPerUser ?? 25,
3086
3615
  maxRecurringPerUser: limits?.maxRecurringPerUser ?? 10,
3087
3616
  maxGlobal: limits?.maxGlobal ?? 1e3
3088
3617
  };
3618
+ if (backend) {
3619
+ this.externalBackend = backend;
3620
+ }
3089
3621
  }
3090
3622
  /**
3091
3623
  * Get singleton instance
@@ -3107,277 +3639,108 @@ var init_schedule_store = __esm({
3107
3639
  /**
3108
3640
  * Create a new isolated instance (for testing)
3109
3641
  */
3110
- static createIsolated(config, limits) {
3111
- return new _ScheduleStore(config, limits);
3642
+ static createIsolated(config, limits, backend) {
3643
+ return new _ScheduleStore(config, limits, backend);
3112
3644
  }
3113
3645
  /**
3114
3646
  * Reset singleton instance (for testing)
3115
3647
  */
3116
3648
  static resetInstance() {
3117
3649
  if (_ScheduleStore.instance) {
3118
- _ScheduleStore.instance.schedules.clear();
3119
- if (_ScheduleStore.instance.saveTimeout) {
3120
- clearTimeout(_ScheduleStore.instance.saveTimeout);
3650
+ if (_ScheduleStore.instance.backend) {
3651
+ _ScheduleStore.instance.backend.shutdown().catch(() => {
3652
+ });
3121
3653
  }
3122
3654
  }
3123
3655
  _ScheduleStore.instance = void 0;
3124
3656
  }
3125
3657
  /**
3126
- * Initialize the store - load from file if it exists
3658
+ * Initialize the store - creates backend and runs migrations
3127
3659
  */
3128
3660
  async initialize() {
3129
3661
  if (this.initialized) {
3130
3662
  return;
3131
3663
  }
3132
- try {
3133
- const resolvedPath = path3.resolve(process.cwd(), this.filePath);
3134
- const content = await fs2.readFile(resolvedPath, "utf-8");
3135
- const data = JSON.parse(content);
3136
- const scheduleList = data.schedules || [];
3137
- if (Array.isArray(scheduleList)) {
3138
- for (const schedule of scheduleList) {
3139
- this.schedules.set(schedule.id, schedule);
3140
- }
3141
- logger.info(
3142
- `[ScheduleStore] Loaded ${this.schedules.size} schedules from ${this.filePath}`
3143
- );
3144
- }
3145
- } catch (error) {
3146
- if (error.code !== "ENOENT") {
3147
- logger.warn(
3148
- `[ScheduleStore] Failed to load schedules: ${error instanceof Error ? error.message : "Unknown error"}`
3149
- );
3150
- } else {
3151
- logger.debug(`[ScheduleStore] No existing schedules file at ${this.filePath}`);
3152
- }
3664
+ if (this.externalBackend) {
3665
+ this.backend = this.externalBackend;
3666
+ } else {
3667
+ this.backend = await createStoreBackend(this.config.storage, this.config.ha);
3153
3668
  }
3154
- this.initialized = true;
3155
- }
3156
- /**
3157
- * Save schedules to file with atomic write and concurrency protection
3158
- */
3159
- async save() {
3160
- const previousLock = this.saveLock;
3161
- let releaseLock;
3162
- this.saveLock = new Promise((resolve5) => {
3163
- releaseLock = resolve5;
3164
- });
3669
+ await this.backend.initialize();
3670
+ const jsonPath = this.config.path || ".visor/schedules.json";
3165
3671
  try {
3166
- await previousLock;
3167
- const resolvedPath = path3.resolve(process.cwd(), this.filePath);
3168
- const dir = path3.dirname(resolvedPath);
3169
- await fs2.mkdir(dir, { recursive: true });
3170
- const savedDirtyCount = this.dirtyCount;
3171
- const data = {
3172
- version: "2.0",
3173
- // New version for schedule format
3174
- savedAt: (/* @__PURE__ */ new Date()).toISOString(),
3175
- schedules: Array.from(this.schedules.values())
3176
- };
3177
- const tempPath = `${resolvedPath}.tmp.${Date.now()}`;
3178
- await fs2.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
3179
- await fs2.rename(tempPath, resolvedPath);
3180
- this.dirtyCount = Math.max(0, this.dirtyCount - savedDirtyCount);
3181
- this.pendingSave = false;
3182
- logger.debug(`[ScheduleStore] Saved ${this.schedules.size} schedules to ${this.filePath}`);
3183
- } finally {
3184
- releaseLock();
3185
- }
3186
- }
3187
- /**
3188
- * Schedule a debounced save operation with dirty tracking
3189
- */
3190
- scheduleSave() {
3191
- if (!this.autoSave) return;
3192
- this.dirtyCount++;
3193
- this.pendingSave = true;
3194
- if (this.saveTimeout) {
3195
- clearTimeout(this.saveTimeout);
3196
- }
3197
- this.saveTimeout = setTimeout(() => {
3198
- this.save().catch((error) => {
3199
- logger.error(
3200
- `[ScheduleStore] Auto-save failed: ${error instanceof Error ? error.message : "Unknown error"}`
3201
- );
3202
- });
3203
- }, this.saveDebounceMs);
3204
- }
3205
- /**
3206
- * Immediately save if there are pending changes (for critical operations)
3207
- */
3208
- async saveImmediate() {
3209
- if (!this.autoSave) return;
3210
- if (this.saveTimeout) {
3211
- clearTimeout(this.saveTimeout);
3212
- this.saveTimeout = null;
3672
+ await migrateJsonToBackend(jsonPath, this.backend);
3673
+ } catch (err) {
3674
+ logger.warn(
3675
+ `[ScheduleStore] JSON migration failed (non-fatal): ${err instanceof Error ? err.message : err}`
3676
+ );
3213
3677
  }
3214
- await this.save();
3678
+ this.initialized = true;
3215
3679
  }
3216
3680
  /**
3217
- * Create a new schedule (saves immediately to prevent data loss)
3681
+ * Create a new schedule (async, persists immediately)
3218
3682
  */
3219
3683
  async createAsync(schedule) {
3220
- this.validateLimits(schedule.creatorId, schedule.isRecurring);
3221
- const newSchedule = {
3222
- ...schedule,
3223
- id: uuidv4(),
3224
- createdAt: Date.now(),
3225
- runCount: 0,
3226
- failureCount: 0,
3227
- status: "active"
3228
- };
3229
- this.schedules.set(newSchedule.id, newSchedule);
3230
- await this.saveImmediate();
3231
- logger.info(
3232
- `[ScheduleStore] Created schedule ${newSchedule.id} for user ${newSchedule.creatorId}: workflow="${newSchedule.workflow}"`
3233
- );
3234
- return newSchedule;
3235
- }
3236
- /**
3237
- * Create a new schedule (synchronous, uses debounced save)
3238
- * @deprecated Use createAsync for reliable persistence
3239
- */
3240
- create(schedule) {
3241
- this.validateLimits(schedule.creatorId, schedule.isRecurring);
3242
- const newSchedule = {
3243
- ...schedule,
3244
- id: uuidv4(),
3245
- createdAt: Date.now(),
3246
- runCount: 0,
3247
- failureCount: 0,
3248
- status: "active"
3249
- };
3250
- this.schedules.set(newSchedule.id, newSchedule);
3251
- this.scheduleSave();
3252
- logger.info(
3253
- `[ScheduleStore] Created schedule ${newSchedule.id} for user ${newSchedule.creatorId}: workflow="${newSchedule.workflow}"`
3254
- );
3255
- return newSchedule;
3256
- }
3257
- /**
3258
- * Validate schedule limits before creation
3259
- */
3260
- validateLimits(creatorId, isRecurring) {
3261
- if (this.limits.maxGlobal && this.schedules.size >= this.limits.maxGlobal) {
3262
- throw new Error(`Global schedule limit reached (${this.limits.maxGlobal})`);
3263
- }
3264
- const userSchedules = this.getByCreator(creatorId);
3265
- if (this.limits.maxPerUser && userSchedules.length >= this.limits.maxPerUser) {
3266
- throw new Error(
3267
- `You have reached the maximum number of schedules (${this.limits.maxPerUser})`
3268
- );
3269
- }
3270
- if (isRecurring && this.limits.maxRecurringPerUser) {
3271
- const recurringCount = userSchedules.filter((s) => s.isRecurring).length;
3272
- if (recurringCount >= this.limits.maxRecurringPerUser) {
3273
- throw new Error(
3274
- `You have reached the maximum number of recurring schedules (${this.limits.maxRecurringPerUser})`
3275
- );
3276
- }
3277
- }
3684
+ const backend = this.getBackend();
3685
+ await backend.validateLimits(schedule.creatorId, schedule.isRecurring, this.limits);
3686
+ return backend.create(schedule);
3278
3687
  }
3279
3688
  /**
3280
3689
  * Get a schedule by ID
3281
3690
  */
3282
- get(id) {
3283
- return this.schedules.get(id);
3691
+ async getAsync(id) {
3692
+ return this.getBackend().get(id);
3284
3693
  }
3285
3694
  /**
3286
3695
  * Update a schedule
3287
3696
  */
3288
- update(id, patch) {
3289
- const schedule = this.schedules.get(id);
3290
- if (!schedule) {
3291
- return void 0;
3292
- }
3293
- const updated = { ...schedule, ...patch, id: schedule.id };
3294
- this.schedules.set(id, updated);
3295
- this.scheduleSave();
3296
- return updated;
3697
+ async updateAsync(id, patch) {
3698
+ return this.getBackend().update(id, patch);
3297
3699
  }
3298
3700
  /**
3299
- * Delete a schedule (saves immediately to prevent data loss)
3701
+ * Delete a schedule
3300
3702
  */
3301
3703
  async deleteAsync(id) {
3302
- const deleted = this.schedules.delete(id);
3303
- if (deleted) {
3304
- await this.saveImmediate();
3305
- logger.info(`[ScheduleStore] Deleted schedule ${id}`);
3306
- }
3307
- return deleted;
3308
- }
3309
- /**
3310
- * Delete a schedule (synchronous, uses debounced save)
3311
- * @deprecated Use deleteAsync for reliable persistence
3312
- */
3313
- delete(id) {
3314
- const deleted = this.schedules.delete(id);
3315
- if (deleted) {
3316
- this.scheduleSave();
3317
- logger.info(`[ScheduleStore] Deleted schedule ${id}`);
3318
- }
3319
- return deleted;
3704
+ return this.getBackend().delete(id);
3320
3705
  }
3321
3706
  /**
3322
3707
  * Get all schedules for a specific creator
3323
3708
  */
3324
- getByCreator(creatorId) {
3325
- return Array.from(this.schedules.values()).filter((s) => s.creatorId === creatorId);
3709
+ async getByCreatorAsync(creatorId) {
3710
+ return this.getBackend().getByCreator(creatorId);
3326
3711
  }
3327
3712
  /**
3328
3713
  * Get all active schedules
3329
3714
  */
3330
- getActiveSchedules() {
3331
- return Array.from(this.schedules.values()).filter((s) => s.status === "active");
3715
+ async getActiveSchedulesAsync() {
3716
+ return this.getBackend().getActiveSchedules();
3332
3717
  }
3333
3718
  /**
3334
3719
  * Get all schedules due for execution
3335
3720
  * @param now Current timestamp in milliseconds
3336
3721
  */
3337
- getDueSchedules(now = Date.now()) {
3338
- return this.getActiveSchedules().filter((s) => {
3339
- if (!s.isRecurring && s.runAt) {
3340
- return s.runAt <= now;
3341
- }
3342
- if (s.isRecurring && s.nextRunAt) {
3343
- return s.nextRunAt <= now;
3344
- }
3345
- return false;
3346
- });
3722
+ async getDueSchedulesAsync(now = Date.now()) {
3723
+ return this.getBackend().getDueSchedules(now);
3347
3724
  }
3348
3725
  /**
3349
3726
  * Find schedules by workflow name
3350
3727
  */
3351
- findByWorkflow(creatorId, workflowName) {
3352
- const lowerWorkflow = workflowName.toLowerCase();
3353
- return this.getByCreator(creatorId).filter(
3354
- (s) => s.status === "active" && s.workflow?.toLowerCase().includes(lowerWorkflow)
3355
- );
3728
+ async findByWorkflowAsync(creatorId, workflowName) {
3729
+ return this.getBackend().findByWorkflow(creatorId, workflowName);
3356
3730
  }
3357
3731
  /**
3358
3732
  * Get schedule count statistics
3359
3733
  */
3360
- getStats() {
3361
- const all = Array.from(this.schedules.values());
3362
- return {
3363
- total: all.length,
3364
- active: all.filter((s) => s.status === "active").length,
3365
- paused: all.filter((s) => s.status === "paused").length,
3366
- completed: all.filter((s) => s.status === "completed").length,
3367
- failed: all.filter((s) => s.status === "failed").length,
3368
- recurring: all.filter((s) => s.isRecurring).length,
3369
- oneTime: all.filter((s) => !s.isRecurring).length
3370
- };
3734
+ async getStatsAsync() {
3735
+ return this.getBackend().getStats();
3371
3736
  }
3372
3737
  /**
3373
3738
  * Force immediate save (useful for shutdown)
3374
3739
  */
3375
3740
  async flush() {
3376
- if (this.saveTimeout) {
3377
- clearTimeout(this.saveTimeout);
3378
- this.saveTimeout = null;
3741
+ if (this.backend) {
3742
+ await this.backend.flush();
3379
3743
  }
3380
- await this.save();
3381
3744
  }
3382
3745
  /**
3383
3746
  * Check if initialized
@@ -3389,13 +3752,32 @@ var init_schedule_store = __esm({
3389
3752
  * Check if there are unsaved changes
3390
3753
  */
3391
3754
  hasPendingChanges() {
3392
- return this.pendingSave || this.dirtyCount > 0;
3755
+ return false;
3393
3756
  }
3394
3757
  /**
3395
- * Get all schedules (for iteration)
3758
+ * Get all schedules
3396
3759
  */
3397
- getAll() {
3398
- return Array.from(this.schedules.values());
3760
+ async getAllAsync() {
3761
+ return this.getBackend().getAll();
3762
+ }
3763
+ /**
3764
+ * Get the underlying backend (for HA lock operations)
3765
+ */
3766
+ getBackend() {
3767
+ if (!this.backend) {
3768
+ throw new Error("[ScheduleStore] Not initialized. Call initialize() first.");
3769
+ }
3770
+ return this.backend;
3771
+ }
3772
+ /**
3773
+ * Shut down the backend cleanly
3774
+ */
3775
+ async shutdown() {
3776
+ if (this.backend) {
3777
+ await this.backend.shutdown();
3778
+ this.backend = null;
3779
+ }
3780
+ this.initialized = false;
3399
3781
  }
3400
3782
  };
3401
3783
  }
@@ -3745,7 +4127,7 @@ async function handleCreate(args, context2, store) {
3745
4127
  } else if (runAtTimestamp) {
3746
4128
  nextRunAt = runAtTimestamp;
3747
4129
  }
3748
- const schedule = store.create({
4130
+ const schedule = await store.createAsync({
3749
4131
  creatorId: context2.userId,
3750
4132
  creatorContext: context2.contextType,
3751
4133
  creatorName: context2.userName,
@@ -3780,7 +4162,8 @@ async function handleCreate(args, context2, store) {
3780
4162
  }
3781
4163
  }
3782
4164
  async function handleList(context2, store) {
3783
- const schedules = store.getByCreator(context2.userId).filter((s) => s.status !== "completed");
4165
+ const allUserSchedules = await store.getByCreatorAsync(context2.userId);
4166
+ const schedules = allUserSchedules.filter((s) => s.status !== "completed");
3784
4167
  let filteredSchedules = schedules;
3785
4168
  if (context2.allowedScheduleType) {
3786
4169
  filteredSchedules = schedules.filter((s) => {
@@ -3809,7 +4192,7 @@ async function handleList(context2, store) {
3809
4192
  async function handleCancel(args, context2, store) {
3810
4193
  let schedule;
3811
4194
  if (args.schedule_id) {
3812
- const userSchedules = store.getByCreator(context2.userId);
4195
+ const userSchedules = await store.getByCreatorAsync(context2.userId);
3813
4196
  schedule = userSchedules.find((s) => s.id === args.schedule_id);
3814
4197
  if (!schedule) {
3815
4198
  schedule = userSchedules.find((s) => s.id.startsWith(args.schedule_id));
@@ -3832,7 +4215,7 @@ async function handleCancel(args, context2, store) {
3832
4215
  error: "You can only cancel your own schedules."
3833
4216
  };
3834
4217
  }
3835
- store.delete(schedule.id);
4218
+ await store.deleteAsync(schedule.id);
3836
4219
  logger.info(`[ScheduleTool] Cancelled schedule ${schedule.id} for user ${context2.userId}`);
3837
4220
  return {
3838
4221
  success: true,
@@ -3849,7 +4232,7 @@ async function handlePauseResume(args, context2, store, newStatus) {
3849
4232
  error: "Please specify which schedule to pause/resume."
3850
4233
  };
3851
4234
  }
3852
- const userSchedules = store.getByCreator(context2.userId);
4235
+ const userSchedules = await store.getByCreatorAsync(context2.userId);
3853
4236
  let schedule = userSchedules.find((s) => s.id === args.schedule_id);
3854
4237
  if (!schedule) {
3855
4238
  schedule = userSchedules.find((s) => s.id.startsWith(args.schedule_id));
@@ -3871,7 +4254,7 @@ async function handlePauseResume(args, context2, store, newStatus) {
3871
4254
  error: "You can only modify your own schedules."
3872
4255
  };
3873
4256
  }
3874
- const updated = store.update(schedule.id, { status: newStatus });
4257
+ const updated = await store.updateAsync(schedule.id, { status: newStatus });
3875
4258
  const action = newStatus === "paused" ? "paused" : "resumed";
3876
4259
  logger.info(`[ScheduleTool] ${action} schedule ${schedule.id} for user ${context2.userId}`);
3877
4260
  return {
@@ -4583,6 +4966,18 @@ async function handleWavePlanning(context2, state, transition) {
4583
4966
  }
4584
4967
  } catch {
4585
4968
  }
4969
+ try {
4970
+ const args = request.args;
4971
+ if (args && Object.keys(args).length > 0) {
4972
+ if (!state.pendingRunArgs) state.pendingRunArgs = /* @__PURE__ */ new Map();
4973
+ const existingArgs = state.pendingRunArgs.get(target) || {};
4974
+ state.pendingRunArgs.set(target, { ...existingArgs, ...args });
4975
+ if (context2.debug) {
4976
+ logger.info(`[WavePlanning] Storing args for ${target}: ${JSON.stringify(args)}`);
4977
+ }
4978
+ }
4979
+ } catch {
4980
+ }
4586
4981
  if (gotoEvent) {
4587
4982
  eventOverrides.set(target, gotoEvent);
4588
4983
  }
@@ -4894,8 +5289,8 @@ var init_wave_planning = __esm({
4894
5289
  });
4895
5290
 
4896
5291
  // src/utils/mermaid-telemetry.ts
4897
- import * as fs3 from "fs";
4898
- import * as path4 from "path";
5292
+ import * as fs4 from "fs";
5293
+ import * as path5 from "path";
4899
5294
  function emitMermaidFromMarkdown(checkName, markdown, origin) {
4900
5295
  if (!markdown || typeof markdown !== "string") return 0;
4901
5296
  let m;
@@ -4908,16 +5303,16 @@ function emitMermaidFromMarkdown(checkName, markdown, origin) {
4908
5303
  addEvent("diagram.block", { check: checkName, origin, code });
4909
5304
  addDiagramBlock(origin);
4910
5305
  if (process.env.VISOR_TRACE_REPORT === "true") {
4911
- const outDir = process.env.VISOR_TRACE_DIR || path4.join(process.cwd(), "output", "traces");
5306
+ const outDir = process.env.VISOR_TRACE_DIR || path5.join(process.cwd(), "output", "traces");
4912
5307
  try {
4913
- if (!fs3.existsSync(outDir)) fs3.mkdirSync(outDir, { recursive: true });
5308
+ if (!fs4.existsSync(outDir)) fs4.mkdirSync(outDir, { recursive: true });
4914
5309
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4915
- const jsonPath = path4.join(outDir, `${ts}.trace.json`);
4916
- const htmlPath = path4.join(outDir, `${ts}.report.html`);
5310
+ const jsonPath = path5.join(outDir, `${ts}.trace.json`);
5311
+ const htmlPath = path5.join(outDir, `${ts}.report.html`);
4917
5312
  let data = { spans: [] };
4918
- if (fs3.existsSync(jsonPath)) {
5313
+ if (fs4.existsSync(jsonPath)) {
4919
5314
  try {
4920
- data = JSON.parse(fs3.readFileSync(jsonPath, "utf8"));
5315
+ data = JSON.parse(fs4.readFileSync(jsonPath, "utf8"));
4921
5316
  } catch {
4922
5317
  data = { spans: [] };
4923
5318
  }
@@ -4925,9 +5320,9 @@ function emitMermaidFromMarkdown(checkName, markdown, origin) {
4925
5320
  data.spans.push({
4926
5321
  events: [{ name: "diagram.block", attrs: { check: checkName, origin, code } }]
4927
5322
  });
4928
- fs3.writeFileSync(jsonPath, JSON.stringify(data, null, 2), "utf8");
4929
- if (!fs3.existsSync(htmlPath)) {
4930
- fs3.writeFileSync(
5323
+ fs4.writeFileSync(jsonPath, JSON.stringify(data, null, 2), "utf8");
5324
+ if (!fs4.existsSync(htmlPath)) {
5325
+ fs4.writeFileSync(
4931
5326
  htmlPath,
4932
5327
  '<!doctype html><html><head><meta charset="utf-8"/><title>Visor Trace Report</title></head><body><h2>Visor Trace Report</h2></body></html>',
4933
5328
  "utf8"
@@ -5377,6 +5772,42 @@ var init_sandbox_routing = __esm({
5377
5772
  }
5378
5773
  });
5379
5774
 
5775
+ // src/state-machine/dispatch/policy-gate.ts
5776
+ async function applyPolicyGate(checkId, checkConfig, policyEngine) {
5777
+ let decision;
5778
+ try {
5779
+ decision = await policyEngine.evaluateCheckExecution(checkId, checkConfig);
5780
+ } catch (err) {
5781
+ const msg = err instanceof Error ? err.message : String(err);
5782
+ logger.warn(`[PolicyEngine] Evaluation failed for check '${checkId}': ${msg}`);
5783
+ decision = { allowed: false, reason: "policy evaluation error" };
5784
+ }
5785
+ const auditReason = decision.reason || "policy violation";
5786
+ if (decision.warn) {
5787
+ logger.warn(`[PolicyEngine] Audit: check '${checkId}' would be denied: ${auditReason}`);
5788
+ }
5789
+ if (!decision.allowed) {
5790
+ logger.info(`\u26D4 Skipped (policy: ${decision.reason || "denied"})`);
5791
+ return {
5792
+ skip: true,
5793
+ reason: decision.reason || "policy denied",
5794
+ warn: !!decision.warn,
5795
+ auditReason: decision.warn ? auditReason : void 0
5796
+ };
5797
+ }
5798
+ return {
5799
+ skip: false,
5800
+ warn: !!decision.warn,
5801
+ auditReason: decision.warn ? auditReason : void 0
5802
+ };
5803
+ }
5804
+ var init_policy_gate = __esm({
5805
+ "src/state-machine/dispatch/policy-gate.ts"() {
5806
+ "use strict";
5807
+ init_logger();
5808
+ }
5809
+ });
5810
+
5380
5811
  // src/state-machine/dispatch/history-snapshot.ts
5381
5812
  var history_snapshot_exports = {};
5382
5813
  __export(history_snapshot_exports, {
@@ -5547,9 +5978,9 @@ var init_dependency_gating = __esm({
5547
5978
  // src/state-machine/dispatch/template-renderer.ts
5548
5979
  async function renderTemplateContent(checkId, checkConfig, reviewSummary) {
5549
5980
  try {
5550
- const { createExtendedLiquid: createExtendedLiquid2 } = await import("./liquid-extensions-5IZLTFSZ.mjs");
5551
- const fs10 = await import("fs/promises");
5552
- const path12 = await import("path");
5981
+ const { createExtendedLiquid: createExtendedLiquid2 } = await import("./liquid-extensions-E4EUOCES.mjs");
5982
+ const fs11 = await import("fs/promises");
5983
+ const path14 = await import("path");
5553
5984
  const schemaRaw = checkConfig.schema || "plain";
5554
5985
  const schema = typeof schemaRaw === "string" ? schemaRaw : "code-review";
5555
5986
  let templateContent;
@@ -5557,24 +5988,24 @@ async function renderTemplateContent(checkId, checkConfig, reviewSummary) {
5557
5988
  templateContent = String(checkConfig.template.content);
5558
5989
  } else if (checkConfig.template && checkConfig.template.file) {
5559
5990
  const file = String(checkConfig.template.file);
5560
- const resolved = path12.resolve(process.cwd(), file);
5561
- templateContent = await fs10.readFile(resolved, "utf-8");
5991
+ const resolved = path14.resolve(process.cwd(), file);
5992
+ templateContent = await fs11.readFile(resolved, "utf-8");
5562
5993
  } else if (schema && schema !== "plain") {
5563
5994
  const sanitized = String(schema).replace(/[^a-zA-Z0-9-]/g, "");
5564
5995
  if (sanitized) {
5565
5996
  const candidatePaths = [
5566
- path12.join(__dirname, "output", sanitized, "template.liquid"),
5997
+ path14.join(__dirname, "output", sanitized, "template.liquid"),
5567
5998
  // bundled: dist/output/
5568
- path12.join(__dirname, "..", "..", "output", sanitized, "template.liquid"),
5999
+ path14.join(__dirname, "..", "..", "output", sanitized, "template.liquid"),
5569
6000
  // source: output/
5570
- path12.join(process.cwd(), "output", sanitized, "template.liquid"),
6001
+ path14.join(process.cwd(), "output", sanitized, "template.liquid"),
5571
6002
  // fallback: cwd/output/
5572
- path12.join(process.cwd(), "dist", "output", sanitized, "template.liquid")
6003
+ path14.join(process.cwd(), "dist", "output", sanitized, "template.liquid")
5573
6004
  // fallback: cwd/dist/output/
5574
6005
  ];
5575
6006
  for (const p of candidatePaths) {
5576
6007
  try {
5577
- templateContent = await fs10.readFile(p, "utf-8");
6008
+ templateContent = await fs11.readFile(p, "utf-8");
5578
6009
  if (templateContent) break;
5579
6010
  } catch {
5580
6011
  }
@@ -6612,6 +7043,48 @@ async function executeSingleCheck(checkId, context2, state, emitEvent, transitio
6612
7043
  return emptyResult;
6613
7044
  }
6614
7045
  }
7046
+ if (context2.policyEngine && checkConfig) {
7047
+ const gate = await applyPolicyGate(checkId, checkConfig, context2.policyEngine);
7048
+ if (gate.skip) {
7049
+ const emptyResult = { issues: [] };
7050
+ try {
7051
+ Object.defineProperty(emptyResult, "__skipped", {
7052
+ value: "policy_denied",
7053
+ enumerable: false
7054
+ });
7055
+ } catch {
7056
+ }
7057
+ state.completedChecks.add(checkId);
7058
+ const stats = {
7059
+ checkName: checkId,
7060
+ totalRuns: 0,
7061
+ successfulRuns: 0,
7062
+ failedRuns: 0,
7063
+ skippedRuns: 0,
7064
+ skipped: true,
7065
+ skipReason: "policy_denied",
7066
+ skipCondition: gate.reason || "policy denied",
7067
+ totalDuration: 0,
7068
+ issuesFound: 0,
7069
+ issuesBySeverity: { critical: 0, error: 0, warning: 0, info: 0 }
7070
+ };
7071
+ state.stats.set(checkId, stats);
7072
+ logger.info(`[LevelDispatch] Recorded skip stats for ${checkId}: skipReason=policy_denied`);
7073
+ try {
7074
+ context2.journal.commitEntry({
7075
+ sessionId: context2.sessionId,
7076
+ checkId,
7077
+ result: emptyResult,
7078
+ event: context2.event || "manual",
7079
+ scope: []
7080
+ });
7081
+ } catch (error) {
7082
+ logger.warn(`[LevelDispatch] Failed to commit policy-skipped result to journal: ${error}`);
7083
+ }
7084
+ emitEvent({ type: "CheckCompleted", checkId, scope: [], result: emptyResult });
7085
+ return emptyResult;
7086
+ }
7087
+ }
6615
7088
  const dependencies = checkConfig?.depends_on || [];
6616
7089
  const depList = Array.isArray(dependencies) ? dependencies : [dependencies];
6617
7090
  const failedChecks = state.failedChecks;
@@ -7126,11 +7599,39 @@ var init_execution_invoker = __esm({
7126
7599
  init_sandbox();
7127
7600
  init_workflow_inputs();
7128
7601
  init_sandbox_routing();
7602
+ init_policy_gate();
7129
7603
  MAX_ON_INIT_ITEMS = 50;
7130
7604
  }
7131
7605
  });
7132
7606
 
7133
7607
  // src/state-machine/states/level-dispatch.ts
7608
+ async function renderTemplateArgs(args, dependencyResults, context2) {
7609
+ if (!args || Object.keys(args).length === 0) {
7610
+ return args;
7611
+ }
7612
+ const liquid = createExtendedLiquid();
7613
+ const renderedArgs = {};
7614
+ const templateContext = {
7615
+ outputs: dependencyResults,
7616
+ output: dependencyResults,
7617
+ // Alias for convenience
7618
+ env: process.env,
7619
+ inputs: context2.executionContext?.workflowInputs || {}
7620
+ };
7621
+ for (const [key, value] of Object.entries(args)) {
7622
+ if (typeof value === "string" && value.includes("{{")) {
7623
+ try {
7624
+ renderedArgs[key] = await liquid.parseAndRender(value, templateContext);
7625
+ } catch (error) {
7626
+ logger.warn(`[LevelDispatch] Failed to render template for arg ${key}: ${error}`);
7627
+ renderedArgs[key] = value;
7628
+ }
7629
+ } else {
7630
+ renderedArgs[key] = value;
7631
+ }
7632
+ }
7633
+ return renderedArgs;
7634
+ }
7134
7635
  function mapCheckNameToFocus2(checkName) {
7135
7636
  const focusMap = {
7136
7637
  security: "security",
@@ -7422,6 +7923,7 @@ async function executeCheckGroup(checks, context2, state, maxParallelism, emitEv
7422
7923
  }
7423
7924
  try {
7424
7925
  state.pendingRunScopes?.delete(checkId);
7926
+ state.pendingRunArgs?.delete(checkId);
7425
7927
  } catch {
7426
7928
  }
7427
7929
  } else {
@@ -7649,6 +8151,15 @@ async function executeCheckWithForEachItems2(checkId, forEachParent, forEachItem
7649
8151
  }
7650
8152
  } catch {
7651
8153
  }
8154
+ try {
8155
+ if (!providerConfig.eventContext?.conversation && context2.executionContext?.conversation) {
8156
+ providerConfig.eventContext = {
8157
+ ...providerConfig.eventContext,
8158
+ conversation: context2.executionContext.conversation
8159
+ };
8160
+ }
8161
+ } catch {
8162
+ }
7652
8163
  const dependencyResults = buildDependencyResultsWithScope2(
7653
8164
  checkId,
7654
8165
  checkConfig,
@@ -7717,11 +8228,20 @@ async function executeCheckWithForEachItems2(checkId, forEachParent, forEachItem
7717
8228
  files: [],
7718
8229
  commits: []
7719
8230
  };
8231
+ const rawPendingArgs = state.pendingRunArgs?.get(checkId);
8232
+ const depResultsObj = {};
8233
+ for (const [k, v] of dependencyResults.entries()) {
8234
+ const summary = v;
8235
+ depResultsObj[k] = summary.output !== void 0 ? summary.output : summary;
8236
+ }
8237
+ const renderedArgs = rawPendingArgs ? await renderTemplateArgs(rawPendingArgs, depResultsObj, context2) : void 0;
7720
8238
  const executionContext = {
7721
8239
  ...context2.executionContext,
7722
8240
  _engineMode: context2.mode,
7723
8241
  _parentContext: context2,
7724
- _parentState: state
8242
+ _parentState: state,
8243
+ // Inject args from on_success.run with directives (merged with existing args)
8244
+ args: renderedArgs ? { ...context2.executionContext?.args || {}, ...renderedArgs } : context2.executionContext?.args
7725
8245
  };
7726
8246
  {
7727
8247
  const assumeExpr = checkConfig?.assume;
@@ -7730,10 +8250,12 @@ async function executeCheckWithForEachItems2(checkId, forEachParent, forEachItem
7730
8250
  try {
7731
8251
  const evaluator = new FailureConditionEvaluator();
7732
8252
  const exprs = Array.isArray(assumeExpr) ? assumeExpr : [assumeExpr];
8253
+ const conversation = context2.executionContext?.conversation || providerConfig?.eventContext?.conversation;
7733
8254
  for (const ex of exprs) {
7734
8255
  const res = await evaluator.evaluateIfCondition(checkId, ex, {
7735
8256
  event: context2.event || "manual",
7736
- previousResults: dependencyResults
8257
+ previousResults: dependencyResults,
8258
+ conversation
7737
8259
  });
7738
8260
  if (!res) {
7739
8261
  ok = false;
@@ -7830,7 +8352,7 @@ async function executeCheckWithForEachItems2(checkId, forEachParent, forEachItem
7830
8352
  let schemaObj = (typeof checkConfig.schema === "object" ? checkConfig.schema : void 0) || checkConfig.output_schema;
7831
8353
  if (!schemaObj && typeof checkConfig.schema === "string") {
7832
8354
  try {
7833
- const { loadRendererSchema } = await import("./renderer-schema-CMXOLNIG.mjs");
8355
+ const { loadRendererSchema } = await import("./renderer-schema-HXEW6BRJ.mjs");
7834
8356
  schemaObj = await loadRendererSchema(checkConfig.schema);
7835
8357
  } catch {
7836
8358
  }
@@ -8168,7 +8690,7 @@ async function executeCheckWithForEachItems2(checkId, forEachParent, forEachItem
8168
8690
  }
8169
8691
  }
8170
8692
  try {
8171
- const { evaluateTransitions } = await import("./routing-S3Y7T2X3.mjs");
8693
+ const { evaluateTransitions } = await import("./routing-OZQWAGAI.mjs");
8172
8694
  const transTarget = await evaluateTransitions(
8173
8695
  onFinish.transitions,
8174
8696
  forEachParent,
@@ -8228,7 +8750,7 @@ async function executeCheckWithForEachItems2(checkId, forEachParent, forEachItem
8228
8750
  `[LevelDispatch] Error evaluating on_finish transitions for ${forEachParent}: ${e instanceof Error ? e.message : String(e)}`
8229
8751
  );
8230
8752
  }
8231
- const { evaluateGoto: evaluateGoto2 } = await import("./routing-S3Y7T2X3.mjs");
8753
+ const { evaluateGoto: evaluateGoto2 } = await import("./routing-OZQWAGAI.mjs");
8232
8754
  if (context2.debug) {
8233
8755
  logger.info(
8234
8756
  `[LevelDispatch] Evaluating on_finish.goto_js for forEach parent: ${forEachParent}`
@@ -8395,6 +8917,59 @@ async function executeSingleCheck2(checkId, context2, state, emitEvent, transiti
8395
8917
  return emptyResult;
8396
8918
  }
8397
8919
  }
8920
+ if (context2.policyEngine && checkConfig) {
8921
+ const gate = await applyPolicyGate(checkId, checkConfig, context2.policyEngine);
8922
+ if (gate.warn && gate.auditReason) {
8923
+ if (state.stats.has(checkId)) {
8924
+ const s = state.stats.get(checkId);
8925
+ s.policyAuditWarning = gate.auditReason;
8926
+ }
8927
+ }
8928
+ if (gate.skip) {
8929
+ const emptyResult = { issues: [] };
8930
+ try {
8931
+ Object.defineProperty(emptyResult, "__skipped", {
8932
+ value: "policy_denied",
8933
+ enumerable: false
8934
+ });
8935
+ } catch {
8936
+ }
8937
+ state.completedChecks.add(checkId);
8938
+ const stats = {
8939
+ checkName: checkId,
8940
+ totalRuns: 0,
8941
+ successfulRuns: 0,
8942
+ failedRuns: 0,
8943
+ skippedRuns: 0,
8944
+ skipped: true,
8945
+ skipReason: "policy_denied",
8946
+ skipCondition: gate.reason || "policy denied",
8947
+ totalDuration: 0,
8948
+ issuesFound: 0,
8949
+ issuesBySeverity: { critical: 0, error: 0, warning: 0, info: 0 }
8950
+ };
8951
+ state.stats.set(checkId, stats);
8952
+ logger.info(`[LevelDispatch] Recorded skip stats for ${checkId}: skipReason=policy_denied`);
8953
+ try {
8954
+ context2.journal.commitEntry({
8955
+ sessionId: context2.sessionId,
8956
+ checkId,
8957
+ result: emptyResult,
8958
+ event: context2.event || "manual",
8959
+ scope: []
8960
+ });
8961
+ } catch (error) {
8962
+ logger.warn(`[LevelDispatch] Failed to commit policy-denied result to journal: ${error}`);
8963
+ }
8964
+ emitEvent({
8965
+ type: "CheckCompleted",
8966
+ checkId,
8967
+ scope: [],
8968
+ result: emptyResult
8969
+ });
8970
+ return emptyResult;
8971
+ }
8972
+ }
8398
8973
  const dependencies = checkConfig?.depends_on || [];
8399
8974
  const depList = Array.isArray(dependencies) ? dependencies : [dependencies];
8400
8975
  const failedChecks = state.failedChecks;
@@ -8699,6 +9274,15 @@ async function executeSingleCheck2(checkId, context2, state, emitEvent, transiti
8699
9274
  }
8700
9275
  } catch {
8701
9276
  }
9277
+ try {
9278
+ if (!providerConfig.eventContext?.conversation && context2.executionContext?.conversation) {
9279
+ providerConfig.eventContext = {
9280
+ ...providerConfig.eventContext,
9281
+ conversation: context2.executionContext.conversation
9282
+ };
9283
+ }
9284
+ } catch {
9285
+ }
8702
9286
  const dependencyResults = buildDependencyResults(checkId, checkConfig2, context2, state);
8703
9287
  const prInfo = context2.prInfo || {
8704
9288
  number: 1,
@@ -8709,13 +9293,22 @@ async function executeSingleCheck2(checkId, context2, state, emitEvent, transiti
8709
9293
  files: [],
8710
9294
  commits: []
8711
9295
  };
9296
+ const rawPendingArgs = state.pendingRunArgs?.get(checkId);
9297
+ const depResultsObj = {};
9298
+ for (const [k, v] of dependencyResults.entries()) {
9299
+ const summary = v;
9300
+ depResultsObj[k] = summary.output !== void 0 ? summary.output : summary;
9301
+ }
9302
+ const renderedArgs = rawPendingArgs ? await renderTemplateArgs(rawPendingArgs, depResultsObj, context2) : void 0;
8712
9303
  const executionContext = {
8713
9304
  ...context2.executionContext,
8714
9305
  _engineMode: context2.mode,
8715
9306
  _parentContext: context2,
8716
9307
  _parentState: state,
8717
9308
  // Make checks metadata available to providers that want it
8718
- checksMeta
9309
+ checksMeta,
9310
+ // Inject args from on_success.run with directives (merged with existing args)
9311
+ args: renderedArgs ? { ...context2.executionContext?.args || {}, ...renderedArgs } : context2.executionContext?.args
8719
9312
  };
8720
9313
  {
8721
9314
  const assumeExpr = checkConfig2?.assume;
@@ -8724,10 +9317,12 @@ async function executeSingleCheck2(checkId, context2, state, emitEvent, transiti
8724
9317
  try {
8725
9318
  const evaluator = new FailureConditionEvaluator();
8726
9319
  const exprs = Array.isArray(assumeExpr) ? assumeExpr : [assumeExpr];
9320
+ const conversation = context2.executionContext?.conversation || providerConfig?.eventContext?.conversation;
8727
9321
  for (const ex of exprs) {
8728
9322
  const res = await evaluator.evaluateIfCondition(checkId, ex, {
8729
9323
  event: context2.event || "manual",
8730
- previousResults: dependencyResults
9324
+ previousResults: dependencyResults,
9325
+ conversation
8731
9326
  });
8732
9327
  if (!res) {
8733
9328
  ok = false;
@@ -8841,7 +9436,7 @@ async function executeSingleCheck2(checkId, context2, state, emitEvent, transiti
8841
9436
  let schemaObj = (typeof checkConfig2.schema === "object" ? checkConfig2.schema : void 0) || checkConfig2.output_schema;
8842
9437
  if (!schemaObj && typeof checkConfig2.schema === "string") {
8843
9438
  try {
8844
- const { loadRendererSchema } = await import("./renderer-schema-CMXOLNIG.mjs");
9439
+ const { loadRendererSchema } = await import("./renderer-schema-HXEW6BRJ.mjs");
8845
9440
  schemaObj = await loadRendererSchema(checkConfig2.schema);
8846
9441
  } catch {
8847
9442
  }
@@ -9407,9 +10002,9 @@ function updateStats2(results, state, isForEachIteration = false) {
9407
10002
  }
9408
10003
  async function renderTemplateContent2(checkId, checkConfig, reviewSummary) {
9409
10004
  try {
9410
- const { createExtendedLiquid: createExtendedLiquid2 } = await import("./liquid-extensions-5IZLTFSZ.mjs");
9411
- const fs10 = await import("fs/promises");
9412
- const path12 = await import("path");
10005
+ const { createExtendedLiquid: createExtendedLiquid2 } = await import("./liquid-extensions-E4EUOCES.mjs");
10006
+ const fs11 = await import("fs/promises");
10007
+ const path14 = await import("path");
9413
10008
  const schemaRaw = checkConfig.schema || "plain";
9414
10009
  const schema = typeof schemaRaw === "string" ? schemaRaw : "code-review";
9415
10010
  let templateContent;
@@ -9418,27 +10013,27 @@ async function renderTemplateContent2(checkId, checkConfig, reviewSummary) {
9418
10013
  logger.debug(`[LevelDispatch] Using inline template for ${checkId}`);
9419
10014
  } else if (checkConfig.template && checkConfig.template.file) {
9420
10015
  const file = String(checkConfig.template.file);
9421
- const resolved = path12.resolve(process.cwd(), file);
9422
- templateContent = await fs10.readFile(resolved, "utf-8");
10016
+ const resolved = path14.resolve(process.cwd(), file);
10017
+ templateContent = await fs11.readFile(resolved, "utf-8");
9423
10018
  logger.debug(`[LevelDispatch] Using template file for ${checkId}: ${resolved}`);
9424
10019
  } else if (schema && schema !== "plain") {
9425
10020
  const sanitized = String(schema).replace(/[^a-zA-Z0-9-]/g, "");
9426
10021
  if (sanitized) {
9427
10022
  const candidatePaths = [
9428
- path12.join(__dirname, "output", sanitized, "template.liquid"),
10023
+ path14.join(__dirname, "output", sanitized, "template.liquid"),
9429
10024
  // bundled: dist/output/
9430
- path12.join(__dirname, "..", "..", "output", sanitized, "template.liquid"),
10025
+ path14.join(__dirname, "..", "..", "output", sanitized, "template.liquid"),
9431
10026
  // source (from state-machine/states)
9432
- path12.join(__dirname, "..", "..", "..", "output", sanitized, "template.liquid"),
10027
+ path14.join(__dirname, "..", "..", "..", "output", sanitized, "template.liquid"),
9433
10028
  // source (alternate)
9434
- path12.join(process.cwd(), "output", sanitized, "template.liquid"),
10029
+ path14.join(process.cwd(), "output", sanitized, "template.liquid"),
9435
10030
  // fallback: cwd/output/
9436
- path12.join(process.cwd(), "dist", "output", sanitized, "template.liquid")
10031
+ path14.join(process.cwd(), "dist", "output", sanitized, "template.liquid")
9437
10032
  // fallback: cwd/dist/output/
9438
10033
  ];
9439
10034
  for (const p of candidatePaths) {
9440
10035
  try {
9441
- templateContent = await fs10.readFile(p, "utf-8");
10036
+ templateContent = await fs11.readFile(p, "utf-8");
9442
10037
  if (templateContent) {
9443
10038
  logger.debug(`[LevelDispatch] Using schema template for ${checkId}: ${p}`);
9444
10039
  break;
@@ -9505,6 +10100,8 @@ var init_level_dispatch = __esm({
9505
10100
  init_failure_condition_evaluator();
9506
10101
  init_workflow_inputs();
9507
10102
  init_sandbox_routing();
10103
+ init_policy_gate();
10104
+ init_liquid_extensions();
9508
10105
  }
9509
10106
  });
9510
10107
 
@@ -10675,7 +11272,7 @@ var init_sandbox_manager = __esm({
10675
11272
 
10676
11273
  // src/utils/workspace-manager.ts
10677
11274
  import * as fsp from "fs/promises";
10678
- import * as path5 from "path";
11275
+ import * as path6 from "path";
10679
11276
  function shellEscape(str) {
10680
11277
  return "'" + str.replace(/'/g, "'\\''") + "'";
10681
11278
  }
@@ -10719,7 +11316,7 @@ var init_workspace_manager = __esm({
10719
11316
  };
10720
11317
  this.basePath = this.config.basePath;
10721
11318
  const workspaceDirName = sanitizePathComponent(this.config.name || this.sessionId);
10722
- this.workspacePath = path5.join(this.basePath, workspaceDirName);
11319
+ this.workspacePath = path6.join(this.basePath, workspaceDirName);
10723
11320
  }
10724
11321
  /**
10725
11322
  * Get or create a WorkspaceManager instance for a session
@@ -10766,8 +11363,8 @@ var init_workspace_manager = __esm({
10766
11363
  );
10767
11364
  if (this.cleanupRequested && this.activeOperations === 0) {
10768
11365
  logger.debug(`[Workspace] All references released, proceeding with deferred cleanup`);
10769
- for (const resolve5 of this.cleanupResolvers) {
10770
- resolve5();
11366
+ for (const resolve6 of this.cleanupResolvers) {
11367
+ resolve6();
10771
11368
  }
10772
11369
  this.cleanupResolvers = [];
10773
11370
  }
@@ -10814,7 +11411,7 @@ var init_workspace_manager = __esm({
10814
11411
  configuredMainProjectName || this.extractProjectName(this.originalPath)
10815
11412
  );
10816
11413
  this.usedNames.add(mainProjectName);
10817
- const mainProjectPath = path5.join(this.workspacePath, mainProjectName);
11414
+ const mainProjectPath = path6.join(this.workspacePath, mainProjectName);
10818
11415
  const isGitRepo = await this.isGitRepository(this.originalPath);
10819
11416
  if (isGitRepo) {
10820
11417
  await this.createMainProjectWorktree(mainProjectPath);
@@ -10855,7 +11452,7 @@ var init_workspace_manager = __esm({
10855
11452
  let projectName = sanitizePathComponent(description || this.extractRepoName(repository));
10856
11453
  projectName = this.getUniqueName(projectName);
10857
11454
  this.usedNames.add(projectName);
10858
- const workspacePath = path5.join(this.workspacePath, projectName);
11455
+ const workspacePath = path6.join(this.workspacePath, projectName);
10859
11456
  await fsp.rm(workspacePath, { recursive: true, force: true });
10860
11457
  try {
10861
11458
  await fsp.symlink(worktreePath, workspacePath);
@@ -10892,19 +11489,19 @@ var init_workspace_manager = __esm({
10892
11489
  );
10893
11490
  this.cleanupRequested = true;
10894
11491
  await Promise.race([
10895
- new Promise((resolve5) => {
11492
+ new Promise((resolve6) => {
10896
11493
  if (this.activeOperations === 0) {
10897
- resolve5();
11494
+ resolve6();
10898
11495
  } else {
10899
- this.cleanupResolvers.push(resolve5);
11496
+ this.cleanupResolvers.push(resolve6);
10900
11497
  }
10901
11498
  }),
10902
- new Promise((resolve5) => {
11499
+ new Promise((resolve6) => {
10903
11500
  setTimeout(() => {
10904
11501
  logger.warn(
10905
11502
  `[Workspace] Cleanup timeout after ${timeout}ms, proceeding anyway (${this.activeOperations} operations still active)`
10906
11503
  );
10907
- resolve5();
11504
+ resolve6();
10908
11505
  }, timeout);
10909
11506
  })
10910
11507
  ]);
@@ -10994,7 +11591,7 @@ var init_workspace_manager = __esm({
10994
11591
  * Extract project name from path
10995
11592
  */
10996
11593
  extractProjectName(dirPath) {
10997
- return path5.basename(dirPath);
11594
+ return path6.basename(dirPath);
10998
11595
  }
10999
11596
  /**
11000
11597
  * Extract repository name from owner/repo format
@@ -11204,8 +11801,8 @@ var init_summary = __esm({
11204
11801
  });
11205
11802
 
11206
11803
  // src/state-machine-execution-engine.ts
11207
- import * as path6 from "path";
11208
- import * as fs4 from "fs";
11804
+ import * as path7 from "path";
11805
+ import * as fs5 from "fs";
11209
11806
  function serializeRunState(state) {
11210
11807
  return {
11211
11808
  ...state,
@@ -11253,9 +11850,14 @@ var init_state_machine_execution_engine = __esm({
11253
11850
  async executeChecks(options) {
11254
11851
  const startTime = Date.now();
11255
11852
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
11853
+ const optConversation = options?.conversation;
11854
+ if (optConversation) {
11855
+ const prev = this.executionContext || {};
11856
+ this.executionContext = { ...prev, conversation: optConversation };
11857
+ }
11256
11858
  try {
11257
11859
  if (options.config?.memory) {
11258
- const { MemoryStore: MemoryStore2 } = await import("./memory-store-3N4AZCYB.mjs");
11860
+ const { MemoryStore: MemoryStore2 } = await import("./memory-store-AAPL2MTE.mjs");
11259
11861
  const memoryStore = MemoryStore2.getInstance(options.config.memory);
11260
11862
  await memoryStore.initialize();
11261
11863
  logger.debug("Memory store initialized");
@@ -11297,7 +11899,7 @@ var init_state_machine_execution_engine = __esm({
11297
11899
  try {
11298
11900
  const map = options?.webhookContext?.webhookData;
11299
11901
  if (map) {
11300
- const { CheckProviderRegistry: CheckProviderRegistry2 } = await import("./check-provider-registry-ACRGIYOB.mjs");
11902
+ const { CheckProviderRegistry: CheckProviderRegistry2 } = await import("./check-provider-registry-PANIXYRB.mjs");
11301
11903
  const reg = CheckProviderRegistry2.getInstance();
11302
11904
  const p = reg.getProvider("http_input");
11303
11905
  if (p && typeof p.setWebhookContext === "function") p.setWebhookContext(map);
@@ -11410,7 +12012,7 @@ var init_state_machine_execution_engine = __esm({
11410
12012
  logger.info("[StateMachine] Using state machine engine");
11411
12013
  }
11412
12014
  if (!config) {
11413
- const { ConfigManager } = await import("./config-7VTT64SQ.mjs");
12015
+ const { ConfigManager } = await import("./config-OGOS4ZU4.mjs");
11414
12016
  const configManager = new ConfigManager();
11415
12017
  config = await configManager.getDefaultConfig();
11416
12018
  logger.debug("[StateMachine] Using default configuration (no config provided)");
@@ -11447,13 +12049,64 @@ var init_state_machine_execution_engine = __esm({
11447
12049
  }
11448
12050
  const { initializeWorkspace: initializeWorkspace2 } = (init_build_engine_context(), __toCommonJS(build_engine_context_exports));
11449
12051
  await initializeWorkspace2(context2);
12052
+ if (configWithTagFilter.policy?.engine && configWithTagFilter.policy.engine !== "disabled") {
12053
+ try {
12054
+ logger.debug(
12055
+ `[PolicyEngine] Loading enterprise policy engine (engine=${configWithTagFilter.policy.engine})`
12056
+ );
12057
+ const { loadEnterprisePolicyEngine } = await import("./enterprise/loader");
12058
+ context2.policyEngine = await loadEnterprisePolicyEngine(configWithTagFilter.policy);
12059
+ logger.debug(
12060
+ `[PolicyEngine] Initialized: ${context2.policyEngine?.constructor?.name || "unknown"}`
12061
+ );
12062
+ } catch (err) {
12063
+ try {
12064
+ logger.warn(
12065
+ `[PolicyEngine] Enterprise policy engine init failed, using default: ${err instanceof Error ? err.message : err}`
12066
+ );
12067
+ } catch {
12068
+ }
12069
+ }
12070
+ }
12071
+ if (context2.policyEngine && "setActorContext" in context2.policyEngine) {
12072
+ const actor = {
12073
+ authorAssociation: prInfo?.authorAssociation || process.env.VISOR_AUTHOR_ASSOCIATION,
12074
+ login: prInfo?.author || process.env.GITHUB_ACTOR,
12075
+ isLocalMode: !process.env.GITHUB_ACTIONS
12076
+ };
12077
+ try {
12078
+ const webhookData = this.executionContext?.webhookContext?.webhookData;
12079
+ if (webhookData instanceof Map) {
12080
+ const { extractSlackContext: extractSlackContext2 } = await import("./schedule-tool-handler-B7TMSG6A.mjs");
12081
+ const slackCtx = extractSlackContext2(webhookData);
12082
+ if (slackCtx) {
12083
+ const payload = Array.from(webhookData.values())[0];
12084
+ const userInfo = payload?.slack_user_info;
12085
+ actor.slack = {
12086
+ userId: slackCtx.userId,
12087
+ channelId: slackCtx.channel,
12088
+ channelType: slackCtx.channelType,
12089
+ email: userInfo?.email
12090
+ };
12091
+ }
12092
+ }
12093
+ } catch {
12094
+ }
12095
+ const pullRequest = prInfo ? {
12096
+ number: prInfo.number,
12097
+ labels: prInfo.labels,
12098
+ draft: prInfo.draft,
12099
+ changedFiles: prInfo.files?.length
12100
+ } : void 0;
12101
+ context2.policyEngine.setActorContext(actor, void 0, pullRequest);
12102
+ }
11450
12103
  context2.executionContext = this.getExecutionContext();
11451
12104
  this._lastContext = context2;
11452
12105
  let frontendsHost;
11453
12106
  if (Array.isArray(configWithTagFilter.frontends) && configWithTagFilter.frontends.length > 0) {
11454
12107
  try {
11455
12108
  const { EventBus } = await import("./event-bus-5K3Y2FCS.mjs");
11456
- const { FrontendsHost } = await import("./host-ONVMEHAA.mjs");
12109
+ const { FrontendsHost } = await import("./host-EE6EJ2FM.mjs");
11457
12110
  const bus = new EventBus();
11458
12111
  context2.eventBus = bus;
11459
12112
  frontendsHost = new FrontendsHost(bus, logger);
@@ -11503,6 +12156,13 @@ var init_state_machine_execution_engine = __esm({
11503
12156
  }
11504
12157
  } catch {
11505
12158
  }
12159
+ let runTraceId;
12160
+ try {
12161
+ const { trace: lazyTrace, context: lazyCtx } = await import("./lazy-otel-5NH4ZJJM.mjs");
12162
+ const activeSpan = lazyTrace.getSpan(lazyCtx.active());
12163
+ runTraceId = activeSpan?.spanContext()?.traceId;
12164
+ } catch {
12165
+ }
11506
12166
  await frontendsHost.startAll(() => ({
11507
12167
  eventBus: bus,
11508
12168
  logger,
@@ -11513,6 +12173,7 @@ var init_state_machine_execution_engine = __esm({
11513
12173
  repo: repoObj,
11514
12174
  pr: prNum,
11515
12175
  headSha,
12176
+ traceId: runTraceId,
11516
12177
  event: context2.event || prInfo?.eventType,
11517
12178
  actor: prInfo?.eventContext?.sender?.login || (typeof process.env.GITHUB_ACTOR === "string" ? process.env.GITHUB_ACTOR : void 0)
11518
12179
  },
@@ -11546,9 +12207,9 @@ var init_state_machine_execution_engine = __esm({
11546
12207
  }
11547
12208
  const checkId = String(ev?.checkId || "unknown");
11548
12209
  const threadKey = ev?.threadKey || (channel && threadTs ? `${channel}:${threadTs}` : "session");
11549
- const baseDir = process.env.VISOR_SNAPSHOT_DIR || path6.resolve(process.cwd(), ".visor", "snapshots");
11550
- fs4.mkdirSync(baseDir, { recursive: true });
11551
- const filePath = path6.join(baseDir, `${threadKey}-${checkId}.json`);
12210
+ const baseDir = process.env.VISOR_SNAPSHOT_DIR || path7.resolve(process.cwd(), ".visor", "snapshots");
12211
+ fs5.mkdirSync(baseDir, { recursive: true });
12212
+ const filePath = path7.join(baseDir, `${threadKey}-${checkId}.json`);
11552
12213
  await this.saveSnapshotToFile(filePath);
11553
12214
  logger.info(`[Snapshot] Saved run snapshot: ${filePath}`);
11554
12215
  try {
@@ -11596,6 +12257,13 @@ var init_state_machine_execution_engine = __esm({
11596
12257
  } catch (error) {
11597
12258
  logger.debug(`[StateMachine] Failed to cleanup sessions: ${error}`);
11598
12259
  }
12260
+ if (context2.policyEngine) {
12261
+ try {
12262
+ await context2.policyEngine.shutdown();
12263
+ } catch (error) {
12264
+ logger.debug(`[StateMachine] Failed to cleanup policy engine: ${error}`);
12265
+ }
12266
+ }
11599
12267
  if (context2.workspace) {
11600
12268
  try {
11601
12269
  await context2.workspace.cleanup();
@@ -11682,7 +12350,7 @@ var init_state_machine_execution_engine = __esm({
11682
12350
  * Does not include secrets. Intended for debugging and future resume support.
11683
12351
  */
11684
12352
  async saveSnapshotToFile(filePath) {
11685
- const fs10 = await import("fs/promises");
12353
+ const fs11 = await import("fs/promises");
11686
12354
  const ctx = this._lastContext;
11687
12355
  const runner = this._lastRunner;
11688
12356
  if (!ctx || !runner) {
@@ -11702,14 +12370,14 @@ var init_state_machine_execution_engine = __esm({
11702
12370
  journal: entries,
11703
12371
  requestedChecks: ctx.requestedChecks || []
11704
12372
  };
11705
- await fs10.writeFile(filePath, JSON.stringify(payload, null, 2), "utf8");
12373
+ await fs11.writeFile(filePath, JSON.stringify(payload, null, 2), "utf8");
11706
12374
  }
11707
12375
  /**
11708
12376
  * Load a snapshot JSON from file and return it. Resume support can build on this.
11709
12377
  */
11710
12378
  async loadSnapshotFromFile(filePath) {
11711
- const fs10 = await import("fs/promises");
11712
- const raw = await fs10.readFile(filePath, "utf8");
12379
+ const fs11 = await import("fs/promises");
12380
+ const raw = await fs11.readFile(filePath, "utf8");
11713
12381
  return JSON.parse(raw);
11714
12382
  }
11715
12383
  /**
@@ -11788,10 +12456,10 @@ var init_state_machine_execution_engine = __esm({
11788
12456
  * @returns Array of failure condition evaluation results
11789
12457
  */
11790
12458
  async evaluateFailureConditions(checkName, reviewSummary, config, previousOutputs, authorAssociation) {
11791
- const { FailureConditionEvaluator: FailureConditionEvaluator2 } = await import("./failure-condition-evaluator-4WMDF4Q3.mjs");
12459
+ const { FailureConditionEvaluator: FailureConditionEvaluator2 } = await import("./failure-condition-evaluator-HC3M5377.mjs");
11792
12460
  const evaluator = new FailureConditionEvaluator2();
11793
- const { addEvent: addEvent3 } = await import("./trace-helpers-YHNPC7MR.mjs");
11794
- const { addFailIfTriggered } = await import("./metrics-GXQ2EDXA.mjs");
12461
+ const { addEvent: addEvent3 } = await import("./trace-helpers-PP3YHTAM.mjs");
12462
+ const { addFailIfTriggered } = await import("./metrics-I6A7IHG4.mjs");
11795
12463
  const checkConfig = config.checks?.[checkName];
11796
12464
  if (!checkConfig) {
11797
12465
  return [];
@@ -12043,6 +12711,7 @@ var init_scheduler2 = __esm({
12043
12711
  "src/scheduler/index.ts"() {
12044
12712
  "use strict";
12045
12713
  init_schedule_store();
12714
+ init_store();
12046
12715
  init_schedule_parser();
12047
12716
  init_scheduler();
12048
12717
  init_schedule_tool();
@@ -12088,11 +12757,99 @@ function extractSlackContext(webhookData) {
12088
12757
  }
12089
12758
  return null;
12090
12759
  }
12760
+ function createScheduleToolWithContext(slackContext, _slackClient) {
12761
+ const baseDef = getScheduleToolDefinition();
12762
+ return {
12763
+ ...baseDef,
12764
+ // Override the exec to handle the tool call with context
12765
+ // This is a placeholder - the actual execution happens via executeScheduleTool
12766
+ exec: JSON.stringify({
12767
+ type: "schedule_tool",
12768
+ context: slackContext
12769
+ })
12770
+ };
12771
+ }
12772
+ async function executeScheduleTool(args, slackContext, slackClient, availableWorkflows, permissions) {
12773
+ let timezone = slackContext.timezone;
12774
+ if (!timezone && slackClient && slackContext.userId) {
12775
+ try {
12776
+ const userInfo = await slackClient.getUserInfo(slackContext.userId);
12777
+ if (userInfo.ok && userInfo.user?.tz) {
12778
+ timezone = userInfo.user.tz;
12779
+ slackContext.timezone = timezone;
12780
+ }
12781
+ } catch {
12782
+ }
12783
+ }
12784
+ const toolContext = buildScheduleToolContext(
12785
+ {
12786
+ slackContext: {
12787
+ userId: slackContext.userId,
12788
+ userName: slackContext.userName,
12789
+ timezone: timezone || "UTC",
12790
+ channelType: slackContext.channelType
12791
+ }
12792
+ },
12793
+ availableWorkflows,
12794
+ permissions
12795
+ );
12796
+ const toolArgs = {
12797
+ action: args.action,
12798
+ // What to do
12799
+ reminder_text: args.reminder_text,
12800
+ workflow: args.workflow,
12801
+ workflow_inputs: args.workflow_inputs,
12802
+ // Where to send
12803
+ target_type: args.target_type,
12804
+ target_id: args.target_id,
12805
+ thread_ts: args.thread_ts,
12806
+ // When to run
12807
+ is_recurring: args.is_recurring,
12808
+ cron: args.cron,
12809
+ run_at: args.run_at,
12810
+ original_expression: args.original_expression,
12811
+ // For cancel/pause/resume
12812
+ schedule_id: args.schedule_id
12813
+ };
12814
+ if (!toolArgs.target_type && slackContext.channel) {
12815
+ if (slackContext.threadTs) {
12816
+ toolArgs.target_type = "thread";
12817
+ toolArgs.target_id = slackContext.channel;
12818
+ toolArgs.thread_ts = slackContext.threadTs;
12819
+ } else {
12820
+ toolArgs.target_type = slackContext.channelType === "channel" ? "channel" : "dm";
12821
+ toolArgs.target_id = slackContext.channel;
12822
+ }
12823
+ }
12824
+ try {
12825
+ const result = await handleScheduleAction(toolArgs, toolContext);
12826
+ if (result.success) {
12827
+ return result.message;
12828
+ } else {
12829
+ return `Error: ${result.error || result.message}`;
12830
+ }
12831
+ } catch (error) {
12832
+ const errorMsg = error instanceof Error ? error.message : "Unknown error";
12833
+ logger.error(`[ScheduleToolHandler] Failed to execute schedule tool: ${errorMsg}`);
12834
+ return `Error: ${errorMsg}`;
12835
+ }
12836
+ }
12837
+ function isScheduleToolCall(toolName) {
12838
+ return toolName === "schedule";
12839
+ }
12840
+ async function ensureScheduleStoreInitialized() {
12841
+ const store = ScheduleStore.getInstance();
12842
+ if (!store.isInitialized()) {
12843
+ await store.initialize();
12844
+ }
12845
+ return store;
12846
+ }
12847
+ var ensureReminderStoreInitialized;
12091
12848
  var init_schedule_tool_handler = __esm({
12092
12849
  "src/slack/schedule-tool-handler.ts"() {
12093
- "use strict";
12094
12850
  init_scheduler2();
12095
12851
  init_logger();
12852
+ ensureReminderStoreInitialized = ensureScheduleStoreInitialized;
12096
12853
  }
12097
12854
  });
12098
12855
 
@@ -12158,7 +12915,7 @@ var init_mcp_custom_sse_server = __esm({
12158
12915
  * Returns the actual bound port number
12159
12916
  */
12160
12917
  async start() {
12161
- return new Promise((resolve5, reject) => {
12918
+ return new Promise((resolve6, reject) => {
12162
12919
  try {
12163
12920
  this.server = http.createServer((req, res) => {
12164
12921
  this.handleRequest(req, res).catch((error) => {
@@ -12192,7 +12949,7 @@ var init_mcp_custom_sse_server = __esm({
12192
12949
  );
12193
12950
  }
12194
12951
  this.startKeepalive();
12195
- resolve5(this.port);
12952
+ resolve6(this.port);
12196
12953
  });
12197
12954
  } catch (error) {
12198
12955
  reject(error);
@@ -12255,7 +13012,7 @@ var init_mcp_custom_sse_server = __esm({
12255
13012
  logger.debug(
12256
13013
  `[CustomToolsSSEServer:${this.sessionId}] Grace period before stop: ${waitMs}ms (activeToolCalls=${this.activeToolCalls})`
12257
13014
  );
12258
- await new Promise((resolve5) => setTimeout(resolve5, waitMs));
13015
+ await new Promise((resolve6) => setTimeout(resolve6, waitMs));
12259
13016
  }
12260
13017
  }
12261
13018
  if (this.activeToolCalls > 0) {
@@ -12264,7 +13021,7 @@ var init_mcp_custom_sse_server = __esm({
12264
13021
  `[CustomToolsSSEServer:${this.sessionId}] Waiting for ${this.activeToolCalls} active tool call(s) before stop`
12265
13022
  );
12266
13023
  while (this.activeToolCalls > 0 && Date.now() - startedAt < effectiveDrainTimeoutMs) {
12267
- await new Promise((resolve5) => setTimeout(resolve5, 250));
13024
+ await new Promise((resolve6) => setTimeout(resolve6, 250));
12268
13025
  }
12269
13026
  if (this.activeToolCalls > 0) {
12270
13027
  logger.warn(
@@ -12289,21 +13046,21 @@ var init_mcp_custom_sse_server = __esm({
12289
13046
  }
12290
13047
  this.connections.clear();
12291
13048
  if (this.server) {
12292
- await new Promise((resolve5, reject) => {
13049
+ await new Promise((resolve6, reject) => {
12293
13050
  const timeout = setTimeout(() => {
12294
13051
  if (this.debug) {
12295
13052
  logger.debug(
12296
13053
  `[CustomToolsSSEServer:${this.sessionId}] Force closing server after timeout`
12297
13054
  );
12298
13055
  }
12299
- this.server?.close(() => resolve5());
13056
+ this.server?.close(() => resolve6());
12300
13057
  }, 5e3);
12301
13058
  this.server.close((error) => {
12302
13059
  clearTimeout(timeout);
12303
13060
  if (error) {
12304
13061
  reject(error);
12305
13062
  } else {
12306
- resolve5();
13063
+ resolve6();
12307
13064
  }
12308
13065
  });
12309
13066
  });
@@ -12477,10 +13234,10 @@ var init_mcp_custom_sse_server = __esm({
12477
13234
  `[CustomToolsSSEServer:${this.sessionId}] Received message: ${JSON.stringify(message)}`
12478
13235
  );
12479
13236
  }
12480
- await this.handleMCPMessage(connection, message);
12481
13237
  this.handleCORS(res);
12482
13238
  res.writeHead(202, { "Content-Type": "application/json" });
12483
13239
  res.end(JSON.stringify({ status: "accepted" }));
13240
+ await this.handleMCPMessage(connection, message);
12484
13241
  } catch (error) {
12485
13242
  const errorMsg = error instanceof Error ? error.message : "Unknown error";
12486
13243
  if (this.debug) {
@@ -12489,8 +13246,10 @@ var init_mcp_custom_sse_server = __esm({
12489
13246
  );
12490
13247
  }
12491
13248
  this.sendErrorResponse(connection, null, -32700, "Parse error", { error: errorMsg });
12492
- res.writeHead(400, { "Content-Type": "application/json" });
12493
- res.end(JSON.stringify({ error: "Parse error", details: errorMsg }));
13249
+ if (!res.headersSent) {
13250
+ res.writeHead(400, { "Content-Type": "application/json" });
13251
+ res.end(JSON.stringify({ error: "Parse error", details: errorMsg }));
13252
+ }
12494
13253
  }
12495
13254
  });
12496
13255
  }
@@ -12715,7 +13474,7 @@ var init_mcp_custom_sse_server = __esm({
12715
13474
  logger.warn(
12716
13475
  `[CustomToolsSSEServer:${this.sessionId}] Tool ${toolName} failed (attempt ${attempt + 1}/${retryCount + 1}): ${errorMsg}. Retrying in ${delay}ms`
12717
13476
  );
12718
- await new Promise((resolve5) => setTimeout(resolve5, delay));
13477
+ await new Promise((resolve6) => setTimeout(resolve6, delay));
12719
13478
  attempt++;
12720
13479
  }
12721
13480
  }
@@ -12794,8 +13553,8 @@ var init_mcp_custom_sse_server = __esm({
12794
13553
  });
12795
13554
 
12796
13555
  // src/providers/ai-check-provider.ts
12797
- import fs5 from "fs/promises";
12798
- import path7 from "path";
13556
+ import fs6 from "fs/promises";
13557
+ import path8 from "path";
12799
13558
  var AICheckProvider;
12800
13559
  var init_ai_check_provider = __esm({
12801
13560
  "src/providers/ai-check-provider.ts"() {
@@ -12968,7 +13727,7 @@ var init_ai_check_provider = __esm({
12968
13727
  const hasFileExtension = /\.[a-zA-Z0-9]{1,10}$/i.test(str);
12969
13728
  const hasPathSeparators = /[\/\\]/.test(str);
12970
13729
  const isRelativePath = /^\.{1,2}\//.test(str);
12971
- const isAbsolutePath = path7.isAbsolute(str);
13730
+ const isAbsolutePath = path8.isAbsolute(str);
12972
13731
  const hasTypicalFileChars = /^[a-zA-Z0-9._\-\/\\:~]+$/.test(str);
12973
13732
  if (!(hasFileExtension || isRelativePath || isAbsolutePath || hasPathSeparators)) {
12974
13733
  return false;
@@ -12978,14 +13737,14 @@ var init_ai_check_provider = __esm({
12978
13737
  }
12979
13738
  try {
12980
13739
  let resolvedPath;
12981
- if (path7.isAbsolute(str)) {
12982
- resolvedPath = path7.normalize(str);
13740
+ if (path8.isAbsolute(str)) {
13741
+ resolvedPath = path8.normalize(str);
12983
13742
  } else {
12984
- resolvedPath = path7.resolve(process.cwd(), str);
13743
+ resolvedPath = path8.resolve(process.cwd(), str);
12985
13744
  }
12986
- const fs10 = __require("fs").promises;
13745
+ const fs11 = __require("fs").promises;
12987
13746
  try {
12988
- const stat = await fs10.stat(resolvedPath);
13747
+ const stat = await fs11.stat(resolvedPath);
12989
13748
  return stat.isFile();
12990
13749
  } catch {
12991
13750
  return hasFileExtension && (isRelativePath || isAbsolutePath || hasPathSeparators);
@@ -13002,14 +13761,14 @@ var init_ai_check_provider = __esm({
13002
13761
  throw new Error("Prompt file must have .liquid extension");
13003
13762
  }
13004
13763
  let resolvedPath;
13005
- if (path7.isAbsolute(promptPath)) {
13764
+ if (path8.isAbsolute(promptPath)) {
13006
13765
  resolvedPath = promptPath;
13007
13766
  } else {
13008
- resolvedPath = path7.resolve(process.cwd(), promptPath);
13767
+ resolvedPath = path8.resolve(process.cwd(), promptPath);
13009
13768
  }
13010
- if (!path7.isAbsolute(promptPath)) {
13011
- const normalizedPath = path7.normalize(resolvedPath);
13012
- const currentDir = path7.resolve(process.cwd());
13769
+ if (!path8.isAbsolute(promptPath)) {
13770
+ const normalizedPath = path8.normalize(resolvedPath);
13771
+ const currentDir = path8.resolve(process.cwd());
13013
13772
  if (!normalizedPath.startsWith(currentDir)) {
13014
13773
  throw new Error("Invalid prompt file path: path traversal detected");
13015
13774
  }
@@ -13018,7 +13777,7 @@ var init_ai_check_provider = __esm({
13018
13777
  throw new Error("Invalid prompt file path: path traversal detected");
13019
13778
  }
13020
13779
  try {
13021
- const promptContent = await fs5.readFile(resolvedPath, "utf-8");
13780
+ const promptContent = await fs6.readFile(resolvedPath, "utf-8");
13022
13781
  return promptContent;
13023
13782
  } catch (error) {
13024
13783
  throw new Error(
@@ -13523,6 +14282,38 @@ ${preview}`);
13523
14282
  if (config.ai_max_iterations !== void 0 && aiConfig.maxIterations === void 0) {
13524
14283
  aiConfig.maxIterations = config.ai_max_iterations;
13525
14284
  }
14285
+ const policyEngine = sessionInfo?._parentContext?.policyEngine;
14286
+ if (policyEngine) {
14287
+ try {
14288
+ const checkName = config.checkName || "unknown";
14289
+ const decision = await policyEngine.evaluateCapabilities(checkName, {
14290
+ allowEdit: aiConfig.allowEdit,
14291
+ allowBash: aiConfig.allowBash,
14292
+ allowedTools: aiConfig.allowedTools
14293
+ });
14294
+ if (decision.capabilities) {
14295
+ if (decision.capabilities.allowEdit === false) aiConfig.allowEdit = false;
14296
+ if (decision.capabilities.allowBash === false) aiConfig.allowBash = false;
14297
+ if (decision.capabilities.allowedTools) {
14298
+ if (aiConfig.allowedTools) {
14299
+ aiConfig.allowedTools = aiConfig.allowedTools.filter(
14300
+ (t) => decision.capabilities.allowedTools.includes(t)
14301
+ );
14302
+ } else {
14303
+ aiConfig.allowedTools = decision.capabilities.allowedTools;
14304
+ }
14305
+ }
14306
+ }
14307
+ } catch (err) {
14308
+ try {
14309
+ const { logger: logger2 } = (init_logger(), __toCommonJS(logger_exports));
14310
+ logger2.warn(
14311
+ `[PolicyEngine] Capability evaluation failed: ${err instanceof Error ? err.message : err}`
14312
+ );
14313
+ } catch {
14314
+ }
14315
+ }
14316
+ }
13526
14317
  const customPrompt = config.prompt;
13527
14318
  if (!customPrompt) {
13528
14319
  throw new Error(
@@ -13541,6 +14332,9 @@ ${preview}`);
13541
14332
  Object.assign(mcpServers, config.ai.mcpServers);
13542
14333
  }
13543
14334
  const mcpServersJsExpr = config.ai_mcp_servers_js;
14335
+ logger.info(
14336
+ `[AICheckProvider] ai_mcp_servers_js check: hasExpr=${!!mcpServersJsExpr}, hasDeps=${!!_dependencyResults}, depsSize=${_dependencyResults?.size ?? 0}`
14337
+ );
13544
14338
  if (mcpServersJsExpr && _dependencyResults) {
13545
14339
  try {
13546
14340
  const dynamicServers = this.evaluateMcpServersJs(
@@ -14119,6 +14913,10 @@ ${processedPrompt}` : processedPrompt;
14119
14913
  memory: config.__memoryAccessor || {}
14120
14914
  };
14121
14915
  try {
14916
+ const buildConfigOutput = jsContext.outputs?.["build-config"];
14917
+ logger.info(
14918
+ `[AICheckProvider] ai_mcp_servers_js context: build-config output keys=${buildConfigOutput ? Object.keys(buildConfigOutput).join(",") : "N/A"}, mcp_servers keys=${buildConfigOutput?.mcp_servers ? Object.keys(buildConfigOutput.mcp_servers).join(",") : "N/A"}`
14919
+ );
14122
14920
  const result = compileAndRun(this.sandbox, expression, jsContext, {
14123
14921
  injectLog: true,
14124
14922
  wrapFunction: true,
@@ -14749,8 +15547,8 @@ var init_template_context = __esm({
14749
15547
  });
14750
15548
 
14751
15549
  // src/providers/http-client-provider.ts
14752
- import * as fs6 from "fs";
14753
- import * as path8 from "path";
15550
+ import * as fs7 from "fs";
15551
+ import * as path9 from "path";
14754
15552
  var HttpClientProvider;
14755
15553
  var init_http_client_provider = __esm({
14756
15554
  "src/providers/http-client-provider.ts"() {
@@ -14855,14 +15653,14 @@ var init_http_client_provider = __esm({
14855
15653
  const parentContext = context2?._parentContext;
14856
15654
  const workingDirectory = parentContext?.workingDirectory;
14857
15655
  const workspaceEnabled = parentContext?.workspace?.isEnabled?.();
14858
- if (workspaceEnabled && workingDirectory && !path8.isAbsolute(resolvedOutputFile)) {
14859
- resolvedOutputFile = path8.join(workingDirectory, resolvedOutputFile);
15656
+ if (workspaceEnabled && workingDirectory && !path9.isAbsolute(resolvedOutputFile)) {
15657
+ resolvedOutputFile = path9.join(workingDirectory, resolvedOutputFile);
14860
15658
  logger.debug(
14861
15659
  `[http_client] Resolved relative output_file to workspace: ${resolvedOutputFile}`
14862
15660
  );
14863
15661
  }
14864
- if (skipIfExists && fs6.existsSync(resolvedOutputFile)) {
14865
- const stats = fs6.statSync(resolvedOutputFile);
15662
+ if (skipIfExists && fs7.existsSync(resolvedOutputFile)) {
15663
+ const stats = fs7.statSync(resolvedOutputFile);
14866
15664
  logger.verbose(`[http_client] File cached: ${resolvedOutputFile} (${stats.size} bytes)`);
14867
15665
  return {
14868
15666
  issues: [],
@@ -15073,13 +15871,13 @@ var init_http_client_provider = __esm({
15073
15871
  ]
15074
15872
  };
15075
15873
  }
15076
- const parentDir = path8.dirname(outputFile);
15077
- if (parentDir && !fs6.existsSync(parentDir)) {
15078
- fs6.mkdirSync(parentDir, { recursive: true });
15874
+ const parentDir = path9.dirname(outputFile);
15875
+ if (parentDir && !fs7.existsSync(parentDir)) {
15876
+ fs7.mkdirSync(parentDir, { recursive: true });
15079
15877
  }
15080
15878
  const arrayBuffer = await response.arrayBuffer();
15081
15879
  const buffer = Buffer.from(arrayBuffer);
15082
- fs6.writeFileSync(outputFile, buffer);
15880
+ fs7.writeFileSync(outputFile, buffer);
15083
15881
  const contentType = response.headers.get("content-type") || "application/octet-stream";
15084
15882
  logger.verbose(`[http_client] Downloaded: ${outputFile} (${buffer.length} bytes)`);
15085
15883
  return {
@@ -15835,8 +16633,8 @@ var init_claude_code_types = __esm({
15835
16633
  });
15836
16634
 
15837
16635
  // src/providers/claude-code-check-provider.ts
15838
- import fs7 from "fs/promises";
15839
- import path9 from "path";
16636
+ import fs8 from "fs/promises";
16637
+ import path10 from "path";
15840
16638
  function isClaudeCodeConstructor(value) {
15841
16639
  return typeof value === "function";
15842
16640
  }
@@ -15995,7 +16793,7 @@ var init_claude_code_check_provider = __esm({
15995
16793
  const hasFileExtension = /\.[a-zA-Z0-9]{1,10}$/i.test(str);
15996
16794
  const hasPathSeparators = /[\/\\]/.test(str);
15997
16795
  const isRelativePath = /^\.{1,2}\//.test(str);
15998
- const isAbsolutePath = path9.isAbsolute(str);
16796
+ const isAbsolutePath = path10.isAbsolute(str);
15999
16797
  const hasTypicalFileChars = /^[a-zA-Z0-9._\-\/\\:~]+$/.test(str);
16000
16798
  if (!(hasFileExtension || isRelativePath || isAbsolutePath || hasPathSeparators)) {
16001
16799
  return false;
@@ -16005,13 +16803,13 @@ var init_claude_code_check_provider = __esm({
16005
16803
  }
16006
16804
  try {
16007
16805
  let resolvedPath;
16008
- if (path9.isAbsolute(str)) {
16009
- resolvedPath = path9.normalize(str);
16806
+ if (path10.isAbsolute(str)) {
16807
+ resolvedPath = path10.normalize(str);
16010
16808
  } else {
16011
- resolvedPath = path9.resolve(process.cwd(), str);
16809
+ resolvedPath = path10.resolve(process.cwd(), str);
16012
16810
  }
16013
16811
  try {
16014
- const stat = await fs7.stat(resolvedPath);
16812
+ const stat = await fs8.stat(resolvedPath);
16015
16813
  return stat.isFile();
16016
16814
  } catch {
16017
16815
  return hasFileExtension && (isRelativePath || isAbsolutePath || hasPathSeparators);
@@ -16028,14 +16826,14 @@ var init_claude_code_check_provider = __esm({
16028
16826
  throw new Error("Prompt file must have .liquid extension");
16029
16827
  }
16030
16828
  let resolvedPath;
16031
- if (path9.isAbsolute(promptPath)) {
16829
+ if (path10.isAbsolute(promptPath)) {
16032
16830
  resolvedPath = promptPath;
16033
16831
  } else {
16034
- resolvedPath = path9.resolve(process.cwd(), promptPath);
16832
+ resolvedPath = path10.resolve(process.cwd(), promptPath);
16035
16833
  }
16036
- if (!path9.isAbsolute(promptPath)) {
16037
- const normalizedPath = path9.normalize(resolvedPath);
16038
- const currentDir = path9.resolve(process.cwd());
16834
+ if (!path10.isAbsolute(promptPath)) {
16835
+ const normalizedPath = path10.normalize(resolvedPath);
16836
+ const currentDir = path10.resolve(process.cwd());
16039
16837
  if (!normalizedPath.startsWith(currentDir)) {
16040
16838
  throw new Error("Invalid prompt file path: path traversal detected");
16041
16839
  }
@@ -16044,7 +16842,7 @@ var init_claude_code_check_provider = __esm({
16044
16842
  throw new Error("Invalid prompt file path: path traversal detected");
16045
16843
  }
16046
16844
  try {
16047
- const promptContent = await fs7.readFile(resolvedPath, "utf-8");
16845
+ const promptContent = await fs8.readFile(resolvedPath, "utf-8");
16048
16846
  return promptContent;
16049
16847
  } catch (error) {
16050
16848
  throw new Error(
@@ -16198,7 +16996,36 @@ var init_claude_code_check_provider = __esm({
16198
16996
  query.tools = claudeCodeConfig.allowedTools.map((name) => ({ name }));
16199
16997
  }
16200
16998
  if (claudeCodeConfig.mcpServers && Object.keys(claudeCodeConfig.mcpServers).length > 0) {
16201
- query.mcpServers = claudeCodeConfig.mcpServers;
16999
+ const policyEngine = sessionInfo?._parentContext?.policyEngine;
17000
+ let filteredServers = claudeCodeConfig.mcpServers;
17001
+ if (policyEngine) {
17002
+ const allowed = {};
17003
+ for (const [name, serverCfg] of Object.entries(claudeCodeConfig.mcpServers)) {
17004
+ try {
17005
+ const decision = await policyEngine.evaluateToolInvocation(
17006
+ name,
17007
+ "*",
17008
+ serverCfg.transport
17009
+ );
17010
+ if (decision.allowed) {
17011
+ allowed[name] = serverCfg;
17012
+ }
17013
+ } catch (err) {
17014
+ allowed[name] = serverCfg;
17015
+ try {
17016
+ const { logger: logger2 } = (init_logger(), __toCommonJS(logger_exports));
17017
+ logger2.warn(
17018
+ `[PolicyEngine] Tool invocation evaluation failed for server '${name}': ${err instanceof Error ? err.message : err}`
17019
+ );
17020
+ } catch {
17021
+ }
17022
+ }
17023
+ }
17024
+ filteredServers = allowed;
17025
+ }
17026
+ if (Object.keys(filteredServers).length > 0) {
17027
+ query.mcpServers = filteredServers;
17028
+ }
16202
17029
  }
16203
17030
  let response;
16204
17031
  if (sessionInfo?.reuseSession && sessionInfo.parentSessionId) {
@@ -18596,14 +19423,14 @@ var require_util = __commonJS({
18596
19423
  }
18597
19424
  const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
18598
19425
  let origin = url.origin != null ? url.origin : `${url.protocol}//${url.hostname}:${port}`;
18599
- let path12 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
19426
+ let path14 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
18600
19427
  if (origin.endsWith("/")) {
18601
19428
  origin = origin.substring(0, origin.length - 1);
18602
19429
  }
18603
- if (path12 && !path12.startsWith("/")) {
18604
- path12 = `/${path12}`;
19430
+ if (path14 && !path14.startsWith("/")) {
19431
+ path14 = `/${path14}`;
18605
19432
  }
18606
- url = new URL(origin + path12);
19433
+ url = new URL(origin + path14);
18607
19434
  }
18608
19435
  return url;
18609
19436
  }
@@ -20217,20 +21044,20 @@ var require_parseParams = __commonJS({
20217
21044
  var require_basename = __commonJS({
20218
21045
  "node_modules/@fastify/busboy/lib/utils/basename.js"(exports, module) {
20219
21046
  "use strict";
20220
- module.exports = function basename2(path12) {
20221
- if (typeof path12 !== "string") {
21047
+ module.exports = function basename2(path14) {
21048
+ if (typeof path14 !== "string") {
20222
21049
  return "";
20223
21050
  }
20224
- for (var i = path12.length - 1; i >= 0; --i) {
20225
- switch (path12.charCodeAt(i)) {
21051
+ for (var i = path14.length - 1; i >= 0; --i) {
21052
+ switch (path14.charCodeAt(i)) {
20226
21053
  case 47:
20227
21054
  // '/'
20228
21055
  case 92:
20229
- path12 = path12.slice(i + 1);
20230
- return path12 === ".." || path12 === "." ? "" : path12;
21056
+ path14 = path14.slice(i + 1);
21057
+ return path14 === ".." || path14 === "." ? "" : path14;
20231
21058
  }
20232
21059
  }
20233
- return path12 === ".." || path12 === "." ? "" : path12;
21060
+ return path14 === ".." || path14 === "." ? "" : path14;
20234
21061
  };
20235
21062
  }
20236
21063
  });
@@ -21623,8 +22450,8 @@ var require_util2 = __commonJS({
21623
22450
  function createDeferredPromise() {
21624
22451
  let res;
21625
22452
  let rej;
21626
- const promise = new Promise((resolve5, reject) => {
21627
- res = resolve5;
22453
+ const promise = new Promise((resolve6, reject) => {
22454
+ res = resolve6;
21628
22455
  rej = reject;
21629
22456
  });
21630
22457
  return { promise, resolve: res, reject: rej };
@@ -23129,8 +23956,8 @@ Content-Type: ${value.type || "application/octet-stream"}\r
23129
23956
  });
23130
23957
  }
23131
23958
  });
23132
- const busboyResolve = new Promise((resolve5, reject) => {
23133
- busboy.on("finish", resolve5);
23959
+ const busboyResolve = new Promise((resolve6, reject) => {
23960
+ busboy.on("finish", resolve6);
23134
23961
  busboy.on("error", (err) => reject(new TypeError(err)));
23135
23962
  });
23136
23963
  if (this.body !== null) for await (const chunk of consumeBody(this[kState].body)) busboy.write(chunk);
@@ -23261,7 +24088,7 @@ var require_request = __commonJS({
23261
24088
  }
23262
24089
  var Request = class _Request {
23263
24090
  constructor(origin, {
23264
- path: path12,
24091
+ path: path14,
23265
24092
  method,
23266
24093
  body,
23267
24094
  headers,
@@ -23275,11 +24102,11 @@ var require_request = __commonJS({
23275
24102
  throwOnError,
23276
24103
  expectContinue
23277
24104
  }, handler) {
23278
- if (typeof path12 !== "string") {
24105
+ if (typeof path14 !== "string") {
23279
24106
  throw new InvalidArgumentError("path must be a string");
23280
- } else if (path12[0] !== "/" && !(path12.startsWith("http://") || path12.startsWith("https://")) && method !== "CONNECT") {
24107
+ } else if (path14[0] !== "/" && !(path14.startsWith("http://") || path14.startsWith("https://")) && method !== "CONNECT") {
23281
24108
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
23282
- } else if (invalidPathRegex.exec(path12) !== null) {
24109
+ } else if (invalidPathRegex.exec(path14) !== null) {
23283
24110
  throw new InvalidArgumentError("invalid request path");
23284
24111
  }
23285
24112
  if (typeof method !== "string") {
@@ -23342,7 +24169,7 @@ var require_request = __commonJS({
23342
24169
  this.completed = false;
23343
24170
  this.aborted = false;
23344
24171
  this.upgrade = upgrade || null;
23345
- this.path = query ? util.buildURL(path12, query) : path12;
24172
+ this.path = query ? util.buildURL(path14, query) : path14;
23346
24173
  this.origin = origin;
23347
24174
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
23348
24175
  this.blocking = blocking == null ? false : blocking;
@@ -23664,9 +24491,9 @@ var require_dispatcher_base = __commonJS({
23664
24491
  }
23665
24492
  close(callback) {
23666
24493
  if (callback === void 0) {
23667
- return new Promise((resolve5, reject) => {
24494
+ return new Promise((resolve6, reject) => {
23668
24495
  this.close((err, data) => {
23669
- return err ? reject(err) : resolve5(data);
24496
+ return err ? reject(err) : resolve6(data);
23670
24497
  });
23671
24498
  });
23672
24499
  }
@@ -23704,12 +24531,12 @@ var require_dispatcher_base = __commonJS({
23704
24531
  err = null;
23705
24532
  }
23706
24533
  if (callback === void 0) {
23707
- return new Promise((resolve5, reject) => {
24534
+ return new Promise((resolve6, reject) => {
23708
24535
  this.destroy(err, (err2, data) => {
23709
24536
  return err2 ? (
23710
24537
  /* istanbul ignore next: should never error */
23711
24538
  reject(err2)
23712
- ) : resolve5(data);
24539
+ ) : resolve6(data);
23713
24540
  });
23714
24541
  });
23715
24542
  }
@@ -24350,9 +25177,9 @@ var require_RedirectHandler = __commonJS({
24350
25177
  return this.handler.onHeaders(statusCode, headers, resume, statusText);
24351
25178
  }
24352
25179
  const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
24353
- const path12 = search ? `${pathname}${search}` : pathname;
25180
+ const path14 = search ? `${pathname}${search}` : pathname;
24354
25181
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
24355
- this.opts.path = path12;
25182
+ this.opts.path = path14;
24356
25183
  this.opts.origin = origin;
24357
25184
  this.opts.maxRedirections = 0;
24358
25185
  this.opts.query = null;
@@ -24771,16 +25598,16 @@ var require_client = __commonJS({
24771
25598
  return this[kNeedDrain] < 2;
24772
25599
  }
24773
25600
  async [kClose]() {
24774
- return new Promise((resolve5) => {
25601
+ return new Promise((resolve6) => {
24775
25602
  if (!this[kSize]) {
24776
- resolve5(null);
25603
+ resolve6(null);
24777
25604
  } else {
24778
- this[kClosedResolve] = resolve5;
25605
+ this[kClosedResolve] = resolve6;
24779
25606
  }
24780
25607
  });
24781
25608
  }
24782
25609
  async [kDestroy](err) {
24783
- return new Promise((resolve5) => {
25610
+ return new Promise((resolve6) => {
24784
25611
  const requests = this[kQueue].splice(this[kPendingIdx]);
24785
25612
  for (let i = 0; i < requests.length; i++) {
24786
25613
  const request = requests[i];
@@ -24791,7 +25618,7 @@ var require_client = __commonJS({
24791
25618
  this[kClosedResolve]();
24792
25619
  this[kClosedResolve] = null;
24793
25620
  }
24794
- resolve5();
25621
+ resolve6();
24795
25622
  };
24796
25623
  if (this[kHTTP2Session] != null) {
24797
25624
  util.destroy(this[kHTTP2Session], err);
@@ -25371,7 +26198,7 @@ var require_client = __commonJS({
25371
26198
  });
25372
26199
  }
25373
26200
  try {
25374
- const socket = await new Promise((resolve5, reject) => {
26201
+ const socket = await new Promise((resolve6, reject) => {
25375
26202
  client[kConnector]({
25376
26203
  host,
25377
26204
  hostname,
@@ -25383,7 +26210,7 @@ var require_client = __commonJS({
25383
26210
  if (err) {
25384
26211
  reject(err);
25385
26212
  } else {
25386
- resolve5(socket2);
26213
+ resolve6(socket2);
25387
26214
  }
25388
26215
  });
25389
26216
  });
@@ -25594,7 +26421,7 @@ var require_client = __commonJS({
25594
26421
  writeH2(client, client[kHTTP2Session], request);
25595
26422
  return;
25596
26423
  }
25597
- const { body, method, path: path12, host, upgrade, headers, blocking, reset } = request;
26424
+ const { body, method, path: path14, host, upgrade, headers, blocking, reset } = request;
25598
26425
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
25599
26426
  if (body && typeof body.read === "function") {
25600
26427
  body.read(0);
@@ -25644,7 +26471,7 @@ var require_client = __commonJS({
25644
26471
  if (blocking) {
25645
26472
  socket[kBlocking] = true;
25646
26473
  }
25647
- let header = `${method} ${path12} HTTP/1.1\r
26474
+ let header = `${method} ${path14} HTTP/1.1\r
25648
26475
  `;
25649
26476
  if (typeof host === "string") {
25650
26477
  header += `host: ${host}\r
@@ -25707,7 +26534,7 @@ upgrade: ${upgrade}\r
25707
26534
  return true;
25708
26535
  }
25709
26536
  function writeH2(client, session, request) {
25710
- const { body, method, path: path12, host, upgrade, expectContinue, signal, headers: reqHeaders } = request;
26537
+ const { body, method, path: path14, host, upgrade, expectContinue, signal, headers: reqHeaders } = request;
25711
26538
  let headers;
25712
26539
  if (typeof reqHeaders === "string") headers = Request[kHTTP2CopyHeaders](reqHeaders.trim());
25713
26540
  else headers = reqHeaders;
@@ -25750,7 +26577,7 @@ upgrade: ${upgrade}\r
25750
26577
  });
25751
26578
  return true;
25752
26579
  }
25753
- headers[HTTP2_HEADER_PATH] = path12;
26580
+ headers[HTTP2_HEADER_PATH] = path14;
25754
26581
  headers[HTTP2_HEADER_SCHEME] = "https";
25755
26582
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
25756
26583
  if (body && typeof body.read === "function") {
@@ -26007,12 +26834,12 @@ upgrade: ${upgrade}\r
26007
26834
  cb();
26008
26835
  }
26009
26836
  }
26010
- const waitForDrain = () => new Promise((resolve5, reject) => {
26837
+ const waitForDrain = () => new Promise((resolve6, reject) => {
26011
26838
  assert(callback === null);
26012
26839
  if (socket[kError]) {
26013
26840
  reject(socket[kError]);
26014
26841
  } else {
26015
- callback = resolve5;
26842
+ callback = resolve6;
26016
26843
  }
26017
26844
  });
26018
26845
  if (client[kHTTPConnVersion] === "h2") {
@@ -26358,8 +27185,8 @@ var require_pool_base = __commonJS({
26358
27185
  if (this[kQueue].isEmpty()) {
26359
27186
  return Promise.all(this[kClients].map((c) => c.close()));
26360
27187
  } else {
26361
- return new Promise((resolve5) => {
26362
- this[kClosedResolve] = resolve5;
27188
+ return new Promise((resolve6) => {
27189
+ this[kClosedResolve] = resolve6;
26363
27190
  });
26364
27191
  }
26365
27192
  }
@@ -26937,7 +27764,7 @@ var require_readable = __commonJS({
26937
27764
  if (this.closed) {
26938
27765
  return Promise.resolve(null);
26939
27766
  }
26940
- return new Promise((resolve5, reject) => {
27767
+ return new Promise((resolve6, reject) => {
26941
27768
  const signalListenerCleanup = signal ? util.addAbortListener(signal, () => {
26942
27769
  this.destroy();
26943
27770
  }) : noop;
@@ -26946,7 +27773,7 @@ var require_readable = __commonJS({
26946
27773
  if (signal && signal.aborted) {
26947
27774
  reject(signal.reason || Object.assign(new Error("The operation was aborted"), { name: "AbortError" }));
26948
27775
  } else {
26949
- resolve5(null);
27776
+ resolve6(null);
26950
27777
  }
26951
27778
  }).on("error", noop).on("data", function(chunk) {
26952
27779
  limit -= chunk.length;
@@ -26968,11 +27795,11 @@ var require_readable = __commonJS({
26968
27795
  throw new TypeError("unusable");
26969
27796
  }
26970
27797
  assert(!stream[kConsume]);
26971
- return new Promise((resolve5, reject) => {
27798
+ return new Promise((resolve6, reject) => {
26972
27799
  stream[kConsume] = {
26973
27800
  type,
26974
27801
  stream,
26975
- resolve: resolve5,
27802
+ resolve: resolve6,
26976
27803
  reject,
26977
27804
  length: 0,
26978
27805
  body: []
@@ -27007,12 +27834,12 @@ var require_readable = __commonJS({
27007
27834
  }
27008
27835
  }
27009
27836
  function consumeEnd(consume2) {
27010
- const { type, body, resolve: resolve5, stream, length } = consume2;
27837
+ const { type, body, resolve: resolve6, stream, length } = consume2;
27011
27838
  try {
27012
27839
  if (type === "text") {
27013
- resolve5(toUSVString(Buffer.concat(body)));
27840
+ resolve6(toUSVString(Buffer.concat(body)));
27014
27841
  } else if (type === "json") {
27015
- resolve5(JSON.parse(Buffer.concat(body)));
27842
+ resolve6(JSON.parse(Buffer.concat(body)));
27016
27843
  } else if (type === "arrayBuffer") {
27017
27844
  const dst = new Uint8Array(length);
27018
27845
  let pos = 0;
@@ -27020,12 +27847,12 @@ var require_readable = __commonJS({
27020
27847
  dst.set(buf, pos);
27021
27848
  pos += buf.byteLength;
27022
27849
  }
27023
- resolve5(dst.buffer);
27850
+ resolve6(dst.buffer);
27024
27851
  } else if (type === "blob") {
27025
27852
  if (!Blob2) {
27026
27853
  Blob2 = __require("buffer").Blob;
27027
27854
  }
27028
- resolve5(new Blob2(body, { type: stream[kContentType] }));
27855
+ resolve6(new Blob2(body, { type: stream[kContentType] }));
27029
27856
  }
27030
27857
  consumeFinish(consume2);
27031
27858
  } catch (err) {
@@ -27282,9 +28109,9 @@ var require_api_request = __commonJS({
27282
28109
  };
27283
28110
  function request(opts, callback) {
27284
28111
  if (callback === void 0) {
27285
- return new Promise((resolve5, reject) => {
28112
+ return new Promise((resolve6, reject) => {
27286
28113
  request.call(this, opts, (err, data) => {
27287
- return err ? reject(err) : resolve5(data);
28114
+ return err ? reject(err) : resolve6(data);
27288
28115
  });
27289
28116
  });
27290
28117
  }
@@ -27457,9 +28284,9 @@ var require_api_stream = __commonJS({
27457
28284
  };
27458
28285
  function stream(opts, factory, callback) {
27459
28286
  if (callback === void 0) {
27460
- return new Promise((resolve5, reject) => {
28287
+ return new Promise((resolve6, reject) => {
27461
28288
  stream.call(this, opts, factory, (err, data) => {
27462
- return err ? reject(err) : resolve5(data);
28289
+ return err ? reject(err) : resolve6(data);
27463
28290
  });
27464
28291
  });
27465
28292
  }
@@ -27740,9 +28567,9 @@ var require_api_upgrade = __commonJS({
27740
28567
  };
27741
28568
  function upgrade(opts, callback) {
27742
28569
  if (callback === void 0) {
27743
- return new Promise((resolve5, reject) => {
28570
+ return new Promise((resolve6, reject) => {
27744
28571
  upgrade.call(this, opts, (err, data) => {
27745
- return err ? reject(err) : resolve5(data);
28572
+ return err ? reject(err) : resolve6(data);
27746
28573
  });
27747
28574
  });
27748
28575
  }
@@ -27831,9 +28658,9 @@ var require_api_connect = __commonJS({
27831
28658
  };
27832
28659
  function connect(opts, callback) {
27833
28660
  if (callback === void 0) {
27834
- return new Promise((resolve5, reject) => {
28661
+ return new Promise((resolve6, reject) => {
27835
28662
  connect.call(this, opts, (err, data) => {
27836
- return err ? reject(err) : resolve5(data);
28663
+ return err ? reject(err) : resolve6(data);
27837
28664
  });
27838
28665
  });
27839
28666
  }
@@ -27993,20 +28820,20 @@ var require_mock_utils = __commonJS({
27993
28820
  }
27994
28821
  return true;
27995
28822
  }
27996
- function safeUrl(path12) {
27997
- if (typeof path12 !== "string") {
27998
- return path12;
28823
+ function safeUrl(path14) {
28824
+ if (typeof path14 !== "string") {
28825
+ return path14;
27999
28826
  }
28000
- const pathSegments = path12.split("?");
28827
+ const pathSegments = path14.split("?");
28001
28828
  if (pathSegments.length !== 2) {
28002
- return path12;
28829
+ return path14;
28003
28830
  }
28004
28831
  const qp = new URLSearchParams(pathSegments.pop());
28005
28832
  qp.sort();
28006
28833
  return [...pathSegments, qp.toString()].join("?");
28007
28834
  }
28008
- function matchKey(mockDispatch2, { path: path12, method, body, headers }) {
28009
- const pathMatch = matchValue(mockDispatch2.path, path12);
28835
+ function matchKey(mockDispatch2, { path: path14, method, body, headers }) {
28836
+ const pathMatch = matchValue(mockDispatch2.path, path14);
28010
28837
  const methodMatch = matchValue(mockDispatch2.method, method);
28011
28838
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
28012
28839
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -28024,7 +28851,7 @@ var require_mock_utils = __commonJS({
28024
28851
  function getMockDispatch(mockDispatches, key) {
28025
28852
  const basePath = key.query ? buildURL(key.path, key.query) : key.path;
28026
28853
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
28027
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path12 }) => matchValue(safeUrl(path12), resolvedPath));
28854
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path14 }) => matchValue(safeUrl(path14), resolvedPath));
28028
28855
  if (matchedMockDispatches.length === 0) {
28029
28856
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
28030
28857
  }
@@ -28061,9 +28888,9 @@ var require_mock_utils = __commonJS({
28061
28888
  }
28062
28889
  }
28063
28890
  function buildKey(opts) {
28064
- const { path: path12, method, body, headers, query } = opts;
28891
+ const { path: path14, method, body, headers, query } = opts;
28065
28892
  return {
28066
- path: path12,
28893
+ path: path14,
28067
28894
  method,
28068
28895
  body,
28069
28896
  headers,
@@ -28512,10 +29339,10 @@ var require_pending_interceptors_formatter = __commonJS({
28512
29339
  }
28513
29340
  format(pendingInterceptors) {
28514
29341
  const withPrettyHeaders = pendingInterceptors.map(
28515
- ({ method, path: path12, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
29342
+ ({ method, path: path14, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
28516
29343
  Method: method,
28517
29344
  Origin: origin,
28518
- Path: path12,
29345
+ Path: path14,
28519
29346
  "Status code": statusCode,
28520
29347
  Persistent: persist ? "\u2705" : "\u274C",
28521
29348
  Invocations: timesInvoked,
@@ -31456,7 +32283,7 @@ var require_fetch = __commonJS({
31456
32283
  async function dispatch({ body }) {
31457
32284
  const url = requestCurrentURL(request);
31458
32285
  const agent = fetchParams.controller.dispatcher;
31459
- return new Promise((resolve5, reject) => agent.dispatch(
32286
+ return new Promise((resolve6, reject) => agent.dispatch(
31460
32287
  {
31461
32288
  path: url.pathname + url.search,
31462
32289
  origin: url.origin,
@@ -31532,7 +32359,7 @@ var require_fetch = __commonJS({
31532
32359
  }
31533
32360
  }
31534
32361
  }
31535
- resolve5({
32362
+ resolve6({
31536
32363
  status,
31537
32364
  statusText,
31538
32365
  headersList: headers[kHeadersList],
@@ -31575,7 +32402,7 @@ var require_fetch = __commonJS({
31575
32402
  const val = headersList[n + 1].toString("latin1");
31576
32403
  headers[kHeadersList].append(key, val);
31577
32404
  }
31578
- resolve5({
32405
+ resolve6({
31579
32406
  status,
31580
32407
  statusText: STATUS_CODES[status],
31581
32408
  headersList: headers[kHeadersList],
@@ -33136,8 +33963,8 @@ var require_util6 = __commonJS({
33136
33963
  }
33137
33964
  }
33138
33965
  }
33139
- function validateCookiePath(path12) {
33140
- for (const char of path12) {
33966
+ function validateCookiePath(path14) {
33967
+ for (const char of path14) {
33141
33968
  const code = char.charCodeAt(0);
33142
33969
  if (code < 33 || char === ";") {
33143
33970
  throw new Error("Invalid cookie path");
@@ -34817,11 +35644,11 @@ var require_undici = __commonJS({
34817
35644
  if (typeof opts.path !== "string") {
34818
35645
  throw new InvalidArgumentError("invalid opts.path");
34819
35646
  }
34820
- let path12 = opts.path;
35647
+ let path14 = opts.path;
34821
35648
  if (!opts.path.startsWith("/")) {
34822
- path12 = `/${path12}`;
35649
+ path14 = `/${path14}`;
34823
35650
  }
34824
- url = new URL(util.parseOrigin(url).origin + path12);
35651
+ url = new URL(util.parseOrigin(url).origin + path14);
34825
35652
  } else {
34826
35653
  if (!opts) {
34827
35654
  opts = typeof url === "object" ? url : {};
@@ -35070,6 +35897,39 @@ var init_mcp_check_provider = __esm({
35070
35897
  }
35071
35898
  async execute(prInfo, config, dependencyResults, sessionInfo) {
35072
35899
  const cfg = config;
35900
+ const policyEngine = sessionInfo?._parentContext?.policyEngine;
35901
+ if (policyEngine && cfg.method) {
35902
+ try {
35903
+ const serverName = config.checkName || cfg.server || "unknown";
35904
+ const decision = await policyEngine.evaluateToolInvocation(
35905
+ serverName,
35906
+ cfg.method,
35907
+ cfg.transport
35908
+ );
35909
+ if (!decision.allowed) {
35910
+ return {
35911
+ issues: [
35912
+ {
35913
+ file: "mcp",
35914
+ line: 0,
35915
+ ruleId: "policy/tool_denied",
35916
+ message: `MCP method '${cfg.method}' blocked by policy: ${decision.reason || "denied"}`,
35917
+ severity: "error",
35918
+ category: "security"
35919
+ }
35920
+ ]
35921
+ };
35922
+ }
35923
+ } catch (err) {
35924
+ try {
35925
+ const { logger: logger2 } = (init_logger(), __toCommonJS(logger_exports));
35926
+ logger2.warn(
35927
+ `[PolicyEngine] Tool invocation evaluation failed: ${err instanceof Error ? err.message : err}`
35928
+ );
35929
+ } catch {
35930
+ }
35931
+ }
35932
+ }
35073
35933
  try {
35074
35934
  const templateContext = {
35075
35935
  pr: {
@@ -35315,7 +36175,7 @@ var init_mcp_check_provider = __esm({
35315
36175
  logger.warn(
35316
36176
  `MCP ${transportName} failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${delay}ms: ${error instanceof Error ? error.message : String(error)}`
35317
36177
  );
35318
- await new Promise((resolve5) => setTimeout(resolve5, delay));
36178
+ await new Promise((resolve6) => setTimeout(resolve6, delay));
35319
36179
  attempt += 1;
35320
36180
  } finally {
35321
36181
  try {
@@ -35335,7 +36195,9 @@ var init_mcp_check_provider = __esm({
35335
36195
  command: config.command,
35336
36196
  args: config.command_args,
35337
36197
  env: config.env,
35338
- cwd: config.workingDirectory
36198
+ cwd: config.workingDirectory,
36199
+ stderr: "pipe"
36200
+ // Prevent child stderr from corrupting TUI
35339
36201
  }),
35340
36202
  config,
35341
36203
  methodArgs,
@@ -35583,7 +36445,7 @@ async function acquirePromptLock() {
35583
36445
  activePrompt = true;
35584
36446
  return;
35585
36447
  }
35586
- await new Promise((resolve5) => waiters.push(resolve5));
36448
+ await new Promise((resolve6) => waiters.push(resolve6));
35587
36449
  activePrompt = true;
35588
36450
  }
35589
36451
  function releasePromptLock() {
@@ -35593,7 +36455,7 @@ function releasePromptLock() {
35593
36455
  }
35594
36456
  async function interactivePrompt(options) {
35595
36457
  await acquirePromptLock();
35596
- return new Promise((resolve5, reject) => {
36458
+ return new Promise((resolve6, reject) => {
35597
36459
  const dbg = process.env.VISOR_DEBUG === "true";
35598
36460
  try {
35599
36461
  if (dbg) {
@@ -35680,12 +36542,12 @@ async function interactivePrompt(options) {
35680
36542
  };
35681
36543
  const finish = (value) => {
35682
36544
  cleanup();
35683
- resolve5(value);
36545
+ resolve6(value);
35684
36546
  };
35685
36547
  if (options.timeout && options.timeout > 0) {
35686
36548
  timeoutId = setTimeout(() => {
35687
36549
  cleanup();
35688
- if (defaultValue !== void 0) return resolve5(defaultValue);
36550
+ if (defaultValue !== void 0) return resolve6(defaultValue);
35689
36551
  return reject(new Error("Input timeout"));
35690
36552
  }, options.timeout);
35691
36553
  }
@@ -35817,7 +36679,7 @@ async function interactivePrompt(options) {
35817
36679
  });
35818
36680
  }
35819
36681
  async function simplePrompt(prompt) {
35820
- return new Promise((resolve5) => {
36682
+ return new Promise((resolve6) => {
35821
36683
  const rl = readline.createInterface({
35822
36684
  input: process.stdin,
35823
36685
  output: process.stdout
@@ -35833,7 +36695,7 @@ async function simplePrompt(prompt) {
35833
36695
  rl.question(`${prompt}
35834
36696
  > `, (answer) => {
35835
36697
  rl.close();
35836
- resolve5(answer.trim());
36698
+ resolve6(answer.trim());
35837
36699
  });
35838
36700
  });
35839
36701
  }
@@ -35851,7 +36713,7 @@ function isStdinAvailable() {
35851
36713
  return !process.stdin.isTTY;
35852
36714
  }
35853
36715
  async function readStdin(timeout, maxSize = 1024 * 1024) {
35854
- return new Promise((resolve5, reject) => {
36716
+ return new Promise((resolve6, reject) => {
35855
36717
  let data = "";
35856
36718
  let timeoutId;
35857
36719
  if (timeout) {
@@ -35878,7 +36740,7 @@ async function readStdin(timeout, maxSize = 1024 * 1024) {
35878
36740
  };
35879
36741
  const onEnd = () => {
35880
36742
  cleanup();
35881
- resolve5(data.trim());
36743
+ resolve6(data.trim());
35882
36744
  };
35883
36745
  const onError = (err) => {
35884
36746
  cleanup();
@@ -35908,8 +36770,8 @@ var init_stdin_reader = __esm({
35908
36770
  });
35909
36771
 
35910
36772
  // src/providers/human-input-check-provider.ts
35911
- import * as fs8 from "fs";
35912
- import * as path10 from "path";
36773
+ import * as fs9 from "fs";
36774
+ import * as path11 from "path";
35913
36775
  var HumanInputCheckProvider;
35914
36776
  var init_human_input_check_provider = __esm({
35915
36777
  "src/providers/human-input-check-provider.ts"() {
@@ -36092,19 +36954,19 @@ var init_human_input_check_provider = __esm({
36092
36954
  */
36093
36955
  async tryReadFile(filePath) {
36094
36956
  try {
36095
- const absolutePath = path10.isAbsolute(filePath) ? filePath : path10.resolve(process.cwd(), filePath);
36096
- const normalizedPath = path10.normalize(absolutePath);
36957
+ const absolutePath = path11.isAbsolute(filePath) ? filePath : path11.resolve(process.cwd(), filePath);
36958
+ const normalizedPath = path11.normalize(absolutePath);
36097
36959
  const cwd = process.cwd();
36098
- if (!normalizedPath.startsWith(cwd + path10.sep) && normalizedPath !== cwd) {
36960
+ if (!normalizedPath.startsWith(cwd + path11.sep) && normalizedPath !== cwd) {
36099
36961
  return null;
36100
36962
  }
36101
36963
  try {
36102
- await fs8.promises.access(normalizedPath, fs8.constants.R_OK);
36103
- const stats = await fs8.promises.stat(normalizedPath);
36964
+ await fs9.promises.access(normalizedPath, fs9.constants.R_OK);
36965
+ const stats = await fs9.promises.stat(normalizedPath);
36104
36966
  if (!stats.isFile()) {
36105
36967
  return null;
36106
36968
  }
36107
- const content = await fs8.promises.readFile(normalizedPath, "utf-8");
36969
+ const content = await fs9.promises.readFile(normalizedPath, "utf-8");
36108
36970
  return content.trim();
36109
36971
  } catch {
36110
36972
  return null;
@@ -36546,9 +37408,9 @@ var init_script_check_provider = __esm({
36546
37408
  });
36547
37409
 
36548
37410
  // src/utils/worktree-manager.ts
36549
- import * as fs9 from "fs";
37411
+ import * as fs10 from "fs";
36550
37412
  import * as fsp2 from "fs/promises";
36551
- import * as path11 from "path";
37413
+ import * as path12 from "path";
36552
37414
  import * as crypto from "crypto";
36553
37415
  var WorktreeManager, worktreeManager;
36554
37416
  var init_worktree_manager = __esm({
@@ -36568,7 +37430,7 @@ var init_worktree_manager = __esm({
36568
37430
  } catch {
36569
37431
  cwd = "/tmp";
36570
37432
  }
36571
- const defaultBasePath = process.env.VISOR_WORKTREE_PATH || path11.join(cwd, ".visor", "worktrees");
37433
+ const defaultBasePath = process.env.VISOR_WORKTREE_PATH || path12.join(cwd, ".visor", "worktrees");
36572
37434
  this.config = {
36573
37435
  enabled: true,
36574
37436
  base_path: defaultBasePath,
@@ -36605,20 +37467,20 @@ var init_worktree_manager = __esm({
36605
37467
  }
36606
37468
  const reposDir = this.getReposDir();
36607
37469
  const worktreesDir = this.getWorktreesDir();
36608
- if (!fs9.existsSync(reposDir)) {
36609
- fs9.mkdirSync(reposDir, { recursive: true });
37470
+ if (!fs10.existsSync(reposDir)) {
37471
+ fs10.mkdirSync(reposDir, { recursive: true });
36610
37472
  logger.debug(`Created repos directory: ${reposDir}`);
36611
37473
  }
36612
- if (!fs9.existsSync(worktreesDir)) {
36613
- fs9.mkdirSync(worktreesDir, { recursive: true });
37474
+ if (!fs10.existsSync(worktreesDir)) {
37475
+ fs10.mkdirSync(worktreesDir, { recursive: true });
36614
37476
  logger.debug(`Created worktrees directory: ${worktreesDir}`);
36615
37477
  }
36616
37478
  }
36617
37479
  getReposDir() {
36618
- return path11.join(this.config.base_path, "repos");
37480
+ return path12.join(this.config.base_path, "repos");
36619
37481
  }
36620
37482
  getWorktreesDir() {
36621
- return path11.join(this.config.base_path, "worktrees");
37483
+ return path12.join(this.config.base_path, "worktrees");
36622
37484
  }
36623
37485
  /**
36624
37486
  * Generate a deterministic worktree ID based on repository and ref.
@@ -36636,8 +37498,8 @@ var init_worktree_manager = __esm({
36636
37498
  async getOrCreateBareRepo(repository, repoUrl, token, fetchDepth, cloneTimeoutMs) {
36637
37499
  const reposDir = this.getReposDir();
36638
37500
  const repoName = repository.replace(/\//g, "-");
36639
- const bareRepoPath = path11.join(reposDir, `${repoName}.git`);
36640
- if (fs9.existsSync(bareRepoPath)) {
37501
+ const bareRepoPath = path12.join(reposDir, `${repoName}.git`);
37502
+ if (fs10.existsSync(bareRepoPath)) {
36641
37503
  logger.debug(`Bare repository already exists: ${bareRepoPath}`);
36642
37504
  const verifyResult = await this.verifyBareRepoRemote(bareRepoPath, repoUrl);
36643
37505
  if (verifyResult === "timeout") {
@@ -36756,11 +37618,11 @@ var init_worktree_manager = __esm({
36756
37618
  options.cloneTimeoutMs
36757
37619
  );
36758
37620
  const worktreeId = this.generateWorktreeId(repository, ref);
36759
- let worktreePath = options.workingDirectory || path11.join(this.getWorktreesDir(), worktreeId);
37621
+ let worktreePath = options.workingDirectory || path12.join(this.getWorktreesDir(), worktreeId);
36760
37622
  if (options.workingDirectory) {
36761
37623
  worktreePath = this.validatePath(options.workingDirectory);
36762
37624
  }
36763
- if (fs9.existsSync(worktreePath)) {
37625
+ if (fs10.existsSync(worktreePath)) {
36764
37626
  logger.debug(`Worktree already exists: ${worktreePath}`);
36765
37627
  const metadata2 = await this.loadMetadata(worktreePath);
36766
37628
  if (metadata2) {
@@ -37001,9 +37863,9 @@ var init_worktree_manager = __esm({
37001
37863
  const result = await this.executeGitCommand(removeCmd, { timeout: 3e4 });
37002
37864
  if (result.exitCode !== 0) {
37003
37865
  logger.warn(`Failed to remove worktree via git: ${result.stderr}`);
37004
- if (fs9.existsSync(worktree_path)) {
37866
+ if (fs10.existsSync(worktree_path)) {
37005
37867
  logger.debug(`Manually removing worktree directory`);
37006
- fs9.rmSync(worktree_path, { recursive: true, force: true });
37868
+ fs10.rmSync(worktree_path, { recursive: true, force: true });
37007
37869
  }
37008
37870
  }
37009
37871
  this.activeWorktrees.delete(worktreeId);
@@ -37013,19 +37875,19 @@ var init_worktree_manager = __esm({
37013
37875
  * Save worktree metadata
37014
37876
  */
37015
37877
  async saveMetadata(worktreePath, metadata) {
37016
- const metadataPath = path11.join(worktreePath, ".visor-metadata.json");
37017
- fs9.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), "utf8");
37878
+ const metadataPath = path12.join(worktreePath, ".visor-metadata.json");
37879
+ fs10.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), "utf8");
37018
37880
  }
37019
37881
  /**
37020
37882
  * Load worktree metadata
37021
37883
  */
37022
37884
  async loadMetadata(worktreePath) {
37023
- const metadataPath = path11.join(worktreePath, ".visor-metadata.json");
37024
- if (!fs9.existsSync(metadataPath)) {
37885
+ const metadataPath = path12.join(worktreePath, ".visor-metadata.json");
37886
+ if (!fs10.existsSync(metadataPath)) {
37025
37887
  return null;
37026
37888
  }
37027
37889
  try {
37028
- const content = fs9.readFileSync(metadataPath, "utf8");
37890
+ const content = fs10.readFileSync(metadataPath, "utf8");
37029
37891
  return JSON.parse(content);
37030
37892
  } catch (error) {
37031
37893
  logger.warn(`Failed to load metadata: ${error}`);
@@ -37037,14 +37899,14 @@ var init_worktree_manager = __esm({
37037
37899
  */
37038
37900
  async listWorktrees() {
37039
37901
  const worktreesDir = this.getWorktreesDir();
37040
- if (!fs9.existsSync(worktreesDir)) {
37902
+ if (!fs10.existsSync(worktreesDir)) {
37041
37903
  return [];
37042
37904
  }
37043
- const entries = fs9.readdirSync(worktreesDir, { withFileTypes: true });
37905
+ const entries = fs10.readdirSync(worktreesDir, { withFileTypes: true });
37044
37906
  const worktrees = [];
37045
37907
  for (const entry of entries) {
37046
37908
  if (!entry.isDirectory()) continue;
37047
- const worktreePath = path11.join(worktreesDir, entry.name);
37909
+ const worktreePath = path12.join(worktreesDir, entry.name);
37048
37910
  const metadata = await this.loadMetadata(worktreePath);
37049
37911
  if (metadata) {
37050
37912
  worktrees.push({
@@ -37176,8 +38038,8 @@ var init_worktree_manager = __esm({
37176
38038
  * Validate path to prevent directory traversal
37177
38039
  */
37178
38040
  validatePath(userPath) {
37179
- const resolvedPath = path11.resolve(userPath);
37180
- if (!path11.isAbsolute(resolvedPath)) {
38041
+ const resolvedPath = path12.resolve(userPath);
38042
+ if (!path12.isAbsolute(resolvedPath)) {
37181
38043
  throw new Error("Path must be absolute");
37182
38044
  }
37183
38045
  const sensitivePatterns = [
@@ -37515,7 +38377,7 @@ var init_git_checkout_provider = __esm({
37515
38377
  }
37516
38378
  async isAvailable() {
37517
38379
  try {
37518
- const { commandExecutor: commandExecutor2 } = await import("./command-executor-DVVXERLR.mjs");
38380
+ const { commandExecutor: commandExecutor2 } = await import("./command-executor-TOYBBE7S.mjs");
37519
38381
  const result = await commandExecutor2.execute("git --version", { timeout: 5e3 });
37520
38382
  return result.exitCode === 0;
37521
38383
  } catch (_error) {
@@ -38155,6 +39017,8 @@ var init_workflow_projection = __esm({
38155
39017
  });
38156
39018
 
38157
39019
  // src/providers/workflow-check-provider.ts
39020
+ import * as path13 from "path";
39021
+ import * as yaml from "js-yaml";
38158
39022
  var WorkflowCheckProvider;
38159
39023
  var init_workflow_check_provider = __esm({
38160
39024
  "src/providers/workflow-check-provider.ts"() {
@@ -38368,6 +39232,28 @@ var init_workflow_check_provider = __esm({
38368
39232
  }
38369
39233
  }
38370
39234
  const parentInputs = config.workflowInputs || {};
39235
+ const basePath = config.basePath || config._parentContext?.originalWorkingDirectory || config._parentContext?.workingDirectory || process.cwd();
39236
+ const loadConfigLiquid = createExtendedLiquid();
39237
+ const loadConfig = (filePath) => {
39238
+ try {
39239
+ const normalizedBasePath = path13.normalize(basePath);
39240
+ const resolvedPath = path13.isAbsolute(filePath) ? path13.normalize(filePath) : path13.normalize(path13.resolve(basePath, filePath));
39241
+ const basePathWithSep = normalizedBasePath.endsWith(path13.sep) ? normalizedBasePath : normalizedBasePath + path13.sep;
39242
+ if (!resolvedPath.startsWith(basePathWithSep) && resolvedPath !== normalizedBasePath) {
39243
+ throw new Error(`Path '${filePath}' escapes base directory`);
39244
+ }
39245
+ const configDir = path13.dirname(resolvedPath);
39246
+ const rawContent = __require("fs").readFileSync(resolvedPath, "utf-8");
39247
+ const renderedContent = loadConfigLiquid.parseAndRenderSync(rawContent, {
39248
+ basePath: configDir
39249
+ });
39250
+ return yaml.load(renderedContent, { schema: yaml.JSON_SCHEMA });
39251
+ } catch (error) {
39252
+ const msg = error instanceof Error ? error.message : String(error);
39253
+ logger.error(`[WorkflowProvider] loadConfig failed for '${filePath}': ${msg}`);
39254
+ throw new Error(`loadConfig('${filePath}') failed: ${msg}`);
39255
+ }
39256
+ };
38371
39257
  const templateContext = {
38372
39258
  pr: prInfo,
38373
39259
  outputs: outputsMap,
@@ -38376,7 +39262,9 @@ var init_workflow_check_provider = __esm({
38376
39262
  conversation,
38377
39263
  outputs_history,
38378
39264
  // Include parent workflow inputs for templates like {{ inputs.question }}
38379
- inputs: parentInputs
39265
+ inputs: parentInputs,
39266
+ // Helper to load external YAML/JSON config files
39267
+ loadConfig
38380
39268
  };
38381
39269
  const userInputs = config.args || config.workflow_inputs;
38382
39270
  if (userInputs) {
@@ -38746,17 +39634,17 @@ var init_workflow_check_provider = __esm({
38746
39634
  * so it can be executed by the state machine as a nested workflow.
38747
39635
  */
38748
39636
  async loadWorkflowFromConfigPath(sourcePath, baseDir) {
38749
- const path12 = __require("path");
38750
- const fs10 = __require("fs");
38751
- const yaml = __require("js-yaml");
38752
- const resolved = path12.isAbsolute(sourcePath) ? sourcePath : path12.resolve(baseDir, sourcePath);
38753
- if (!fs10.existsSync(resolved)) {
39637
+ const path14 = __require("path");
39638
+ const fs11 = __require("fs");
39639
+ const yaml2 = __require("js-yaml");
39640
+ const resolved = path14.isAbsolute(sourcePath) ? sourcePath : path14.resolve(baseDir, sourcePath);
39641
+ if (!fs11.existsSync(resolved)) {
38754
39642
  throw new Error(`Workflow config not found at: ${resolved}`);
38755
39643
  }
38756
- const rawContent = fs10.readFileSync(resolved, "utf8");
38757
- const rawData = yaml.load(rawContent);
39644
+ const rawContent = fs11.readFileSync(resolved, "utf8");
39645
+ const rawData = yaml2.load(rawContent);
38758
39646
  if (rawData.imports && Array.isArray(rawData.imports)) {
38759
- const configDir = path12.dirname(resolved);
39647
+ const configDir = path14.dirname(resolved);
38760
39648
  for (const source of rawData.imports) {
38761
39649
  const results = await this.registry.import(source, {
38762
39650
  basePath: configDir,
@@ -38786,8 +39674,8 @@ ${errors}`);
38786
39674
  if (!steps || Object.keys(steps).length === 0) {
38787
39675
  throw new Error(`Config '${resolved}' does not contain any steps to execute as a workflow`);
38788
39676
  }
38789
- const id = path12.basename(resolved).replace(/\.(ya?ml)$/i, "");
38790
- const name = loaded.name || `Workflow from ${path12.basename(resolved)}`;
39677
+ const id = path14.basename(resolved).replace(/\.(ya?ml)$/i, "");
39678
+ const name = loaded.name || `Workflow from ${path14.basename(resolved)}`;
38791
39679
  const workflowDef = {
38792
39680
  id,
38793
39681
  name,
@@ -38809,6 +39697,13 @@ ${errors}`);
38809
39697
  export {
38810
39698
  WorkflowCheckProvider,
38811
39699
  init_workflow_check_provider,
39700
+ extractSlackContext,
39701
+ createScheduleToolWithContext,
39702
+ executeScheduleTool,
39703
+ isScheduleToolCall,
39704
+ ensureScheduleStoreInitialized,
39705
+ ensureReminderStoreInitialized,
39706
+ init_schedule_tool_handler,
38812
39707
  CheckProviderRegistry,
38813
39708
  init_check_provider_registry,
38814
39709
  StateMachineExecutionEngine,
@@ -38822,4 +39717,4 @@ undici/lib/fetch/body.js:
38822
39717
  undici/lib/websocket/frame.js:
38823
39718
  (*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> *)
38824
39719
  */
38825
- //# sourceMappingURL=chunk-BDGUM6BA.mjs.map
39720
+ //# sourceMappingURL=chunk-S6CD7GFM.mjs.map