@probelabs/visor 0.1.182-ee → 0.1.183-ee

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/defaults/assistant.yaml +2 -1
  2. package/defaults/code-talk.yaml +6 -0
  3. package/defaults/skills/task-progress.yaml +39 -0
  4. package/dist/agent-protocol/task-evaluator.d.ts +2 -1
  5. package/dist/agent-protocol/task-evaluator.d.ts.map +1 -1
  6. package/dist/agent-protocol/task-progress-tool.d.ts +29 -0
  7. package/dist/agent-protocol/task-progress-tool.d.ts.map +1 -0
  8. package/dist/agent-protocol/task-store.d.ts +8 -0
  9. package/dist/agent-protocol/task-store.d.ts.map +1 -1
  10. package/dist/agent-protocol/tasks-cli-handler.d.ts.map +1 -1
  11. package/dist/agent-protocol/trace-serializer.d.ts +5 -2
  12. package/dist/agent-protocol/trace-serializer.d.ts.map +1 -1
  13. package/dist/agent-protocol/track-execution.d.ts +1 -1
  14. package/dist/agent-protocol/track-execution.d.ts.map +1 -1
  15. package/dist/ai-review-service.d.ts.map +1 -1
  16. package/dist/cli-main.d.ts.map +1 -1
  17. package/dist/debug-visualizer/trace-reader.d.ts.map +1 -1
  18. package/dist/defaults/assistant.yaml +2 -1
  19. package/dist/defaults/code-talk.yaml +6 -0
  20. package/dist/defaults/skills/task-progress.yaml +39 -0
  21. package/dist/docs/telemetry-live-spans-plan.md +510 -0
  22. package/dist/generated/config-schema.json +43 -6
  23. package/dist/index.js +3545 -701
  24. package/dist/providers/ai-check-provider.d.ts.map +1 -1
  25. package/dist/providers/git-checkout-provider.d.ts.map +1 -1
  26. package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
  27. package/dist/reviewer.d.ts +2 -0
  28. package/dist/reviewer.d.ts.map +1 -1
  29. package/dist/runners/process-cli-handler.d.ts +2 -0
  30. package/dist/runners/process-cli-handler.d.ts.map +1 -0
  31. package/dist/runners/process-discovery.d.ts +29 -0
  32. package/dist/runners/process-discovery.d.ts.map +1 -0
  33. package/dist/sandbox/check-runner.d.ts.map +1 -1
  34. package/dist/sandbox/sandbox-telemetry.d.ts +7 -0
  35. package/dist/sandbox/sandbox-telemetry.d.ts.map +1 -1
  36. package/dist/sandbox/trace-ingester.d.ts +28 -15
  37. package/dist/sandbox/trace-ingester.d.ts.map +1 -1
  38. package/dist/scheduler/schedule-tool.d.ts +5 -0
  39. package/dist/scheduler/schedule-tool.d.ts.map +1 -1
  40. package/dist/sdk/{a2a-frontend-MU5EO2HZ.mjs → a2a-frontend-5YDHFQXD.mjs} +47 -8
  41. package/dist/sdk/{a2a-frontend-MU5EO2HZ.mjs.map → a2a-frontend-5YDHFQXD.mjs.map} +1 -1
  42. package/dist/sdk/{a2a-frontend-4LP3MLTS.mjs → a2a-frontend-6LWBIPMS.mjs} +19 -3
  43. package/dist/sdk/a2a-frontend-6LWBIPMS.mjs.map +1 -0
  44. package/dist/sdk/check-provider-registry-WSEVHJEV.mjs +31 -0
  45. package/dist/sdk/{check-provider-registry-I4BCWKRU.mjs → check-provider-registry-YRADEEQY.mjs} +6 -6
  46. package/dist/sdk/chunk-4BN2XI4X.mjs +459 -0
  47. package/dist/sdk/chunk-4BN2XI4X.mjs.map +1 -0
  48. package/dist/sdk/chunk-54KOAC4W.mjs +665 -0
  49. package/dist/sdk/chunk-54KOAC4W.mjs.map +1 -0
  50. package/dist/sdk/chunk-6C3R6E42.mjs +1700 -0
  51. package/dist/sdk/chunk-6C3R6E42.mjs.map +1 -0
  52. package/dist/sdk/{chunk-4I3TJ7UJ.mjs → chunk-7W5QCO4Y.mjs} +47 -10
  53. package/dist/sdk/chunk-7W5QCO4Y.mjs.map +1 -0
  54. package/dist/sdk/chunk-B2OUZAWY.mjs +237 -0
  55. package/dist/sdk/chunk-B2OUZAWY.mjs.map +1 -0
  56. package/dist/sdk/chunk-FWWLD555.mjs +244 -0
  57. package/dist/sdk/chunk-FWWLD555.mjs.map +1 -0
  58. package/dist/sdk/{chunk-QXT47ZHR.mjs → chunk-G7GSN3SK.mjs} +2 -2
  59. package/dist/sdk/{chunk-QXT47ZHR.mjs.map → chunk-G7GSN3SK.mjs.map} +1 -1
  60. package/dist/sdk/{chunk-DHETLQIX.mjs → chunk-GA2TYKSR.mjs} +5 -5
  61. package/dist/sdk/{chunk-6DPPP7LD.mjs → chunk-IDL3AA3G.mjs} +203 -42
  62. package/dist/sdk/chunk-IDL3AA3G.mjs.map +1 -0
  63. package/dist/sdk/chunk-MEB2TTIE.mjs +157 -0
  64. package/dist/sdk/chunk-MEB2TTIE.mjs.map +1 -0
  65. package/dist/sdk/{chunk-3JFK6KCD.mjs → chunk-MFXPJUUE.mjs} +150 -280
  66. package/dist/sdk/chunk-MFXPJUUE.mjs.map +1 -0
  67. package/dist/sdk/{chunk-KBGQJKIZ.mjs → chunk-NPSLGKXB.mjs} +3 -3
  68. package/dist/sdk/chunk-P2K4VOMU.mjs +825 -0
  69. package/dist/sdk/chunk-P2K4VOMU.mjs.map +1 -0
  70. package/dist/sdk/chunk-RI4ONH5X.mjs +482 -0
  71. package/dist/sdk/chunk-RI4ONH5X.mjs.map +1 -0
  72. package/dist/sdk/chunk-S5FSRHMY.mjs +139 -0
  73. package/dist/sdk/chunk-S5FSRHMY.mjs.map +1 -0
  74. package/dist/sdk/{chunk-7ERVRLDV.mjs → chunk-TFUQ2D5L.mjs} +13 -2
  75. package/dist/sdk/chunk-TFUQ2D5L.mjs.map +1 -0
  76. package/dist/sdk/{chunk-TQQNSHQV.mjs → chunk-UXB4XWEE.mjs} +1044 -179
  77. package/dist/sdk/chunk-UXB4XWEE.mjs.map +1 -0
  78. package/dist/sdk/{chunk-U6K5SK7X.mjs → chunk-V45TITKX.mjs} +2 -2
  79. package/dist/sdk/{chunk-ANUT54HW.mjs → chunk-WKLJ57WF.mjs} +6 -6
  80. package/dist/sdk/chunk-XOAEKFKB.mjs +1150 -0
  81. package/dist/sdk/chunk-XOAEKFKB.mjs.map +1 -0
  82. package/dist/sdk/chunk-ZPYODGYA.mjs +251 -0
  83. package/dist/sdk/chunk-ZPYODGYA.mjs.map +1 -0
  84. package/dist/sdk/command-executor-YNJOS77A.mjs +14 -0
  85. package/dist/sdk/{config-2STD74CJ.mjs → config-PCP6O6Y6.mjs} +4 -4
  86. package/dist/sdk/{failure-condition-evaluator-FFWJRAEQ.mjs → failure-condition-evaluator-H3PBFBYT.mjs} +4 -4
  87. package/dist/sdk/failure-condition-evaluator-IRFKTYZD.mjs +18 -0
  88. package/dist/sdk/github-auth-BJQBLK2V.mjs +196 -0
  89. package/dist/sdk/github-auth-BJQBLK2V.mjs.map +1 -0
  90. package/dist/sdk/{github-frontend-L3F5JXPJ.mjs → github-frontend-DECYOBRN.mjs} +8 -8
  91. package/dist/sdk/{github-frontend-KGV2R5Z6.mjs → github-frontend-TZRBOQCN.mjs} +4 -4
  92. package/dist/sdk/{host-QBJ7TOWG.mjs → host-CFM2ASDI.mjs} +4 -4
  93. package/dist/sdk/{host-X5ZZCEWN.mjs → host-T4LNVU2H.mjs} +3 -3
  94. package/dist/sdk/{knex-store-QCEW4I4R.mjs → knex-store-OEWSZEBY.mjs} +3 -3
  95. package/dist/sdk/lazy-otel-5RDTVS5L.mjs +24 -0
  96. package/dist/sdk/liquid-extensions-E3AKRX7P.mjs +25 -0
  97. package/dist/sdk/{loader-ZNKKJEZ3.mjs → loader-WRGI244P.mjs} +5 -5
  98. package/dist/sdk/memory-store-OHUIXCWJ.mjs +12 -0
  99. package/dist/sdk/metrics-MYUPQBBV.mjs +41 -0
  100. package/dist/sdk/{opa-policy-engine-QCSSIMUF.mjs → opa-policy-engine-IVMCGVNA.mjs} +3 -3
  101. package/dist/sdk/prompt-state-LN57DQF3.mjs +16 -0
  102. package/dist/sdk/renderer-schema-BT2IXMLW.mjs +51 -0
  103. package/dist/sdk/renderer-schema-BT2IXMLW.mjs.map +1 -0
  104. package/dist/sdk/routing-H2PQ57OA.mjs +26 -0
  105. package/dist/sdk/{routing-CVQT4KHX.mjs → routing-JMZ7HDCC.mjs} +5 -5
  106. package/dist/sdk/schedule-tool-2DPNSU63.mjs +37 -0
  107. package/dist/sdk/{schedule-tool-AECLFHSY.mjs → schedule-tool-4M45RK3E.mjs} +6 -6
  108. package/dist/sdk/{schedule-tool-handler-6QLZRTQA.mjs → schedule-tool-handler-KLHE2SOW.mjs} +6 -6
  109. package/dist/sdk/schedule-tool-handler-KLHE2SOW.mjs.map +1 -0
  110. package/dist/sdk/{schedule-tool-handler-J4NUETJ6.mjs → schedule-tool-handler-NBEO46RV.mjs} +16 -16
  111. package/dist/sdk/schedule-tool-handler-NBEO46RV.mjs.map +1 -0
  112. package/dist/sdk/sdk.d.mts +2 -0
  113. package/dist/sdk/sdk.d.ts +2 -0
  114. package/dist/sdk/sdk.js +3125 -666
  115. package/dist/sdk/sdk.js.map +1 -1
  116. package/dist/sdk/sdk.mjs +15 -15
  117. package/dist/sdk/slack-frontend-DF5VL4OF.mjs +929 -0
  118. package/dist/sdk/slack-frontend-DF5VL4OF.mjs.map +1 -0
  119. package/dist/sdk/{task-evaluator-HLNXKKVV.mjs → task-evaluator-GQYDOSGT.mjs} +138 -24
  120. package/dist/sdk/task-evaluator-GQYDOSGT.mjs.map +1 -0
  121. package/dist/sdk/task-evaluator-OVMG7S56.mjs +263 -0
  122. package/dist/sdk/task-evaluator-OVMG7S56.mjs.map +1 -0
  123. package/dist/sdk/{trace-helpers-WJXYVV4S.mjs → trace-helpers-26ZCAE2V.mjs} +7 -5
  124. package/dist/sdk/trace-helpers-26ZCAE2V.mjs.map +1 -0
  125. package/dist/sdk/{trace-helpers-3FFAI7X3.mjs → trace-helpers-XV5GAX5L.mjs} +3 -3
  126. package/dist/sdk/trace-helpers-XV5GAX5L.mjs.map +1 -0
  127. package/dist/sdk/{trace-reader-ZY77OFNM.mjs → trace-reader-OVE4DL2D.mjs} +6 -2
  128. package/dist/sdk/trace-reader-OVE4DL2D.mjs.map +1 -0
  129. package/dist/sdk/trace-serializer-KKBJHM7J.mjs +24 -0
  130. package/dist/sdk/trace-serializer-KKBJHM7J.mjs.map +1 -0
  131. package/dist/sdk/{track-execution-AMQQNXKE.mjs → track-execution-3EC24C2X.mjs} +68 -7
  132. package/dist/sdk/track-execution-3EC24C2X.mjs.map +1 -0
  133. package/dist/sdk/{track-execution-MKIQXP2C.mjs → track-execution-66RLL6QT.mjs} +10 -3
  134. package/dist/sdk/track-execution-66RLL6QT.mjs.map +1 -0
  135. package/dist/sdk/utcp-check-provider-WI3QZ3W6.mjs +16 -0
  136. package/dist/sdk/utcp-check-provider-WI3QZ3W6.mjs.map +1 -0
  137. package/dist/sdk/workflow-check-provider-X2UREEH7.mjs +31 -0
  138. package/dist/sdk/workflow-check-provider-X2UREEH7.mjs.map +1 -0
  139. package/dist/sdk/{workflow-check-provider-EXMC6JIS.mjs → workflow-check-provider-YXALZNAQ.mjs} +6 -6
  140. package/dist/sdk/workflow-check-provider-YXALZNAQ.mjs.map +1 -0
  141. package/dist/sdk/workflow-registry-YCZ3FCJC.mjs +12 -0
  142. package/dist/sdk/workflow-registry-YCZ3FCJC.mjs.map +1 -0
  143. package/dist/slack/socket-runner.d.ts.map +1 -1
  144. package/dist/state-machine/dispatch/sandbox-routing.d.ts.map +1 -1
  145. package/dist/state-machine/states/level-dispatch.d.ts.map +1 -1
  146. package/dist/telemetry/fallback-ndjson.d.ts +21 -0
  147. package/dist/telemetry/fallback-ndjson.d.ts.map +1 -1
  148. package/dist/telemetry/lazy-otel.d.ts +2 -0
  149. package/dist/telemetry/lazy-otel.d.ts.map +1 -1
  150. package/dist/telemetry/opentelemetry.d.ts +5 -0
  151. package/dist/telemetry/opentelemetry.d.ts.map +1 -1
  152. package/dist/telemetry/trace-helpers.d.ts +10 -0
  153. package/dist/telemetry/trace-helpers.d.ts.map +1 -1
  154. package/dist/test-runner/conversation-sugar.d.ts +7 -0
  155. package/dist/test-runner/conversation-sugar.d.ts.map +1 -1
  156. package/dist/test-runner/core/flow-stage.d.ts.map +1 -1
  157. package/dist/test-runner/index.d.ts.map +1 -1
  158. package/dist/test-runner/validator.d.ts.map +1 -1
  159. package/dist/types/git-checkout.d.ts +2 -0
  160. package/dist/types/git-checkout.d.ts.map +1 -1
  161. package/dist/utils/script-tool-environment.d.ts.map +1 -1
  162. package/package.json +2 -2
  163. package/dist/sdk/a2a-frontend-4LP3MLTS.mjs.map +0 -1
  164. package/dist/sdk/check-provider-registry-RRWCXSTG.mjs +0 -31
  165. package/dist/sdk/chunk-3JFK6KCD.mjs.map +0 -1
  166. package/dist/sdk/chunk-4I3TJ7UJ.mjs.map +0 -1
  167. package/dist/sdk/chunk-6DPPP7LD.mjs.map +0 -1
  168. package/dist/sdk/chunk-6VVXKXTI.mjs +0 -164
  169. package/dist/sdk/chunk-6VVXKXTI.mjs.map +0 -1
  170. package/dist/sdk/chunk-7ERVRLDV.mjs.map +0 -1
  171. package/dist/sdk/chunk-TQQNSHQV.mjs.map +0 -1
  172. package/dist/sdk/failure-condition-evaluator-5DZYMCGW.mjs +0 -18
  173. package/dist/sdk/routing-XALEDC2G.mjs +0 -26
  174. package/dist/sdk/schedule-tool-Z6QYL2B3.mjs +0 -37
  175. package/dist/sdk/task-evaluator-HLNXKKVV.mjs.map +0 -1
  176. package/dist/sdk/trace-reader-ZY77OFNM.mjs.map +0 -1
  177. package/dist/sdk/track-execution-AMQQNXKE.mjs.map +0 -1
  178. package/dist/sdk/track-execution-MKIQXP2C.mjs.map +0 -1
  179. package/dist/sdk/workflow-check-provider-VKYGI5GK.mjs +0 -31
  180. /package/dist/sdk/{check-provider-registry-I4BCWKRU.mjs.map → check-provider-registry-WSEVHJEV.mjs.map} +0 -0
  181. /package/dist/sdk/{check-provider-registry-RRWCXSTG.mjs.map → check-provider-registry-YRADEEQY.mjs.map} +0 -0
  182. /package/dist/sdk/{chunk-DHETLQIX.mjs.map → chunk-GA2TYKSR.mjs.map} +0 -0
  183. /package/dist/sdk/{chunk-ANUT54HW.mjs.map → chunk-NPSLGKXB.mjs.map} +0 -0
  184. /package/dist/sdk/{chunk-U6K5SK7X.mjs.map → chunk-V45TITKX.mjs.map} +0 -0
  185. /package/dist/sdk/{chunk-KBGQJKIZ.mjs.map → chunk-WKLJ57WF.mjs.map} +0 -0
  186. /package/dist/sdk/{config-2STD74CJ.mjs.map → command-executor-YNJOS77A.mjs.map} +0 -0
  187. /package/dist/sdk/{failure-condition-evaluator-5DZYMCGW.mjs.map → config-PCP6O6Y6.mjs.map} +0 -0
  188. /package/dist/sdk/{failure-condition-evaluator-FFWJRAEQ.mjs.map → failure-condition-evaluator-H3PBFBYT.mjs.map} +0 -0
  189. /package/dist/sdk/{routing-CVQT4KHX.mjs.map → failure-condition-evaluator-IRFKTYZD.mjs.map} +0 -0
  190. /package/dist/sdk/{github-frontend-KGV2R5Z6.mjs.map → github-frontend-DECYOBRN.mjs.map} +0 -0
  191. /package/dist/sdk/{github-frontend-L3F5JXPJ.mjs.map → github-frontend-TZRBOQCN.mjs.map} +0 -0
  192. /package/dist/sdk/{host-QBJ7TOWG.mjs.map → host-CFM2ASDI.mjs.map} +0 -0
  193. /package/dist/sdk/{host-X5ZZCEWN.mjs.map → host-T4LNVU2H.mjs.map} +0 -0
  194. /package/dist/sdk/{knex-store-QCEW4I4R.mjs.map → knex-store-OEWSZEBY.mjs.map} +0 -0
  195. /package/dist/sdk/{routing-XALEDC2G.mjs.map → lazy-otel-5RDTVS5L.mjs.map} +0 -0
  196. /package/dist/sdk/{schedule-tool-AECLFHSY.mjs.map → liquid-extensions-E3AKRX7P.mjs.map} +0 -0
  197. /package/dist/sdk/{loader-ZNKKJEZ3.mjs.map → loader-WRGI244P.mjs.map} +0 -0
  198. /package/dist/sdk/{schedule-tool-Z6QYL2B3.mjs.map → memory-store-OHUIXCWJ.mjs.map} +0 -0
  199. /package/dist/sdk/{schedule-tool-handler-6QLZRTQA.mjs.map → metrics-MYUPQBBV.mjs.map} +0 -0
  200. /package/dist/sdk/{opa-policy-engine-QCSSIMUF.mjs.map → opa-policy-engine-IVMCGVNA.mjs.map} +0 -0
  201. /package/dist/sdk/{schedule-tool-handler-J4NUETJ6.mjs.map → prompt-state-LN57DQF3.mjs.map} +0 -0
  202. /package/dist/sdk/{trace-helpers-3FFAI7X3.mjs.map → routing-H2PQ57OA.mjs.map} +0 -0
  203. /package/dist/sdk/{trace-helpers-WJXYVV4S.mjs.map → routing-JMZ7HDCC.mjs.map} +0 -0
  204. /package/dist/sdk/{workflow-check-provider-EXMC6JIS.mjs.map → schedule-tool-2DPNSU63.mjs.map} +0 -0
  205. /package/dist/sdk/{workflow-check-provider-VKYGI5GK.mjs.map → schedule-tool-4M45RK3E.mjs.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/check-provider.interface.ts","../../src/utils/env-resolver.ts","../../src/utils/issue-normalizer.ts","../../src/utils/env-exposure.ts","../../src/providers/utcp-check-provider.ts"],"sourcesContent":["import { PRInfo } from '../pr-analyzer';\nimport { ReviewSummary } from '../reviewer';\nimport { EnvConfig, HumanInputRequest } from '../types/config';\n\n/**\n * Configuration for a check provider\n */\nexport interface CheckProviderConfig {\n type: string;\n prompt?: string;\n eventContext?: Record<string, unknown>;\n focus?: string;\n command?: string; // For PR comment triggers\n exec?: string; // For command execution (supports Liquid templates)\n stdin?: string; // Optional stdin input (supports Liquid templates)\n args?: string[] | Record<string, unknown>; // string[] deprecated for command args; Record for workflow inputs\n command_args?: string[]; // MCP stdio command arguments\n interpreter?: string;\n url?: string;\n method?: string;\n headers?: Record<string, string>;\n timeout?: number;\n metadata?: Record<string, unknown>;\n workingDirectory?: string;\n env?: EnvConfig;\n ai?: import('../types/config').AIProviderConfig;\n /** AI model to use for this check - overrides global setting */\n ai_model?: string;\n /** AI provider to use for this check - overrides global setting */\n ai_provider?: 'google' | 'anthropic' | 'openai' | string;\n /** Check name for sessionID and logging purposes */\n checkName?: string;\n /** Session ID for AI session management */\n sessionId?: string;\n /** Script content for 'script' provider */\n content?: string;\n [key: string]: unknown;\n}\n\n/**\n * Execution context passed to check providers\n */\nexport interface ExecutionContext {\n /** Session information for AI session reuse */\n parentSessionId?: string;\n reuseSession?: boolean;\n /** CLI message value (from --message argument) */\n cliMessage?: string;\n /** Conversation context - unified access to user message across transports (CLI, Slack, etc.) */\n conversation?: import('../types/bot').ConversationContext;\n /**\n * Stage-local baseline of output history lengths per check name.\n * When present, providers should expose an `outputs_history_stage` object in\n * Liquid/JS contexts that slices the global history from this baseline.\n * This enables stage-scoped assertions in the YAML test runner without\n * relying on global execution history.\n */\n stageHistoryBase?: Record<string, number>;\n /** Workflow inputs - available when executing within a workflow */\n workflowInputs?: Record<string, unknown>;\n /** Custom arguments passed from on_init 'with' directive */\n args?: Record<string, unknown>;\n /** SDK hooks for human input and check completion */\n hooks?: {\n onHumanInput?: (request: HumanInputRequest) => Promise<string>;\n onPromptCaptured?: (info: { step: string; provider: string; prompt: string }) => void;\n mockForStep?: (step: string) => unknown | undefined;\n /** Returns true if the mock for a step has been consumed (for loop termination) */\n isMockExhausted?: (step: string) => boolean;\n /** Called when a check completes - useful for streaming TUI updates */\n onCheckComplete?: (info: {\n checkId: string;\n result: { output?: unknown; content?: string };\n checkConfig?: { type?: string; group?: string; criticality?: string; schema?: unknown };\n }) => void;\n };\n /**\n * Optional execution mode hints. The core engine does not read environment\n * variables directly; callers (CLI, test runner) can set these flags to\n * request certain behaviors without polluting core logic with test-specific\n * branches.\n */\n mode?: {\n /** true when running under the YAML test runner */\n test?: boolean;\n /** post review comments from grouped execution paths (used by tests) */\n postGroupedComments?: boolean;\n /** reset per-run guard state before grouped execution */\n resetPerRunState?: boolean;\n };\n /**\n * Absolute timestamp (ms since epoch) by which this execution must complete.\n * Set by the engine from `Date.now() + timeout` and inherited by sub-workflows\n * so nested steps know how much time the parent has left.\n */\n deadline?: number;\n /** Optional event bus for emitting integration events (e.g., HumanInputRequested) */\n eventBus?: import('../event-bus/event-bus').EventBus;\n /** Optional webhook context (e.g., Slack Events API payload) */\n webhookContext?: { webhookData?: Map<string, unknown>; eventType?: string };\n /**\n * Callback for capturing AI responses - used by scheduler to store previousResponse\n * for recurring reminders. The text passed is the AI response before mrkdwn formatting.\n */\n responseCapture?: (text: string) => void;\n}\n\n/**\n * Abstract base class for all check providers\n * Implementing classes provide specific check functionality (AI, tool, script, etc.)\n */\nexport abstract class CheckProvider {\n /**\n * Get the unique name/type of this provider\n */\n abstract getName(): string;\n\n /**\n * Get a human-readable description of this provider\n */\n abstract getDescription(): string;\n\n /**\n * Validate provider-specific configuration\n * @param config The configuration to validate\n * @returns true if configuration is valid, false otherwise\n */\n abstract validateConfig(config: unknown): Promise<boolean>;\n\n /**\n * Execute the check on the given PR information\n * @param prInfo Information about the pull request\n * @param config Provider-specific configuration\n * @param dependencyResults Optional results from dependency checks that this check depends on\n * @param context Optional execution context with session info, hooks, and CLI state\n * @returns Review summary with scores, issues, and comments\n */\n abstract execute(\n prInfo: PRInfo,\n config: CheckProviderConfig,\n dependencyResults?: Map<string, ReviewSummary>,\n context?: ExecutionContext\n ): Promise<ReviewSummary>;\n\n /**\n * Get the list of configuration keys this provider supports\n * Used for documentation and validation\n */\n abstract getSupportedConfigKeys(): string[];\n\n /**\n * Check if this provider is available (e.g., has required API keys)\n * @returns true if provider can be used, false otherwise\n */\n abstract isAvailable(): Promise<boolean>;\n\n /**\n * Get provider requirements (e.g., environment variables needed)\n */\n abstract getRequirements(): string[];\n\n /**\n * Set webhook context for providers that need access to webhook data\n * This is optional and only used by http_input providers\n * @param webhookContext Map of endpoint paths to webhook data\n */\n setWebhookContext?(webhookContext: Map<string, unknown>): void;\n}\n","/**\n * Environment variable resolution utilities\n * Supports GitHub Actions-like syntax for referencing environment variables\n */\n\nimport { EnvConfig } from '../types/config';\n\n/**\n * Resolves environment variables in configuration values\n * Supports the following syntaxes:\n * - ${{ env.VARIABLE_NAME }} (GitHub Actions style)\n * - ${VARIABLE_NAME} (shell style)\n * - $VARIABLE_NAME (simple shell style)\n * - Direct environment variable names\n */\nexport class EnvironmentResolver {\n /**\n * Resolves a single configuration value that may contain environment variable references\n */\n static resolveValue(value: string | number | boolean): string | number | boolean {\n if (typeof value !== 'string') {\n return value;\n }\n\n // GitHub Actions style: ${{ env.VARIABLE_NAME }}\n let resolved = value.replace(/\\$\\{\\{\\s*env\\.([A-Z_][A-Z0-9_]*)\\s*\\}\\}/g, (match, envVar) => {\n return process.env[envVar] || match;\n });\n\n // Shell style: ${VARIABLE_NAME}\n resolved = resolved.replace(/\\$\\{([A-Z_][A-Z0-9_]*)\\}/g, (match, envVar) => {\n return process.env[envVar] || match;\n });\n\n // Simple shell style: $VARIABLE_NAME\n resolved = resolved.replace(/\\$([A-Z_][A-Z0-9_]*)/g, (match, envVar) => {\n return process.env[envVar] || match;\n });\n\n return resolved;\n }\n\n /**\n * Resolves all environment variables in an EnvConfig object\n */\n static resolveEnvConfig(envConfig: EnvConfig): EnvConfig {\n const resolved: EnvConfig = {};\n\n for (const [key, value] of Object.entries(envConfig)) {\n resolved[key] = this.resolveValue(value);\n }\n\n return resolved;\n }\n\n /**\n * Applies environment configuration to the process environment\n * This allows checks to access their specific environment variables\n */\n static applyEnvConfig(envConfig: EnvConfig): void {\n const resolved = this.resolveEnvConfig(envConfig);\n\n for (const [key, value] of Object.entries(resolved)) {\n if (value !== undefined) {\n process.env[key] = String(value);\n }\n }\n }\n\n /**\n * Creates a temporary environment for a specific check execution\n * Returns a cleanup function to restore the original environment\n */\n static withTemporaryEnv<T>(envConfig: EnvConfig, callback: () => T | Promise<T>): T | Promise<T> {\n const resolved = this.resolveEnvConfig(envConfig);\n const originalValues: Record<string, string | undefined> = {};\n\n // Store original values and apply new ones\n for (const [key, value] of Object.entries(resolved)) {\n originalValues[key] = process.env[key];\n if (value !== undefined) {\n process.env[key] = String(value);\n }\n }\n\n try {\n const result = callback();\n\n // If callback returns a promise, handle cleanup after it resolves\n if (result instanceof Promise) {\n return result.finally(() => {\n // Restore original values\n for (const [key, originalValue] of Object.entries(originalValues)) {\n if (originalValue === undefined) {\n delete process.env[key];\n } else {\n process.env[key] = originalValue;\n }\n }\n });\n }\n\n // Restore original values immediately for sync callbacks\n for (const [key, originalValue] of Object.entries(originalValues)) {\n if (originalValue === undefined) {\n delete process.env[key];\n } else {\n process.env[key] = originalValue;\n }\n }\n\n return result;\n } catch (error) {\n // Restore original values on error\n for (const [key, originalValue] of Object.entries(originalValues)) {\n if (originalValue === undefined) {\n delete process.env[key];\n } else {\n process.env[key] = originalValue;\n }\n }\n throw error;\n }\n }\n\n /**\n * Validates that all required environment variables are available\n */\n static validateRequiredEnvVars(envConfig: EnvConfig, requiredVars: string[]): string[] {\n const resolved = this.resolveEnvConfig(envConfig);\n const missing: string[] = [];\n\n for (const varName of requiredVars) {\n const value = resolved[varName] || process.env[varName];\n if (!value) {\n missing.push(varName);\n }\n }\n\n return missing;\n }\n\n /**\n * Resolves environment variables in HTTP headers\n * Each header value is processed through resolveValue to replace env var references\n */\n static resolveHeaders(headers: Record<string, string>): Record<string, string> {\n const resolved: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n resolved[key] = String(this.resolveValue(value));\n }\n return resolved;\n }\n\n /**\n * Sanitizes headers for logging/telemetry by redacting sensitive values\n * Headers like Authorization, API keys, and cookies are replaced with [REDACTED]\n */\n static sanitizeHeaders(headers: Record<string, string>): Record<string, string> {\n const sensitiveHeaders = ['authorization', 'x-api-key', 'cookie', 'set-cookie'];\n const sanitized: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(headers)) {\n if (sensitiveHeaders.includes(key.toLowerCase())) {\n sanitized[key] = '[REDACTED]';\n } else {\n sanitized[key] = value;\n }\n }\n\n return sanitized;\n }\n}\n","/**\n * Shared issue normalization utilities.\n *\n * Used by MCP, UTCP, and command providers to extract and normalize\n * ReviewIssue objects from tool/command output.\n */\nimport { ReviewIssue } from '../reviewer';\n\n/**\n * Extract issues from tool output.\n * Handles: JSON strings, arrays of issues, objects with `issues` property, single issue objects.\n */\nexport function extractIssuesFromOutput(\n output: unknown,\n defaultRuleId?: string\n): { issues: ReviewIssue[]; remainingOutput: unknown } | null {\n if (output === null || output === undefined) {\n return null;\n }\n\n // If output is a string, try to parse as JSON\n if (typeof output === 'string') {\n try {\n const parsed = JSON.parse(output);\n return extractIssuesFromOutput(parsed, defaultRuleId);\n } catch {\n return null;\n }\n }\n\n // If output is an array of issues\n if (Array.isArray(output)) {\n const issues = normalizeIssueArray(output, defaultRuleId);\n if (issues) {\n return { issues, remainingOutput: undefined };\n }\n return null;\n }\n\n // If output is an object with issues property\n if (typeof output === 'object') {\n const record = output as Record<string, unknown>;\n\n if (Array.isArray(record.issues)) {\n const issues = normalizeIssueArray(record.issues, defaultRuleId);\n if (!issues) {\n return null;\n }\n\n const remaining = { ...record };\n delete (remaining as { issues?: unknown }).issues;\n\n return {\n issues,\n remainingOutput: Object.keys(remaining).length > 0 ? remaining : undefined,\n };\n }\n\n // Check if output itself is a single issue\n const singleIssue = normalizeIssue(record, defaultRuleId);\n if (singleIssue) {\n return { issues: [singleIssue], remainingOutput: undefined };\n }\n }\n\n return null;\n}\n\n/**\n * Normalize an array of issues. Returns null if any element cannot be normalized.\n */\nexport function normalizeIssueArray(\n values: unknown[],\n defaultRuleId?: string\n): ReviewIssue[] | null {\n const normalized: ReviewIssue[] = [];\n for (const value of values) {\n const issue = normalizeIssue(value, defaultRuleId);\n if (!issue) {\n return null;\n }\n normalized.push(issue);\n }\n return normalized;\n}\n\n/**\n * Normalize a single issue from raw data.\n * Accepts various field aliases (message/text/description, severity/level/priority, etc.)\n */\nexport function normalizeIssue(raw: unknown, defaultRuleId = 'tool'): ReviewIssue | null {\n if (!raw || typeof raw !== 'object') {\n return null;\n }\n\n const data = raw as Record<string, unknown>;\n\n // Only accept string values for issue message fields.\n // Non-string values (e.g. Slack's `message: {text: \"...\", ...}` object)\n // must not be coerced — they are API payloads, not issue descriptions.\n const rawMessage = data.message || data.text || data.description || data.summary;\n if (typeof rawMessage !== 'string') {\n return null;\n }\n const message = rawMessage.trim();\n if (!message) {\n return null;\n }\n\n const allowedSeverities = new Set(['info', 'warning', 'error', 'critical']);\n const severityRaw = toTrimmedString(data.severity || data.level || data.priority);\n let severity: ReviewIssue['severity'] = 'warning';\n if (severityRaw) {\n const lower = severityRaw.toLowerCase();\n if (allowedSeverities.has(lower)) {\n severity = lower as ReviewIssue['severity'];\n }\n }\n\n const allowedCategories = new Set(['security', 'performance', 'style', 'logic', 'documentation']);\n const categoryRaw = toTrimmedString(data.category || data.type || data.group);\n let category: ReviewIssue['category'] = 'logic';\n if (categoryRaw && allowedCategories.has(categoryRaw.toLowerCase())) {\n category = categoryRaw.toLowerCase() as ReviewIssue['category'];\n }\n\n const file = toTrimmedString(data.file || data.path || data.filename) || 'system';\n const line = toNumber(data.line || data.startLine || data.lineNumber) ?? 0;\n const endLine = toNumber(data.endLine || data.end_line || data.stopLine);\n const suggestion = toTrimmedString(data.suggestion);\n const replacement = toTrimmedString(data.replacement);\n const ruleId =\n toTrimmedString(data.ruleId || data.rule || data.id || data.check) || defaultRuleId;\n\n return {\n file,\n line,\n endLine: endLine ?? undefined,\n ruleId,\n message,\n severity,\n category,\n suggestion: suggestion || undefined,\n replacement: replacement || undefined,\n };\n}\n\nexport function toTrimmedString(value: unknown): string | null {\n if (typeof value === 'string') {\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n if (value !== null && value !== undefined && typeof value.toString === 'function') {\n const converted = String(value).trim();\n return converted.length > 0 ? converted : null;\n }\n return null;\n}\n\nexport function toNumber(value: unknown): number | null {\n if (value === null || value === undefined) {\n return null;\n }\n const num = Number(value);\n if (Number.isFinite(num)) {\n return Math.trunc(num);\n }\n return null;\n}\n","export type EnvMap = Record<string, string>;\n\n// Default: expose all env vars except a conservative denylist.\n// If VISOR_ALLOW_ENV is set and not '*', restrict to that allowlist.\n// VISOR_DENY_ENV can further mask exact keys or prefix* patterns.\nexport function buildSandboxEnv(input: NodeJS.ProcessEnv): EnvMap {\n const denyDefaults = [\n 'GITHUB_TOKEN',\n 'INPUT_GITHUB-TOKEN',\n 'ACTIONS_RUNTIME_TOKEN',\n 'ACTIONS_ID_TOKEN_REQUEST_TOKEN',\n 'AWS_ACCESS_KEY_ID',\n 'AWS_SECRET_ACCESS_KEY',\n 'AWS_SESSION_TOKEN',\n 'AZURE_CLIENT_SECRET',\n 'GOOGLE_APPLICATION_CREDENTIALS',\n 'OPENAI_API_KEY',\n 'ANTHROPIC_API_KEY',\n 'HUGGINGFACE_API_KEY',\n 'CLAUDE_CODE_API_KEY',\n 'PROBE_API_KEY',\n ];\n\n const denyExtra = (input.VISOR_DENY_ENV || '')\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n const deny = Array.from(new Set([...denyDefaults, ...denyExtra]));\n const allowSpec = (input.VISOR_ALLOW_ENV || '*').trim();\n\n const denyMatch = (key: string): boolean => {\n for (const pat of deny) {\n if (!pat) continue;\n if (pat.endsWith('*')) {\n const prefix = pat.slice(0, -1);\n if (key.startsWith(prefix)) return true;\n } else if (key === pat) {\n return true;\n }\n }\n if (/(_TOKEN|_SECRET|_PASSWORD|_PRIVATE_KEY)$/i.test(key)) return true;\n return false;\n };\n\n const out: EnvMap = {};\n if (allowSpec !== '*') {\n const allow = allowSpec\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n for (const key of allow) {\n const val = input[key];\n if (key && val !== undefined && !denyMatch(key)) out[key] = String(val);\n }\n return out;\n }\n\n for (const [k, v] of Object.entries(input)) {\n if (v === undefined || v === null) continue;\n if (denyMatch(k)) continue;\n out[k] = String(v);\n }\n return out;\n}\n","import { CheckProvider, CheckProviderConfig } from './check-provider.interface';\nimport { PRInfo } from '../pr-analyzer';\nimport { ReviewSummary, ReviewIssue } from '../reviewer';\nimport { logger } from '../logger';\nimport { Liquid } from 'liquidjs';\nimport { createExtendedLiquid } from '../liquid-extensions';\nimport Sandbox from '@nyariv/sandboxjs';\nimport { createSecureSandbox, compileAndRun } from '../utils/sandbox';\nimport { EnvironmentResolver } from '../utils/env-resolver';\nimport { extractIssuesFromOutput } from '../utils/issue-normalizer';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\n/**\n * UTCP Check Provider Configuration\n */\nexport interface UtcpCheckConfig extends CheckProviderConfig {\n /** UTCP manual source: URL string, file path string, or inline call template object */\n manual: string | Record<string, unknown>;\n /** Tool method name to call (format: manual_name.tool_name or just tool_name) */\n method: string;\n /** Arguments to pass to the UTCP tool (supports Liquid templates) */\n methodArgs?: Record<string, unknown>;\n /** Transform template for method arguments (Liquid) - overrides methodArgs */\n argsTransform?: string;\n /** UTCP variables for manual authentication/configuration */\n variables?: Record<string, string>;\n /** UTCP plugins to load (default: ['http']) */\n plugins?: string[];\n /** Transform template for output (Liquid) */\n transform?: string;\n /** Transform using JavaScript expressions */\n transform_js?: string;\n /** Timeout in seconds (default: 60) */\n timeout?: number;\n}\n\n/**\n * Check provider that calls UTCP (Universal Tool Calling Protocol) tools directly.\n * UTCP is a client-side protocol where tools publish JSON \"manuals\" describing\n * how to call them via their native protocols (HTTP, CLI, SSE, etc.).\n *\n * Supports manual discovery from:\n * - HTTP/HTTPS URLs (GET endpoint returning UTCP manual)\n * - Local JSON files\n * - Inline call template objects\n */\nexport class UtcpCheckProvider extends CheckProvider {\n private liquid: Liquid;\n private sandbox?: Sandbox;\n private sdkAvailable: boolean | null = null;\n\n constructor() {\n super();\n this.liquid = createExtendedLiquid({\n cache: false,\n strictFilters: false,\n strictVariables: false,\n });\n }\n\n getName(): string {\n return 'utcp';\n }\n\n getDescription(): string {\n return 'Call UTCP tools directly using their native protocols (HTTP, CLI, SSE)';\n }\n\n async validateConfig(config: unknown): Promise<boolean> {\n if (!config || typeof config !== 'object') {\n return false;\n }\n\n const cfg = config as UtcpCheckConfig;\n\n // Type must be utcp\n if (cfg.type !== 'utcp') {\n return false;\n }\n\n // Manual is required\n if (!cfg.manual) {\n logger.error('UTCP check requires a manual (URL, file path, or inline call template)');\n return false;\n }\n\n // Method is required\n if (!cfg.method || typeof cfg.method !== 'string') {\n logger.error('UTCP check requires a method name');\n return false;\n }\n\n // Validate manual format\n if (typeof cfg.manual === 'string') {\n // URL validation\n if (cfg.manual.startsWith('http://') || cfg.manual.startsWith('https://')) {\n try {\n const parsedUrl = new URL(cfg.manual);\n if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {\n logger.error(`Invalid URL protocol for UTCP manual: ${parsedUrl.protocol}`);\n return false;\n }\n } catch {\n logger.error(`Invalid URL format for UTCP manual: ${cfg.manual}`);\n return false;\n }\n }\n // File paths are validated at execution time\n } else if (typeof cfg.manual === 'object') {\n // Inline call template must have call_template_type\n if (!cfg.manual.call_template_type) {\n logger.error('Inline UTCP manual must have call_template_type');\n return false;\n }\n } else {\n logger.error('UTCP manual must be a URL string, file path, or inline call template object');\n return false;\n }\n\n return true;\n }\n\n async execute(\n prInfo: PRInfo,\n config: CheckProviderConfig,\n dependencyResults?: Map<string, ReviewSummary>,\n sessionInfo?: any\n ): Promise<ReviewSummary> {\n const cfg = config as UtcpCheckConfig;\n\n // Test hook: mock output for this step\n try {\n const stepName = (config as any).checkName || 'unknown';\n const mock = sessionInfo?.hooks?.mockForStep?.(String(stepName));\n if (mock !== undefined) {\n const ms = mock as any;\n const issuesArr = Array.isArray(ms?.issues) ? (ms.issues as any[]) : [];\n const out = ms && typeof ms === 'object' && 'output' in ms ? ms.output : ms;\n return {\n issues: issuesArr,\n ...(out !== undefined ? { output: out } : {}),\n } as ReviewSummary;\n }\n } catch {}\n\n try {\n // Build template context\n const templateContext = {\n pr: {\n number: prInfo.number,\n title: prInfo.title,\n author: prInfo.author,\n branch: prInfo.head,\n base: prInfo.base,\n },\n files: prInfo.files,\n fileCount: prInfo.files.length,\n outputs: this.buildOutputContext(dependencyResults),\n args: sessionInfo?.args || {},\n env: this.getSafeEnvironmentVariables(),\n inputs: (config as any).workflowInputs || sessionInfo?.workflowInputs || {},\n };\n\n // Render method arguments\n let methodArgs = cfg.methodArgs || {};\n if (cfg.argsTransform) {\n const rendered = await this.liquid.parseAndRender(cfg.argsTransform, templateContext);\n try {\n methodArgs = JSON.parse(rendered);\n } catch (error) {\n logger.error(`Failed to parse argsTransform as JSON: ${error}`);\n return {\n issues: [\n {\n file: 'utcp',\n line: 0,\n ruleId: 'utcp/args_transform_error',\n message: `Failed to parse argsTransform: ${error instanceof Error ? error.message : 'Unknown error'}`,\n severity: 'error',\n category: 'logic',\n },\n ],\n };\n }\n } else if (methodArgs && typeof methodArgs === 'object') {\n // Recursively render Liquid templates in methodArgs\n const renderValue = async (val: unknown): Promise<unknown> => {\n if (typeof val === 'string' && (val.includes('{{') || val.includes('{%'))) {\n return await this.liquid.parseAndRender(val, templateContext);\n } else if (val && typeof val === 'object' && !Array.isArray(val)) {\n const rendered: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(val)) {\n rendered[k] = await renderValue(v);\n }\n return rendered;\n } else if (Array.isArray(val)) {\n return Promise.all(val.map(item => renderValue(item)));\n }\n return val;\n };\n methodArgs = (await renderValue(methodArgs)) as Record<string, unknown>;\n }\n\n // Resolve variables through environment resolver\n const resolvedVariables: Record<string, string> = {};\n if (cfg.variables) {\n for (const [key, value] of Object.entries(cfg.variables)) {\n resolvedVariables[key] = String(EnvironmentResolver.resolveValue(value));\n }\n }\n\n // Call tool via shared static method (handles SDK import, client lifecycle, timeout)\n const result = await UtcpCheckProvider.callTool(cfg.manual, cfg.method, methodArgs, {\n variables: resolvedVariables,\n plugins: cfg.plugins || ['http'],\n timeoutMs: (cfg.timeout || 60) * 1000,\n });\n\n {\n // Apply transforms\n let finalOutput = result;\n\n // Apply Liquid transform\n if (cfg.transform) {\n try {\n const transformContext = {\n ...templateContext,\n output: result,\n };\n const rendered = await this.liquid.parseAndRender(cfg.transform, transformContext);\n try {\n finalOutput = JSON.parse(rendered.trim());\n } catch {\n finalOutput = rendered.trim();\n }\n } catch (error) {\n logger.error(`Failed to apply Liquid transform: ${error}`);\n // Throw to let the outer finally close the client before returning\n throw new Error(\n `Failed to apply transform: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n }\n\n // Apply JavaScript transform\n if (cfg.transform_js) {\n try {\n this.sandbox = createSecureSandbox();\n const scope = {\n output: finalOutput,\n pr: templateContext.pr,\n files: templateContext.files,\n outputs: templateContext.outputs,\n env: templateContext.env,\n };\n finalOutput = compileAndRun<unknown>(\n this.sandbox,\n `return (${cfg.transform_js});`,\n scope,\n { injectLog: true, wrapFunction: false, logPrefix: '[utcp:transform_js]' }\n );\n } catch (error) {\n logger.error(`Failed to apply JavaScript transform: ${error}`);\n // Throw to let the outer finally close the client before returning\n throw new Error(\n `Failed to apply JavaScript transform: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n }\n\n // Extract issues from output\n const extracted = extractIssuesFromOutput(finalOutput, 'utcp');\n if (extracted) {\n return {\n issues: extracted.issues,\n ...(extracted.remainingOutput ? { output: extracted.remainingOutput } : {}),\n } as ReviewSummary;\n }\n\n // Return output directly\n return {\n issues: [],\n ...(finalOutput ? { output: finalOutput } : {}),\n } as ReviewSummary;\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n const isTimeout = this.isTimeoutError(error);\n const severity: ReviewIssue['severity'] = isTimeout ? 'warning' : 'error';\n const ruleId = isTimeout ? 'utcp/timeout' : 'utcp/execution_error';\n\n if (isTimeout) {\n logger.warn(`UTCP check timed out: ${errorMessage}`);\n } else {\n logger.error(`UTCP check failed: ${errorMessage}`);\n }\n\n return {\n issues: [\n {\n file: 'utcp',\n line: 0,\n ruleId,\n message: isTimeout\n ? `UTCP check timed out: ${errorMessage}`\n : `UTCP check failed: ${errorMessage}`,\n severity,\n category: 'logic',\n },\n ],\n };\n }\n }\n\n /**\n * Resolve manual config to a UTCP call template object.\n * Shared utility used by both the standalone UTCP provider and the AI check provider's UTCP-to-MCP bridge.\n */\n static async resolveManualCallTemplate(\n manual: string | Record<string, unknown>\n ): Promise<Record<string, unknown>> {\n if (typeof manual === 'object') {\n if (!manual.call_template_type) {\n throw new Error('Inline manual must have call_template_type');\n }\n // Ensure it has a name\n if (!manual.name) {\n manual.name = 'inline';\n }\n return manual;\n }\n\n // URL-based discovery\n if (manual.startsWith('http://') || manual.startsWith('https://')) {\n return {\n name: UtcpCheckProvider.deriveManualName(manual),\n call_template_type: 'http',\n url: manual,\n http_method: 'GET',\n };\n }\n\n // File-based discovery\n\n // Security: reject null bytes that could bypass path validation\n if (manual.includes('\\0')) {\n throw new Error('Invalid UTCP manual path: null bytes are not allowed');\n }\n\n const resolvedPath = path.resolve(manual);\n\n // Security: ensure resolved path stays within cwd (prevent path traversal)\n const cwd = path.resolve(process.cwd());\n const normalizedResolved = path.normalize(resolvedPath);\n const cwdPrefix = cwd.endsWith(path.sep) ? cwd : cwd + path.sep;\n if (normalizedResolved !== cwd && !normalizedResolved.startsWith(cwdPrefix)) {\n throw new Error(\n `Path traversal detected: \"${manual}\" resolves outside the project directory. ` +\n `UTCP manual paths must be within the project directory.`\n );\n }\n\n // Security: resolve symlinks and re-validate to prevent symlink attacks\n if (fs.existsSync(resolvedPath)) {\n const realPath = fs.realpathSync(resolvedPath);\n if (realPath !== cwd && !realPath.startsWith(cwdPrefix)) {\n throw new Error(\n `Symlink traversal detected: \"${manual}\" points outside the project directory via symlink.`\n );\n }\n }\n\n // Validate file exists and is readable\n if (!fs.existsSync(resolvedPath)) {\n throw new Error(`UTCP manual file not found: ${resolvedPath}`);\n }\n\n // Read and parse the file\n let content: string;\n try {\n content = fs.readFileSync(resolvedPath, 'utf-8');\n } catch (err) {\n throw new Error(\n `Failed to read UTCP manual file: ${resolvedPath}: ${err instanceof Error ? err.message : 'Unknown error'}`\n );\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(content);\n } catch (err) {\n throw new Error(\n `Failed to parse UTCP manual file as JSON: ${resolvedPath}: ${err instanceof Error ? err.message : 'Unknown error'}`\n );\n }\n\n if (parsed.call_template_type) {\n // File contains a call template directly - use as-is\n if (!parsed.name) {\n parsed.name = path.basename(resolvedPath, path.extname(resolvedPath));\n }\n return parsed;\n }\n\n // File contains a UTCP manual - use file call template to let SDK handle it\n // Load the file plugin for file-based manuals\n try {\n await import('@utcp/file');\n } catch {\n logger.debug('UTCP @utcp/file plugin not available, attempting direct parse');\n }\n\n return {\n name: parsed.name || path.basename(resolvedPath, path.extname(resolvedPath)),\n call_template_type: 'file',\n file_path: resolvedPath,\n allowed_communication_protocols: ['file', 'http', 'https'],\n };\n }\n\n /**\n * Derive a manual name from a URL.\n * Shared utility for UTCP manual name derivation.\n */\n static deriveManualName(url: string): string {\n try {\n const parsed = new URL(url);\n // Use hostname with dots replaced by underscores\n return parsed.hostname.replace(/\\./g, '_').replace(/-/g, '_');\n } catch {\n return 'utcp_manual';\n }\n }\n\n /**\n * Call a UTCP tool directly. Shared by both the standalone provider and the MCP-bridge SSE server.\n * Handles SDK import, plugin loading, client creation, tool calling, and cleanup.\n */\n static async callTool(\n manual: string | Record<string, unknown>,\n toolName: string,\n args: Record<string, unknown>,\n options?: {\n variables?: Record<string, string>;\n plugins?: string[];\n timeoutMs?: number;\n }\n ): Promise<unknown> {\n const variables = options?.variables || {};\n const plugins = options?.plugins || ['http'];\n const timeoutMs = options?.timeoutMs || 60000;\n\n // Dynamic import UTCP SDK and plugins\n const { UtcpClient } = await import('@utcp/sdk');\n for (const plugin of plugins) {\n try {\n await import(`@utcp/${plugin}`);\n } catch {\n logger.debug(`UTCP plugin @utcp/${plugin} not available`);\n }\n }\n\n // Resolve manual to call template\n const callTemplate = await UtcpCheckProvider.resolveManualCallTemplate(manual);\n\n // Create client\n const client = await UtcpClient.create(process.cwd(), {\n manual_call_templates: [callTemplate],\n variables,\n } as any);\n\n try {\n // Resolve tool name - try exact match first, then suffix match\n let resolvedToolName = toolName;\n try {\n const tools = await client.getTools();\n const toolNames = tools.map((t: any) => t.name as string);\n logger.debug(`UTCP tools available: ${JSON.stringify(toolNames)}`);\n\n if (!toolNames.includes(resolvedToolName)) {\n const suffixMatch = toolNames.find((name: string) =>\n name.endsWith(`.${resolvedToolName}`)\n );\n if (suffixMatch) {\n logger.debug(\n `UTCP method '${resolvedToolName}' resolved to '${suffixMatch}' via suffix match`\n );\n resolvedToolName = suffixMatch;\n }\n }\n } catch (err) {\n logger.debug(`Failed to list UTCP tools for name resolution: ${err}`);\n }\n\n // Call tool with timeout (clear timer on success to avoid resource leak)\n let timer: ReturnType<typeof setTimeout> | undefined;\n const result = await Promise.race([\n client.callTool(resolvedToolName, args as Record<string, any>),\n new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error(`UTCP tool '${toolName}' timed out after ${timeoutMs}ms`)),\n timeoutMs\n );\n }),\n ]).finally(() => clearTimeout(timer));\n\n return result;\n } finally {\n try {\n if (typeof (client as any).close === 'function') {\n await (client as any).close();\n }\n } catch {}\n }\n }\n\n /**\n * Check if an error is a timeout error\n */\n private isTimeoutError(error: unknown): boolean {\n const err = error as { message?: unknown; code?: unknown; cause?: unknown };\n const message = typeof err?.message === 'string' ? err.message.toLowerCase() : '';\n const code = typeof err?.code === 'string' ? err.code.toLowerCase() : '';\n return message.includes('timeout') || message.includes('timed out') || code.includes('timeout');\n }\n\n /**\n * Build output context from dependency results\n */\n private buildOutputContext(\n dependencyResults?: Map<string, ReviewSummary>\n ): Record<string, unknown> {\n if (!dependencyResults) {\n return {};\n }\n const outputs: Record<string, unknown> = {};\n for (const [checkName, result] of dependencyResults) {\n const summary = result as ReviewSummary & { output?: unknown };\n outputs[checkName] = summary.output !== undefined ? summary.output : summary;\n }\n return outputs;\n }\n\n /**\n * Get safe environment variables\n */\n private getSafeEnvironmentVariables(): Record<string, string> {\n const safeVars: Record<string, string> = {};\n const { buildSandboxEnv } = require('../utils/env-exposure');\n const merged = buildSandboxEnv(process.env);\n for (const [key, value] of Object.entries(merged)) {\n safeVars[key] = String(value);\n }\n safeVars['PWD'] = process.cwd();\n return safeVars;\n }\n\n getSupportedConfigKeys(): string[] {\n return [\n 'type',\n 'manual',\n 'method',\n 'methodArgs',\n 'argsTransform',\n 'variables',\n 'plugins',\n 'transform',\n 'transform_js',\n 'timeout',\n 'depends_on',\n 'on',\n 'if',\n 'group',\n ];\n }\n\n async isAvailable(): Promise<boolean> {\n if (this.sdkAvailable !== null) {\n return this.sdkAvailable;\n }\n try {\n await import('@utcp/sdk');\n this.sdkAvailable = true;\n } catch {\n this.sdkAvailable = false;\n }\n return this.sdkAvailable;\n }\n\n getRequirements(): string[] {\n return [\n '@utcp/sdk package installed',\n 'UTCP manual source (URL, file path, or inline)',\n 'Tool method name',\n ];\n }\n}\n"],"mappings":"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","names":["buildSandboxEnv"]}
@@ -0,0 +1,482 @@
1
+ import {
2
+ init_logger,
3
+ logger
4
+ } from "./chunk-ZPYODGYA.mjs";
5
+ import {
6
+ __esm,
7
+ __export
8
+ } from "./chunk-J7LXIPZS.mjs";
9
+
10
+ // src/memory-store.ts
11
+ var memory_store_exports = {};
12
+ __export(memory_store_exports, {
13
+ MemoryStore: () => MemoryStore
14
+ });
15
+ import fs from "fs/promises";
16
+ import path from "path";
17
+ var MemoryStore;
18
+ var init_memory_store = __esm({
19
+ "src/memory-store.ts"() {
20
+ init_logger();
21
+ MemoryStore = class _MemoryStore {
22
+ static instance;
23
+ data;
24
+ // namespace -> key -> value
25
+ config;
26
+ initialized = false;
27
+ constructor(config) {
28
+ this.data = /* @__PURE__ */ new Map();
29
+ this.config = this.normalizeConfig(config);
30
+ }
31
+ /**
32
+ * Get singleton instance
33
+ */
34
+ static getInstance(config) {
35
+ if (!_MemoryStore.instance) {
36
+ _MemoryStore.instance = new _MemoryStore(config);
37
+ } else if (config && !_MemoryStore.instance.initialized) {
38
+ _MemoryStore.instance.config = _MemoryStore.instance.normalizeConfig(config);
39
+ }
40
+ return _MemoryStore.instance;
41
+ }
42
+ /**
43
+ * Create a new isolated MemoryStore instance that does not affect the
44
+ * process-wide singleton. Useful for nested workflows or tests where
45
+ * state must not leak between runs.
46
+ */
47
+ static createIsolated(config) {
48
+ return new _MemoryStore(config);
49
+ }
50
+ /**
51
+ * Reset singleton instance (for testing)
52
+ */
53
+ static resetInstance() {
54
+ _MemoryStore.instance = void 0;
55
+ }
56
+ /**
57
+ * Initialize memory store (load from file if configured)
58
+ */
59
+ async initialize() {
60
+ if (this.initialized) {
61
+ return;
62
+ }
63
+ if (this.config.storage === "file" && this.config.auto_load && this.config.file) {
64
+ try {
65
+ await this.load();
66
+ logger.debug(`Memory store loaded from ${this.config.file}`);
67
+ } catch (error) {
68
+ if (error.code !== "ENOENT") {
69
+ logger.warn(
70
+ `Failed to load memory store from ${this.config.file}: ${error instanceof Error ? error.message : "Unknown error"}`
71
+ );
72
+ }
73
+ }
74
+ }
75
+ this.initialized = true;
76
+ }
77
+ /**
78
+ * Normalize and apply defaults to config
79
+ */
80
+ normalizeConfig(config) {
81
+ const storage = config?.storage || "memory";
82
+ return {
83
+ storage,
84
+ format: config?.format || "json",
85
+ file: config?.file,
86
+ namespace: config?.namespace || "default",
87
+ auto_load: config?.auto_load !== false,
88
+ auto_save: config?.auto_save !== false
89
+ };
90
+ }
91
+ /**
92
+ * Get the default namespace
93
+ */
94
+ getDefaultNamespace() {
95
+ return this.config.namespace || "default";
96
+ }
97
+ /**
98
+ * Get a value from memory
99
+ */
100
+ get(key, namespace) {
101
+ const ns = namespace || this.getDefaultNamespace();
102
+ const nsData = this.data.get(ns);
103
+ return nsData?.get(key);
104
+ }
105
+ /**
106
+ * Check if a key exists in memory
107
+ */
108
+ has(key, namespace) {
109
+ const ns = namespace || this.getDefaultNamespace();
110
+ const nsData = this.data.get(ns);
111
+ return nsData?.has(key) || false;
112
+ }
113
+ /**
114
+ * Set a value in memory (override existing)
115
+ */
116
+ async set(key, value, namespace) {
117
+ const ns = namespace || this.getDefaultNamespace();
118
+ if (!this.data.has(ns)) {
119
+ this.data.set(ns, /* @__PURE__ */ new Map());
120
+ }
121
+ const nsData = this.data.get(ns);
122
+ nsData.set(key, value);
123
+ try {
124
+ if (process.env.VISOR_DEBUG === "true" || process.env.JEST_WORKER_ID !== void 0) {
125
+ if (ns === "fact-validation" && (key === "total_validations" || key === "all_valid")) {
126
+ console.log("[MemoryStore] SET " + ns + "." + key + " = " + JSON.stringify(value));
127
+ }
128
+ }
129
+ } catch {
130
+ }
131
+ try {
132
+ if (process.env.VISOR_DEBUG === "true" || process.env.JEST_WORKER_ID !== void 0) {
133
+ if (ns === "fact-validation" && (key === "total_validations" || key === "all_valid")) {
134
+ console.log();
135
+ }
136
+ }
137
+ } catch {
138
+ }
139
+ if (this.config.storage === "file" && this.config.auto_save) {
140
+ await this.save();
141
+ }
142
+ }
143
+ /**
144
+ * Append a value to an array in memory
145
+ * If key doesn't exist, creates a new array
146
+ * If key exists but is not an array, converts it to an array
147
+ */
148
+ async append(key, value, namespace) {
149
+ const ns = namespace || this.getDefaultNamespace();
150
+ const existing = this.get(key, ns);
151
+ let newValue;
152
+ if (existing === void 0) {
153
+ newValue = [value];
154
+ } else if (Array.isArray(existing)) {
155
+ newValue = [...existing, value];
156
+ } else {
157
+ newValue = [existing, value];
158
+ }
159
+ await this.set(key, newValue, ns);
160
+ }
161
+ /**
162
+ * Increment a numeric value in memory
163
+ * If key doesn't exist, initializes to 0 before incrementing
164
+ * If key exists but is not a number, throws an error
165
+ */
166
+ async increment(key, amount = 1, namespace) {
167
+ const ns = namespace || this.getDefaultNamespace();
168
+ const existing = this.get(key, ns);
169
+ let newValue;
170
+ if (existing === void 0 || existing === null) {
171
+ newValue = amount;
172
+ } else if (typeof existing === "number") {
173
+ newValue = existing + amount;
174
+ } else {
175
+ throw new Error(
176
+ `Cannot increment non-numeric value at key '${key}' (type: ${typeof existing})`
177
+ );
178
+ }
179
+ await this.set(key, newValue, ns);
180
+ return newValue;
181
+ }
182
+ /**
183
+ * Delete a key from memory
184
+ */
185
+ async delete(key, namespace) {
186
+ const ns = namespace || this.getDefaultNamespace();
187
+ const nsData = this.data.get(ns);
188
+ if (!nsData) {
189
+ return false;
190
+ }
191
+ const deleted = nsData.delete(key);
192
+ if (deleted && this.config.storage === "file" && this.config.auto_save) {
193
+ await this.save();
194
+ }
195
+ return deleted;
196
+ }
197
+ /**
198
+ * Clear all keys in a namespace (or all namespaces if none specified)
199
+ */
200
+ async clear(namespace) {
201
+ if (namespace) {
202
+ this.data.delete(namespace);
203
+ } else {
204
+ this.data.clear();
205
+ }
206
+ if (this.config.storage === "file" && this.config.auto_save) {
207
+ await this.save();
208
+ }
209
+ }
210
+ /**
211
+ * List all keys in a namespace
212
+ */
213
+ list(namespace) {
214
+ const ns = namespace || this.getDefaultNamespace();
215
+ const nsData = this.data.get(ns);
216
+ return nsData ? Array.from(nsData.keys()) : [];
217
+ }
218
+ /**
219
+ * List all namespaces
220
+ */
221
+ listNamespaces() {
222
+ return Array.from(this.data.keys());
223
+ }
224
+ /**
225
+ * Get all data in a namespace
226
+ */
227
+ getAll(namespace) {
228
+ const ns = namespace || this.getDefaultNamespace();
229
+ const nsData = this.data.get(ns);
230
+ if (!nsData) {
231
+ return {};
232
+ }
233
+ const result = {};
234
+ for (const [key, value] of nsData.entries()) {
235
+ result[key] = value;
236
+ }
237
+ return result;
238
+ }
239
+ /**
240
+ * Load data from file
241
+ */
242
+ async load() {
243
+ if (!this.config.file) {
244
+ throw new Error("No file path configured for memory store");
245
+ }
246
+ const filePath = path.resolve(process.cwd(), this.config.file);
247
+ const content = await fs.readFile(filePath, "utf-8");
248
+ if (this.config.format === "json") {
249
+ await this.loadFromJson(content);
250
+ } else if (this.config.format === "csv") {
251
+ await this.loadFromCsv(content);
252
+ } else {
253
+ throw new Error(`Unsupported format: ${this.config.format}`);
254
+ }
255
+ }
256
+ /**
257
+ * Save data to file
258
+ */
259
+ async save() {
260
+ if (!this.config.file) {
261
+ throw new Error("No file path configured for memory store");
262
+ }
263
+ const filePath = path.resolve(process.cwd(), this.config.file);
264
+ const dir = path.dirname(filePath);
265
+ await fs.mkdir(dir, { recursive: true });
266
+ let content;
267
+ if (this.config.format === "json") {
268
+ content = this.saveToJson();
269
+ } else if (this.config.format === "csv") {
270
+ content = this.saveToCsv();
271
+ } else {
272
+ throw new Error(`Unsupported format: ${this.config.format}`);
273
+ }
274
+ await fs.writeFile(filePath, content, "utf-8");
275
+ }
276
+ /**
277
+ * Load data from JSON format
278
+ */
279
+ async loadFromJson(content) {
280
+ const data = JSON.parse(content);
281
+ this.data.clear();
282
+ for (const [namespace, nsData] of Object.entries(data)) {
283
+ if (typeof nsData === "object" && nsData !== null && !Array.isArray(nsData)) {
284
+ const nsMap = /* @__PURE__ */ new Map();
285
+ for (const [key, value] of Object.entries(nsData)) {
286
+ nsMap.set(key, value);
287
+ }
288
+ this.data.set(namespace, nsMap);
289
+ }
290
+ }
291
+ }
292
+ /**
293
+ * Save data to JSON format
294
+ */
295
+ saveToJson() {
296
+ const result = {};
297
+ for (const [namespace, nsData] of this.data.entries()) {
298
+ const nsObj = {};
299
+ for (const [key, value] of nsData.entries()) {
300
+ nsObj[key] = value;
301
+ }
302
+ result[namespace] = nsObj;
303
+ }
304
+ return JSON.stringify(result, null, 2);
305
+ }
306
+ /**
307
+ * Load data from CSV format
308
+ * CSV format: namespace,key,value,type
309
+ */
310
+ async loadFromCsv(content) {
311
+ const lines = content.split("\n").filter((line) => line.trim());
312
+ let startIndex = 0;
313
+ if (lines[0]?.startsWith("namespace,")) {
314
+ startIndex = 1;
315
+ }
316
+ this.data.clear();
317
+ const arrays = /* @__PURE__ */ new Map();
318
+ for (let i = startIndex; i < lines.length; i++) {
319
+ const line = lines[i];
320
+ const parts = this.parseCsvLine(line);
321
+ if (parts.length < 3) {
322
+ logger.warn(`Invalid CSV line ${i + 1}: ${line}`);
323
+ continue;
324
+ }
325
+ const [namespace, key, valueStr, typeStr] = parts;
326
+ const value = this.parseCsvValue(valueStr, typeStr);
327
+ if (!this.data.has(namespace)) {
328
+ this.data.set(namespace, /* @__PURE__ */ new Map());
329
+ arrays.set(namespace, /* @__PURE__ */ new Map());
330
+ }
331
+ const nsData = this.data.get(namespace);
332
+ const nsArrays = arrays.get(namespace);
333
+ if (nsData.has(key)) {
334
+ if (!nsArrays.has(key)) {
335
+ const existingValue = nsData.get(key);
336
+ nsArrays.set(key, [existingValue]);
337
+ }
338
+ nsArrays.get(key).push(value);
339
+ nsData.set(key, nsArrays.get(key));
340
+ } else {
341
+ nsData.set(key, value);
342
+ }
343
+ }
344
+ }
345
+ /**
346
+ * Save data to CSV format
347
+ */
348
+ saveToCsv() {
349
+ const lines = ["namespace,key,value,type"];
350
+ for (const [namespace, nsData] of this.data.entries()) {
351
+ for (const [key, value] of nsData.entries()) {
352
+ if (Array.isArray(value)) {
353
+ for (const item of value) {
354
+ lines.push(this.formatCsvLine(namespace, key, item));
355
+ }
356
+ } else {
357
+ lines.push(this.formatCsvLine(namespace, key, value));
358
+ }
359
+ }
360
+ }
361
+ return lines.join("\n") + "\n";
362
+ }
363
+ /**
364
+ * Parse a CSV line, handling quoted values with commas
365
+ */
366
+ parseCsvLine(line) {
367
+ const parts = [];
368
+ let current = "";
369
+ let inQuotes = false;
370
+ for (let i = 0; i < line.length; i++) {
371
+ const char = line[i];
372
+ if (char === '"') {
373
+ if (inQuotes && line[i + 1] === '"') {
374
+ current += '"';
375
+ i++;
376
+ } else {
377
+ inQuotes = !inQuotes;
378
+ }
379
+ } else if (char === "," && !inQuotes) {
380
+ parts.push(current);
381
+ current = "";
382
+ } else {
383
+ current += char;
384
+ }
385
+ }
386
+ parts.push(current);
387
+ return parts;
388
+ }
389
+ /**
390
+ * Format a CSV line with proper escaping
391
+ */
392
+ formatCsvLine(namespace, key, value) {
393
+ const type = this.getValueType(value);
394
+ const valueStr = this.formatCsvValue(value);
395
+ return `${this.escapeCsv(namespace)},${this.escapeCsv(key)},${valueStr},${type}`;
396
+ }
397
+ /**
398
+ * Escape a CSV value
399
+ */
400
+ escapeCsv(value) {
401
+ if (value.includes(",") || value.includes('"') || value.includes("\n")) {
402
+ return `"${value.replace(/"/g, '""')}"`;
403
+ }
404
+ return value;
405
+ }
406
+ /**
407
+ * Format a value for CSV storage
408
+ */
409
+ formatCsvValue(value) {
410
+ if (value === null) {
411
+ return '""';
412
+ }
413
+ if (value === void 0) {
414
+ return '""';
415
+ }
416
+ if (typeof value === "string") {
417
+ return this.escapeCsv(value);
418
+ }
419
+ if (typeof value === "number" || typeof value === "boolean") {
420
+ return this.escapeCsv(String(value));
421
+ }
422
+ return this.escapeCsv(JSON.stringify(value));
423
+ }
424
+ /**
425
+ * Parse a CSV value based on its type
426
+ */
427
+ parseCsvValue(valueStr, typeStr) {
428
+ if (!typeStr || typeStr === "string") {
429
+ return valueStr;
430
+ }
431
+ if (typeStr === "number") {
432
+ return Number(valueStr);
433
+ }
434
+ if (typeStr === "boolean") {
435
+ return valueStr === "true";
436
+ }
437
+ if (typeStr === "object" || typeStr === "array") {
438
+ try {
439
+ return JSON.parse(valueStr);
440
+ } catch {
441
+ return valueStr;
442
+ }
443
+ }
444
+ return valueStr;
445
+ }
446
+ /**
447
+ * Get the type of a value for CSV storage
448
+ */
449
+ getValueType(value) {
450
+ if (value === null || value === void 0) {
451
+ return "string";
452
+ }
453
+ if (typeof value === "number") {
454
+ return "number";
455
+ }
456
+ if (typeof value === "boolean") {
457
+ return "boolean";
458
+ }
459
+ if (Array.isArray(value)) {
460
+ return "array";
461
+ }
462
+ if (typeof value === "object") {
463
+ return "object";
464
+ }
465
+ return "string";
466
+ }
467
+ /**
468
+ * Get the current configuration
469
+ */
470
+ getConfig() {
471
+ return { ...this.config };
472
+ }
473
+ };
474
+ }
475
+ });
476
+
477
+ export {
478
+ MemoryStore,
479
+ memory_store_exports,
480
+ init_memory_store
481
+ };
482
+ //# sourceMappingURL=chunk-RI4ONH5X.mjs.map