@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.
- package/README.md +23 -0
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/docs/author-permissions.md +20 -0
- package/dist/docs/enterprise-policy.md +1325 -0
- package/dist/docs/index.md +10 -0
- package/dist/docs/scheduler-storage.md +433 -0
- package/dist/docs/scheduler.md +12 -2
- package/dist/enterprise/license/validator.d.ts +39 -0
- package/dist/enterprise/license/validator.d.ts.map +1 -0
- package/dist/enterprise/loader.d.ts +25 -0
- package/dist/enterprise/loader.d.ts.map +1 -0
- package/dist/enterprise/policy/opa-compiler.d.ts +37 -0
- package/dist/enterprise/policy/opa-compiler.d.ts.map +1 -0
- package/dist/enterprise/policy/opa-http-evaluator.d.ts +36 -0
- package/dist/enterprise/policy/opa-http-evaluator.d.ts.map +1 -0
- package/dist/enterprise/policy/opa-policy-engine.d.ts +48 -0
- package/dist/enterprise/policy/opa-policy-engine.d.ts.map +1 -0
- package/dist/enterprise/policy/opa-wasm-evaluator.d.ts +34 -0
- package/dist/enterprise/policy/opa-wasm-evaluator.d.ts.map +1 -0
- package/dist/enterprise/policy/policy-input-builder.d.ts +120 -0
- package/dist/enterprise/policy/policy-input-builder.d.ts.map +1 -0
- package/dist/enterprise/scheduler/knex-store.d.ts +41 -0
- package/dist/enterprise/scheduler/knex-store.d.ts.map +1 -0
- package/dist/examples/README.md +23 -0
- package/dist/examples/enterprise-policy/README.md +344 -0
- package/dist/examples/enterprise-policy/policies/capability_resolve.rego +29 -0
- package/dist/examples/enterprise-policy/policies/capability_resolve_test.rego +230 -0
- package/dist/examples/enterprise-policy/policies/check_execute.rego +71 -0
- package/dist/examples/enterprise-policy/policies/check_execute_test.rego +321 -0
- package/dist/examples/enterprise-policy/policies/deploy_production.rego +33 -0
- package/dist/examples/enterprise-policy/policies/deploy_production_test.rego +29 -0
- package/dist/examples/enterprise-policy/policies/slack_channel_gate.rego +17 -0
- package/dist/examples/enterprise-policy/policies/slack_tool_restrict.rego +16 -0
- package/dist/examples/enterprise-policy/policies/tool_invoke.rego +24 -0
- package/dist/examples/enterprise-policy/policies/tool_invoke_test.rego +227 -0
- package/dist/examples/enterprise-policy/visor.yaml +64 -0
- package/dist/failure-condition-evaluator.d.ts +18 -0
- package/dist/failure-condition-evaluator.d.ts.map +1 -1
- package/dist/frontends/slack-frontend.d.ts +1 -0
- package/dist/frontends/slack-frontend.d.ts.map +1 -1
- package/dist/generated/config-schema.d.ts +139 -0
- package/dist/generated/config-schema.d.ts.map +1 -1
- package/dist/index.js +12121 -7169
- package/dist/liquid-extensions.d.ts.map +1 -1
- package/dist/output/traces/{run-2026-02-08T18-16-04-160Z.ndjson → run-2026-02-11T16-20-59-999Z.ndjson} +84 -84
- package/dist/{traces/run-2026-02-08T18-16-51-253Z.ndjson → output/traces/run-2026-02-11T16-21-47-711Z.ndjson} +1032 -1032
- package/dist/policy/default-engine.d.ts +17 -0
- package/dist/policy/default-engine.d.ts.map +1 -0
- package/dist/policy/index.d.ts +4 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/policy-check-command.d.ts +65 -0
- package/dist/policy/policy-check-command.d.ts.map +1 -0
- package/dist/policy/types.d.ts +81 -0
- package/dist/policy/types.d.ts.map +1 -0
- package/dist/providers/ai-check-provider.d.ts.map +1 -1
- package/dist/providers/check-provider.interface.d.ts +2 -0
- package/dist/providers/check-provider.interface.d.ts.map +1 -1
- package/dist/providers/claude-code-check-provider.d.ts.map +1 -1
- package/dist/providers/mcp-check-provider.d.ts.map +1 -1
- package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
- package/dist/providers/workflow-check-provider.d.ts.map +1 -1
- package/dist/scheduler/index.d.ts +2 -0
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/schedule-store.d.ts +33 -59
- package/dist/scheduler/schedule-store.d.ts.map +1 -1
- package/dist/scheduler/schedule-tool.d.ts.map +1 -1
- package/dist/scheduler/scheduler.d.ts +24 -3
- package/dist/scheduler/scheduler.d.ts.map +1 -1
- package/dist/scheduler/store/index.d.ts +7 -0
- package/dist/scheduler/store/index.d.ts.map +1 -0
- package/dist/scheduler/store/json-migrator.d.ts +10 -0
- package/dist/scheduler/store/json-migrator.d.ts.map +1 -0
- package/dist/scheduler/store/sqlite-store.d.ts +32 -0
- package/dist/scheduler/store/sqlite-store.d.ts.map +1 -0
- package/dist/scheduler/store/types.d.ts +127 -0
- package/dist/scheduler/store/types.d.ts.map +1 -0
- package/dist/sdk/check-provider-registry-M3Y6JMTW.mjs +28 -0
- package/dist/sdk/check-provider-registry-PANIXYRB.mjs +28 -0
- package/dist/sdk/{chunk-D5KI4YQ4.mjs → chunk-DIND4ZCV.mjs} +2 -2
- package/dist/sdk/{chunk-DGZPPGJJ.mjs → chunk-EUUAQBTW.mjs} +1463 -568
- package/dist/sdk/chunk-EUUAQBTW.mjs.map +1 -0
- package/dist/sdk/{chunk-XDLQ3UNF.mjs → chunk-GEW6LS32.mjs} +2 -2
- package/dist/sdk/{chunk-N7HO6KKC.mjs → chunk-HOKQOO3G.mjs} +11 -6
- package/dist/sdk/chunk-HOKQOO3G.mjs.map +1 -0
- package/dist/sdk/{chunk-XR7XXGL7.mjs → chunk-JL7JXCET.mjs} +2 -2
- package/dist/sdk/{chunk-6W75IMDC.mjs → chunk-LG4AUKHB.mjs} +2 -2
- package/dist/sdk/{chunk-BDGUM6BA.mjs → chunk-S6CD7GFM.mjs} +1463 -568
- package/dist/sdk/chunk-S6CD7GFM.mjs.map +1 -0
- package/dist/sdk/{chunk-PO7X5XI7.mjs → chunk-SZXICFQ3.mjs} +2 -2
- package/dist/sdk/{chunk-HEX3RL32.mjs → chunk-UCMJJ3IM.mjs} +5 -2
- package/dist/sdk/{chunk-HEX3RL32.mjs.map → chunk-UCMJJ3IM.mjs.map} +1 -1
- package/dist/sdk/{chunk-7YSOINAQ.mjs → chunk-UCNT3PDT.mjs} +342 -5
- package/dist/sdk/chunk-UCNT3PDT.mjs.map +1 -0
- package/dist/sdk/{chunk-R5Z7YWPB.mjs → chunk-V2IV3ILA.mjs} +7 -5
- package/dist/sdk/chunk-V2IV3ILA.mjs.map +1 -0
- package/dist/sdk/{chunk-SGS2VMEL.mjs → chunk-VMLORODQ.mjs} +107 -20
- package/dist/sdk/chunk-VMLORODQ.mjs.map +1 -0
- package/dist/sdk/{chunk-2KB35MB7.mjs → chunk-VPC3QSPW.mjs} +2 -2
- package/dist/sdk/{chunk-J5RGJQ53.mjs → chunk-YJRBN3XS.mjs} +2 -2
- package/dist/sdk/{command-executor-DVVXERLR.mjs → command-executor-TOYBBE7S.mjs} +4 -4
- package/dist/sdk/{config-7VTT64SQ.mjs → config-OGOS4ZU4.mjs} +4 -4
- package/dist/sdk/failure-condition-evaluator-HC3M5377.mjs +17 -0
- package/dist/sdk/{github-frontend-3N2NLO66.mjs → github-frontend-E2KJSC3Y.mjs} +7 -7
- package/dist/sdk/{host-ONVMEHAA.mjs → host-EE6EJ2FM.mjs} +4 -4
- package/dist/sdk/lazy-otel-5NH4ZJJM.mjs +24 -0
- package/dist/sdk/{liquid-extensions-5IZLTFSZ.mjs → liquid-extensions-E4EUOCES.mjs} +5 -5
- package/dist/sdk/memory-store-AAPL2MTE.mjs +12 -0
- package/dist/sdk/{metrics-GXQ2EDXA.mjs → metrics-I6A7IHG4.mjs} +3 -3
- package/dist/sdk/{prompt-state-YHGXB2OA.mjs → prompt-state-VAKKC773.mjs} +4 -4
- package/dist/sdk/{renderer-schema-CMXOLNIG.mjs → renderer-schema-HXEW6BRJ.mjs} +3 -3
- package/dist/sdk/{routing-S3Y7T2X3.mjs → routing-OZQWAGAI.mjs} +9 -8
- package/dist/sdk/schedule-tool-handler-B7TMSG6A.mjs +38 -0
- package/dist/sdk/schedule-tool-handler-IEB2VS7O.mjs +38 -0
- package/dist/sdk/sdk.d.mts +134 -4
- package/dist/sdk/sdk.d.ts +134 -4
- package/dist/sdk/sdk.js +2509 -1085
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +14 -14
- package/dist/sdk/{slack-frontend-R3M2CACB.mjs → slack-frontend-LAY45IBR.mjs} +119 -29
- package/dist/sdk/slack-frontend-LAY45IBR.mjs.map +1 -0
- package/dist/sdk/{trace-helpers-YHNPC7MR.mjs → trace-helpers-PP3YHTAM.mjs} +3 -3
- package/dist/sdk/{tui-frontend-S546M7A7.mjs → tui-frontend-T56PZB67.mjs} +25 -16
- package/dist/sdk/tui-frontend-T56PZB67.mjs.map +1 -0
- package/dist/sdk/workflow-check-provider-2ET3SFZH.mjs +28 -0
- package/dist/sdk/workflow-check-provider-2ET3SFZH.mjs.map +1 -0
- package/dist/sdk/workflow-check-provider-HB4XTD4Z.mjs +28 -0
- package/dist/sdk/workflow-check-provider-HB4XTD4Z.mjs.map +1 -0
- package/dist/sdk/workflow-registry-AAD37XKZ.mjs +12 -0
- package/dist/sdk/workflow-registry-AAD37XKZ.mjs.map +1 -0
- package/dist/slack/client.d.ts +12 -0
- package/dist/slack/client.d.ts.map +1 -1
- package/dist/slack/slack-output-adapter.d.ts.map +1 -1
- package/dist/slack/socket-runner.d.ts.map +1 -1
- package/dist/state-machine/dispatch/execution-invoker.d.ts.map +1 -1
- package/dist/state-machine/dispatch/policy-gate.d.ts +28 -0
- package/dist/state-machine/dispatch/policy-gate.d.ts.map +1 -0
- package/dist/state-machine/states/level-dispatch.d.ts.map +1 -1
- package/dist/state-machine/states/routing.d.ts.map +1 -1
- package/dist/state-machine/states/wave-planning.d.ts.map +1 -1
- package/dist/state-machine-execution-engine.d.ts.map +1 -1
- package/dist/test-runner/core/flow-stage.d.ts.map +1 -1
- package/dist/test-runner/validator.d.ts.map +1 -1
- package/dist/traces/{run-2026-02-08T18-16-04-160Z.ndjson → run-2026-02-11T16-20-59-999Z.ndjson} +84 -84
- package/dist/{output/traces/run-2026-02-08T18-16-51-253Z.ndjson → traces/run-2026-02-11T16-21-47-711Z.ndjson} +1032 -1032
- package/dist/tui/chat-runner.d.ts.map +1 -1
- package/dist/tui/chat-state.d.ts +1 -0
- package/dist/tui/chat-state.d.ts.map +1 -1
- package/dist/tui/chat-tui.d.ts +3 -2
- package/dist/tui/chat-tui.d.ts.map +1 -1
- package/dist/tui/components/chat-box.d.ts +9 -0
- package/dist/tui/components/chat-box.d.ts.map +1 -1
- package/dist/tui/components/input-bar.d.ts +18 -1
- package/dist/tui/components/input-bar.d.ts.map +1 -1
- package/dist/tui/components/status-bar.d.ts +5 -2
- package/dist/tui/components/status-bar.d.ts.map +1 -1
- package/dist/tui/components/trace-viewer.d.ts +1 -0
- package/dist/tui/components/trace-viewer.d.ts.map +1 -1
- package/dist/tui/tui-frontend.d.ts.map +1 -1
- package/dist/types/config.d.ts +107 -3
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/engine.d.ts +5 -0
- package/dist/types/engine.d.ts.map +1 -1
- package/dist/types/execution.d.ts +1 -1
- package/dist/types/execution.d.ts.map +1 -1
- package/package.json +14 -4
- package/dist/sdk/check-provider-registry-ACRGIYOB.mjs +0 -28
- package/dist/sdk/check-provider-registry-VYHKFHK2.mjs +0 -28
- package/dist/sdk/chunk-7YSOINAQ.mjs.map +0 -1
- package/dist/sdk/chunk-BDGUM6BA.mjs.map +0 -1
- package/dist/sdk/chunk-DGZPPGJJ.mjs.map +0 -1
- package/dist/sdk/chunk-N7HO6KKC.mjs.map +0 -1
- package/dist/sdk/chunk-R5Z7YWPB.mjs.map +0 -1
- package/dist/sdk/chunk-SGS2VMEL.mjs.map +0 -1
- package/dist/sdk/failure-condition-evaluator-4WMDF4Q3.mjs +0 -17
- package/dist/sdk/memory-store-3N4AZCYB.mjs +0 -12
- package/dist/sdk/slack-frontend-R3M2CACB.mjs.map +0 -1
- package/dist/sdk/tui-frontend-S546M7A7.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-4F3432ZP.mjs +0 -28
- package/dist/sdk/workflow-check-provider-A44PBPG2.mjs +0 -28
- package/dist/sdk/workflow-registry-ZAYYXLEP.mjs +0 -12
- /package/dist/sdk/{check-provider-registry-ACRGIYOB.mjs.map → check-provider-registry-M3Y6JMTW.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-VYHKFHK2.mjs.map → check-provider-registry-PANIXYRB.mjs.map} +0 -0
- /package/dist/sdk/{chunk-D5KI4YQ4.mjs.map → chunk-DIND4ZCV.mjs.map} +0 -0
- /package/dist/sdk/{chunk-XDLQ3UNF.mjs.map → chunk-GEW6LS32.mjs.map} +0 -0
- /package/dist/sdk/{chunk-XR7XXGL7.mjs.map → chunk-JL7JXCET.mjs.map} +0 -0
- /package/dist/sdk/{chunk-6W75IMDC.mjs.map → chunk-LG4AUKHB.mjs.map} +0 -0
- /package/dist/sdk/{chunk-PO7X5XI7.mjs.map → chunk-SZXICFQ3.mjs.map} +0 -0
- /package/dist/sdk/{chunk-2KB35MB7.mjs.map → chunk-VPC3QSPW.mjs.map} +0 -0
- /package/dist/sdk/{chunk-J5RGJQ53.mjs.map → chunk-YJRBN3XS.mjs.map} +0 -0
- /package/dist/sdk/{command-executor-DVVXERLR.mjs.map → command-executor-TOYBBE7S.mjs.map} +0 -0
- /package/dist/sdk/{config-7VTT64SQ.mjs.map → config-OGOS4ZU4.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-4WMDF4Q3.mjs.map → failure-condition-evaluator-HC3M5377.mjs.map} +0 -0
- /package/dist/sdk/{github-frontend-3N2NLO66.mjs.map → github-frontend-E2KJSC3Y.mjs.map} +0 -0
- /package/dist/sdk/{host-ONVMEHAA.mjs.map → host-EE6EJ2FM.mjs.map} +0 -0
- /package/dist/sdk/{liquid-extensions-5IZLTFSZ.mjs.map → lazy-otel-5NH4ZJJM.mjs.map} +0 -0
- /package/dist/sdk/{memory-store-3N4AZCYB.mjs.map → liquid-extensions-E4EUOCES.mjs.map} +0 -0
- /package/dist/sdk/{metrics-GXQ2EDXA.mjs.map → memory-store-AAPL2MTE.mjs.map} +0 -0
- /package/dist/sdk/{prompt-state-YHGXB2OA.mjs.map → metrics-I6A7IHG4.mjs.map} +0 -0
- /package/dist/sdk/{routing-S3Y7T2X3.mjs.map → prompt-state-VAKKC773.mjs.map} +0 -0
- /package/dist/sdk/{renderer-schema-CMXOLNIG.mjs.map → renderer-schema-HXEW6BRJ.mjs.map} +0 -0
- /package/dist/sdk/{trace-helpers-YHNPC7MR.mjs.map → routing-OZQWAGAI.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-4F3432ZP.mjs.map → schedule-tool-handler-B7TMSG6A.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-A44PBPG2.mjs.map → schedule-tool-handler-IEB2VS7O.mjs.map} +0 -0
- /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-
|
|
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-
|
|
27
|
+
} from "./chunk-DIND4ZCV.mjs";
|
|
20
28
|
import {
|
|
21
29
|
config_exports,
|
|
22
30
|
init_config
|
|
23
|
-
} from "./chunk-
|
|
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-
|
|
40
|
+
} from "./chunk-VMLORODQ.mjs";
|
|
37
41
|
import {
|
|
38
42
|
FailureConditionEvaluator,
|
|
39
43
|
init_failure_condition_evaluator
|
|
40
|
-
} from "./chunk-
|
|
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-
|
|
55
|
+
} from "./chunk-YJRBN3XS.mjs";
|
|
52
56
|
import {
|
|
53
57
|
addDiagramBlock,
|
|
54
58
|
init_metrics
|
|
55
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-JL7JXCET.mjs";
|
|
56
60
|
import {
|
|
57
61
|
createExtendedLiquid,
|
|
58
62
|
init_liquid_extensions
|
|
59
|
-
} from "./chunk-
|
|
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-
|
|
79
|
+
} from "./chunk-VPC3QSPW.mjs";
|
|
76
80
|
import {
|
|
77
81
|
init_logger,
|
|
78
|
-
logger
|
|
79
|
-
|
|
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-
|
|
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
|
|
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 (
|
|
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
|
|
1192
|
-
const
|
|
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 ||
|
|
1307
|
-
if (!
|
|
1308
|
-
|
|
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 =
|
|
1311
|
+
const debugFile = path14.join(
|
|
1311
1312
|
debugArtifactsDir,
|
|
1312
1313
|
`prompt-${_checkName || "unknown"}-${timestamp}.json`
|
|
1313
1314
|
);
|
|
1314
|
-
|
|
1315
|
-
const readableFile =
|
|
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
|
-
|
|
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
|
|
1353
|
-
const
|
|
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 ||
|
|
1365
|
-
const sessionBase =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1414
|
-
const
|
|
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 ||
|
|
1417
|
-
const responseFile =
|
|
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
|
-
|
|
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
|
|
1467
|
-
if (
|
|
1468
|
-
const stats =
|
|
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
|
|
1664
|
-
const
|
|
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 =
|
|
1739
|
-
|
|
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 ||
|
|
1743
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path14.join(process.cwd(), "debug-artifacts");
|
|
1743
1744
|
try {
|
|
1744
|
-
const base =
|
|
1745
|
+
const base = path14.join(
|
|
1745
1746
|
debugArtifactsDir,
|
|
1746
1747
|
`prompt-${_checkName || "unknown"}-${timestamp}`
|
|
1747
1748
|
);
|
|
1748
|
-
|
|
1749
|
-
|
|
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
|
|
1795
|
-
const
|
|
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 ||
|
|
1807
|
-
const sessionBase =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1856
|
-
const
|
|
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 ||
|
|
1859
|
-
const responseFile =
|
|
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
|
-
|
|
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
|
|
1911
|
-
if (
|
|
1912
|
-
const stats =
|
|
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
|
|
1951
|
-
const
|
|
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")) && !
|
|
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 =
|
|
1970
|
+
const schemaPath = path14.resolve(process.cwd(), schema);
|
|
1970
1971
|
log(`\u{1F4CB} Loading custom schema from file: ${schemaPath}`);
|
|
1971
|
-
const schemaContent = await
|
|
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
|
-
|
|
1986
|
+
path14.join(__dirname, "output", sanitizedSchemaName, "schema.json"),
|
|
1986
1987
|
// Historical fallback when src/output was inadvertently bundled as output1/
|
|
1987
|
-
|
|
1988
|
+
path14.join(__dirname, "output1", sanitizedSchemaName, "schema.json"),
|
|
1988
1989
|
// Local dev (repo root)
|
|
1989
|
-
|
|
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
|
|
1994
|
+
const schemaContent = await fs11.readFile(schemaPath, "utf-8");
|
|
1994
1995
|
return schemaContent.trim();
|
|
1995
1996
|
} catch {
|
|
1996
1997
|
}
|
|
1997
1998
|
}
|
|
1998
|
-
const distPath =
|
|
1999
|
-
const distAltPath =
|
|
2000
|
-
const cwdPath =
|
|
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((
|
|
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-
|
|
3000
|
+
const { WorkflowCheckProvider: WorkflowCheckProvider2 } = await import("./workflow-check-provider-2ET3SFZH.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/
|
|
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
|
-
|
|
3069
|
-
filePath;
|
|
3070
|
-
autoSave;
|
|
3071
|
-
saveDebounceMs;
|
|
3606
|
+
backend = null;
|
|
3072
3607
|
initialized = false;
|
|
3073
|
-
saveTimeout = null;
|
|
3074
3608
|
limits;
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
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.
|
|
3119
|
-
|
|
3120
|
-
|
|
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 -
|
|
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
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
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.
|
|
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
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
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
|
-
|
|
3678
|
+
this.initialized = true;
|
|
3215
3679
|
}
|
|
3216
3680
|
/**
|
|
3217
|
-
* Create a new schedule (
|
|
3681
|
+
* Create a new schedule (async, persists immediately)
|
|
3218
3682
|
*/
|
|
3219
3683
|
async createAsync(schedule) {
|
|
3220
|
-
this.
|
|
3221
|
-
|
|
3222
|
-
|
|
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
|
-
|
|
3283
|
-
return this.
|
|
3691
|
+
async getAsync(id) {
|
|
3692
|
+
return this.getBackend().get(id);
|
|
3284
3693
|
}
|
|
3285
3694
|
/**
|
|
3286
3695
|
* Update a schedule
|
|
3287
3696
|
*/
|
|
3288
|
-
|
|
3289
|
-
|
|
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
|
|
3701
|
+
* Delete a schedule
|
|
3300
3702
|
*/
|
|
3301
3703
|
async deleteAsync(id) {
|
|
3302
|
-
|
|
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
|
-
|
|
3325
|
-
return
|
|
3709
|
+
async getByCreatorAsync(creatorId) {
|
|
3710
|
+
return this.getBackend().getByCreator(creatorId);
|
|
3326
3711
|
}
|
|
3327
3712
|
/**
|
|
3328
3713
|
* Get all active schedules
|
|
3329
3714
|
*/
|
|
3330
|
-
|
|
3331
|
-
return
|
|
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
|
-
|
|
3338
|
-
return this.
|
|
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
|
-
|
|
3352
|
-
|
|
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
|
-
|
|
3361
|
-
|
|
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.
|
|
3377
|
-
|
|
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
|
|
3755
|
+
return false;
|
|
3393
3756
|
}
|
|
3394
3757
|
/**
|
|
3395
|
-
* Get all schedules
|
|
3758
|
+
* Get all schedules
|
|
3396
3759
|
*/
|
|
3397
|
-
|
|
3398
|
-
return
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
4898
|
-
import * as
|
|
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 ||
|
|
5306
|
+
const outDir = process.env.VISOR_TRACE_DIR || path5.join(process.cwd(), "output", "traces");
|
|
4912
5307
|
try {
|
|
4913
|
-
if (!
|
|
5308
|
+
if (!fs4.existsSync(outDir)) fs4.mkdirSync(outDir, { recursive: true });
|
|
4914
5309
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
4915
|
-
const jsonPath =
|
|
4916
|
-
const htmlPath =
|
|
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 (
|
|
5313
|
+
if (fs4.existsSync(jsonPath)) {
|
|
4919
5314
|
try {
|
|
4920
|
-
data = JSON.parse(
|
|
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
|
-
|
|
4929
|
-
if (!
|
|
4930
|
-
|
|
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-
|
|
5551
|
-
const
|
|
5552
|
-
const
|
|
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 =
|
|
5561
|
-
templateContent = await
|
|
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
|
-
|
|
5997
|
+
path14.join(__dirname, "output", sanitized, "template.liquid"),
|
|
5567
5998
|
// bundled: dist/output/
|
|
5568
|
-
|
|
5999
|
+
path14.join(__dirname, "..", "..", "output", sanitized, "template.liquid"),
|
|
5569
6000
|
// source: output/
|
|
5570
|
-
|
|
6001
|
+
path14.join(process.cwd(), "output", sanitized, "template.liquid"),
|
|
5571
6002
|
// fallback: cwd/output/
|
|
5572
|
-
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
9411
|
-
const
|
|
9412
|
-
const
|
|
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 =
|
|
9422
|
-
templateContent = await
|
|
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
|
-
|
|
10023
|
+
path14.join(__dirname, "output", sanitized, "template.liquid"),
|
|
9429
10024
|
// bundled: dist/output/
|
|
9430
|
-
|
|
10025
|
+
path14.join(__dirname, "..", "..", "output", sanitized, "template.liquid"),
|
|
9431
10026
|
// source (from state-machine/states)
|
|
9432
|
-
|
|
10027
|
+
path14.join(__dirname, "..", "..", "..", "output", sanitized, "template.liquid"),
|
|
9433
10028
|
// source (alternate)
|
|
9434
|
-
|
|
10029
|
+
path14.join(process.cwd(), "output", sanitized, "template.liquid"),
|
|
9435
10030
|
// fallback: cwd/output/
|
|
9436
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
10770
|
-
|
|
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 =
|
|
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 =
|
|
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((
|
|
11492
|
+
new Promise((resolve6) => {
|
|
10896
11493
|
if (this.activeOperations === 0) {
|
|
10897
|
-
|
|
11494
|
+
resolve6();
|
|
10898
11495
|
} else {
|
|
10899
|
-
this.cleanupResolvers.push(
|
|
11496
|
+
this.cleanupResolvers.push(resolve6);
|
|
10900
11497
|
}
|
|
10901
11498
|
}),
|
|
10902
|
-
new Promise((
|
|
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
|
-
|
|
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
|
|
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
|
|
11208
|
-
import * as
|
|
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-
|
|
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-
|
|
11902
|
+
const { CheckProviderRegistry: CheckProviderRegistry2 } = await import("./check-provider-registry-M3Y6JMTW.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-
|
|
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-IEB2VS7O.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-
|
|
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 ||
|
|
11550
|
-
|
|
11551
|
-
const filePath =
|
|
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
|
|
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
|
|
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
|
|
11712
|
-
const raw = await
|
|
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-
|
|
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-
|
|
11794
|
-
const { addFailIfTriggered } = await import("./metrics-
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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((
|
|
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((
|
|
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(() =>
|
|
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
|
-
|
|
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.
|
|
12493
|
-
|
|
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((
|
|
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
|
|
12798
|
-
import
|
|
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 =
|
|
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 (
|
|
12982
|
-
resolvedPath =
|
|
13740
|
+
if (path8.isAbsolute(str)) {
|
|
13741
|
+
resolvedPath = path8.normalize(str);
|
|
12983
13742
|
} else {
|
|
12984
|
-
resolvedPath =
|
|
13743
|
+
resolvedPath = path8.resolve(process.cwd(), str);
|
|
12985
13744
|
}
|
|
12986
|
-
const
|
|
13745
|
+
const fs11 = __require("fs").promises;
|
|
12987
13746
|
try {
|
|
12988
|
-
const stat = await
|
|
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 (
|
|
13764
|
+
if (path8.isAbsolute(promptPath)) {
|
|
13006
13765
|
resolvedPath = promptPath;
|
|
13007
13766
|
} else {
|
|
13008
|
-
resolvedPath =
|
|
13767
|
+
resolvedPath = path8.resolve(process.cwd(), promptPath);
|
|
13009
13768
|
}
|
|
13010
|
-
if (!
|
|
13011
|
-
const normalizedPath =
|
|
13012
|
-
const currentDir =
|
|
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
|
|
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
|
|
14753
|
-
import * as
|
|
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 && !
|
|
14859
|
-
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 &&
|
|
14865
|
-
const stats =
|
|
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 =
|
|
15077
|
-
if (parentDir && !
|
|
15078
|
-
|
|
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
|
-
|
|
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
|
|
15839
|
-
import
|
|
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 =
|
|
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 (
|
|
16009
|
-
resolvedPath =
|
|
16806
|
+
if (path10.isAbsolute(str)) {
|
|
16807
|
+
resolvedPath = path10.normalize(str);
|
|
16010
16808
|
} else {
|
|
16011
|
-
resolvedPath =
|
|
16809
|
+
resolvedPath = path10.resolve(process.cwd(), str);
|
|
16012
16810
|
}
|
|
16013
16811
|
try {
|
|
16014
|
-
const stat = await
|
|
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 (
|
|
16829
|
+
if (path10.isAbsolute(promptPath)) {
|
|
16032
16830
|
resolvedPath = promptPath;
|
|
16033
16831
|
} else {
|
|
16034
|
-
resolvedPath =
|
|
16832
|
+
resolvedPath = path10.resolve(process.cwd(), promptPath);
|
|
16035
16833
|
}
|
|
16036
|
-
if (!
|
|
16037
|
-
const normalizedPath =
|
|
16038
|
-
const currentDir =
|
|
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
|
|
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
|
-
|
|
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
|
|
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 (
|
|
18604
|
-
|
|
19430
|
+
if (path14 && !path14.startsWith("/")) {
|
|
19431
|
+
path14 = `/${path14}`;
|
|
18605
19432
|
}
|
|
18606
|
-
url = new URL(origin +
|
|
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(
|
|
20221
|
-
if (typeof
|
|
21047
|
+
module.exports = function basename2(path14) {
|
|
21048
|
+
if (typeof path14 !== "string") {
|
|
20222
21049
|
return "";
|
|
20223
21050
|
}
|
|
20224
|
-
for (var i =
|
|
20225
|
-
switch (
|
|
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
|
-
|
|
20230
|
-
return
|
|
21056
|
+
path14 = path14.slice(i + 1);
|
|
21057
|
+
return path14 === ".." || path14 === "." ? "" : path14;
|
|
20231
21058
|
}
|
|
20232
21059
|
}
|
|
20233
|
-
return
|
|
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((
|
|
21627
|
-
res =
|
|
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((
|
|
23133
|
-
busboy.on("finish",
|
|
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:
|
|
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
|
|
24105
|
+
if (typeof path14 !== "string") {
|
|
23279
24106
|
throw new InvalidArgumentError("path must be a string");
|
|
23280
|
-
} else if (
|
|
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(
|
|
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(
|
|
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((
|
|
24494
|
+
return new Promise((resolve6, reject) => {
|
|
23668
24495
|
this.close((err, data) => {
|
|
23669
|
-
return err ? reject(err) :
|
|
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((
|
|
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
|
-
) :
|
|
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
|
|
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 =
|
|
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((
|
|
25601
|
+
return new Promise((resolve6) => {
|
|
24775
25602
|
if (!this[kSize]) {
|
|
24776
|
-
|
|
25603
|
+
resolve6(null);
|
|
24777
25604
|
} else {
|
|
24778
|
-
this[kClosedResolve] =
|
|
25605
|
+
this[kClosedResolve] = resolve6;
|
|
24779
25606
|
}
|
|
24780
25607
|
});
|
|
24781
25608
|
}
|
|
24782
25609
|
async [kDestroy](err) {
|
|
24783
|
-
return new Promise((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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:
|
|
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} ${
|
|
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:
|
|
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] =
|
|
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((
|
|
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 =
|
|
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((
|
|
26362
|
-
this[kClosedResolve] =
|
|
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((
|
|
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
|
-
|
|
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((
|
|
27798
|
+
return new Promise((resolve6, reject) => {
|
|
26972
27799
|
stream[kConsume] = {
|
|
26973
27800
|
type,
|
|
26974
27801
|
stream,
|
|
26975
|
-
resolve:
|
|
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:
|
|
27837
|
+
const { type, body, resolve: resolve6, stream, length } = consume2;
|
|
27011
27838
|
try {
|
|
27012
27839
|
if (type === "text") {
|
|
27013
|
-
|
|
27840
|
+
resolve6(toUSVString(Buffer.concat(body)));
|
|
27014
27841
|
} else if (type === "json") {
|
|
27015
|
-
|
|
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
|
-
|
|
27850
|
+
resolve6(dst.buffer);
|
|
27024
27851
|
} else if (type === "blob") {
|
|
27025
27852
|
if (!Blob2) {
|
|
27026
27853
|
Blob2 = __require("buffer").Blob;
|
|
27027
27854
|
}
|
|
27028
|
-
|
|
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((
|
|
28112
|
+
return new Promise((resolve6, reject) => {
|
|
27286
28113
|
request.call(this, opts, (err, data) => {
|
|
27287
|
-
return err ? reject(err) :
|
|
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((
|
|
28287
|
+
return new Promise((resolve6, reject) => {
|
|
27461
28288
|
stream.call(this, opts, factory, (err, data) => {
|
|
27462
|
-
return err ? reject(err) :
|
|
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((
|
|
28570
|
+
return new Promise((resolve6, reject) => {
|
|
27744
28571
|
upgrade.call(this, opts, (err, data) => {
|
|
27745
|
-
return err ? reject(err) :
|
|
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((
|
|
28661
|
+
return new Promise((resolve6, reject) => {
|
|
27835
28662
|
connect.call(this, opts, (err, data) => {
|
|
27836
|
-
return err ? reject(err) :
|
|
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(
|
|
27997
|
-
if (typeof
|
|
27998
|
-
return
|
|
28823
|
+
function safeUrl(path14) {
|
|
28824
|
+
if (typeof path14 !== "string") {
|
|
28825
|
+
return path14;
|
|
27999
28826
|
}
|
|
28000
|
-
const pathSegments =
|
|
28827
|
+
const pathSegments = path14.split("?");
|
|
28001
28828
|
if (pathSegments.length !== 2) {
|
|
28002
|
-
return
|
|
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:
|
|
28009
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
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:
|
|
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:
|
|
28891
|
+
const { path: path14, method, body, headers, query } = opts;
|
|
28065
28892
|
return {
|
|
28066
|
-
path:
|
|
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:
|
|
29342
|
+
({ method, path: path14, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
28516
29343
|
Method: method,
|
|
28517
29344
|
Origin: origin,
|
|
28518
|
-
Path:
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
33140
|
-
for (const char of
|
|
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
|
|
35647
|
+
let path14 = opts.path;
|
|
34821
35648
|
if (!opts.path.startsWith("/")) {
|
|
34822
|
-
|
|
35649
|
+
path14 = `/${path14}`;
|
|
34823
35650
|
}
|
|
34824
|
-
url = new URL(util.parseOrigin(url).origin +
|
|
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((
|
|
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((
|
|
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((
|
|
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
|
-
|
|
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
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
|
35912
|
-
import * as
|
|
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 =
|
|
36096
|
-
const normalizedPath =
|
|
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 +
|
|
36960
|
+
if (!normalizedPath.startsWith(cwd + path11.sep) && normalizedPath !== cwd) {
|
|
36099
36961
|
return null;
|
|
36100
36962
|
}
|
|
36101
36963
|
try {
|
|
36102
|
-
await
|
|
36103
|
-
const stats = await
|
|
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
|
|
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
|
|
37411
|
+
import * as fs10 from "fs";
|
|
36550
37412
|
import * as fsp2 from "fs/promises";
|
|
36551
|
-
import * as
|
|
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 ||
|
|
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 (!
|
|
36609
|
-
|
|
37470
|
+
if (!fs10.existsSync(reposDir)) {
|
|
37471
|
+
fs10.mkdirSync(reposDir, { recursive: true });
|
|
36610
37472
|
logger.debug(`Created repos directory: ${reposDir}`);
|
|
36611
37473
|
}
|
|
36612
|
-
if (!
|
|
36613
|
-
|
|
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
|
|
37480
|
+
return path12.join(this.config.base_path, "repos");
|
|
36619
37481
|
}
|
|
36620
37482
|
getWorktreesDir() {
|
|
36621
|
-
return
|
|
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 =
|
|
36640
|
-
if (
|
|
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 ||
|
|
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 (
|
|
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 (
|
|
37866
|
+
if (fs10.existsSync(worktree_path)) {
|
|
37005
37867
|
logger.debug(`Manually removing worktree directory`);
|
|
37006
|
-
|
|
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 =
|
|
37017
|
-
|
|
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 =
|
|
37024
|
-
if (!
|
|
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 =
|
|
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 (!
|
|
37902
|
+
if (!fs10.existsSync(worktreesDir)) {
|
|
37041
37903
|
return [];
|
|
37042
37904
|
}
|
|
37043
|
-
const entries =
|
|
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 =
|
|
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 =
|
|
37180
|
-
if (!
|
|
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-
|
|
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
|
|
38750
|
-
const
|
|
38751
|
-
const
|
|
38752
|
-
const resolved =
|
|
38753
|
-
if (!
|
|
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 =
|
|
38757
|
-
const rawData =
|
|
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 =
|
|
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 =
|
|
38790
|
-
const name = loaded.name || `Workflow from ${
|
|
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-
|
|
39720
|
+
//# sourceMappingURL=chunk-EUUAQBTW.mjs.map
|