@openhands/extensions 0.11.0 → 0.13.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.
Files changed (49) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/AGENTS.md +2 -1
  3. package/MIGRATION.md +31 -0
  4. package/README.md +9 -7
  5. package/automations/README.md +300 -8
  6. package/automations/catalog/github-pr-reviewer/manifest.json +83 -0
  7. package/automations/catalog/github-repo-monitor/manifest.json +83 -0
  8. package/automations/catalog/incident-retrospective-drafter/manifest.json +100 -0
  9. package/automations/catalog/{jira-issue-to-pr.json → jira-issue-to-pr/manifest.json} +10 -5
  10. package/automations/catalog/{linear-triage-assistant.json → linear-triage-assistant/manifest.json} +8 -4
  11. package/automations/catalog/{research-brief-writer.json → research-brief-writer/manifest.json} +11 -5
  12. package/automations/catalog/{slack-channel-monitor.json → slack-channel-monitor/manifest.json} +7 -2
  13. package/automations/catalog/{slack-standup-digest.json → slack-standup-digest/manifest.json} +8 -5
  14. package/automations/catalog-index.js +23 -0
  15. package/automations/catalog.schema.json +272 -0
  16. package/automations/index.d.ts +232 -3
  17. package/automations/index.js +28 -18
  18. package/automations/interface.json +70 -0
  19. package/automations/interface.schema.json +243 -0
  20. package/index.d.ts +29 -2
  21. package/index.js +1 -1
  22. package/integrations/catalog/datadog.json +3 -3
  23. package/integrations/index.d.ts +1 -1
  24. package/package.json +8 -3
  25. package/pyproject.toml +1 -1
  26. package/python/openhands_extensions/__init__.py +0 -4
  27. package/python/openhands_extensions/_version.py +3 -2
  28. package/python/openhands_extensions/integrations.py +8 -30
  29. package/scripts/build-automation-catalog.mjs +51 -0
  30. package/skills/bitbucket/SKILL.md +0 -1
  31. package/skills/github/SKILL.md +0 -1
  32. package/skills/gitlab/SKILL.md +0 -1
  33. package/skills/index.js +5 -8
  34. package/skills/openhands-automation/SKILL.md +11 -0
  35. package/skills/openhands-automation/references/custom-automation.md +2 -0
  36. package/skills/openhands-automation/references/security.md +84 -0
  37. package/skills/openhands-sdk/SKILL.md +2 -0
  38. package/tests/fixtures/automations/capabilities.json +92 -0
  39. package/tests/fixtures/automations/github-pr-reviewer.json +251 -0
  40. package/tests/fixtures/automations/github-repo-monitor.json +180 -0
  41. package/tests/fixtures/automations/incident-retrospective-drafter.json +91 -0
  42. package/tests/test_automation_setup.py +526 -0
  43. package/tests/test_catalogs.py +37 -12
  44. package/tests/test_deprecations.py +39 -4
  45. package/tests/test_integration_catalog_in_sync.py +50 -60
  46. package/tests/test_interface_manifest.py +107 -0
  47. package/automations/catalog/github-pr-reviewer.json +0 -13
  48. package/automations/catalog/github-repo-monitor.json +0 -11
  49. package/automations/catalog/incident-retrospective-drafter.json +0 -15
