@decocms/bindings 1.3.2 → 1.3.4
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/package.json +6 -5
- package/src/core/plugin-router.tsx +17 -12
- package/src/index.ts +19 -28
- package/src/well-known/language-model.ts +0 -5
- package/src/well-known/trigger.ts +143 -0
- package/src/well-known/workflow.ts +8 -4
- package/src/well-known/reports.ts +0 -333
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/bindings",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"check": "tsc --noEmit",
|
|
7
7
|
"test": "bun test"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@modelcontextprotocol/sdk": "1.
|
|
10
|
+
"@modelcontextprotocol/sdk": "1.27.1",
|
|
11
11
|
"@tanstack/react-router": "1.139.7",
|
|
12
12
|
"react": "^19.2.0",
|
|
13
13
|
"zod": "^4.0.0",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"hono": "^4.7.10",
|
|
18
|
-
"kysely": "^0.
|
|
18
|
+
"kysely": "^0.28.12"
|
|
19
19
|
},
|
|
20
20
|
"exports": {
|
|
21
21
|
".": "./src/index.ts",
|
|
@@ -31,14 +31,15 @@
|
|
|
31
31
|
"./plugins": "./src/core/plugins.ts",
|
|
32
32
|
"./plugin-router": "./src/core/plugin-router.tsx",
|
|
33
33
|
"./ai-gateway": "./src/well-known/ai-gateway.ts",
|
|
34
|
-
"./server-plugin": "./src/core/server-plugin.ts"
|
|
34
|
+
"./server-plugin": "./src/core/server-plugin.ts",
|
|
35
|
+
"./trigger": "./src/well-known/trigger.ts"
|
|
35
36
|
},
|
|
36
37
|
"engines": {
|
|
37
38
|
"node": ">=24.0.0"
|
|
38
39
|
},
|
|
39
40
|
"repository": {
|
|
40
41
|
"type": "git",
|
|
41
|
-
"url": "git+https://github.com/decocms/
|
|
42
|
+
"url": "git+https://github.com/decocms/studio.git",
|
|
42
43
|
"directory": "packages/bindings"
|
|
43
44
|
},
|
|
44
45
|
"publishConfig": {
|
|
@@ -17,20 +17,20 @@ import {
|
|
|
17
17
|
import type { PluginSetupContext } from "./plugins";
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Prepends the plugin base path (/$org/$
|
|
20
|
+
* Prepends the plugin base path (/$org/projects/$virtualMcpId/$pluginId) to a route path.
|
|
21
21
|
* Handles both absolute plugin paths (starting with /) and relative paths.
|
|
22
22
|
*/
|
|
23
23
|
function prependBasePath(
|
|
24
24
|
to: string | undefined,
|
|
25
25
|
org: string,
|
|
26
|
-
|
|
26
|
+
virtualMcpId: string,
|
|
27
27
|
pluginId: string,
|
|
28
28
|
): string {
|
|
29
|
-
if (!to) return `/${org}/${
|
|
29
|
+
if (!to) return `/${org}/projects/${virtualMcpId}/${pluginId}`;
|
|
30
30
|
|
|
31
31
|
// If path starts with /, it's relative to the plugin root
|
|
32
32
|
if (to.startsWith("/")) {
|
|
33
|
-
return `/${org}/${
|
|
33
|
+
return `/${org}/projects/${virtualMcpId}/${pluginId}${to}`;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
// Otherwise, it's already a full path or relative
|
|
@@ -123,9 +123,9 @@ export function createPluginRouter<TRoutes extends AnyRoute | AnyRoute[]>(
|
|
|
123
123
|
*/
|
|
124
124
|
useNavigate: () => {
|
|
125
125
|
const navigate = useNavigate();
|
|
126
|
-
const { org,
|
|
126
|
+
const { org, virtualMcpId, pluginId } = useParams({ strict: false }) as {
|
|
127
127
|
org: string;
|
|
128
|
-
|
|
128
|
+
virtualMcpId: string;
|
|
129
129
|
pluginId: string;
|
|
130
130
|
};
|
|
131
131
|
|
|
@@ -136,14 +136,14 @@ export function createPluginRouter<TRoutes extends AnyRoute | AnyRoute[]>(
|
|
|
136
136
|
search?: TRouteById<TTo>["types"]["fullSearchSchema"];
|
|
137
137
|
},
|
|
138
138
|
) => {
|
|
139
|
-
const to = prependBasePath(options.to, org,
|
|
139
|
+
const to = prependBasePath(options.to, org, virtualMcpId, pluginId);
|
|
140
140
|
|
|
141
141
|
return navigate({
|
|
142
142
|
...options,
|
|
143
143
|
to,
|
|
144
144
|
params: {
|
|
145
145
|
org,
|
|
146
|
-
|
|
146
|
+
virtualMcpId,
|
|
147
147
|
pluginId,
|
|
148
148
|
...(options.params as Record<string, string>),
|
|
149
149
|
},
|
|
@@ -171,13 +171,18 @@ export function createPluginRouter<TRoutes extends AnyRoute | AnyRoute[]>(
|
|
|
171
171
|
children?: ReactNode;
|
|
172
172
|
},
|
|
173
173
|
) {
|
|
174
|
-
const { org,
|
|
174
|
+
const { org, virtualMcpId, pluginId } = useParams({ strict: false }) as {
|
|
175
175
|
org: string;
|
|
176
|
-
|
|
176
|
+
virtualMcpId: string;
|
|
177
177
|
pluginId: string;
|
|
178
178
|
};
|
|
179
179
|
|
|
180
|
-
const to = prependBasePath(
|
|
180
|
+
const to = prependBasePath(
|
|
181
|
+
props.to as string,
|
|
182
|
+
org,
|
|
183
|
+
virtualMcpId,
|
|
184
|
+
pluginId,
|
|
185
|
+
);
|
|
181
186
|
|
|
182
187
|
return (
|
|
183
188
|
<TanStackLink
|
|
@@ -185,7 +190,7 @@ export function createPluginRouter<TRoutes extends AnyRoute | AnyRoute[]>(
|
|
|
185
190
|
to={to}
|
|
186
191
|
params={{
|
|
187
192
|
org,
|
|
188
|
-
|
|
193
|
+
virtualMcpId,
|
|
189
194
|
pluginId,
|
|
190
195
|
...props.params,
|
|
191
196
|
}}
|
package/src/index.ts
CHANGED
|
@@ -84,6 +84,25 @@ export {
|
|
|
84
84
|
type EventBusBindingClient,
|
|
85
85
|
} from "./well-known/event-bus";
|
|
86
86
|
|
|
87
|
+
// Re-export trigger binding types (for connections that can emit triggers)
|
|
88
|
+
export {
|
|
89
|
+
TriggerParamSchema,
|
|
90
|
+
type TriggerParam,
|
|
91
|
+
TriggerDefinitionSchema,
|
|
92
|
+
type TriggerDefinition,
|
|
93
|
+
TriggerListInputSchema,
|
|
94
|
+
type TriggerListInput,
|
|
95
|
+
TriggerListOutputSchema,
|
|
96
|
+
type TriggerListOutput,
|
|
97
|
+
TriggerConfigureInputSchema,
|
|
98
|
+
type TriggerConfigureInput,
|
|
99
|
+
TriggerConfigureOutputSchema,
|
|
100
|
+
type TriggerConfigureOutput,
|
|
101
|
+
TRIGGER_BINDING,
|
|
102
|
+
TriggerBinding,
|
|
103
|
+
type TriggerBindingClient,
|
|
104
|
+
} from "./well-known/trigger";
|
|
105
|
+
|
|
87
106
|
// Re-export object storage binding types
|
|
88
107
|
export {
|
|
89
108
|
OBJECT_STORAGE_BINDING,
|
|
@@ -104,31 +123,3 @@ export {
|
|
|
104
123
|
|
|
105
124
|
// Re-export workflow binding types
|
|
106
125
|
export { WORKFLOWS_COLLECTION_BINDING } from "./well-known/workflow";
|
|
107
|
-
|
|
108
|
-
// Re-export reports binding types
|
|
109
|
-
export {
|
|
110
|
-
REPORTS_BINDING,
|
|
111
|
-
type ReportsBinding,
|
|
112
|
-
type ReportStatus,
|
|
113
|
-
type ReportLifecycleStatus,
|
|
114
|
-
type CriterionItem,
|
|
115
|
-
type MetricItem,
|
|
116
|
-
type RankedListRow,
|
|
117
|
-
type ReportSection,
|
|
118
|
-
type ReportSummary,
|
|
119
|
-
type Report,
|
|
120
|
-
type ReportsListInput,
|
|
121
|
-
type ReportsListOutput,
|
|
122
|
-
type ReportsGetInput,
|
|
123
|
-
type ReportsGetOutput,
|
|
124
|
-
type ReportsUpdateStatusInput,
|
|
125
|
-
type ReportsUpdateStatusOutput,
|
|
126
|
-
ReportStatusSchema,
|
|
127
|
-
ReportLifecycleStatusSchema,
|
|
128
|
-
MetricItemSchema,
|
|
129
|
-
ReportSectionSchema,
|
|
130
|
-
ReportSummarySchema,
|
|
131
|
-
ReportSchema,
|
|
132
|
-
type SectionGroup,
|
|
133
|
-
groupSections,
|
|
134
|
-
} from "./well-known/reports";
|
|
@@ -640,11 +640,6 @@ export const LanguageModelInputSchema = z.object({
|
|
|
640
640
|
callOptions: LanguageModelCallOptionsSchema,
|
|
641
641
|
});
|
|
642
642
|
|
|
643
|
-
/**
|
|
644
|
-
* Model entity schema for AI models (Collection Entity)
|
|
645
|
-
* Extends BaseCollectionEntitySchema with model-specific fields
|
|
646
|
-
* Base schema already includes: id, title, created_at, updated_at, created_by, updated_by
|
|
647
|
-
*/
|
|
648
643
|
export const ModelCollectionEntitySchema = BaseCollectionEntitySchema.extend({
|
|
649
644
|
// Model-specific fields
|
|
650
645
|
logo: z.string().nullable(),
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trigger Well-Known Binding
|
|
3
|
+
*
|
|
4
|
+
* Defines the interface for connections that can emit triggers.
|
|
5
|
+
* Any MCP that implements this binding can list available triggers
|
|
6
|
+
* and configure them for automations.
|
|
7
|
+
*
|
|
8
|
+
* This binding includes:
|
|
9
|
+
* - TRIGGER_LIST: List available trigger definitions
|
|
10
|
+
* - TRIGGER_CONFIGURE: Configure a trigger with parameters
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
import { bindingClient, type ToolBinder } from "../core/binder";
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Trigger List Schemas
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Schema for a trigger parameter definition
|
|
22
|
+
*/
|
|
23
|
+
export const TriggerParamSchema = z.object({
|
|
24
|
+
type: z.literal("string"),
|
|
25
|
+
enum: z.array(z.string()).optional(),
|
|
26
|
+
description: z.string().optional(),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export type TriggerParam = z.infer<typeof TriggerParamSchema>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Schema for a trigger definition
|
|
33
|
+
*/
|
|
34
|
+
export const TriggerDefinitionSchema = z.object({
|
|
35
|
+
type: z.string(),
|
|
36
|
+
description: z.string(),
|
|
37
|
+
paramsSchema: z.record(z.string(), TriggerParamSchema),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export type TriggerDefinition = z.infer<typeof TriggerDefinitionSchema>;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* TRIGGER_LIST Input Schema
|
|
44
|
+
*/
|
|
45
|
+
export const TriggerListInputSchema = z.object({});
|
|
46
|
+
|
|
47
|
+
export type TriggerListInput = z.infer<typeof TriggerListInputSchema>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* TRIGGER_LIST Output Schema
|
|
51
|
+
*/
|
|
52
|
+
export const TriggerListOutputSchema = z.object({
|
|
53
|
+
triggers: z.array(TriggerDefinitionSchema),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export type TriggerListOutput = z.infer<typeof TriggerListOutputSchema>;
|
|
57
|
+
|
|
58
|
+
// ============================================================================
|
|
59
|
+
// Trigger Configure Schemas
|
|
60
|
+
// ============================================================================
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* TRIGGER_CONFIGURE Input Schema
|
|
64
|
+
*
|
|
65
|
+
* Input for configuring a trigger with parameters.
|
|
66
|
+
*/
|
|
67
|
+
export const TriggerConfigureInputSchema = z.object({
|
|
68
|
+
type: z.string(),
|
|
69
|
+
params: z.record(z.string(), z.string()),
|
|
70
|
+
enabled: z.boolean(),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
export type TriggerConfigureInput = z.infer<typeof TriggerConfigureInputSchema>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* TRIGGER_CONFIGURE Output Schema
|
|
77
|
+
*/
|
|
78
|
+
export const TriggerConfigureOutputSchema = z.object({
|
|
79
|
+
success: z.boolean(),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export type TriggerConfigureOutput = z.infer<
|
|
83
|
+
typeof TriggerConfigureOutputSchema
|
|
84
|
+
>;
|
|
85
|
+
|
|
86
|
+
// ============================================================================
|
|
87
|
+
// Trigger Binding
|
|
88
|
+
// ============================================================================
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Trigger Binding
|
|
92
|
+
*
|
|
93
|
+
* Defines the interface for connections that can emit triggers.
|
|
94
|
+
* Implementations must provide TRIGGER_LIST and TRIGGER_CONFIGURE tools.
|
|
95
|
+
*
|
|
96
|
+
* Required tools:
|
|
97
|
+
* - TRIGGER_LIST: List available trigger definitions with their parameter schemas
|
|
98
|
+
* - TRIGGER_CONFIGURE: Configure a trigger with specific parameters
|
|
99
|
+
*/
|
|
100
|
+
export const TRIGGER_BINDING = [
|
|
101
|
+
{
|
|
102
|
+
name: "TRIGGER_LIST" as const,
|
|
103
|
+
inputSchema: TriggerListInputSchema,
|
|
104
|
+
outputSchema: TriggerListOutputSchema,
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "TRIGGER_CONFIGURE" as const,
|
|
108
|
+
inputSchema: TriggerConfigureInputSchema,
|
|
109
|
+
outputSchema: TriggerConfigureOutputSchema,
|
|
110
|
+
},
|
|
111
|
+
] satisfies ToolBinder[];
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Trigger Binding Client
|
|
115
|
+
*
|
|
116
|
+
* Use this to create a client for interacting with triggers.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* import { TriggerBinding } from "@decocms/bindings/trigger";
|
|
121
|
+
*
|
|
122
|
+
* // For a connection
|
|
123
|
+
* const client = TriggerBinding.forConnection(connection);
|
|
124
|
+
*
|
|
125
|
+
* // List available triggers
|
|
126
|
+
* const { triggers } = await client.TRIGGER_LIST({});
|
|
127
|
+
*
|
|
128
|
+
* // Configure a trigger
|
|
129
|
+
* await client.TRIGGER_CONFIGURE({
|
|
130
|
+
* type: "cron",
|
|
131
|
+
* params: { schedule: "0 9 * * 1" },
|
|
132
|
+
* enabled: true,
|
|
133
|
+
* });
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export const TriggerBinding = bindingClient(TRIGGER_BINDING);
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Type helper for the Trigger binding client
|
|
140
|
+
*/
|
|
141
|
+
export type TriggerBindingClient = ReturnType<
|
|
142
|
+
typeof TriggerBinding.forConnection
|
|
143
|
+
>;
|
|
@@ -107,8 +107,8 @@ type JsonSchema = {
|
|
|
107
107
|
properties?: Record<string, unknown>;
|
|
108
108
|
required?: string[];
|
|
109
109
|
description?: string;
|
|
110
|
-
additionalProperties?: boolean
|
|
111
|
-
additionalItems?: boolean
|
|
110
|
+
additionalProperties?: boolean | Record<string, unknown>;
|
|
111
|
+
additionalItems?: boolean | Record<string, unknown>;
|
|
112
112
|
items?: JsonSchema;
|
|
113
113
|
};
|
|
114
114
|
const JsonSchemaSchema: z.ZodType<JsonSchema> = z.lazy(() =>
|
|
@@ -118,8 +118,12 @@ const JsonSchemaSchema: z.ZodType<JsonSchema> = z.lazy(() =>
|
|
|
118
118
|
properties: z.record(z.string(), z.unknown()).optional(),
|
|
119
119
|
required: z.array(z.string()).optional(),
|
|
120
120
|
description: z.string().optional(),
|
|
121
|
-
additionalProperties: z
|
|
122
|
-
|
|
121
|
+
additionalProperties: z
|
|
122
|
+
.union([z.boolean(), z.record(z.string(), z.unknown())])
|
|
123
|
+
.optional(),
|
|
124
|
+
additionalItems: z
|
|
125
|
+
.union([z.boolean(), z.record(z.string(), z.unknown())])
|
|
126
|
+
.optional(),
|
|
123
127
|
items: JsonSchemaSchema.optional(),
|
|
124
128
|
})
|
|
125
129
|
.passthrough(),
|
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reports Well-Known Binding
|
|
3
|
-
*
|
|
4
|
-
* Defines the interface for viewing automated reports.
|
|
5
|
-
* Any MCP that implements this binding can provide reports to the Reports plugin
|
|
6
|
-
* (e.g. performance audits, security scans, accessibility checks).
|
|
7
|
-
*
|
|
8
|
-
* This binding includes:
|
|
9
|
-
* - REPORTS_LIST: List all available reports with metadata
|
|
10
|
-
* - REPORTS_GET: Get a specific report with full content
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { z } from "zod";
|
|
14
|
-
import type { Binder, ToolBinder } from "../core/binder";
|
|
15
|
-
|
|
16
|
-
// ============================================================================
|
|
17
|
-
// Shared Schemas
|
|
18
|
-
// ============================================================================
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Report status indicates the overall health/outcome of the report.
|
|
22
|
-
*/
|
|
23
|
-
export const ReportStatusSchema = z.enum([
|
|
24
|
-
"passing",
|
|
25
|
-
"warning",
|
|
26
|
-
"failing",
|
|
27
|
-
"info",
|
|
28
|
-
]);
|
|
29
|
-
export type ReportStatus = z.infer<typeof ReportStatusSchema>;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* A single metric item within a metrics section.
|
|
33
|
-
*/
|
|
34
|
-
export const MetricItemSchema = z.object({
|
|
35
|
-
label: z.string().describe("Metric label (e.g. 'LCP', 'Performance')"),
|
|
36
|
-
value: z.union([z.number(), z.string()]).describe("Current metric value"),
|
|
37
|
-
unit: z
|
|
38
|
-
.string()
|
|
39
|
-
.optional()
|
|
40
|
-
.describe("Unit of measurement (e.g. 's', 'ms', 'score')"),
|
|
41
|
-
previousValue: z
|
|
42
|
-
.union([z.number(), z.string()])
|
|
43
|
-
.optional()
|
|
44
|
-
.describe("Previous value for delta comparison"),
|
|
45
|
-
status: ReportStatusSchema.optional().describe(
|
|
46
|
-
"Status of this individual metric",
|
|
47
|
-
),
|
|
48
|
-
});
|
|
49
|
-
export type MetricItem = z.infer<typeof MetricItemSchema>;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* A single criterion item within a criteria section.
|
|
53
|
-
*/
|
|
54
|
-
export const CriterionItemSchema = z.object({
|
|
55
|
-
label: z.string().describe("Short name of the criterion"),
|
|
56
|
-
description: z.string().optional().describe("Longer explanation"),
|
|
57
|
-
status: ReportStatusSchema.optional().describe(
|
|
58
|
-
"Status of this individual criterion (passing/warning/failing/info)",
|
|
59
|
-
),
|
|
60
|
-
});
|
|
61
|
-
export type CriterionItem = z.infer<typeof CriterionItemSchema>;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* A single row within a ranked-list section.
|
|
65
|
-
*/
|
|
66
|
-
export const RankedListRowSchema = z.object({
|
|
67
|
-
position: z.number().describe("Current rank position"),
|
|
68
|
-
reference_position: z
|
|
69
|
-
.number()
|
|
70
|
-
.optional()
|
|
71
|
-
.describe(
|
|
72
|
-
"Previous rank position before reordering. Used to compute delta automatically (delta = reference_position - position).",
|
|
73
|
-
),
|
|
74
|
-
delta: z
|
|
75
|
-
.number()
|
|
76
|
-
.optional()
|
|
77
|
-
.describe(
|
|
78
|
-
"Explicit change in position. Ignored when reference_position is provided.",
|
|
79
|
-
),
|
|
80
|
-
label: z.string().describe("Item name"),
|
|
81
|
-
image: z.string().describe("URL of the item image"),
|
|
82
|
-
values: z
|
|
83
|
-
.array(z.union([z.string(), z.number()]))
|
|
84
|
-
.describe("Values matching columns"),
|
|
85
|
-
note: z
|
|
86
|
-
.union([
|
|
87
|
-
z.string(),
|
|
88
|
-
z.record(z.string(), z.union([z.string(), z.number()])),
|
|
89
|
-
])
|
|
90
|
-
.optional()
|
|
91
|
-
.describe("Inline annotation or structured key-value metrics"),
|
|
92
|
-
});
|
|
93
|
-
export type RankedListRow = z.infer<typeof RankedListRowSchema>;
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Report sections -- polymorphic by type.
|
|
97
|
-
* Sections represent the main content blocks of a report.
|
|
98
|
-
*/
|
|
99
|
-
export const ReportSectionSchema = z.discriminatedUnion("type", [
|
|
100
|
-
z.object({
|
|
101
|
-
type: z.literal("markdown"),
|
|
102
|
-
content: z.string().describe("Markdown content"),
|
|
103
|
-
}),
|
|
104
|
-
z.object({
|
|
105
|
-
type: z.literal("metrics"),
|
|
106
|
-
title: z.string().optional().describe("Section title"),
|
|
107
|
-
items: z.array(MetricItemSchema).describe("Metric items"),
|
|
108
|
-
}),
|
|
109
|
-
z.object({
|
|
110
|
-
type: z.literal("table"),
|
|
111
|
-
title: z.string().optional().describe("Section title"),
|
|
112
|
-
columns: z.array(z.string()).describe("Column headers"),
|
|
113
|
-
rows: z
|
|
114
|
-
.array(z.array(z.union([z.string(), z.number(), z.null()])))
|
|
115
|
-
.describe("Table rows"),
|
|
116
|
-
}),
|
|
117
|
-
z.object({
|
|
118
|
-
type: z.literal("criteria"),
|
|
119
|
-
title: z.string().optional().describe("Section title"),
|
|
120
|
-
items: z.array(CriterionItemSchema).describe("List of criteria items"),
|
|
121
|
-
}),
|
|
122
|
-
z.object({
|
|
123
|
-
type: z.literal("note"),
|
|
124
|
-
content: z.string().describe("The note text"),
|
|
125
|
-
}),
|
|
126
|
-
z.object({
|
|
127
|
-
type: z.literal("ranked-list"),
|
|
128
|
-
title: z.string().optional().describe("Section title"),
|
|
129
|
-
rows: z.array(RankedListRowSchema).describe("Ranked items"),
|
|
130
|
-
}),
|
|
131
|
-
]);
|
|
132
|
-
export type ReportSection = z.infer<typeof ReportSectionSchema>;
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Lifecycle status of a report within the inbox workflow.
|
|
136
|
-
*/
|
|
137
|
-
export const ReportLifecycleStatusSchema = z.enum([
|
|
138
|
-
"unread",
|
|
139
|
-
"read",
|
|
140
|
-
"dismissed",
|
|
141
|
-
]);
|
|
142
|
-
export type ReportLifecycleStatus = z.infer<typeof ReportLifecycleStatusSchema>;
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Summary of a report returned by REPORTS_LIST.
|
|
146
|
-
*/
|
|
147
|
-
export const ReportSummarySchema = z.object({
|
|
148
|
-
id: z.string().describe("Unique report identifier"),
|
|
149
|
-
collectionId: z
|
|
150
|
-
.string()
|
|
151
|
-
.describe("Collection identifier used to scope reports"),
|
|
152
|
-
title: z.string().describe("Report title"),
|
|
153
|
-
category: z
|
|
154
|
-
.string()
|
|
155
|
-
.describe(
|
|
156
|
-
"Report category (e.g. 'performance', 'security', 'accessibility')",
|
|
157
|
-
),
|
|
158
|
-
status: ReportStatusSchema.describe("Overall report status"),
|
|
159
|
-
summary: z.string().describe("One-line summary of findings"),
|
|
160
|
-
updatedAt: z.string().describe("ISO 8601 timestamp of last update"),
|
|
161
|
-
source: z
|
|
162
|
-
.string()
|
|
163
|
-
.optional()
|
|
164
|
-
.describe(
|
|
165
|
-
"Agent or service that generated the report (e.g. 'security-auditor', 'performance-monitor')",
|
|
166
|
-
),
|
|
167
|
-
tags: z
|
|
168
|
-
.array(z.string())
|
|
169
|
-
.optional()
|
|
170
|
-
.describe("Free-form tags for filtering (e.g. 'homepage', 'api', 'ci')"),
|
|
171
|
-
lifecycleStatus: ReportLifecycleStatusSchema.optional().describe(
|
|
172
|
-
"Inbox lifecycle status of the report (default: unread)",
|
|
173
|
-
),
|
|
174
|
-
});
|
|
175
|
-
export type ReportSummary = z.infer<typeof ReportSummarySchema>;
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Full report returned by REPORTS_GET.
|
|
179
|
-
*/
|
|
180
|
-
export const ReportSchema = ReportSummarySchema.extend({
|
|
181
|
-
sections: z.array(ReportSectionSchema).describe("Ordered content sections"),
|
|
182
|
-
});
|
|
183
|
-
export type Report = z.infer<typeof ReportSchema>;
|
|
184
|
-
|
|
185
|
-
// ============================================================================
|
|
186
|
-
// UI Helpers
|
|
187
|
-
// ============================================================================
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Groups adjacent criteria+metrics sections into side-by-side pairs for display.
|
|
191
|
-
* In a pair, criteria always goes left and metrics always goes right,
|
|
192
|
-
* regardless of their original order.
|
|
193
|
-
*/
|
|
194
|
-
|
|
195
|
-
type SingleGroup = { type: "single"; section: ReportSection; idx: number };
|
|
196
|
-
type SideBySideGroup = {
|
|
197
|
-
type: "side-by-side";
|
|
198
|
-
left: Extract<ReportSection, { type: "criteria" }>;
|
|
199
|
-
right: Extract<ReportSection, { type: "metrics" }>;
|
|
200
|
-
leftIdx: number;
|
|
201
|
-
rightIdx: number;
|
|
202
|
-
};
|
|
203
|
-
export type SectionGroup = SingleGroup | SideBySideGroup;
|
|
204
|
-
|
|
205
|
-
export function groupSections(sections: ReportSection[]): SectionGroup[] {
|
|
206
|
-
const groups: SectionGroup[] = [];
|
|
207
|
-
let i = 0;
|
|
208
|
-
while (i < sections.length) {
|
|
209
|
-
const current = sections[i]!;
|
|
210
|
-
const next = sections[i + 1];
|
|
211
|
-
const isPair =
|
|
212
|
-
(current.type === "criteria" && next?.type === "metrics") ||
|
|
213
|
-
(current.type === "metrics" && next?.type === "criteria");
|
|
214
|
-
|
|
215
|
-
if (isPair) {
|
|
216
|
-
const isCriteriaFirst = current.type === "criteria";
|
|
217
|
-
const criteria = isCriteriaFirst ? current : next!;
|
|
218
|
-
const metrics = isCriteriaFirst ? next! : current;
|
|
219
|
-
const criteriaIdx = isCriteriaFirst ? i : i + 1;
|
|
220
|
-
const metricsIdx = isCriteriaFirst ? i + 1 : i;
|
|
221
|
-
groups.push({
|
|
222
|
-
type: "side-by-side",
|
|
223
|
-
left: criteria as Extract<ReportSection, { type: "criteria" }>,
|
|
224
|
-
right: metrics as Extract<ReportSection, { type: "metrics" }>,
|
|
225
|
-
leftIdx: criteriaIdx,
|
|
226
|
-
rightIdx: metricsIdx,
|
|
227
|
-
});
|
|
228
|
-
i += 2;
|
|
229
|
-
} else {
|
|
230
|
-
groups.push({ type: "single", section: current, idx: i });
|
|
231
|
-
i += 1;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
return groups;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// ============================================================================
|
|
238
|
-
// Tool Schemas
|
|
239
|
-
// ============================================================================
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* REPORTS_LIST - List all available reports with optional filters
|
|
243
|
-
*/
|
|
244
|
-
const ReportsListInputSchema = z.object({
|
|
245
|
-
category: z
|
|
246
|
-
.string()
|
|
247
|
-
.optional()
|
|
248
|
-
.describe("Filter by category (e.g. 'performance', 'security')"),
|
|
249
|
-
status: ReportStatusSchema.optional().describe("Filter by report status"),
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
const ReportsListOutputSchema = z.object({
|
|
253
|
-
reports: z.array(ReportSummarySchema).describe("List of report summaries"),
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
export type ReportsListInput = z.infer<typeof ReportsListInputSchema>;
|
|
257
|
-
export type ReportsListOutput = z.infer<typeof ReportsListOutputSchema>;
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* REPORTS_GET - Get a specific report with full content
|
|
261
|
-
*/
|
|
262
|
-
const ReportsGetInputSchema = z.object({
|
|
263
|
-
id: z.string().describe("Report identifier"),
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
const ReportsGetOutputSchema = ReportSchema;
|
|
267
|
-
|
|
268
|
-
export type ReportsGetInput = z.infer<typeof ReportsGetInputSchema>;
|
|
269
|
-
export type ReportsGetOutput = z.infer<typeof ReportsGetOutputSchema>;
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* REPORTS_UPDATE_STATUS - Update the lifecycle status of a report (optional tool)
|
|
273
|
-
*/
|
|
274
|
-
const ReportsUpdateStatusInputSchema = z.object({
|
|
275
|
-
reportId: z.string().describe("Report identifier"),
|
|
276
|
-
lifecycleStatus: ReportLifecycleStatusSchema.describe(
|
|
277
|
-
"New lifecycle status for the report",
|
|
278
|
-
),
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
const ReportsUpdateStatusOutputSchema = z.object({
|
|
282
|
-
success: z.boolean().describe("Whether the operation succeeded"),
|
|
283
|
-
message: z.string().optional().describe("Human-readable result message"),
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
export type ReportsUpdateStatusInput = z.infer<
|
|
287
|
-
typeof ReportsUpdateStatusInputSchema
|
|
288
|
-
>;
|
|
289
|
-
export type ReportsUpdateStatusOutput = z.infer<
|
|
290
|
-
typeof ReportsUpdateStatusOutputSchema
|
|
291
|
-
>;
|
|
292
|
-
|
|
293
|
-
// ============================================================================
|
|
294
|
-
// Binding Definition
|
|
295
|
-
// ============================================================================
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Reports Binding
|
|
299
|
-
*
|
|
300
|
-
* Defines the interface for viewing automated reports.
|
|
301
|
-
* Any MCP that implements this binding can be used with the Reports plugin.
|
|
302
|
-
*
|
|
303
|
-
* Required tools:
|
|
304
|
-
* - REPORTS_LIST: List available reports with optional filtering
|
|
305
|
-
* - REPORTS_GET: Get a single report with full content
|
|
306
|
-
*
|
|
307
|
-
* Optional tools:
|
|
308
|
-
* - REPORTS_UPDATE_STATUS: Update the lifecycle status of a report (unread → read → dismissed)
|
|
309
|
-
*/
|
|
310
|
-
export const REPORTS_BINDING = [
|
|
311
|
-
{
|
|
312
|
-
name: "REPORTS_LIST" as const,
|
|
313
|
-
inputSchema: ReportsListInputSchema,
|
|
314
|
-
outputSchema: ReportsListOutputSchema,
|
|
315
|
-
} satisfies ToolBinder<"REPORTS_LIST", ReportsListInput, ReportsListOutput>,
|
|
316
|
-
{
|
|
317
|
-
name: "REPORTS_GET" as const,
|
|
318
|
-
inputSchema: ReportsGetInputSchema,
|
|
319
|
-
outputSchema: ReportsGetOutputSchema,
|
|
320
|
-
} satisfies ToolBinder<"REPORTS_GET", ReportsGetInput, ReportsGetOutput>,
|
|
321
|
-
{
|
|
322
|
-
name: "REPORTS_UPDATE_STATUS" as const,
|
|
323
|
-
inputSchema: ReportsUpdateStatusInputSchema,
|
|
324
|
-
outputSchema: ReportsUpdateStatusOutputSchema,
|
|
325
|
-
opt: true,
|
|
326
|
-
} satisfies ToolBinder<
|
|
327
|
-
"REPORTS_UPDATE_STATUS",
|
|
328
|
-
ReportsUpdateStatusInput,
|
|
329
|
-
ReportsUpdateStatusOutput
|
|
330
|
-
>,
|
|
331
|
-
] as const satisfies Binder;
|
|
332
|
-
|
|
333
|
-
export type ReportsBinding = typeof REPORTS_BINDING;
|