@muxoai/sdk 1.2.3 → 1.3.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.
Files changed (183) hide show
  1. package/.agents/plugins/marketplace.json +22 -0
  2. package/.claude-plugin/marketplace.json +17 -0
  3. package/.codex/config.toml +5 -0
  4. package/ARCHITECTURE.md +111 -0
  5. package/README.md +21 -12
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +894 -0
  8. package/dist/config.d.ts +20 -0
  9. package/dist/config.js +89 -0
  10. package/dist/engine.d.ts +156 -0
  11. package/dist/engine.js +876 -0
  12. package/dist/index.d.ts +7 -0
  13. package/dist/index.js +7 -0
  14. package/dist/mcp.d.ts +45 -0
  15. package/dist/mcp.js +914 -0
  16. package/dist/nl.d.ts +34 -0
  17. package/dist/nl.js +577 -0
  18. package/dist/providers/composio-instant.d.ts +14 -0
  19. package/dist/providers/composio-instant.js +814 -0
  20. package/dist/providers/composio-sdk.d.ts +41 -0
  21. package/dist/providers/composio-sdk.js +572 -0
  22. package/dist/providers/microsoft-governance.d.ts +66 -0
  23. package/dist/providers/microsoft-governance.js +415 -0
  24. package/dist/providers/stripe-billing.d.ts +41 -0
  25. package/dist/providers/stripe-billing.js +372 -0
  26. package/dist/providers/stripe-projects.d.ts +53 -0
  27. package/dist/providers/stripe-projects.js +636 -0
  28. package/dist/providers/supermemory.d.ts +64 -0
  29. package/dist/providers/supermemory.js +224 -0
  30. package/{index.d.ts → dist/sdk.d.ts} +77 -1
  31. package/dist/sdk.js +270 -0
  32. package/dist/server.d.ts +10 -0
  33. package/dist/server.js +1277 -0
  34. package/dist/store.d.ts +216 -0
  35. package/dist/store.js +1449 -0
  36. package/dist/types.d.ts +285 -0
  37. package/dist/types.js +1 -0
  38. package/dist/ui/console-html.d.ts +2 -0
  39. package/dist/ui/console-html.js +2343 -0
  40. package/package.json +66 -6
  41. package/plugins/muxo/.app.json +8 -0
  42. package/plugins/muxo/.claude-plugin/plugin.json +16 -0
  43. package/plugins/muxo/.codex-plugin/plugin.json +55 -0
  44. package/plugins/muxo/.mcp.json +40 -0
  45. package/plugins/muxo/assets/logo.png +0 -0
  46. package/plugins/muxo/assets/logo.svg +6 -0
  47. package/plugins/muxo/hooks/hooks.json +27 -0
  48. package/plugins/muxo/hooks/session-start.sh +85 -0
  49. package/plugins/muxo/hooks/user-prompt-submit.sh +45 -0
  50. package/plugins/muxo/mcp.json +38 -0
  51. package/plugins/muxo/plugin.json +59 -0
  52. package/plugins/muxo/skills/muxo/SKILL.md +25 -0
  53. package/plugins/muxo/skills/muxo/references/cli.md +57 -0
  54. package/plugins/muxo/skills/muxo/references/mcp.md +25 -0
  55. package/plugins/muxo/skills/setup/SKILL.md +28 -0
  56. package/src/catalogues/stripe-projects-catalog.json +9832 -0
  57. package/vendor/microsoft-governance/README.md +363 -0
  58. package/vendor/microsoft-governance/dist/audit.d.ts +26 -0
  59. package/vendor/microsoft-governance/dist/audit.d.ts.map +1 -0
  60. package/vendor/microsoft-governance/dist/audit.js +107 -0
  61. package/vendor/microsoft-governance/dist/audit.js.map +1 -0
  62. package/vendor/microsoft-governance/dist/cascade-containment.d.ts +84 -0
  63. package/vendor/microsoft-governance/dist/cascade-containment.d.ts.map +1 -0
  64. package/vendor/microsoft-governance/dist/cascade-containment.js +387 -0
  65. package/vendor/microsoft-governance/dist/cascade-containment.js.map +1 -0
  66. package/vendor/microsoft-governance/dist/client.d.ts +34 -0
  67. package/vendor/microsoft-governance/dist/client.d.ts.map +1 -0
  68. package/vendor/microsoft-governance/dist/client.js +112 -0
  69. package/vendor/microsoft-governance/dist/client.js.map +1 -0
  70. package/vendor/microsoft-governance/dist/context-poisoning.d.ts +58 -0
  71. package/vendor/microsoft-governance/dist/context-poisoning.d.ts.map +1 -0
  72. package/vendor/microsoft-governance/dist/context-poisoning.js +410 -0
  73. package/vendor/microsoft-governance/dist/context-poisoning.js.map +1 -0
  74. package/vendor/microsoft-governance/dist/credential-vault.d.ts +213 -0
  75. package/vendor/microsoft-governance/dist/credential-vault.d.ts.map +1 -0
  76. package/vendor/microsoft-governance/dist/credential-vault.js +567 -0
  77. package/vendor/microsoft-governance/dist/credential-vault.js.map +1 -0
  78. package/vendor/microsoft-governance/dist/discovery.d.ts +80 -0
  79. package/vendor/microsoft-governance/dist/discovery.d.ts.map +1 -0
  80. package/vendor/microsoft-governance/dist/discovery.js +404 -0
  81. package/vendor/microsoft-governance/dist/discovery.js.map +1 -0
  82. package/vendor/microsoft-governance/dist/encryption/channel.d.ts +29 -0
  83. package/vendor/microsoft-governance/dist/encryption/channel.d.ts.map +1 -0
  84. package/vendor/microsoft-governance/dist/encryption/channel.js +78 -0
  85. package/vendor/microsoft-governance/dist/encryption/channel.js.map +1 -0
  86. package/vendor/microsoft-governance/dist/encryption/index.d.ts +9 -0
  87. package/vendor/microsoft-governance/dist/encryption/index.d.ts.map +1 -0
  88. package/vendor/microsoft-governance/dist/encryption/index.js +23 -0
  89. package/vendor/microsoft-governance/dist/encryption/index.js.map +1 -0
  90. package/vendor/microsoft-governance/dist/encryption/mesh-client.d.ts +267 -0
  91. package/vendor/microsoft-governance/dist/encryption/mesh-client.d.ts.map +1 -0
  92. package/vendor/microsoft-governance/dist/encryption/mesh-client.js +1001 -0
  93. package/vendor/microsoft-governance/dist/encryption/mesh-client.js.map +1 -0
  94. package/vendor/microsoft-governance/dist/encryption/ratchet.d.ts +38 -0
  95. package/vendor/microsoft-governance/dist/encryption/ratchet.d.ts.map +1 -0
  96. package/vendor/microsoft-governance/dist/encryption/ratchet.js +223 -0
  97. package/vendor/microsoft-governance/dist/encryption/ratchet.js.map +1 -0
  98. package/vendor/microsoft-governance/dist/encryption/registry-client.d.ts +136 -0
  99. package/vendor/microsoft-governance/dist/encryption/registry-client.d.ts.map +1 -0
  100. package/vendor/microsoft-governance/dist/encryption/registry-client.js +369 -0
  101. package/vendor/microsoft-governance/dist/encryption/registry-client.js.map +1 -0
  102. package/vendor/microsoft-governance/dist/encryption/x3dh.d.ts +80 -0
  103. package/vendor/microsoft-governance/dist/encryption/x3dh.d.ts.map +1 -0
  104. package/vendor/microsoft-governance/dist/encryption/x3dh.js +238 -0
  105. package/vendor/microsoft-governance/dist/encryption/x3dh.js.map +1 -0
  106. package/vendor/microsoft-governance/dist/framework-adapter.d.ts +63 -0
  107. package/vendor/microsoft-governance/dist/framework-adapter.d.ts.map +1 -0
  108. package/vendor/microsoft-governance/dist/framework-adapter.js +253 -0
  109. package/vendor/microsoft-governance/dist/framework-adapter.js.map +1 -0
  110. package/vendor/microsoft-governance/dist/identity.d.ts +124 -0
  111. package/vendor/microsoft-governance/dist/identity.d.ts.map +1 -0
  112. package/vendor/microsoft-governance/dist/identity.js +446 -0
  113. package/vendor/microsoft-governance/dist/identity.js.map +1 -0
  114. package/vendor/microsoft-governance/dist/index.d.ts +39 -0
  115. package/vendor/microsoft-governance/dist/index.d.ts.map +1 -0
  116. package/vendor/microsoft-governance/dist/index.js +95 -0
  117. package/vendor/microsoft-governance/dist/index.js.map +1 -0
  118. package/vendor/microsoft-governance/dist/kill-switch.d.ts +22 -0
  119. package/vendor/microsoft-governance/dist/kill-switch.d.ts.map +1 -0
  120. package/vendor/microsoft-governance/dist/kill-switch.js +60 -0
  121. package/vendor/microsoft-governance/dist/kill-switch.js.map +1 -0
  122. package/vendor/microsoft-governance/dist/lifecycle.d.ts +50 -0
  123. package/vendor/microsoft-governance/dist/lifecycle.d.ts.map +1 -0
  124. package/vendor/microsoft-governance/dist/lifecycle.js +113 -0
  125. package/vendor/microsoft-governance/dist/lifecycle.js.map +1 -0
  126. package/vendor/microsoft-governance/dist/mcp.d.ts +41 -0
  127. package/vendor/microsoft-governance/dist/mcp.d.ts.map +1 -0
  128. package/vendor/microsoft-governance/dist/mcp.js +233 -0
  129. package/vendor/microsoft-governance/dist/mcp.js.map +1 -0
  130. package/vendor/microsoft-governance/dist/metrics.d.ts +123 -0
  131. package/vendor/microsoft-governance/dist/metrics.d.ts.map +1 -0
  132. package/vendor/microsoft-governance/dist/metrics.js +289 -0
  133. package/vendor/microsoft-governance/dist/metrics.js.map +1 -0
  134. package/vendor/microsoft-governance/dist/oci-manifest.d.ts +49 -0
  135. package/vendor/microsoft-governance/dist/oci-manifest.d.ts.map +1 -0
  136. package/vendor/microsoft-governance/dist/oci-manifest.js +182 -0
  137. package/vendor/microsoft-governance/dist/oci-manifest.js.map +1 -0
  138. package/vendor/microsoft-governance/dist/policy-backends/cedar.d.ts +15 -0
  139. package/vendor/microsoft-governance/dist/policy-backends/cedar.d.ts.map +1 -0
  140. package/vendor/microsoft-governance/dist/policy-backends/cedar.js +88 -0
  141. package/vendor/microsoft-governance/dist/policy-backends/cedar.js.map +1 -0
  142. package/vendor/microsoft-governance/dist/policy-backends/opa.d.ts +17 -0
  143. package/vendor/microsoft-governance/dist/policy-backends/opa.d.ts.map +1 -0
  144. package/vendor/microsoft-governance/dist/policy-backends/opa.js +74 -0
  145. package/vendor/microsoft-governance/dist/policy-backends/opa.js.map +1 -0
  146. package/vendor/microsoft-governance/dist/policy.d.ts +77 -0
  147. package/vendor/microsoft-governance/dist/policy.d.ts.map +1 -0
  148. package/vendor/microsoft-governance/dist/policy.js +760 -0
  149. package/vendor/microsoft-governance/dist/policy.js.map +1 -0
  150. package/vendor/microsoft-governance/dist/prompt-defense.d.ts +37 -0
  151. package/vendor/microsoft-governance/dist/prompt-defense.d.ts.map +1 -0
  152. package/vendor/microsoft-governance/dist/prompt-defense.js +229 -0
  153. package/vendor/microsoft-governance/dist/prompt-defense.js.map +1 -0
  154. package/vendor/microsoft-governance/dist/protocol-facets.d.ts +87 -0
  155. package/vendor/microsoft-governance/dist/protocol-facets.d.ts.map +1 -0
  156. package/vendor/microsoft-governance/dist/protocol-facets.js +728 -0
  157. package/vendor/microsoft-governance/dist/protocol-facets.js.map +1 -0
  158. package/vendor/microsoft-governance/dist/rings.d.ts +17 -0
  159. package/vendor/microsoft-governance/dist/rings.d.ts.map +1 -0
  160. package/vendor/microsoft-governance/dist/rings.js +61 -0
  161. package/vendor/microsoft-governance/dist/rings.js.map +1 -0
  162. package/vendor/microsoft-governance/dist/sandbox.d.ts +61 -0
  163. package/vendor/microsoft-governance/dist/sandbox.d.ts.map +1 -0
  164. package/vendor/microsoft-governance/dist/sandbox.js +199 -0
  165. package/vendor/microsoft-governance/dist/sandbox.js.map +1 -0
  166. package/vendor/microsoft-governance/dist/surface-parity.d.ts +45 -0
  167. package/vendor/microsoft-governance/dist/surface-parity.d.ts.map +1 -0
  168. package/vendor/microsoft-governance/dist/surface-parity.js +216 -0
  169. package/vendor/microsoft-governance/dist/surface-parity.js.map +1 -0
  170. package/vendor/microsoft-governance/dist/trust.d.ts +28 -0
  171. package/vendor/microsoft-governance/dist/trust.d.ts.map +1 -0
  172. package/vendor/microsoft-governance/dist/trust.js +209 -0
  173. package/vendor/microsoft-governance/dist/trust.js.map +1 -0
  174. package/vendor/microsoft-governance/dist/types.d.ts +422 -0
  175. package/vendor/microsoft-governance/dist/types.d.ts.map +1 -0
  176. package/vendor/microsoft-governance/dist/types.js +29 -0
  177. package/vendor/microsoft-governance/dist/types.js.map +1 -0
  178. package/vendor/microsoft-governance/dist/verify.d.ts +135 -0
  179. package/vendor/microsoft-governance/dist/verify.d.ts.map +1 -0
  180. package/vendor/microsoft-governance/dist/verify.js +356 -0
  181. package/vendor/microsoft-governance/dist/verify.js.map +1 -0
  182. package/vendor/microsoft-governance/package.json +64 -0
  183. package/index.js +0 -1