@@ -3,12 +3,241 @@ export interface RecommendedAutomation {
3
3
  name: string;
4
4
  category: string;
5
5
  description: string;
6
- prompt: string;
7
- exampleImplementation: string;
8
- requiredIntegrationIds: string[];
6
+ requires: AutomationPrerequisites;
9
7
  popularityRank: number;
10
8
  estimatedSetupMinutes: number;
9
+ /**
10
+ * The `skills/` directory that builds this automation today. Defaults to
11
+ * `id`; present only where the two differ. Look the launch command up from
12
+ * that skill's entry in `SKILLS_CATALOG` rather than storing it here.
13
+ */
14
+ skill?: string;
15
+ exampleImplementation: string;
16
+ /** Present when this automation ships an extension-owned setup experience. */
17
+ setup?: AutomationSetup;
18
+ }
19
+
20
+ /**
21
+ * The extension-owned configuration experience for one automation.
22
+ *
23
+ * Mirrors the `setup` block in `automations/catalog.schema.json`, which is
24
+ * authoritative. It describes how an automation is *configured*; it never
25
+ * describes what the automation does at runtime.
26
+ *
27
+ * It states only what varies between automations, and states each of those
28
+ * things once. Everything else is the same for every automation and is the
29
+ * host's to generate: the slash command (`/<id>:setup`), the setup route
30
+ * (`/automations/new/<id>`), the capabilities check, the preflight call, the
31
+ * mapping from a rejected payload path back to the input at fault, the review
32
+ * screen, the navigation after a success, and the analytics stages.
33
+ */
34
+
35
+ export type AutomationSetupMode = "direct" | "assisted";
36
+ export type AutomationFieldType =
37
+ | "text"
38
+ | "textarea"
39
+ | "select"
40
+ | "cron"
41
+ | "timezone"
42
+ | "repo-picker";
43
+ export type AutomationGitProvider = "github" | "gitlab" | "bitbucket";
44
+ export type AutomationTriggerKind = "cron" | "event";
45
+
46
+ export interface AutomationFieldOption {
47
+ value: string;
48
+ label: string;
49
+ }
50
+
51
+ export interface AutomationFieldConstraints {
52
+ minLength?: number;
53
+ maxLength?: number;
54
+ /** Host-implemented check, named from a closed set. Entries supply no regex. */
55
+ format?: "safeExpressionLiteral";
56
+ }
57
+
58
+ export interface AutomationFormField {
59
+ type: AutomationFieldType;
60
+ label: string;
61
+ help: string;
62
+ placeholder?: string;
63
+ default?: string;
64
+ required: boolean;
65
+ provider?: AutomationGitProvider;
66
+ options?: AutomationFieldOption[];
67
+ constraints?: AutomationFieldConstraints;
68
+ }
69
+
70
+ /** Keyed by field name, which is what `{{form.<name>}}` resolves against. */
71
+ export type AutomationFormFields = Record<string, AutomationFormField>;
72
+
73
+ export interface AutomationIntegrationRequirement {
74
+ /** Why this automation needs it. Omitted when there is no setup flow to show it in. */
75
+ message?: string;
76
+ /** Defaults to true. `false` lets setup continue while it is unconnected. */
77
+ required?: false;
78
+ }
79
+
80
+ export interface AutomationPrerequisites {
81
+ /** Keyed by integration catalog id. */
82
+ integrations: Record<string, AutomationIntegrationRequirement>;
83
+ /** Deployment capabilities this automation cannot run without. */
84
+ features?: string[];
11
85
  }
12
86
 
