runline 0.1.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/.pi/extensions/runline-context/index.ts +135 -0
- package/.pi/extensions/runline-context/package.json +17 -0
- package/README.md +273 -0
- package/dist/commands/actions.d.ts +3 -0
- package/dist/commands/actions.js +43 -0
- package/dist/commands/connection.d.ts +11 -0
- package/dist/commands/connection.js +56 -0
- package/dist/commands/exec.d.ts +5 -0
- package/dist/commands/exec.js +46 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +26 -0
- package/dist/commands/plugin.d.ts +10 -0
- package/dist/commands/plugin.js +57 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.js +2 -0
- package/dist/config/loader.d.ts +11 -0
- package/dist/config/loader.js +82 -0
- package/dist/config/types.d.ts +9 -0
- package/dist/config/types.js +5 -0
- package/dist/core/engine.d.ts +21 -0
- package/dist/core/engine.js +280 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +9 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +127 -0
- package/dist/plugin/api.d.ts +32 -0
- package/dist/plugin/api.js +68 -0
- package/dist/plugin/installer.d.ts +27 -0
- package/dist/plugin/installer.js +181 -0
- package/dist/plugin/loader.d.ts +13 -0
- package/dist/plugin/loader.js +164 -0
- package/dist/plugin/registry.d.ts +18 -0
- package/dist/plugin/registry.js +43 -0
- package/dist/plugin/types.d.ts +40 -0
- package/dist/plugin/types.js +1 -0
- package/dist/plugins/actionNetwork/src/index.js +353 -0
- package/dist/plugins/activeCampaign/src/index.js +711 -0
- package/dist/plugins/adalo/src/index.js +131 -0
- package/dist/plugins/affinity/src/index.js +279 -0
- package/dist/plugins/agileCrm/src/index.js +415 -0
- package/dist/plugins/airtable/src/index.js +280 -0
- package/dist/plugins/airtop/src/index.js +527 -0
- package/dist/plugins/apiTemplateIo/src/index.js +86 -0
- package/dist/plugins/asana/src/index.js +413 -0
- package/dist/plugins/autopilot/src/index.js +203 -0
- package/dist/plugins/bambooHr/src/index.js +252 -0
- package/dist/plugins/bannerbear/src/index.js +100 -0
- package/dist/plugins/baserow/src/index.js +180 -0
- package/dist/plugins/beeminder/src/index.js +298 -0
- package/dist/plugins/bitly/src/index.js +107 -0
- package/dist/plugins/bitwarden/src/index.js +383 -0
- package/dist/plugins/box/src/index.js +300 -0
- package/dist/plugins/brandfetch/src/index.js +80 -0
- package/dist/plugins/brevo/src/index.js +305 -0
- package/dist/plugins/bubble/src/index.js +181 -0
- package/dist/plugins/chargebee/src/index.js +126 -0
- package/dist/plugins/circleci/src/index.js +111 -0
- package/dist/plugins/ciscoWebex/src/index.js +245 -0
- package/dist/plugins/clearbit/src/index.js +103 -0
- package/dist/plugins/clickup/src/index.js +1043 -0
- package/dist/plugins/clockify/src/index.js +443 -0
- package/dist/plugins/cloudflare/src/index.js +93 -0
- package/dist/plugins/cockpit/src/index.js +131 -0
- package/dist/plugins/coda/src/index.js +327 -0
- package/dist/plugins/coingecko/src/index.js +244 -0
- package/dist/plugins/contentful/src/index.js +146 -0
- package/dist/plugins/convertkit/src/index.js +270 -0
- package/dist/plugins/copper/src/index.js +140 -0
- package/dist/plugins/cortex/src/index.js +147 -0
- package/dist/plugins/currents/src/index.js +405 -0
- package/dist/plugins/customerIo/src/index.js +184 -0
- package/dist/plugins/databricks/src/index.js +342 -0
- package/dist/plugins/deepl/src/index.js +87 -0
- package/dist/plugins/demio/src/index.js +111 -0
- package/dist/plugins/dhl/src/index.js +40 -0
- package/dist/plugins/discord/src/index.js +275 -0
- package/dist/plugins/discourse/src/index.js +273 -0
- package/dist/plugins/disqus/src/index.js +145 -0
- package/dist/plugins/docker/src/index.js +76 -0
- package/dist/plugins/drift/src/index.js +89 -0
- package/dist/plugins/dropbox/src/index.js +159 -0
- package/dist/plugins/dropcontact/src/index.js +59 -0
- package/dist/plugins/egoi/src/index.js +151 -0
- package/dist/plugins/elasticsearch/src/index.js +157 -0
- package/dist/plugins/emelia/src/index.js +174 -0
- package/dist/plugins/erpnext/src/index.js +121 -0
- package/dist/plugins/facebookGraph/src/index.js +57 -0
- package/dist/plugins/freshdesk/src/index.js +320 -0
- package/dist/plugins/freshservice/src/index.js +146 -0
- package/dist/plugins/freshworksCrm/src/index.js +149 -0
- package/dist/plugins/getresponse/src/index.js +140 -0
- package/dist/plugins/ghost/src/index.js +192 -0
- package/dist/plugins/github/src/index.js +630 -0
- package/dist/plugins/gitlab/src/index.js +358 -0
- package/dist/plugins/gong/src/index.js +126 -0
- package/dist/plugins/gotify/src/index.js +77 -0
- package/dist/plugins/gotowebinar/src/index.js +316 -0
- package/dist/plugins/grafana/src/index.js +250 -0
- package/dist/plugins/graphql/src/index.js +78 -0
- package/dist/plugins/grist/src/index.js +106 -0
- package/dist/plugins/hackernews/src/index.js +89 -0
- package/dist/plugins/halopsa/src/index.js +79 -0
- package/dist/plugins/harvest/src/index.js +163 -0
- package/dist/plugins/helpscout/src/index.js +176 -0
- package/dist/plugins/highlevel/src/index.js +172 -0
- package/dist/plugins/homeAssistant/src/index.js +148 -0
- package/dist/plugins/hubspot/src/index.js +176 -0
- package/dist/plugins/humanticAi/src/index.js +60 -0
- package/dist/plugins/hunter/src/index.js +59 -0
- package/dist/plugins/intercom/src/index.js +156 -0
- package/dist/plugins/iterable/src/index.js +139 -0
- package/dist/plugins/jenkins/src/index.js +132 -0
- package/dist/plugins/jira/src/index.js +229 -0
- package/dist/plugins/keap/src/index.js +502 -0
- package/dist/plugins/kobotoolbox/src/index.js +281 -0
- package/dist/plugins/lemlist/src/index.js +231 -0
- package/dist/plugins/linear/src/index.js +133 -0
- package/dist/plugins/lingvanex/src/index.js +31 -0
- package/dist/plugins/linkedin/src/index.js +80 -0
- package/dist/plugins/lonescale/src/index.js +119 -0
- package/dist/plugins/magento/src/index.js +300 -0
- package/dist/plugins/mailcheck/src/index.js +27 -0
- package/dist/plugins/mailchimp/src/index.js +321 -0
- package/dist/plugins/mailerlite/src/index.js +123 -0
- package/dist/plugins/mailgun/src/index.js +48 -0
- package/dist/plugins/mailjet/src/index.js +155 -0
- package/dist/plugins/mandrill/src/index.js +145 -0
- package/dist/plugins/marketstack/src/index.js +97 -0
- package/dist/plugins/matrix/src/index.js +194 -0
- package/dist/plugins/mattermost/src/index.js +331 -0
- package/dist/plugins/mautic/src/index.js +311 -0
- package/dist/plugins/medium/src/index.js +77 -0
- package/dist/plugins/messagebird/src/index.js +57 -0
- package/dist/plugins/metabase/src/index.js +130 -0
- package/dist/plugins/misp/src/index.js +476 -0
- package/dist/plugins/mocean/src/index.js +67 -0
- package/dist/plugins/monday/src/index.js +231 -0
- package/dist/plugins/monicaCrm/src/index.js +52 -0
- package/dist/plugins/msg91/src/index.js +31 -0
- package/dist/plugins/nasa/src/index.js +146 -0
- package/dist/plugins/netlify/src/index.js +151 -0
- package/dist/plugins/netscalerAdc/src/index.js +131 -0
- package/dist/plugins/nextcloud/src/index.js +263 -0
- package/dist/plugins/nocodb/src/index.js +130 -0
- package/dist/plugins/notion/src/index.js +112 -0
- package/dist/plugins/npm/src/index.js +104 -0
- package/dist/plugins/odoo/src/index.js +157 -0
- package/dist/plugins/okta/src/index.js +141 -0
- package/dist/plugins/oneSimpleApi/src/index.js +155 -0
- package/dist/plugins/onfleet/src/index.js +254 -0
- package/dist/plugins/openThesaurus/src/index.js +32 -0
- package/dist/plugins/openweathermap/src/index.js +60 -0
- package/dist/plugins/oura/src/index.js +62 -0
- package/dist/plugins/paddle/src/index.js +247 -0
- package/dist/plugins/pagerduty/src/index.js +201 -0
- package/dist/plugins/paypal/src/index.js +106 -0
- package/dist/plugins/peekalink/src/index.js +35 -0
- package/dist/plugins/phantombuster/src/index.js +94 -0
- package/dist/plugins/philipsHue/src/index.js +98 -0
- package/dist/plugins/pipedrive/src/index.js +169 -0
- package/dist/plugins/plivo/src/index.js +66 -0
- package/dist/plugins/postbin/src/index.js +93 -0
- package/dist/plugins/posthog/src/index.js +113 -0
- package/dist/plugins/profitwell/src/index.js +50 -0
- package/dist/plugins/pushbullet/src/index.js +102 -0
- package/dist/plugins/pushcut/src/index.js +39 -0
- package/dist/plugins/pushover/src/index.js +65 -0
- package/dist/plugins/quickbase/src/index.js +153 -0
- package/dist/plugins/quickbooks/src/index.js +73 -0
- package/dist/plugins/quickchart/src/index.js +36 -0
- package/dist/plugins/raindrop/src/index.js +209 -0
- package/dist/plugins/reddit/src/index.js +185 -0
- package/dist/plugins/rocketchat/src/index.js +53 -0
- package/dist/plugins/rundeck/src/index.js +62 -0
- package/dist/plugins/salesforce/src/index.js +94 -0
- package/dist/plugins/salesmate/src/index.js +83 -0
- package/dist/plugins/securityScorecard/src/index.js +200 -0
- package/dist/plugins/segment/src/index.js +125 -0
- package/dist/plugins/sendgrid/src/index.js +187 -0
- package/dist/plugins/sendy/src/index.js +138 -0
- package/dist/plugins/sentry/src/index.js +233 -0
- package/dist/plugins/servicenow/src/index.js +108 -0
- package/dist/plugins/shopify/src/index.js +222 -0
- package/dist/plugins/signl4/src/index.js +61 -0
- package/dist/plugins/slack/src/index.js +236 -0
- package/dist/plugins/sms77/src/index.js +63 -0
- package/dist/plugins/splunk/src/index.js +207 -0
- package/dist/plugins/spotify/src/index.js +188 -0
- package/dist/plugins/stackby/src/index.js +82 -0
- package/dist/plugins/storyblok/src/index.js +141 -0
- package/dist/plugins/strapi/src/index.js +152 -0
- package/dist/plugins/strava/src/index.js +137 -0
- package/dist/plugins/stripe/src/index.js +222 -0
- package/dist/plugins/supabase/src/index.js +121 -0
- package/dist/plugins/syncromsp/src/index.js +255 -0
- package/dist/plugins/tapfiliate/src/index.js +125 -0
- package/dist/plugins/telegram/src/index.js +233 -0
- package/dist/plugins/thehive/src/index.js +142 -0
- package/dist/plugins/thehiveProject/src/index.js +194 -0
- package/dist/plugins/todoist/src/index.js +244 -0
- package/dist/plugins/travisci/src/index.js +71 -0
- package/dist/plugins/trello/src/index.js +341 -0
- package/dist/plugins/twake/src/index.js +40 -0
- package/dist/plugins/twilio/src/index.js +75 -0
- package/dist/plugins/twist/src/index.js +90 -0
- package/dist/plugins/twitter/src/index.js +123 -0
- package/dist/plugins/unleashedSoftware/src/index.js +84 -0
- package/dist/plugins/uplead/src/index.js +59 -0
- package/dist/plugins/uproc/src/index.js +34 -0
- package/dist/plugins/uptimerobot/src/index.js +264 -0
- package/dist/plugins/urlscanio/src/index.js +64 -0
- package/dist/plugins/vero/src/index.js +80 -0
- package/dist/plugins/vonage/src/index.js +42 -0
- package/dist/plugins/wekan/src/index.js +91 -0
- package/dist/plugins/woocommerce/src/index.js +92 -0
- package/dist/plugins/wordpress/src/index.js +121 -0
- package/dist/plugins/xero/src/index.js +136 -0
- package/dist/plugins/yourls/src/index.js +56 -0
- package/dist/plugins/zammad/src/index.js +91 -0
- package/dist/plugins/zendesk/src/index.js +137 -0
- package/dist/plugins/zoho/src/index.js +85 -0
- package/dist/plugins/zoom/src/index.js +122 -0
- package/dist/plugins/zulip/src/index.js +170 -0
- package/dist/sdk.d.ts +38 -0
- package/dist/sdk.js +105 -0
- package/dist/utils/cli.d.ts +13 -0
- package/dist/utils/cli.js +32 -0
- package/dist/utils/output.d.ts +4 -0
- package/dist/utils/output.js +13 -0
- package/package.json +57 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
function buildBaseUrl(accountName) {
|
|
2
|
+
return `https://${accountName}.chargebee.com/api/v2`;
|
|
3
|
+
}
|
|
4
|
+
async function apiRequest(accountName, apiKey, method, endpoint, qs) {
|
|
5
|
+
const url = new URL(`${buildBaseUrl(accountName)}/${endpoint}`);
|
|
6
|
+
if (qs) {
|
|
7
|
+
for (const [k, v] of Object.entries(qs)) {
|
|
8
|
+
if (v !== undefined && v !== null)
|
|
9
|
+
url.searchParams.set(k, String(v));
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const opts = {
|
|
13
|
+
method,
|
|
14
|
+
headers: {
|
|
15
|
+
Authorization: `Basic ${btoa(`${apiKey}:`)}`,
|
|
16
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
const res = await fetch(url.toString(), opts);
|
|
20
|
+
if (!res.ok) {
|
|
21
|
+
const text = await res.text();
|
|
22
|
+
throw new Error(`Chargebee API error ${res.status}: ${text}`);
|
|
23
|
+
}
|
|
24
|
+
return res.json();
|
|
25
|
+
}
|
|
26
|
+
function getConn(ctx) {
|
|
27
|
+
return {
|
|
28
|
+
accountName: ctx.connection.config.accountName,
|
|
29
|
+
apiKey: ctx.connection.config.apiKey,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export default function chargebee(rl) {
|
|
33
|
+
rl.setName("chargebee");
|
|
34
|
+
rl.setVersion("0.1.0");
|
|
35
|
+
rl.setConnectionSchema({
|
|
36
|
+
accountName: {
|
|
37
|
+
type: "string",
|
|
38
|
+
required: true,
|
|
39
|
+
description: "Chargebee account/site name",
|
|
40
|
+
env: "CHARGEBEE_ACCOUNT_NAME",
|
|
41
|
+
},
|
|
42
|
+
apiKey: {
|
|
43
|
+
type: "string",
|
|
44
|
+
required: true,
|
|
45
|
+
description: "Chargebee API key",
|
|
46
|
+
env: "CHARGEBEE_API_KEY",
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
// ── Customer ────────────────────────────────────────
|
|
50
|
+
rl.registerAction("customer.create", {
|
|
51
|
+
description: "Create a customer",
|
|
52
|
+
inputSchema: {
|
|
53
|
+
id: { type: "string", required: false, description: "Customer ID (auto-generated if omitted)" },
|
|
54
|
+
first_name: { type: "string", required: false, description: "First name" },
|
|
55
|
+
last_name: { type: "string", required: false, description: "Last name" },
|
|
56
|
+
email: { type: "string", required: false, description: "Email" },
|
|
57
|
+
phone: { type: "string", required: false, description: "Phone" },
|
|
58
|
+
company: { type: "string", required: false, description: "Company" },
|
|
59
|
+
},
|
|
60
|
+
async execute(input, ctx) {
|
|
61
|
+
const { accountName, apiKey } = getConn(ctx);
|
|
62
|
+
const params = (input ?? {});
|
|
63
|
+
// Chargebee uses form-encoded POST params via query string
|
|
64
|
+
return apiRequest(accountName, apiKey, "POST", "customers", params);
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
// ── Invoice ─────────────────────────────────────────
|
|
68
|
+
rl.registerAction("invoice.list", {
|
|
69
|
+
description: "List invoices",
|
|
70
|
+
inputSchema: {
|
|
71
|
+
limit: { type: "number", required: false, description: "Max results (default: 10, max: 100)" },
|
|
72
|
+
sortBy: { type: "string", required: false, description: "Sort field (default: date desc)" },
|
|
73
|
+
},
|
|
74
|
+
async execute(input, ctx) {
|
|
75
|
+
const { accountName, apiKey } = getConn(ctx);
|
|
76
|
+
const { limit = 10 } = (input ?? {});
|
|
77
|
+
const qs = {
|
|
78
|
+
limit,
|
|
79
|
+
"sort_by[desc]": "date",
|
|
80
|
+
};
|
|
81
|
+
const data = (await apiRequest(accountName, apiKey, "GET", "invoices", qs));
|
|
82
|
+
const list = data.list ?? [];
|
|
83
|
+
return list.map((item) => item.invoice);
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
rl.registerAction("invoice.getPdfUrl", {
|
|
87
|
+
description: "Get the PDF download URL for an invoice",
|
|
88
|
+
inputSchema: {
|
|
89
|
+
invoiceId: { type: "string", required: true, description: "Invoice ID" },
|
|
90
|
+
},
|
|
91
|
+
async execute(input, ctx) {
|
|
92
|
+
const { invoiceId } = input;
|
|
93
|
+
const { accountName, apiKey } = getConn(ctx);
|
|
94
|
+
const data = (await apiRequest(accountName, apiKey, "POST", `invoices/${invoiceId.trim()}/pdf`));
|
|
95
|
+
const download = data.download;
|
|
96
|
+
return { pdfUrl: download?.download_url };
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
// ── Subscription ────────────────────────────────────
|
|
100
|
+
rl.registerAction("subscription.cancel", {
|
|
101
|
+
description: "Cancel a subscription",
|
|
102
|
+
inputSchema: {
|
|
103
|
+
subscriptionId: { type: "string", required: true, description: "Subscription ID" },
|
|
104
|
+
endOfTerm: { type: "boolean", required: false, description: "Schedule cancellation at end of term instead of immediate" },
|
|
105
|
+
},
|
|
106
|
+
async execute(input, ctx) {
|
|
107
|
+
const { subscriptionId, endOfTerm } = input;
|
|
108
|
+
const { accountName, apiKey } = getConn(ctx);
|
|
109
|
+
const qs = {};
|
|
110
|
+
if (endOfTerm)
|
|
111
|
+
qs.end_of_term = "true";
|
|
112
|
+
return apiRequest(accountName, apiKey, "POST", `subscriptions/${subscriptionId.trim()}/cancel`, qs);
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
rl.registerAction("subscription.delete", {
|
|
116
|
+
description: "Delete a subscription",
|
|
117
|
+
inputSchema: {
|
|
118
|
+
subscriptionId: { type: "string", required: true, description: "Subscription ID" },
|
|
119
|
+
},
|
|
120
|
+
async execute(input, ctx) {
|
|
121
|
+
const { subscriptionId } = input;
|
|
122
|
+
const { accountName, apiKey } = getConn(ctx);
|
|
123
|
+
return apiRequest(accountName, apiKey, "POST", `subscriptions/${subscriptionId.trim()}/delete`);
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const BASE_URL = "https://circleci.com/api/v2";
|
|
2
|
+
async function apiRequest(token, method, endpoint, body, qs) {
|
|
3
|
+
const url = new URL(`${BASE_URL}${endpoint}`);
|
|
4
|
+
if (qs) {
|
|
5
|
+
for (const [k, v] of Object.entries(qs)) {
|
|
6
|
+
if (v !== undefined && v !== null)
|
|
7
|
+
url.searchParams.set(k, String(v));
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
const opts = {
|
|
11
|
+
method,
|
|
12
|
+
headers: {
|
|
13
|
+
"Circle-Token": token,
|
|
14
|
+
"Content-Type": "application/json",
|
|
15
|
+
Accept: "application/json",
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
if (body && Object.keys(body).length > 0 && method !== "GET") {
|
|
19
|
+
opts.body = JSON.stringify(body);
|
|
20
|
+
}
|
|
21
|
+
const res = await fetch(url.toString(), opts);
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
const text = await res.text();
|
|
24
|
+
throw new Error(`CircleCI API error ${res.status}: ${text}`);
|
|
25
|
+
}
|
|
26
|
+
return res.json();
|
|
27
|
+
}
|
|
28
|
+
async function paginateAll(token, endpoint, qs) {
|
|
29
|
+
const results = [];
|
|
30
|
+
const q = { ...qs };
|
|
31
|
+
while (true) {
|
|
32
|
+
const data = (await apiRequest(token, "GET", endpoint, undefined, q));
|
|
33
|
+
const items = data.items ?? [];
|
|
34
|
+
results.push(...items);
|
|
35
|
+
if (!data.next_page_token)
|
|
36
|
+
break;
|
|
37
|
+
q["page-token"] = data.next_page_token;
|
|
38
|
+
}
|
|
39
|
+
return results;
|
|
40
|
+
}
|
|
41
|
+
function getToken(ctx) {
|
|
42
|
+
return ctx.connection.config.apiKey;
|
|
43
|
+
}
|
|
44
|
+
function encodeSlug(slug) {
|
|
45
|
+
return slug.replace(/\//g, "%2F");
|
|
46
|
+
}
|
|
47
|
+
export default function circleci(rl) {
|
|
48
|
+
rl.setName("circleci");
|
|
49
|
+
rl.setVersion("0.1.0");
|
|
50
|
+
rl.setConnectionSchema({
|
|
51
|
+
apiKey: {
|
|
52
|
+
type: "string",
|
|
53
|
+
required: true,
|
|
54
|
+
description: "CircleCI API token",
|
|
55
|
+
env: "CIRCLECI_API_KEY",
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
rl.registerAction("pipeline.get", {
|
|
59
|
+
description: "Get a specific pipeline by number",
|
|
60
|
+
inputSchema: {
|
|
61
|
+
vcs: { type: "string", required: true, description: "VCS type: github or bitbucket" },
|
|
62
|
+
projectSlug: { type: "string", required: true, description: "Project slug (org/repo)" },
|
|
63
|
+
pipelineNumber: { type: "number", required: true, description: "Pipeline number" },
|
|
64
|
+
},
|
|
65
|
+
async execute(input, ctx) {
|
|
66
|
+
const { vcs, projectSlug, pipelineNumber } = input;
|
|
67
|
+
return apiRequest(getToken(ctx), "GET", `/project/${vcs}/${encodeSlug(projectSlug)}/pipeline/${pipelineNumber}`);
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
rl.registerAction("pipeline.list", {
|
|
71
|
+
description: "List pipelines for a project",
|
|
72
|
+
inputSchema: {
|
|
73
|
+
vcs: { type: "string", required: true, description: "VCS type: github or bitbucket" },
|
|
74
|
+
projectSlug: { type: "string", required: true, description: "Project slug (org/repo)" },
|
|
75
|
+
branch: { type: "string", required: false, description: "Filter by branch" },
|
|
76
|
+
limit: { type: "number", required: false, description: "Max results (omit for all)" },
|
|
77
|
+
},
|
|
78
|
+
async execute(input, ctx) {
|
|
79
|
+
const { vcs, projectSlug, branch, limit } = (input ?? {});
|
|
80
|
+
const token = getToken(ctx);
|
|
81
|
+
const endpoint = `/project/${vcs}/${encodeSlug(projectSlug)}/pipeline`;
|
|
82
|
+
const qs = {};
|
|
83
|
+
if (branch)
|
|
84
|
+
qs.branch = branch;
|
|
85
|
+
if (limit) {
|
|
86
|
+
qs.limit = limit;
|
|
87
|
+
const data = (await apiRequest(token, "GET", endpoint, undefined, qs));
|
|
88
|
+
return (data.items ?? []).slice(0, limit);
|
|
89
|
+
}
|
|
90
|
+
return paginateAll(token, endpoint, qs);
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
rl.registerAction("pipeline.trigger", {
|
|
94
|
+
description: "Trigger a new pipeline",
|
|
95
|
+
inputSchema: {
|
|
96
|
+
vcs: { type: "string", required: true, description: "VCS type: github or bitbucket" },
|
|
97
|
+
projectSlug: { type: "string", required: true, description: "Project slug (org/repo)" },
|
|
98
|
+
branch: { type: "string", required: false, description: "Branch to build" },
|
|
99
|
+
tag: { type: "string", required: false, description: "Tag to build" },
|
|
100
|
+
},
|
|
101
|
+
async execute(input, ctx) {
|
|
102
|
+
const { vcs, projectSlug, branch, tag } = (input ?? {});
|
|
103
|
+
const body = {};
|
|
104
|
+
if (branch)
|
|
105
|
+
body.branch = branch;
|
|
106
|
+
if (tag)
|
|
107
|
+
body.tag = tag;
|
|
108
|
+
return apiRequest(getToken(ctx), "POST", `/project/${vcs}/${encodeSlug(projectSlug)}/pipeline`, body);
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
const BASE_URL = "https://webexapis.com/v1";
|
|
2
|
+
async function apiRequest(token, method, endpoint, body, qs) {
|
|
3
|
+
const url = new URL(`${BASE_URL}${endpoint}`);
|
|
4
|
+
if (qs) {
|
|
5
|
+
for (const [k, v] of Object.entries(qs)) {
|
|
6
|
+
if (v !== undefined && v !== null)
|
|
7
|
+
url.searchParams.set(k, String(v));
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
const opts = {
|
|
11
|
+
method,
|
|
12
|
+
headers: {
|
|
13
|
+
"Content-Type": "application/json",
|
|
14
|
+
Authorization: `Bearer ${token}`,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE") {
|
|
18
|
+
opts.body = JSON.stringify(body);
|
|
19
|
+
}
|
|
20
|
+
const res = await fetch(url.toString(), opts);
|
|
21
|
+
if (!res.ok) {
|
|
22
|
+
const text = await res.text();
|
|
23
|
+
throw new Error(`Webex API error ${res.status}: ${text}`);
|
|
24
|
+
}
|
|
25
|
+
if (res.status === 204)
|
|
26
|
+
return { success: true };
|
|
27
|
+
const ct = res.headers.get("content-type") ?? "";
|
|
28
|
+
if (ct.includes("application/json"))
|
|
29
|
+
return res.json();
|
|
30
|
+
return { success: true };
|
|
31
|
+
}
|
|
32
|
+
async function paginateAll(token, endpoint, property, qs) {
|
|
33
|
+
const results = [];
|
|
34
|
+
const q = { ...qs, max: 100 };
|
|
35
|
+
let nextUrl;
|
|
36
|
+
while (true) {
|
|
37
|
+
const res = await fetch(nextUrl ?? `${BASE_URL}${endpoint}?${new URLSearchParams(Object.entries(q).map(([k, v]) => [k, String(v)]))}`, {
|
|
38
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
39
|
+
});
|
|
40
|
+
if (!res.ok)
|
|
41
|
+
throw new Error(`Webex API error ${res.status}: ${await res.text()}`);
|
|
42
|
+
const data = (await res.json());
|
|
43
|
+
results.push(...(data[property] ?? []));
|
|
44
|
+
const link = res.headers.get("link");
|
|
45
|
+
if (link?.includes('rel="next"')) {
|
|
46
|
+
const match = link.match(/<([^>]+)>/);
|
|
47
|
+
nextUrl = match?.[1];
|
|
48
|
+
if (!nextUrl)
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return results;
|
|
56
|
+
}
|
|
57
|
+
function getToken(ctx) {
|
|
58
|
+
return ctx.connection.config.accessToken;
|
|
59
|
+
}
|
|
60
|
+
export default function ciscoWebex(rl) {
|
|
61
|
+
rl.setName("ciscoWebex");
|
|
62
|
+
rl.setVersion("0.1.0");
|
|
63
|
+
rl.setConnectionSchema({
|
|
64
|
+
accessToken: {
|
|
65
|
+
type: "string",
|
|
66
|
+
required: true,
|
|
67
|
+
description: "Webex access token (OAuth2 or bot token)",
|
|
68
|
+
env: "WEBEX_ACCESS_TOKEN",
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
// ── Message ─────────────────────────────────────────
|
|
72
|
+
rl.registerAction("message.create", {
|
|
73
|
+
description: "Send a message to a room or person",
|
|
74
|
+
inputSchema: {
|
|
75
|
+
roomId: { type: "string", required: false, description: "Room ID (use this or toPersonId/toPersonEmail)" },
|
|
76
|
+
toPersonId: { type: "string", required: false, description: "Person ID to message" },
|
|
77
|
+
toPersonEmail: { type: "string", required: false, description: "Person email to message" },
|
|
78
|
+
text: { type: "string", required: true, description: "Message text" },
|
|
79
|
+
markdown: { type: "string", required: false, description: "Markdown-formatted message" },
|
|
80
|
+
files: { type: "array", required: false, description: "Array of file URLs to attach" },
|
|
81
|
+
},
|
|
82
|
+
async execute(input, ctx) {
|
|
83
|
+
const body = (input ?? {});
|
|
84
|
+
return apiRequest(getToken(ctx), "POST", "/messages", body);
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
rl.registerAction("message.get", {
|
|
88
|
+
description: "Get message details",
|
|
89
|
+
inputSchema: {
|
|
90
|
+
messageId: { type: "string", required: true, description: "Message ID" },
|
|
91
|
+
},
|
|
92
|
+
async execute(input, ctx) {
|
|
93
|
+
const { messageId } = input;
|
|
94
|
+
return apiRequest(getToken(ctx), "GET", `/messages/${messageId}`);
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
rl.registerAction("message.list", {
|
|
98
|
+
description: "List messages in a room",
|
|
99
|
+
inputSchema: {
|
|
100
|
+
roomId: { type: "string", required: true, description: "Room ID" },
|
|
101
|
+
limit: { type: "number", required: false, description: "Max results (omit for all)" },
|
|
102
|
+
mentionedPeople: { type: "string", required: false, description: "Filter: 'me' or person ID" },
|
|
103
|
+
before: { type: "string", required: false, description: "List messages before this date (ISO 8601)" },
|
|
104
|
+
beforeMessage: { type: "string", required: false, description: "List messages before this message ID" },
|
|
105
|
+
},
|
|
106
|
+
async execute(input, ctx) {
|
|
107
|
+
const { roomId, limit, mentionedPeople, before, beforeMessage } = (input ?? {});
|
|
108
|
+
const qs = { roomId };
|
|
109
|
+
if (mentionedPeople)
|
|
110
|
+
qs.mentionedPeople = mentionedPeople;
|
|
111
|
+
if (before)
|
|
112
|
+
qs.before = before;
|
|
113
|
+
if (beforeMessage)
|
|
114
|
+
qs.beforeMessage = beforeMessage;
|
|
115
|
+
if (limit) {
|
|
116
|
+
qs.max = limit;
|
|
117
|
+
const data = (await apiRequest(getToken(ctx), "GET", "/messages", undefined, qs));
|
|
118
|
+
return data.items;
|
|
119
|
+
}
|
|
120
|
+
return paginateAll(getToken(ctx), "/messages", "items", qs);
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
rl.registerAction("message.update", {
|
|
124
|
+
description: "Edit a message",
|
|
125
|
+
inputSchema: {
|
|
126
|
+
messageId: { type: "string", required: true, description: "Message ID" },
|
|
127
|
+
text: { type: "string", required: false, description: "New plain text" },
|
|
128
|
+
markdown: { type: "string", required: false, description: "New markdown text" },
|
|
129
|
+
},
|
|
130
|
+
async execute(input, ctx) {
|
|
131
|
+
const { messageId, text, markdown } = input;
|
|
132
|
+
// Need roomId from original message
|
|
133
|
+
const original = (await apiRequest(getToken(ctx), "GET", `/messages/${messageId}`));
|
|
134
|
+
const body = { roomId: original.roomId };
|
|
135
|
+
if (markdown)
|
|
136
|
+
body.markdown = markdown;
|
|
137
|
+
else if (text)
|
|
138
|
+
body.text = text;
|
|
139
|
+
return apiRequest(getToken(ctx), "PUT", `/messages/${messageId}`, body);
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
rl.registerAction("message.delete", {
|
|
143
|
+
description: "Delete a message",
|
|
144
|
+
inputSchema: {
|
|
145
|
+
messageId: { type: "string", required: true, description: "Message ID" },
|
|
146
|
+
},
|
|
147
|
+
async execute(input, ctx) {
|
|
148
|
+
const { messageId } = input;
|
|
149
|
+
await apiRequest(getToken(ctx), "DELETE", `/messages/${messageId}`);
|
|
150
|
+
return { success: true };
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
// ── Meeting ─────────────────────────────────────────
|
|
154
|
+
rl.registerAction("meeting.create", {
|
|
155
|
+
description: "Create a meeting",
|
|
156
|
+
inputSchema: {
|
|
157
|
+
title: { type: "string", required: true, description: "Meeting title" },
|
|
158
|
+
start: { type: "string", required: true, description: "Start time (ISO 8601)" },
|
|
159
|
+
end: { type: "string", required: true, description: "End time (ISO 8601)" },
|
|
160
|
+
invitees: { type: "array", required: false, description: "Array of {email} objects" },
|
|
161
|
+
agenda: { type: "string", required: false, description: "Meeting agenda" },
|
|
162
|
+
password: { type: "string", required: false, description: "Meeting password" },
|
|
163
|
+
enabledAutoRecordMeeting: { type: "boolean", required: false, description: "Auto-record" },
|
|
164
|
+
allowAnyUserToBeCoHost: { type: "boolean", required: false, description: "Allow any user to be co-host" },
|
|
165
|
+
},
|
|
166
|
+
async execute(input, ctx) {
|
|
167
|
+
const body = (input ?? {});
|
|
168
|
+
return apiRequest(getToken(ctx), "POST", "/meetings", body);
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
rl.registerAction("meeting.get", {
|
|
172
|
+
description: "Get meeting details",
|
|
173
|
+
inputSchema: {
|
|
174
|
+
meetingId: { type: "string", required: true, description: "Meeting ID" },
|
|
175
|
+
},
|
|
176
|
+
async execute(input, ctx) {
|
|
177
|
+
const { meetingId } = input;
|
|
178
|
+
return apiRequest(getToken(ctx), "GET", `/meetings/${meetingId}`);
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
rl.registerAction("meeting.list", {
|
|
182
|
+
description: "List meetings",
|
|
183
|
+
inputSchema: {
|
|
184
|
+
from: { type: "string", required: false, description: "Start date filter (ISO 8601)" },
|
|
185
|
+
to: { type: "string", required: false, description: "End date filter (ISO 8601)" },
|
|
186
|
+
meetingType: { type: "string", required: false, description: "Meeting type filter" },
|
|
187
|
+
state: { type: "string", required: false, description: "State filter" },
|
|
188
|
+
limit: { type: "number", required: false, description: "Max results (omit for all)" },
|
|
189
|
+
},
|
|
190
|
+
async execute(input, ctx) {
|
|
191
|
+
const { from, to, meetingType, state, limit } = (input ?? {});
|
|
192
|
+
const qs = {};
|
|
193
|
+
if (from)
|
|
194
|
+
qs.from = from;
|
|
195
|
+
if (to)
|
|
196
|
+
qs.to = to;
|
|
197
|
+
if (meetingType)
|
|
198
|
+
qs.meetingType = meetingType;
|
|
199
|
+
if (state)
|
|
200
|
+
qs.state = state;
|
|
201
|
+
if (limit) {
|
|
202
|
+
qs.max = limit;
|
|
203
|
+
const data = (await apiRequest(getToken(ctx), "GET", "/meetings", undefined, qs));
|
|
204
|
+
return data.items;
|
|
205
|
+
}
|
|
206
|
+
return paginateAll(getToken(ctx), "/meetings", "items", qs);
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
rl.registerAction("meeting.update", {
|
|
210
|
+
description: "Update a meeting",
|
|
211
|
+
inputSchema: {
|
|
212
|
+
meetingId: { type: "string", required: true, description: "Meeting ID" },
|
|
213
|
+
title: { type: "string", required: false, description: "New title" },
|
|
214
|
+
start: { type: "string", required: false, description: "New start time (ISO 8601)" },
|
|
215
|
+
end: { type: "string", required: false, description: "New end time (ISO 8601)" },
|
|
216
|
+
password: { type: "string", required: false, description: "New password" },
|
|
217
|
+
invitees: { type: "array", required: false, description: "Array of {email} objects" },
|
|
218
|
+
},
|
|
219
|
+
async execute(input, ctx) {
|
|
220
|
+
const { meetingId, ...fields } = input;
|
|
221
|
+
// API requires title, password, start, end — fetch current if not provided
|
|
222
|
+
const current = (await apiRequest(getToken(ctx), "GET", `/meetings/${meetingId}`));
|
|
223
|
+
const body = {
|
|
224
|
+
title: fields.title ?? current.title,
|
|
225
|
+
password: fields.password ?? current.password,
|
|
226
|
+
start: fields.start ?? current.start,
|
|
227
|
+
end: fields.end ?? current.end,
|
|
228
|
+
...fields,
|
|
229
|
+
};
|
|
230
|
+
delete body.meetingId;
|
|
231
|
+
return apiRequest(getToken(ctx), "PUT", `/meetings/${meetingId}`, body);
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
rl.registerAction("meeting.delete", {
|
|
235
|
+
description: "Delete a meeting",
|
|
236
|
+
inputSchema: {
|
|
237
|
+
meetingId: { type: "string", required: true, description: "Meeting ID" },
|
|
238
|
+
},
|
|
239
|
+
async execute(input, ctx) {
|
|
240
|
+
const { meetingId } = input;
|
|
241
|
+
await apiRequest(getToken(ctx), "DELETE", `/meetings/${meetingId}`);
|
|
242
|
+
return { success: true };
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
async function apiRequest(apiKey, subdomain, endpoint, qs) {
|
|
2
|
+
const url = new URL(`https://${subdomain}.clearbit.com${endpoint}`);
|
|
3
|
+
if (qs) {
|
|
4
|
+
for (const [k, v] of Object.entries(qs)) {
|
|
5
|
+
if (v !== undefined && v !== null)
|
|
6
|
+
url.searchParams.set(k, String(v));
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
const res = await fetch(url.toString(), {
|
|
10
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
11
|
+
});
|
|
12
|
+
if (!res.ok) {
|
|
13
|
+
const text = await res.text();
|
|
14
|
+
throw new Error(`Clearbit API error ${res.status}: ${text}`);
|
|
15
|
+
}
|
|
16
|
+
return res.json();
|
|
17
|
+
}
|
|
18
|
+
function getKey(ctx) {
|
|
19
|
+
return ctx.connection.config.apiKey;
|
|
20
|
+
}
|
|
21
|
+
export default function clearbit(rl) {
|
|
22
|
+
rl.setName("clearbit");
|
|
23
|
+
rl.setVersion("0.1.0");
|
|
24
|
+
rl.setConnectionSchema({
|
|
25
|
+
apiKey: {
|
|
26
|
+
type: "string",
|
|
27
|
+
required: true,
|
|
28
|
+
description: "Clearbit API key",
|
|
29
|
+
env: "CLEARBIT_API_KEY",
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
rl.registerAction("person.enrich", {
|
|
33
|
+
description: "Look up a person by email address",
|
|
34
|
+
inputSchema: {
|
|
35
|
+
email: { type: "string", required: true, description: "Email address" },
|
|
36
|
+
givenName: { type: "string", required: false, description: "First name hint" },
|
|
37
|
+
familyName: { type: "string", required: false, description: "Last name hint" },
|
|
38
|
+
ipAddress: { type: "string", required: false, description: "IP address hint" },
|
|
39
|
+
location: { type: "string", required: false, description: "Location hint" },
|
|
40
|
+
company: { type: "string", required: false, description: "Company name hint" },
|
|
41
|
+
companyDomain: { type: "string", required: false, description: "Company domain hint" },
|
|
42
|
+
linkedin: { type: "string", required: false, description: "LinkedIn URL hint" },
|
|
43
|
+
twitter: { type: "string", required: false, description: "Twitter handle hint" },
|
|
44
|
+
facebook: { type: "string", required: false, description: "Facebook URL hint" },
|
|
45
|
+
},
|
|
46
|
+
async execute(input, ctx) {
|
|
47
|
+
const { email, givenName, familyName, ipAddress, location, company, companyDomain, linkedin, twitter, facebook } = (input ?? {});
|
|
48
|
+
const qs = { email };
|
|
49
|
+
if (givenName)
|
|
50
|
+
qs.given_name = givenName;
|
|
51
|
+
if (familyName)
|
|
52
|
+
qs.family_name = familyName;
|
|
53
|
+
if (ipAddress)
|
|
54
|
+
qs.ip_address = ipAddress;
|
|
55
|
+
if (location)
|
|
56
|
+
qs.location = location;
|
|
57
|
+
if (company)
|
|
58
|
+
qs.company = company;
|
|
59
|
+
if (companyDomain)
|
|
60
|
+
qs.company_domain = companyDomain;
|
|
61
|
+
if (linkedin)
|
|
62
|
+
qs.linkedin = linkedin;
|
|
63
|
+
if (twitter)
|
|
64
|
+
qs.twitter = twitter;
|
|
65
|
+
if (facebook)
|
|
66
|
+
qs.facebook = facebook;
|
|
67
|
+
return apiRequest(getKey(ctx), "person-stream", "/v2/people/find", qs);
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
rl.registerAction("company.enrich", {
|
|
71
|
+
description: "Look up a company by domain",
|
|
72
|
+
inputSchema: {
|
|
73
|
+
domain: { type: "string", required: true, description: "Company domain" },
|
|
74
|
+
companyName: { type: "string", required: false, description: "Company name hint" },
|
|
75
|
+
linkedin: { type: "string", required: false, description: "LinkedIn URL hint" },
|
|
76
|
+
twitter: { type: "string", required: false, description: "Twitter handle hint" },
|
|
77
|
+
facebook: { type: "string", required: false, description: "Facebook URL hint" },
|
|
78
|
+
},
|
|
79
|
+
async execute(input, ctx) {
|
|
80
|
+
const { domain, companyName, linkedin, twitter, facebook } = (input ?? {});
|
|
81
|
+
const qs = { domain };
|
|
82
|
+
if (companyName)
|
|
83
|
+
qs.company_name = companyName;
|
|
84
|
+
if (linkedin)
|
|
85
|
+
qs.linkedin = linkedin;
|
|
86
|
+
if (twitter)
|
|
87
|
+
qs.twitter = twitter;
|
|
88
|
+
if (facebook)
|
|
89
|
+
qs.facebook = facebook;
|
|
90
|
+
return apiRequest(getKey(ctx), "company-stream", "/v2/companies/find", qs);
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
rl.registerAction("company.autocomplete", {
|
|
94
|
+
description: "Autocomplete company names",
|
|
95
|
+
inputSchema: {
|
|
96
|
+
name: { type: "string", required: true, description: "Partial company name" },
|
|
97
|
+
},
|
|
98
|
+
async execute(input, ctx) {
|
|
99
|
+
const { name } = input;
|
|
100
|
+
return apiRequest(getKey(ctx), "autocomplete", "/v1/companies/suggest", { query: name });
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|