@openhands/extensions 0.5.0 → 0.7.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 +34 -4
- package/integrations/README.md +25 -9
- package/integrations/catalog/airtable.json +16 -10
- package/integrations/catalog/apify.json +0 -2
- package/integrations/catalog/asana.json +33 -0
- package/integrations/catalog/atlassian.json +5 -8
- package/integrations/catalog/bitbucket.json +34 -0
- package/integrations/catalog/box.json +34 -0
- package/integrations/catalog/brave-search.json +1 -2
- package/integrations/catalog/browser-mcp.json +0 -3
- package/integrations/catalog/canva.json +31 -0
- package/integrations/catalog/clickhouse.json +1 -2
- 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 +33 -0
- package/integrations/catalog/datadog.json +34 -0
- package/integrations/catalog/deepwiki.json +3 -7
- package/integrations/catalog/discord.json +34 -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 +35 -9
- package/integrations/catalog/filesystem.json +0 -3
- package/integrations/catalog/firecrawl.json +0 -2
- package/integrations/catalog/git.json +0 -3
- package/integrations/catalog/github.json +34 -10
- package/integrations/catalog/gmail.json +33 -0
- package/integrations/catalog/google-calendar.json +33 -0
- package/integrations/catalog/google-docs.json +33 -0
- package/integrations/catalog/google-drive.json +33 -0
- package/integrations/catalog/google-sheets.json +33 -0
- package/integrations/catalog/hubspot.json +34 -0
- package/integrations/catalog/huggingface.json +1 -2
- package/integrations/catalog/intercom.json +34 -0
- package/integrations/catalog/jira.json +33 -0
- package/integrations/catalog/kagi.json +2 -3
- package/integrations/catalog/linear.json +24 -16
- package/integrations/catalog/memory.json +0 -2
- package/integrations/catalog/microsoft-outlook.json +33 -0
- package/integrations/catalog/microsoft-teams.json +33 -0
- package/integrations/catalog/miro.json +42 -0
- package/integrations/catalog/monday.json +42 -0
- package/integrations/catalog/mongodb.json +1 -2
- package/integrations/catalog/neon.json +0 -2
- package/integrations/catalog/netlify.json +33 -0
- package/integrations/catalog/notion.json +30 -10
- package/integrations/catalog/obsidian.json +1 -3
- package/integrations/catalog/okta.json +33 -0
- package/integrations/catalog/onedrive.json +33 -0
- package/integrations/catalog/ordinal.json +33 -0
- package/integrations/catalog/paypal.json +5 -8
- package/integrations/catalog/playwright.json +0 -2
- package/integrations/catalog/posthog.json +38 -0
- package/integrations/catalog/quickbooks.json +86 -0
- package/integrations/catalog/redis.json +1 -3
- package/integrations/catalog/resend.json +1 -2
- package/integrations/catalog/salesforce.json +44 -0
- package/integrations/catalog/sentry.json +47 -14
- package/integrations/catalog/sequential-thinking.json +0 -2
- package/integrations/catalog/sharepoint.json +33 -0
- package/integrations/catalog/slack.json +49 -10
- package/integrations/catalog/stripe.json +39 -14
- package/integrations/catalog/supabase.json +31 -9
- package/integrations/catalog/tavily.json +0 -2
- package/integrations/catalog/time.json +0 -2
- package/integrations/catalog/trello.json +34 -0
- package/integrations/catalog/vercel.json +33 -0
- package/integrations/catalog/webflow.json +34 -0
- package/integrations/catalog/xero.json +33 -0
- package/integrations/catalog/zoom.json +33 -0
- package/integrations/catalog-index.js +151 -0
- package/integrations/catalog.schema.json +255 -0
- package/integrations/index.d.ts +49 -69
- package/integrations/index.js +36 -206
- package/marketplaces/openhands-extensions.json +40 -2
- 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/plugins/pr-review/scripts/prompt.py +1 -1
- package/pyproject.toml +18 -3
- package/python/openhands_extensions/__init__.py +24 -0
- package/python/openhands_extensions/_version.py +25 -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 +202 -0
- package/skills/bitbucket/README.md +23 -40
- package/skills/bitbucket/SKILL.md +43 -31
- package/skills/bitbucket-cloud/.plugin/plugin.json +18 -0
- package/skills/bitbucket-cloud/README.md +15 -0
- package/skills/bitbucket-cloud/SKILL.md +46 -0
- package/skills/bitbucket-data-center/.plugin/plugin.json +19 -0
- package/skills/bitbucket-data-center/README.md +20 -0
- package/skills/bitbucket-data-center/SKILL.md +53 -0
- package/skills/code-review/SKILL.md +1 -1
- package/skills/code-review/references/supply-chain-security.md +2 -2
- 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 +34 -8
- 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 -3
- 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_catalog_schema.py +47 -0
- package/tests/test_catalogs.py +47 -3
- package/tests/test_integration_catalog_in_sync.py +252 -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
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
SCRIPT_PATH = (
|
|
6
|
+
Path(__file__).parent.parent
|
|
7
|
+
/ "skills"
|
|
8
|
+
/ "slack-channel-monitor"
|
|
9
|
+
/ "scripts"
|
|
10
|
+
/ "main.py"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def load_slack_monitor_helpers():
|
|
15
|
+
os.environ["WORKSPACE_BASE"] = "/tmp/openhands/workspaces/slack-monitor-test/run"
|
|
16
|
+
source = SCRIPT_PATH.read_text(encoding="utf-8")
|
|
17
|
+
helper_source = source.split("\nPOLL_ITERATIONS = 10", 1)[0]
|
|
18
|
+
namespace: dict = {}
|
|
19
|
+
exec(compile(helper_source, str(SCRIPT_PATH), "exec"), namespace)
|
|
20
|
+
return namespace
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_post_message_sends_markdown_text(monkeypatch):
|
|
24
|
+
helpers = load_slack_monitor_helpers()
|
|
25
|
+
posted: dict = {}
|
|
26
|
+
|
|
27
|
+
def fake_slack_post(token: str, endpoint: str, body: dict) -> dict:
|
|
28
|
+
posted["token"] = token
|
|
29
|
+
posted["endpoint"] = endpoint
|
|
30
|
+
posted["body"] = body
|
|
31
|
+
return {"ts": "123.456"}
|
|
32
|
+
|
|
33
|
+
monkeypatch.setitem(helpers, "slack_post", fake_slack_post)
|
|
34
|
+
markdown_summary = "✅ Done!\n\n- **Bold:** [link](https://example.com)"
|
|
35
|
+
|
|
36
|
+
ts = helpers["post_message"](
|
|
37
|
+
"xoxb-test",
|
|
38
|
+
"C123",
|
|
39
|
+
markdown_summary,
|
|
40
|
+
thread_ts="111.222",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
assert ts == "123.456"
|
|
44
|
+
assert posted["endpoint"] == "chat.postMessage"
|
|
45
|
+
assert posted["body"] == {
|
|
46
|
+
"channel": "C123",
|
|
47
|
+
"markdown_text": markdown_summary,
|
|
48
|
+
"unfurl_links": False,
|
|
49
|
+
"unfurl_media": False,
|
|
50
|
+
"thread_ts": "111.222",
|
|
51
|
+
}
|
|
52
|
+
assert "text" not in posted["body"]
|
|
53
|
+
assert "blocks" not in posted["body"]
|
|
54
|
+
assert "mrkdwn" not in posted["body"]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_followup_quiet_poll_is_capped_at_watch_expiry(monkeypatch):
|
|
58
|
+
helpers = load_slack_monitor_helpers()
|
|
59
|
+
monkeypatch.setattr(helpers["time"], "time", lambda: 950.0)
|
|
60
|
+
calls: list[tuple[str, str, str]] = []
|
|
61
|
+
|
|
62
|
+
def fake_thread_replies(
|
|
63
|
+
token: str,
|
|
64
|
+
channel: str,
|
|
65
|
+
thread_ts: str,
|
|
66
|
+
oldest: str,
|
|
67
|
+
) -> list[dict]:
|
|
68
|
+
calls.append((channel, thread_ts, oldest))
|
|
69
|
+
return []
|
|
70
|
+
|
|
71
|
+
monkeypatch.setitem(helpers, "thread_replies", fake_thread_replies)
|
|
72
|
+
rec = {
|
|
73
|
+
"channel_id": "C123",
|
|
74
|
+
"thread_ts": "900.000000",
|
|
75
|
+
"status": "watching",
|
|
76
|
+
"last_seen_reply_ts": "900.000000",
|
|
77
|
+
"reply_poll_backoff_seconds": 80,
|
|
78
|
+
"next_reply_poll_at": 950.0,
|
|
79
|
+
"watch_until": 1000.0,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
replies = helpers["_poll_due_thread_replies"](
|
|
83
|
+
"xoxb-test",
|
|
84
|
+
{"C123:900.000000": rec},
|
|
85
|
+
"UBOT",
|
|
86
|
+
[],
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
assert replies == []
|
|
90
|
+
assert calls == [("C123", "900.000000", "900.000000")]
|
|
91
|
+
assert rec["status"] == "watching"
|
|
92
|
+
assert rec["next_reply_poll_at"] == 1000.0
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_expired_followup_watch_polls_once_before_closing(monkeypatch):
|
|
96
|
+
helpers = load_slack_monitor_helpers()
|
|
97
|
+
monkeypatch.setattr(helpers["time"], "time", lambda: 1001.0)
|
|
98
|
+
trigger = helpers["TRIGGER_PHRASE"]
|
|
99
|
+
reply = {
|
|
100
|
+
"ts": "999.500000",
|
|
101
|
+
"user": "U1",
|
|
102
|
+
"text": f"{trigger} please continue",
|
|
103
|
+
}
|
|
104
|
+
calls: list[tuple[str, str, str]] = []
|
|
105
|
+
|
|
106
|
+
def fake_thread_replies(
|
|
107
|
+
token: str,
|
|
108
|
+
channel: str,
|
|
109
|
+
thread_ts: str,
|
|
110
|
+
oldest: str,
|
|
111
|
+
) -> list[dict]:
|
|
112
|
+
calls.append((channel, thread_ts, oldest))
|
|
113
|
+
return [reply]
|
|
114
|
+
|
|
115
|
+
monkeypatch.setitem(helpers, "thread_replies", fake_thread_replies)
|
|
116
|
+
rec = {
|
|
117
|
+
"channel_id": "C123",
|
|
118
|
+
"thread_ts": "900.000000",
|
|
119
|
+
"status": "watching",
|
|
120
|
+
"last_seen_reply_ts": "900.000000",
|
|
121
|
+
"reply_poll_backoff_seconds": 160,
|
|
122
|
+
"next_reply_poll_at": 1100.0,
|
|
123
|
+
"watch_until": 1000.0,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
replies = helpers["_poll_due_thread_replies"](
|
|
127
|
+
"xoxb-test",
|
|
128
|
+
{"C123:900.000000": rec},
|
|
129
|
+
"UBOT",
|
|
130
|
+
[],
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
assert calls == [("C123", "900.000000", "900.000000")]
|
|
134
|
+
assert replies == [("C123", reply)]
|
|
135
|
+
assert rec["last_seen_reply_ts"] == "999.500000"
|
|
136
|
+
assert (
|
|
137
|
+
rec["reply_poll_backoff_seconds"]
|
|
138
|
+
== helpers["THREAD_REPLY_INITIAL_BACKOFF_SECONDS"]
|
|
139
|
+
)
|
|
140
|
+
assert rec["next_reply_poll_at"] == 1006.0
|
|
141
|
+
assert rec["watch_until"] == 1301.0
|
|
142
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Assert the JS (``package.json``) and Python (``pyproject.toml`` +
|
|
2
|
+
``_version.py``) package versions never drift apart.
|
|
3
|
+
|
|
4
|
+
``release-please`` is configured to bump both ``package.json`` and
|
|
5
|
+
``pyproject.toml`` together (see ``release-please-config.json`` ->
|
|
6
|
+
``extra-files``). This test is the guard that catches a manual edit that
|
|
7
|
+
bumps only one.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _package_json_version() -> str:
|
|
19
|
+
text = (ROOT / "package.json").read_text()
|
|
20
|
+
match = re.search(r'"version"\s*:\s*"([^"]+)"', text)
|
|
21
|
+
assert match, "package.json has no version field"
|
|
22
|
+
return match.group(1)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _pyproject_version() -> str:
|
|
26
|
+
text = (ROOT / "pyproject.toml").read_text()
|
|
27
|
+
match = re.search(r'^version\s*=\s*"([^"]+)"', text, re.MULTILINE)
|
|
28
|
+
assert match, "pyproject.toml has no version field"
|
|
29
|
+
return match.group(1)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _version_module_version() -> str:
|
|
33
|
+
import openhands_extensions._version as v
|
|
34
|
+
|
|
35
|
+
text = (ROOT / "python" / "openhands_extensions" / "_version.py").read_text()
|
|
36
|
+
match = re.search(r'_FALLBACK_VERSION\s*=\s*"([^"]+)"', text)
|
|
37
|
+
assert match, "_version.py has no _FALLBACK_VERSION"
|
|
38
|
+
fallback = match.group(1)
|
|
39
|
+
# Runtime __version__ is metadata-derived when installed, fallback otherwise;
|
|
40
|
+
# both must agree with the declared versions.
|
|
41
|
+
assert v.__version__ in (fallback, _package_json_version()), (
|
|
42
|
+
f"runtime __version__ {v.__version__!r} disagrees with fallback/package.json"
|
|
43
|
+
)
|
|
44
|
+
return fallback
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_package_json_and_pyproject_versions_match() -> None:
|
|
48
|
+
assert _package_json_version() == _pyproject_version(), (
|
|
49
|
+
"package.json and pyproject.toml versions differ. release-please "
|
|
50
|
+
"should bump both together; check release-please-config.json."
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_version_module_matches_package_json() -> None:
|
|
55
|
+
assert _version_module_version() == _package_json_version(), (
|
|
56
|
+
"python/openhands_extensions/_version.py is out of sync with "
|
|
57
|
+
"package.json."
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_installed_package_version_matches_source() -> None:
|
|
62
|
+
import openhands_extensions
|
|
63
|
+
|
|
64
|
+
assert openhands_extensions.__version__ == _package_json_version()
|
package/integrations/logos.d.ts
DELETED
package/integrations/logos.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { createElement } from "react";
|
|
2
|
-
import {
|
|
3
|
-
BookOpen,
|
|
4
|
-
Bot,
|
|
5
|
-
Brain,
|
|
6
|
-
Clock,
|
|
7
|
-
Database,
|
|
8
|
-
Flame,
|
|
9
|
-
Folder,
|
|
10
|
-
GitBranch,
|
|
11
|
-
Globe,
|
|
12
|
-
ListTree,
|
|
13
|
-
MousePointerClick,
|
|
14
|
-
Search,
|
|
15
|
-
Sparkles,
|
|
16
|
-
Telescope,
|
|
17
|
-
TestTube,
|
|
18
|
-
} from "lucide-react";
|
|
19
|
-
import {
|
|
20
|
-
SiAirtable,
|
|
21
|
-
SiAtlassian,
|
|
22
|
-
SiBrave,
|
|
23
|
-
SiClickhouse,
|
|
24
|
-
SiCloudflare,
|
|
25
|
-
SiElevenlabs,
|
|
26
|
-
SiFigma,
|
|
27
|
-
SiGithub,
|
|
28
|
-
SiHuggingface,
|
|
29
|
-
SiKagi,
|
|
30
|
-
SiLinear,
|
|
31
|
-
SiMongodb,
|
|
32
|
-
SiNotion,
|
|
33
|
-
SiObsidian,
|
|
34
|
-
SiPaypal,
|
|
35
|
-
SiRedis,
|
|
36
|
-
SiResend,
|
|
37
|
-
SiSentry,
|
|
38
|
-
SiSlack,
|
|
39
|
-
SiStripe,
|
|
40
|
-
SiSupabase,
|
|
41
|
-
} from "react-icons/si";
|
|
42
|
-
|
|
43
|
-
const LOGO = "h-5 w-5";
|
|
44
|
-
|
|
45
|
-
const simpleIcon = (Icon) => createElement(Icon, { className: LOGO });
|
|
46
|
-
const lucideIcon = (Icon) =>
|
|
47
|
-
createElement(Icon, { className: LOGO, strokeWidth: 2.25 });
|
|
48
|
-
|
|
49
|
-
export const INTEGRATION_FALLBACK_LOGO = lucideIcon(Bot);
|
|
50
|
-
|
|
51
|
-
export const INTEGRATION_LOGOS = {
|
|
52
|
-
github: simpleIcon(SiGithub),
|
|
53
|
-
slack: simpleIcon(SiSlack),
|
|
54
|
-
tavily: createElement(Search, { className: LOGO, strokeWidth: 2.5 }),
|
|
55
|
-
linear: simpleIcon(SiLinear),
|
|
56
|
-
notion: simpleIcon(SiNotion),
|
|
57
|
-
atlassian: simpleIcon(SiAtlassian),
|
|
58
|
-
sentry: simpleIcon(SiSentry),
|
|
59
|
-
stripe: simpleIcon(SiStripe),
|
|
60
|
-
paypal: simpleIcon(SiPaypal),
|
|
61
|
-
"cloudflare-docs": simpleIcon(SiCloudflare),
|
|
62
|
-
"cloudflare-bindings": simpleIcon(SiCloudflare),
|
|
63
|
-
"cloudflare-observability": simpleIcon(SiCloudflare),
|
|
64
|
-
huggingface: simpleIcon(SiHuggingface),
|
|
65
|
-
deepwiki: simpleIcon(BookOpen),
|
|
66
|
-
git: lucideIcon(GitBranch),
|
|
67
|
-
"brave-search": simpleIcon(SiBrave),
|
|
68
|
-
exa: lucideIcon(Telescope),
|
|
69
|
-
firecrawl: lucideIcon(Flame),
|
|
70
|
-
apify: lucideIcon(Bot),
|
|
71
|
-
fetch: lucideIcon(Globe),
|
|
72
|
-
"browser-mcp": lucideIcon(MousePointerClick),
|
|
73
|
-
playwright: lucideIcon(TestTube),
|
|
74
|
-
supabase: simpleIcon(SiSupabase),
|
|
75
|
-
neon: lucideIcon(Database),
|
|
76
|
-
mongodb: simpleIcon(SiMongodb),
|
|
77
|
-
redis: simpleIcon(SiRedis),
|
|
78
|
-
filesystem: lucideIcon(Folder),
|
|
79
|
-
memory: lucideIcon(Brain),
|
|
80
|
-
"sequential-thinking": lucideIcon(ListTree),
|
|
81
|
-
time: lucideIcon(Clock),
|
|
82
|
-
everything: lucideIcon(Sparkles),
|
|
83
|
-
figma: simpleIcon(SiFigma),
|
|
84
|
-
airtable: simpleIcon(SiAirtable),
|
|
85
|
-
obsidian: simpleIcon(SiObsidian),
|
|
86
|
-
elevenlabs: simpleIcon(SiElevenlabs),
|
|
87
|
-
resend: simpleIcon(SiResend),
|
|
88
|
-
"cloudflare-builds": simpleIcon(SiCloudflare),
|
|
89
|
-
"cloudflare-browser-rendering": simpleIcon(SiCloudflare),
|
|
90
|
-
kagi: simpleIcon(SiKagi),
|
|
91
|
-
clickhouse: simpleIcon(SiClickhouse),
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
export const INTEGRATION_LOGO_IDS = new Set(Object.keys(INTEGRATION_LOGOS));
|