87
+ /** The inputs that decide when the automation runs, keyed by trigger kind. */
88
+ export type AutomationTriggerForm = Partial<
89
+ Record<AutomationTriggerKind, AutomationFormFields>
90
+ >;
91
+
92
+ export interface AutomationForm {
93
+ note?: string;
94
+ triggers?: AutomationTriggerForm;
95
+ /** Every other input: the arguments to the automation itself. */
96
+ args: AutomationFormFields;
97
+ }
98
+
99
+ export interface AutomationSetup {
100
+ version: "1.0";
101
+ mode: AutomationSetupMode;
102
+ form: AutomationForm;
103
+ /** direct only. What the automation is told to do. */
104
+ prompt?: string;
105
+ /** direct only, event trigger only. Which delivered events belong to it. */
106
+ filter?: string;
107
+ /**
108
+ * Setup context for the conversation that finishes setup. Required for
109
+ * assisted mode. Optional for direct mode, where it seeds the fallback
110
+ * conversation offered when the deployment cannot run the direct path.
111
+ */
112
+ message?: string;
113
+ }
114
+
115
+ /**
116
+ * The production Automation interface manifest.
117
+ *
118
+ * Mirrors `automations/interface.schema.json`, which is authoritative. The
119
+ * catalog states what varies per automation; this states the domain-level
120
+ * facts of the interface itself: routes, navigation, page-identity copy, the
121
+ * settable attributes of an automation, the import/export envelope, the
122
+ * service-relative endpoints, and the featured and responder id lists. The
123
+ * host validates it at admission and falls back to its built-in defaults when
124
+ * it is absent or rejected.
125
+ */
126
+
127
+ export interface AutomationInterfaceRoutes {
128
+ list: string;
129
+ /** Carries the `:automationId` segment the host substitutes. */
130
+ setup: string;
131
+ /** Carries the `:automationId` segment the host substitutes. */
132
+ detail: string;
133
+ }
134
+
135
+ export interface AutomationInterfaceNavigation {
136
+ sidebar: { label: string };
137
+ commandMenu: { title: string; description: string; keywords: string };
138
+ }
139
+
140
+ export interface AutomationInterfacePages {
141
+ list: { title: string; subtitle: string };
142
+ detail: { backLabel: string };
143
+ edit: { title: string };
144
+ }
145
+
146
+ export type AutomationAttributeType =
147
+ | "text"
148
+ | "textarea"
149
+ | "number"
150
+ | "llm-profile"
151
+ | "schedule";
152
+
153
+ /** The closed set of runtime-model properties a client may offer for setting. */
154
+ export type AutomationAttributeName =
155
+ | "name"
156
+ | "prompt"
157
+ | "model"
158
+ | "timeout"
159
+ | "schedule";
160
+
161
+ export interface AutomationAttributeConstraints {
162
+ min?: number;
163
+ max?: number;
164
+ }
165
+
166
+ /** How one settable attribute of an existing Automation is offered. */
167
+ export interface AutomationAttribute {
168
+ type: AutomationAttributeType;
169
+ label: string;
170
+ help?: string;
171
+ required: boolean;
172
+ /** Only a `number` attribute carries constraints. */
173
+ constraints?: AutomationAttributeConstraints;
174
+ }
175
+
176
+ /**
177
+ * The input surface of an existing Automation, keyed by the runtime-model
178
+ * property the host sends. How a client offers these - Agent Canvas renders
179
+ * an edit dialog - is the client's choice, not stated here.
180
+ */
181
+ export type AutomationInterfaceAttributes = Partial<
182
+ Record<AutomationAttributeName, AutomationAttribute>
183
+ >;
184
+
185
+ export interface AutomationImportDefaults {
186
+ /** Provider inferred for short owner/repo repository URLs on import. */
187
+ repoProvider: AutomationGitProvider;
188
+ /** Event source of the placeholder trigger that keeps an import inert. */
189
+ placeholderEventSource: string;
190
+ }
191
+
192
+ export interface AutomationInterfaceImportExport {
193
+ fileKind: string;
194
+ fileVersion: 1;
195
+ filenameSuffix: string;
196
+ importDefaults: AutomationImportDefaults;
197
+ }
198
+
199
+ /**
200
+ * Service-relative paths the host calls. Relative paths only: the base path,
201
+ * methods, headers, and auth remain the host's. `{id}` marks where the host
202
+ * substitutes the automation id.
203
+ */
204
+ export interface AutomationInterfaceEndpoints {
205
+ list: string;
206
+ detail: string;
207
+ dispatch: string;
208
+ runs: string;
209
+ tarball: string;
210
+ health: string;
211
+ capabilities: string;
212
+ validate: string;
213
+ createPrompt: string;
214
+ createPlugin: string;
215
+ }
216
+
217
+ export interface AutomationInterfaceManifest {
218
+ version: "1.0";
219
+ routes: AutomationInterfaceRoutes;
220
+ navigation: AutomationInterfaceNavigation;
221
+ pages: AutomationInterfacePages;
222
+ docsUrl: string;
223
+ attributes: AutomationInterfaceAttributes;
224
+ importExport: AutomationInterfaceImportExport;
225
+ endpoints: AutomationInterfaceEndpoints;
226
+ featuredAutomationIds: string[];
227
+ responderIntegrationIds: string[];
228
+ }
229
+
230
+ export const AUTOMATION_INTERFACE: AutomationInterfaceManifest;
231
+
13
232
  export const AUTOMATION_CATALOG: RecommendedAutomation[];