package/dist/engine.js ADDED
@@ -0,0 +1,876 @@
1
+ import { resolveNaturalLanguageIntent, } from "./nl.js";
2
+ import { ComposioInstantAdapter } from "./providers/composio-instant.js";
3
+ import { ComposioSdkAdapter } from "./providers/composio-sdk.js";
4
+ import { MicrosoftGovernanceAdapter } from "./providers/microsoft-governance.js";
5
+ import { StripeBillingAdapter } from "./providers/stripe-billing.js";
6
+ import { StripeProjectsAdapter } from "./providers/stripe-projects.js";
7
+ import { SupermemoryAdapter } from "./providers/supermemory.js";
8
+ export class MuxoEngine {
9
+ config;
10
+ store;
11
+ composioSdk;
12
+ composioInstant;
13
+ stripeProjects;
14
+ stripeBilling;
15
+ governance;
16
+ supermemory;
17
+ constructor(config, store) {
18
+ this.config = config;
19
+ this.store = store;
20
+ this.composioSdk = new ComposioSdkAdapter(config);
21
+ this.composioInstant = new ComposioInstantAdapter(config);
22
+ this.stripeProjects = new StripeProjectsAdapter(config);
23
+ this.stripeBilling = new StripeBillingAdapter(config, store);
24
+ this.governance = new MicrosoftGovernanceAdapter(config.vaultMasterKey);
25
+ this.supermemory = new SupermemoryAdapter(config);
26
+ }
27
+ // 1. get_profile
28
+ getProfile(ctx) {
29
+ return {
30
+ id: ctx.user.id,
31
+ name: ctx.user.name,
32
+ email: ctx.user.email,
33
+ user: ctx.user,
34
+ actorId: ctx.actorId,
35
+ authType: ctx.authType,
36
+ workspaceId: ctx.workspace.id,
37
+ workspaceName: ctx.workspace.name,
38
+ tier: ctx.workspace.tier,
39
+ };
40
+ }
41
+ // 2. get_organization
42
+ getOrganization(ctx) {
43
+ const ws = this.store.getWorkspace(ctx.workspace.id);
44
+ const resources = this.store.listResources(ws.id);
45
+ const connections = this.store.listConnections(ws.id);
46
+ const supplierSettlementSummary = this.store.getSupplierSettlementSummary(ws.id);
47
+ return {
48
+ organization: {
49
+ id: ws.id,
50
+ name: ws.name,
51
+ slug: ws.slug,
52
+ tier: ws.tier,
53
+ usage: {
54
+ monthlyActionsUsed: ws.monthlyActionsUsed,
55
+ monthlyActionsLimit: ws.monthlyActionsLimit,
56
+ monthlyActionsRemaining: Math.max(0, ws.monthlyActionsLimit - ws.monthlyActionsUsed),
57
+ creditsBalance: ws.creditsBalance,
58
+ },
59
+ supplierSettlementSummary,
60
+ policy: ws.policy,
61
+ activeConnectionsCount: connections.filter((c) => c.status === "active").length,
62
+ provisionedResourcesCount: resources.filter((r) => r.status === "active").length,
63
+ projectsEnvironment: ws.projectsEnvName,
64
+ createdAt: ws.createdAt,
65
+ },
66
+ };
67
+ }
68
+ // 3. search_tools
69
+ async searchTools(params) {
70
+ const limit = Math.min(100, Math.max(1, Number(params.limit || 25)));
71
+ const lane = params.lane || "all";
72
+ const query = params.query?.trim();
73
+ const results = [];
74
+ if (lane === "all" || lane === "composio_instant") {
75
+ results.push(...this.composioInstant.searchTools(query, limit));
76
+ }
77
+ if (lane === "all" || lane === "composio_sdk") {
78
+ const sdkTools = await this.composioSdk.searchTools(query, limit);
79
+ results.push(...sdkTools);
80
+ }
81
+ if (lane === "all" || lane === "stripe_projects") {
82
+ results.push(...this.stripeProjects.searchTools(query, limit));
83
+ const billingTools = this.stripeBilling.listTools().filter((t) => {
84
+ if (!query)
85
+ return true;
86
+ const q = query.toLowerCase();
87
+ const hay = `${t.slug} ${t.name} ${t.description} ${t.categories.join(" ")}`.toLowerCase();
88
+ return q.split(/\s+/).some((tok) => hay.includes(tok));
89
+ });
90
+ results.push(...billingTools);
91
+ }
92
+ const filtered = params.riskLevel
93
+ ? results.filter((t) => t.riskLevel === params.riskLevel)
94
+ : results;
95
+ return {
96
+ tools: filtered.slice(0, limit),
97
+ total: filtered.length,
98
+ };
99
+ }
100
+ async listAllCatalogTools() {
101
+ const instant = this.composioInstant.searchTools(undefined, 100);
102
+ const sdk = await this.composioSdk.searchTools(undefined, 100);
103
+ const proj = this.stripeProjects.searchTools(undefined, 100);
104
+ const billing = this.stripeBilling.listTools();
105
+ return [...instant, ...billing, ...sdk, ...proj];
106
+ }
107
+ // 4. inspect_tool
108
+ async inspectTool(slug) {
109
+ const normalized = slug.trim();
110
+ const billing = this.stripeBilling
111
+ .listTools()
112
+ .find((t) => t.slug.toLowerCase() === normalized.toLowerCase() ||
113
+ t.upstreamSlug.toLowerCase() === normalized.toLowerCase());
114
+ if (billing)
115
+ return billing;
116
+ const instant = this.composioInstant.inspectTool(normalized);
117
+ if (instant)
118
+ return instant;
119
+ const proj = this.stripeProjects.inspectTool(normalized);
120
+ if (proj)
121
+ return proj;
122
+ const sdk = await this.composioSdk.inspectTool(normalized);
123
+ if (sdk)
124
+ return sdk;
125
+ throw new Error(`Tool '${normalized}' not found in Muxo catalog. Use search_tools to discover valid slugs.`);
126
+ }
127
+ // 5. connection_status
128
+ async connectionStatus(ctx, params) {
129
+ if (params?.syncLive !== false) {
130
+ // Sync live Composio connected accounts for this workspace
131
+ const liveComposio = await this.composioSdk.listLiveConnections(ctx.workspace.id);
132
+ for (const c of liveComposio) {
133
+ this.store.upsertConnection({
134
+ workspaceId: ctx.workspace.id,
135
+ lane: "composio_sdk",
136
+ providerSlug: c.providerSlug,
137
+ providerName: c.providerName,
138
+ status: c.status,
139
+ externalAccountId: c.externalAccountId,
140
+ });
141
+ }
142
+ // Sync live Stripe Projects linked providers
143
+ try {
144
+ const projStatus = await this.stripeProjects.getLiveStatus();
145
+ for (const p of projStatus.providers) {
146
+ this.store.upsertConnection({
147
+ workspaceId: ctx.workspace.id,
148
+ lane: "stripe_projects",
149
+ providerSlug: p.slug,
150
+ providerName: p.name,
151
+ status: p.status,
152
+ externalAccountId: p.id,
153
+ redirectUrl: p.redirectUrl,
154
+ });
155
+ }
156
+ }
157
+ catch {
158
+ // Keep cached connections if CLI is busy
159
+ }
160
+ }
161
+ let connections = this.store.listConnections(ctx.workspace.id);
162
+ if (params?.provider) {
163
+ const target = params.provider.toLowerCase();
164
+ connections = connections.filter((c) => c.providerSlug.toLowerCase() === target ||
165
+ c.providerName.toLowerCase().includes(target));
166
+ }
167
+ return {
168
+ workspaceId: ctx.workspace.id,
169
+ instantWalletStatus: "active",
170
+ connections,
171
+ summary: {
172
+ total: connections.length,
173
+ active: connections.filter((c) => c.status === "active").length,
174
+ pending: connections.filter((c) => c.status === "pending").length,
175
+ expired: connections.filter((c) => c.status === "expired").length,
176
+ },
177
+ };
178
+ }
179
+ // 6. start_connection
180
+ async startConnection(ctx, params) {
181
+ const rawProvider = params.provider.trim().toLowerCase();
182
+ const isProjectsLane = params.lane === "stripe_projects" || rawProvider.startsWith("resource.");
183
+ const cleanSlug = rawProvider.replace(/^(app\.|resource\.)/, "");
184
+ if (isProjectsLane) {
185
+ const linked = await this.stripeProjects.linkProvider(cleanSlug);
186
+ const record = this.store.upsertConnection({
187
+ workspaceId: ctx.workspace.id,
188
+ lane: "stripe_projects",
189
+ providerSlug: linked.providerSlug,
190
+ providerName: linked.providerSlug.charAt(0).toUpperCase() +
191
+ linked.providerSlug.slice(1),
192
+ status: linked.status,
193
+ redirectUrl: linked.redirectUrl,
194
+ });
195
+ return { ...record, message: linked.message };
196
+ }
197
+ const started = await this.composioSdk.startConnection({
198
+ workspaceId: ctx.workspace.id,
199
+ providerSlug: cleanSlug,
200
+ callbackUrl: params.callbackUrl,
201
+ });
202
+ const record = this.store.upsertConnection({
203
+ workspaceId: ctx.workspace.id,
204
+ lane: "composio_sdk",
205
+ providerSlug: started.providerSlug,
206
+ providerName: started.providerName,
207
+ status: started.status,
208
+ externalAccountId: started.externalAccountId,
209
+ redirectUrl: started.redirectUrl,
210
+ metadata: { callbackUrl: started.callbackUrl },
211
+ });
212
+ return {
213
+ ...record,
214
+ callbackUrl: started.callbackUrl,
215
+ message: started.message,
216
+ };
217
+ }
218
+ // 6b. wait_for_connection (OAuth handoff polling & recovery, like COMPOSIO_WAIT_FOR_CONNECTIONS)
219
+ async waitForConnection(ctx, params) {
220
+ const cleanSlug = params.provider
221
+ .trim()
222
+ .toLowerCase()
223
+ .replace(/^(app\.|resource\.)/, "");
224
+ const timeoutMs = Math.min(120, Math.max(0, Number(params.timeoutSeconds ?? 15))) * 1000;
225
+ const pollIntervalMs = Math.min(5000, Math.max(200, Number(params.pollIntervalMs ?? 1500)));
226
+ const deadline = Date.now() + timeoutMs;
227
+ let current = this.store
228
+ .listConnections(ctx.workspace.id)
229
+ .find((c) => c.providerSlug.toLowerCase() === cleanSlug);
230
+ if (!current || (!current.redirectUrl && current.status !== "active")) {
231
+ try {
232
+ current = await this.startConnection(ctx, { provider: cleanSlug });
233
+ }
234
+ catch {
235
+ // Proceed with status check
236
+ }
237
+ }
238
+ while (true) {
239
+ const latestLocal = this.store
240
+ .listConnections(ctx.workspace.id)
241
+ .find((c) => c.providerSlug.toLowerCase() === cleanSlug);
242
+ if (latestLocal) {
243
+ current = latestLocal;
244
+ if (latestLocal.status === "active") {
245
+ return {
246
+ connected: true,
247
+ provider: cleanSlug,
248
+ status: "active",
249
+ connection: latestLocal,
250
+ redirectUrl: null,
251
+ message: `${latestLocal.providerName} OAuth handoff completed and connection is active.`,
252
+ };
253
+ }
254
+ }
255
+ if (current?.externalAccountId && current.lane === "composio_sdk") {
256
+ const direct = await this.composioSdk.getConnectedAccountStatus(current.externalAccountId);
257
+ if (direct && direct.status === "active") {
258
+ current = this.store.upsertConnection({
259
+ workspaceId: ctx.workspace.id,
260
+ lane: "composio_sdk",
261
+ providerSlug: cleanSlug,
262
+ providerName: cleanSlug.charAt(0).toUpperCase() + cleanSlug.slice(1),
263
+ status: "active",
264
+ externalAccountId: direct.id,
265
+ redirectUrl: null,
266
+ });
267
+ return {
268
+ connected: true,
269
+ provider: cleanSlug,
270
+ status: "active",
271
+ connection: current,
272
+ redirectUrl: null,
273
+ message: `${current.providerName} OAuth handoff completed and connection is active.`,
274
+ };
275
+ }
276
+ }
277
+ const synced = await this.connectionStatus(ctx, {
278
+ provider: cleanSlug,
279
+ syncLive: true,
280
+ });
281
+ const list = synced.connections || [];
282
+ const found = list.find((c) => c.providerSlug.toLowerCase() === cleanSlug);
283
+ if (found) {
284
+ current = found;
285
+ if (found.status === "active") {
286
+ return {
287
+ connected: true,
288
+ provider: cleanSlug,
289
+ status: "active",
290
+ connection: found,
291
+ redirectUrl: null,
292
+ message: `${found.providerName} connection is active and ready for governed execution.`,
293
+ };
294
+ }
295
+ }
296
+ if (Date.now() >= deadline) {
297
+ break;
298
+ }
299
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
300
+ }
301
+ if (!current) {
302
+ current = await this.startConnection(ctx, { provider: cleanSlug });
303
+ }
304
+ return {
305
+ connected: false,
306
+ provider: cleanSlug,
307
+ status: current.status,
308
+ connection: current,
309
+ redirectUrl: current.redirectUrl,
310
+ message: current.redirectUrl
311
+ ? `Awaiting user OAuth authorization for ${current.providerName}. Open ${current.redirectUrl} in a browser, then re-run wait_for_connection.`
312
+ : `Connection for ${current.providerName} is currently ${current.status}.`,
313
+ };
314
+ }
315
+ // 6c. Browser OAuth callback handoff handler (GET /oauth/callback)
316
+ async handleOAuthCallback(params) {
317
+ const cleanSlug = params.provider
318
+ .trim()
319
+ .toLowerCase()
320
+ .replace(/^(app\.|resource\.)/, "");
321
+ const providerName = cleanSlug.charAt(0).toUpperCase() + cleanSlug.slice(1);
322
+ const ws = this.store.getWorkspace(params.workspaceId);
323
+ if (!ws) {
324
+ throw new Error(`Workspace '${params.workspaceId}' not found`);
325
+ }
326
+ const existing = this.store
327
+ .listConnections(ws.id)
328
+ .find((c) => c.providerSlug.toLowerCase() === cleanSlug);
329
+ const accountId = params.connectedAccountId || existing?.externalAccountId || null;
330
+ let resolvedStatus = "pending";
331
+ if (accountId) {
332
+ const live = await this.composioSdk.getConnectedAccountStatus(accountId);
333
+ if (live) {
334
+ resolvedStatus = live.status;
335
+ }
336
+ }
337
+ if (resolvedStatus !== "active") {
338
+ const liveList = await this.composioSdk.listLiveConnections(ws.id);
339
+ const match = liveList.find((c) => c.providerSlug === cleanSlug);
340
+ if (match) {
341
+ resolvedStatus = match.status;
342
+ }
343
+ }
344
+ const rawCallbackStatus = String(params.status || "").toLowerCase();
345
+ if (rawCallbackStatus === "success" ||
346
+ rawCallbackStatus === "active" ||
347
+ rawCallbackStatus === "connected") {
348
+ resolvedStatus = "active";
349
+ }
350
+ const updated = this.store.upsertConnection({
351
+ workspaceId: ws.id,
352
+ lane: "composio_sdk",
353
+ providerSlug: cleanSlug,
354
+ providerName,
355
+ status: resolvedStatus,
356
+ externalAccountId: accountId,
357
+ redirectUrl: resolvedStatus === "active" ? null : existing?.redirectUrl,
358
+ });
359
+ return {
360
+ ok: true,
361
+ workspaceId: ws.id,
362
+ providerSlug: cleanSlug,
363
+ providerName,
364
+ status: updated.status,
365
+ externalAccountId: updated.externalAccountId,
366
+ };
367
+ }
368
+ // 7. plan_action
369
+ async planAction(ctx, params) {
370
+ const ws = this.store.getWorkspace(ctx.workspace.id);
371
+ let tool;
372
+ let resolvedInput = { ...(params.input || {}) };
373
+ let resolvedReason = params.reason || `Planned execution of ${params.toolSlug}`;
374
+ try {
375
+ tool = await this.inspectTool(params.toolSlug);
376
+ }
377
+ catch (inspectErr) {
378
+ // Natural-language fallback: if an agent or human passed plain English as toolSlug/instruction, resolve it!
379
+ const nlSource = `${params.toolSlug} ${params.reason || ""}`.trim();
380
+ const allTools = await this.listAllCatalogTools();
381
+ const byokEnv = this.store.getDecryptedWorkspaceEnv(ws.id);
382
+ const nl = await resolveNaturalLanguageIntent({
383
+ prompt: nlSource,
384
+ tools: allTools,
385
+ explicitInput: resolvedInput,
386
+ byokKeys: byokEnv,
387
+ });
388
+ if (!nl.resolved || !nl.tool) {
389
+ throw inspectErr;
390
+ }
391
+ tool = nl.tool;
392
+ resolvedInput = nl.input;
393
+ resolvedReason = params.reason || nl.reason || nlSource;
394
+ }
395
+ const byokActive = this.store.hasByokForLane(ws.id, tool.lane, tool.slug);
396
+ const effectiveCreditCost = byokActive ? 0 : tool.creditCost;
397
+ if (ws.monthlyActionsUsed >= ws.monthlyActionsLimit) {
398
+ throw new Error(`Monthly action limit reached (${ws.monthlyActionsUsed}/${ws.monthlyActionsLimit}). Upgrade to Starter ($29/mo) to unlock 5,000 actions/mo.`);
399
+ }
400
+ if (effectiveCreditCost > ws.creditsBalance) {
401
+ throw new Error(`Insufficient workspace credits for ${tool.slug} (requires ${effectiveCreditCost}, available ${ws.creditsBalance}). Top up credits or configure a BYOK key.`);
402
+ }
403
+ if (effectiveCreditCost > ws.policy.maxCreditsPerRun) {
404
+ throw new Error(`Tool credit cost (${effectiveCreditCost}) exceeds workspace policy maxCreditsPerRun (${ws.policy.maxCreditsPerRun}).`);
405
+ }
406
+ // 1. Evaluate Microsoft Agent Governance Pipeline:
407
+ // Agent -> McpSecurityScanner -> PolicyEngine -> AgentIdentity (Ed25519 DID) -> AuditLogger -> DecisionRecord
408
+ const decisionRecord = this.governance.evaluatePlan({
409
+ workspace: ws,
410
+ actorId: ctx.actorId,
411
+ tool,
412
+ input: resolvedInput,
413
+ reason: resolvedReason,
414
+ });
415
+ if (decisionRecord.verdict === "deny") {
416
+ throw new Error(`Microsoft Agent Governance denied plan for ${tool.slug} (rule: ${decisionRecord.matchedRule}): ${decisionRecord.reason}`);
417
+ }
418
+ // 2. Recall Supermemory v5 contextual brain for this workspace + tool intent
419
+ const memoryQuery = `${tool.slug} ${tool.name} ${resolvedReason}`.trim();
420
+ const memoryContext = await this.supermemory.getContextForWorkspace(ws.id, memoryQuery);
421
+ const requiresHumanApproval = decisionRecord.verdict === "escalate" ||
422
+ (ws.policy.mode === "enforce" &&
423
+ ws.policy.requireApprovalFor.includes(tool.riskLevel));
424
+ const approvalStatus = requiresHumanApproval
425
+ ? "pending_approval"
426
+ : "auto_approved";
427
+ const plan = this.store.createPlan({
428
+ workspaceId: ws.id,
429
+ actorId: ctx.actorId,
430
+ toolSlug: tool.slug,
431
+ upstreamSlug: tool.upstreamSlug,
432
+ lane: tool.lane,
433
+ riskLevel: tool.riskLevel,
434
+ input: resolvedInput,
435
+ reason: resolvedReason,
436
+ creditCost: effectiveCreditCost,
437
+ approvalStatus,
438
+ decisionRecord,
439
+ memoryContext,
440
+ });
441
+ // 3. Check external user OAuth connection state for Connected Apps (composio_sdk)
442
+ let authHandoff;
443
+ if (tool.lane === "composio_sdk" && tool.requiresAuth) {
444
+ let existingConn = this.store
445
+ .listConnections(ws.id)
446
+ .find((c) => c.lane === "composio_sdk" &&
447
+ c.providerSlug.toLowerCase() === tool.providerSlug.toLowerCase());
448
+ if (!existingConn || existingConn.status !== "active") {
449
+ try {
450
+ if (!existingConn || !existingConn.redirectUrl) {
451
+ existingConn = await this.startConnection(ctx, {
452
+ provider: tool.providerSlug,
453
+ });
454
+ }
455
+ }
456
+ catch {
457
+ // Keep existing connection state if offline
458
+ }
459
+ if (!existingConn || existingConn.status !== "active") {
460
+ authHandoff = {
461
+ required: true,
462
+ provider: tool.providerSlug,
463
+ status: existingConn?.status || "pending",
464
+ redirectUrl: existingConn?.redirectUrl || null,
465
+ externalAccountId: existingConn?.externalAccountId || null,
466
+ instructions: existingConn?.redirectUrl
467
+ ? `Ask the user to authorize ${tool.providerName} at ${existingConn.redirectUrl}, then call wait_for_connection({ provider: "${tool.providerSlug}" }) before executing ${plan.id}.`
468
+ : `Call start_connection({ provider: "${tool.providerSlug}" }) to authorize ${tool.providerName} before executing ${plan.id}.`,
469
+ };
470
+ }
471
+ }
472
+ }
473
+ const executeToolName = `execute_${tool.riskLevel}`;
474
+ let nextStep = approvalStatus === "pending_approval"
475
+ ? `Plan ${plan.id} requires human owner approval in the Muxo Console or via approve_plan before calling ${executeToolName}.`
476
+ : `Plan ${plan.id} is auto-approved. Call ${executeToolName}({ plan_id: "${plan.id}" }) to execute.`;
477
+ if (authHandoff?.required) {
478
+ nextStep = `${authHandoff.instructions} Once connected, ${nextStep}`;
479
+ }
480
+ return {
481
+ plan,
482
+ tool,
483
+ decisionRecord,
484
+ memoryContext,
485
+ ...(authHandoff ? { authHandoff } : {}),
486
+ nextStep,
487
+ };
488
+ }
489
+ // 8. get_plan
490
+ getPlan(ctx, planId) {
491
+ const plan = this.store.getPlan(ctx.workspace.id, planId);
492
+ if (!plan)
493
+ throw new Error(`Plan '${planId}' not found in workspace.`);
494
+ return plan;
495
+ }
496
+ // Human owner approval / rejection
497
+ approvePlan(ctx, planId, decision = "approved") {
498
+ const plan = this.getPlan(ctx, planId);
499
+ if (plan.approvalStatus === "executed") {
500
+ throw new Error(`Plan '${planId}' has already been executed.`);
501
+ }
502
+ return this.store.updatePlanApproval({
503
+ workspaceId: ctx.workspace.id,
504
+ planId,
505
+ approvalStatus: decision,
506
+ approvedBy: ctx.user.email,
507
+ });
508
+ }
509
+ // 9. get_run_context
510
+ async getRunContext(ctx, query) {
511
+ const ws = this.store.getWorkspace(ctx.workspace.id);
512
+ const resources = this.store.listResources(ws.id);
513
+ const activeEnv = this.store.getDecryptedWorkspaceEnv(ws.id);
514
+ const redactedEnv = {};
515
+ for (const [k, v] of Object.entries(activeEnv)) {
516
+ redactedEnv[k] =
517
+ v.length > 8 ? `${v.slice(0, 4)}••••${v.slice(-3)}` : "••••••••";
518
+ }
519
+ const memoryContext = await this.supermemory.getContextForWorkspace(ws.id, query);
520
+ return {
521
+ workspaceId: ws.id,
522
+ workspaceSlug: ws.slug,
523
+ projectsEnvironment: ws.projectsEnvName,
524
+ policy: ws.policy,
525
+ creditsBalance: ws.creditsBalance,
526
+ monthlyActionsRemaining: Math.max(0, ws.monthlyActionsLimit - ws.monthlyActionsUsed),
527
+ provisionedResources: resources.filter((r) => r.status === "active"),
528
+ environmentVariablesRedacted: redactedEnv,
529
+ supermemoryBrain: memoryContext,
530
+ governance: this.governance.getStatus(ws),
531
+ envPullHint: "Run `muxo env pull` or call GET /api/v1/resources/env to write decrypted credentials to your local .env file.",
532
+ };
533
+ }
534
+ // Supermemory Workspace Brain Operations
535
+ async getMemoryOverview(ctx, query) {
536
+ const context = await this.supermemory.getContextForWorkspace(ctx.workspace.id, query);
537
+ const recentMemories = this.store.listMemoryRecords(ctx.workspace.id, 25);
538
+ return {
539
+ enabled: context.enabled,
540
+ namespace: context.namespace,
541
+ context,
542
+ recentMemories,
543
+ memories: recentMemories,
544
+ };
545
+ }
546
+ async addWorkspaceMemory(ctx, params) {
547
+ const kind = params.kind || "fact";
548
+ const remote = await this.supermemory.addMemory({
549
+ workspaceId: ctx.workspace.id,
550
+ title: params.title,
551
+ content: params.content,
552
+ kind,
553
+ metadata: params.metadata,
554
+ });
555
+ return this.store.saveMemoryRecord({
556
+ workspaceId: ctx.workspace.id,
557
+ namespace: remote.namespace,
558
+ documentId: remote.documentId,
559
+ title: params.title,
560
+ content: remote.sanitizedContent,
561
+ kind,
562
+ metadata: {
563
+ ...(params.metadata || {}),
564
+ supermemoryStatus: remote.status,
565
+ },
566
+ });
567
+ }
568
+ async deleteWorkspaceMemory(ctx, idOrDocId) {
569
+ const local = this.store.deleteMemoryRecord(ctx.workspace.id, idOrDocId);
570
+ const docId = local?.documentId || idOrDocId;
571
+ const remote = await this.supermemory.deleteMemory(ctx.workspace.id, docId);
572
+ return {
573
+ deleted: Boolean(local || remote.deleted),
574
+ record: local,
575
+ };
576
+ }
577
+ // 10-15. execute_<risk_level>
578
+ async executePlanForRisk(ctx, planId, expectedRisk) {
579
+ const plan = this.getPlan(ctx, planId);
580
+ if (plan.riskLevel !== expectedRisk) {
581
+ throw new Error(`Risk lane mismatch: Plan '${plan.id}' has risk level '${plan.riskLevel}', so it must be executed with 'execute_${plan.riskLevel}' instead of 'execute_${expectedRisk}'.`);
582
+ }
583
+ if (plan.runId) {
584
+ const existingRun = this.store.getRun(ctx.workspace.id, plan.runId);
585
+ const existingReceipt = this.store.getReceipt(ctx.workspace.id, plan.runId);
586
+ if (existingRun && existingReceipt) {
587
+ return { run: existingRun, receipt: existingReceipt };
588
+ }
589
+ throw new Error(`Plan '${plan.id}' was already claimed by run '${plan.runId}' (execute-once invariant).`);
590
+ }
591
+ if (plan.approvalStatus === "pending_approval") {
592
+ throw new Error(`Plan '${plan.id}' (${plan.riskLevel}) is awaiting human approval. Approve it in the Muxo Console or via CLI 'muxo approve ${plan.id}' before executing.`);
593
+ }
594
+ if (plan.approvalStatus === "rejected") {
595
+ throw new Error(`Plan '${plan.id}' was rejected and cannot be executed.`);
596
+ }
597
+ const ws = this.store.getWorkspace(ctx.workspace.id);
598
+ const tool = await this.inspectTool(plan.toolSlug);
599
+ const execDecisionRecord = this.governance.evaluateExecution({
600
+ workspace: ws,
601
+ actorId: ctx.actorId,
602
+ plan,
603
+ tool,
604
+ });
605
+ if (execDecisionRecord.verdict === "deny") {
606
+ throw new Error(`Microsoft Agent Governance denied execution of plan '${plan.id}': ${execDecisionRecord.reason}`);
607
+ }
608
+ let activeConnId = null;
609
+ if (plan.lane === "composio_sdk" && tool.requiresAuth) {
610
+ let connections = this.store.listConnections(ctx.workspace.id);
611
+ let activeConn = connections.find((c) => c.lane === "composio_sdk" &&
612
+ c.providerSlug === tool.providerSlug &&
613
+ c.status === "active");
614
+ if (!activeConn) {
615
+ await this.waitForConnection(ctx, {
616
+ provider: tool.providerSlug,
617
+ timeoutSeconds: 0,
618
+ }).catch(() => { });
619
+ connections = this.store.listConnections(ctx.workspace.id);
620
+ activeConn = connections.find((c) => c.lane === "composio_sdk" &&
621
+ c.providerSlug === tool.providerSlug &&
622
+ c.status === "active");
623
+ }
624
+ if (!activeConn) {
625
+ throw new Error(`No active OAuth connection for ${tool.providerSlug}. Complete OAuth handoff and call wait_for_connection({ provider: "${tool.providerSlug}" }) before executing plan '${plan.id}'.`);
626
+ }
627
+ activeConnId = activeConn.externalAccountId;
628
+ }
629
+ const run = this.store.createRun(plan, ctx.actorId);
630
+ const startedMs = Date.now();
631
+ try {
632
+ let output;
633
+ if (plan.toolSlug.startsWith("billing.")) {
634
+ output = await this.stripeBilling.executeTool({
635
+ workspace: ws,
636
+ customerEmail: ctx.user.email,
637
+ toolSlug: plan.toolSlug,
638
+ input: plan.input,
639
+ });
640
+ }
641
+ else if (plan.lane === "composio_instant") {
642
+ output = await this.composioInstant.executeTool({
643
+ workspaceId: ctx.workspace.id,
644
+ tool,
645
+ input: plan.input,
646
+ });
647
+ }
648
+ else if (plan.lane === "composio_sdk") {
649
+ output = await this.composioSdk.executeTool({
650
+ workspaceId: ctx.workspace.id,
651
+ tool,
652
+ input: plan.input,
653
+ connectedAccountId: activeConnId,
654
+ });
655
+ }
656
+ else if (plan.lane === "stripe_projects") {
657
+ const projResult = await this.stripeProjects.executeTool({
658
+ workspaceId: ctx.workspace.id,
659
+ tool,
660
+ input: plan.input,
661
+ });
662
+ output = projResult.output;
663
+ if (projResult.provisionedResource) {
664
+ this.store.upsertResource({
665
+ workspaceId: ctx.workspace.id,
666
+ ...projResult.provisionedResource,
667
+ });
668
+ }
669
+ }
670
+ else {
671
+ throw new Error(`Unsupported execution lane: ${plan.lane}`);
672
+ }
673
+ const durationMs = Date.now() - startedMs;
674
+ const finalized = this.store.finalizeRun({
675
+ workspaceId: ctx.workspace.id,
676
+ runId: run.id,
677
+ status: "succeeded",
678
+ output,
679
+ actionsMetered: 1,
680
+ creditsMetered: plan.creditCost,
681
+ durationMs,
682
+ decisionRecord: execDecisionRecord,
683
+ });
684
+ // Record secret-redacted post-run memory in Supermemory for stateful actions
685
+ if (plan.riskLevel !== "read") {
686
+ const summary = `Executed ${plan.toolSlug} (${plan.lane}, risk=${plan.riskLevel}) for reason "${plan.reason}" -> status=succeeded (receipt=${finalized.receipt.id}).`;
687
+ this.supermemory
688
+ .recordExecutionMemory({
689
+ workspaceId: ctx.workspace.id,
690
+ toolSlug: plan.toolSlug,
691
+ lane: plan.lane,
692
+ riskLevel: plan.riskLevel,
693
+ reason: plan.reason,
694
+ status: "succeeded",
695
+ summary,
696
+ })
697
+ .then((docId) => {
698
+ if (docId) {
699
+ this.store.saveMemoryRecord({
700
+ workspaceId: ctx.workspace.id,
701
+ namespace: this.supermemory.getWorkspaceNamespace(ctx.workspace.id),
702
+ documentId: docId,
703
+ title: `Execution: ${plan.toolSlug} (succeeded)`,
704
+ content: this.supermemory.sanitizeContent(summary),
705
+ kind: "execution_outcome",
706
+ metadata: {
707
+ runId: finalized.run.id,
708
+ receiptId: finalized.receipt.id,
709
+ toolSlug: plan.toolSlug,
710
+ },
711
+ });
712
+ }
713
+ })
714
+ .catch(() => { });
715
+ }
716
+ return finalized;
717
+ }
718
+ catch (err) {
719
+ const durationMs = Date.now() - startedMs;
720
+ const errorMessage = String(err?.message || err || "Execution failed");
721
+ return this.store.finalizeRun({
722
+ workspaceId: ctx.workspace.id,
723
+ runId: run.id,
724
+ status: "failed",
725
+ output: { error: errorMessage },
726
+ error: errorMessage,
727
+ actionsMetered: 1,
728
+ creditsMetered: 0,
729
+ durationMs,
730
+ decisionRecord: execDecisionRecord,
731
+ });
732
+ }
733
+ }
734
+ // 16. get_run
735
+ getRun(ctx, runId) {
736
+ const run = this.store.getRun(ctx.workspace.id, runId);
737
+ if (!run)
738
+ throw new Error(`Run '${runId}' not found in workspace.`);
739
+ return run;
740
+ }
741
+ // 17. cancel_run
742
+ cancelRun(ctx, runId) {
743
+ const run = this.getRun(ctx, runId);
744
+ if (run.status === "succeeded" || run.status === "failed" || run.status === "cancelled") {
745
+ return {
746
+ run,
747
+ receipt: this.store.getReceipt(ctx.workspace.id, run.id),
748
+ };
749
+ }
750
+ const finalized = this.store.finalizeRun({
751
+ workspaceId: ctx.workspace.id,
752
+ runId: run.id,
753
+ status: "cancelled",
754
+ output: { cancelledBy: ctx.actorId },
755
+ error: "Cancelled by operator",
756
+ actionsMetered: 0,
757
+ creditsMetered: 0,
758
+ durationMs: Date.now() - new Date(run.startedAt).getTime(),
759
+ });
760
+ return finalized;
761
+ }
762
+ // 18. get_receipt
763
+ getReceipt(ctx, receiptOrRunId) {
764
+ const receipt = this.store.getReceipt(ctx.workspace.id, receiptOrRunId);
765
+ if (!receipt) {
766
+ throw new Error(`Receipt '${receiptOrRunId}' not found in workspace.`);
767
+ }
768
+ const signatureValid = this.store.verifyReceipt(receipt);
769
+ const governanceSignatureValid = receipt.decisionRecord
770
+ ? this.governance.verifyDecisionRecord(receipt.decisionRecord)
771
+ : true;
772
+ return { receipt, signatureValid, governanceSignatureValid };
773
+ }
774
+ // 19. Natural Language Router & End-to-End Executor (`muxo do` / `POST /api/v1/do`)
775
+ async doNaturalLanguage(ctx, params) {
776
+ const allTools = await this.listAllCatalogTools();
777
+ const byokEnv = this.store.getDecryptedWorkspaceEnv(ctx.workspace.id);
778
+ const activeConns = new Set(this.store
779
+ .listConnections(ctx.workspace.id)
780
+ .filter((c) => c.status === "active")
781
+ .map((c) => c.providerSlug.toLowerCase()));
782
+ const resolution = await resolveNaturalLanguageIntent({
783
+ prompt: params.prompt,
784
+ tools: allTools,
785
+ explicitInput: params.input,
786
+ byokKeys: byokEnv,
787
+ activeConnectionProviders: activeConns,
788
+ });
789
+ if (!resolution.resolved || !resolution.tool) {
790
+ return {
791
+ ok: false,
792
+ executed: false,
793
+ status: "unresolved",
794
+ intent: resolution,
795
+ resolution,
796
+ byokPrompt: {
797
+ needed: !byokEnv.OPENAI_API_KEY && !byokEnv.ANTHROPIC_API_KEY && !byokEnv.OPENROUTER_API_KEY,
798
+ provider: "openai",
799
+ envVarName: "OPENAI_API_KEY",
800
+ cliCommand: "muxo byok set openai <sk-...>",
801
+ message: "Tip: Add an OpenAI, Anthropic, or OpenRouter BYOK key (`muxo byok set openai <key>`) for unrestricted natural-language LLM routing.",
802
+ },
803
+ humanMessage: resolution.humanSummary,
804
+ };
805
+ }
806
+ if (resolution.missingInputs.length > 0) {
807
+ return {
808
+ ok: false,
809
+ executed: false,
810
+ status: "missing_inputs",
811
+ intent: resolution,
812
+ resolution,
813
+ humanMessage: `Matched ${resolution.tool.name} (${resolution.tool.slug}), but missing required parameter(s): ${resolution.missingInputs.join(", ")}. Please include them in your request.`,
814
+ };
815
+ }
816
+ const planned = await this.planAction(ctx, {
817
+ toolSlug: resolution.tool.slug,
818
+ input: resolution.input,
819
+ reason: params.prompt,
820
+ });
821
+ if (planned.authHandoff?.required) {
822
+ return {
823
+ ok: false,
824
+ executed: false,
825
+ status: "awaiting_oauth_connection",
826
+ intent: resolution,
827
+ resolution,
828
+ plan: planned.plan,
829
+ authHandoff: planned.authHandoff,
830
+ humanMessage: planned.authHandoff.instructions,
831
+ };
832
+ }
833
+ if (params.dryRun || params.planOnly) {
834
+ return {
835
+ ok: true,
836
+ executed: false,
837
+ status: "planned_dry_run",
838
+ intent: resolution,
839
+ resolution,
840
+ plan: planned.plan,
841
+ humanMessage: `Planned ${planned.tool.name} (${planned.plan.id}) with risk=${planned.plan.riskLevel} and cost=${planned.plan.creditCost} credits.`,
842
+ };
843
+ }
844
+ let currentPlan = planned.plan;
845
+ if (currentPlan.approvalStatus === "pending_approval" &&
846
+ params.autoApprove !== false) {
847
+ currentPlan = this.approvePlan(ctx, currentPlan.id, "approved");
848
+ }
849
+ if (currentPlan.approvalStatus === "pending_approval") {
850
+ return {
851
+ ok: true,
852
+ executed: false,
853
+ status: "awaiting_approval",
854
+ intent: resolution,
855
+ resolution,
856
+ plan: currentPlan,
857
+ humanMessage: `Plan ${currentPlan.id} (${currentPlan.toolSlug}, risk=${currentPlan.riskLevel}) requires owner approval. Run 'muxo approve ${currentPlan.id}' or pass --yes to auto-approve.`,
858
+ };
859
+ }
860
+ const executed = await this.executePlanForRisk(ctx, currentPlan.id, currentPlan.riskLevel);
861
+ const isSuccess = executed.run.status === "succeeded";
862
+ return {
863
+ ok: isSuccess,
864
+ executed: isSuccess,
865
+ status: "executed",
866
+ intent: resolution,
867
+ resolution,
868
+ plan: currentPlan,
869
+ run: executed.run,
870
+ receipt: executed.receipt,
871
+ humanMessage: isSuccess
872
+ ? `Completed ${resolution.tool.name} (${resolution.tool.slug}) in ${executed.run.durationMs ?? 0}ms [receipt: ${executed.receipt.id}, funding: ${executed.receipt.supplierSettlement?.fundingMode || "muxo_funded"}].`
873
+ : `Execution of ${resolution.tool.slug} failed: ${executed.run.error || "Unknown error"}`,
874
+ };
875
+ }
876
+ }