@nimbus-dev/connectors 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/LICENSE +662 -0
- package/NOTICE +40 -0
- package/README.md +111 -0
- package/connectors/airflow/nimbus.extension.json +16 -0
- package/connectors/airflow/src/search-filter.ts +38 -0
- package/connectors/airflow/src/server.ts +91 -0
- package/connectors/apple/nimbus.extension.json +40 -0
- package/connectors/apple/src/apple-mail-core.ts +43 -0
- package/connectors/apple/src/caldav-core.ts +116 -0
- package/connectors/apple/src/calendar-tools.ts +278 -0
- package/connectors/apple/src/server.ts +541 -0
- package/connectors/apple/src/tools.ts +138 -0
- package/connectors/argocd/nimbus.extension.json +16 -0
- package/connectors/argocd/src/search-filter.ts +24 -0
- package/connectors/argocd/src/server.ts +158 -0
- package/connectors/athena/nimbus.extension.json +15 -0
- package/connectors/athena/src/server.ts +6 -0
- package/connectors/athena/src/tools.ts +181 -0
- package/connectors/aws/nimbus.extension.json +21 -0
- package/connectors/aws/src/server.ts +191 -0
- package/connectors/azure/nimbus.extension.json +15 -0
- package/connectors/azure/src/server.ts +139 -0
- package/connectors/bigeye/nimbus.extension.json +16 -0
- package/connectors/bigeye/src/search-filter.ts +22 -0
- package/connectors/bigeye/src/server.ts +161 -0
- package/connectors/bigquery/nimbus.extension.json +15 -0
- package/connectors/bigquery/src/server.ts +6 -0
- package/connectors/bigquery/src/tools.ts +175 -0
- package/connectors/bitbucket/nimbus.extension.json +15 -0
- package/connectors/bitbucket/src/server.ts +252 -0
- package/connectors/bitrise/nimbus.extension.json +15 -0
- package/connectors/bitrise/src/search-filter.ts +11 -0
- package/connectors/bitrise/src/server.ts +83 -0
- package/connectors/canva/nimbus.extension.json +15 -0
- package/connectors/canva/src/search-filter.ts +23 -0
- package/connectors/canva/src/server.ts +77 -0
- package/connectors/circleci/nimbus.extension.json +15 -0
- package/connectors/circleci/src/server.ts +184 -0
- package/connectors/cloud-logging/nimbus.extension.json +15 -0
- package/connectors/cloud-logging/src/server.ts +6 -0
- package/connectors/cloud-logging/src/tools.ts +115 -0
- package/connectors/cloudwatch/nimbus.extension.json +15 -0
- package/connectors/cloudwatch/src/server.ts +6 -0
- package/connectors/cloudwatch/src/tools.ts +144 -0
- package/connectors/codemagic/nimbus.extension.json +15 -0
- package/connectors/codemagic/src/search-filter.ts +11 -0
- package/connectors/codemagic/src/server.ts +74 -0
- package/connectors/confluence/nimbus.extension.json +15 -0
- package/connectors/confluence/src/kb-append.ts +25 -0
- package/connectors/confluence/src/server.ts +309 -0
- package/connectors/dagster/nimbus.extension.json +16 -0
- package/connectors/dagster/src/search-filter.ts +53 -0
- package/connectors/dagster/src/server.ts +218 -0
- package/connectors/databricks/nimbus.extension.json +16 -0
- package/connectors/databricks/src/search-filter.ts +28 -0
- package/connectors/databricks/src/server.ts +81 -0
- package/connectors/datadog/nimbus.extension.json +15 -0
- package/connectors/datadog/src/server.ts +56 -0
- package/connectors/dataprofile/nimbus.extension.json +16 -0
- package/connectors/dataprofile/src/profile.ts +298 -0
- package/connectors/dataprofile/src/server.ts +6 -0
- package/connectors/dataprofile/src/tools.ts +69 -0
- package/connectors/dbt/nimbus.extension.json +16 -0
- package/connectors/dbt/src/search-filter.ts +28 -0
- package/connectors/dbt/src/server.ts +96 -0
- package/connectors/dependencytrack/nimbus.extension.json +16 -0
- package/connectors/dependencytrack/src/search-filter.ts +24 -0
- package/connectors/dependencytrack/src/server.ts +80 -0
- package/connectors/discord/nimbus.extension.json +15 -0
- package/connectors/discord/src/server.ts +93 -0
- package/connectors/elasticsearch/nimbus.extension.json +16 -0
- package/connectors/elasticsearch/src/server.ts +6 -0
- package/connectors/elasticsearch/src/tools.ts +110 -0
- package/connectors/fastmail/nimbus.extension.json +16 -0
- package/connectors/fastmail/src/jmap-core.ts +86 -0
- package/connectors/fastmail/src/server.ts +194 -0
- package/connectors/fastmail/src/tools.ts +143 -0
- package/connectors/figma/nimbus.extension.json +15 -0
- package/connectors/figma/src/search-filter.ts +24 -0
- package/connectors/figma/src/server.ts +117 -0
- package/connectors/firebase/nimbus.extension.json +15 -0
- package/connectors/firebase/src/search-filter.ts +30 -0
- package/connectors/firebase/src/server.ts +94 -0
- package/connectors/firebase/src/token.ts +41 -0
- package/connectors/flagsmith/nimbus.extension.json +15 -0
- package/connectors/flagsmith/src/search-filter.ts +29 -0
- package/connectors/flagsmith/src/server.ts +102 -0
- package/connectors/flux/nimbus.extension.json +16 -0
- package/connectors/flux/src/search-filter.ts +42 -0
- package/connectors/flux/src/server.ts +182 -0
- package/connectors/gcp/nimbus.extension.json +15 -0
- package/connectors/gcp/src/server.ts +140 -0
- package/connectors/github/nimbus.extension.json +15 -0
- package/connectors/github/src/server.ts +347 -0
- package/connectors/github-actions/nimbus.extension.json +15 -0
- package/connectors/github-actions/src/server.ts +213 -0
- package/connectors/gitlab/nimbus.extension.json +15 -0
- package/connectors/gitlab/src/server.ts +392 -0
- package/connectors/gmail/nimbus.extension.json +15 -0
- package/connectors/gmail/src/server.ts +277 -0
- package/connectors/google-drive/nimbus.extension.json +15 -0
- package/connectors/google-drive/src/drive-query.ts +3 -0
- package/connectors/google-drive/src/server.ts +531 -0
- package/connectors/google-meet/nimbus.extension.json +15 -0
- package/connectors/google-meet/src/server.ts +89 -0
- package/connectors/google-photos/nimbus.extension.json +15 -0
- package/connectors/google-photos/src/server.ts +139 -0
- package/connectors/grafana/nimbus.extension.json +15 -0
- package/connectors/grafana/src/server.ts +61 -0
- package/connectors/great-expectations/nimbus.extension.json +16 -0
- package/connectors/great-expectations/src/gx-parse.ts +292 -0
- package/connectors/great-expectations/src/server.ts +6 -0
- package/connectors/great-expectations/src/tools.ts +91 -0
- package/connectors/greenhouse/nimbus.extension.json +15 -0
- package/connectors/greenhouse/src/search-filter.ts +65 -0
- package/connectors/greenhouse/src/server.ts +67 -0
- package/connectors/hubspot/nimbus.extension.json +15 -0
- package/connectors/hubspot/src/search-filter.ts +28 -0
- package/connectors/hubspot/src/server.ts +81 -0
- package/connectors/iac/nimbus.extension.json +14 -0
- package/connectors/iac/src/server.ts +145 -0
- package/connectors/imap/nimbus.extension.json +16 -0
- package/connectors/imap/src/imap-core.ts +110 -0
- package/connectors/imap/src/server.ts +232 -0
- package/connectors/imap/src/tools.ts +40 -0
- package/connectors/intercom/nimbus.extension.json +15 -0
- package/connectors/intercom/src/search-filter.ts +46 -0
- package/connectors/intercom/src/server.ts +65 -0
- package/connectors/jenkins/nimbus.extension.json +15 -0
- package/connectors/jenkins/src/jenkins-api.ts +156 -0
- package/connectors/jenkins/src/server.ts +223 -0
- package/connectors/jira/nimbus.extension.json +15 -0
- package/connectors/jira/src/server.ts +309 -0
- package/connectors/kubernetes/nimbus.extension.json +15 -0
- package/connectors/kubernetes/src/server.ts +163 -0
- package/connectors/launchdarkly/nimbus.extension.json +15 -0
- package/connectors/launchdarkly/src/search-filter.ts +31 -0
- package/connectors/launchdarkly/src/server.ts +79 -0
- package/connectors/lever/nimbus.extension.json +15 -0
- package/connectors/lever/src/search-filter.ts +35 -0
- package/connectors/lever/src/server.ts +64 -0
- package/connectors/linear/nimbus.extension.json +15 -0
- package/connectors/linear/src/server.ts +467 -0
- package/connectors/localdb/nimbus.extension.json +16 -0
- package/connectors/localdb/src/server.ts +6 -0
- package/connectors/localdb/src/sql-scan.ts +158 -0
- package/connectors/localdb/src/tools.ts +67 -0
- package/connectors/looker/nimbus.extension.json +16 -0
- package/connectors/looker/src/search-filter.ts +22 -0
- package/connectors/looker/src/server.ts +254 -0
- package/connectors/mendeley/nimbus.extension.json +15 -0
- package/connectors/mendeley/src/search-filter.ts +68 -0
- package/connectors/mendeley/src/server.ts +59 -0
- package/connectors/mercury/nimbus.extension.json +15 -0
- package/connectors/mercury/src/search-filter.ts +11 -0
- package/connectors/mercury/src/server.ts +61 -0
- package/connectors/metabase/nimbus.extension.json +16 -0
- package/connectors/metabase/src/search-filter.ts +22 -0
- package/connectors/metabase/src/server.ts +83 -0
- package/connectors/miro/nimbus.extension.json +15 -0
- package/connectors/miro/src/search-filter.ts +24 -0
- package/connectors/miro/src/server.ts +76 -0
- package/connectors/mlflow/nimbus.extension.json +16 -0
- package/connectors/mlflow/src/search-filter.ts +38 -0
- package/connectors/mlflow/src/server.ts +167 -0
- package/connectors/monte-carlo/nimbus.extension.json +16 -0
- package/connectors/monte-carlo/src/search-filter.ts +11 -0
- package/connectors/monte-carlo/src/server.ts +241 -0
- package/connectors/netlify/nimbus.extension.json +15 -0
- package/connectors/netlify/src/search-filter.ts +37 -0
- package/connectors/netlify/src/server.ts +64 -0
- package/connectors/newrelic/nimbus.extension.json +15 -0
- package/connectors/newrelic/src/server.ts +48 -0
- package/connectors/notion/nimbus.extension.json +15 -0
- package/connectors/notion/src/kb-append.ts +23 -0
- package/connectors/notion/src/server.ts +343 -0
- package/connectors/obsidian/nimbus.extension.json +19 -0
- package/connectors/obsidian/src/server.ts +433 -0
- package/connectors/onedrive/nimbus.extension.json +15 -0
- package/connectors/onedrive/src/server.ts +256 -0
- package/connectors/outlook/nimbus.extension.json +15 -0
- package/connectors/outlook/src/server.ts +358 -0
- package/connectors/outlook/src/tool-scope-policy.ts +53 -0
- package/connectors/pagerduty/nimbus.extension.json +15 -0
- package/connectors/pagerduty/src/server.ts +140 -0
- package/connectors/pipedrive/nimbus.extension.json +15 -0
- package/connectors/pipedrive/src/search-filter.ts +11 -0
- package/connectors/pipedrive/src/server.ts +62 -0
- package/connectors/powerbi/nimbus.extension.json +16 -0
- package/connectors/powerbi/src/search-filter.ts +22 -0
- package/connectors/powerbi/src/server.ts +249 -0
- package/connectors/prefect/nimbus.extension.json +16 -0
- package/connectors/prefect/src/search-filter.ts +40 -0
- package/connectors/prefect/src/server.ts +94 -0
- package/connectors/protonmail/nimbus.extension.json +16 -0
- package/connectors/protonmail/src/mail-core.ts +96 -0
- package/connectors/protonmail/src/server.ts +231 -0
- package/connectors/protonmail/src/tools.ts +45 -0
- package/connectors/raindrop/nimbus.extension.json +15 -0
- package/connectors/raindrop/src/search-filter.ts +20 -0
- package/connectors/raindrop/src/server.ts +107 -0
- package/connectors/ramp/nimbus.extension.json +15 -0
- package/connectors/ramp/src/search-filter.ts +37 -0
- package/connectors/ramp/src/server.ts +109 -0
- package/connectors/readwise/nimbus.extension.json +15 -0
- package/connectors/readwise/src/search-filter.ts +64 -0
- package/connectors/readwise/src/server.ts +92 -0
- package/connectors/sagemaker/nimbus.extension.json +15 -0
- package/connectors/sagemaker/src/server.ts +6 -0
- package/connectors/sagemaker/src/tools.ts +121 -0
- package/connectors/salesforce/nimbus.extension.json +15 -0
- package/connectors/salesforce/src/search-filter.ts +23 -0
- package/connectors/salesforce/src/server.ts +94 -0
- package/connectors/semgrep/nimbus.extension.json +15 -0
- package/connectors/semgrep/src/search-filter.ts +31 -0
- package/connectors/semgrep/src/server.ts +108 -0
- package/connectors/sentry/nimbus.extension.json +15 -0
- package/connectors/sentry/src/server.ts +66 -0
- package/connectors/slack/nimbus.extension.json +15 -0
- package/connectors/slack/src/server.ts +360 -0
- package/connectors/snowflake/nimbus.extension.json +16 -0
- package/connectors/snowflake/src/search-filter.ts +26 -0
- package/connectors/snowflake/src/server.ts +236 -0
- package/connectors/snyk/nimbus.extension.json +15 -0
- package/connectors/snyk/src/search-filter.ts +28 -0
- package/connectors/snyk/src/server.ts +144 -0
- package/connectors/sonarqube/nimbus.extension.json +15 -0
- package/connectors/sonarqube/src/search-filter.ts +28 -0
- package/connectors/sonarqube/src/server.ts +115 -0
- package/connectors/stackoverflow/nimbus.extension.json +15 -0
- package/connectors/stackoverflow/src/search-filter.ts +52 -0
- package/connectors/stackoverflow/src/server.ts +81 -0
- package/connectors/storybook/nimbus.extension.json +16 -0
- package/connectors/storybook/src/server.ts +6 -0
- package/connectors/storybook/src/storybook-parse.ts +67 -0
- package/connectors/storybook/src/tools.ts +68 -0
- package/connectors/stripe/nimbus.extension.json +15 -0
- package/connectors/stripe/src/search-filter.ts +19 -0
- package/connectors/stripe/src/server.ts +65 -0
- package/connectors/superset/nimbus.extension.json +16 -0
- package/connectors/superset/src/search-filter.ts +22 -0
- package/connectors/superset/src/server.ts +119 -0
- package/connectors/tableau/nimbus.extension.json +16 -0
- package/connectors/tableau/src/search-filter.ts +22 -0
- package/connectors/tableau/src/server.ts +248 -0
- package/connectors/teams/nimbus.extension.json +20 -0
- package/connectors/teams/src/bot-send.ts +72 -0
- package/connectors/teams/src/server.ts +257 -0
- package/connectors/testflight/nimbus.extension.json +15 -0
- package/connectors/testflight/src/jwt.ts +27 -0
- package/connectors/testflight/src/search-filter.ts +30 -0
- package/connectors/testflight/src/server.ts +74 -0
- package/connectors/vercel/nimbus.extension.json +15 -0
- package/connectors/vercel/src/search-filter.ts +34 -0
- package/connectors/vercel/src/server.ts +79 -0
- package/connectors/vertex-ai/nimbus.extension.json +15 -0
- package/connectors/vertex-ai/src/server.ts +6 -0
- package/connectors/vertex-ai/src/tools.ts +145 -0
- package/connectors/wiz/nimbus.extension.json +15 -0
- package/connectors/wiz/src/search-filter.ts +50 -0
- package/connectors/wiz/src/server.ts +192 -0
- package/connectors/workday/nimbus.extension.json +19 -0
- package/connectors/workday/src/search-filter.ts +5 -0
- package/connectors/workday/src/server.ts +78 -0
- package/connectors/workday/src/tools.ts +1 -0
- package/connectors/zendesk/nimbus.extension.json +16 -0
- package/connectors/zendesk/src/search-filter.ts +11 -0
- package/connectors/zendesk/src/server.ts +77 -0
- package/connectors/zoom/nimbus.extension.json +15 -0
- package/connectors/zoom/src/encode-meeting-path.ts +5 -0
- package/connectors/zoom/src/recordings-window.ts +34 -0
- package/connectors/zoom/src/search-filter.ts +42 -0
- package/connectors/zoom/src/server.ts +98 -0
- package/connectors/zotero/nimbus.extension.json +15 -0
- package/connectors/zotero/src/search-filter.ts +81 -0
- package/connectors/zotero/src/server.ts +82 -0
- package/package.json +152 -0
- package/shared/atlassian-json-fetch.ts +42 -0
- package/shared/audit-chain.ts +133 -0
- package/shared/connector-mode.ts +60 -0
- package/shared/consent-kit.ts +323 -0
- package/shared/fetch-bearer-json.ts +18 -0
- package/shared/header-safe.ts +28 -0
- package/shared/imap-bodystructure.ts +113 -0
- package/shared/imap-mail-core.ts +57 -0
- package/shared/imap-tool-kit.ts +293 -0
- package/shared/join-api-path.ts +18 -0
- package/shared/kb-markdown.ts +142 -0
- package/shared/mcp-search-tool.ts +37 -0
- package/shared/mcp-tool-kit.ts +35 -0
- package/shared/nimbus-spawn.ts +128 -0
- package/shared/rest-tool-kit.ts +18 -0
- package/shared/run-cli-json.ts +55 -0
- package/shared/run-read-only-mcp-connector.ts +59 -0
- package/shared/safe-cli-arg.ts +55 -0
- package/shared/search-filter.ts +140 -0
- package/shared/strip-trailing-slashes.ts +7 -0
- package/shared/write-scope.ts +58 -0
- package/standalone/src/bin.ts +19 -0
- package/standalone/src/launcher.ts +186 -0
- package/standalone/tsconfig.json +8 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
asObjectish,
|
|
3
|
+
makeQueryFilter,
|
|
4
|
+
type SearchMatchOptions,
|
|
5
|
+
stringField,
|
|
6
|
+
} from "../../../shared/search-filter.ts";
|
|
7
|
+
|
|
8
|
+
export type GreenhouseSearchMatchOptions = SearchMatchOptions;
|
|
9
|
+
|
|
10
|
+
function namedArrayText(row: Record<string, unknown>, key: string): string {
|
|
11
|
+
const arr = row[key];
|
|
12
|
+
if (!Array.isArray(arr)) {
|
|
13
|
+
return "";
|
|
14
|
+
}
|
|
15
|
+
const names: string[] = [];
|
|
16
|
+
for (const e of arr) {
|
|
17
|
+
if (e === null || typeof e !== "object" || Array.isArray(e)) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const name = (e as Record<string, unknown>)["name"];
|
|
21
|
+
if (typeof name === "string") {
|
|
22
|
+
names.push(name);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return names.join(" ");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function officeLocationText(row: Record<string, unknown>): string {
|
|
29
|
+
const arr = row["offices"];
|
|
30
|
+
if (!Array.isArray(arr)) {
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
const locs: string[] = [];
|
|
34
|
+
for (const e of arr) {
|
|
35
|
+
if (e === null || typeof e !== "object" || Array.isArray(e)) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const loc = (e as Record<string, unknown>)["location"];
|
|
39
|
+
if (loc === null || typeof loc !== "object" || Array.isArray(loc)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const name = (loc as Record<string, unknown>)["name"];
|
|
43
|
+
if (typeof name === "string") {
|
|
44
|
+
locs.push(name);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return locs.join(" ");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function fieldsOf(item: unknown): readonly string[] | null {
|
|
51
|
+
const row = asObjectish(item);
|
|
52
|
+
if (row === undefined) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
return [
|
|
56
|
+
stringField(row, "name"),
|
|
57
|
+
stringField(row, "status"),
|
|
58
|
+
stringField(row, "requisition_id"),
|
|
59
|
+
namedArrayText(row, "departments"),
|
|
60
|
+
namedArrayText(row, "offices"),
|
|
61
|
+
officeLocationText(row),
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const filterGreenhouseJobs = makeQueryFilter(fieldsOf);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { matchesResult, searchToolInputSchema } from "../../../shared/mcp-search-tool.ts";
|
|
3
|
+
import {
|
|
4
|
+
encodeBasicAuthHeader,
|
|
5
|
+
mcpJsonResult as jsonResult,
|
|
6
|
+
} from "../../../shared/mcp-tool-kit.ts";
|
|
7
|
+
import { runReadOnlyMcpConnector } from "../../../shared/run-read-only-mcp-connector.ts";
|
|
8
|
+
import { filterGreenhouseJobs } from "./search-filter.ts";
|
|
9
|
+
|
|
10
|
+
const BASE = "https://harvest.greenhouse.io";
|
|
11
|
+
|
|
12
|
+
function apiKey(): string {
|
|
13
|
+
const t = process.env["GREENHOUSE_API_KEY"]?.trim();
|
|
14
|
+
if (t === undefined || t === "") {
|
|
15
|
+
throw new Error("GREENHOUSE_API_KEY is not set");
|
|
16
|
+
}
|
|
17
|
+
return t;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function authHeader(): Record<string, string> {
|
|
21
|
+
return { Authorization: encodeBasicAuthHeader(apiKey(), ""), Accept: "application/json" };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function greenhouseGet(path: string): Promise<unknown> {
|
|
25
|
+
const res = await fetch(`${BASE}${path}`, { headers: authHeader() });
|
|
26
|
+
const text = await res.text();
|
|
27
|
+
if (!res.ok) {
|
|
28
|
+
throw new Error(`Greenhouse ${String(res.status)}: ${text.slice(0, 400)}`);
|
|
29
|
+
}
|
|
30
|
+
return JSON.parse(text) as unknown;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
await runReadOnlyMcpConnector("nimbus-greenhouse", (reg) => {
|
|
34
|
+
reg(
|
|
35
|
+
"greenhouse_list",
|
|
36
|
+
"List the company's Greenhouse Harvest job openings (`GET /v1/jobs?per_page=100`). Returns a bare JSON array of job objects (NOT an envelope), each carrying the name, status, requisition id, departments, and offices.",
|
|
37
|
+
z.object({
|
|
38
|
+
per_page: z.number().int().min(1).max(100).optional(),
|
|
39
|
+
}),
|
|
40
|
+
async (p) => {
|
|
41
|
+
const search = new URLSearchParams({ per_page: String(p.per_page ?? 100), page: "1" });
|
|
42
|
+
return jsonResult(await greenhouseGet(`/v1/jobs?${search.toString()}`));
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
reg(
|
|
47
|
+
"greenhouse_get",
|
|
48
|
+
"Fetch one Greenhouse job by its id (`GET /v1/jobs/{id}`). Returns the job object directly. Throws when no match is found.",
|
|
49
|
+
z.object({
|
|
50
|
+
id: z.string().min(1),
|
|
51
|
+
}),
|
|
52
|
+
async (p) => {
|
|
53
|
+
return jsonResult(await greenhouseGet(`/v1/jobs/${encodeURIComponent(p.id)}`));
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
reg(
|
|
58
|
+
"greenhouse_search",
|
|
59
|
+
"Substring search across the company's Greenhouse job openings (first page only). Matches the query against the job name, status, requisition id, the department names, and the office names + locations (case-insensitive). Returns a `{ matches: [...] }` envelope.",
|
|
60
|
+
searchToolInputSchema(100),
|
|
61
|
+
async (p) => {
|
|
62
|
+
const search = new URLSearchParams({ per_page: "100", page: "1" });
|
|
63
|
+
const root = await greenhouseGet(`/v1/jobs?${search.toString()}`);
|
|
64
|
+
return matchesResult(root, filterGreenhouseJobs, p);
|
|
65
|
+
},
|
|
66
|
+
);
|
|
67
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "com.nimbus.hubspot",
|
|
3
|
+
"displayName": "HubSpot",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "HubSpot CRM connector (read-only). Surfaces the authenticated portal's deals as hubspot:deal items in the local index via GET /crm/v3/objects/deals — the deal name, the amount, the deal stage, the pipeline, the close date, the create date, and the last-modified timestamp. Bearer OAuth auth (Authorization: Bearer <token>; short-lived access token refreshed by the Gateway via the 3-legged OAuth authorization-code flow; never logged); fixed SaaS host api.hubapi.com. The list endpoint paginates by the paging.next.after cursor until absent; the gateway-side syncable walks a single forward pass per cycle, page-capped. Read-only — hitlRequired is intentionally empty. Sparse structured pipeline/spend metadata; deal URLs require a portal id the API does not return, so url/canonical_url are null.",
|
|
6
|
+
"author": "Nimbus",
|
|
7
|
+
"entrypoint": "dist/server.js",
|
|
8
|
+
"runtime": "bun",
|
|
9
|
+
"permissions": {
|
|
10
|
+
"network": ["api.hubapi.com"]
|
|
11
|
+
},
|
|
12
|
+
"hitlRequired": [],
|
|
13
|
+
"syncInterval": 600,
|
|
14
|
+
"minNimbusVersion": "0.2.0"
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
asObjectish,
|
|
3
|
+
makeQueryFilter,
|
|
4
|
+
type SearchMatchOptions,
|
|
5
|
+
stringField,
|
|
6
|
+
} from "../../../shared/search-filter.ts";
|
|
7
|
+
|
|
8
|
+
export type HubspotSearchMatchOptions = SearchMatchOptions;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* HubSpot deal objects nest their searchable text under a `properties` map:
|
|
12
|
+
* `{ id, properties: { dealname, dealstage, pipeline, ... } }`. Match against the
|
|
13
|
+
* deal name, stage, and pipeline (case-insensitive substring).
|
|
14
|
+
*/
|
|
15
|
+
function fieldsOf(item: unknown): readonly string[] | null {
|
|
16
|
+
const row = asObjectish(item);
|
|
17
|
+
if (row === undefined) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const props = asObjectish(row["properties"]) ?? {};
|
|
21
|
+
return [
|
|
22
|
+
stringField(props, "dealname"),
|
|
23
|
+
stringField(props, "dealstage"),
|
|
24
|
+
stringField(props, "pipeline"),
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const filterHubspotDeals = makeQueryFilter(fieldsOf);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { searchToolInputSchema } from "../../../shared/mcp-search-tool.ts";
|
|
3
|
+
import { mcpJsonResult as jsonResult } from "../../../shared/mcp-tool-kit.ts";
|
|
4
|
+
import { runReadOnlyMcpConnector } from "../../../shared/run-read-only-mcp-connector.ts";
|
|
5
|
+
import { filterHubspotDeals } from "./search-filter.ts";
|
|
6
|
+
|
|
7
|
+
const BASE = "https://api.hubapi.com";
|
|
8
|
+
const DEAL_PROPERTIES =
|
|
9
|
+
"dealname,amount,dealstage,pipeline,closedate,createdate,hs_lastmodifieddate";
|
|
10
|
+
|
|
11
|
+
function apiToken(): string {
|
|
12
|
+
const t = process.env["HUBSPOT_TOKEN"]?.trim();
|
|
13
|
+
if (t === undefined || t === "") {
|
|
14
|
+
throw new Error("HUBSPOT_TOKEN is not set");
|
|
15
|
+
}
|
|
16
|
+
return t;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function authHeader(): Record<string, string> {
|
|
20
|
+
return { Authorization: `Bearer ${apiToken()}`, Accept: "application/json" };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function hubspotGet(path: string): Promise<unknown> {
|
|
24
|
+
const res = await fetch(`${BASE}${path}`, { headers: authHeader() });
|
|
25
|
+
const text = await res.text();
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
throw new Error(`HubSpot ${String(res.status)}: ${text.slice(0, 400)}`);
|
|
28
|
+
}
|
|
29
|
+
return JSON.parse(text) as unknown;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function dealsFrom(root: unknown): unknown[] {
|
|
33
|
+
const results = (root as { results?: unknown } | null)?.results;
|
|
34
|
+
return Array.isArray(results) ? results : [];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await runReadOnlyMcpConnector("nimbus-hubspot", (reg) => {
|
|
38
|
+
reg(
|
|
39
|
+
"hubspot_list",
|
|
40
|
+
"List the authenticated portal's HubSpot deals (GET /crm/v3/objects/deals?limit=N&properties=dealname,amount,dealstage,pipeline,closedate,createdate,hs_lastmodifieddate). Returns the { results: [...], paging?: { next?: { after } } } envelope — `results` holds the deal objects, each shaped { id, properties: { dealname, amount, dealstage, pipeline, closedate, createdate, hs_lastmodifieddate }, createdAt, updatedAt }. `limit` (default 100, max 100) caps page_size of the single first-page request.",
|
|
41
|
+
z.object({
|
|
42
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
43
|
+
}),
|
|
44
|
+
async (p) => {
|
|
45
|
+
const params = new URLSearchParams({
|
|
46
|
+
limit: String(p.limit ?? 100),
|
|
47
|
+
properties: DEAL_PROPERTIES,
|
|
48
|
+
});
|
|
49
|
+
return jsonResult(await hubspotGet(`/crm/v3/objects/deals?${params.toString()}`));
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
reg(
|
|
54
|
+
"hubspot_get",
|
|
55
|
+
"Fetch one HubSpot deal by its id (GET /crm/v3/objects/deals/{dealId}?properties=dealname,amount,dealstage,pipeline,closedate,createdate,hs_lastmodifieddate). Returns the deal object directly (NOT wrapped in `results`). Throws when no deal with that id exists.",
|
|
56
|
+
z.object({
|
|
57
|
+
id: z.string().min(1),
|
|
58
|
+
}),
|
|
59
|
+
async (p) => {
|
|
60
|
+
const params = new URLSearchParams({ properties: DEAL_PROPERTIES });
|
|
61
|
+
return jsonResult(
|
|
62
|
+
await hubspotGet(`/crm/v3/objects/deals/${encodeURIComponent(p.id)}?${params.toString()}`),
|
|
63
|
+
);
|
|
64
|
+
},
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
reg(
|
|
68
|
+
"hubspot_search",
|
|
69
|
+
"**Substring search over the FIRST PAGE only** (up to 100 most-recently-listed deals) of the authenticated portal's HubSpot deals. This tool fetches GET /crm/v3/objects/deals?limit=100 once and matches the query locally (case-insensitive) against the deal name, deal stage, and pipeline. **Deals beyond the first page are not searchable here — query the local Nimbus index instead for full coverage.** Returns a { matches: [...] } envelope.",
|
|
70
|
+
searchToolInputSchema(100),
|
|
71
|
+
async (p) => {
|
|
72
|
+
const params = new URLSearchParams({ limit: "100", properties: DEAL_PROPERTIES });
|
|
73
|
+
const root = await hubspotGet(`/crm/v3/objects/deals?${params.toString()}`);
|
|
74
|
+
const matches = filterHubspotDeals(dealsFrom(root), {
|
|
75
|
+
query: p.query,
|
|
76
|
+
limit: p.limit,
|
|
77
|
+
});
|
|
78
|
+
return jsonResult({ matches });
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "com.nimbus.iac",
|
|
3
|
+
"displayName": "Infrastructure-as-Code",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Terraform / Pulumi / OpenTofu CLI helpers. The connector itself opens no sockets; CLI subprocesses' network access is sandbox-bounded. Workspace paths are tool-call scoped (workingDirectory argument), not baked into the manifest. Mutations require Gateway HITL.",
|
|
6
|
+
"author": "Nimbus",
|
|
7
|
+
"entrypoint": "dist/server.js",
|
|
8
|
+
"runtime": "bun",
|
|
9
|
+
"permissions": {
|
|
10
|
+
"network": []
|
|
11
|
+
},
|
|
12
|
+
"hitlRequired": ["write", "delete"],
|
|
13
|
+
"minNimbusVersion": "0.2.0"
|
|
14
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import {
|
|
5
|
+
createRegisterSimpleTool,
|
|
6
|
+
createZodToolRegistrar,
|
|
7
|
+
mcpJsonResult as jsonResult,
|
|
8
|
+
} from "../../../shared/mcp-tool-kit.ts";
|
|
9
|
+
import { runCliOkThrowing } from "../../../shared/run-cli-json.ts";
|
|
10
|
+
|
|
11
|
+
const mcp = new McpServer({ name: "nimbus-iac", version: "0.1.0" });
|
|
12
|
+
|
|
13
|
+
import { createWriteToolRegistrar } from "../../../shared/consent-kit.ts";
|
|
14
|
+
|
|
15
|
+
const reg = createZodToolRegistrar(createRegisterSimpleTool(mcp));
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Every MUTATING iac tool goes through here. Outside the gateway this adds the
|
|
19
|
+
* consent gate, the write-scope allow-list, the mutation budget and the audit record; inside
|
|
20
|
+
* the gateway it is a pass-through, because executor.ts (I2) is the gate there.
|
|
21
|
+
*/
|
|
22
|
+
const registerWriteTool = createWriteToolRegistrar(mcp, {
|
|
23
|
+
connector: "iac",
|
|
24
|
+
scopeEnv: "NIMBUS_MCP_IAC_WRITE_SCOPE",
|
|
25
|
+
scopeKinds: ["dir", "stack"],
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const processEnv = process.env as Record<string, string | undefined>;
|
|
29
|
+
|
|
30
|
+
reg(
|
|
31
|
+
"iac_terraform_plan",
|
|
32
|
+
"Run terraform plan in a directory.",
|
|
33
|
+
z.object({ workingDirectory: z.string().min(1) }),
|
|
34
|
+
async (p) => {
|
|
35
|
+
await runCliOkThrowing(["terraform", "-chdir", p.workingDirectory, "plan", "-input=false"], {
|
|
36
|
+
...processEnv,
|
|
37
|
+
});
|
|
38
|
+
return jsonResult({ ok: true });
|
|
39
|
+
},
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
registerWriteTool(
|
|
43
|
+
"iac_terraform_apply",
|
|
44
|
+
{
|
|
45
|
+
mutates: "iac.terraform.apply",
|
|
46
|
+
recoverable: true,
|
|
47
|
+
scopeTargetOf: (p) => ({ kind: "dir", value: p.workingDirectory }),
|
|
48
|
+
},
|
|
49
|
+
"Run terraform apply.",
|
|
50
|
+
z.object({ workingDirectory: z.string().min(1) }),
|
|
51
|
+
async (p) => {
|
|
52
|
+
await runCliOkThrowing(
|
|
53
|
+
["terraform", "-chdir", p.workingDirectory, "apply", "-auto-approve", "-input=false"],
|
|
54
|
+
{ ...processEnv },
|
|
55
|
+
);
|
|
56
|
+
return jsonResult({ ok: true });
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
registerWriteTool(
|
|
61
|
+
"iac_terraform_destroy",
|
|
62
|
+
{
|
|
63
|
+
mutates: "iac.terraform.destroy",
|
|
64
|
+
// Destroying infrastructure cannot be undone from its own result, and there is nothing
|
|
65
|
+
// queryable to snapshot, so the identifying parameters ARE the pre-state: a record naming
|
|
66
|
+
// WHICH directory was destroyed still beats silence.
|
|
67
|
+
recoverable: false,
|
|
68
|
+
capturePreState: (p) => Promise.resolve({ workingDirectory: p.workingDirectory }),
|
|
69
|
+
scopeTargetOf: (p) => ({ kind: "dir", value: p.workingDirectory }),
|
|
70
|
+
},
|
|
71
|
+
"Run terraform destroy.",
|
|
72
|
+
z.object({ workingDirectory: z.string().min(1) }),
|
|
73
|
+
async (p) => {
|
|
74
|
+
await runCliOkThrowing(
|
|
75
|
+
["terraform", "-chdir", p.workingDirectory, "destroy", "-auto-approve", "-input=false"],
|
|
76
|
+
{ ...processEnv },
|
|
77
|
+
);
|
|
78
|
+
return jsonResult({ ok: true });
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
registerWriteTool(
|
|
83
|
+
"iac_cloudformation_deploy",
|
|
84
|
+
{
|
|
85
|
+
mutates: "iac.cloudformation.deploy",
|
|
86
|
+
recoverable: true,
|
|
87
|
+
scopeTargetOf: (p) => ({ kind: "stack", value: p.stackName }),
|
|
88
|
+
},
|
|
89
|
+
"Deploy a CloudFormation stack via AWS CLI.",
|
|
90
|
+
z.object({
|
|
91
|
+
stackName: z.string().min(1),
|
|
92
|
+
templateBody: z.string().min(1),
|
|
93
|
+
}),
|
|
94
|
+
async (p) => {
|
|
95
|
+
await runCliOkThrowing(
|
|
96
|
+
[
|
|
97
|
+
"aws",
|
|
98
|
+
"cloudformation",
|
|
99
|
+
"deploy",
|
|
100
|
+
"--stack-name",
|
|
101
|
+
p.stackName,
|
|
102
|
+
"--template-body",
|
|
103
|
+
p.templateBody,
|
|
104
|
+
"--capabilities",
|
|
105
|
+
"CAPABILITY_IAM",
|
|
106
|
+
],
|
|
107
|
+
{ ...processEnv },
|
|
108
|
+
);
|
|
109
|
+
return jsonResult({ ok: true });
|
|
110
|
+
},
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
reg(
|
|
114
|
+
"iac_pulumi_preview",
|
|
115
|
+
"Run pulumi preview in a stack directory.",
|
|
116
|
+
z.object({ workingDirectory: z.string().min(1) }),
|
|
117
|
+
async (p) => {
|
|
118
|
+
await runCliOkThrowing(
|
|
119
|
+
["pulumi", "preview", "--cwd", p.workingDirectory, "--non-interactive"],
|
|
120
|
+
{ ...processEnv },
|
|
121
|
+
);
|
|
122
|
+
return jsonResult({ ok: true });
|
|
123
|
+
},
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
registerWriteTool(
|
|
127
|
+
"iac_pulumi_up",
|
|
128
|
+
{
|
|
129
|
+
mutates: "iac.pulumi.up",
|
|
130
|
+
recoverable: true,
|
|
131
|
+
scopeTargetOf: (p) => ({ kind: "dir", value: p.workingDirectory }),
|
|
132
|
+
},
|
|
133
|
+
"Run pulumi up.",
|
|
134
|
+
z.object({ workingDirectory: z.string().min(1) }),
|
|
135
|
+
async (p) => {
|
|
136
|
+
await runCliOkThrowing(
|
|
137
|
+
["pulumi", "up", "--yes", "--cwd", p.workingDirectory, "--non-interactive"],
|
|
138
|
+
{ ...processEnv },
|
|
139
|
+
);
|
|
140
|
+
return jsonResult({ ok: true });
|
|
141
|
+
},
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const transport = new StdioServerTransport();
|
|
145
|
+
await mcp.connect(transport);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "com.nimbus.imap",
|
|
3
|
+
"displayName": "IMAP / SMTP Email",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Generic IMAP/SMTP email connector (Tier-4 EMAIL class). Indexes the user's mailbox over raw IMAP as `imap:email` items — message HEADERS (subject, from, to/cc, date, message-id), a short capped plain-text body PREVIEW (~2 KB / 2000 chars), and attachment METADATA only (filename, size, mimetype). It NEVER downloads or parses attachment bytes and never fetches the full message body: it uses the IMAP ENVELOPE + BODYSTRUCTURE for headers and attachment metadata, and fetches only a truncated text/plain body part for the preview. Read tools (`imap_list`, `imap_get`, `imap_search`) plus one HITL-gated write tool (`imap_mail_send`) that sends mail over SMTP via nodemailer. IMAP/SMTP credentials are per-tenant (host, port, username, password) and arrive as scoped environment variables injected at spawn time (IMAP_HOST/IMAP_PORT/IMAP_USERNAME/IMAP_PASSWORD and IMAP_SMTP_*) — the connector never reads the vault. Because the IMAP/SMTP hosts are user-configured and non-443 (IMAP 993, SMTP 465/587), the static manifest network list is intentionally empty: the concrete <imap.host>:993 + <smtp.host>:<port> host:port entries are added to the sandbox network allow-list at spawn time by phase3AddImapMcp via manifestWithExtraNetworkHosts.",
|
|
6
|
+
"author": "Nimbus",
|
|
7
|
+
"entrypoint": "dist/server.js",
|
|
8
|
+
"runtime": "bun",
|
|
9
|
+
"permissions": {
|
|
10
|
+
"network": [],
|
|
11
|
+
"filesystem": { "read": [], "write": [] }
|
|
12
|
+
},
|
|
13
|
+
"hitlRequired": ["write"],
|
|
14
|
+
"syncInterval": 300,
|
|
15
|
+
"minNimbusVersion": "0.2.0"
|
|
16
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IMAP/SMTP connector core — transport-agnostic logic for the read tools
|
|
3
|
+
* (`imap_list`, `imap_get`, `imap_search`) and the HITL-gated send tool
|
|
4
|
+
* (`imap_mail_send`).
|
|
5
|
+
*
|
|
6
|
+
* HARD SCOPE CONSTRAINT (security): this connector indexes HEADERS + a short
|
|
7
|
+
* capped plain-text body PREVIEW + attachment METADATA only. It NEVER downloads
|
|
8
|
+
* or parses attachment bytes and never fetches the full message body. The IMAP
|
|
9
|
+
* client interface below deliberately exposes only `envelope` + `bodyStructure`
|
|
10
|
+
* (headers / attachment metadata) and a single truncated text body part for the
|
|
11
|
+
* preview — there is no surface to request `BODY[]` or an attachment part.
|
|
12
|
+
*
|
|
13
|
+
* The IMAP client and SMTP mailer are injected so tests never open real sockets.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { MailAddress } from "../../../shared/imap-mail-core.ts";
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
capPreview,
|
|
20
|
+
clampLimit,
|
|
21
|
+
formatAddress,
|
|
22
|
+
PREVIEW_FETCH_BYTES,
|
|
23
|
+
PREVIEW_MAX_CHARS,
|
|
24
|
+
} from "../../../shared/imap-mail-core.ts";
|
|
25
|
+
|
|
26
|
+
/** One parsed address (name optional). */
|
|
27
|
+
export type ImapAddress = MailAddress;
|
|
28
|
+
|
|
29
|
+
/** Message ENVELOPE — RFC 2822 header fields only. */
|
|
30
|
+
export interface ImapEnvelope {
|
|
31
|
+
readonly date?: Date | string | null;
|
|
32
|
+
readonly subject?: string | null;
|
|
33
|
+
readonly messageId?: string | null;
|
|
34
|
+
readonly from?: readonly ImapAddress[];
|
|
35
|
+
readonly to?: readonly ImapAddress[];
|
|
36
|
+
readonly cc?: readonly ImapAddress[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Attachment METADATA only — filename, size, mimetype. NEVER the bytes.
|
|
41
|
+
* Derived from BODYSTRUCTURE.
|
|
42
|
+
*/
|
|
43
|
+
export interface ImapAttachmentMeta {
|
|
44
|
+
readonly filename: string | null;
|
|
45
|
+
readonly sizeBytes: number | null;
|
|
46
|
+
readonly mimeType: string | null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A single mailbox message reduced to header + attachment-metadata + a capped
|
|
51
|
+
* text preview. This is the ONLY shape the connector ever materializes; it has
|
|
52
|
+
* no field that could carry attachment content or a full body.
|
|
53
|
+
*/
|
|
54
|
+
export interface ImapMessageMeta {
|
|
55
|
+
readonly uid: number;
|
|
56
|
+
readonly mailbox: string;
|
|
57
|
+
readonly uidValidity: string | null;
|
|
58
|
+
readonly envelope: ImapEnvelope;
|
|
59
|
+
readonly attachments: readonly ImapAttachmentMeta[];
|
|
60
|
+
/** Plain-text body preview, already capped to {@link PREVIEW_MAX_CHARS}. */
|
|
61
|
+
readonly preview: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Listing options. */
|
|
65
|
+
export interface ImapListOptions {
|
|
66
|
+
readonly mailbox?: string;
|
|
67
|
+
readonly limit?: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Search options — searches header/envelope fields, never document/body content scans. */
|
|
71
|
+
export interface ImapSearchOptions {
|
|
72
|
+
readonly query: string;
|
|
73
|
+
readonly mailbox?: string;
|
|
74
|
+
readonly limit?: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Minimal IMAP client surface the connector depends on. Implemented for real by
|
|
79
|
+
* the imapflow adapter in `server.ts` and by a fake in tests. Deliberately
|
|
80
|
+
* exposes ONLY header/attachment-metadata + capped-preview reads.
|
|
81
|
+
*/
|
|
82
|
+
export interface ImapClient {
|
|
83
|
+
/** List the most recent messages (header + attachment metadata + preview). */
|
|
84
|
+
list(options: ImapListOptions): Promise<ImapMessageMeta[]>;
|
|
85
|
+
/** Fetch one message's header + attachment metadata + preview by uid. */
|
|
86
|
+
get(uid: number, mailbox?: string): Promise<ImapMessageMeta | null>;
|
|
87
|
+
/** Search by subject/from/to substring; returns matching message metas. */
|
|
88
|
+
search(options: ImapSearchOptions): Promise<ImapMessageMeta[]>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Outgoing message for the SMTP send tool. */
|
|
92
|
+
export interface SendMailInput {
|
|
93
|
+
readonly to: string;
|
|
94
|
+
readonly subject: string;
|
|
95
|
+
readonly body: string;
|
|
96
|
+
readonly cc?: string;
|
|
97
|
+
readonly bcc?: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Result of a send (message id assigned by the SMTP server, if any). */
|
|
101
|
+
export interface SendMailResult {
|
|
102
|
+
readonly messageId: string | null;
|
|
103
|
+
readonly accepted: readonly string[];
|
|
104
|
+
readonly rejected: readonly string[];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Minimal SMTP mailer surface; implemented for real over nodemailer. */
|
|
108
|
+
export interface SmtpMailer {
|
|
109
|
+
send(input: SendMailInput): Promise<SendMailResult>;
|
|
110
|
+
}
|