233
+ /**
234
+ * Return the full automation catalog.
235
+ * Reads the generated static import index over `automations/catalog/<id>/manifest.json`.
236
+ * Returns an independent copy.
237
+ */
238
+ export function listAutomationCatalog(): RecommendedAutomation[];
239
+ /** Return one automation catalog entry by id as an independent copy. */
240
+ export function getAutomationCatalogEntry(
241
+ id: string,
242
+ ): RecommendedAutomation | undefined;
14
243
  export default AUTOMATION_CATALOG;
@@ -1,20 +1,30 @@
1
- import github_pr_reviewer from "./catalog/github-pr-reviewer.json" with { type: "json" };
2
- import github_repo_monitor from "./catalog/github-repo-monitor.json" with { type: "json" };
3
- import slack_standup_digest from "./catalog/slack-standup-digest.json" with { type: "json" };
4
- import slack_channel_monitor from "./catalog/slack-channel-monitor.json" with { type: "json" };
5
- import linear_triage_assistant from "./catalog/linear-triage-assistant.json" with { type: "json" };
6
- import research_brief_writer from "./catalog/research-brief-writer.json" with { type: "json" };
7
- import incident_retrospective_drafter from "./catalog/incident-retrospective-drafter.json" with { type: "json" };
8
- import jira_issue_to_pr from "./catalog/jira-issue-to-pr.json" with { type: "json" };
1
+ /**
2
+ * Runtime automation catalog.
3
+ *
4
+ * The source of truth is the hand-authored `automations/catalog/<id>/manifest.json`
5
+ * directory. `catalog-index.js` is generated from that directory so the JS
6
+ * package can statically import each JSON file without an aggregate JSON asset.
7
+ */
8
+ import { AUTOMATION_CATALOG_ENTRIES } from "./catalog-index.js";
9
+ import interfaceManifest from "./interface.json" with { type: "json" };
10
+
11
+ const clone = (value) => JSON.parse(JSON.stringify(value));
12
+ const AUTOMATIONS = AUTOMATION_CATALOG_ENTRIES;
13
+ const AUTOMATION_BY_ID = new Map(AUTOMATIONS.map((entry) => [entry.id, entry]));
14
+
15
+ export const listAutomationCatalog = () => clone(AUTOMATIONS);
16
+
17
+ export const getAutomationCatalogEntry = (id) => {
18
+ const entry = AUTOMATION_BY_ID.get(id);
19
+ return entry ? clone(entry) : undefined;
20
+ };
21
+
22
+ export const AUTOMATION_CATALOG = clone(AUTOMATIONS);
23
+
24
+ /**
25
+ * The production Automation interface manifest: the domain-level facts of the
26
+ * interface, hand-authored in `automations/interface.json`.
27
+ */
28
+ export const AUTOMATION_INTERFACE = clone(interfaceManifest);
9
29
 
10
- export const AUTOMATION_CATALOG = [
11
- github_pr_reviewer,
12
- github_repo_monitor,
13
- slack_standup_digest,
14
- slack_channel_monitor,
15
- linear_triage_assistant,
16
- research_brief_writer,
17
- incident_retrospective_drafter,
18
- jira_issue_to_pr,
19
- ];
20
30
  export default AUTOMATION_CATALOG;
