@openhands/extensions 0.5.0 → 0.6.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/.github/workflows/pypi-publish.yml +104 -0
- package/.github/workflows/tests.yml +6 -0
- package/.release-please-manifest.json +1 -1
- package/AGENTS.md +1 -1
- package/README.md +31 -3
- package/integrations/README.md +17 -7
- package/integrations/catalog/airtable.json +40 -10
- package/integrations/catalog/apify.json +0 -2
- package/integrations/catalog/asana.json +38 -0
- package/integrations/catalog/atlassian.json +5 -8
- package/integrations/catalog/bitbucket.json +39 -0
- package/integrations/catalog/box.json +39 -0
- package/integrations/catalog/brave-search.json +1 -2
- package/integrations/catalog/browser-mcp.json +0 -3
- package/integrations/catalog/canva.json +35 -0
- package/integrations/catalog/clickhouse.json +1 -2
- package/integrations/catalog/clickup.json +36 -0
- package/integrations/catalog/cloudflare-bindings.json +5 -8
- package/integrations/catalog/cloudflare-browser-rendering.json +5 -8
- package/integrations/catalog/cloudflare-builds.json +6 -9
- package/integrations/catalog/cloudflare-docs.json +4 -7
- package/integrations/catalog/cloudflare-observability.json +5 -8
- package/integrations/catalog/confluence.json +38 -0
- package/integrations/catalog/datadog.json +34 -0
- package/integrations/catalog/deepwiki.json +3 -7
- package/integrations/catalog/discord.json +39 -0
- package/integrations/catalog/dropbox.json +38 -0
- package/integrations/catalog/elevenlabs.json +27 -28
- package/integrations/catalog/everything.json +0 -2
- package/integrations/catalog/exa.json +0 -2
- package/integrations/catalog/fetch.json +0 -2
- package/integrations/catalog/figma.json +41 -9
- package/integrations/catalog/filesystem.json +0 -3
- package/integrations/catalog/firecrawl.json +0 -2
- package/integrations/catalog/freshdesk.json +38 -0
- package/integrations/catalog/git.json +0 -3
- package/integrations/catalog/github.json +43 -10
- package/integrations/catalog/gitlab.json +38 -0
- package/integrations/catalog/gmail.json +38 -0
- package/integrations/catalog/google-calendar.json +38 -0
- package/integrations/catalog/google-docs.json +38 -0
- package/integrations/catalog/google-drive.json +38 -0
- package/integrations/catalog/google-sheets.json +38 -0
- package/integrations/catalog/hubspot.json +34 -0
- package/integrations/catalog/huggingface.json +1 -2
- package/integrations/catalog/intercom.json +39 -0
- package/integrations/catalog/jira.json +38 -0
- package/integrations/catalog/kagi.json +2 -3
- package/integrations/catalog/linear.json +47 -16
- package/integrations/catalog/mailchimp.json +38 -0
- package/integrations/catalog/memory.json +0 -2
- package/integrations/catalog/microsoft-outlook.json +38 -0
- package/integrations/catalog/microsoft-teams.json +38 -0
- package/integrations/catalog/miro.json +38 -0
- package/integrations/catalog/monday.json +38 -0
- package/integrations/catalog/mongodb.json +1 -2
- package/integrations/catalog/neon.json +0 -2
- package/integrations/catalog/netlify.json +38 -0
- package/integrations/catalog/notion.json +37 -10
- package/integrations/catalog/obsidian.json +1 -3
- package/integrations/catalog/okta.json +38 -0
- package/integrations/catalog/onedrive.json +38 -0
- package/integrations/catalog/ordinal.json +33 -0
- package/integrations/catalog/paypal.json +5 -8
- package/integrations/catalog/pipedrive.json +39 -0
- package/integrations/catalog/plaid.json +31 -0
- package/integrations/catalog/playwright.json +0 -2
- package/integrations/catalog/posthog.json +38 -0
- package/integrations/catalog/quickbooks.json +38 -0
- package/integrations/catalog/redis.json +1 -3
- package/integrations/catalog/resend.json +1 -2
- package/integrations/catalog/salesforce.json +38 -0
- package/integrations/catalog/sentry.json +52 -14
- package/integrations/catalog/sequential-thinking.json +0 -2
- package/integrations/catalog/servicenow.json +39 -0
- package/integrations/catalog/sharepoint.json +38 -0
- package/integrations/catalog/shopify.json +38 -0
- package/integrations/catalog/slack.json +49 -10
- package/integrations/catalog/stripe.json +44 -14
- package/integrations/catalog/supabase.json +36 -9
- package/integrations/catalog/tavily.json +0 -2
- package/integrations/catalog/time.json +0 -2
- package/integrations/catalog/trello.json +31 -0
- package/integrations/catalog/vercel.json +38 -0
- package/integrations/catalog/webflow.json +34 -0
- package/integrations/catalog/xero.json +38 -0
- package/integrations/catalog/zendesk.json +38 -0
- package/integrations/catalog/zoom.json +38 -0
- package/integrations/catalog-index.js +171 -0
- package/integrations/index.d.ts +24 -60
- package/integrations/index.js +29 -207
- package/marketplaces/openhands-extensions.json +14 -1
- package/package.json +4 -7
- package/plugins/cobol-modernization/README.md +3 -3
- package/plugins/cobol-modernization/skills/{cobol-modernization-overview → cobol-modernization}/SKILL.md +1 -1
- package/plugins/magic-test/skills/magic-word/SKILL.md +1 -0
- package/plugins/migration-scoring/README.md +1 -1
- package/pyproject.toml +17 -3
- package/python/openhands_extensions/__init__.py +24 -0
- package/python/openhands_extensions/_version.py +24 -0
- package/python/openhands_extensions/integrations.py +92 -0
- package/release-please-config.json +2 -1
- package/scripts/build-integration-catalog.mjs +45 -0
- package/skills/agent-canvas-environment/.plugin/plugin.json +19 -0
- package/skills/agent-canvas-environment/README.md +5 -0
- package/skills/agent-canvas-environment/SKILL.md +141 -0
- package/skills/github-pr-reviewer/references/state-schema.md +18 -4
- package/skills/github-pr-reviewer/scripts/main.py +66 -12
- package/skills/github-repo-monitor/references/state-schema.md +11 -4
- package/skills/github-repo-monitor/scripts/main.py +67 -19
- package/skills/github-repo-monitor/tests/test_main.py +67 -8
- package/skills/index.js +19 -5
- package/skills/openhands-api/README.md +5 -1
- package/skills/openhands-api/SKILL.md +74 -5
- package/skills/openhands-automation/SKILL.md +3 -1
- package/skills/openhands-automation/references/custom-automation.md +166 -0
- package/skills/openhands-sdk/SKILL.md +8 -2
- package/skills/slack-channel-monitor/README.md +3 -3
- package/skills/slack-channel-monitor/SKILL.md +3 -2
- package/skills/slack-channel-monitor/references/state-schema.md +11 -4
- package/skills/slack-channel-monitor/scripts/main.py +111 -41
- package/tests/test_catalogs.py +21 -3
- package/tests/test_integration_catalog_in_sync.py +204 -0
- package/tests/test_slack_channel_monitor.py +142 -0
- package/tests/test_version_alignment.py +64 -0
- package/integrations/logos.d.ts +0 -5
- package/integrations/logos.js +0 -94
- package/integrations/oauth-provider-catalog.js +0 -553
- package/integrations/oauth-provider-registration-defaults.js +0 -610
- /package/plugins/cobol-modernization/skills/{mainfraime-removal → mainframe-removal}/SKILL.md +0 -0
- /package/plugins/cobol-modernization/skills/{mainfraime-removal → mainframe-removal}/references/cics-transformation-examples.md +0 -0
- /package/plugins/migration-scoring/skills/{migration-scoring-overview → migration-scoring}/SKILL.md +0 -0
package/integrations/index.d.ts
CHANGED
|
@@ -88,52 +88,9 @@ export interface IntegrationConnectionOption {
|
|
|
88
88
|
auth: IntegrationAuthConfig;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
export interface OAuthProviderRegistrationDefaults {
|
|
92
|
-
provider?: IntegrationProvider;
|
|
93
|
-
authModes?: IntegrationAuthStrategy[];
|
|
94
|
-
authStrategy?: IntegrationAuthStrategy;
|
|
95
|
-
credentialLabel?: string;
|
|
96
|
-
credentialPlaceholder?: string;
|
|
97
|
-
credentialHelp?: string;
|
|
98
|
-
apiKeyHeaderName?: string;
|
|
99
|
-
apiBaseUrl?: string;
|
|
100
|
-
serverUrl?: string;
|
|
101
|
-
openApiUrl?: string;
|
|
102
|
-
authorizationUrl?: string;
|
|
103
|
-
tokenUrl?: string;
|
|
104
|
-
scopes?: string[];
|
|
105
|
-
optionalScopes?: string[];
|
|
106
|
-
toolScopes?: string[];
|
|
107
|
-
scopeSeparator?: "space" | "comma";
|
|
108
|
-
pkce?: boolean;
|
|
109
|
-
clientAuthentication?: "basic" | "body" | "none";
|
|
110
|
-
registrationUrl?: string;
|
|
111
|
-
additionalAuthorizationParams?: Record<string, string>;
|
|
112
|
-
additionalTokenParams?: Record<string, string>;
|
|
113
|
-
toolName?: string;
|
|
114
|
-
toolDescription?: string;
|
|
115
|
-
requestMethod?: string;
|
|
116
|
-
requestPath?: string;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export interface OAuthProviderCatalogOption {
|
|
120
|
-
slug: string;
|
|
121
|
-
name: string;
|
|
122
|
-
description: string;
|
|
123
|
-
categories: string[];
|
|
124
|
-
authStrategy: IntegrationAuthStrategy;
|
|
125
|
-
availability: "oauth_ready" | "manual_token" | "planned";
|
|
126
|
-
managedConnectorSlug?: string;
|
|
127
|
-
appUrl?: string;
|
|
128
|
-
docsUrl?: string;
|
|
129
|
-
notes: string;
|
|
130
|
-
popularityRank: number;
|
|
131
|
-
registrationDefaults?: OAuthProviderRegistrationDefaults;
|
|
132
|
-
}
|
|
133
91
|
|
|
134
92
|
export interface IntegrationCatalogEntry {
|
|
135
93
|
id: string;
|
|
136
|
-
kind: IntegrationProvider;
|
|
137
94
|
name: string;
|
|
138
95
|
description: string;
|
|
139
96
|
categories?: string[];
|
|
@@ -142,28 +99,35 @@ export interface IntegrationCatalogEntry {
|
|
|
142
99
|
notes?: string;
|
|
143
100
|
iconBg?: string;
|
|
144
101
|
iconColor?: string;
|
|
102
|
+
logoUrl?: string;
|
|
145
103
|
keywords?: string[];
|
|
146
104
|
popularityRank?: number;
|
|
147
|
-
runtimeAvailability?: "all" | "local";
|
|
148
|
-
catalogStatus?: "oauth_ready" | "manual_token" | "planned";
|
|
149
|
-
managedConnectorSlug?: string;
|
|
150
|
-
authStrategy?: IntegrationAuthStrategy;
|
|
151
105
|
installHint?: string;
|
|
152
|
-
defaultConnectionOptionId?: string;
|
|
153
106
|
connectionOptions: IntegrationConnectionOption[];
|
|
154
|
-
registrationDefaults?: OAuthProviderRegistrationDefaults;
|
|
155
107
|
}
|
|
156
108
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Filter for {@link listIntegrationCatalog}. Each dimension is tri-state:
|
|
111
|
+
* `true` keeps only entries that support that connector type, `false` keeps
|
|
112
|
+
* only entries that do not, and `undefined` leaves that dimension unfiltered.
|
|
113
|
+
*/
|
|
114
|
+
export interface IntegrationCatalogFilter {
|
|
115
|
+
/** Filter on whether the entry exposes at least one `mcp` connector. */
|
|
116
|
+
mcp?: boolean;
|
|
117
|
+
/** Filter on whether the entry exposes at least one `oauth2` connector. */
|
|
118
|
+
oauth?: boolean;
|
|
119
|
+
}
|
|
168
120
|
|
|
121
|
+
export const INTEGRATION_CATALOG: IntegrationCatalogEntry[];
|
|
122
|
+
/**
|
|
123
|
+
* Return the full integration catalog, optionally filtered by connector type.
|
|
124
|
+
* Reads the generated static import index over `integrations/catalog/<id>.json`.
|
|
125
|
+
* Returns the cached array; callers must treat it as read-only.
|
|
126
|
+
*/
|
|
127
|
+
export function listIntegrationCatalog(
|
|
128
|
+
filter?: IntegrationCatalogFilter,
|
|
129
|
+
): IntegrationCatalogEntry[];
|
|
130
|
+
export function getIntegrationCatalogEntry(
|
|
131
|
+
id: string,
|
|
132
|
+
): IntegrationCatalogEntry | undefined;
|
|
169
133
|
export default INTEGRATION_CATALOG;
|
package/integrations/index.js
CHANGED
|
@@ -1,212 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
import notion from "./catalog/notion.json" with { type: "json" };
|
|
29
|
-
import obsidian from "./catalog/obsidian.json" with { type: "json" };
|
|
30
|
-
import paypal from "./catalog/paypal.json" with { type: "json" };
|
|
31
|
-
import playwright from "./catalog/playwright.json" with { type: "json" };
|
|
32
|
-
import redis from "./catalog/redis.json" with { type: "json" };
|
|
33
|
-
import resend from "./catalog/resend.json" with { type: "json" };
|
|
34
|
-
import sentry from "./catalog/sentry.json" with { type: "json" };
|
|
35
|
-
import sequential_thinking from "./catalog/sequential-thinking.json" with { type: "json" };
|
|
36
|
-
import slack from "./catalog/slack.json" with { type: "json" };
|
|
37
|
-
import stripe from "./catalog/stripe.json" with { type: "json" };
|
|
38
|
-
import supabase from "./catalog/supabase.json" with { type: "json" };
|
|
39
|
-
import tavily from "./catalog/tavily.json" with { type: "json" };
|
|
40
|
-
import time from "./catalog/time.json" with { type: "json" };
|
|
41
|
-
import { listOAuthProviderCatalog } from "./oauth-provider-catalog.js";
|
|
42
|
-
export { listOAuthProviderCatalog } from "./oauth-provider-catalog.js";
|
|
43
|
-
export {
|
|
44
|
-
getOAuthProviderRegistrationDefaults,
|
|
45
|
-
hubspotMcpAuthorizationUrl,
|
|
46
|
-
hubspotMcpServerUrl,
|
|
47
|
-
hubspotMcpTokenUrl,
|
|
48
|
-
hubspotOptionalScopes,
|
|
49
|
-
hubspotRequiredScopes,
|
|
50
|
-
} from "./oauth-provider-registration-defaults.js";
|
|
51
|
-
|
|
52
|
-
const DIRECT_INTEGRATIONS = [
|
|
53
|
-
airtable,
|
|
54
|
-
apify,
|
|
55
|
-
atlassian,
|
|
56
|
-
brave_search,
|
|
57
|
-
browser_mcp,
|
|
58
|
-
clickhouse,
|
|
59
|
-
cloudflare_bindings,
|
|
60
|
-
cloudflare_browser_rendering,
|
|
61
|
-
cloudflare_builds,
|
|
62
|
-
cloudflare_docs,
|
|
63
|
-
cloudflare_observability,
|
|
64
|
-
deepwiki,
|
|
65
|
-
elevenlabs,
|
|
66
|
-
everything,
|
|
67
|
-
exa,
|
|
68
|
-
fetch,
|
|
69
|
-
figma,
|
|
70
|
-
filesystem,
|
|
71
|
-
firecrawl,
|
|
72
|
-
git,
|
|
73
|
-
github,
|
|
74
|
-
huggingface,
|
|
75
|
-
kagi,
|
|
76
|
-
linear,
|
|
77
|
-
memory,
|
|
78
|
-
mongodb,
|
|
79
|
-
neon,
|
|
80
|
-
notion,
|
|
81
|
-
obsidian,
|
|
82
|
-
paypal,
|
|
83
|
-
playwright,
|
|
84
|
-
redis,
|
|
85
|
-
resend,
|
|
86
|
-
sentry,
|
|
87
|
-
sequential_thinking,
|
|
88
|
-
slack,
|
|
89
|
-
stripe,
|
|
90
|
-
supabase,
|
|
91
|
-
tavily,
|
|
92
|
-
time,
|
|
93
|
-
];
|
|
94
|
-
|
|
95
|
-
const optionIdForDefaults = (defaults) => {
|
|
96
|
-
const strategy = defaults?.authStrategy ?? (defaults?.authorizationUrl || defaults?.tokenUrl ? "oauth2" : "oauth2");
|
|
97
|
-
if (strategy === "oauth2") return "oauth";
|
|
98
|
-
if (strategy === "none") return "none";
|
|
99
|
-
return "api";
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const providerConnectionOption = (provider) => {
|
|
103
|
-
const defaults = provider.registrationDefaults;
|
|
104
|
-
if (!defaults) return null;
|
|
105
|
-
const option = {
|
|
106
|
-
id: optionIdForDefaults(defaults),
|
|
107
|
-
provider: defaults.provider ?? (defaults.serverUrl ? "mcp" : "http"),
|
|
108
|
-
auth: {
|
|
109
|
-
strategy: defaults.authStrategy ?? provider.authStrategy ?? "oauth2",
|
|
110
|
-
authModes: defaults.authModes,
|
|
111
|
-
credentialLabel: defaults.credentialLabel,
|
|
112
|
-
credentialPlaceholder: defaults.credentialPlaceholder,
|
|
113
|
-
credentialHelp: defaults.credentialHelp,
|
|
114
|
-
apiKeyHeaderName: defaults.apiKeyHeaderName,
|
|
115
|
-
oauth: defaults.authorizationUrl || defaults.tokenUrl ? {
|
|
116
|
-
authorizationUrl: defaults.authorizationUrl,
|
|
117
|
-
tokenUrl: defaults.tokenUrl,
|
|
118
|
-
scopes: defaults.scopes ?? [],
|
|
119
|
-
optionalScopes: defaults.optionalScopes,
|
|
120
|
-
toolScopes: defaults.toolScopes,
|
|
121
|
-
scopeSeparator: defaults.scopeSeparator,
|
|
122
|
-
pkce: defaults.pkce,
|
|
123
|
-
clientAuthentication: defaults.clientAuthentication,
|
|
124
|
-
registrationUrl: defaults.registrationUrl,
|
|
125
|
-
additionalAuthorizationParams: defaults.additionalAuthorizationParams,
|
|
126
|
-
additionalTokenParams: defaults.additionalTokenParams,
|
|
127
|
-
} : undefined,
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
if (option.provider === "mcp") {
|
|
132
|
-
option.transport = { kind: "shttp", url: defaults.serverUrl };
|
|
133
|
-
} else {
|
|
134
|
-
option.http = {
|
|
135
|
-
apiBaseUrl: defaults.apiBaseUrl,
|
|
136
|
-
openApiUrl: defaults.openApiUrl,
|
|
137
|
-
defaultTool: defaults.toolName ? {
|
|
138
|
-
name: defaults.toolName,
|
|
139
|
-
description: defaults.toolDescription,
|
|
140
|
-
method: defaults.requestMethod,
|
|
141
|
-
path: defaults.requestPath,
|
|
142
|
-
scopes: defaults.toolScopes,
|
|
143
|
-
} : undefined,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return option;
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const providerIntegration = (provider) => {
|
|
151
|
-
const option = providerConnectionOption(provider);
|
|
152
|
-
return {
|
|
153
|
-
id: provider.slug,
|
|
154
|
-
kind: option?.provider ?? "http",
|
|
155
|
-
name: provider.name,
|
|
156
|
-
description: provider.description,
|
|
157
|
-
categories: provider.categories,
|
|
158
|
-
appUrl: provider.appUrl,
|
|
159
|
-
docsUrl: provider.docsUrl,
|
|
160
|
-
notes: provider.notes,
|
|
161
|
-
catalogStatus: provider.availability,
|
|
162
|
-
managedConnectorSlug: provider.managedConnectorSlug,
|
|
163
|
-
authStrategy: provider.authStrategy,
|
|
164
|
-
popularityRank: provider.popularityRank,
|
|
165
|
-
registrationDefaults: provider.registrationDefaults,
|
|
166
|
-
...(option ? { defaultConnectionOptionId: option.id, connectionOptions: [option] } : { connectionOptions: [] }),
|
|
167
|
-
};
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const mergeOptions = (left = [], right = []) => {
|
|
171
|
-
const options = new Map();
|
|
172
|
-
for (const option of left) options.set(option.id, option);
|
|
173
|
-
for (const option of right) {
|
|
174
|
-
if (!options.has(option.id)) options.set(option.id, option);
|
|
175
|
-
}
|
|
176
|
-
return [...options.values()];
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const mergeIntegration = (base, override) => {
|
|
180
|
-
const connectionOptions = mergeOptions(base.connectionOptions, override.connectionOptions);
|
|
181
|
-
return {
|
|
182
|
-
...base,
|
|
183
|
-
...override,
|
|
184
|
-
catalogStatus: base.catalogStatus ?? override.catalogStatus,
|
|
185
|
-
managedConnectorSlug: base.managedConnectorSlug ?? override.managedConnectorSlug,
|
|
186
|
-
authStrategy: base.authStrategy ?? override.authStrategy,
|
|
187
|
-
registrationDefaults: base.registrationDefaults ?? override.registrationDefaults,
|
|
188
|
-
connectionOptions,
|
|
189
|
-
defaultConnectionOptionId:
|
|
190
|
-
base.defaultConnectionOptionId ?? override.defaultConnectionOptionId ?? connectionOptions[0]?.id,
|
|
191
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Runtime integration catalog.
|
|
3
|
+
*
|
|
4
|
+
* The source of truth is the hand-authored `integrations/catalog/<id>.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 { INTEGRATION_CATALOG_ENTRIES } from "./catalog-index.js";
|
|
9
|
+
|
|
10
|
+
const INTEGRATIONS = INTEGRATION_CATALOG_ENTRIES;
|
|
11
|
+
const INTEGRATION_BY_ID = new Map(INTEGRATIONS.map((entry) => [entry.id, entry]));
|
|
12
|
+
|
|
13
|
+
const entrySupportsMcp = (entry) =>
|
|
14
|
+
entry.connectionOptions.some((option) => option.provider === "mcp");
|
|
15
|
+
|
|
16
|
+
const entrySupportsOauth = (entry) =>
|
|
17
|
+
entry.connectionOptions.some((option) => option.auth?.strategy === "oauth2");
|
|
18
|
+
|
|
19
|
+
export const listIntegrationCatalog = (filter) => {
|
|
20
|
+
if (!filter) return INTEGRATIONS;
|
|
21
|
+
const { mcp, oauth } = filter;
|
|
22
|
+
if (mcp === undefined && oauth === undefined) return INTEGRATIONS;
|
|
23
|
+
return INTEGRATIONS.filter((entry) => {
|
|
24
|
+
const mcpOk = mcp === undefined || entrySupportsMcp(entry) === mcp;
|
|
25
|
+
const oauthOk = oauth === undefined || entrySupportsOauth(entry) === oauth;
|
|
26
|
+
return mcpOk && oauthOk;
|
|
27
|
+
});
|
|
192
28
|
};
|
|
193
29
|
|
|
194
|
-
const
|
|
195
|
-
for (const provider of listOAuthProviderCatalog().map(providerIntegration)) {
|
|
196
|
-
entriesById.set(provider.id, provider);
|
|
197
|
-
}
|
|
198
|
-
for (const direct of DIRECT_INTEGRATIONS) {
|
|
199
|
-
entriesById.set(
|
|
200
|
-
direct.id,
|
|
201
|
-
entriesById.has(direct.id)
|
|
202
|
-
? mergeIntegration(entriesById.get(direct.id), direct)
|
|
203
|
-
: direct,
|
|
204
|
-
);
|
|
205
|
-
}
|
|
30
|
+
export const getIntegrationCatalogEntry = (id) => INTEGRATION_BY_ID.get(id);
|
|
206
31
|
|
|
207
|
-
export const INTEGRATION_CATALOG =
|
|
208
|
-
const rankDelta = (b.popularityRank ?? 0) - (a.popularityRank ?? 0);
|
|
209
|
-
return rankDelta || a.name.localeCompare(b.name);
|
|
210
|
-
});
|
|
32
|
+
export const INTEGRATION_CATALOG = INTEGRATIONS;
|
|
211
33
|
|
|
212
34
|
export default INTEGRATION_CATALOG;
|
|
@@ -88,6 +88,19 @@
|
|
|
88
88
|
"openhands"
|
|
89
89
|
]
|
|
90
90
|
},
|
|
91
|
+
{
|
|
92
|
+
"name": "agent-canvas-environment",
|
|
93
|
+
"source": "./skills/agent-canvas-environment",
|
|
94
|
+
"description": "Work effectively inside a local Agent Canvas environment, including local agent-server auth, safe workspace hygiene, and local conversation delegation.",
|
|
95
|
+
"category": "development",
|
|
96
|
+
"keywords": [
|
|
97
|
+
"agent-canvas",
|
|
98
|
+
"openhands",
|
|
99
|
+
"local",
|
|
100
|
+
"conversation",
|
|
101
|
+
"delegation"
|
|
102
|
+
]
|
|
103
|
+
},
|
|
91
104
|
{
|
|
92
105
|
"name": "openhands-sdk",
|
|
93
106
|
"source": "./skills/openhands-sdk",
|
|
@@ -404,7 +417,7 @@
|
|
|
404
417
|
{
|
|
405
418
|
"name": "openhands-api",
|
|
406
419
|
"source": "./skills/openhands-api",
|
|
407
|
-
"description": "Use the OpenHands Cloud REST API (V1) to create and manage
|
|
420
|
+
"description": "Use the OpenHands Cloud REST API (V1) and agent-server APIs to create and manage Cloud or local backend conversations, including multi-conversation delegation workflows. Includes minimal Python and TypeScript clients under scripts/.",
|
|
408
421
|
"category": "development",
|
|
409
422
|
"keywords": [
|
|
410
423
|
"openhands",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openhands/extensions",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Public OpenHands extension catalogs for skills, plugins, integrations, and automation templates.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
"url": "https://github.com/OpenHands/extensions"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"build:skills": "node scripts/build-skills-catalog.mjs"
|
|
12
|
+
"build:skills": "node scripts/build-skills-catalog.mjs",
|
|
13
|
+
"build:integrations": "node scripts/build-integration-catalog.mjs",
|
|
14
|
+
"build": "npm run build:skills && npm run build:integrations"
|
|
13
15
|
},
|
|
14
16
|
"engines": {
|
|
15
17
|
"node": ">=18.20.0"
|
|
@@ -39,11 +41,6 @@
|
|
|
39
41
|
"import": "./integrations/index.js",
|
|
40
42
|
"default": "./integrations/index.js"
|
|
41
43
|
},
|
|
42
|
-
"./integrations/logos": {
|
|
43
|
-
"types": "./integrations/logos.d.ts",
|
|
44
|
-
"import": "./integrations/logos.js",
|
|
45
|
-
"default": "./integrations/logos.js"
|
|
46
|
-
},
|
|
47
44
|
"./integrations/catalog/*.json": "./integrations/catalog/*.json",
|
|
48
45
|
"./skills": {
|
|
49
46
|
"types": "./skills/index.d.ts",
|
|
@@ -36,11 +36,11 @@ plugins/cobol-modernization/
|
|
|
36
36
|
└── skills/ # Workflow phase skills
|
|
37
37
|
├── build-setup/ # Phase 1: Build environment
|
|
38
38
|
│ └── SKILL.md
|
|
39
|
-
├── cobol-modernization
|
|
39
|
+
├── cobol-modernization/ # Plugin overview
|
|
40
40
|
│ └── SKILL.md
|
|
41
41
|
├── mainframe-planning/ # Phase 2: Transformation planning
|
|
42
42
|
│ └── SKILL.md
|
|
43
|
-
├──
|
|
43
|
+
├── mainframe-removal/ # Phase 3: Mainframe dependency removal
|
|
44
44
|
│ ├── SKILL.md
|
|
45
45
|
│ └── references/
|
|
46
46
|
│ └── cics-transformation-examples.md
|
|
@@ -139,7 +139,7 @@ You can also run individual phases by using the specific skill definitions:
|
|
|
139
139
|
|
|
140
140
|
- See [skills/build-setup/SKILL.md](skills/build-setup/SKILL.md) for build setup only
|
|
141
141
|
- See [skills/mainframe-planning/SKILL.md](skills/mainframe-planning/SKILL.md) for planning
|
|
142
|
-
- See [skills/
|
|
142
|
+
- See [skills/mainframe-removal/SKILL.md](skills/mainframe-removal/SKILL.md) for mainframe removal
|
|
143
143
|
- See [skills/to-java-migration/SKILL.md](skills/to-java-migration/SKILL.md) for Java translation
|
|
144
144
|
|
|
145
145
|
## Troubleshooting
|
|
@@ -67,7 +67,7 @@ Creates a transformation guide without modifying code:
|
|
|
67
67
|
|
|
68
68
|
### Phase 3: Mainframe Removal
|
|
69
69
|
|
|
70
|
-
See [../
|
|
70
|
+
See [../mainframe-removal/SKILL.md](../mainframe-removal/SKILL.md)
|
|
71
71
|
|
|
72
72
|
Applies the transformation guide:
|
|
73
73
|
- Replaces EXEC CICS commands with file I/O
|
|
@@ -34,7 +34,7 @@ uv run python -m lc_sdk_examples.migration_scoring \
|
|
|
34
34
|
plugins/migration-scoring/
|
|
35
35
|
├── README.md # This file
|
|
36
36
|
└── skills/ # Workflow phase skills
|
|
37
|
-
├── migration-scoring
|
|
37
|
+
├── migration-scoring/ # Plugin overview
|
|
38
38
|
│ └── SKILL.md
|
|
39
39
|
├── migration-mapping/ # Phase 1: Source-to-target mapping
|
|
40
40
|
│ └── SKILL.md
|
package/pyproject.toml
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
[project]
|
|
2
|
-
name = "extensions"
|
|
3
|
-
version = "0.
|
|
4
|
-
description = "OpenHands extensions, plugins, and skills"
|
|
2
|
+
name = "openhands-extensions"
|
|
3
|
+
version = "0.6.0"
|
|
4
|
+
description = "OpenHands extensions, plugins, and skills (Python bindings for the integration catalog)"
|
|
5
5
|
requires-python = ">=3.12"
|
|
6
6
|
|
|
7
|
+
[build-system]
|
|
8
|
+
requires = ["hatchling>=1.21"]
|
|
9
|
+
build-backend = "hatchling.build"
|
|
10
|
+
|
|
11
|
+
[tool.hatch.build.targets.wheel]
|
|
12
|
+
packages = ["python/openhands_extensions"]
|
|
13
|
+
|
|
14
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
15
|
+
"integrations/catalog" = "openhands_extensions/catalog"
|
|
16
|
+
|
|
7
17
|
[dependency-groups]
|
|
8
18
|
test = [
|
|
9
19
|
"pytest>=8.0",
|
|
10
20
|
"requests>=2.31",
|
|
11
21
|
"openhands-sdk>=0.3",
|
|
12
22
|
]
|
|
23
|
+
|
|
24
|
+
[tool.pytest.ini_options]
|
|
25
|
+
pythonpath = ["python"]
|
|
26
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Python bindings for the OpenHands extensions catalogs.
|
|
2
|
+
|
|
3
|
+
Mirrors the JavaScript package (``@openhands/extensions``): both read the same
|
|
4
|
+
hand-authored ``integrations/catalog/<id>.json`` files. The JavaScript package
|
|
5
|
+
uses a generated static import index; the Python package loads the packaged
|
|
6
|
+
individual JSON files directly. See ``integrations.py`` for the catalog API,
|
|
7
|
+
including filtering by connector type (mcp / oauth).
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from ._version import __version__
|
|
13
|
+
from .integrations import (
|
|
14
|
+
INTEGRATION_CATALOG_SNAPSHOT,
|
|
15
|
+
get_integration_catalog_entry,
|
|
16
|
+
list_integration_catalog,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"INTEGRATION_CATALOG_SNAPSHOT",
|
|
21
|
+
"__version__",
|
|
22
|
+
"get_integration_catalog_entry",
|
|
23
|
+
"list_integration_catalog",
|
|
24
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Package version, derived from installed package metadata.
|
|
2
|
+
|
|
3
|
+
The single source of truth is ``pyproject.toml``'s ``[project].version``
|
|
4
|
+
(which ``release-please`` bumps together with ``package.json`` via
|
|
5
|
+
``release-please-config.json`` -> ``extra-files``). At runtime we read the
|
|
6
|
+
installed distribution metadata via ``importlib.metadata`` so there is no
|
|
7
|
+
second hand-maintained version string. ``_FALLBACK_VERSION`` is only used
|
|
8
|
+
when the package is imported without being installed (e.g. straight off a
|
|
9
|
+
source checkout with no build), and ``tests/test_version_alignment.py``
|
|
10
|
+
asserts it stays in lock-step with ``pyproject.toml`` / ``package.json``.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
16
|
+
|
|
17
|
+
#: Fallback used only when the package is not installed (no dist metadata).
|
|
18
|
+
#: Kept in lock-step with pyproject.toml/package.json by the version test.
|
|
19
|
+
_FALLBACK_VERSION = "0.6.0"
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
__version__: str = version("openhands-extensions")
|
|
23
|
+
except PackageNotFoundError: # not installed (e.g. raw source checkout)
|
|
24
|
+
__version__ = _FALLBACK_VERSION
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Python bindings for the OpenHands extensions integration catalog.
|
|
2
|
+
|
|
3
|
+
The source of truth is the hand-authored ``integrations/catalog/<id>.json``
|
|
4
|
+
directory. Wheels include those individual JSON files directly; no aggregate
|
|
5
|
+
catalog JSON is authored or packaged.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import copy
|
|
11
|
+
import json
|
|
12
|
+
from functools import lru_cache
|
|
13
|
+
from importlib import resources
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any, Iterable
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"INTEGRATION_CATALOG_SNAPSHOT",
|
|
19
|
+
"get_integration_catalog_entry",
|
|
20
|
+
"list_integration_catalog",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _repo_catalog_dir() -> Path:
|
|
25
|
+
return Path(__file__).resolve().parents[2] / "integrations" / "catalog"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _catalog_files() -> Iterable[Any]:
|
|
29
|
+
packaged = resources.files(__package__).joinpath("catalog")
|
|
30
|
+
if packaged.is_dir():
|
|
31
|
+
return sorted(
|
|
32
|
+
(path for path in packaged.iterdir() if path.name.endswith(".json")),
|
|
33
|
+
key=lambda path: path.name,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
repo_catalog = _repo_catalog_dir()
|
|
37
|
+
return sorted(repo_catalog.glob("*.json"), key=lambda path: path.name)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _read_json(path: Any) -> dict[str, Any]:
|
|
41
|
+
return json.loads(path.read_text(encoding="utf-8"))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@lru_cache(maxsize=1)
|
|
45
|
+
def _integrations() -> tuple[dict[str, Any], ...]:
|
|
46
|
+
entries = [_read_json(path) for path in _catalog_files()]
|
|
47
|
+
entries.sort(
|
|
48
|
+
key=lambda entry: (-(entry.get("popularityRank") if entry.get("popularityRank") is not None else -1), entry["id"]),
|
|
49
|
+
)
|
|
50
|
+
return tuple(entries)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@lru_cache(maxsize=1)
|
|
54
|
+
def _integration_by_id() -> dict[str, dict[str, Any]]:
|
|
55
|
+
return {entry["id"]: entry for entry in _integrations()}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _entry_supports_mcp(entry: dict[str, Any]) -> bool:
|
|
59
|
+
return any(option.get("provider") == "mcp" for option in entry.get("connectionOptions", []))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _entry_supports_oauth(entry: dict[str, Any]) -> bool:
|
|
63
|
+
return any(
|
|
64
|
+
option.get("auth", {}).get("strategy") == "oauth2"
|
|
65
|
+
for option in entry.get("connectionOptions", [])
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def list_integration_catalog(
|
|
70
|
+
mcp: bool | None = None,
|
|
71
|
+
oauth: bool | None = None,
|
|
72
|
+
) -> list[dict[str, Any]]:
|
|
73
|
+
"""Return the integration catalog, optionally filtered by connector type."""
|
|
74
|
+
result = []
|
|
75
|
+
for entry in _integrations():
|
|
76
|
+
if mcp is not None and _entry_supports_mcp(entry) != mcp:
|
|
77
|
+
continue
|
|
78
|
+
if oauth is not None and _entry_supports_oauth(entry) != oauth:
|
|
79
|
+
continue
|
|
80
|
+
result.append(copy.deepcopy(entry))
|
|
81
|
+
return result
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def get_integration_catalog_entry(id: str) -> dict[str, Any] | None:
|
|
85
|
+
"""Return one integration catalog entry by id, or ``None``."""
|
|
86
|
+
entry = _integration_by_id().get(id)
|
|
87
|
+
return copy.deepcopy(entry) if entry is not None else None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
INTEGRATION_CATALOG_SNAPSHOT: dict[str, Any] = {
|
|
91
|
+
"integrations": copy.deepcopy(list(_integrations()))
|
|
92
|
+
}
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"include-component-in-tag": false,
|
|
10
10
|
"skip-changelog": true,
|
|
11
11
|
"extra-files": [
|
|
12
|
-
{ "type": "toml", "path": "pyproject.toml", "jsonpath": "$.project.version" }
|
|
12
|
+
{ "type": "toml", "path": "pyproject.toml", "jsonpath": "$.project.version" },
|
|
13
|
+
"python/openhands_extensions/_version.py"
|
|
13
14
|
]
|
|
14
15
|
}
|
|
15
16
|
}
|