@muxoai/sdk 1.3.0 → 1.4.3

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.
Files changed (76) hide show
  1. package/.agents/plugins/marketplace.json +2 -2
  2. package/.claude-plugin/marketplace.json +19 -4
  3. package/.codex/config.toml +9 -2
  4. package/ARCHITECTURE.md +16 -6
  5. package/README.md +69 -24
  6. package/dist/clerk.d.ts +35 -0
  7. package/dist/clerk.js +201 -0
  8. package/dist/cli.js +1677 -103
  9. package/dist/composio-catalog.d.ts +234 -0
  10. package/dist/composio-catalog.js +1894 -0
  11. package/dist/config.d.ts +16 -0
  12. package/dist/config.js +27 -1
  13. package/dist/durable-workflow.d.ts +112 -0
  14. package/dist/durable-workflow.js +284 -0
  15. package/dist/engine.d.ts +377 -6
  16. package/dist/engine.js +1919 -94
  17. package/dist/index.d.ts +3 -0
  18. package/dist/index.js +3 -0
  19. package/dist/mcp-schema.d.ts +286 -0
  20. package/dist/mcp-schema.js +2580 -0
  21. package/dist/mcp.d.ts +2 -25
  22. package/dist/mcp.js +1008 -507
  23. package/dist/memory-graph.d.ts +45 -0
  24. package/dist/memory-graph.js +293 -0
  25. package/dist/nl.js +214 -35
  26. package/dist/oauth.d.ts +32 -0
  27. package/dist/oauth.js +134 -0
  28. package/dist/oss-suite.d.ts +217 -0
  29. package/dist/oss-suite.js +836 -0
  30. package/dist/policy.d.ts +190 -0
  31. package/dist/policy.js +1597 -0
  32. package/dist/providers/composio-instant.d.ts +4 -0
  33. package/dist/providers/composio-instant.js +890 -535
  34. package/dist/providers/composio-sdk.d.ts +126 -5
  35. package/dist/providers/composio-sdk.js +902 -79
  36. package/dist/providers/microsoft-governance.d.ts +89 -3
  37. package/dist/providers/microsoft-governance.js +673 -26
  38. package/dist/providers/stripe-billing.d.ts +42 -0
  39. package/dist/providers/stripe-billing.js +244 -5
  40. package/dist/providers/stripe-projects.d.ts +459 -4
  41. package/dist/providers/stripe-projects.js +2674 -122
  42. package/dist/providers/supermemory.d.ts +102 -6
  43. package/dist/providers/supermemory.js +609 -55
  44. package/dist/provisioning-managed.d.ts +50 -0
  45. package/dist/provisioning-managed.js +155 -0
  46. package/dist/sdk.d.ts +728 -7
  47. package/dist/sdk.js +539 -10
  48. package/dist/server.js +2744 -321
  49. package/dist/store.d.ts +138 -6
  50. package/dist/store.js +932 -58
  51. package/dist/types.d.ts +330 -4
  52. package/dist/ui/console-html.d.ts +62 -0
  53. package/dist/ui/console-html.js +3742 -2228
  54. package/dist/ui/design-tokens.d.ts +177 -0
  55. package/dist/ui/design-tokens.js +210 -0
  56. package/dist/version.d.ts +1 -0
  57. package/dist/version.js +1 -0
  58. package/package.json +6 -5
  59. package/plugins/muxo/.app.json +1 -1
  60. package/plugins/muxo/.claude-plugin/plugin.json +3 -3
  61. package/plugins/muxo/.codex-plugin/plugin.json +19 -10
  62. package/plugins/muxo/.cursor-plugin/plugin.json +30 -0
  63. package/plugins/muxo/.mcp.json +1 -33
  64. package/plugins/muxo/assets/logo.png +0 -0
  65. package/plugins/muxo/hooks/session-start.sh +16 -4
  66. package/plugins/muxo/hooks/user-prompt-submit.sh +14 -1
  67. package/plugins/muxo/mcp.json +0 -10
  68. package/plugins/muxo/plugin.json +65 -8
  69. package/plugins/muxo/skills/muxo/SKILL.md +142 -14
  70. package/plugins/muxo/skills/muxo/agents/openai.yaml +12 -0
  71. package/plugins/muxo/skills/muxo/references/cli.md +9 -3
  72. package/plugins/muxo/skills/muxo/references/mcp.md +22 -10
  73. package/plugins/muxo/skills/muxo-activity-summary/SKILL.md +81 -0
  74. package/plugins/muxo/skills/setup/SKILL.md +17 -3
  75. package/plugins/muxo/skills/setup/agents/openai.yaml +12 -0
  76. package/src/catalogues/stripe-projects-catalog.json +140 -0