@@ -0,0 +1,70 @@
1
+ {
2
+ "version": "1.0",
3
+ "routes": {
4
+ "list": "/automations",
5
+ "setup": "/automations/new/:automationId",
6
+ "detail": "/automations/:automationId"
7
+ },
8
+ "navigation": {
9
+ "sidebar": { "label": "Automate" },
10
+ "commandMenu": {
11
+ "title": "Automations",
12
+ "description": "Review scheduled and webhook automations.",
13
+ "keywords": "automate cron schedule webhook jobs"
14
+ }
15
+ },
16
+ "pages": {
17
+ "list": {
18
+ "title": "Automations",
19
+ "subtitle": "View active and inactive automations, search by metadata, and inspect read-only details."
20
+ },
21
+ "detail": { "backLabel": "Back to Automations" },
22
+ "edit": { "title": "Edit automation" }
23
+ },
24
+ "docsUrl": "https://docs.openhands.dev/openhands/usage/automations/overview",
25
+ "attributes": {
26
+ "name": { "type": "text", "label": "Name", "required": true },
27
+ "prompt": {
28
+ "type": "textarea",
29
+ "label": "Prompt",
30
+ "help": "Edits apply to future runs only.",
31
+ "required": false
32
+ },
33
+ "model": { "type": "llm-profile", "label": "LLM profile", "required": false },
34
+ "timeout": {
35
+ "type": "number",
36
+ "label": "Timeout (seconds)",
37
+ "help": "Maximum time a single run may take. Leave empty for the default of 600 seconds (10 minutes); maximum 1800 seconds (30 minutes).",
38
+ "required": false,
39
+ "constraints": { "min": 1, "max": 1800 }
40
+ },
41
+ "schedule": { "type": "schedule", "label": "Frequency", "required": false }
42
+ },
43
+ "importExport": {
44
+ "fileKind": "automation",
45
+ "fileVersion": 1,
46
+ "filenameSuffix": ".automation.json",
47
+ "importDefaults": {
48
+ "repoProvider": "github",
49
+ "placeholderEventSource": "agent-canvas-import"
50
+ }
51
+ },
52
+ "endpoints": {
53
+ "list": "/v1",
54
+ "detail": "/v1/{id}",
55
+ "dispatch": "/v1/{id}/dispatch",
56
+ "runs": "/v1/{id}/runs",
57
+ "tarball": "/v1/{id}/tarball",
58
+ "health": "/health",
59
+ "capabilities": "/v1/capabilities",
60
+ "validate": "/v1/validate",
61
+ "createPrompt": "/v1/preset/prompt",
62
+ "createPlugin": "/v1/preset/plugin"
63
+ },
64
+ "featuredAutomationIds": [
65
+ "github-pr-reviewer",
66
+ "github-repo-monitor",
67
+ "slack-channel-monitor"
68
+ ],
69
+ "responderIntegrationIds": ["github", "slack"]
70
+ }
@@ -0,0 +1,243 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/OpenHands/extensions/automations/interface.schema.json",
4
+ "title": "AutomationInterfaceManifest",
5
+ "description": "Strict schema for automations/interface.json. Mirrors the AutomationInterfaceManifest types in automations/index.d.ts. The catalog states what varies per automation; this file states the domain-level facts of the production Automation interface - routes, navigation, page-identity copy, the settable attributes of an automation, the import/export envelope, the service-relative endpoints, and the featured and responder id lists. The host renders it; it is data, not code - no markup in copy, no free-form URL, no host name, method, or credential.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "version",
10
+ "routes",
11
+ "navigation",
12
+ "pages",
13
+ "docsUrl",
14
+ "attributes",
15
+ "importExport",
16
+ "endpoints",
17
+ "featuredAutomationIds",
18
+ "responderIntegrationIds"
19
+ ],
20
+ "properties": {
21
+ "version": {
22
+ "const": "1.0",
23
+ "description": "Selects how this manifest is interpreted. A future format ships a new constant."
24
+ },
25
+ "routes": {
26
+ "description": "The routes of the Automation interface. The host must have a registration serving each declared shape, so admission verifies they match what it mounted; the manifest is the single source for link construction.",
27
+ "type": "object",
28
+ "additionalProperties": false,
29
+ "required": ["list", "setup", "detail"],
30
+ "properties": {
31
+ "list": { "$ref": "#/$defs/routePath" },
32
+ "setup": { "$ref": "#/$defs/parameterizedRoutePath" },
33
+ "detail": { "$ref": "#/$defs/parameterizedRoutePath" }
34
+ }
35
+ },
36
+ "navigation": {
37
+ "type": "object",
38
+ "additionalProperties": false,
39
+ "required": ["sidebar", "commandMenu"],
40
+ "properties": {
41
+ "sidebar": {
42
+ "type": "object",
43
+ "additionalProperties": false,
44
+ "required": ["label"],
45
+ "properties": { "label": { "$ref": "#/$defs/copy" } }
46
+ },
47
+ "commandMenu": {
48
+ "type": "object",
49
+ "additionalProperties": false,
50
+ "required": ["title", "description", "keywords"],
51
+ "properties": {
52
+ "title": { "$ref": "#/$defs/copy" },
53
+ "description": { "$ref": "#/$defs/copy" },
54
+ "keywords": { "$ref": "#/$defs/copy" }
55
+ }
56
+ }
57
+ }
58
+ },
59
+ "pages": {
60
+ "description": "Page-identity copy. Generic chrome - buttons, toasts, empty states, validation sentences - stays host copy, rendered through the host's translations.",
61
+ "type": "object",
62
+ "additionalProperties": false,
63
+ "required": ["list", "detail", "edit"],
64
+ "properties": {
65
+ "list": {
66
+ "type": "object",
67
+ "additionalProperties": false,
68
+ "required": ["title", "subtitle"],
69
+ "properties": {
70
+ "title": { "$ref": "#/$defs/copy" },
71
+ "subtitle": { "$ref": "#/$defs/copy" }
72
+ }
73
+ },
74
+ "detail": {
75
+ "type": "object",
76
+ "additionalProperties": false,
77
+ "required": ["backLabel"],
78
+ "properties": { "backLabel": { "$ref": "#/$defs/copy" } }
79
+ },
80
+ "edit": {
81
+ "type": "object",
82
+ "additionalProperties": false,
83
+ "required": ["title"],
84
+ "properties": { "title": { "$ref": "#/$defs/copy" } }
85
+ }
86
+ }
87
+ },
88
+ "docsUrl": {
89
+ "description": "The automations documentation link. Prefix-pinned so this cannot become an arbitrary link.",
90
+ "type": "string",
91
+ "pattern": "^https://docs\\.openhands\\.dev/[A-Za-z0-9/._-]*$"
92
+ },
93
+ "attributes": {
94
+ "description": "The input surface of an existing Automation: which attributes can be set after creation, keyed by the runtime-model property the host sends. The closed key set is the settable surface of the runtime model; how a client offers them - Agent Canvas renders an edit dialog, an agent sends them over the API - is the client's choice, not stated here. schedule is a semantic type whose frequency/weekday/time composite the host owns, like the setup form's cron type.",
95
+ "type": "object",
96
+ "additionalProperties": false,
97
+ "minProperties": 1,
98
+ "properties": {
99
+ "name": { "$ref": "#/$defs/attribute" },
100
+ "prompt": { "$ref": "#/$defs/attribute" },
101
+ "model": { "$ref": "#/$defs/attribute" },
102
+ "timeout": { "$ref": "#/$defs/attribute" },
103
+ "schedule": { "$ref": "#/$defs/attribute" }
104
+ }
105
+ },
106
+ "importExport": {
107
+ "description": "The export file envelope, and the two facts an import cannot derive from the file: the provider inferred for short repository URLs and the placeholder event source that keeps a half-imported automation inert until its real trigger is applied.",
108
+ "type": "object",
109
+ "additionalProperties": false,
110
+ "required": ["fileKind", "fileVersion", "filenameSuffix", "importDefaults"],
111
+ "properties": {
112
+ "fileKind": { "type": "string", "pattern": "^[a-z][a-z-]*$" },
113
+ "fileVersion": { "const": 1 },
114
+ "filenameSuffix": { "type": "string", "pattern": "^\\.[a-z][a-z.]*json$" },
115
+ "importDefaults": {
116
+ "type": "object",
117
+ "additionalProperties": false,
118
+ "required": ["repoProvider", "placeholderEventSource"],
119
+ "properties": {
120
+ "repoProvider": { "enum": ["github", "gitlab", "bitbucket"] },
121
+ "placeholderEventSource": {
122
+ "type": "string",
123
+ "pattern": "^[a-z0-9][a-z0-9.-]*$"
124
+ }
125
+ }
126
+ }
127
+ }
128
+ },
129
+ "endpoints": {
130
+ "description": "Service-relative paths the host calls. Relative paths only: the base path, methods, headers, and auth remain the host's, so this cannot express a request to anywhere the host did not choose. {id} marks where the host substitutes the automation id.",
131
+ "type": "object",
132
+ "additionalProperties": false,
133
+ "required": [
134
+ "list",
135
+ "detail",
136
+ "dispatch",
137
+ "runs",
138
+ "tarball",
139
+ "health",
140
+ "capabilities",
141
+ "validate",
142
+ "createPrompt",
143
+ "createPlugin"
144
+ ],
145
+ "properties": {
146
+ "list": { "$ref": "#/$defs/plainEndpoint" },
147
+ "detail": { "$ref": "#/$defs/idEndpoint" },
148
+ "dispatch": { "$ref": "#/$defs/idEndpoint" },
149
+ "runs": { "$ref": "#/$defs/idEndpoint" },
150
+ "tarball": { "$ref": "#/$defs/idEndpoint" },
151
+ "health": { "$ref": "#/$defs/plainEndpoint" },
152
+ "capabilities": { "$ref": "#/$defs/plainEndpoint" },
153
+ "validate": { "$ref": "#/$defs/plainEndpoint" },
154
+ "createPrompt": { "$ref": "#/$defs/plainEndpoint" },
155
+ "createPlugin": { "$ref": "#/$defs/plainEndpoint" }
156
+ }
157
+ },
158
+ "featuredAutomationIds": {
159
+ "description": "Catalog entries the list page surfaces as proven. Each id must resolve to an automations/catalog entry; the host's admission checks that, mirroring how requires.integrations ids are checked by the catalog tests.",
160
+ "$ref": "#/$defs/slugList"
161
+ },
162
+ "responderIntegrationIds": {
163
+ "description": "Integrations whose automations are treated as continuously-polling responders and get the deployment-choice dialog.",
164
+ "$ref": "#/$defs/slugList"
165
+ }
166
+ },
167
+ "$defs": {
168
+ "copy": {
169
+ "description": "Literal user-visible copy. Carries no markup, because this manifest must never inject HTML into the host.",
170
+ "type": "string",
171
+ "minLength": 1,
172
+ "not": { "pattern": "<[A-Za-z/!]" }
173
+ },
174
+ "routePath": {
175
+ "type": "string",
176
+ "pattern": "^/[A-Za-z0-9/:_-]*$",
177
+ "not": { "pattern": "//" }
178
+ },
179
+ "parameterizedRoutePath": {
180
+ "description": "A route path carrying the :automationId segment the host substitutes.",
181
+ "allOf": [
182
+ { "$ref": "#/$defs/routePath" },
183
+ { "pattern": ":automationId" }
184
+ ]
185
+ },
186
+ "endpointPath": {
187
+ "type": "string",
188
+ "pattern": "^/[A-Za-z0-9/{}_-]*$",
189
+ "not": { "pattern": "//" }
190
+ },
191
+ "plainEndpoint": {
192
+ "allOf": [
193
+ { "$ref": "#/$defs/endpointPath" },
194
+ { "not": { "pattern": "[{}]" } }
195
+ ]
196
+ },
197
+ "idEndpoint": {
198
+ "description": "An endpoint path with exactly one {id} substitution and no other braces.",
199
+ "allOf": [
200
+ { "$ref": "#/$defs/endpointPath" },
201
+ { "pattern": "^[^{}]*\\{id\\}[^{}]*$" }
202
+ ]
203
+ },
204
+ "attribute": {
205
+ "description": "How one settable attribute is offered: a semantic input type, user-visible copy, and value constraints. Only a number attribute carries constraints.",
206
+ "type": "object",
207
+ "additionalProperties": false,
208
+ "required": ["type", "label", "required"],
209
+ "properties": {
210
+ "type": {
211
+ "enum": ["text", "textarea", "number", "llm-profile", "schedule"]
212
+ },
213
+ "label": { "$ref": "#/$defs/copy" },
214
+ "help": { "$ref": "#/$defs/copy" },
215
+ "required": { "type": "boolean" },
216
+ "constraints": {
217
+ "type": "object",
218
+ "additionalProperties": false,
219
+ "minProperties": 1,
220
+ "properties": {
221
+ "min": { "type": "integer", "minimum": 0 },
222
+ "max": { "type": "integer", "minimum": 1 }
223
+ }
224
+ }
225
+ },
226
+ "allOf": [
227
+ {
228
+ "if": {
229
+ "properties": { "type": { "not": { "const": "number" } } },
230
+ "required": ["type"]
231
+ },
232
+ "then": { "not": { "required": ["constraints"] } }
233
+ }
234
+ ]
235
+ },
236
+ "slugList": {
237
+ "type": "array",
238
+ "minItems": 1,
239
+ "uniqueItems": true,
240
+ "items": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" }
241
+ }
242
+ }
243
+ }
package/index.d.ts CHANGED
@@ -13,7 +13,34 @@ export {
13
13
  type OAuthProviderCatalogOption,
14
14
  type OAuthProviderRegistrationDefaults,
15
15
  } from "./integrations/index.js";
