@openhands/extensions 0.16.0 → 0.17.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 +1 -0
- package/automations/README.md +75 -9
- package/automations/bundle-index.js +9 -0
- package/automations/catalog/github-pr-reviewer/manifest.json +23 -7
- package/automations/catalog/github-repo-monitor/manifest.json +28 -34
- package/automations/catalog/jira-issue-to-pr/manifest.json +3 -3
- package/automations/catalog.schema.json +102 -1
- package/automations/index.d.ts +48 -0
- package/automations/index.js +14 -0
- package/automations/interface.json +3 -1
- package/automations/interface.schema.json +6 -2
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/integrations/catalog/posthog.json +41 -3
- package/integrations/catalog/sonarqube.json +78 -0
- package/integrations/catalog-index.js +65 -63
- package/marketplaces/openhands-extensions.json +11 -0
- package/package.json +1 -1
- package/plugins/qa-changes/action.yml +1 -1
- package/pyproject.toml +1 -1
- package/python/openhands_extensions/_version.py +1 -1
- package/scripts/build-automation-catalog.mjs +30 -0
- package/scripts/build-skills-catalog.mjs +24 -7
- package/skills/add-skill/SKILL.md +1 -1
- package/skills/github-pr-reviewer/README.md +12 -6
- package/skills/github-pr-reviewer/SKILL.md +93 -31
- package/skills/github-pr-reviewer/commands/pr-reviewer-setup.md +1 -1
- package/skills/github-pr-reviewer/references/state-schema.md +68 -18
- package/skills/github-pr-reviewer/scripts/main.py +540 -103
- package/skills/github-pr-reviewer/tests/test_main.py +503 -0
- package/skills/index.d.ts +6 -0
- package/skills/index.js +29 -17
- package/skills/jira-issue-to-pr/scripts/main.py +4 -2
- package/skills/openhands-sdk/SKILL.md +2 -0
- package/skills/skill-creator/SKILL.md +1 -1
- package/skills/slack-channel-monitor/scripts/main.py +3 -2
- package/tests/fixtures/automations/capabilities.json +30 -0
- package/tests/fixtures/automations/github-pr-reviewer.json +319 -55
- package/tests/fixtures/automations/github-repo-monitor.json +153 -62
- package/tests/test_automation_setup.py +226 -31
- package/tests/test_catalogs.py +43 -0
- package/tests/test_skills_catalog.py +182 -36
- package/tests/test_slack_channel_monitor.py +1 -1
package/automations/index.d.ts
CHANGED
|
@@ -63,6 +63,11 @@ export interface AutomationFormField {
|
|
|
63
63
|
default?: string;
|
|
64
64
|
required: boolean;
|
|
65
65
|
provider?: AutomationGitProvider;
|
|
66
|
+
/**
|
|
67
|
+
* repo-picker only. The field collects several repositories rather than one,
|
|
68
|
+
* and its value is a list. A whole-value placeholder resolves to that list.
|
|
69
|
+
*/
|
|
70
|
+
multiple?: true;
|
|
66
71
|
options?: AutomationFieldOption[];
|
|
67
72
|
constraints?: AutomationFieldConstraints;
|
|
68
73
|
}
|
|
@@ -96,12 +101,40 @@ export interface AutomationForm {
|
|
|
96
101
|
args: AutomationFormFields;
|
|
97
102
|
}
|
|
98
103
|
|
|
104
|
+
/** A config.json leaf: templated string, number, boolean, null, or a nesting of those. */
|
|
105
|
+
export type AutomationBundleConfigValue =
|
|
106
|
+
| string
|
|
107
|
+
| number
|
|
108
|
+
| boolean
|
|
109
|
+
| null
|
|
110
|
+
| AutomationBundleConfigValue[]
|
|
111
|
+
| { [key: string]: AutomationBundleConfigValue };
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The script tarball a direct entry may ship instead of a prompt, for an
|
|
115
|
+
* automation that is deterministic machinery rather than judgement.
|
|
116
|
+
*/
|
|
117
|
+
export interface AutomationBundle {
|
|
118
|
+
/** The command run inside the extracted tarball. */
|
|
119
|
+
entrypoint: string;
|
|
120
|
+
/** Script run once before the entrypoint. Absent when nothing to install. */
|
|
121
|
+
setupScript?: string;
|
|
122
|
+
/** Seconds a run may take, when the service default is not enough. */
|
|
123
|
+
timeout?: number;
|
|
124
|
+
/** Packed path -> the repository path the file is read from at build time. */
|
|
125
|
+
files: Record<string, string>;
|
|
126
|
+
/** Rendered from the form and packed as config.json beside the entrypoint. */
|
|
127
|
+
config: Record<string, AutomationBundleConfigValue>;
|
|
128
|
+
}
|
|
129
|
+
|
|
99
130
|
export interface AutomationSetup {
|
|
100
131
|
version: "1.0";
|
|
101
132
|
mode: AutomationSetupMode;
|
|
102
133
|
form: AutomationForm;
|
|
103
134
|
/** direct only. What the automation is told to do. */
|
|
104
135
|
prompt?: string;
|
|
136
|
+
/** direct only, and the alternative to `prompt`. Exactly one is present. */
|
|
137
|
+
bundle?: AutomationBundle;
|
|
105
138
|
/** direct only, event trigger only. Which delivered events belong to it. */
|
|
106
139
|
filter?: string;
|
|
107
140
|
/**
|
|
@@ -337,6 +370,10 @@ export interface AutomationInterfaceEndpoints {
|
|
|
337
370
|
validate: string;
|
|
338
371
|
createPrompt: string;
|
|
339
372
|
createPlugin: string;
|
|
373
|
+
/** The raw create endpoint, which a bundle entry is created through. */
|
|
374
|
+
createBundle: string;
|
|
375
|
+
/** Where a bundle's tarball is uploaded before that create call. */
|
|
376
|
+
uploads: string;
|
|
340
377
|
}
|
|
341
378
|
|
|
342
379
|
export interface AutomationInterfaceManifest {
|
|
@@ -365,4 +402,15 @@ export function listAutomationCatalog(): RecommendedAutomation[];
|
|
|
365
402
|
export function getAutomationCatalogEntry(
|
|
366
403
|
id: string,
|
|
367
404
|
): RecommendedAutomation | undefined;
|
|
405
|
+
/**
|
|
406
|
+
* Return the files a bundle entry ships, keyed by the path each takes inside
|
|
407
|
+
* the tarball, as an independent copy. Undefined for an entry with no bundle.
|
|
408
|
+
*
|
|
409
|
+
* The contents are inlined at build time from the repository paths
|
|
410
|
+
* `setup.bundle.files` names, because a host packing the tarball has the
|
|
411
|
+
* published package but not the repository.
|
|
412
|
+
*/
|
|
413
|
+
export function getAutomationBundleFiles(
|
|
414
|
+
id: string,
|
|
415
|
+
): Record<string, string> | undefined;
|
|
368
416
|
export default AUTOMATION_CATALOG;
|
package/automations/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* directory. `catalog-index.js` is generated from that directory so the JS
|
|
6
6
|
* package can statically import each JSON file without an aggregate JSON asset.
|
|
7
7
|
*/
|
|
8
|
+
import { AUTOMATION_BUNDLE_FILES } from "./bundle-index.js";
|
|
8
9
|
import { AUTOMATION_CATALOG_ENTRIES } from "./catalog-index.js";
|
|
9
10
|
import interfaceManifest from "./interface.json" with { type: "json" };
|
|
10
11
|
|
|
@@ -21,6 +22,19 @@ export const getAutomationCatalogEntry = (id) => {
|
|
|
21
22
|
|
|
22
23
|
export const AUTOMATION_CATALOG = clone(AUTOMATIONS);
|
|
23
24
|
|
|
25
|
+
/**
|
|
26
|
+
* The files a bundle entry ships, keyed by entry id and then by the path each
|
|
27
|
+
* file takes inside the tarball. Generated from the repository paths the
|
|
28
|
+
* entry's `setup.bundle.files` names, because a host packing the tarball has
|
|
29
|
+
* the package but not the repository.
|
|
30
|
+
*
|
|
31
|
+
* Absent for every entry that does not ship a bundle.
|
|
32
|
+
*/
|
|
33
|
+
export const getAutomationBundleFiles = (id) => {
|
|
34
|
+
const files = AUTOMATION_BUNDLE_FILES[id];
|
|
35
|
+
return files ? clone(files) : undefined;
|
|
36
|
+
};
|
|
37
|
+
|
|
24
38
|
/**
|
|
25
39
|
* The production Automation interface manifest: the domain-level facts of the
|
|
26
40
|
* interface, hand-authored in `automations/interface.json`.
|
|
@@ -144,7 +144,9 @@
|
|
|
144
144
|
"capabilities": "/v1/capabilities",
|
|
145
145
|
"validate": "/v1/validate",
|
|
146
146
|
"createPrompt": "/v1/preset/prompt",
|
|
147
|
-
"createPlugin": "/v1/preset/plugin"
|
|
147
|
+
"createPlugin": "/v1/preset/plugin",
|
|
148
|
+
"createBundle": "/v1",
|
|
149
|
+
"uploads": "/v1/uploads"
|
|
148
150
|
},
|
|
149
151
|
"featuredAutomationIds": [
|
|
150
152
|
"github-pr-reviewer",
|
|
@@ -178,7 +178,9 @@
|
|
|
178
178
|
"capabilities",
|
|
179
179
|
"validate",
|
|
180
180
|
"createPrompt",
|
|
181
|
-
"createPlugin"
|
|
181
|
+
"createPlugin",
|
|
182
|
+
"createBundle",
|
|
183
|
+
"uploads"
|
|
182
184
|
],
|
|
183
185
|
"properties": {
|
|
184
186
|
"list": { "$ref": "#/$defs/plainEndpoint" },
|
|
@@ -190,7 +192,9 @@
|
|
|
190
192
|
"capabilities": { "$ref": "#/$defs/plainEndpoint" },
|
|
191
193
|
"validate": { "$ref": "#/$defs/plainEndpoint" },
|
|
192
194
|
"createPrompt": { "$ref": "#/$defs/plainEndpoint" },
|
|
193
|
-
"createPlugin": { "$ref": "#/$defs/plainEndpoint" }
|
|
195
|
+
"createPlugin": { "$ref": "#/$defs/plainEndpoint" },
|
|
196
|
+
"createBundle": { "$ref": "#/$defs/plainEndpoint" },
|
|
197
|
+
"uploads": { "$ref": "#/$defs/plainEndpoint" }
|
|
194
198
|
}
|
|
195
199
|
},
|
|
196
200
|
"featuredAutomationIds": {
|
package/index.d.ts
CHANGED
|
@@ -42,5 +42,5 @@ export type {
|
|
|
42
42
|
AutomationInterfacePages,
|
|
43
43
|
AutomationInterfaceRoutes,
|
|
44
44
|
} from "./automations/index.js";
|
|
45
|
-
export { SKILLS_CATALOG } from "./skills/index.js";
|
|
45
|
+
export { SKILLS_CATALOG, DEFAULT_ENABLED_SKILL_NAMES } from "./skills/index.js";
|
|
46
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
2
|
export { AUTOMATION_CATALOG, AUTOMATION_INTERFACE } from "./automations/index.js";
|
|
3
|
-
export { SKILLS_CATALOG } from "./skills/index.js";
|
|
3
|
+
export { SKILLS_CATALOG, DEFAULT_ENABLED_SKILL_NAMES } from "./skills/index.js";
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
],
|
|
9
9
|
"appUrl": "https://posthog.com",
|
|
10
10
|
"docsUrl": "https://posthog.com/docs/model-context-protocol",
|
|
11
|
-
"notes": "
|
|
11
|
+
"notes": "Uses PostHog's official hosted MCP server. OAuth is preferred; the bearer-token option remains for clients or deployments that require a personal API key. The OAuth URL defaults to read-only mode; remove readonly=true only when write access has been approved.",
|
|
12
12
|
"popularityRank": 37,
|
|
13
13
|
"iconBg": "#1D4AFF",
|
|
14
14
|
"logoUrl": "https://cdn.simpleicons.org/posthog/FFFFFF",
|
|
@@ -18,8 +18,44 @@
|
|
|
18
18
|
"product",
|
|
19
19
|
"experiments"
|
|
20
20
|
],
|
|
21
|
-
"installHint": "
|
|
21
|
+
"installHint": "Prefer OAuth. The default OAuth connection uses read-only MCP mode; edit the URL or use the bearer-key fallback only when a workflow needs approved write access. For API keys, create a PostHog personal API key with the MCP Server preset.",
|
|
22
22
|
"connectionOptions": [
|
|
23
|
+
{
|
|
24
|
+
"id": "oauth",
|
|
25
|
+
"provider": "mcp",
|
|
26
|
+
"auth": {
|
|
27
|
+
"strategy": "oauth2",
|
|
28
|
+
"oauth": {
|
|
29
|
+
"authorizationUrl": "https://oauth.posthog.com/oauth/authorize/",
|
|
30
|
+
"tokenUrl": "https://oauth.posthog.com/oauth/token/",
|
|
31
|
+
"registrationUrl": "https://oauth.posthog.com/oauth/register/",
|
|
32
|
+
"scopes": [
|
|
33
|
+
"openid",
|
|
34
|
+
"profile",
|
|
35
|
+
"email",
|
|
36
|
+
"organization:read",
|
|
37
|
+
"project:read",
|
|
38
|
+
"dashboard:read",
|
|
39
|
+
"insight:read",
|
|
40
|
+
"query:read",
|
|
41
|
+
"event_definition:read"
|
|
42
|
+
],
|
|
43
|
+
"pkce": true,
|
|
44
|
+
"clientAuthentication": "none",
|
|
45
|
+
"additionalAuthorizationParams": {
|
|
46
|
+
"resource": "https://mcp.posthog.com/mcp"
|
|
47
|
+
},
|
|
48
|
+
"additionalTokenParams": {
|
|
49
|
+
"resource": "https://mcp.posthog.com/mcp"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"transport": {
|
|
54
|
+
"kind": "shttp",
|
|
55
|
+
"url": "https://mcp.posthog.com/mcp?readonly=true",
|
|
56
|
+
"urlEditable": true
|
|
57
|
+
}
|
|
58
|
+
},
|
|
23
59
|
{
|
|
24
60
|
"id": "api-key",
|
|
25
61
|
"provider": "mcp",
|
|
@@ -31,7 +67,9 @@
|
|
|
31
67
|
"strategy": "bearer",
|
|
32
68
|
"credentialLabel": "PostHog personal API key",
|
|
33
69
|
"credentialPlaceholder": "Paste your PostHog personal API key",
|
|
34
|
-
"credentialHelp": "Create one under PostHog
|
|
70
|
+
"credentialHelp": "Create one under PostHog > User settings > API keys using the MCP Server preset. Sent as Authorization: Bearer <token>.",
|
|
71
|
+
"credentialSecretName": "POSTHOG_PERSONAL_API_KEY",
|
|
72
|
+
"saveCredentialAsSecretByDefault": true
|
|
35
73
|
}
|
|
36
74
|
}
|
|
37
75
|
]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "sonarqube",
|
|
3
|
+
"name": "SonarQube",
|
|
4
|
+
"description": "Inspect code quality and security findings, quality gates, and analyze code snippets from SonarQube Server or Cloud.",
|
|
5
|
+
"categories": [
|
|
6
|
+
"Engineering",
|
|
7
|
+
"Security"
|
|
8
|
+
],
|
|
9
|
+
"appUrl": "https://www.sonarsource.com/products/sonarqube/mcp-server/",
|
|
10
|
+
"docsUrl": "https://github.com/SonarSource/sonarqube-mcp-server",
|
|
11
|
+
"notes": "Uses SonarSource's official SonarQube MCP Server, run locally as a Docker container. Provide a SonarQube user token. Set SONARQUBE_ORG for SonarQube Cloud, or SONARQUBE_URL for a self-managed SonarQube Server (or https://sonarqube.us for SonarQube Cloud US).",
|
|
12
|
+
"popularityRank": 43,
|
|
13
|
+
"installHint": "SONARQUBE_TOKEN is always required. For SonarQube Cloud, set your organization key in SONARQUBE_ORG. For a self-managed SonarQube Server, set SONARQUBE_URL to your server URL; for SonarQube Cloud US, set SONARQUBE_URL to https://sonarqube.us. Requires a container runtime such as Docker.",
|
|
14
|
+
"connectionOptions": [
|
|
15
|
+
{
|
|
16
|
+
"id": "api",
|
|
17
|
+
"provider": "mcp",
|
|
18
|
+
"transport": {
|
|
19
|
+
"kind": "stdio",
|
|
20
|
+
"serverName": "sonarqube",
|
|
21
|
+
"command": "docker",
|
|
22
|
+
"args": [
|
|
23
|
+
"run",
|
|
24
|
+
"--init",
|
|
25
|
+
"--pull=always",
|
|
26
|
+
"-i",
|
|
27
|
+
"--rm",
|
|
28
|
+
"-e",
|
|
29
|
+
"SONARQUBE_TOKEN",
|
|
30
|
+
"-e",
|
|
31
|
+
"SONARQUBE_ORG",
|
|
32
|
+
"-e",
|
|
33
|
+
"SONARQUBE_URL",
|
|
34
|
+
"sonarsource/sonarqube-mcp"
|
|
35
|
+
],
|
|
36
|
+
"envFields": [
|
|
37
|
+
{
|
|
38
|
+
"key": "SONARQUBE_TOKEN",
|
|
39
|
+
"label": "SonarQube token",
|
|
40
|
+
"type": "password",
|
|
41
|
+
"required": true,
|
|
42
|
+
"helperText": "User token generated in your SonarQube Server or Cloud account settings.",
|
|
43
|
+
"helperLink": "https://docs.sonarsource.com/sonarqube-cloud/managing-your-account/managing-tokens/"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"key": "SONARQUBE_ORG",
|
|
47
|
+
"label": "Organization key (SonarQube Cloud)",
|
|
48
|
+
"type": "text",
|
|
49
|
+
"required": false,
|
|
50
|
+
"placeholder": "my-org",
|
|
51
|
+
"helperText": "Required for SonarQube Cloud. Your organization key, found in SonarQube Cloud."
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"key": "SONARQUBE_URL",
|
|
55
|
+
"label": "Server URL (SonarQube Server)",
|
|
56
|
+
"type": "text",
|
|
57
|
+
"required": false,
|
|
58
|
+
"placeholder": "https://sonarqube.example.com",
|
|
59
|
+
"helperText": "Required for a self-managed SonarQube Server. For SonarQube Cloud US, use https://sonarqube.us."
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"auth": {
|
|
64
|
+
"strategy": "api_key"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"iconBg": "#126ED3",
|
|
69
|
+
"logoUrl": "https://cdn.simpleicons.org/sonarqubeserver/FFFFFF",
|
|
70
|
+
"keywords": [
|
|
71
|
+
"code quality",
|
|
72
|
+
"static analysis",
|
|
73
|
+
"security",
|
|
74
|
+
"sast",
|
|
75
|
+
"quality gate",
|
|
76
|
+
"sonarcloud"
|
|
77
|
+
]
|
|
78
|
+
}
|
|
@@ -14,69 +14,70 @@ import entry8 from "./catalog/elevenlabs.json" with { type: "json" };
|
|
|
14
14
|
import entry9 from "./catalog/bitbucket.json" with { type: "json" };
|
|
15
15
|
import entry10 from "./catalog/xero.json" with { type: "json" };
|
|
16
16
|
import entry11 from "./catalog/quickbooks.json" with { type: "json" };
|
|
17
|
-
import entry12 from "./catalog/
|
|
18
|
-
import entry13 from "./catalog/
|
|
19
|
-
import entry14 from "./catalog/
|
|
20
|
-
import entry15 from "./catalog/
|
|
21
|
-
import entry16 from "./catalog/
|
|
22
|
-
import entry17 from "./catalog/
|
|
23
|
-
import entry18 from "./catalog/
|
|
24
|
-
import entry19 from "./catalog/
|
|
25
|
-
import entry20 from "./catalog/
|
|
26
|
-
import entry21 from "./catalog/
|
|
27
|
-
import entry22 from "./catalog/
|
|
28
|
-
import entry23 from "./catalog/
|
|
29
|
-
import entry24 from "./catalog/
|
|
30
|
-
import entry25 from "./catalog/
|
|
31
|
-
import entry26 from "./catalog/
|
|
32
|
-
import entry27 from "./catalog/
|
|
33
|
-
import entry28 from "./catalog/
|
|
34
|
-
import entry29 from "./catalog/
|
|
35
|
-
import entry30 from "./catalog/
|
|
36
|
-
import entry31 from "./catalog/microsoft-
|
|
37
|
-
import entry32 from "./catalog/
|
|
38
|
-
import entry33 from "./catalog/
|
|
39
|
-
import entry34 from "./catalog/
|
|
40
|
-
import entry35 from "./catalog/
|
|
41
|
-
import entry36 from "./catalog/
|
|
42
|
-
import entry37 from "./catalog/
|
|
43
|
-
import entry38 from "./catalog/
|
|
44
|
-
import entry39 from "./catalog/
|
|
45
|
-
import entry40 from "./catalog/
|
|
46
|
-
import entry41 from "./catalog/
|
|
47
|
-
import entry42 from "./catalog/google-
|
|
48
|
-
import entry43 from "./catalog/
|
|
49
|
-
import entry44 from "./catalog/
|
|
50
|
-
import entry45 from "./catalog/
|
|
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/
|
|
56
|
-
import entry51 from "./catalog/cloudflare-
|
|
57
|
-
import entry52 from "./catalog/cloudflare-
|
|
58
|
-
import entry53 from "./catalog/cloudflare-
|
|
59
|
-
import entry54 from "./catalog/cloudflare-
|
|
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/
|
|
79
|
-
import entry74 from "./catalog/
|
|
17
|
+
import entry12 from "./catalog/sonarqube.json" with { type: "json" };
|
|
18
|
+
import entry13 from "./catalog/okta.json" with { type: "json" };
|
|
19
|
+
import entry14 from "./catalog/netlify.json" with { type: "json" };
|
|
20
|
+
import entry15 from "./catalog/vercel.json" with { type: "json" };
|
|
21
|
+
import entry16 from "./catalog/supabase.json" with { type: "json" };
|
|
22
|
+
import entry17 from "./catalog/posthog.json" with { type: "json" };
|
|
23
|
+
import entry18 from "./catalog/sentry.json" with { type: "json" };
|
|
24
|
+
import entry19 from "./catalog/datadog.json" with { type: "json" };
|
|
25
|
+
import entry20 from "./catalog/canva.json" with { type: "json" };
|
|
26
|
+
import entry21 from "./catalog/miro.json" with { type: "json" };
|
|
27
|
+
import entry22 from "./catalog/webflow.json" with { type: "json" };
|
|
28
|
+
import entry23 from "./catalog/zoom.json" with { type: "json" };
|
|
29
|
+
import entry24 from "./catalog/discord.json" with { type: "json" };
|
|
30
|
+
import entry25 from "./catalog/stripe.json" with { type: "json" };
|
|
31
|
+
import entry26 from "./catalog/intercom.json" with { type: "json" };
|
|
32
|
+
import entry27 from "./catalog/hubspot.json" with { type: "json" };
|
|
33
|
+
import entry28 from "./catalog/salesforce.json" with { type: "json" };
|
|
34
|
+
import entry29 from "./catalog/sharepoint.json" with { type: "json" };
|
|
35
|
+
import entry30 from "./catalog/onedrive.json" with { type: "json" };
|
|
36
|
+
import entry31 from "./catalog/microsoft-teams.json" with { type: "json" };
|
|
37
|
+
import entry32 from "./catalog/microsoft-outlook.json" with { type: "json" };
|
|
38
|
+
import entry33 from "./catalog/box.json" with { type: "json" };
|
|
39
|
+
import entry34 from "./catalog/airtable.json" with { type: "json" };
|
|
40
|
+
import entry35 from "./catalog/monday.json" with { type: "json" };
|
|
41
|
+
import entry36 from "./catalog/trello.json" with { type: "json" };
|
|
42
|
+
import entry37 from "./catalog/asana.json" with { type: "json" };
|
|
43
|
+
import entry38 from "./catalog/confluence.json" with { type: "json" };
|
|
44
|
+
import entry39 from "./catalog/jira.json" with { type: "json" };
|
|
45
|
+
import entry40 from "./catalog/google-calendar.json" with { type: "json" };
|
|
46
|
+
import entry41 from "./catalog/gmail.json" with { type: "json" };
|
|
47
|
+
import entry42 from "./catalog/google-sheets.json" with { type: "json" };
|
|
48
|
+
import entry43 from "./catalog/google-drive.json" with { type: "json" };
|
|
49
|
+
import entry44 from "./catalog/figma.json" with { type: "json" };
|
|
50
|
+
import entry45 from "./catalog/google-docs.json" with { type: "json" };
|
|
51
|
+
import entry46 from "./catalog/apify.json" with { type: "json" };
|
|
52
|
+
import entry47 from "./catalog/atlassian-rovo.json" with { type: "json" };
|
|
53
|
+
import entry48 from "./catalog/brave-search.json" with { type: "json" };
|
|
54
|
+
import entry49 from "./catalog/browser-mcp.json" with { type: "json" };
|
|
55
|
+
import entry50 from "./catalog/clickhouse.json" with { type: "json" };
|
|
56
|
+
import entry51 from "./catalog/cloudflare-bindings.json" with { type: "json" };
|
|
57
|
+
import entry52 from "./catalog/cloudflare-browser-rendering.json" with { type: "json" };
|
|
58
|
+
import entry53 from "./catalog/cloudflare-builds.json" with { type: "json" };
|
|
59
|
+
import entry54 from "./catalog/cloudflare-docs.json" with { type: "json" };
|
|
60
|
+
import entry55 from "./catalog/cloudflare-observability.json" with { type: "json" };
|
|
61
|
+
import entry56 from "./catalog/deepwiki.json" with { type: "json" };
|
|
62
|
+
import entry57 from "./catalog/everything.json" with { type: "json" };
|
|
63
|
+
import entry58 from "./catalog/exa.json" with { type: "json" };
|
|
64
|
+
import entry59 from "./catalog/fetch.json" with { type: "json" };
|
|
65
|
+
import entry60 from "./catalog/filesystem.json" with { type: "json" };
|
|
66
|
+
import entry61 from "./catalog/firecrawl.json" with { type: "json" };
|
|
67
|
+
import entry62 from "./catalog/git.json" with { type: "json" };
|
|
68
|
+
import entry63 from "./catalog/huggingface.json" with { type: "json" };
|
|
69
|
+
import entry64 from "./catalog/kagi.json" with { type: "json" };
|
|
70
|
+
import entry65 from "./catalog/memory.json" with { type: "json" };
|
|
71
|
+
import entry66 from "./catalog/mongodb.json" with { type: "json" };
|
|
72
|
+
import entry67 from "./catalog/neon.json" with { type: "json" };
|
|
73
|
+
import entry68 from "./catalog/obsidian.json" with { type: "json" };
|
|
74
|
+
import entry69 from "./catalog/paypal.json" with { type: "json" };
|
|
75
|
+
import entry70 from "./catalog/playwright.json" with { type: "json" };
|
|
76
|
+
import entry71 from "./catalog/redis.json" with { type: "json" };
|
|
77
|
+
import entry72 from "./catalog/resend.json" with { type: "json" };
|
|
78
|
+
import entry73 from "./catalog/sequential-thinking.json" with { type: "json" };
|
|
79
|
+
import entry74 from "./catalog/superhuman-mail.json" with { type: "json" };
|
|
80
|
+
import entry75 from "./catalog/time.json" with { type: "json" };
|
|
80
81
|
|
|
81
82
|
export const INTEGRATION_CATALOG_ENTRIES = [
|
|
82
83
|
entry0,
|
|
@@ -154,4 +155,5 @@ export const INTEGRATION_CATALOG_ENTRIES = [
|
|
|
154
155
|
entry72,
|
|
155
156
|
entry73,
|
|
156
157
|
entry74,
|
|
158
|
+
entry75,
|
|
157
159
|
];
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"source": "./skills/add-skill",
|
|
30
30
|
"description": "Add (import) an OpenHands skill from a GitHub repository into the current workspace.",
|
|
31
31
|
"category": "agent-authoring",
|
|
32
|
+
"defaultEnabled": true,
|
|
32
33
|
"keywords": [
|
|
33
34
|
"skill",
|
|
34
35
|
"import",
|
|
@@ -41,6 +42,7 @@
|
|
|
41
42
|
"source": "./skills/agent-memory",
|
|
42
43
|
"description": "Persist and retrieve repository-specific knowledge using AGENTS.md files. Use when you want to save important information about a codebase (build commands, code style, workflows) for future sessions.",
|
|
43
44
|
"category": "agent-authoring",
|
|
45
|
+
"defaultEnabled": true,
|
|
44
46
|
"keywords": [
|
|
45
47
|
"memory",
|
|
46
48
|
"knowledge",
|
|
@@ -53,6 +55,7 @@
|
|
|
53
55
|
"source": "./skills/agent-sdk-builder",
|
|
54
56
|
"description": "Guided workflow for building custom AI agents using the OpenHands Software Agent SDK. Use when you want to create a new agent through an interactive interview process that gathers requirements and generates implementation plans.",
|
|
55
57
|
"category": "agent-authoring",
|
|
58
|
+
"defaultEnabled": true,
|
|
56
59
|
"keywords": [
|
|
57
60
|
"agent",
|
|
58
61
|
"sdk",
|
|
@@ -80,6 +83,7 @@
|
|
|
80
83
|
"source": "./skills/openhands-automation",
|
|
81
84
|
"description": "Create and manage OpenHands automations - scheduled tasks that run in sandboxes. Use the prompt preset to create automations from natural language, or manage existing automations.",
|
|
82
85
|
"category": "automations",
|
|
86
|
+
"defaultEnabled": true,
|
|
83
87
|
"keywords": [
|
|
84
88
|
"automation",
|
|
85
89
|
"cron",
|
|
@@ -93,6 +97,7 @@
|
|
|
93
97
|
"source": "./skills/agent-canvas-environment",
|
|
94
98
|
"description": "Work effectively inside a local Agent Canvas environment, including local agent-server auth, safe workspace hygiene, and local conversation delegation.",
|
|
95
99
|
"category": "agent-authoring",
|
|
100
|
+
"defaultEnabled": true,
|
|
96
101
|
"keywords": [
|
|
97
102
|
"agent-canvas",
|
|
98
103
|
"openhands",
|
|
@@ -106,6 +111,7 @@
|
|
|
106
111
|
"source": "./skills/openhands-sdk",
|
|
107
112
|
"description": "Reference skill for the OpenHands Software Agent SDK - build AI agents with custom tools, LLM configuration, conversations, sub-agent delegation, MCP integration, security, and persistence.",
|
|
108
113
|
"category": "agent-authoring",
|
|
114
|
+
"defaultEnabled": true,
|
|
109
115
|
"keywords": [
|
|
110
116
|
"sdk",
|
|
111
117
|
"agent",
|
|
@@ -182,6 +188,7 @@
|
|
|
182
188
|
"source": "./skills/code-review",
|
|
183
189
|
"description": "Rigorous code review focusing on data structures, simplicity, security, pragmatism, and risk/safety evaluation. Provides brutally honest, actionable feedback on pull requests or merge requests, including a risk assessment for every review. Use when reviewing code changes.",
|
|
184
190
|
"category": "code-quality",
|
|
191
|
+
"defaultEnabled": true,
|
|
185
192
|
"keywords": [
|
|
186
193
|
"code-review",
|
|
187
194
|
"quality",
|
|
@@ -232,6 +239,7 @@
|
|
|
232
239
|
"source": "./skills/docker",
|
|
233
240
|
"description": "Run Docker commands within a container environment, including starting the Docker daemon and managing containers. Use when building, running, or managing Docker containers and images.",
|
|
234
241
|
"category": "environment",
|
|
242
|
+
"defaultEnabled": true,
|
|
235
243
|
"keywords": [
|
|
236
244
|
"docker",
|
|
237
245
|
"container",
|
|
@@ -268,6 +276,7 @@
|
|
|
268
276
|
"source": "./skills/github",
|
|
269
277
|
"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.",
|
|
270
278
|
"category": "code-hosting",
|
|
279
|
+
"defaultEnabled": true,
|
|
271
280
|
"keywords": [
|
|
272
281
|
"github",
|
|
273
282
|
"git",
|
|
@@ -444,6 +453,7 @@
|
|
|
444
453
|
"source": "./skills/openhands-api",
|
|
445
454
|
"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/.",
|
|
446
455
|
"category": "agent-authoring",
|
|
456
|
+
"defaultEnabled": true,
|
|
447
457
|
"keywords": [
|
|
448
458
|
"openhands",
|
|
449
459
|
"api",
|
|
@@ -534,6 +544,7 @@
|
|
|
534
544
|
"source": "./skills/skill-creator",
|
|
535
545
|
"description": "Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.",
|
|
536
546
|
"category": "agent-authoring",
|
|
547
|
+
"defaultEnabled": true,
|
|
537
548
|
"keywords": [
|
|
538
549
|
"skill",
|
|
539
550
|
"plugin",
|
package/package.json
CHANGED
|
@@ -160,7 +160,7 @@ runs:
|
|
|
160
160
|
# so we enforce the time limit via the coreutils timeout command.
|
|
161
161
|
TIMEOUT_SECONDS=$((TIMEOUT_MINUTES * 60))
|
|
162
162
|
timeout "${TIMEOUT_SECONDS}" \
|
|
163
|
-
uv run --no-project --with openhands-sdk --with openhands-tools --with
|
|
163
|
+
uv run --no-project --with openhands-sdk --with openhands-tools --with lmnr \
|
|
164
164
|
python ../extensions/plugins/qa-changes/scripts/agent_script.py
|
|
165
165
|
|
|
166
166
|
- name: Upload logs as artifact
|
package/pyproject.toml
CHANGED
|
@@ -18,7 +18,7 @@ from importlib.metadata import PackageNotFoundError, version
|
|
|
18
18
|
#: Kept in lock-step with pyproject.toml/package.json by the version test.
|
|
19
19
|
#: release-please only rewrites a semver found on the annotated line itself, so
|
|
20
20
|
#: the annotation must stay on the assignment; on its own line it is a no-op.
|
|
21
|
-
_FALLBACK_VERSION = "0.
|
|
21
|
+
_FALLBACK_VERSION = "0.17.0" # x-release-please-version
|
|
22
22
|
|
|
23
23
|
try:
|
|
24
24
|
__version__: str = version("openhands-extensions")
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
const root = process.cwd();
|
|
5
5
|
const catalogDir = path.join(root, "automations", "catalog");
|
|
6
6
|
const outputPath = path.join(root, "automations", "catalog-index.js");
|
|
7
|
+
const bundleOutputPath = path.join(root, "automations", "bundle-index.js");
|
|
7
8
|
|
|
8
9
|
const directories = (await readdir(catalogDir, { withFileTypes: true }))
|
|
9
10
|
.filter((entry) => entry.isDirectory())
|
|
@@ -37,6 +38,25 @@ const imports = indexedAutomations
|
|
|
37
38
|
.join("\n");
|
|
38
39
|
const entries = indexedAutomations.map(({ importName }) => ` ${importName},`).join("\n");
|
|
39
40
|
|
|
41
|
+
// A bundle entry names its files by repository-relative path, so the one copy
|
|
42
|
+
// of a script shipped by both a skill and the catalog stays in one place. The
|
|
43
|
+
// package cannot ship a path, though - a browser host has no repository - so
|
|
44
|
+
// the contents are inlined here at build time.
|
|
45
|
+
const bundles = {};
|
|
46
|
+
for (const { entry } of automations) {
|
|
47
|
+
const files = entry.setup?.bundle?.files;
|
|
48
|
+
if (!files) continue;
|
|
49
|
+
bundles[entry.id] = {};
|
|
50
|
+
for (const [packedPath, source] of Object.entries(files).sort()) {
|
|
51
|
+
if (!/^(skills|automations)\//.test(source) || source.includes("..")) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`${entry.id}: bundle file "${packedPath}" names ${source}, which is outside skills/ or automations/`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
bundles[entry.id][packedPath] = await readFile(path.join(root, source), "utf8");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
40
60
|
const header = `// This file is auto-generated by scripts/build-automation-catalog.mjs.
|
|
41
61
|
// Do not edit it manually. To update it after changing automations/catalog/*/manifest.json,
|
|
42
62
|
// run: npm run build:automations
|
|
@@ -49,3 +69,13 @@ ${entries}
|
|
|
49
69
|
];
|
|
50
70
|
`;
|
|
51
71
|
await writeFile(outputPath, body);
|
|
72
|
+
|
|
73
|
+
const bundleHeader = `// This file is auto-generated by scripts/build-automation-catalog.mjs.
|
|
74
|
+
// Do not edit it manually. It inlines the files each bundle entry ships, read from
|
|
75
|
+
// the repository paths its manifest names. To update it, run: npm run build:automations
|
|
76
|
+
|
|
77
|
+
`;
|
|
78
|
+
await writeFile(
|
|
79
|
+
bundleOutputPath,
|
|
80
|
+
`${bundleHeader}export const AUTOMATION_BUNDLE_FILES = ${JSON.stringify(bundles, null, 2)};\n`,
|
|
81
|
+
);
|