@@ -0,0 +1,45 @@
1
+ import type { ConnectionRecord, GovernancePolicy, MemoryGraphEdge, MemoryGraphNode, MemoryKnowledgeGraph, ProvisionedResource, TemporalGraphFact } from "./types.js";
2
+ export interface MemoryGraphInput {
3
+ workspace: {
4
+ id: string;
5
+ slug: string;
6
+ name: string;
7
+ tier: string;
8
+ policy?: GovernancePolicy;
9
+ };
10
+ namespace: string;
11
+ query?: string;
12
+ asOf?: string | null;
13
+ focalEntity?: string | null;
14
+ maxHops?: number;
15
+ facts: TemporalGraphFact[];
16
+ resources: Array<Pick<ProvisionedResource, "resourceName" | "status" | "providerName" | "serviceSlug">>;
17
+ activeConnections: Array<Pick<ConnectionRecord, "id" | "providerSlug" | "providerName" | "createdAt">>;
18
+ memoriesCount: number;
19
+ }
20
+ /**
21
+ * Graphiti-style Point-in-Time ("As-Of") Bi-Temporal Fact Filter.
22
+ * Reconstructs which facts were active at `asOf` vs. already retired by `asOf`,
23
+ * excluding facts created after `asOf`.
24
+ */
25
+ export declare function filterFactsAsOf(facts: TemporalGraphFact[], asOf?: string | null): {
26
+ scopedFacts: TemporalGraphFact[];
27
+ isActiveAtPointInTime: (fact: TemporalGraphFact) => boolean;
28
+ };
29
+ /**
30
+ * Graphiti-style Multi-Hop Subgraph Community Traversal (BFS).
31
+ * Finds all nodes and edges within `maxHops` (default 2) of a focal entity.
32
+ */
33
+ export declare function traverseSubgraphBfs(nodes: MemoryGraphNode[], edges: MemoryGraphEdge[], focalQuery: string, maxHops?: number): {
34
+ focalEntity: string;
35
+ maxHops: number;
36
+ nodes: MemoryGraphNode[];
37
+ edges: MemoryGraphEdge[];
38
+ hopDistances: Record<string, number>;
39
+ };
40
+ /**
41
+ * Builds the Graphiti-inspired Bi-Temporal Knowledge Graph (nodes, active/historical edges,
42
+ * episodic provenance, point-in-time `asOf` time-travel, 2-hop BFS subgraph, and Mermaid preview)
43
+ * from runtime-agnostic inputs so the Node engine and the Edge Worker render identical graphs.
44
+ */
45
+ export declare function buildMemoryKnowledgeGraph(input: MemoryGraphInput): MemoryKnowledgeGraph;
@@ -0,0 +1,293 @@
1
+ import { formatHumanFriendlyExplanation } from "./policy.js";
2
+ /**
3
+ * Graphiti-style Point-in-Time ("As-Of") Bi-Temporal Fact Filter.
4
+ * Reconstructs which facts were active at `asOf` vs. already retired by `asOf`,
5
+ * excluding facts created after `asOf`.
6
+ */
7
+ export function filterFactsAsOf(facts, asOf) {
8
+ if (!asOf || !asOf.trim()) {
9
+ return {
10
+ scopedFacts: facts,
11
+ isActiveAtPointInTime: (fact) => fact.validTo === null,
12
+ };
13
+ }
14
+ const asOfMs = Date.parse(asOf);
15
+ if (!Number.isFinite(asOfMs)) {
16
+ return {
17
+ scopedFacts: facts,
18
+ isActiveAtPointInTime: (fact) => fact.validTo === null,
19
+ };
20
+ }
21
+ const scopedFacts = facts.filter((fact) => {
22
+ const validFromMs = Date.parse(fact.validFrom || fact.createdAt);
23
+ return !Number.isFinite(validFromMs) || validFromMs <= asOfMs;
24
+ });
25
+ return {
26
+ scopedFacts,
27
+ isActiveAtPointInTime: (fact) => {
28
+ if (!fact.validTo)
29
+ return true;
30
+ const validToMs = Date.parse(fact.validTo);
31
+ return Number.isFinite(validToMs) && validToMs > asOfMs;
32
+ },
33
+ };
34
+ }
35
+ /**
36
+ * Graphiti-style Multi-Hop Subgraph Community Traversal (BFS).
37
+ * Finds all nodes and edges within `maxHops` (default 2) of a focal entity.
38
+ */
39
+ export function traverseSubgraphBfs(nodes, edges, focalQuery, maxHops = 2) {
40
+ const needle = focalQuery.trim().toLowerCase();
41
+ const clampedHops = Math.min(4, Math.max(1, Number(maxHops) || 2));
42
+ const seedNode = nodes.find((n) => n.id.toLowerCase() === needle) ||
43
+ nodes.find((n) => n.label.toLowerCase() === needle) ||
44
+ nodes.find((n) => n.id.toLowerCase().includes(needle) ||
45
+ n.label.toLowerCase().includes(needle)) ||
46
+ nodes[0];
47
+ if (!seedNode) {
48
+ return {
49
+ focalEntity: focalQuery,
50
+ maxHops: clampedHops,
51
+ nodes: [],
52
+ edges: [],
53
+ hopDistances: {},
54
+ };
55
+ }
56
+ const hopDistances = { [seedNode.id]: 0 };
57
+ const queue = [
58
+ { nodeId: seedNode.id, depth: 0 },
59
+ ];
60
+ while (queue.length > 0) {
61
+ const current = queue.shift();
62
+ if (current.depth >= clampedHops)
63
+ continue;
64
+ for (const edge of edges) {
65
+ let neighborId = null;
66
+ if (edge.source === current.nodeId)
67
+ neighborId = edge.target;
68
+ else if (edge.target === current.nodeId)
69
+ neighborId = edge.source;
70
+ if (neighborId && hopDistances[neighborId] === undefined) {
71
+ hopDistances[neighborId] = current.depth + 1;
72
+ queue.push({ nodeId: neighborId, depth: current.depth + 1 });
73
+ }
74
+ }
75
+ }
76
+ const subNodes = nodes
77
+ .filter((n) => hopDistances[n.id] !== undefined)
78
+ .map((n) => ({ ...n, hopDistance: hopDistances[n.id] }));
79
+ const subEdges = edges.filter((e) => hopDistances[e.source] !== undefined &&
80
+ hopDistances[e.target] !== undefined);
81
+ return {
82
+ focalEntity: seedNode.id,
83
+ maxHops: clampedHops,
84
+ nodes: subNodes,
85
+ edges: subEdges,
86
+ hopDistances,
87
+ };
88
+ }
89
+ /**
90
+ * Builds the Graphiti-inspired Bi-Temporal Knowledge Graph (nodes, active/historical edges,
91
+ * episodic provenance, point-in-time `asOf` time-travel, 2-hop BFS subgraph, and Mermaid preview)
92
+ * from runtime-agnostic inputs so the Node engine and the Edge Worker render identical graphs.
93
+ */
94
+ export function buildMemoryKnowledgeGraph(input) {
95
+ const ws = input.workspace;
96
+ const query = input.query;
97
+ const asOf = input.asOf ?? null;
98
+ const maxHops = Math.min(4, Math.max(1, Number(input.maxHops || 2)));
99
+ const { scopedFacts, isActiveAtPointInTime } = filterFactsAsOf(input.facts, asOf);
100
+ const nodeMap = new Map();
101
+ const rootId = `workspace:${ws.slug}`;
102
+ nodeMap.set(rootId, {
103
+ id: rootId,
104
+ kind: "workspace",
105
+ label: ws.name,
106
+ summary: `Workspace ${ws.name} (${ws.slug}, tier=${ws.tier})`,
107
+ status: "active",
108
+ metadata: { workspaceId: ws.id, tier: ws.tier },
109
+ });
110
+ const ensureNode = (id, status, fallbackKind = "entity", summary) => {
111
+ const existing = nodeMap.get(id);
112
+ if (existing) {
113
+ if (status === "active" && existing.status === "historical") {
114
+ existing.status = "active";
115
+ }
116
+ return existing;
117
+ }
118
+ const kind = id.startsWith("workspace:")
119
+ ? "workspace"
120
+ : id.startsWith("resource:")
121
+ ? "resource"
122
+ : id.startsWith("connection:")
123
+ ? "connection"
124
+ : id.startsWith("tool:")
125
+ ? "tool"
126
+ : id.startsWith("guardrail:")
127
+ ? "guardrail"
128
+ : id.startsWith("episode:")
129
+ ? "episode"
130
+ : fallbackKind;
131
+ const label = id.includes(":")
132
+ ? id.split(":").slice(1).join(":")
133
+ : id.length > 36
134
+ ? `${id.slice(0, 33)}...`
135
+ : id;
136
+ const created = {
137
+ id,
138
+ kind,
139
+ label,
140
+ summary: summary || label,
141
+ status,
142
+ };
143
+ nodeMap.set(id, created);
144
+ return created;
145
+ };
146
+ let episodesCount = 0;
147
+ const edges = scopedFacts.map((fact) => {
148
+ const status = isActiveAtPointInTime(fact)
149
+ ? "active"
150
+ : "historical";
151
+ const objKind = fact.sourceKind === "preference"
152
+ ? "preference"
153
+ : fact.sourceKind === "policy_decision"
154
+ ? "guardrail"
155
+ : fact.sourceKind === "resource_topology"
156
+ ? "resource"
157
+ : "entity";
158
+ ensureNode(fact.subject, status, "entity", fact.subject);
159
+ ensureNode(fact.object, status, objKind, fact.summary);
160
+ const episodeId = fact.episodeId || fact.sourceReferenceId || null;
161
+ if (episodeId) {
162
+ const epNodeId = episodeId.startsWith("episode:")
163
+ ? episodeId
164
+ : `episode:${episodeId}`;
165
+ if (!nodeMap.has(epNodeId))
166
+ episodesCount += 1;
167
+ ensureNode(epNodeId, status, "episode", `Episodic provenance (${episodeId})`);
168
+ }
169
+ return {
170
+ id: fact.id,
171
+ source: fact.subject,
172
+ target: fact.object,
173
+ subject: fact.subject,
174
+ object: fact.object,
175
+ predicate: fact.predicate,
176
+ summary: fact.summary,
177
+ confidence: fact.confidence,
178
+ status,
179
+ validFrom: fact.validFrom,
180
+ validTo: status === "active" && asOf ? null : fact.validTo,
181
+ transactionFrom: fact.transactionFrom || fact.createdAt,
182
+ transactionTo: fact.transactionTo ?? fact.validTo,
183
+ episodeId,
184
+ supersededById: fact.supersededById ?? null,
185
+ sourceKind: fact.sourceKind,
186
+ sourceReferenceId: fact.sourceReferenceId ?? null,
187
+ };
188
+ });
189
+ for (const res of input.resources) {
190
+ ensureNode(`resource:${res.resourceName}`, res.status === "active" ? "active" : "historical", "resource", `${res.resourceName} (${res.providerName} / ${res.serviceSlug})`);
191
+ }
192
+ for (const conn of input.activeConnections) {
193
+ const connId = `connection:${conn.providerSlug}`;
194
+ ensureNode(connId, "active", "connection", `Connected OAuth App: ${conn.providerName} (${conn.providerSlug})`);
195
+ if (!edges.some((e) => e.source === rootId && e.target === connId)) {
196
+ edges.push({
197
+ id: `edge_conn_${conn.id}`,
198
+ source: rootId,
199
+ target: connId,
200
+ predicate: "CONNECTED_TO",
201
+ summary: `${ws.name} has active OAuth connection to ${conn.providerName}`,
202
+ confidence: 1.0,
203
+ status: "active",
204
+ validFrom: conn.createdAt,
205
+ validTo: null,
206
+ transactionFrom: conn.createdAt,
207
+ transactionTo: null,
208
+ episodeId: conn.id,
209
+ supersededById: null,
210
+ sourceKind: "system",
211
+ sourceReferenceId: conn.id,
212
+ });
213
+ }
214
+ }
215
+ const activeEdges = edges.filter((e) => e.status === "active");
216
+ const historicalEdges = edges.filter((e) => e.status === "historical");
217
+ const nodes = Array.from(nodeMap.values());
218
+ const focalTarget = input.focalEntity || query || null;
219
+ const subgraph = focalTarget
220
+ ? traverseSubgraphBfs(nodes, edges, focalTarget, maxHops)
221
+ : null;
222
+ const safeMermaidId = (raw, idx) => `N${idx}_${raw.replace(/[^a-zA-Z0-9]/g, "_").slice(0, 14)}`;
223
+ const nodeIndex = new Map();
224
+ nodes.slice(0, 24).forEach((n, idx) => {
225
+ nodeIndex.set(n.id, safeMermaidId(n.label, idx));
226
+ });
227
+ const mermaidLines = ["flowchart LR"];
228
+ for (const n of nodes.slice(0, 24)) {
229
+ const mId = nodeIndex.get(n.id);
230
+ const cleanLabel = n.label.replace(/"/g, "'").slice(0, 22);
231
+ mermaidLines.push(` ${mId}["${cleanLabel}"]`);
232
+ }
233
+ for (const e of edges.slice(0, 24)) {
234
+ const srcId = nodeIndex.get(e.source);
235
+ const tgtId = nodeIndex.get(e.target);
236
+ if (!srcId || !tgtId)
237
+ continue;
238
+ const pred = e.predicate.replace(/"/g, "'").slice(0, 18);
239
+ if (e.status === "active") {
240
+ mermaidLines.push(` ${srcId} -->|${pred}| ${tgtId}`);
241
+ }
242
+ else {
243
+ mermaidLines.push(` ${srcId} -.->|RETIRED: ${pred}| ${tgtId}`);
244
+ }
245
+ }
246
+ const headline = `Bi-Temporal Knowledge Graph (${ws.name}${asOf ? ` as of ${asOf}` : ""}): ${activeEdges.length} active relationship${activeEdges.length === 1 ? "" : "s"}, ${historicalEdges.length} superseded historical relationship${historicalEdges.length === 1 ? "" : "s"} across ${nodes.length} node${nodes.length === 1 ? "" : "s"}.`;
247
+ const activePreview = activeEdges
248
+ .slice(0, 4)
249
+ .map((e) => `${e.source} --[${e.predicate}]--> ${e.target}`)
250
+ .join("; ");
251
+ const nonTechnical = [
252
+ headline,
253
+ activeEdges.length > 0
254
+ ? `Current facts: ${activeEdges.slice(0, 3).map((e) => e.summary).join(" · ")}.`
255
+ : "No active facts recorded yet.",
256
+ historicalEdges.length > 0
257
+ ? `Time-travel lineage: ${historicalEdges.length} older fact${historicalEdges.length === 1 ? " was" : "s were"} automatically retired when newer workspace settings or facts replaced them.`
258
+ : "No superseded historical facts yet.",
259
+ ].join(" ");
260
+ const technical = `workspace=${ws.id} | namespace=${input.namespace} | asOf=${asOf || "latest"} | nodes=${nodes.length} | activeEdges=${activeEdges.length} | historicalEdges=${historicalEdges.length} | episodes=${episodesCount} | memories=${input.memoriesCount} | activePreview=[${activePreview || "none"}]`;
261
+ const explanation = formatHumanFriendlyExplanation({
262
+ headline,
263
+ nonTechnical,
264
+ technical,
265
+ policy: ws.policy,
266
+ });
267
+ return {
268
+ workspaceId: ws.id,
269
+ workspaceSlug: ws.slug,
270
+ namespace: input.namespace,
271
+ generatedAt: new Date().toISOString(),
272
+ asOf,
273
+ focalEntity: subgraph?.focalEntity ?? null,
274
+ maxHops,
275
+ query: query ?? null,
276
+ nodes,
277
+ edges,
278
+ activeEdges,
279
+ historicalEdges,
280
+ subgraph,
281
+ stats: {
282
+ nodesCount: nodes.length,
283
+ activeEdgesCount: activeEdges.length,
284
+ historicalEdgesCount: historicalEdges.length,
285
+ memoriesCount: input.memoriesCount,
286
+ resourcesCount: input.resources.length,
287
+ connectionsCount: input.activeConnections.length,
288
+ episodesCount,
289
+ },
290
+ mermaid: mermaidLines.join("\n"),
291
+ explanation,
292
+ };
293
+ }
package/dist/nl.js CHANGED
@@ -80,23 +80,39 @@ export function extractParametersFromNaturalLanguage(prompt, tool, explicitInput
80
80
  input.numResults = extractNumberAfterKeyword(text, ["results", "limit", "top"], 5);
81
81
  }
82
82
  }
83
- else if (slug === "instant.code.execute") {
84
- if (!input.language) {
83
+ else if (slug === "instant.code.execute" || slug === "instant.composio.workbench") {
84
+ if (!input.language && slug === "instant.code.execute") {
85
85
  input.language = /\b(javascript|js|node|typescript|ts)\b/i.test(text)
86
86
  ? "javascript"
87
87
  : "python";
88
88
  }
89
- if (!input.code) {
90
- const codeBlock = text.match(/```(?:\w+)?\n([\s\S]*?)```/);
91
- if (codeBlock) {
92
- input.code = codeBlock[1].trim();
89
+ const codeBlock = text.match(/```(?:\w+)?\n([\s\S]*?)```/);
90
+ const inlineCode = text.match(/`([^`]+)`/);
91
+ const extractedCode = codeBlock
92
+ ? codeBlock[1].trim()
93
+ : inlineCode
94
+ ? inlineCode[1].trim()
95
+ : text;
96
+ if (slug === "instant.composio.workbench") {
97
+ if (!input.code_to_execute) {
98
+ input.code_to_execute = String(input.code || extractedCode);
93
99
  }
94
- else {
95
- const inlineCode = text.match(/`([^`]+)`/);
96
- if (inlineCode)
97
- input.code = inlineCode[1].trim();
100
+ if (!input.thought) {
101
+ input.thought = `Natural language workbench execution: ${text.slice(0, 80)}`;
98
102
  }
99
103
  }
104
+ else if (!input.code) {
105
+ input.code = extractedCode;
106
+ }
107
+ }
108
+ else if (slug === "instant.github.repo_intel") {
109
+ const repoMatch = text.match(/\b([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)\b/);
110
+ if (repoMatch && !repoMatch[0].includes(".ai") && !repoMatch[0].includes(".com")) {
111
+ if (!input.owner)
112
+ input.owner = repoMatch[1];
113
+ if (!input.repo)
114
+ input.repo = repoMatch[2];
115
+ }
100
116
  }
101
117
  else if (slug.startsWith("resource.")) {
102
118
  if (!input.resource_name && !input.name) {
@@ -207,6 +223,93 @@ export function extractParametersFromNaturalLanguage(prompt, tool, explicitInput
207
223
  input.limit = extractNumberAfterKeyword(text, ["top", "stories", "items", "limit", "posts"], 5);
208
224
  }
209
225
  }
226
+ else if (slug === "app.jira.create_issue") {
227
+ if (!input.project_key) {
228
+ const projMatch = text.match(/\bproject\s+([A-Z][A-Z0-9]{1,9})\b|\b([A-Z]{2,8})-\d+\b/);
229
+ input.project_key = projMatch ? projMatch[1] || projMatch[2] : "ENG";
230
+ }
231
+ if (!input.summary) {
232
+ const sumMatch = text.match(/\b(?:summary|titled|title)\s*[:=]?\s*["']?([^"'\n]+)["']?/i);
233
+ input.summary = sumMatch ? sumMatch[1].trim() : text.slice(0, 80);
234
+ }
235
+ if (!input.issue_type)
236
+ input.issue_type = "Task";
237
+ }
238
+ else if (slug === "app.linear.create_issue") {
239
+ if (!input.team_id) {
240
+ const teamMatch = text.match(/\bteam\s+["']?([a-zA-Z0-9_-]+)["']?/i);
241
+ input.team_id = teamMatch ? teamMatch[1] : "ENG";
242
+ }
243
+ if (!input.title) {
244
+ const titleMatch = text.match(/\b(?:titled|title)\s*[:=]?\s*["']?([^"'\n]+)["']?/i);
245
+ input.title = titleMatch ? titleMatch[1].trim() : text.slice(0, 80);
246
+ }
247
+ }
248
+ else if (slug === "app.googlecalendar.list_events") {
249
+ if (!input.calendarId)
250
+ input.calendarId = "primary";
251
+ if (input.maxResults === undefined) {
252
+ input.maxResults = extractNumberAfterKeyword(text, ["events", "meetings", "limit", "next"], 10);
253
+ }
254
+ }
255
+ else if (slug === "app.hubspot.search_contacts") {
256
+ if (!input.query) {
257
+ const cleaned = text.replace(/^(?:search\s+hubspot\s+(?:contacts\s+)?(?:for)?|find\s+contact)\s*/i, "").trim();
258
+ input.query = cleaned || text;
259
+ }
260
+ if (input.limit === undefined)
261
+ input.limit = 10;
262
+ }
263
+ else if (slug === "app.discord.send_message") {
264
+ if (!input.channel_id) {
265
+ const chMatch = text.match(/#([a-zA-Z0-9_-]+)|\bchannel\s+([a-zA-Z0-9_-]+)/i);
266
+ input.channel_id = chMatch ? chMatch[1] || chMatch[2] : "general";
267
+ }
268
+ if (!input.content) {
269
+ const msgMatch = text.match(/\b(?:saying|message|text|content)\s*[:=]?\s*["']?([\s\S]+?)["']?$/i);
270
+ input.content = msgMatch ? msgMatch[1].trim() : text;
271
+ }
272
+ }
273
+ else if (slug === "app.googledrive.search_files") {
274
+ if (!input.query) {
275
+ const cleaned = text.replace(/^(?:search\s+(?:google\s+)?drive\s+(?:files\s+)?(?:for)?)\s*/i, "").trim();
276
+ input.query = cleaned || text;
277
+ }
278
+ }
279
+ else if (slug === "app.airtable.list_records") {
280
+ if (!input.base_id) {
281
+ const baseMatch = text.match(/\b(app[a-zA-Z0-9]{10,})\b/);
282
+ input.base_id = baseMatch ? baseMatch[1] : "appDefaultBase";
283
+ }
284
+ if (!input.table_name) {
285
+ const tblMatch = text.match(/\btable\s+["']?([a-zA-Z0-9_-]+)["']?/i);
286
+ input.table_name = tblMatch ? tblMatch[1] : "Tasks";
287
+ }
288
+ }
289
+ else if (slug === "app.salesforce.query_records" || slug === "app.salesforce.soql_query") {
290
+ if (!input.query) {
291
+ const soqlMatch = text.match(/\b(SELECT\s+[\s\S]+)$/i);
292
+ input.query = soqlMatch ? soqlMatch[1].trim() : "SELECT Id, Name, Email FROM Contact LIMIT 10";
293
+ }
294
+ }
295
+ else if (slug === "app.pagerduty.create_incident") {
296
+ if (!input.title)
297
+ input.title = text.slice(0, 80);
298
+ if (!input.service_id)
299
+ input.service_id = "PDEFAULT";
300
+ }
301
+ else if (slug === "billing.stripe.refund") {
302
+ if (!input.paymentIntentId) {
303
+ const piMatch = text.match(/\b(pi_[a-zA-Z0-9_]+|ch_[a-zA-Z0-9_]+)\b/);
304
+ if (piMatch)
305
+ input.paymentIntentId = piMatch[1];
306
+ }
307
+ if (input.amountCents === undefined) {
308
+ const dollarMatch = text.match(/\$(\d+(?:\.\d{1,2})?)/);
309
+ if (dollarMatch)
310
+ input.amountCents = Math.round(parseFloat(dollarMatch[1]) * 100);
311
+ }
312
+ }
210
313
  const schemaReq = Array.isArray(tool.inputSchema?.required)
211
314
  ? tool.inputSchema.required
212
315
  : [];
@@ -235,13 +338,19 @@ function scoreToolForPrompt(prompt, tool) {
235
338
  if (slug === "instant.web.scrape")
236
339
  score += 110;
237
340
  }
238
- if (/\b(search\s+the\s+web|web\s+search|search\s+for|look\s+up|find\s+news|exa|google)\b/i.test(q)) {
341
+ const isExplicitWebSearch = /\b(search\s+(?:the\s+)?web|web\s+search|search\s+online|search\s+(?:for|about)|look\s+up|find\s+(?:news|info|information|articles)|exa|google)\b/i.test(q);
342
+ const hasProvisionVerb = /\b(provision|create|deploy|spin\s+up|setup|set\s+up|add\s+resource|new\s+db|new\s+database|database|db)\b/i.test(q);
343
+ if (isExplicitWebSearch) {
239
344
  if (slug === "instant.web.search")
240
- score += 105;
345
+ score += 155;
241
346
  }
242
- if (/\b(run\s+python|execute\s+code|run\s+script|sandbox|calculate|e2b)\b/i.test(q)) {
243
- if (slug === "instant.code.execute")
244
- score += 105;
347
+ if (/\b(run\s+python|execute\s+code|run\s+script|sandbox|workbench|calculate|e2b)\b/i.test(q)) {
348
+ if (slug === "instant.code.execute" || slug === "instant.composio.workbench")
349
+ score += 125;
350
+ }
351
+ if (/\b(repo\s+intel|github\s+repo|inspect\s+repo|repository\s+intel|stars\s+and\s+forks)\b/i.test(q)) {
352
+ if (slug === "instant.github.repo_intel")
353
+ score += 135;
245
354
  }
246
355
  if (/\b(top\s*up|add\s+credits|buy\s+credits|refill\s+credits|more\s+credits|\d+\s+credits)\b/i.test(q)) {
247
356
  if (slug === "billing.credits.topup")
@@ -255,27 +364,53 @@ function scoreToolForPrompt(prompt, tool) {
255
364
  if (slug === "billing.checkout.create")
256
365
  score += 125;
257
366
  }
258
- if (/\b(turso|libsql|sqlite\s+database|sqlite\s+db)\b/i.test(q)) {
259
- if (slug.startsWith("resource.turso."))
260
- score += 120;
261
- if (slug.includes("database"))
262
- score += 15;
263
- }
264
- if (/\b(neon|postgres|postgresql|pg\s+database)\b/i.test(q)) {
265
- if (slug.startsWith("resource.neon."))
266
- score += 120;
267
- }
268
- if (/\b(upstash|redis|cache\s+store|kv\s+store)\b/i.test(q)) {
269
- if (slug.startsWith("resource.upstash."))
270
- score += 120;
271
- }
272
- if (/\b(supabase)\b/i.test(q)) {
273
- if (slug.startsWith("resource.supabase."))
274
- score += 120;
367
+ if (/\b(refund|chargeback|pi_[a-z0-9_]+)\b/i.test(q)) {
368
+ if (slug === "billing.stripe.refund" || slug === "app.shopify.create_refund")
369
+ score += 130;
275
370
  }
276
- if (/\b(mongodb|mongo)\b/i.test(q)) {
277
- if (slug.startsWith("resource.mongodb."))
278
- score += 120;
371
+ if (!isExplicitWebSearch || hasProvisionVerb) {
372
+ if (/\b(turso|libsql|sqlite\s+database|sqlite\s+db)\b/i.test(q)) {
373
+ if (slug.startsWith("resource.turso."))
374
+ score += 120;
375
+ if (slug.includes("database"))
376
+ score += 15;
377
+ }
378
+ if (/\b(neon|postgres|postgresql|pg\s+database)\b/i.test(q)) {
379
+ if (slug.startsWith("resource.neon."))
380
+ score += 120;
381
+ }
382
+ if (/\b(upstash|redis|cache\s+store|kv\s+store)\b/i.test(q)) {
383
+ if (slug.startsWith("resource.upstash."))
384
+ score += 120;
385
+ }
386
+ if (/\b(supabase)\b/i.test(q)) {
387
+ if (slug.startsWith("resource.supabase."))
388
+ score += 120;
389
+ }
390
+ if (/\b(mongodb|mongo)\b/i.test(q)) {
391
+ if (slug.startsWith("resource.mongodb."))
392
+ score += 120;
393
+ }
394
+ if (/\b(cloudflare\s+worker|d1\s+database|r2\s+storage)\b/i.test(q)) {
395
+ if (slug.startsWith("resource.cloudflare."))
396
+ score += 120;
397
+ }
398
+ if (/\b(vercel\s+project|deploy\s+vercel)\b/i.test(q)) {
399
+ if (slug.startsWith("resource.vercel."))
400
+ score += 120;
401
+ }
402
+ if (/\b(resend\s+email|transactional\s+email\s+api)\b/i.test(q)) {
403
+ if (slug.startsWith("resource.resend."))
404
+ score += 120;
405
+ }
406
+ if (/\b(clerk\s+auth)\b/i.test(q)) {
407
+ if (slug.startsWith("resource.clerk."))
408
+ score += 120;
409
+ }
410
+ if (/\b(workos|enterprise\s+sso|scim)\b/i.test(q)) {
411
+ if (slug.startsWith("resource.workos."))
412
+ score += 120;
413
+ }
279
414
  }
280
415
  if (/\b(hacker\s*news|hn\s+stories|top\s+stories)\b/i.test(q)) {
281
416
  if (slug === "instant.hackernews.top_stories")
@@ -305,6 +440,10 @@ function scoreToolForPrompt(prompt, tool) {
305
440
  if (slug === "app.github.list_pull_requests" || slug === "app.github.list_issues")
306
441
  score += 110;
307
442
  }
443
+ if (/\b(list\s+github\s+repos|github\s+repositories|my\s+repos)\b/i.test(q)) {
444
+ if (slug === "app.github.list_repos")
445
+ score += 120;
446
+ }
308
447
  if (/\b(notion\s+page|search\s+notion)\b/i.test(q)) {
309
448
  if (slug === "app.notion.search_pages")
310
449
  score += 115;
@@ -313,6 +452,46 @@ function scoreToolForPrompt(prompt, tool) {
313
452
  if (slug === "app.linear.create_issue")
314
453
  score += 115;
315
454
  }
455
+ if (/\b(jira\s+issue|create\s+jira|atlassian|jql)\b/i.test(q)) {
456
+ if (slug.startsWith("app.jira."))
457
+ score += 120;
458
+ }
459
+ if (/\b(hubspot|crm\s+contacts?|search\s+contacts?)\b/i.test(q)) {
460
+ if (slug.startsWith("app.hubspot."))
461
+ score += 120;
462
+ }
463
+ if (/\b(discord\s+message|send\s+discord|post\s+to\s+discord)\b/i.test(q)) {
464
+ if (slug.startsWith("app.discord."))
465
+ score += 120;
466
+ }
467
+ if (/\b(google\s+drive|gdrive|drive\s+files?)\b/i.test(q)) {
468
+ if (slug.startsWith("app.googledrive."))
469
+ score += 120;
470
+ }
471
+ if (/\b(airtable|base\s+records?)\b/i.test(q)) {
472
+ if (slug.startsWith("app.airtable."))
473
+ score += 120;
474
+ }
475
+ if (/\b(salesforce|soql|crm\s+records?)\b/i.test(q)) {
476
+ if (slug.startsWith("app.salesforce."))
477
+ score += 120;
478
+ }
479
+ if (/\b(zendesk|support\s+tickets?)\b/i.test(q)) {
480
+ if (slug.startsWith("app.zendesk."))
481
+ score += 120;
482
+ }
483
+ if (/\b(shopify|store\s+orders?)\b/i.test(q)) {
484
+ if (slug.startsWith("app.shopify."))
485
+ score += 120;
486
+ }
487
+ if (/\b(pagerduty|on-call|trigger\s+incident)\b/i.test(q)) {
488
+ if (slug.startsWith("app.pagerduty."))
489
+ score += 120;
490
+ }
491
+ if (/\b(sentry|error\s+issues?|stack\s+traces?)\b/i.test(q)) {
492
+ if (slug.startsWith("app.sentry."))
493
+ score += 120;
494
+ }
316
495
  if (/\b(google\s+calendar|schedule\s+meeting|list\s+events|calendar\s+events)\b/i.test(q)) {
317
496
  if (slug.includes("calendar") || slug.includes("gcal"))
318
497
  score += 110;
@@ -0,0 +1,32 @@
1
+ /** Shared OAuth 2.1 (PKCE + consent) helpers for the Node server and the edge worker. */
2
+ export declare const DEFAULT_OAUTH_SCOPE = "mcp:tools muxo:mcp muxo:read muxo:execute muxo:provision";
3
+ export declare const PKCE_VERIFIER_PATTERN: RegExp;
4
+ export declare const OAUTH_CODE_TTL_MS: number;
5
+ /** API keys minted through OAuth do not expire; this is the advisory lifetime clients see. */
6
+ export declare const OAUTH_ACCESS_TOKEN_TTL_SECONDS = 2592000;
7
+ export declare const LOOPBACK_CLIENT_NAME = "An app on this computer";
8
+ export interface AuthorizeRequest {
9
+ clientId: string;
10
+ clientName: string;
11
+ redirectUri: string;
12
+ state: string;
13
+ codeChallenge: string | null;
14
+ codeChallengeMethod: "S256" | "plain" | null;
15
+ scope: string;
16
+ }
17
+ export declare function base64UrlEncode(bytes: Uint8Array): string;
18
+ export declare function pkceS256(verifier: string): Promise<string>;
19
+ export declare function timingSafeEqualText(a: string, b: string): boolean;
20
+ /** Checks a token-endpoint code_verifier against the challenge stored with the authorization code. */
21
+ export declare function verifyPkce(verifier: string, challenge: string, method: "S256" | "plain" | null): Promise<"ok" | "missing" | "mismatch">;
22
+ export declare function oauthClientName(redirect: URL, clientId: string): string;
23
+ /** Name of the workspace API key minted for an OAuth connection, as listed in the console. */
24
+ export declare function oauthConnectionKeyName(clientName: string): string;
25
+ /** Origin shown on the consent screen; app-scheme redirects have no origin, so show the scheme. */
26
+ export declare function oauthRedirectOrigin(redirectUri: string): string;
27
+ export declare function parseAuthorizeRequest(params: URLSearchParams): AuthorizeRequest | {
28
+ error: string;
29
+ };
30
+ /** Parses a token-endpoint body (form or JSON) and HTTP Basic client credentials into one parameter set. */
31
+ export declare function parseOAuthFormBody(rawBody: string, contentType: string, authorizationHeader: string): URLSearchParams;
32
+ export declare function oauthSecretToken(prefix: string): string;