16
- export { AUTOMATION_CATALOG } from "./automations/index.js";
17
- export type { RecommendedAutomation } from "./automations/index.js";
16
+ export { AUTOMATION_CATALOG, AUTOMATION_INTERFACE } from "./automations/index.js";
17
+ export type {
18
+ AutomationFieldConstraints,
19
+ AutomationFieldOption,
20
+ AutomationFieldType,
21
+ AutomationForm,
22
+ AutomationFormField,
23
+ AutomationFormFields,
24
+ AutomationGitProvider,
25
+ AutomationIntegrationRequirement,
26
+ AutomationPrerequisites,
27
+ AutomationSetup,
28
+ AutomationSetupMode,
29
+ AutomationTriggerForm,
30
+ AutomationTriggerKind,
31
+ RecommendedAutomation,
32
+ AutomationAttribute,
33
+ AutomationAttributeConstraints,
34
+ AutomationAttributeName,
35
+ AutomationAttributeType,
36
+ AutomationImportDefaults,
37
+ AutomationInterfaceAttributes,
38
+ AutomationInterfaceEndpoints,
39
+ AutomationInterfaceImportExport,
40
+ AutomationInterfaceManifest,
41
+ AutomationInterfaceNavigation,
42
+ AutomationInterfacePages,
43
+ AutomationInterfaceRoutes,
44
+ } from "./automations/index.js";
18
45
  export { SKILLS_CATALOG } from "./skills/index.js";
