@miragon/pulse-analytics-connector 0.0.0-bootstrap.0 → 0.21.0
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/LICENSE +21 -0
- package/README.md +86 -3
- package/dist/bpmn-name-lookup.d.ts +72 -0
- package/dist/bpmn-name-lookup.d.ts.map +1 -0
- package/dist/bpmn-name-lookup.js +123 -0
- package/dist/bpmn-name-lookup.js.map +1 -0
- package/dist/bpmn-name-lookup.test.d.ts +2 -0
- package/dist/bpmn-name-lookup.test.d.ts.map +1 -0
- package/dist/bpmn-name-lookup.test.js +287 -0
- package/dist/bpmn-name-lookup.test.js.map +1 -0
- package/dist/bpmn-names.d.ts +38 -0
- package/dist/bpmn-names.d.ts.map +1 -0
- package/dist/bpmn-names.js +22 -0
- package/dist/bpmn-names.js.map +1 -0
- package/dist/brand-gates.test.d.ts +2 -0
- package/dist/brand-gates.test.d.ts.map +1 -0
- package/dist/brand-gates.test.js +58 -0
- package/dist/brand-gates.test.js.map +1 -0
- package/dist/builder-texts.d.ts +4 -0
- package/dist/builder-texts.d.ts.map +1 -0
- package/dist/builder-texts.js +14 -0
- package/dist/builder-texts.js.map +1 -0
- package/dist/builder-texts.test.d.ts +2 -0
- package/dist/builder-texts.test.d.ts.map +1 -0
- package/dist/builder-texts.test.js +32 -0
- package/dist/builder-texts.test.js.map +1 -0
- package/dist/definition.d.ts +3 -0
- package/dist/definition.d.ts.map +1 -0
- package/dist/definition.js +151 -0
- package/dist/definition.js.map +1 -0
- package/dist/engine-ids.d.ts +42 -0
- package/dist/engine-ids.d.ts.map +1 -0
- package/dist/engine-ids.js +50 -0
- package/dist/engine-ids.js.map +1 -0
- package/dist/engine-scope.test.d.ts +2 -0
- package/dist/engine-scope.test.d.ts.map +1 -0
- package/dist/engine-scope.test.js +260 -0
- package/dist/engine-scope.test.js.map +1 -0
- package/dist/heatmap-data.d.ts +15 -0
- package/dist/heatmap-data.d.ts.map +1 -0
- package/dist/heatmap-data.js +2 -0
- package/dist/heatmap-data.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/instructions.d.ts +8 -0
- package/dist/instructions.d.ts.map +1 -0
- package/dist/instructions.js +33 -0
- package/dist/instructions.js.map +1 -0
- package/dist/messages/de.ask-ai.d.ts +9 -0
- package/dist/messages/de.ask-ai.d.ts.map +1 -0
- package/dist/messages/de.ask-ai.js +18 -0
- package/dist/messages/de.ask-ai.js.map +1 -0
- package/dist/messages/de.builder.d.ts +12 -0
- package/dist/messages/de.builder.d.ts.map +1 -0
- package/dist/messages/de.builder.js +53 -0
- package/dist/messages/de.builder.js.map +1 -0
- package/dist/messages/de.server.d.ts +8 -0
- package/dist/messages/de.server.d.ts.map +1 -0
- package/dist/messages/de.server.js +26 -0
- package/dist/messages/de.server.js.map +1 -0
- package/dist/messages/de.sweep.d.ts +10 -0
- package/dist/messages/de.sweep.d.ts.map +1 -0
- package/dist/messages/de.sweep.js +203 -0
- package/dist/messages/de.sweep.js.map +1 -0
- package/dist/messages/en.ask-ai.d.ts +25 -0
- package/dist/messages/en.ask-ai.d.ts.map +1 -0
- package/dist/messages/en.ask-ai.js +24 -0
- package/dist/messages/en.ask-ai.js.map +1 -0
- package/dist/messages/en.builder.d.ts +12 -0
- package/dist/messages/en.builder.d.ts.map +1 -0
- package/dist/messages/en.builder.js +53 -0
- package/dist/messages/en.builder.js.map +1 -0
- package/dist/messages/en.server.d.ts +8 -0
- package/dist/messages/en.server.d.ts.map +1 -0
- package/dist/messages/en.server.js +26 -0
- package/dist/messages/en.server.js.map +1 -0
- package/dist/messages/en.sweep.d.ts +11 -0
- package/dist/messages/en.sweep.d.ts.map +1 -0
- package/dist/messages/en.sweep.js +204 -0
- package/dist/messages/en.sweep.js.map +1 -0
- package/dist/messages/glossary.d.ts +26 -0
- package/dist/messages/glossary.d.ts.map +1 -0
- package/dist/messages/glossary.js +37 -0
- package/dist/messages/glossary.js.map +1 -0
- package/dist/messages/glossary.test.d.ts +2 -0
- package/dist/messages/glossary.test.d.ts.map +1 -0
- package/dist/messages/glossary.test.js +109 -0
- package/dist/messages/glossary.test.js.map +1 -0
- package/dist/messages/index.d.ts +12 -0
- package/dist/messages/index.d.ts.map +1 -0
- package/dist/messages/index.js +23 -0
- package/dist/messages/index.js.map +1 -0
- package/dist/messages/plural.d.ts +10 -0
- package/dist/messages/plural.d.ts.map +1 -0
- package/dist/messages/plural.js +17 -0
- package/dist/messages/plural.js.map +1 -0
- package/dist/messages/use-t.d.ts +10 -0
- package/dist/messages/use-t.d.ts.map +1 -0
- package/dist/messages/use-t.js +10 -0
- package/dist/messages/use-t.js.map +1 -0
- package/dist/module.d.ts +48 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +174 -0
- package/dist/module.js.map +1 -0
- package/dist/module.test.d.ts +2 -0
- package/dist/module.test.d.ts.map +1 -0
- package/dist/module.test.js +230 -0
- package/dist/module.test.js.map +1 -0
- package/dist/named-views.d.ts +27 -0
- package/dist/named-views.d.ts.map +1 -0
- package/dist/named-views.js +73 -0
- package/dist/named-views.js.map +1 -0
- package/dist/named-views.test.d.ts +2 -0
- package/dist/named-views.test.d.ts.map +1 -0
- package/dist/named-views.test.js +110 -0
- package/dist/named-views.test.js.map +1 -0
- package/dist/plugin.d.ts +44 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +52 -0
- package/dist/plugin.js.map +1 -0
- package/dist/prometheus-wiring.test.d.ts +2 -0
- package/dist/prometheus-wiring.test.d.ts.map +1 -0
- package/dist/prometheus-wiring.test.js +142 -0
- package/dist/prometheus-wiring.test.js.map +1 -0
- package/dist/server-locale.d.ts +48 -0
- package/dist/server-locale.d.ts.map +1 -0
- package/dist/server-locale.js +33 -0
- package/dist/server-locale.js.map +1 -0
- package/dist/settings-tools.d.ts +23 -0
- package/dist/settings-tools.d.ts.map +1 -0
- package/dist/settings-tools.js +100 -0
- package/dist/settings-tools.js.map +1 -0
- package/dist/settings.d.ts +77 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +99 -0
- package/dist/settings.js.map +1 -0
- package/dist/settings.test.d.ts +2 -0
- package/dist/settings.test.d.ts.map +1 -0
- package/dist/settings.test.js +299 -0
- package/dist/settings.test.js.map +1 -0
- package/dist/steps/app-config.d.ts +30 -0
- package/dist/steps/app-config.d.ts.map +1 -0
- package/dist/steps/app-config.js +46 -0
- package/dist/steps/app-config.js.map +1 -0
- package/dist/steps/dashboard.d.ts +12 -0
- package/dist/steps/dashboard.d.ts.map +1 -0
- package/dist/steps/dashboard.js +58 -0
- package/dist/steps/dashboard.js.map +1 -0
- package/dist/steps/failure-dashboard.d.ts +10 -0
- package/dist/steps/failure-dashboard.d.ts.map +1 -0
- package/dist/steps/failure-dashboard.js +32 -0
- package/dist/steps/failure-dashboard.js.map +1 -0
- package/dist/steps/index.d.ts +3 -0
- package/dist/steps/index.d.ts.map +1 -0
- package/dist/steps/index.js +3 -0
- package/dist/steps/index.js.map +1 -0
- package/dist/steps/steps.test.d.ts +2 -0
- package/dist/steps/steps.test.d.ts.map +1 -0
- package/dist/steps/steps.test.js +153 -0
- package/dist/steps/steps.test.js.map +1 -0
- package/dist/tool-names.d.ts +13 -0
- package/dist/tool-names.d.ts.map +1 -0
- package/dist/tool-names.js +27 -0
- package/dist/tool-names.js.map +1 -0
- package/dist/tools/cluster-compare.d.ts +8 -0
- package/dist/tools/cluster-compare.d.ts.map +1 -0
- package/dist/tools/cluster-compare.js +17 -0
- package/dist/tools/cluster-compare.js.map +1 -0
- package/dist/tools/element.d.ts +8 -0
- package/dist/tools/element.d.ts.map +1 -0
- package/dist/tools/element.js +25 -0
- package/dist/tools/element.js.map +1 -0
- package/dist/tools/engine-compare.d.ts +8 -0
- package/dist/tools/engine-compare.d.ts.map +1 -0
- package/dist/tools/engine-compare.js +18 -0
- package/dist/tools/engine-compare.js.map +1 -0
- package/dist/tools/engine-compare.test.d.ts +2 -0
- package/dist/tools/engine-compare.test.d.ts.map +1 -0
- package/dist/tools/engine-compare.test.js +166 -0
- package/dist/tools/engine-compare.test.js.map +1 -0
- package/dist/tools/engine-landscape.d.ts +7 -0
- package/dist/tools/engine-landscape.d.ts.map +1 -0
- package/dist/tools/engine-landscape.js +13 -0
- package/dist/tools/engine-landscape.js.map +1 -0
- package/dist/tools/engine-landscape.test.d.ts +2 -0
- package/dist/tools/engine-landscape.test.d.ts.map +1 -0
- package/dist/tools/engine-landscape.test.js +110 -0
- package/dist/tools/engine-landscape.test.js.map +1 -0
- package/dist/tools/failures.d.ts +7 -0
- package/dist/tools/failures.d.ts.map +1 -0
- package/dist/tools/failures.js +13 -0
- package/dist/tools/failures.js.map +1 -0
- package/dist/tools/health.d.ts +7 -0
- package/dist/tools/health.d.ts.map +1 -0
- package/dist/tools/health.js +23 -0
- package/dist/tools/health.js.map +1 -0
- package/dist/tools/health.test.d.ts +2 -0
- package/dist/tools/health.test.d.ts.map +1 -0
- package/dist/tools/health.test.js +119 -0
- package/dist/tools/health.test.js.map +1 -0
- package/dist/tools/index.d.ts +18 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +35 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/performance.d.ts +8 -0
- package/dist/tools/performance.d.ts.map +1 -0
- package/dist/tools/performance.js +25 -0
- package/dist/tools/performance.js.map +1 -0
- package/dist/tools/performance.test.d.ts +2 -0
- package/dist/tools/performance.test.d.ts.map +1 -0
- package/dist/tools/performance.test.js +176 -0
- package/dist/tools/performance.test.js.map +1 -0
- package/dist/tools/version-compare.d.ts +8 -0
- package/dist/tools/version-compare.d.ts.map +1 -0
- package/dist/tools/version-compare.js +17 -0
- package/dist/tools/version-compare.js.map +1 -0
- package/dist/tools/version-compare.test.d.ts +2 -0
- package/dist/tools/version-compare.test.d.ts.map +1 -0
- package/dist/tools/version-compare.test.js +82 -0
- package/dist/tools/version-compare.test.js.map +1 -0
- package/dist/toolsets.d.ts +17 -0
- package/dist/toolsets.d.ts.map +1 -0
- package/dist/toolsets.js +47 -0
- package/dist/toolsets.js.map +1 -0
- package/dist/toolsets.test.d.ts +2 -0
- package/dist/toolsets.test.d.ts.map +1 -0
- package/dist/toolsets.test.js +91 -0
- package/dist/toolsets.test.js.map +1 -0
- package/dist/view-title.test.d.ts +2 -0
- package/dist/view-title.test.d.ts.map +1 -0
- package/dist/view-title.test.js +91 -0
- package/dist/view-title.test.js.map +1 -0
- package/dist/widget-tools/comparisons.d.ts +13 -0
- package/dist/widget-tools/comparisons.d.ts.map +1 -0
- package/dist/widget-tools/comparisons.js +177 -0
- package/dist/widget-tools/comparisons.js.map +1 -0
- package/dist/widget-tools/comparisons.test.d.ts +2 -0
- package/dist/widget-tools/comparisons.test.d.ts.map +1 -0
- package/dist/widget-tools/comparisons.test.js +123 -0
- package/dist/widget-tools/comparisons.test.js.map +1 -0
- package/dist/widget-tools/shared.d.ts +36 -0
- package/dist/widget-tools/shared.d.ts.map +1 -0
- package/dist/widget-tools/shared.js +39 -0
- package/dist/widget-tools/shared.js.map +1 -0
- package/dist/widget-tools.d.ts +25 -0
- package/dist/widget-tools.d.ts.map +1 -0
- package/dist/widget-tools.js +269 -0
- package/dist/widget-tools.js.map +1 -0
- package/dist/widget-tools.test.d.ts +2 -0
- package/dist/widget-tools.test.d.ts.map +1 -0
- package/dist/widget-tools.test.js +272 -0
- package/dist/widget-tools.test.js.map +1 -0
- package/package.json +91 -5
- package/src/bpmn-name-lookup.test.ts +333 -0
- package/src/bpmn-name-lookup.ts +197 -0
- package/src/bpmn-names.ts +51 -0
- package/src/brand-gates.test.ts +69 -0
- package/src/builder-texts.test.ts +40 -0
- package/src/builder-texts.ts +15 -0
- package/src/definition.ts +181 -0
- package/src/engine-ids.ts +85 -0
- package/src/engine-scope.test.ts +324 -0
- package/src/heatmap-data.ts +14 -0
- package/src/index.ts +4 -0
- package/src/instructions.ts +33 -0
- package/src/messages/GLOSSARY.md +88 -0
- package/src/messages/de.ask-ai.ts +28 -0
- package/src/messages/de.builder.ts +77 -0
- package/src/messages/de.server.ts +39 -0
- package/src/messages/de.sweep.ts +244 -0
- package/src/messages/en.ask-ai.ts +34 -0
- package/src/messages/en.builder.ts +76 -0
- package/src/messages/en.server.ts +39 -0
- package/src/messages/en.sweep.ts +240 -0
- package/src/messages/glossary.test.ts +122 -0
- package/src/messages/glossary.ts +62 -0
- package/src/messages/index.ts +24 -0
- package/src/messages/plural.ts +18 -0
- package/src/messages/use-t.ts +12 -0
- package/src/module.test.ts +319 -0
- package/src/module.ts +211 -0
- package/src/named-views.test.ts +141 -0
- package/src/named-views.ts +97 -0
- package/src/plugin.ts +94 -0
- package/src/prometheus-wiring.test.ts +174 -0
- package/src/server-locale.ts +59 -0
- package/src/settings-tools.ts +170 -0
- package/src/settings.test.ts +402 -0
- package/src/settings.ts +114 -0
- package/src/steps/app-config.ts +75 -0
- package/src/steps/dashboard.ts +73 -0
- package/src/steps/failure-dashboard.ts +38 -0
- package/src/steps/index.ts +2 -0
- package/src/steps/steps.test.ts +216 -0
- package/src/tool-names.ts +26 -0
- package/src/tools/cluster-compare.ts +28 -0
- package/src/tools/element.ts +35 -0
- package/src/tools/engine-compare.test.ts +210 -0
- package/src/tools/engine-compare.ts +30 -0
- package/src/tools/engine-landscape.test.ts +138 -0
- package/src/tools/engine-landscape.ts +21 -0
- package/src/tools/failures.ts +19 -0
- package/src/tools/health.test.ts +156 -0
- package/src/tools/health.ts +29 -0
- package/src/tools/index.ts +44 -0
- package/src/tools/performance.test.ts +210 -0
- package/src/tools/performance.ts +38 -0
- package/src/tools/version-compare.test.ts +97 -0
- package/src/tools/version-compare.ts +28 -0
- package/src/toolsets.test.ts +107 -0
- package/src/toolsets.ts +56 -0
- package/src/view-title.test.ts +123 -0
- package/src/widget-tools/comparisons.test.ts +170 -0
- package/src/widget-tools/comparisons.ts +229 -0
- package/src/widget-tools/shared.ts +67 -0
- package/src/widget-tools.test.ts +306 -0
- package/src/widget-tools.ts +375 -0
- package/src/widgets/analytics-dashboard/activity-bottleneck-table.tsx +179 -0
- package/src/widgets/analytics-dashboard/definition-breakdown.tsx +108 -0
- package/src/widgets/analytics-dashboard/execution-performance-kpi.tsx +94 -0
- package/src/widgets/analytics-dashboard/execution-summary-kpi.tsx +122 -0
- package/src/widgets/analytics-dashboard/lib.ts +43 -0
- package/src/widgets/bpmn-heatmap.test.tsx +75 -0
- package/src/widgets/bpmn-heatmap.tsx +127 -0
- package/src/widgets/catalogue-sync.test.ts +16 -0
- package/src/widgets/cluster-compare.tsx +148 -0
- package/src/widgets/comparison-shared.test.ts +237 -0
- package/src/widgets/comparison-shared.tsx +371 -0
- package/src/widgets/comparison-widgets.test.tsx +307 -0
- package/src/widgets/dashboard-widgets.test.tsx +397 -0
- package/src/widgets/engine-compare.tsx +87 -0
- package/src/widgets/engine-landscape.tsx +352 -0
- package/src/widgets/failure-dashboard/error-patterns-table.tsx +122 -0
- package/src/widgets/failure-dashboard/failure-rate-table.test.ts +80 -0
- package/src/widgets/failure-dashboard/failure-rate-table.tsx +170 -0
- package/src/widgets/failure-dashboard/lib.ts +32 -0
- package/src/widgets/failure-dashboard/summary-kpi.tsx +122 -0
- package/src/widgets/failure-landscape-widgets.test.tsx +393 -0
- package/src/widgets/figure.tsx +79 -0
- package/src/widgets/hand-off.test.ts +126 -0
- package/src/widgets/hand-off.ts +102 -0
- package/src/widgets/index.ts +124 -0
- package/src/widgets/model-descriptions.dashboard.test.ts +280 -0
- package/src/widgets/model-descriptions.test.ts +251 -0
- package/src/widgets/model-descriptions.ts +428 -0
- package/src/widgets/names.test.ts +32 -0
- package/src/widgets/names.ts +39 -0
- package/src/widgets/query-gate.test.tsx +57 -0
- package/src/widgets/query-gate.tsx +50 -0
- package/src/widgets/settings-section.test.tsx +174 -0
- package/src/widgets/settings-section.tsx +244 -0
- package/src/widgets/version-compare.test.ts +68 -0
- package/src/widgets/version-compare.tsx +96 -0
- package/src/widgets/view-meta.ts +18 -0
- package/src/widgets/widget-render.test-support.tsx +103 -0
package/src/module.ts
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { z } from "zod"
|
|
2
|
+
import type { AppPlugin } from "@miragon/mcp-toolkit-core"
|
|
3
|
+
import type { MCPServer } from "mcp-use"
|
|
4
|
+
import { createPlugin } from "./plugin.js"
|
|
5
|
+
import { analyticsToolsets } from "./toolsets.js"
|
|
6
|
+
import { analyticsInstructions } from "./instructions.js"
|
|
7
|
+
import type { FetchBpmnXml } from "./bpmn-name-lookup.js"
|
|
8
|
+
import type { ProfileSource } from "./server-locale.js"
|
|
9
|
+
import { NO_ENGINE_SCOPE_MESSAGE } from "./engine-ids.js"
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Self-contained module definition for host apps: everything the app needs to
|
|
13
|
+
* mount the analytics module without knowing its config surface. Conforms
|
|
14
|
+
* structurally to the app's `ModuleDefinition` port — no import of the app.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** The longest delay a Node timer holds — a longer deadline would fire at once. */
|
|
18
|
+
const MAX_TIMEOUT_MS = 2_147_483_647
|
|
19
|
+
|
|
20
|
+
const HEADERS_ERROR =
|
|
21
|
+
'PROMETHEUS_HEADERS must be a JSON object of string header values, e.g. {"X-Scope-OrgID":"tenant-a"}'
|
|
22
|
+
|
|
23
|
+
/** `PROMETHEUS_HEADERS` JSON text (env) or an object (direct caller) → a header record. */
|
|
24
|
+
const headersSchema = z
|
|
25
|
+
.union([
|
|
26
|
+
z.record(z.string(), z.string()),
|
|
27
|
+
z.string().transform((text, ctx) => {
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(text) as unknown
|
|
30
|
+
} catch {
|
|
31
|
+
// Never echo the text: header values are often secrets (API keys).
|
|
32
|
+
ctx.addIssue({ code: "custom", message: HEADERS_ERROR })
|
|
33
|
+
return z.NEVER
|
|
34
|
+
}
|
|
35
|
+
}),
|
|
36
|
+
])
|
|
37
|
+
.pipe(z.record(z.string(), z.string({ error: HEADERS_ERROR }), { error: HEADERS_ERROR }))
|
|
38
|
+
|
|
39
|
+
const analyticsConfigSchema = z.object({
|
|
40
|
+
url: z.string().default("http://localhost:9090"),
|
|
41
|
+
/**
|
|
42
|
+
* Prometheus auth (all optional): a bearer token, OR basic auth — explicit
|
|
43
|
+
* username + password or userinfo in `url` — plus extra headers (tenant
|
|
44
|
+
* ids). The client rejects ambiguous combinations at boot and keeps every
|
|
45
|
+
* credential out of model-visible errors.
|
|
46
|
+
*/
|
|
47
|
+
bearerToken: z.string().optional(),
|
|
48
|
+
username: z.string().optional(),
|
|
49
|
+
password: z.string().optional(),
|
|
50
|
+
headers: headersSchema.optional(),
|
|
51
|
+
// PROMETHEUS_TIMEOUT_MS — strict: a typo fails the boot instead of being
|
|
52
|
+
// coerced into some other deadline. Unset = the client default (30 s).
|
|
53
|
+
timeoutMs: z
|
|
54
|
+
.union([
|
|
55
|
+
z.number(),
|
|
56
|
+
z
|
|
57
|
+
.string()
|
|
58
|
+
.regex(/^\d+$/, "PROMETHEUS_TIMEOUT_MS must be a whole number of milliseconds")
|
|
59
|
+
.transform(Number),
|
|
60
|
+
])
|
|
61
|
+
.pipe(
|
|
62
|
+
z
|
|
63
|
+
.number()
|
|
64
|
+
.int("PROMETHEUS_TIMEOUT_MS must be a whole number of milliseconds")
|
|
65
|
+
.min(1, "PROMETHEUS_TIMEOUT_MS must be at least 1 ms")
|
|
66
|
+
.max(MAX_TIMEOUT_MS, `PROMETHEUS_TIMEOUT_MS must be at most ${MAX_TIMEOUT_MS} ms`),
|
|
67
|
+
)
|
|
68
|
+
.optional(),
|
|
69
|
+
/**
|
|
70
|
+
* `ANALYTICS_ENGINE_IDS` — the engine ids a STANDALONE analytics boot may
|
|
71
|
+
* read (comma-separated `engine_id` values). Only the fallback: when the
|
|
72
|
+
* composition root injects its configured engines (`shared.engineIds`,
|
|
73
|
+
* from camunda7) those win. See `engine-ids.ts`.
|
|
74
|
+
*/
|
|
75
|
+
engineIds: z
|
|
76
|
+
.union([
|
|
77
|
+
z.array(z.string()),
|
|
78
|
+
z.string().transform((text) =>
|
|
79
|
+
text
|
|
80
|
+
.split(",")
|
|
81
|
+
.map((id) => id.trim())
|
|
82
|
+
.filter((id) => id.length > 0),
|
|
83
|
+
),
|
|
84
|
+
])
|
|
85
|
+
.optional(),
|
|
86
|
+
/**
|
|
87
|
+
* The effective toolset the composition root resolved from the
|
|
88
|
+
* `MCP_ACTIVE_MODULES` suffix — always a concrete declared name there. The
|
|
89
|
+
* module's tools are read-only by nature; the toolset only gates the one
|
|
90
|
+
* durable write, `analytics_save_settings` (`standard` only). Kept a plain
|
|
91
|
+
* string here so a direct caller's unknown name still fails closed (warning
|
|
92
|
+
* + `read-only`) instead of throwing — `createPlugin` below resolves it.
|
|
93
|
+
*/
|
|
94
|
+
toolset: z.string().optional(),
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
/** Cross-module resources the host app threads in (structural, app-owned). */
|
|
98
|
+
interface AnalyticsModuleShared {
|
|
99
|
+
profileStore?: ProfileSource
|
|
100
|
+
fetchBpmnXml?: FetchBpmnXml
|
|
101
|
+
/**
|
|
102
|
+
* The engine ids this server is configured for (the camunda7 module's
|
|
103
|
+
* engines) — analytics reads only these. Wins over `ANALYTICS_ENGINE_IDS`.
|
|
104
|
+
*/
|
|
105
|
+
engineIds?: readonly string[]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The engine ids analytics covers: the injected ones, else
|
|
110
|
+
* `ANALYTICS_ENGINE_IDS`, else none (fail-closed). Warns at boot for the two
|
|
111
|
+
* surprising cases — no scope at all, and an env list the injected one
|
|
112
|
+
* overrides.
|
|
113
|
+
*/
|
|
114
|
+
function effectiveEngineIds(
|
|
115
|
+
injected: readonly string[] | undefined,
|
|
116
|
+
fromEnv: readonly string[] | undefined,
|
|
117
|
+
): readonly string[] {
|
|
118
|
+
if (injected && injected.length > 0) {
|
|
119
|
+
if (fromEnv && fromEnv.length > 0) {
|
|
120
|
+
console.warn(
|
|
121
|
+
`[analytics] ANALYTICS_ENGINE_IDS is ignored: the server's configured engines (${injected.join(", ")}) scope analytics.`,
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
return injected
|
|
125
|
+
}
|
|
126
|
+
if (fromEnv && fromEnv.length > 0) return fromEnv
|
|
127
|
+
console.warn(`[analytics] ${NO_ENGINE_SCOPE_MESSAGE}`)
|
|
128
|
+
return []
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export const analyticsModule = {
|
|
132
|
+
name: "analytics",
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Pure env → raw-config mapping. `PROMETHEUS_URL` is trimmed so an empty
|
|
136
|
+
* assignment (`PROMETHEUS_URL=` left in a .env or compose env_file) falls
|
|
137
|
+
* through to the schema default instead of producing an invalid-URL client.
|
|
138
|
+
*/
|
|
139
|
+
configFromEnv(env: NodeJS.ProcessEnv): Record<string, unknown> {
|
|
140
|
+
// Blank = unset for every variable (a `KEY=` left in a .env file).
|
|
141
|
+
// Credentials are passed verbatim otherwise — never trimmed into another secret.
|
|
142
|
+
const trimmed = (name: string) => env[name]?.trim() || undefined
|
|
143
|
+
const verbatim = (name: string) => (env[name]?.trim() ? env[name] : undefined)
|
|
144
|
+
return {
|
|
145
|
+
url: trimmed("PROMETHEUS_URL"),
|
|
146
|
+
bearerToken: verbatim("PROMETHEUS_BEARER_TOKEN"),
|
|
147
|
+
username: verbatim("PROMETHEUS_USERNAME"),
|
|
148
|
+
password: verbatim("PROMETHEUS_PASSWORD"),
|
|
149
|
+
headers: trimmed("PROMETHEUS_HEADERS"),
|
|
150
|
+
timeoutMs: trimmed("PROMETHEUS_TIMEOUT_MS"),
|
|
151
|
+
engineIds: trimmed("ANALYTICS_ENGINE_IDS"),
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
/** This module's slice of the app's unknown-env-var typo warner. */
|
|
156
|
+
knownEnvVars: [
|
|
157
|
+
"PROMETHEUS_URL",
|
|
158
|
+
"PROMETHEUS_BEARER_TOKEN",
|
|
159
|
+
"PROMETHEUS_USERNAME",
|
|
160
|
+
"PROMETHEUS_PASSWORD",
|
|
161
|
+
"PROMETHEUS_HEADERS",
|
|
162
|
+
"PROMETHEUS_TIMEOUT_MS",
|
|
163
|
+
"ANALYTICS_ENGINE_IDS",
|
|
164
|
+
] as const,
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* `read-only` (the floor) | `standard` (adds the caller's own settings save,
|
|
168
|
+
* `analytics_save_settings`; everything else is read-only anyway). No suffix
|
|
169
|
+
* means `read-only` without OAuth and `standard` with it; an empty or unknown
|
|
170
|
+
* suffix falls back to `read-only`. See `toolsets.ts`.
|
|
171
|
+
*/
|
|
172
|
+
toolsets: analyticsToolsets,
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Boot-time hints for active deployments. The code default (:9090) matches a
|
|
176
|
+
* bare Prometheus, NOT the repo's compose stack (:8460) — without the hint
|
|
177
|
+
* every analytics query 404s silently.
|
|
178
|
+
*/
|
|
179
|
+
bootWarnings(env: NodeJS.ProcessEnv): string[] {
|
|
180
|
+
if (env.PROMETHEUS_URL?.trim()) return []
|
|
181
|
+
return [
|
|
182
|
+
"PROMETHEUS_URL is not set — defaulting to http://localhost:9090. The repo's Compose stack publishes Prometheus on :8460 (PROMETHEUS_URL=http://localhost:8460).",
|
|
183
|
+
]
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* The module's server-instructions snippet: what `engine` means here (a
|
|
188
|
+
* metric filter over the configured engines — their fleet aggregate when
|
|
189
|
+
* omitted, camunda7's saved default does not apply), the periods and the
|
|
190
|
+
* health routing.
|
|
191
|
+
*/
|
|
192
|
+
instructions(): string {
|
|
193
|
+
return analyticsInstructions()
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
createPlugin(
|
|
197
|
+
config: Record<string, unknown>,
|
|
198
|
+
shared: AnalyticsModuleShared,
|
|
199
|
+
): AppPlugin<MCPServer> {
|
|
200
|
+
const { toolset, engineIds, ...parsed } = analyticsConfigSchema.parse(config)
|
|
201
|
+
return createPlugin({
|
|
202
|
+
...parsed,
|
|
203
|
+
engineIds: effectiveEngineIds(shared.engineIds, engineIds),
|
|
204
|
+
// Resolved once, here: missing → the read-only floor, unknown → warning +
|
|
205
|
+
// floor. The plugin only ever sees a declared name.
|
|
206
|
+
toolset: analyticsToolsets.resolve(toolset),
|
|
207
|
+
fetchBpmnXml: shared.fetchBpmnXml,
|
|
208
|
+
profileStore: shared.profileStore,
|
|
209
|
+
})
|
|
210
|
+
},
|
|
211
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest"
|
|
2
|
+
import type {
|
|
3
|
+
AnalyticsDashboardData,
|
|
4
|
+
EngineLandscapeResult,
|
|
5
|
+
FailureDashboardData,
|
|
6
|
+
} from "@miragon/pulse-analytics-client"
|
|
7
|
+
import { namedDashboard, namedFailureDashboard, namedLandscape } from "./named-views.js"
|
|
8
|
+
import { createNameLookup, type NameLookup } from "./bpmn-name-lookup.js"
|
|
9
|
+
import { elementNameOf, processNameOf } from "./bpmn-names.js"
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Every view asks for the names of exactly the ids it lists, no more, by
|
|
13
|
+
* priority, on the engines its rows come from.
|
|
14
|
+
*/
|
|
15
|
+
describe("named views", () => {
|
|
16
|
+
const lookup = () => vi.fn<NameLookup>(() => Promise.resolve({}))
|
|
17
|
+
|
|
18
|
+
it("the dashboard: its scope, the elements of its activities, then its definitions", async () => {
|
|
19
|
+
const namesFor = lookup()
|
|
20
|
+
const data = {
|
|
21
|
+
processDefinitionKey: "order",
|
|
22
|
+
engines: ["prod-b", "prod-a", "prod-c"],
|
|
23
|
+
reportingEngines: ["prod-a", "prod-b"],
|
|
24
|
+
definitionBreakdown: [{ processDefinitionKey: "order" }, { processDefinitionKey: "refund" }],
|
|
25
|
+
activityBreakdown: [
|
|
26
|
+
{ processDefinitionKey: "order", activityId: "Task_A" },
|
|
27
|
+
{ processDefinitionKey: "order", activityId: "Task_B" },
|
|
28
|
+
],
|
|
29
|
+
} as unknown as AnalyticsDashboardData
|
|
30
|
+
const named = await namedDashboard(data, namesFor)
|
|
31
|
+
expect(named.names).toEqual({})
|
|
32
|
+
const [keys, request] = namesFor.mock.calls[0]
|
|
33
|
+
expect([...keys]).toEqual(["order", "order", "order", "order", "refund"])
|
|
34
|
+
expect(request?.elementIds).toEqual({ order: ["Task_A", "Task_B"], refund: [] })
|
|
35
|
+
// The reporting engines, in the scope's (configuration) order; a silent one has no rows.
|
|
36
|
+
expect(request?.engines).toEqual(["prod-b", "prod-a"])
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it("the dashboard reads on its whole scope when the payload does not say which engines report", async () => {
|
|
40
|
+
const namesFor = lookup()
|
|
41
|
+
await namedDashboard(
|
|
42
|
+
{
|
|
43
|
+
processDefinitionKey: null,
|
|
44
|
+
engines: ["prod-a", "prod-b"],
|
|
45
|
+
definitionBreakdown: [],
|
|
46
|
+
activityBreakdown: [],
|
|
47
|
+
} as unknown as AnalyticsDashboardData,
|
|
48
|
+
namesFor,
|
|
49
|
+
)
|
|
50
|
+
expect(namesFor.mock.calls[0][1]?.engines).toEqual(["prod-a", "prod-b"])
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it("names a process key such as constructor like any other", async () => {
|
|
54
|
+
const namesFor = lookup()
|
|
55
|
+
await namedDashboard(
|
|
56
|
+
{
|
|
57
|
+
processDefinitionKey: null,
|
|
58
|
+
engines: null,
|
|
59
|
+
definitionBreakdown: [{ processDefinitionKey: "constructor" }],
|
|
60
|
+
activityBreakdown: [{ processDefinitionKey: "constructor", activityId: "Task_A" }],
|
|
61
|
+
} as unknown as AnalyticsDashboardData,
|
|
62
|
+
namesFor,
|
|
63
|
+
)
|
|
64
|
+
expect(namesFor.mock.calls[0][1]?.elementIds).toEqual({ constructor: ["Task_A"] })
|
|
65
|
+
expect(namesFor.mock.calls[0][1]?.engines).toBeNull()
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// The lookup reads at most 40 models per view: a fleet with more
|
|
69
|
+
// definitions must not lose the names of its bottleneck activities to the
|
|
70
|
+
// long tail of the breakdown (sorted by starts).
|
|
71
|
+
it("keeps the activities' names when the fleet has more than 40 definitions", async () => {
|
|
72
|
+
const fetchBpmnXml = vi.fn((key: string) =>
|
|
73
|
+
Promise.resolve(
|
|
74
|
+
`<process id="${key}" name="Process ${key}"><userTask id="Task_Slow" name="Review"/></process>`,
|
|
75
|
+
),
|
|
76
|
+
)
|
|
77
|
+
const definitions = Array.from({ length: 45 }, (_, i) => ({ processDefinitionKey: `p${i}` }))
|
|
78
|
+
const data = {
|
|
79
|
+
processDefinitionKey: null,
|
|
80
|
+
engines: ["prod-a"],
|
|
81
|
+
reportingEngines: ["prod-a"],
|
|
82
|
+
definitionBreakdown: definitions,
|
|
83
|
+
// A long-running, low-volume process: the last of the breakdown.
|
|
84
|
+
activityBreakdown: [{ processDefinitionKey: "p44", activityId: "Task_Slow" }],
|
|
85
|
+
} as unknown as AnalyticsDashboardData
|
|
86
|
+
const { names } = await namedDashboard(data, createNameLookup(fetchBpmnXml))
|
|
87
|
+
expect(elementNameOf(names, "p44", "Task_Slow")).toBe("Review")
|
|
88
|
+
expect(processNameOf(names, "p44")).toBe("Process p44")
|
|
89
|
+
expect(fetchBpmnXml).toHaveBeenCalledTimes(40)
|
|
90
|
+
// The cap falls on the end of the breakdown instead.
|
|
91
|
+
expect(processNameOf(names, "p0")).toBe("Process p0")
|
|
92
|
+
expect(processNameOf(names, "p40")).toBeNull()
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it("the failure dashboard: process names only, its most affected first, on its engines", async () => {
|
|
96
|
+
const failures = lookup()
|
|
97
|
+
await namedFailureDashboard(
|
|
98
|
+
{
|
|
99
|
+
engines: ["prod-a", "prod-b"],
|
|
100
|
+
errorPatterns: [{ processDefinitionKey: "a" }],
|
|
101
|
+
processBreakdown: [{ processDefinitionKey: "b" }],
|
|
102
|
+
mostAffectedProcess: "b",
|
|
103
|
+
} as unknown as FailureDashboardData,
|
|
104
|
+
failures,
|
|
105
|
+
)
|
|
106
|
+
expect([...failures.mock.calls[0][0]]).toEqual(["b", "a", "b"])
|
|
107
|
+
expect(failures.mock.calls[0][1]).toEqual({
|
|
108
|
+
elementIds: { a: [], b: [] },
|
|
109
|
+
engines: ["prod-a", "prod-b"],
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
const none = lookup()
|
|
113
|
+
await namedFailureDashboard(
|
|
114
|
+
{
|
|
115
|
+
engines: ["prod-a"],
|
|
116
|
+
errorPatterns: [],
|
|
117
|
+
processBreakdown: [],
|
|
118
|
+
mostAffectedProcess: null,
|
|
119
|
+
} as unknown as FailureDashboardData,
|
|
120
|
+
none,
|
|
121
|
+
)
|
|
122
|
+
expect([...none.mock.calls[0][0]]).toEqual([])
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it("the landscape: each process read on the engines it runs on", async () => {
|
|
126
|
+
const landscape = lookup()
|
|
127
|
+
await namedLandscape(
|
|
128
|
+
{
|
|
129
|
+
processes: [
|
|
130
|
+
{ processDefinitionKey: "c", engineIds: ["prod-b", "prod-c"] },
|
|
131
|
+
{ processDefinitionKey: "d", engineIds: ["prod-a"] },
|
|
132
|
+
],
|
|
133
|
+
} as unknown as EngineLandscapeResult,
|
|
134
|
+
landscape,
|
|
135
|
+
)
|
|
136
|
+
expect(landscape.mock.calls[0][1]).toEqual({
|
|
137
|
+
elementIds: { c: [], d: [] },
|
|
138
|
+
enginesByKey: { c: ["prod-b", "prod-c"], d: ["prod-a"] },
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
})
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnalyticsDashboardData,
|
|
3
|
+
EngineLandscapeResult,
|
|
4
|
+
FailureDashboardData,
|
|
5
|
+
} from "@miragon/pulse-analytics-client"
|
|
6
|
+
import type { NameLookup } from "./bpmn-name-lookup.js"
|
|
7
|
+
import type { Named } from "./bpmn-names.js"
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The names behind the ids a view lists (U13), added to its payload once,
|
|
11
|
+
* here — the show tool, its `*_data` feed and the pipeline step of a view
|
|
12
|
+
* all pass their figures through the same function, so the three paths show
|
|
13
|
+
* the same names. Names are enrichment: a model that cannot be read leaves
|
|
14
|
+
* its key out of `names` and the view shows the id, never fails.
|
|
15
|
+
*
|
|
16
|
+
* Each model is read on the engines the view's rows come from (a process
|
|
17
|
+
* that runs only on the third engine is still named), and a view names its
|
|
18
|
+
* keys by priority: the lookup reads at most so many models per view.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The dashboard: its scope, then the processes of the activity breakdown
|
|
23
|
+
* (whose element names the activity table shows: a bottleneck in a
|
|
24
|
+
* low-volume process must not lose its names to the long tail of the
|
|
25
|
+
* breakdown), then the per-definition breakdown. Its models are read on the
|
|
26
|
+
* engines in scope that report, in configuration order.
|
|
27
|
+
*/
|
|
28
|
+
export async function namedDashboard(
|
|
29
|
+
data: AnalyticsDashboardData,
|
|
30
|
+
namesFor: NameLookup,
|
|
31
|
+
): Promise<Named<AnalyticsDashboardData>> {
|
|
32
|
+
const keys = [
|
|
33
|
+
...(data.processDefinitionKey ? [data.processDefinitionKey] : []),
|
|
34
|
+
...data.activityBreakdown.map((a) => a.processDefinitionKey),
|
|
35
|
+
...data.definitionBreakdown.map((d) => d.processDefinitionKey),
|
|
36
|
+
]
|
|
37
|
+
const elementIds = new Map<string, string[]>(keys.map((key) => [key, []]))
|
|
38
|
+
for (const a of data.activityBreakdown) elementIds.get(a.processDefinitionKey)?.push(a.activityId)
|
|
39
|
+
return {
|
|
40
|
+
...data,
|
|
41
|
+
names: await namesFor(keys, {
|
|
42
|
+
elementIds: Object.fromEntries(elementIds),
|
|
43
|
+
engines: reportingInOrder(data.engines, data.reportingEngines),
|
|
44
|
+
}),
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The failure dashboard: the processes of its incident groups and its per-process table. */
|
|
49
|
+
export async function namedFailureDashboard(
|
|
50
|
+
data: FailureDashboardData,
|
|
51
|
+
namesFor: NameLookup,
|
|
52
|
+
): Promise<Named<FailureDashboardData>> {
|
|
53
|
+
const keys = [
|
|
54
|
+
...(data.mostAffectedProcess ? [data.mostAffectedProcess] : []),
|
|
55
|
+
...data.errorPatterns.map((p) => p.processDefinitionKey),
|
|
56
|
+
...data.processBreakdown.map((p) => p.processDefinitionKey),
|
|
57
|
+
]
|
|
58
|
+
return {
|
|
59
|
+
...data,
|
|
60
|
+
names: await namesFor(keys, { elementIds: noElements(keys), engines: data.engines }),
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The landscape: the processes of its what-runs-where matrix, each read on the engines it runs on. */
|
|
65
|
+
export async function namedLandscape(
|
|
66
|
+
data: EngineLandscapeResult,
|
|
67
|
+
namesFor: NameLookup,
|
|
68
|
+
): Promise<Named<EngineLandscapeResult>> {
|
|
69
|
+
const keys = data.processes.map((p) => p.processDefinitionKey)
|
|
70
|
+
return {
|
|
71
|
+
...data,
|
|
72
|
+
names: await namesFor(keys, {
|
|
73
|
+
elementIds: noElements(keys),
|
|
74
|
+
enginesByKey: Object.fromEntries(
|
|
75
|
+
data.processes.map((p) => [p.processDefinitionKey, p.engineIds]),
|
|
76
|
+
),
|
|
77
|
+
}),
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Process names only: no element of these models is on screen. */
|
|
82
|
+
function noElements(keys: readonly string[]): Record<string, string[]> {
|
|
83
|
+
return Object.fromEntries(keys.map((key) => [key, []]))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The engines in scope (configuration order: the default engine first) that
|
|
88
|
+
* report metrics: the rows come from them, a silent engine has none. All of
|
|
89
|
+
* the scope when the payload does not say which report.
|
|
90
|
+
*/
|
|
91
|
+
function reportingInOrder(
|
|
92
|
+
engines: readonly string[] | null,
|
|
93
|
+
reporting: readonly string[] | undefined,
|
|
94
|
+
): readonly string[] | null {
|
|
95
|
+
if (!engines || !reporting) return engines ?? reporting ?? null
|
|
96
|
+
return engines.filter((id) => reporting.includes(id))
|
|
97
|
+
}
|
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { AppPlugin } from "@miragon/mcp-toolkit-core"
|
|
2
|
+
import type { MCPServer } from "mcp-use"
|
|
3
|
+
import { installMcpRequestContext } from "@miragon/pulse-widget-shell/server"
|
|
4
|
+
import { createPrometheusClient, type PrometheusConfig } from "@miragon/pulse-analytics-client"
|
|
5
|
+
import { registerTools } from "./tools/index.js"
|
|
6
|
+
import { registerSettingsTools } from "./settings-tools.js"
|
|
7
|
+
import { registerWidgetTools } from "./widget-tools.js"
|
|
8
|
+
import { createNameLookup, type FetchBpmnXml } from "./bpmn-name-lookup.js"
|
|
9
|
+
import { definition } from "./definition.js"
|
|
10
|
+
import type { ProfileSource } from "./server-locale.js"
|
|
11
|
+
import { analyticsToolsets } from "./toolsets.js"
|
|
12
|
+
import { createEngineScope } from "./engine-ids.js"
|
|
13
|
+
import type { AnalyticsAppConfig } from "./steps/app-config.js"
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* `PrometheusConfig` carries the connection: the base URL (e.g.
|
|
17
|
+
* http://localhost:9090), optional bearer/basic auth + extra headers, and the
|
|
18
|
+
* per-query deadline (`timeoutMs`).
|
|
19
|
+
*/
|
|
20
|
+
export interface AnalyticsPluginConfig extends PrometheusConfig {
|
|
21
|
+
/**
|
|
22
|
+
* Optional BPMN-XML lookup used by widget tools that enrich metric data with
|
|
23
|
+
* engine lookups — the BPMN heatmap's diagram, and the process and activity
|
|
24
|
+
* names the dashboards, the failure dashboard and the landscape show in
|
|
25
|
+
* place of ids. Injected by the host app (which owns the engine client) so
|
|
26
|
+
* this module stays free of engine SDKs. When absent, the heatmap degrades
|
|
27
|
+
* to a non-diagram fallback and the views show ids.
|
|
28
|
+
*/
|
|
29
|
+
fetchBpmnXml?: FetchBpmnXml
|
|
30
|
+
/**
|
|
31
|
+
* Profile store (shared with camunda7): locale for model-facing summaries,
|
|
32
|
+
* plus this module's own settings slice (`modules.analytics`) — read for
|
|
33
|
+
* period/minBucketSize defaults, written by `analytics_save_settings`.
|
|
34
|
+
*/
|
|
35
|
+
profileStore?: ProfileSource
|
|
36
|
+
/**
|
|
37
|
+
* The module's toolset (`analyticsModule` passes the one the composition
|
|
38
|
+
* root resolved). `"read-only"` — also what an ABSENT or unknown toolset
|
|
39
|
+
* resolves to (an unknown name warns) — registers no settings save tool;
|
|
40
|
+
* `"standard"` registers it, given a writable `profileStore`. Typed `string`
|
|
41
|
+
* like camunda7's, so callers can pass a configured value through; it is
|
|
42
|
+
* resolved fail-closed here.
|
|
43
|
+
*/
|
|
44
|
+
toolset?: string
|
|
45
|
+
/**
|
|
46
|
+
* The engine ids analytics may read — the server's configured engines.
|
|
47
|
+
* Empty or absent: every engine-reading tool refuses (fail-closed), see
|
|
48
|
+
* `engine-ids.ts`.
|
|
49
|
+
*/
|
|
50
|
+
engineIds?: readonly string[]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function createPlugin(config: AnalyticsPluginConfig): AppPlugin<MCPServer> {
|
|
54
|
+
const client = createPrometheusClient({
|
|
55
|
+
url: config.url,
|
|
56
|
+
bearerToken: config.bearerToken,
|
|
57
|
+
username: config.username,
|
|
58
|
+
password: config.password,
|
|
59
|
+
headers: config.headers,
|
|
60
|
+
timeoutMs: config.timeoutMs,
|
|
61
|
+
})
|
|
62
|
+
const engineScope = createEngineScope(config.engineIds)
|
|
63
|
+
// ONE name lookup (and its per-caller cache) for the tools, the feeds and the steps.
|
|
64
|
+
const namesFor = createNameLookup(config.fetchBpmnXml)
|
|
65
|
+
// The steps get the profile store too: a step's omitted period resolves to
|
|
66
|
+
// the caller's saved default, like every tool's.
|
|
67
|
+
const appConfig = {
|
|
68
|
+
client,
|
|
69
|
+
engineScope,
|
|
70
|
+
profileStore: config.profileStore,
|
|
71
|
+
namesFor,
|
|
72
|
+
} satisfies AnalyticsAppConfig
|
|
73
|
+
return {
|
|
74
|
+
definition,
|
|
75
|
+
appConfig,
|
|
76
|
+
// Tools and feeds resolve the caller (saved defaults, summary locale) from
|
|
77
|
+
// the handler ctx. The pipeline steps get none, so their saved-period
|
|
78
|
+
// lookup reads the ambient request info — installed here like camunda7
|
|
79
|
+
// does (idempotent; the host installs it too).
|
|
80
|
+
registerTools: (server) => {
|
|
81
|
+
installMcpRequestContext(server)
|
|
82
|
+
registerTools(server, client, engineScope, config.profileStore)
|
|
83
|
+
},
|
|
84
|
+
registerWidgetTools: (server) => {
|
|
85
|
+
registerWidgetTools(server, client, {
|
|
86
|
+
fetchBpmnXml: config.fetchBpmnXml,
|
|
87
|
+
namesFor,
|
|
88
|
+
profileStore: config.profileStore,
|
|
89
|
+
engineScope,
|
|
90
|
+
})
|
|
91
|
+
registerSettingsTools(server, config.profileStore, analyticsToolsets.resolve(config.toolset))
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
}
|