@openhands/extensions 0.10.0 → 0.12.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/.release-please-manifest.json +1 -1
- package/AGENTS.md +2 -1
- package/MIGRATION.md +31 -0
- package/README.md +12 -9
- package/automations/README.md +251 -8
- package/automations/catalog/github-pr-reviewer/manifest.json +82 -0
- package/automations/catalog/github-repo-monitor/manifest.json +82 -0
- package/automations/catalog/incident-retrospective-drafter/manifest.json +100 -0
- package/automations/catalog/{jira-issue-to-pr.json → jira-issue-to-pr/manifest.json} +10 -5
- package/automations/catalog/{linear-triage-assistant.json → linear-triage-assistant/manifest.json} +8 -4
- package/automations/catalog/{research-brief-writer.json → research-brief-writer/manifest.json} +11 -5
- package/automations/catalog/{slack-channel-monitor.json → slack-channel-monitor/manifest.json} +7 -2
- package/automations/catalog/{slack-standup-digest.json → slack-standup-digest/manifest.json} +8 -5
- package/automations/catalog-index.js +23 -0
- package/automations/catalog.schema.json +273 -0
- package/automations/index.d.ts +111 -3
- package/automations/index.js +21 -18
- package/index.d.ts +16 -1
- package/integrations/catalog/atlassian-rovo.json +44 -0
- package/integrations/catalog/datadog.json +3 -3
- package/integrations/catalog/github.json +1 -1
- package/integrations/catalog/linear.json +1 -1
- package/integrations/catalog/slack.json +2 -2
- package/integrations/catalog-index.js +30 -28
- package/integrations/index.d.ts +1 -1
- package/marketplaces/openhands-extensions.json +9 -0
- package/package.json +6 -3
- package/pyproject.toml +1 -1
- package/python/openhands_extensions/__init__.py +0 -4
- package/python/openhands_extensions/_version.py +3 -2
- package/python/openhands_extensions/integrations.py +8 -30
- package/scripts/build-automation-catalog.mjs +51 -0
- package/skills/bitbucket/SKILL.md +0 -1
- package/skills/github/SKILL.md +0 -1
- package/skills/gitlab/SKILL.md +0 -1
- package/skills/index.js +11 -8
- package/skills/iterate/README.md +4 -1
- package/skills/iterate/SKILL.md +22 -2
- package/skills/openhands-sdk/SKILL.md +2 -0
- package/skills/technical-writing/.plugin/plugin.json +15 -0
- package/skills/technical-writing/README.md +14 -0
- package/skills/technical-writing/SKILL.md +106 -0
- package/tests/fixtures/automations/capabilities.json +92 -0
- package/tests/fixtures/automations/github-pr-reviewer.json +251 -0
- package/tests/fixtures/automations/github-repo-monitor.json +180 -0
- package/tests/fixtures/automations/incident-retrospective-drafter.json +91 -0
- package/tests/test_automation_setup.py +526 -0
- package/tests/test_catalogs.py +104 -12
- package/tests/test_deprecations.py +39 -4
- package/tests/test_integration_catalog_in_sync.py +50 -60
- package/tests/test_live_integration_smoke.py +366 -0
- package/automations/catalog/github-pr-reviewer.json +0 -13
- package/automations/catalog/github-repo-monitor.json +0 -11
- package/automations/catalog/incident-retrospective-drafter.json +0 -15
package/automations/index.js
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
import
|
|
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
|
+
|
|
10
|
+
const clone = (value) => JSON.parse(JSON.stringify(value));
|
|
11
|
+
const AUTOMATIONS = AUTOMATION_CATALOG_ENTRIES;
|
|
12
|
+
const AUTOMATION_BY_ID = new Map(AUTOMATIONS.map((entry) => [entry.id, entry]));
|
|
13
|
+
|
|
14
|
+
export const listAutomationCatalog = () => clone(AUTOMATIONS);
|
|
15
|
+
|
|
16
|
+
export const getAutomationCatalogEntry = (id) => {
|
|
17
|
+
const entry = AUTOMATION_BY_ID.get(id);
|
|
18
|
+
return entry ? clone(entry) : undefined;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const AUTOMATION_CATALOG = clone(AUTOMATIONS);
|
|
9
22
|
|
|
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
23
|
export default AUTOMATION_CATALOG;
|
package/index.d.ts
CHANGED
|
@@ -14,6 +14,21 @@ export {
|
|
|
14
14
|
type OAuthProviderRegistrationDefaults,
|
|
15
15
|
} from "./integrations/index.js";
|
|
16
16
|
export { AUTOMATION_CATALOG } from "./automations/index.js";
|
|
17
|
-
export type {
|
|
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
|
+
} from "./automations/index.js";
|
|
18
33
|
export { SKILLS_CATALOG } from "./skills/index.js";
|
|
19
34
|
export type { SkillCatalogEntry } from "./skills/index.js";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "atlassian-rovo",
|
|
3
|
+
"name": "Atlassian Rovo",
|
|
4
|
+
"description": "Search, create, and update Jira issues, Confluence pages, Bitbucket repos, and Jira Service Management tickets - all through Atlassian's official hosted MCP server, powered by your Teamwork Graph.",
|
|
5
|
+
"categories": [
|
|
6
|
+
"Project management",
|
|
7
|
+
"Documentation",
|
|
8
|
+
"Engineering"
|
|
9
|
+
],
|
|
10
|
+
"appUrl": "https://www.atlassian.com/rovo",
|
|
11
|
+
"docsUrl": "https://support.atlassian.com/atlassian-rovo-mcp-server/docs/getting-started-with-the-atlassian-remote-mcp-server/",
|
|
12
|
+
"notes": "OAuth 2.1 is handled entirely by the Atlassian Rovo MCP server. No client credentials required - sign in with your Atlassian account when the authentication flow starts.",
|
|
13
|
+
"iconBg": "#0052CC",
|
|
14
|
+
"logoUrl": "https://cdn.simpleicons.org/atlassian/FFFFFF",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"atlassian",
|
|
17
|
+
"rovo",
|
|
18
|
+
"jira",
|
|
19
|
+
"confluence",
|
|
20
|
+
"bitbucket",
|
|
21
|
+
"jsm",
|
|
22
|
+
"tickets",
|
|
23
|
+
"wiki",
|
|
24
|
+
"issues",
|
|
25
|
+
"sprint",
|
|
26
|
+
"mcp"
|
|
27
|
+
],
|
|
28
|
+
"connectionOptions": [
|
|
29
|
+
{
|
|
30
|
+
"id": "oauth",
|
|
31
|
+
"provider": "mcp",
|
|
32
|
+
"transport": {
|
|
33
|
+
"kind": "shttp",
|
|
34
|
+
"url": "https://mcp.atlassian.com/v1/mcp/authv2"
|
|
35
|
+
},
|
|
36
|
+
"auth": {
|
|
37
|
+
"strategy": "oauth2",
|
|
38
|
+
"oauth": {
|
|
39
|
+
"clientAuthentication": "none"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"Operations"
|
|
8
8
|
],
|
|
9
9
|
"appUrl": "https://www.datadoghq.com",
|
|
10
|
-
"docsUrl": "https://docs.datadoghq.com/
|
|
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": "
|
|
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": "
|
|
54
|
+
"key": "DD_APPLICATION_KEY",
|
|
55
55
|
"label": "Datadog Application key",
|
|
56
56
|
"type": "password",
|
|
57
57
|
"required": true,
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"strategy": "api_key",
|
|
62
62
|
"credentialLabel": "Personal access token",
|
|
63
63
|
"credentialPlaceholder": "github_pat_...",
|
|
64
|
-
"credentialHelp": "
|
|
64
|
+
"credentialHelp": "Create a token in [GitHub settings](https://github.com/settings/personal-access-tokens): classic tokens need the repo and read:user scopes; fine-grained tokens need read access to Contents, Issues, and Pull requests for the repositories you use.",
|
|
65
65
|
"credentialSecretName": "GITHUB_PERSONAL_ACCESS_TOKEN",
|
|
66
66
|
"saveCredentialAsSecretByDefault": true
|
|
67
67
|
}
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"apiKeyOptional": true,
|
|
53
53
|
"credentialLabel": "Linear API key",
|
|
54
54
|
"credentialPlaceholder": "Paste your Linear API key",
|
|
55
|
-
"credentialHelp": "
|
|
55
|
+
"credentialHelp": "Create a personal API key (grant at least read access) under Security & access in [Linear settings](https://linear.app/settings/account/security). Sent as Authorization: Bearer <token>; optional when the endpoint accepts your OAuth session."
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
],
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
],
|
|
9
9
|
"appUrl": "https://slack.com",
|
|
10
10
|
"docsUrl": "https://github.com/zencoderai/slack-mcp-server",
|
|
11
|
-
"notes": "
|
|
11
|
+
"notes": "The OAuth option uses Slack's official hosted MCP server (confidential OAuth user-token auth); the local option runs the open-source zencoderai stdio server with a bot token.",
|
|
12
12
|
"popularityRank": 95,
|
|
13
13
|
"connectionOptions": [
|
|
14
14
|
{
|
|
@@ -101,5 +101,5 @@
|
|
|
101
101
|
"messaging",
|
|
102
102
|
"team"
|
|
103
103
|
],
|
|
104
|
-
"installHint": "Create a Slack app with
|
|
104
|
+
"installHint": "Create a Slack app with bot token scopes channels:history, channels:read, chat:write, reactions:write, users:read, and users.profile:read, then paste its bot token below."
|
|
105
105
|
}
|
|
@@ -48,34 +48,35 @@ import entry42 from "./catalog/google-drive.json" with { type: "json" };
|
|
|
48
48
|
import entry43 from "./catalog/figma.json" with { type: "json" };
|
|
49
49
|
import entry44 from "./catalog/google-docs.json" with { type: "json" };
|
|
50
50
|
import entry45 from "./catalog/apify.json" with { type: "json" };
|
|
51
|
-
import entry46 from "./catalog/
|
|
52
|
-
import entry47 from "./catalog/
|
|
53
|
-
import entry48 from "./catalog/
|
|
54
|
-
import entry49 from "./catalog/
|
|
55
|
-
import entry50 from "./catalog/cloudflare-
|
|
56
|
-
import entry51 from "./catalog/cloudflare-
|
|
57
|
-
import entry52 from "./catalog/cloudflare-
|
|
58
|
-
import entry53 from "./catalog/cloudflare-
|
|
59
|
-
import entry54 from "./catalog/
|
|
60
|
-
import entry55 from "./catalog/
|
|
61
|
-
import entry56 from "./catalog/
|
|
62
|
-
import entry57 from "./catalog/
|
|
63
|
-
import entry58 from "./catalog/
|
|
64
|
-
import entry59 from "./catalog/
|
|
65
|
-
import entry60 from "./catalog/
|
|
66
|
-
import entry61 from "./catalog/
|
|
67
|
-
import entry62 from "./catalog/
|
|
68
|
-
import entry63 from "./catalog/
|
|
69
|
-
import entry64 from "./catalog/
|
|
70
|
-
import entry65 from "./catalog/
|
|
71
|
-
import entry66 from "./catalog/
|
|
72
|
-
import entry67 from "./catalog/
|
|
73
|
-
import entry68 from "./catalog/
|
|
74
|
-
import entry69 from "./catalog/
|
|
75
|
-
import entry70 from "./catalog/
|
|
76
|
-
import entry71 from "./catalog/
|
|
77
|
-
import entry72 from "./catalog/
|
|
78
|
-
import entry73 from "./catalog/
|
|
51
|
+
import entry46 from "./catalog/atlassian-rovo.json" with { type: "json" };
|
|
52
|
+
import entry47 from "./catalog/brave-search.json" with { type: "json" };
|
|
53
|
+
import entry48 from "./catalog/browser-mcp.json" with { type: "json" };
|
|
54
|
+
import entry49 from "./catalog/clickhouse.json" with { type: "json" };
|
|
55
|
+
import entry50 from "./catalog/cloudflare-bindings.json" with { type: "json" };
|
|
56
|
+
import entry51 from "./catalog/cloudflare-browser-rendering.json" with { type: "json" };
|
|
57
|
+
import entry52 from "./catalog/cloudflare-builds.json" with { type: "json" };
|
|
58
|
+
import entry53 from "./catalog/cloudflare-docs.json" with { type: "json" };
|
|
59
|
+
import entry54 from "./catalog/cloudflare-observability.json" with { type: "json" };
|
|
60
|
+
import entry55 from "./catalog/deepwiki.json" with { type: "json" };
|
|
61
|
+
import entry56 from "./catalog/everything.json" with { type: "json" };
|
|
62
|
+
import entry57 from "./catalog/exa.json" with { type: "json" };
|
|
63
|
+
import entry58 from "./catalog/fetch.json" with { type: "json" };
|
|
64
|
+
import entry59 from "./catalog/filesystem.json" with { type: "json" };
|
|
65
|
+
import entry60 from "./catalog/firecrawl.json" with { type: "json" };
|
|
66
|
+
import entry61 from "./catalog/git.json" with { type: "json" };
|
|
67
|
+
import entry62 from "./catalog/huggingface.json" with { type: "json" };
|
|
68
|
+
import entry63 from "./catalog/kagi.json" with { type: "json" };
|
|
69
|
+
import entry64 from "./catalog/memory.json" with { type: "json" };
|
|
70
|
+
import entry65 from "./catalog/mongodb.json" with { type: "json" };
|
|
71
|
+
import entry66 from "./catalog/neon.json" with { type: "json" };
|
|
72
|
+
import entry67 from "./catalog/obsidian.json" with { type: "json" };
|
|
73
|
+
import entry68 from "./catalog/paypal.json" with { type: "json" };
|
|
74
|
+
import entry69 from "./catalog/playwright.json" with { type: "json" };
|
|
75
|
+
import entry70 from "./catalog/redis.json" with { type: "json" };
|
|
76
|
+
import entry71 from "./catalog/resend.json" with { type: "json" };
|
|
77
|
+
import entry72 from "./catalog/sequential-thinking.json" with { type: "json" };
|
|
78
|
+
import entry73 from "./catalog/superhuman-mail.json" with { type: "json" };
|
|
79
|
+
import entry74 from "./catalog/time.json" with { type: "json" };
|
|
79
80
|
|
|
80
81
|
export const INTEGRATION_CATALOG_ENTRIES = [
|
|
81
82
|
entry0,
|
|
@@ -152,4 +153,5 @@ export const INTEGRATION_CATALOG_ENTRIES = [
|
|
|
152
153
|
entry71,
|
|
153
154
|
entry72,
|
|
154
155
|
entry73,
|
|
156
|
+
entry74,
|
|
155
157
|
];
|
package/integrations/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export type IntegrationTransport =
|
|
|
17
17
|
apiKeyOptional?: boolean;
|
|
18
18
|
/**
|
|
19
19
|
* Named request headers the user must supply (e.g. Datadog's
|
|
20
|
-
* `
|
|
20
|
+
* `DD_API_KEY` / `DD_APPLICATION_KEY`). Values are sent verbatim as
|
|
21
21
|
* headers on every MCP request. The direct analog of stdio's
|
|
22
22
|
* `envFields`: each entry renders one input in the install modal,
|
|
23
23
|
* `type: "password"` entries are secret-saved by default, and
|
|
@@ -729,6 +729,15 @@
|
|
|
729
729
|
"automation"
|
|
730
730
|
]
|
|
731
731
|
},
|
|
732
|
+
{
|
|
733
|
+
"name": "technical-writing",
|
|
734
|
+
"source": "./skills/technical-writing",
|
|
735
|
+
"description": "Write and revise technical explanations in flowing, direct, conversational prose that stays concise without becoming fragmented or vague.",
|
|
736
|
+
"category": "productivity",
|
|
737
|
+
"keywords": [
|
|
738
|
+
"technical-writing"
|
|
739
|
+
]
|
|
740
|
+
},
|
|
732
741
|
{
|
|
733
742
|
"name": "plain-english-content",
|
|
734
743
|
"source": "./skills/plain-english-content",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openhands/extensions",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Public OpenHands extension catalogs for skills, plugins, integrations, and automation templates.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build:skills": "node scripts/build-skills-catalog.mjs",
|
|
13
13
|
"build:integrations": "node scripts/build-integration-catalog.mjs",
|
|
14
|
-
"build": "
|
|
14
|
+
"build:automations": "node scripts/build-automation-catalog.mjs",
|
|
15
|
+
"build": "npm run build:skills && npm run build:integrations && npm run build:automations"
|
|
15
16
|
},
|
|
16
17
|
"engines": {
|
|
17
18
|
"node": ">=18.20.0"
|
|
@@ -35,7 +36,8 @@
|
|
|
35
36
|
"import": "./automations/index.js",
|
|
36
37
|
"default": "./automations/index.js"
|
|
37
38
|
},
|
|
38
|
-
"./automations/catalog
|
|
39
|
+
"./automations/catalog/*": "./automations/catalog/*",
|
|
40
|
+
"./automations/catalog.schema.json": "./automations/catalog.schema.json",
|
|
39
41
|
"./integrations": {
|
|
40
42
|
"types": "./integrations/index.d.ts",
|
|
41
43
|
"import": "./integrations/index.js",
|
|
@@ -50,6 +52,7 @@
|
|
|
50
52
|
"./skills/*": "./skills/*",
|
|
51
53
|
"./plugins/*": "./plugins/*",
|
|
52
54
|
"./marketplaces/*.json": "./marketplaces/*.json",
|
|
55
|
+
"./testing/automations/*.json": "./tests/fixtures/automations/*.json",
|
|
53
56
|
"./package.json": "./package.json"
|
|
54
57
|
}
|
|
55
58
|
}
|
package/pyproject.toml
CHANGED
|
@@ -12,9 +12,7 @@ from __future__ import annotations
|
|
|
12
12
|
from ._version import __version__
|
|
13
13
|
from .integrations import (
|
|
14
14
|
INTEGRATION_CATALOG_SNAPSHOT,
|
|
15
|
-
get_integration_catalog_entry,
|
|
16
15
|
get_integration_catalog_entry_model,
|
|
17
|
-
list_integration_catalog,
|
|
18
16
|
list_integration_catalog_models,
|
|
19
17
|
)
|
|
20
18
|
from .integration_models import (
|
|
@@ -55,8 +53,6 @@ __all__ = [
|
|
|
55
53
|
"StdioTransport",
|
|
56
54
|
"StreamableHttpTransport",
|
|
57
55
|
"__version__",
|
|
58
|
-
"get_integration_catalog_entry",
|
|
59
56
|
"get_integration_catalog_entry_model",
|
|
60
|
-
"list_integration_catalog",
|
|
61
57
|
"list_integration_catalog_models",
|
|
62
58
|
]
|
|
@@ -16,8 +16,9 @@ from importlib.metadata import PackageNotFoundError, version
|
|
|
16
16
|
|
|
17
17
|
#: Fallback used only when the package is not installed (no dist metadata).
|
|
18
18
|
#: Kept in lock-step with pyproject.toml/package.json by the version test.
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
#: release-please only rewrites a semver found on the annotated line itself, so
|
|
20
|
+
#: the annotation must stay on the assignment; on its own line it is a no-op.
|
|
21
|
+
_FALLBACK_VERSION = "0.12.0" # x-release-please-version
|
|
21
22
|
|
|
22
23
|
try:
|
|
23
24
|
__version__: str = version("openhands-extensions")
|
|
@@ -14,15 +14,12 @@ from importlib import resources
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
from typing import Any, Iterable
|
|
16
16
|
|
|
17
|
-
from .deprecation import deprecated
|
|
18
17
|
from .integration_models import IntegrationCatalogEntry
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
__all__ = [
|
|
22
21
|
"INTEGRATION_CATALOG_SNAPSHOT",
|
|
23
|
-
"get_integration_catalog_entry",
|
|
24
22
|
"get_integration_catalog_entry_model",
|
|
25
|
-
"list_integration_catalog",
|
|
26
23
|
"list_integration_catalog_models",
|
|
27
24
|
]
|
|
28
25
|
|
|
@@ -81,20 +78,11 @@ def _entry_supports_oauth(entry: dict[str, Any]) -> bool:
|
|
|
81
78
|
)
|
|
82
79
|
|
|
83
80
|
|
|
84
|
-
|
|
85
|
-
deprecated_in="0.10.0",
|
|
86
|
-
removed_in="0.12.0",
|
|
87
|
-
details="Use list_integration_catalog_models() for validated Pydantic models.",
|
|
88
|
-
)
|
|
89
|
-
def list_integration_catalog(
|
|
81
|
+
def _list_catalog_entries(
|
|
90
82
|
mcp: bool | None = None,
|
|
91
83
|
oauth: bool | None = None,
|
|
92
84
|
) -> list[dict[str, Any]]:
|
|
93
|
-
"""Return raw catalog dictionaries, optionally filtered by connector type.
|
|
94
|
-
|
|
95
|
-
Deprecated since v0.10.0 and scheduled for removal in v0.12.0.
|
|
96
|
-
Use :func:`list_integration_catalog_models` instead.
|
|
97
|
-
"""
|
|
85
|
+
"""Return raw catalog dictionaries, optionally filtered by connector type."""
|
|
98
86
|
result = []
|
|
99
87
|
for entry in _integrations():
|
|
100
88
|
if mcp is not None and _entry_supports_mcp(entry) != mcp:
|
|
@@ -111,34 +99,24 @@ def list_integration_catalog_models(
|
|
|
111
99
|
) -> list[IntegrationCatalogEntry]:
|
|
112
100
|
"""Return typed, validated integration catalog entries.
|
|
113
101
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
this function for a stable, validated contract.
|
|
102
|
+
This is the supported Python contract for reading the catalog. The raw
|
|
103
|
+
dictionary accessors it replaced were removed in v0.12.0.
|
|
117
104
|
"""
|
|
118
105
|
return [
|
|
119
106
|
IntegrationCatalogEntry.model_validate(entry)
|
|
120
|
-
for entry in
|
|
107
|
+
for entry in _list_catalog_entries(mcp=mcp, oauth=oauth)
|
|
121
108
|
]
|
|
122
109
|
|
|
123
110
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
removed_in="0.12.0",
|
|
127
|
-
details="Use get_integration_catalog_entry_model() for a validated Pydantic model.",
|
|
128
|
-
)
|
|
129
|
-
def get_integration_catalog_entry(id: str) -> dict[str, Any] | None:
|
|
130
|
-
"""Return one raw catalog dictionary by id, or ``None``.
|
|
131
|
-
|
|
132
|
-
Deprecated since v0.10.0 and scheduled for removal in v0.12.0.
|
|
133
|
-
Use :func:`get_integration_catalog_entry_model` instead.
|
|
134
|
-
"""
|
|
111
|
+
def _get_catalog_entry(id: str) -> dict[str, Any] | None:
|
|
112
|
+
"""Return one raw catalog dictionary by id, or ``None``."""
|
|
135
113
|
entry = _integration_by_id().get(id)
|
|
136
114
|
return copy.deepcopy(entry) if entry is not None else None
|
|
137
115
|
|
|
138
116
|
|
|
139
117
|
def get_integration_catalog_entry_model(id: str) -> IntegrationCatalogEntry | None:
|
|
140
118
|
"""Return one typed catalog entry, or ``None`` when it does not exist."""
|
|
141
|
-
entry =
|
|
119
|
+
entry = _get_catalog_entry(id)
|
|
142
120
|
return IntegrationCatalogEntry.model_validate(entry) if entry is not None else None
|
|
143
121
|
|
|
144
122
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { readdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
const root = process.cwd();
|
|
5
|
+
const catalogDir = path.join(root, "automations", "catalog");
|
|
6
|
+
const outputPath = path.join(root, "automations", "catalog-index.js");
|
|
7
|
+
|
|
8
|
+
const directories = (await readdir(catalogDir, { withFileTypes: true }))
|
|
9
|
+
.filter((entry) => entry.isDirectory())
|
|
10
|
+
.map((entry) => entry.name)
|
|
11
|
+
.sort((left, right) => left.localeCompare(right));
|
|
12
|
+
|
|
13
|
+
const automations = await Promise.all(
|
|
14
|
+
directories.map(async (directory) => ({
|
|
15
|
+
directory,
|
|
16
|
+
entry: JSON.parse(
|
|
17
|
+
await readFile(path.join(catalogDir, directory, "manifest.json"), "utf8"),
|
|
18
|
+
),
|
|
19
|
+
})),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
automations.sort((left, right) => {
|
|
23
|
+
const rank = (right.entry.popularityRank ?? -1) - (left.entry.popularityRank ?? -1);
|
|
24
|
+
return rank || left.entry.id.localeCompare(right.entry.id);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const indexedAutomations = automations.map((automation, index) => ({
|
|
28
|
+
...automation,
|
|
29
|
+
importName: `entry${index}`,
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
const imports = indexedAutomations
|
|
33
|
+
.map(
|
|
34
|
+
({ directory, importName }) =>
|
|
35
|
+
`import ${importName} from "./catalog/${directory}/manifest.json" with { type: "json" };`,
|
|
36
|
+
)
|
|
37
|
+
.join("\n");
|
|
38
|
+
const entries = indexedAutomations.map(({ importName }) => ` ${importName},`).join("\n");
|
|
39
|
+
|
|
40
|
+
const header = `// This file is auto-generated by scripts/build-automation-catalog.mjs.
|
|
41
|
+
// Do not edit it manually. To update it after changing automations/catalog/*/manifest.json,
|
|
42
|
+
// run: npm run build:automations
|
|
43
|
+
|
|
44
|
+
`;
|
|
45
|
+
const body = `${header}${imports}
|
|
46
|
+
|
|
47
|
+
export const AUTOMATION_CATALOG_ENTRIES = [
|
|
48
|
+
${entries}
|
|
49
|
+
];
|
|
50
|
+
`;
|
|
51
|
+
await writeFile(outputPath, body);
|
|
@@ -3,7 +3,6 @@ name: bitbucket
|
|
|
3
3
|
description: Bitbucket integration hub. Detects whether the repository is on Bitbucket Cloud or Bitbucket Data Center and directs you to the matching detailed skill (bitbucket-cloud or bitbucket-data-center). Use for any Bitbucket repository or pull request task.
|
|
4
4
|
triggers:
|
|
5
5
|
- bitbucket
|
|
6
|
-
- git
|
|
7
6
|
---
|
|
8
7
|
|
|
9
8
|
You are working with **Bitbucket**, which ships as two distinct products that behave
|
package/skills/github/SKILL.md
CHANGED
|
@@ -3,7 +3,6 @@ name: github
|
|
|
3
3
|
description: Interact with GitHub repositories, pull requests, issues, and workflows using the GITHUB_TOKEN environment variable and GitHub CLI. Use when working with code hosted on GitHub or managing GitHub resources.
|
|
4
4
|
triggers:
|
|
5
5
|
- github
|
|
6
|
-
- git
|
|
7
6
|
---
|
|
8
7
|
|
|
9
8
|
You have access to an environment variable, `GITHUB_TOKEN`, which allows you to interact with
|
package/skills/gitlab/SKILL.md
CHANGED
|
@@ -3,7 +3,6 @@ name: gitlab
|
|
|
3
3
|
description: Interact with GitLab repositories, merge requests, and APIs using the GITLAB_TOKEN environment variable. Use when working with code hosted on GitLab or managing GitLab resources.
|
|
4
4
|
triggers:
|
|
5
5
|
- gitlab
|
|
6
|
-
- git
|
|
7
6
|
---
|
|
8
7
|
|
|
9
8
|
You have access to an environment variable, `GITLAB_TOKEN`, which allows you to interact with
|