@geteigen/cli 0.0.0-stage → 3.0.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/README.md +154 -2
- package/dist/agent.d.ts +32 -0
- package/dist/agent.js +246 -0
- package/dist/auth.d.ts +5 -0
- package/dist/auth.js +33 -0
- package/dist/cli/src/agent.d.ts +24 -0
- package/dist/cli/src/agent.js +260 -0
- package/dist/cli/src/agentTools.d.ts +10 -0
- package/dist/cli/src/agentTools.js +70 -0
- package/dist/cli/src/auth.d.ts +5 -0
- package/dist/cli/src/auth.js +33 -0
- package/dist/cli/src/config.d.ts +11 -0
- package/dist/cli/src/config.js +51 -0
- package/dist/cli/src/cursorAuth.d.ts +10 -0
- package/dist/cli/src/cursorAuth.js +92 -0
- package/dist/cli/src/index.d.ts +2 -0
- package/dist/cli/src/index.js +244 -0
- package/dist/cli/src/listModels.d.ts +14 -0
- package/dist/cli/src/listModels.js +196 -0
- package/dist/cli/src/listSessions.d.ts +9 -0
- package/dist/cli/src/listSessions.js +37 -0
- package/dist/cli/src/machineConfig.d.ts +20 -0
- package/dist/cli/src/machineConfig.js +66 -0
- package/dist/cli/src/pickFolder.d.ts +5 -0
- package/dist/cli/src/pickFolder.js +65 -0
- package/dist/cli/src/proc.d.ts +23 -0
- package/dist/cli/src/proc.js +77 -0
- package/dist/cli/src/service.d.ts +17 -0
- package/dist/cli/src/service.js +246 -0
- package/dist/cli/src/workRoots.d.ts +30 -0
- package/dist/cli/src/workRoots.js +221 -0
- package/dist/cli/src/worker.d.ts +8 -0
- package/dist/cli/src/worker.js +51 -0
- package/dist/cli/src/workerCore.d.ts +47 -0
- package/dist/cli/src/workerCore.js +702 -0
- package/dist/cli/src/workspace.d.ts +8 -0
- package/dist/cli/src/workspace.js +269 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.js +51 -0
- package/dist/cursorAuth.d.ts +10 -0
- package/dist/cursorAuth.js +95 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +108 -0
- package/dist/listModels.d.ts +6 -0
- package/dist/listModels.js +62 -0
- package/dist/listSessions.d.ts +9 -0
- package/dist/listSessions.js +37 -0
- package/dist/pickFolder.d.ts +5 -0
- package/dist/pickFolder.js +65 -0
- package/dist/shared/actionDrafts.d.ts +83 -0
- package/dist/shared/actionDrafts.js +169 -0
- package/dist/shared/agentArtifacts.d.ts +49 -0
- package/dist/shared/agentArtifacts.js +169 -0
- package/dist/shared/agentLabel.d.ts +18 -0
- package/dist/shared/agentLabel.js +22 -0
- package/dist/shared/agentMentions.d.ts +38 -0
- package/dist/shared/agentMentions.js +110 -0
- package/dist/shared/agentRepos.d.ts +28 -0
- package/dist/shared/agentRepos.js +60 -0
- package/dist/shared/agentRunStatus.d.ts +12 -0
- package/dist/shared/agentRunStatus.js +17 -0
- package/dist/shared/agentUsage.d.ts +24 -0
- package/dist/shared/agentUsage.js +139 -0
- package/dist/shared/approvals.d.ts +44 -0
- package/dist/shared/approvals.js +97 -0
- package/dist/shared/askEigen.d.ts +190 -0
- package/dist/shared/askEigen.js +76 -0
- package/dist/shared/attribution.d.ts +25 -0
- package/dist/shared/attribution.js +63 -0
- package/dist/shared/automations.d.ts +136 -0
- package/dist/shared/automations.js +546 -0
- package/dist/shared/backends/claudeCode.d.ts +42 -0
- package/dist/shared/backends/claudeCode.js +540 -0
- package/dist/shared/backends/codex.d.ts +15 -0
- package/dist/shared/backends/codex.js +287 -0
- package/dist/shared/backends/cursor.d.ts +102 -0
- package/dist/shared/backends/cursor.js +1197 -0
- package/dist/shared/backends/index.d.ts +18 -0
- package/dist/shared/backends/index.js +58 -0
- package/dist/shared/backends/opencode.d.ts +40 -0
- package/dist/shared/backends/opencode.js +397 -0
- package/dist/shared/backends/types.d.ts +171 -0
- package/dist/shared/backends/types.js +19 -0
- package/dist/shared/backends/usage.d.ts +8 -0
- package/dist/shared/backends/usage.js +71 -0
- package/dist/shared/billingPlans.d.ts +60 -0
- package/dist/shared/billingPlans.js +262 -0
- package/dist/shared/brain.d.ts +353 -0
- package/dist/shared/brain.js +487 -0
- package/dist/shared/clarifyingQuestions.d.ts +13 -0
- package/dist/shared/clarifyingQuestions.js +207 -0
- package/dist/shared/claudeModels.d.ts +10 -0
- package/dist/shared/claudeModels.js +52 -0
- package/dist/shared/cloudBackends.d.ts +21 -0
- package/dist/shared/cloudBackends.js +29 -0
- package/dist/shared/codexModels.d.ts +10 -0
- package/dist/shared/codexModels.js +28 -0
- package/dist/shared/contextWindows.d.ts +2 -0
- package/dist/shared/contextWindows.js +30 -0
- package/dist/shared/cursorMcpConfig.d.ts +14 -0
- package/dist/shared/cursorMcpConfig.js +43 -0
- package/dist/shared/cursorProjectMcp.d.ts +10 -0
- package/dist/shared/cursorProjectMcp.js +42 -0
- package/dist/shared/docs.d.ts +59 -0
- package/dist/shared/docs.js +87 -0
- package/dist/shared/events.d.ts +929 -0
- package/dist/shared/events.js +59 -0
- package/dist/shared/integrations.d.ts +266 -0
- package/dist/shared/integrations.js +449 -0
- package/dist/shared/issueTranscript.d.ts +64 -0
- package/dist/shared/issueTranscript.js +387 -0
- package/dist/shared/issues.d.ts +139 -0
- package/dist/shared/issues.js +217 -0
- package/dist/shared/machines.d.ts +115 -0
- package/dist/shared/machines.js +58 -0
- package/dist/shared/markdownMedia.d.ts +13 -0
- package/dist/shared/markdownMedia.js +41 -0
- package/dist/shared/notificationText.d.ts +6 -0
- package/dist/shared/notificationText.js +38 -0
- package/dist/shared/opencodeModels.d.ts +19 -0
- package/dist/shared/opencodeModels.js +62 -0
- package/dist/shared/opencodeSession.d.ts +7 -0
- package/dist/shared/opencodeSession.js +30 -0
- package/dist/shared/orchestration.d.ts +58 -0
- package/dist/shared/orchestration.js +12 -0
- package/dist/shared/orgs.d.ts +47 -0
- package/dist/shared/orgs.js +49 -0
- package/dist/shared/personalOrg.d.ts +5 -0
- package/dist/shared/personalOrg.js +12 -0
- package/dist/shared/plans.d.ts +3 -0
- package/dist/shared/plans.js +19 -0
- package/dist/shared/providerModels.d.ts +40 -0
- package/dist/shared/providerModels.js +503 -0
- package/dist/shared/roomAttention.d.ts +17 -0
- package/dist/shared/roomAttention.js +36 -0
- package/dist/shared/roomContext.d.ts +120 -0
- package/dist/shared/roomContext.js +133 -0
- package/dist/shared/roomPermissions.d.ts +56 -0
- package/dist/shared/roomPermissions.js +133 -0
- package/dist/shared/sessionSeats.d.ts +29 -0
- package/dist/shared/sessionSeats.js +57 -0
- package/dist/shared/slashCommands.d.ts +39 -0
- package/dist/shared/slashCommands.js +166 -0
- package/dist/shared/space.d.ts +33 -0
- package/dist/shared/space.js +54 -0
- package/dist/shared/spaceFeed.d.ts +78 -0
- package/dist/shared/spaceFeed.js +194 -0
- package/dist/shared/stringifyUnknown.d.ts +1 -0
- package/dist/shared/stringifyUnknown.js +1 -0
- package/dist/shared/swarm.d.ts +320 -0
- package/dist/shared/swarm.js +328 -0
- package/dist/shared/swarmVisual.d.ts +79 -0
- package/dist/shared/swarmVisual.js +212 -0
- package/dist/shared/terminalFilter.d.ts +13 -0
- package/dist/shared/terminalFilter.js +46 -0
- package/dist/shared/toolIntegration.d.ts +56 -0
- package/dist/shared/toolIntegration.js +180 -0
- package/dist/shared/typing.d.ts +9 -0
- package/dist/shared/typing.js +37 -0
- package/dist/shared/uploads.d.ts +31 -0
- package/dist/shared/uploads.js +65 -0
- package/dist/shared/voiceApprovals.d.ts +36 -0
- package/dist/shared/voiceApprovals.js +229 -0
- package/dist/shared/workspace.d.ts +47 -0
- package/dist/shared/workspace.js +40 -0
- package/dist/worker.d.ts +1 -0
- package/dist/worker.js +266 -0
- package/package.json +51 -4
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integrations Hub — Steer-owned MCP credentials for live external actions.
|
|
3
|
+
* Memory lives in Supermemory; live actions go through these connections.
|
|
4
|
+
*/
|
|
5
|
+
/** Composio marketplace sidebar groups (same taxonomy as composio.com toolkits). */
|
|
6
|
+
export const COMPOSIO_MARKETPLACE_GROUP_NAMES = [
|
|
7
|
+
"Artificial Intelligence",
|
|
8
|
+
"Sales & CRM",
|
|
9
|
+
"Marketing",
|
|
10
|
+
"Communication",
|
|
11
|
+
"Commerce & Payments",
|
|
12
|
+
"Customer Support",
|
|
13
|
+
"Developer Tools",
|
|
14
|
+
"Data & Analytics",
|
|
15
|
+
"Databases & Storage",
|
|
16
|
+
"HR & Recruiting",
|
|
17
|
+
];
|
|
18
|
+
export function normalizeMarketplaceCategoryName(name) {
|
|
19
|
+
return name.trim().toLowerCase().replace(/\s+/g, " ");
|
|
20
|
+
}
|
|
21
|
+
export function marketplaceCategorySlug(name) {
|
|
22
|
+
return normalizeMarketplaceCategoryName(name).replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
23
|
+
}
|
|
24
|
+
/** Fallback ids when Composio category API is unavailable. */
|
|
25
|
+
export function composioMarketplaceGroupCategoriesFallback() {
|
|
26
|
+
return COMPOSIO_MARKETPLACE_GROUP_NAMES.map((name) => ({
|
|
27
|
+
id: marketplaceCategorySlug(name),
|
|
28
|
+
name,
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
/** Keep only the standard Composio sidebar groups, in display order. */
|
|
32
|
+
export function filterComposioMarketplaceSidebarCategories(categories) {
|
|
33
|
+
const order = new Map(COMPOSIO_MARKETPLACE_GROUP_NAMES.map((name, index) => [normalizeMarketplaceCategoryName(name), index]));
|
|
34
|
+
const byNormName = new Map();
|
|
35
|
+
for (const c of categories) {
|
|
36
|
+
const norm = normalizeMarketplaceCategoryName(c.name);
|
|
37
|
+
if (order.has(norm) && !byNormName.has(norm))
|
|
38
|
+
byNormName.set(norm, c);
|
|
39
|
+
}
|
|
40
|
+
return COMPOSIO_MARKETPLACE_GROUP_NAMES.map((name) => {
|
|
41
|
+
const norm = normalizeMarketplaceCategoryName(name);
|
|
42
|
+
return byNormName.get(norm) || { id: marketplaceCategorySlug(name), name };
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/** Map toolkit meta categories onto a canonical Composio sidebar group id. */
|
|
46
|
+
export function resolveToolkitMarketplaceCategory(metaCategories, sidebar) {
|
|
47
|
+
const byId = new Map(sidebar.map((c) => [c.id, c]));
|
|
48
|
+
const bySlug = new Map(sidebar.map((c) => [marketplaceCategorySlug(c.name), c]));
|
|
49
|
+
const byName = new Map(sidebar.map((c) => [normalizeMarketplaceCategoryName(c.name), c]));
|
|
50
|
+
const raw = Array.isArray(metaCategories) ? metaCategories : [];
|
|
51
|
+
for (const mc of raw) {
|
|
52
|
+
const id = mc.id?.trim();
|
|
53
|
+
if (id && byId.has(id)) {
|
|
54
|
+
const hit = byId.get(id);
|
|
55
|
+
return { categoryId: hit.id, categoryLabel: hit.name };
|
|
56
|
+
}
|
|
57
|
+
const slug = mc.slug?.trim();
|
|
58
|
+
if (slug && byId.has(slug)) {
|
|
59
|
+
const hit = byId.get(slug);
|
|
60
|
+
return { categoryId: hit.id, categoryLabel: hit.name };
|
|
61
|
+
}
|
|
62
|
+
if (slug && bySlug.has(slug)) {
|
|
63
|
+
const hit = bySlug.get(slug);
|
|
64
|
+
return { categoryId: hit.id, categoryLabel: hit.name };
|
|
65
|
+
}
|
|
66
|
+
const name = mc.name?.trim();
|
|
67
|
+
if (name) {
|
|
68
|
+
const hit = byName.get(normalizeMarketplaceCategoryName(name));
|
|
69
|
+
if (hit)
|
|
70
|
+
return { categoryId: hit.id, categoryLabel: hit.name };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { categoryId: "other", categoryLabel: "Other" };
|
|
74
|
+
}
|
|
75
|
+
export function integrationCatalogPublic() {
|
|
76
|
+
return INTEGRATION_CATALOG.map(({ id, name, tagline, category, tokenLabel, tokenHelpUrl, templates, accent }) => ({
|
|
77
|
+
id,
|
|
78
|
+
name,
|
|
79
|
+
tagline,
|
|
80
|
+
category,
|
|
81
|
+
tokenLabel,
|
|
82
|
+
tokenHelpUrl,
|
|
83
|
+
templates,
|
|
84
|
+
accent,
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
export const INTEGRATION_CATALOG = [
|
|
88
|
+
{
|
|
89
|
+
id: "linear",
|
|
90
|
+
name: "Linear",
|
|
91
|
+
tagline: "Read issues and projects; file and update issues from your account.",
|
|
92
|
+
category: "planning",
|
|
93
|
+
mcpUrl: "https://mcp.linear.app/mcp",
|
|
94
|
+
credentialKind: "api_key",
|
|
95
|
+
composioToolkit: "linear",
|
|
96
|
+
tokenLabel: "Linear API key",
|
|
97
|
+
tokenHelpUrl: "https://linear.app/settings/account/security",
|
|
98
|
+
templates: ["incident", "planning", "support"],
|
|
99
|
+
accent: "#5e6ad2",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: "sentry",
|
|
103
|
+
name: "Sentry",
|
|
104
|
+
tagline: "Pull issues, events, and stack traces into incident runs.",
|
|
105
|
+
category: "observability",
|
|
106
|
+
mcpUrl: "https://mcp.sentry.dev/mcp",
|
|
107
|
+
credentialKind: "hosted_oauth",
|
|
108
|
+
composioToolkit: "sentry",
|
|
109
|
+
tokenLabel: "Sentry account",
|
|
110
|
+
tokenHelpUrl: "https://sentry.io/settings/account/api/auth-tokens/",
|
|
111
|
+
templates: ["incident"],
|
|
112
|
+
accent: "#e1567c",
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: "notion",
|
|
116
|
+
name: "Notion",
|
|
117
|
+
tagline: "Search specs and docs; append pages when you allow writes.",
|
|
118
|
+
category: "docs",
|
|
119
|
+
mcpUrl: "https://mcp.notion.com/mcp",
|
|
120
|
+
credentialKind: "hosted_oauth",
|
|
121
|
+
composioToolkit: "notion",
|
|
122
|
+
tokenLabel: "Notion account",
|
|
123
|
+
tokenHelpUrl: "https://www.notion.so/my-integrations",
|
|
124
|
+
templates: ["planning"],
|
|
125
|
+
accent: "#e4e4e4",
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
id: "github",
|
|
129
|
+
name: "GitHub",
|
|
130
|
+
tagline: "Issues, discussions, releases, and Actions beyond the git checkout.",
|
|
131
|
+
category: "code",
|
|
132
|
+
mcpUrl: "https://api.githubcopilot.com/mcp/",
|
|
133
|
+
credentialKind: "api_key",
|
|
134
|
+
composioToolkit: "github",
|
|
135
|
+
tokenLabel: "GitHub personal access token",
|
|
136
|
+
tokenHelpUrl: "https://github.com/settings/tokens",
|
|
137
|
+
templates: ["incident", "planning"],
|
|
138
|
+
accent: "#8b949e",
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: "plain",
|
|
142
|
+
name: "Plain",
|
|
143
|
+
tagline: "Customer threads and support context for support runs.",
|
|
144
|
+
category: "support",
|
|
145
|
+
mcpUrl: "https://mcp.plain.com/mcp",
|
|
146
|
+
credentialKind: "api_key",
|
|
147
|
+
composioToolkit: "plain",
|
|
148
|
+
tokenLabel: "Plain API key",
|
|
149
|
+
tokenHelpUrl: "https://app.plain.com/settings/api-keys",
|
|
150
|
+
templates: ["support"],
|
|
151
|
+
accent: "#3ecf8e",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: "posthog",
|
|
155
|
+
name: "PostHog",
|
|
156
|
+
tagline: "Query product analytics, flags, and error tracking.",
|
|
157
|
+
category: "analytics",
|
|
158
|
+
mcpUrl: "https://mcp.posthog.com/mcp",
|
|
159
|
+
credentialKind: "api_key",
|
|
160
|
+
composioToolkit: "posthog",
|
|
161
|
+
tokenLabel: "PostHog personal API key",
|
|
162
|
+
tokenHelpUrl: "https://app.posthog.com/settings/user-api-keys",
|
|
163
|
+
templates: ["incident", "support"],
|
|
164
|
+
accent: "#f9bd2b",
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: "custom",
|
|
168
|
+
name: "Custom MCP",
|
|
169
|
+
tagline: "Any streamable-HTTP MCP server on the admin allowlist.",
|
|
170
|
+
category: "custom",
|
|
171
|
+
mcpUrl: "",
|
|
172
|
+
credentialKind: "api_key",
|
|
173
|
+
tokenLabel: "Auth header value",
|
|
174
|
+
templates: [],
|
|
175
|
+
accent: "#8ec5ff",
|
|
176
|
+
},
|
|
177
|
+
];
|
|
178
|
+
export const INTEGRATION_TEMPLATES = {
|
|
179
|
+
incident: {
|
|
180
|
+
title: "Incident response",
|
|
181
|
+
description: "Sentry read + workspace brain, optional Linear write for follow-ups.",
|
|
182
|
+
read: ["sentry", "github", "posthog"],
|
|
183
|
+
write: ["linear"],
|
|
184
|
+
},
|
|
185
|
+
support: {
|
|
186
|
+
title: "Support triage",
|
|
187
|
+
description: "Plain threads + PostHog context, file bugs in Linear from your account.",
|
|
188
|
+
read: ["plain", "posthog"],
|
|
189
|
+
write: ["linear"],
|
|
190
|
+
},
|
|
191
|
+
planning: {
|
|
192
|
+
title: "Planning & research",
|
|
193
|
+
description: "Notion specs + Linear roadmap, no repository required.",
|
|
194
|
+
read: ["notion", "linear"],
|
|
195
|
+
write: [],
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
export function catalogItem(id) {
|
|
199
|
+
return INTEGRATION_CATALOG.find((c) => c.id === id);
|
|
200
|
+
}
|
|
201
|
+
export function composioToolkitSlug(provider) {
|
|
202
|
+
if (provider === "custom")
|
|
203
|
+
return undefined;
|
|
204
|
+
return catalogItem(provider)?.composioToolkit || provider;
|
|
205
|
+
}
|
|
206
|
+
export function providerSupportsComposioOAuth(provider) {
|
|
207
|
+
return provider !== "custom" && Boolean(composioToolkitSlug(provider));
|
|
208
|
+
}
|
|
209
|
+
export function staticCatalogPublic() {
|
|
210
|
+
return integrationCatalogPublic();
|
|
211
|
+
}
|
|
212
|
+
export function paginateMarketplaceCatalog(items, opts) {
|
|
213
|
+
const pageSize = Math.min(Math.max(Math.round(opts.pageSize) || 25, 1), 100);
|
|
214
|
+
const category = opts.category?.trim();
|
|
215
|
+
const q = (opts.q || "").trim().toLowerCase();
|
|
216
|
+
const sort = opts.sort === "name" ? "name" : "popular";
|
|
217
|
+
let filtered = items;
|
|
218
|
+
if (category && category !== "all") {
|
|
219
|
+
filtered = filtered.filter((i) => i.category === category);
|
|
220
|
+
}
|
|
221
|
+
if (q) {
|
|
222
|
+
filtered = filtered.filter((i) => i.name.toLowerCase().includes(q) ||
|
|
223
|
+
i.id.toLowerCase().includes(q) ||
|
|
224
|
+
i.tagline.toLowerCase().includes(q) ||
|
|
225
|
+
String(i.category).toLowerCase().includes(q) ||
|
|
226
|
+
(i.categoryLabel || "").toLowerCase().includes(q));
|
|
227
|
+
}
|
|
228
|
+
if (sort === "name") {
|
|
229
|
+
filtered = [...filtered].sort((a, b) => a.name.localeCompare(b.name));
|
|
230
|
+
}
|
|
231
|
+
const total = filtered.length;
|
|
232
|
+
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
233
|
+
const page = Math.min(Math.max(Math.round(opts.page) || 0, 0), totalPages - 1);
|
|
234
|
+
const start = page * pageSize;
|
|
235
|
+
const counts = new Map();
|
|
236
|
+
for (const i of items) {
|
|
237
|
+
if (i.id === "custom")
|
|
238
|
+
continue;
|
|
239
|
+
const key = String(i.category);
|
|
240
|
+
counts.set(key, (counts.get(key) || 0) + 1);
|
|
241
|
+
}
|
|
242
|
+
let categories;
|
|
243
|
+
if (opts.categoryCatalog && opts.categoryCatalog.length) {
|
|
244
|
+
const sidebarSource = filterComposioMarketplaceSidebarCategories(opts.categoryCatalog);
|
|
245
|
+
categories = sidebarSource
|
|
246
|
+
.map((c) => ({
|
|
247
|
+
...c,
|
|
248
|
+
count: counts.get(c.id) || 0,
|
|
249
|
+
}))
|
|
250
|
+
.filter((c) => (c.count ?? 0) > 0);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
categories = [...new Set(items.map((i) => String(i.category)))].sort().map((id) => ({
|
|
254
|
+
id,
|
|
255
|
+
name: items.find((i) => i.category === id)?.categoryLabel || id,
|
|
256
|
+
count: counts.get(id) || 0,
|
|
257
|
+
})).filter((c) => (c.count ?? 0) > 0);
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
catalog: filtered.slice(start, start + pageSize),
|
|
261
|
+
pagination: { page, pageSize, total, totalPages },
|
|
262
|
+
categories,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
export function normalizeMcpUrl(raw) {
|
|
266
|
+
return raw.trim().replace(/\/+$/, "");
|
|
267
|
+
}
|
|
268
|
+
/** True when connecting to the vendor's default hosted MCP (OAuth-only providers). */
|
|
269
|
+
export function usesDefaultHostedMcp(provider, mcpUrl) {
|
|
270
|
+
const item = catalogItem(provider);
|
|
271
|
+
if (!item?.mcpUrl)
|
|
272
|
+
return false;
|
|
273
|
+
return normalizeMcpUrl(mcpUrl) === normalizeMcpUrl(item.mcpUrl);
|
|
274
|
+
}
|
|
275
|
+
export function hostedOAuthConnectBlockedMessage(provider) {
|
|
276
|
+
const item = catalogItem(provider);
|
|
277
|
+
const name = item?.name || provider;
|
|
278
|
+
if (provider === "notion") {
|
|
279
|
+
return (`${name}'s hosted MCP (${item?.mcpUrl}) requires a user OAuth session. Notion internal integration secrets and personal access tokens do not work on that endpoint. ` +
|
|
280
|
+
"Steer Integrations Hub only supports long-lived API keys today (Linear works this way). Notion support needs an OAuth connect flow — use Linear for now, or point Advanced → MCP URL at a self-hosted MCP bridge that accepts bearer tokens.");
|
|
281
|
+
}
|
|
282
|
+
if (provider === "sentry") {
|
|
283
|
+
return (`${name}'s hosted MCP (${item?.mcpUrl}) only accepts OAuth on the remote HTTP endpoint. Sentry User Auth Tokens work with the local \`@sentry/mcp-server\` stdio transport, not with a pasted Bearer token here. ` +
|
|
284
|
+
"Steer does not run OAuth for Sentry yet — use Linear, or self-host Sentry MCP and set a custom MCP URL in Advanced.");
|
|
285
|
+
}
|
|
286
|
+
return `${name}'s hosted MCP requires OAuth; API keys are not supported on ${item?.mcpUrl}.`;
|
|
287
|
+
}
|
|
288
|
+
/** Turn upstream MCP health-check errors into actionable copy for the Integrations UI. */
|
|
289
|
+
export function formatIntegrationHealthError(provider, mcpUrl, raw) {
|
|
290
|
+
const msg = raw.trim();
|
|
291
|
+
const onHostedDefault = usesDefaultHostedMcp(provider, mcpUrl);
|
|
292
|
+
if (onHostedDefault &&
|
|
293
|
+
(/invalid_token|invalid access token/i.test(msg) ||
|
|
294
|
+
/restricted_resource|endpoint unavailable|api token is invalid/i.test(msg))) {
|
|
295
|
+
if (provider === "notion") {
|
|
296
|
+
return `${hostedOAuthConnectBlockedMessage("notion")} If your workspace restricts AI apps, a Notion admin must approve this client under Settings → Connections → Permissions.`;
|
|
297
|
+
}
|
|
298
|
+
return hostedOAuthConnectBlockedMessage(provider);
|
|
299
|
+
}
|
|
300
|
+
return msg.length > 400 ? `${msg.slice(0, 397)}…` : msg;
|
|
301
|
+
}
|
|
302
|
+
export function isIntegrationProvider(v) {
|
|
303
|
+
return typeof v === "string" && INTEGRATION_CATALOG.some((c) => c.id === v);
|
|
304
|
+
}
|
|
305
|
+
export const DEFAULT_INTEGRATION_POLICY = {
|
|
306
|
+
externalWrites: "approval",
|
|
307
|
+
toolAllowlist: [],
|
|
308
|
+
blockedTools: [],
|
|
309
|
+
allowCustomMcp: false,
|
|
310
|
+
customMcpHosts: [],
|
|
311
|
+
allowLeasing: true,
|
|
312
|
+
leaseTtlMinutes: 60,
|
|
313
|
+
leaseSlackNotify: false,
|
|
314
|
+
instantEnabled: false,
|
|
315
|
+
};
|
|
316
|
+
/** Verbs that change something outside Steer (send, reply, delete, schedule…). */
|
|
317
|
+
const WRITE_VERBS = new Set([
|
|
318
|
+
"create", "update", "delete", "remove", "add", "set", "post", "comment", "assign", "archive", "close",
|
|
319
|
+
"reopen", "merge", "send", "edit", "move", "write", "upsert", "patch", "put", "insert", "resolve", "mute",
|
|
320
|
+
"publish", "invite", "transition", "trigger", "cancel", "rerun", "dispatch", "label", "link", "unlink",
|
|
321
|
+
"reply", "forward", "draft", "trash", "untrash", "modify", "mark", "star", "unstar", "schedule", "react",
|
|
322
|
+
"approve", "reject", "accept", "decline", "rename", "copy", "duplicate", "upload", "import", "share",
|
|
323
|
+
"unshare", "restore", "revoke", "grant", "transfer", "submit", "save", "start", "stop", "run", "execute",
|
|
324
|
+
"enable", "disable", "pin", "unpin", "follow", "unfollow", "like", "subscribe", "unsubscribe", "block",
|
|
325
|
+
"unblock", "clear", "purge", "empty", "reset", "book", "pay", "charge", "refund", "notify", "kick", "ban",
|
|
326
|
+
"unmute", "join", "leave", "upvote", "downvote", "retweet", "tweet",
|
|
327
|
+
]);
|
|
328
|
+
/** Verbs that only read. A tool counts as read-only only with one of these and no write verb. */
|
|
329
|
+
const READ_VERBS = new Set([
|
|
330
|
+
"get", "list", "search", "fetch", "find", "read", "query", "retrieve", "lookup", "describe", "count",
|
|
331
|
+
"view", "show", "browse", "preview", "inspect", "download", "export", "check", "status",
|
|
332
|
+
]);
|
|
333
|
+
/**
|
|
334
|
+
* Apps whose outbound messages are drafted instead of sent. A Drive upload
|
|
335
|
+
* or a PostHog query is not one of these, so it runs.
|
|
336
|
+
*/
|
|
337
|
+
const OUTBOUND_PROVIDERS = new Set([
|
|
338
|
+
"gmail", "outlook", "hotmail",
|
|
339
|
+
"linkedin",
|
|
340
|
+
"reddit",
|
|
341
|
+
"twitter", "tweet", "x",
|
|
342
|
+
"slack",
|
|
343
|
+
"discord",
|
|
344
|
+
"whatsapp",
|
|
345
|
+
"telegram",
|
|
346
|
+
"facebook",
|
|
347
|
+
"instagram",
|
|
348
|
+
"threads",
|
|
349
|
+
"bluesky", "bsky",
|
|
350
|
+
"mastodon",
|
|
351
|
+
"messenger",
|
|
352
|
+
]);
|
|
353
|
+
/** Verbs that deliver a message or post on those apps. */
|
|
354
|
+
const OUTBOUND_VERBS = new Set([
|
|
355
|
+
"send", "reply", "forward", "post", "comment", "tweet", "retweet",
|
|
356
|
+
"publish", "message", "dm", "share", "draft", "compose", "react",
|
|
357
|
+
]);
|
|
358
|
+
function toolTokens(name) {
|
|
359
|
+
return name
|
|
360
|
+
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
361
|
+
.toLowerCase()
|
|
362
|
+
.split(/[^a-z0-9]+/)
|
|
363
|
+
.filter(Boolean);
|
|
364
|
+
}
|
|
365
|
+
function tokenIn(verbs, token) {
|
|
366
|
+
return verbs.has(token) || verbs.has(token.replace(/es$/, "")) || verbs.has(token.replace(/s$/, ""));
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Mail and social sends (Gmail, LinkedIn, Reddit, Twitter, Slack, and the
|
|
370
|
+
* same kind of app). Fetches on those apps are not included. Everything else
|
|
371
|
+
* runs, including uploads and analytics queries.
|
|
372
|
+
*/
|
|
373
|
+
export function isOutboundAction(name) {
|
|
374
|
+
const tokens = toolTokens(name);
|
|
375
|
+
if (!tokens.some((token) => OUTBOUND_PROVIDERS.has(token)))
|
|
376
|
+
return false;
|
|
377
|
+
if (tokens.some((token) => tokenIn(OUTBOUND_VERBS, token)))
|
|
378
|
+
return true;
|
|
379
|
+
if (tokens.some((token) => tokenIn(READ_VERBS, token)))
|
|
380
|
+
return false;
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Classify external tools. A write verb in the name (send, reply, create…)
|
|
385
|
+
* always wins, even if the provider tagged the tool read-only. Otherwise a
|
|
386
|
+
* read-only annotation is trusted. Anything else, including unfamiliar verbs,
|
|
387
|
+
* is a write, so a read-only connection does not expose it. Drafting is
|
|
388
|
+
* narrower: only {@link isOutboundAction}.
|
|
389
|
+
*/
|
|
390
|
+
const OUTBOUND_ARG_KEYS = new Set([
|
|
391
|
+
"to",
|
|
392
|
+
"recipient_email",
|
|
393
|
+
"recipient",
|
|
394
|
+
"recipients",
|
|
395
|
+
"to_email",
|
|
396
|
+
"to_emails",
|
|
397
|
+
"cc",
|
|
398
|
+
"bcc",
|
|
399
|
+
"subject",
|
|
400
|
+
"body",
|
|
401
|
+
"message_body",
|
|
402
|
+
"html_body",
|
|
403
|
+
]);
|
|
404
|
+
/**
|
|
405
|
+
* A call that is trying to deliver a message, even when the tool name looks
|
|
406
|
+
* read-only. Ask-first automations draft these instead of executing them.
|
|
407
|
+
*/
|
|
408
|
+
export function isOutboundMessage(toolName, args) {
|
|
409
|
+
if (!args)
|
|
410
|
+
return false;
|
|
411
|
+
if (!/(gmail|outlook|e-?mail|mail)/i.test(toolName))
|
|
412
|
+
return false;
|
|
413
|
+
return Object.keys(args).some((key) => OUTBOUND_ARG_KEYS.has(key.toLowerCase()));
|
|
414
|
+
}
|
|
415
|
+
export function isWriteTool(name, annotations) {
|
|
416
|
+
const tokens = toolTokens(name);
|
|
417
|
+
// Composio often conjugates: SENDS_A_MESSAGE, RETRIEVES, LISTS.
|
|
418
|
+
if (tokens.some((token) => tokenIn(WRITE_VERBS, token)))
|
|
419
|
+
return true;
|
|
420
|
+
if (annotations?.readOnlyHint === true)
|
|
421
|
+
return false;
|
|
422
|
+
if (annotations?.destructiveHint === true)
|
|
423
|
+
return true;
|
|
424
|
+
return !tokens.some((token) => tokenIn(READ_VERBS, token));
|
|
425
|
+
}
|
|
426
|
+
/** `linear__create_issue` — provider-prefixed, MCP-safe, ≤ 64 chars. */
|
|
427
|
+
export function bundledToolName(provider, tool) {
|
|
428
|
+
const safe = `${provider}__${tool}`.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
429
|
+
return safe.length <= 64 ? safe : safe.slice(0, 64);
|
|
430
|
+
}
|
|
431
|
+
export function splitBundledToolName(name) {
|
|
432
|
+
const i = name.indexOf("__");
|
|
433
|
+
if (i <= 0)
|
|
434
|
+
return null;
|
|
435
|
+
return { provider: name.slice(0, i), tool: name.slice(i + 2) };
|
|
436
|
+
}
|
|
437
|
+
export const EXTERNAL_TOOL_PREFIX = "external:";
|
|
438
|
+
export function connectionHealthLabel(h) {
|
|
439
|
+
switch (h) {
|
|
440
|
+
case "healthy":
|
|
441
|
+
return "Healthy";
|
|
442
|
+
case "error":
|
|
443
|
+
return "Error";
|
|
444
|
+
case "expiring":
|
|
445
|
+
return "Expiring soon";
|
|
446
|
+
default:
|
|
447
|
+
return "Not tested";
|
|
448
|
+
}
|
|
449
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export type IssueTranscriptItemKind = "user" | "assistant" | "thinking" | "tool" | "error";
|
|
2
|
+
export type IssueTranscriptToolStatus = "running" | "done" | "error";
|
|
3
|
+
export interface IssueTranscriptItem {
|
|
4
|
+
id: string;
|
|
5
|
+
kind: IssueTranscriptItemKind;
|
|
6
|
+
text: string;
|
|
7
|
+
toolName?: string;
|
|
8
|
+
detail?: string;
|
|
9
|
+
path?: string;
|
|
10
|
+
status?: IssueTranscriptToolStatus;
|
|
11
|
+
runId?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface IssueTranscriptRun {
|
|
14
|
+
id: string;
|
|
15
|
+
status: "running" | "finished" | "error" | "cancelled";
|
|
16
|
+
createdAt?: number | null;
|
|
17
|
+
durationMs?: number | null;
|
|
18
|
+
result?: string | null;
|
|
19
|
+
error?: string | null;
|
|
20
|
+
}
|
|
21
|
+
export interface IssueTranscript {
|
|
22
|
+
cursorAgentId: string | null;
|
|
23
|
+
available: boolean;
|
|
24
|
+
live: boolean;
|
|
25
|
+
error?: string | null;
|
|
26
|
+
runs: IssueTranscriptRun[];
|
|
27
|
+
items: IssueTranscriptItem[];
|
|
28
|
+
}
|
|
29
|
+
export declare function emptyIssueTranscript(partial?: Partial<IssueTranscript>): IssueTranscript;
|
|
30
|
+
export declare function parseStoredTranscriptItems(raw: unknown): IssueTranscriptItem[];
|
|
31
|
+
export declare function applyIssueStreamEvent(items: IssueTranscriptItem[], event: {
|
|
32
|
+
kind: "user";
|
|
33
|
+
text: string;
|
|
34
|
+
runId?: string;
|
|
35
|
+
} | {
|
|
36
|
+
kind: "assistant";
|
|
37
|
+
text: string;
|
|
38
|
+
runId?: string;
|
|
39
|
+
} | {
|
|
40
|
+
kind: "thinking";
|
|
41
|
+
text: string;
|
|
42
|
+
runId?: string;
|
|
43
|
+
} | {
|
|
44
|
+
kind: "tool_start" | "tool_done";
|
|
45
|
+
callId: string;
|
|
46
|
+
name: string;
|
|
47
|
+
detail?: string;
|
|
48
|
+
path?: string;
|
|
49
|
+
runId?: string;
|
|
50
|
+
} | {
|
|
51
|
+
kind: "error";
|
|
52
|
+
text: string;
|
|
53
|
+
runId?: string;
|
|
54
|
+
}): IssueTranscriptItem[];
|
|
55
|
+
/**
|
|
56
|
+
* Build a chat timeline from listed/hydrated Cursor run metadata.
|
|
57
|
+
* `run.conversation()` is avoided here — on cloud that replays SSE.
|
|
58
|
+
*/
|
|
59
|
+
export declare function transcriptItemsFromListedRuns(runs: Array<Pick<IssueTranscriptRun, "id" | "status" | "result" | "error">>): IssueTranscriptItem[];
|
|
60
|
+
/**
|
|
61
|
+
* Flatten Cursor `run.conversation()` turns into a read-only chat timeline.
|
|
62
|
+
* Pure: does not call Cursor.
|
|
63
|
+
*/
|
|
64
|
+
export declare function conversationTurnsToItems(runId: string, turns: unknown): IssueTranscriptItem[];
|