19
46
  export type { SkillCatalogEntry } from "./skills/index.js";
package/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { INTEGRATION_CATALOG } from "./integrations/index.js";
2
- export { AUTOMATION_CATALOG } from "./automations/index.js";
2
+ export { AUTOMATION_CATALOG, AUTOMATION_INTERFACE } from "./automations/index.js";
3
3
  export { SKILLS_CATALOG } from "./skills/index.js";
@@ -7,7 +7,7 @@
7
7
  "Operations"
8
8
  ],
9
9
  "appUrl": "https://www.datadoghq.com",
10
- "docsUrl": "https://docs.datadoghq.com/bits_ai/mcp_server/setup/",
10
+ "docsUrl": "https://docs.datadoghq.com/mcp_server/setup/",
11
11
  "notes": "Uses Datadog's official hosted MCP server. The MCP endpoint host is site-specific: use https://mcp.<site>.datadoghq.com/v1/mcp for your Datadog site (e.g. mcp.us5.datadoghq.com for US5). The default URL below targets US1 and can be edited in the install dialog.",
12
12
  "popularityRank": 35,
13
13
  "installHint": "The Datadog MCP URL is site-specific. Edit the URL to https://mcp.<site>.datadoghq.com/v1/mcp for your Datadog site (for example https://mcp.us5.datadoghq.com/v1/mcp for US5, https://mcp.eu.datadoghq.com/v1/mcp for EU). Find your site at Organization Settings → Site in Datadog.",
@@ -43,7 +43,7 @@
43
43
  "urlEditable": true,
44
44
  "headerFields": [
45
45
  {
46
- "key": "DD-API-KEY",
46
+ "key": "DD_API_KEY",
47
47
  "label": "Datadog API key",
48
48
  "type": "password",
49
49
  "required": true,
@@ -51,7 +51,7 @@
51
51
  "helperText": "Created in Datadog under Organization Settings → API Keys. Used to authenticate to the Datadog MCP server. See the [setup docs](https://docs.datadoghq.com/mcp_server/setup/?tab=other#authentication)."
52
52
  },
53
53
  {
54
- "key": "DD-APPLICATION-KEY",
54
+ "key": "DD_APPLICATION_KEY",
55
55
  "label": "Datadog Application key",
56
56
  "type": "password",
57
57
  "required": true,