@muxoai/platform 0.0.0-stage → 1.2.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 (173) hide show
  1. package/ARCHITECTURE.md +111 -0
  2. package/README.md +53 -2
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +527 -0
  5. package/dist/config.d.ts +20 -0
  6. package/dist/config.js +89 -0
  7. package/dist/engine.d.ts +128 -0
  8. package/dist/engine.js +709 -0
  9. package/dist/index.d.ts +7 -0
  10. package/dist/index.js +7 -0
  11. package/dist/mcp.d.ts +9 -0
  12. package/dist/mcp.js +401 -0
  13. package/dist/providers/composio-instant.d.ts +14 -0
  14. package/dist/providers/composio-instant.js +372 -0
  15. package/dist/providers/composio-sdk.d.ts +41 -0
  16. package/dist/providers/composio-sdk.js +514 -0
  17. package/dist/providers/microsoft-governance.d.ts +66 -0
  18. package/dist/providers/microsoft-governance.js +415 -0
  19. package/dist/providers/stripe-billing.d.ts +31 -0
  20. package/dist/providers/stripe-billing.js +168 -0
  21. package/dist/providers/stripe-projects.d.ts +53 -0
  22. package/dist/providers/stripe-projects.js +607 -0
  23. package/dist/providers/supermemory.d.ts +64 -0
  24. package/dist/providers/supermemory.js +224 -0
  25. package/dist/sdk.d.ts +115 -0
  26. package/dist/sdk.js +117 -0
  27. package/dist/server.d.ts +10 -0
  28. package/dist/server.js +816 -0
  29. package/dist/store.d.ts +200 -0
  30. package/dist/store.js +1260 -0
  31. package/dist/types.d.ts +273 -0
  32. package/dist/types.js +1 -0
  33. package/dist/ui/console-html.d.ts +2 -0
  34. package/dist/ui/console-html.js +2153 -0
  35. package/package.json +74 -4
  36. package/plugins/muxo/.app.json +8 -0
  37. package/plugins/muxo/.claude-plugin/plugin.json +16 -0
  38. package/plugins/muxo/.codex-plugin/plugin.json +51 -0
  39. package/plugins/muxo/.mcp.json +8 -0
  40. package/plugins/muxo/assets/logo.png +0 -0
  41. package/plugins/muxo/assets/logo.svg +6 -0
  42. package/plugins/muxo/hooks/hooks.json +27 -0
  43. package/plugins/muxo/hooks/session-start.sh +85 -0
  44. package/plugins/muxo/hooks/user-prompt-submit.sh +45 -0
  45. package/plugins/muxo/skills/muxo/SKILL.md +25 -0
  46. package/plugins/muxo/skills/muxo/references/cli.md +57 -0
  47. package/plugins/muxo/skills/muxo/references/mcp.md +25 -0
  48. package/src/catalogues/stripe-projects-catalog.json +9832 -0
  49. package/vendor/microsoft-governance/README.md +363 -0
  50. package/vendor/microsoft-governance/dist/audit.d.ts +26 -0
  51. package/vendor/microsoft-governance/dist/audit.d.ts.map +1 -0
  52. package/vendor/microsoft-governance/dist/audit.js +107 -0
  53. package/vendor/microsoft-governance/dist/audit.js.map +1 -0
  54. package/vendor/microsoft-governance/dist/cascade-containment.d.ts +84 -0
  55. package/vendor/microsoft-governance/dist/cascade-containment.d.ts.map +1 -0
  56. package/vendor/microsoft-governance/dist/cascade-containment.js +387 -0
  57. package/vendor/microsoft-governance/dist/cascade-containment.js.map +1 -0
  58. package/vendor/microsoft-governance/dist/client.d.ts +34 -0
  59. package/vendor/microsoft-governance/dist/client.d.ts.map +1 -0
  60. package/vendor/microsoft-governance/dist/client.js +112 -0
  61. package/vendor/microsoft-governance/dist/client.js.map +1 -0
  62. package/vendor/microsoft-governance/dist/context-poisoning.d.ts +58 -0
  63. package/vendor/microsoft-governance/dist/context-poisoning.d.ts.map +1 -0
  64. package/vendor/microsoft-governance/dist/context-poisoning.js +410 -0
  65. package/vendor/microsoft-governance/dist/context-poisoning.js.map +1 -0
  66. package/vendor/microsoft-governance/dist/credential-vault.d.ts +213 -0
  67. package/vendor/microsoft-governance/dist/credential-vault.d.ts.map +1 -0
  68. package/vendor/microsoft-governance/dist/credential-vault.js +567 -0
  69. package/vendor/microsoft-governance/dist/credential-vault.js.map +1 -0
  70. package/vendor/microsoft-governance/dist/discovery.d.ts +80 -0
  71. package/vendor/microsoft-governance/dist/discovery.d.ts.map +1 -0
  72. package/vendor/microsoft-governance/dist/discovery.js +404 -0
  73. package/vendor/microsoft-governance/dist/discovery.js.map +1 -0
  74. package/vendor/microsoft-governance/dist/encryption/channel.d.ts +29 -0
  75. package/vendor/microsoft-governance/dist/encryption/channel.d.ts.map +1 -0
  76. package/vendor/microsoft-governance/dist/encryption/channel.js +78 -0
  77. package/vendor/microsoft-governance/dist/encryption/channel.js.map +1 -0
  78. package/vendor/microsoft-governance/dist/encryption/index.d.ts +9 -0
  79. package/vendor/microsoft-governance/dist/encryption/index.d.ts.map +1 -0
  80. package/vendor/microsoft-governance/dist/encryption/index.js +23 -0
  81. package/vendor/microsoft-governance/dist/encryption/index.js.map +1 -0
  82. package/vendor/microsoft-governance/dist/encryption/mesh-client.d.ts +267 -0
  83. package/vendor/microsoft-governance/dist/encryption/mesh-client.d.ts.map +1 -0
  84. package/vendor/microsoft-governance/dist/encryption/mesh-client.js +1001 -0
  85. package/vendor/microsoft-governance/dist/encryption/mesh-client.js.map +1 -0
  86. package/vendor/microsoft-governance/dist/encryption/ratchet.d.ts +38 -0
  87. package/vendor/microsoft-governance/dist/encryption/ratchet.d.ts.map +1 -0
  88. package/vendor/microsoft-governance/dist/encryption/ratchet.js +223 -0
  89. package/vendor/microsoft-governance/dist/encryption/ratchet.js.map +1 -0
  90. package/vendor/microsoft-governance/dist/encryption/registry-client.d.ts +136 -0
  91. package/vendor/microsoft-governance/dist/encryption/registry-client.d.ts.map +1 -0
  92. package/vendor/microsoft-governance/dist/encryption/registry-client.js +369 -0
  93. package/vendor/microsoft-governance/dist/encryption/registry-client.js.map +1 -0
  94. package/vendor/microsoft-governance/dist/encryption/x3dh.d.ts +80 -0
  95. package/vendor/microsoft-governance/dist/encryption/x3dh.d.ts.map +1 -0
  96. package/vendor/microsoft-governance/dist/encryption/x3dh.js +238 -0
  97. package/vendor/microsoft-governance/dist/encryption/x3dh.js.map +1 -0
  98. package/vendor/microsoft-governance/dist/framework-adapter.d.ts +63 -0
  99. package/vendor/microsoft-governance/dist/framework-adapter.d.ts.map +1 -0
  100. package/vendor/microsoft-governance/dist/framework-adapter.js +253 -0
  101. package/vendor/microsoft-governance/dist/framework-adapter.js.map +1 -0
  102. package/vendor/microsoft-governance/dist/identity.d.ts +124 -0
  103. package/vendor/microsoft-governance/dist/identity.d.ts.map +1 -0
  104. package/vendor/microsoft-governance/dist/identity.js +446 -0
  105. package/vendor/microsoft-governance/dist/identity.js.map +1 -0
  106. package/vendor/microsoft-governance/dist/index.d.ts +39 -0
  107. package/vendor/microsoft-governance/dist/index.d.ts.map +1 -0
  108. package/vendor/microsoft-governance/dist/index.js +95 -0
  109. package/vendor/microsoft-governance/dist/index.js.map +1 -0
  110. package/vendor/microsoft-governance/dist/kill-switch.d.ts +22 -0
  111. package/vendor/microsoft-governance/dist/kill-switch.d.ts.map +1 -0
  112. package/vendor/microsoft-governance/dist/kill-switch.js +60 -0
  113. package/vendor/microsoft-governance/dist/kill-switch.js.map +1 -0
  114. package/vendor/microsoft-governance/dist/lifecycle.d.ts +50 -0
  115. package/vendor/microsoft-governance/dist/lifecycle.d.ts.map +1 -0
  116. package/vendor/microsoft-governance/dist/lifecycle.js +113 -0
  117. package/vendor/microsoft-governance/dist/lifecycle.js.map +1 -0
  118. package/vendor/microsoft-governance/dist/mcp.d.ts +41 -0
  119. package/vendor/microsoft-governance/dist/mcp.d.ts.map +1 -0
  120. package/vendor/microsoft-governance/dist/mcp.js +233 -0
  121. package/vendor/microsoft-governance/dist/mcp.js.map +1 -0
  122. package/vendor/microsoft-governance/dist/metrics.d.ts +123 -0
  123. package/vendor/microsoft-governance/dist/metrics.d.ts.map +1 -0
  124. package/vendor/microsoft-governance/dist/metrics.js +289 -0
  125. package/vendor/microsoft-governance/dist/metrics.js.map +1 -0
  126. package/vendor/microsoft-governance/dist/oci-manifest.d.ts +49 -0
  127. package/vendor/microsoft-governance/dist/oci-manifest.d.ts.map +1 -0
  128. package/vendor/microsoft-governance/dist/oci-manifest.js +182 -0
  129. package/vendor/microsoft-governance/dist/oci-manifest.js.map +1 -0
  130. package/vendor/microsoft-governance/dist/policy-backends/cedar.d.ts +15 -0
  131. package/vendor/microsoft-governance/dist/policy-backends/cedar.d.ts.map +1 -0
  132. package/vendor/microsoft-governance/dist/policy-backends/cedar.js +88 -0
  133. package/vendor/microsoft-governance/dist/policy-backends/cedar.js.map +1 -0
  134. package/vendor/microsoft-governance/dist/policy-backends/opa.d.ts +17 -0
  135. package/vendor/microsoft-governance/dist/policy-backends/opa.d.ts.map +1 -0
  136. package/vendor/microsoft-governance/dist/policy-backends/opa.js +74 -0
  137. package/vendor/microsoft-governance/dist/policy-backends/opa.js.map +1 -0
  138. package/vendor/microsoft-governance/dist/policy.d.ts +77 -0
  139. package/vendor/microsoft-governance/dist/policy.d.ts.map +1 -0
  140. package/vendor/microsoft-governance/dist/policy.js +760 -0
  141. package/vendor/microsoft-governance/dist/policy.js.map +1 -0
  142. package/vendor/microsoft-governance/dist/prompt-defense.d.ts +37 -0
  143. package/vendor/microsoft-governance/dist/prompt-defense.d.ts.map +1 -0
  144. package/vendor/microsoft-governance/dist/prompt-defense.js +229 -0
  145. package/vendor/microsoft-governance/dist/prompt-defense.js.map +1 -0
  146. package/vendor/microsoft-governance/dist/protocol-facets.d.ts +87 -0
  147. package/vendor/microsoft-governance/dist/protocol-facets.d.ts.map +1 -0
  148. package/vendor/microsoft-governance/dist/protocol-facets.js +728 -0
  149. package/vendor/microsoft-governance/dist/protocol-facets.js.map +1 -0
  150. package/vendor/microsoft-governance/dist/rings.d.ts +17 -0
  151. package/vendor/microsoft-governance/dist/rings.d.ts.map +1 -0
  152. package/vendor/microsoft-governance/dist/rings.js +61 -0
  153. package/vendor/microsoft-governance/dist/rings.js.map +1 -0
  154. package/vendor/microsoft-governance/dist/sandbox.d.ts +61 -0
  155. package/vendor/microsoft-governance/dist/sandbox.d.ts.map +1 -0
  156. package/vendor/microsoft-governance/dist/sandbox.js +199 -0
  157. package/vendor/microsoft-governance/dist/sandbox.js.map +1 -0
  158. package/vendor/microsoft-governance/dist/surface-parity.d.ts +45 -0
  159. package/vendor/microsoft-governance/dist/surface-parity.d.ts.map +1 -0
  160. package/vendor/microsoft-governance/dist/surface-parity.js +216 -0
  161. package/vendor/microsoft-governance/dist/surface-parity.js.map +1 -0
  162. package/vendor/microsoft-governance/dist/trust.d.ts +28 -0
  163. package/vendor/microsoft-governance/dist/trust.d.ts.map +1 -0
  164. package/vendor/microsoft-governance/dist/trust.js +209 -0
  165. package/vendor/microsoft-governance/dist/trust.js.map +1 -0
  166. package/vendor/microsoft-governance/dist/types.d.ts +422 -0
  167. package/vendor/microsoft-governance/dist/types.d.ts.map +1 -0
  168. package/vendor/microsoft-governance/dist/types.js +29 -0
  169. package/vendor/microsoft-governance/dist/types.js.map +1 -0
  170. package/vendor/microsoft-governance/dist/verify.d.ts +135 -0
  171. package/vendor/microsoft-governance/dist/verify.d.ts.map +1 -0
  172. package/vendor/microsoft-governance/dist/verify.js +356 -0
  173. package/vendor/microsoft-governance/dist/verify.js.map +1 -0
package/dist/server.js ADDED
@@ -0,0 +1,816 @@
1
+ import fs from "node:fs";
2
+ import http from "node:http";
3
+ import path from "node:path";
4
+ import { getConfig, ROOT_DIR } from "./config.js";
5
+ import { MuxoEngine } from "./engine.js";
6
+ import { handleJsonRpcMcpRequest, MUXO_MCP_TOOLS } from "./mcp.js";
7
+ import { MuxoStore } from "./store.js";
8
+ import { renderConsoleHtml, renderLandingHtml } from "./ui/console-html.js";
9
+ function renderSkillMarkdown(baseUrl) {
10
+ return `---
11
+ name: muxo
12
+ description: Discover, plan, and execute governed actions across Connected Apps (Composio SDK), Instant Tools (Composio Instant), Cloud Infrastructure (Stripe Projects), Contextual Memory (Supermemory v5), and Cryptographic Governance (Microsoft Agent Governance Toolkit) through Muxo.
13
+ ---
14
+
15
+ # Muxo — Unified Agent Execution, Infrastructure, Memory & Governance Platform
16
+
17
+ Muxo provides one governed interface over 4 pillars so agents and customers only ever interact with Muxo:
18
+
19
+ 1. **Instant Tools (\`instant.*\`)**: Zero-OAuth tools powered by Composio Instant (\`instant.web.search\`, \`instant.web.scrape\`, \`instant.hackernews.top_stories\`, \`instant.github.repo_intel\`, \`instant.dns.lookup\`).
20
+ 2. **Connected Apps (\`app.*\`)**: Managed OAuth SaaS integrations powered by Composio SDK (\`app.github.*\`, \`app.gmail.*\`, \`app.slack.*\`, \`app.notion.*\`, \`app.linear.*\`, etc.).
21
+ 3. **Cloud Infrastructure (\`resource.*\`)**: Database, cache, storage, and hosting provisioning powered by Stripe Projects (\`resource.neon.*\`, \`resource.supabase.*\`, \`resource.turso.*\`, \`resource.cloudflare.*\`, \`resource.vercel.*\`, etc.) with AES-256-GCM secret custody in Muxo Vault.
22
+ 4. **Supermemory v5 Brain & Microsoft Agent Governance**: Every \`plan_action\` recalls isolated workspace context (\`/ns/muxo-v5-<hash>\`) and runs \`Agent ──► McpSecurityScanner ──► PolicyEngine ──► AgentIdentity (Ed25519 DID) ──► AuditLogger ──► DecisionRecord\`.
23
+
24
+ ## Installable Muxo Plugin (OpenAI Codex, ChatGPT, Claude Code & Factory Droid)
25
+
26
+ \`\`\`bash
27
+ # Install Muxo CLI & sign in (or auto-provision an isolated external workspace)
28
+ npm install -g muxo-platform
29
+ muxo login --signup --name "my-agent"
30
+
31
+ # Link OAuth apps with live browser handoff + polling recovery
32
+ muxo link github --wait
33
+
34
+ # Plugin manifests served by this instance:
35
+ # - ${baseUrl}/.agents/plugins/marketplace.json (OpenAI Codex / ChatGPT)
36
+ # - ${baseUrl}/.claude-plugin/marketplace.json (Claude Code / Factory Droid)
37
+ # - ${baseUrl}/api/v1/plugin
38
+ \`\`\`
39
+
40
+ ## Autonomous Agent 2-Call Signup (Zero Browser Required)
41
+
42
+ \`\`\`bash
43
+ # 1. Create an autonomous workspace + mk_live_* API key
44
+ curl -sX POST ${baseUrl}/api/v1/agents/signup \\
45
+ -H "Content-Type: application/json" \\
46
+ -d '{"agentName":"MyAgent","harness":"claude-code"}'
47
+
48
+ # 2. (Optional) Generate a human owner claim link
49
+ curl -sX POST ${baseUrl}/api/v1/agents/claim \\
50
+ -H "Authorization: Bearer <mk_live_key>" \\
51
+ -H "Content-Type: application/json" \\
52
+ -d '{"email":"founder@company.com"}'
53
+ \`\`\`
54
+
55
+ ## Endpoint & Authentication
56
+
57
+ - **MCP Endpoint (Streamable HTTP)**: \`${baseUrl}/mcp\`
58
+ - **OAuth Callback Handoff**: \`${baseUrl}/oauth/callback\`
59
+ - **REST API Base**: \`${baseUrl}/api/v1\`
60
+ - **Marketing & Provider Canvas (muxo.ai)**: \`${baseUrl}/landing\`
61
+ - **Documentation (docs.muxo.ai)**: \`https://docs.muxo.ai\`
62
+ - **Authorization Header**: \`Authorization: Bearer mk_live_<your_key>\`
63
+
64
+ ## 19 Canonical MCP Operations
65
+
66
+ ${MUXO_MCP_TOOLS.map((t, i) => `${i + 1}. \`${t.name}\` — ${t.description}`).join("\n")}
67
+
68
+ ## Standard Execution & OAuth Handoff Workflow
69
+
70
+ 1. **Discover**: Call \`search_tools\` with a keyword or lane filter.
71
+ 2. **Inspect**: Call \`inspect_tool\` to read the tool's \`inputSchema\`, \`riskLevel\`, and \`creditCost\`.
72
+ 3. **Plan**: Call \`plan_action({ tool_slug, input, reason })\` to receive a \`plan_*\` ID.
73
+ - If the tool is an unconnected \`app.<provider>.*\` action, \`plan_action\` automatically attaches \`authHandoff.redirectUrl\`. Show that URL to the user, then call \`wait_for_connection({ provider })\` until \`status === "active"\`.
74
+ 4. **Execute**: Call the matching risk lane tool (\`execute_read\`, \`execute_write\`, \`execute_admin\`, \`execute_financial\`, \`execute_provisioning\`, or \`execute_destructive\`) with \`{ plan_id }\`.
75
+ 5. **Verify Receipt**: Every run issues an HMAC-SHA256 chained cryptographic receipt (\`rcpt_*\`) verifiable via \`get_receipt\`.
76
+ `;
77
+ }
78
+ async function readBody(req) {
79
+ const chunks = [];
80
+ for await (const chunk of req) {
81
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
82
+ }
83
+ return Buffer.concat(chunks).toString("utf8");
84
+ }
85
+ function sendJson(res, status, payload) {
86
+ const body = JSON.stringify(payload, null, 2);
87
+ res.writeHead(status, {
88
+ "Content-Type": "application/json; charset=utf-8",
89
+ "Access-Control-Allow-Origin": "*",
90
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
91
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
92
+ });
93
+ res.end(body);
94
+ }
95
+ export function createMuxoServer(customConfig) {
96
+ const config = { ...getConfig(), ...customConfig };
97
+ const store = new MuxoStore(config.dbPath, config.vaultMasterKey);
98
+ const engine = new MuxoEngine(config, store);
99
+ const bootstrap = store.ensureDefaultWorkspace();
100
+ const resolveContext = (req) => {
101
+ const authHeader = String(req.headers.authorization || "").trim();
102
+ if (authHeader.toLowerCase().startsWith("bearer ")) {
103
+ const token = authHeader.slice(7).trim();
104
+ const resolved = store.resolveAuthToken(token);
105
+ if (resolved)
106
+ return resolved;
107
+ }
108
+ // Default local console session fallback to the primary workspace
109
+ const ws = store.getWorkspace(bootstrap.workspace.id);
110
+ const user = store.getUser(ws.ownerUserId);
111
+ return {
112
+ user,
113
+ workspace: ws,
114
+ actorId: user.id,
115
+ authType: "session",
116
+ };
117
+ };
118
+ const server = http.createServer(async (req, res) => {
119
+ if (req.method === "OPTIONS") {
120
+ res.writeHead(204, {
121
+ "Access-Control-Allow-Origin": "*",
122
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
123
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
124
+ });
125
+ res.end();
126
+ return;
127
+ }
128
+ const url = new URL(req.url || "/", config.baseUrl);
129
+ const pathname = url.pathname;
130
+ try {
131
+ // Public Discovery & Health Endpoints
132
+ if (pathname === "/health" && req.method === "GET") {
133
+ sendJson(res, 200, {
134
+ ok: true,
135
+ status: "ready",
136
+ service: "muxo-platform",
137
+ version: "1.2.0",
138
+ environment: "production",
139
+ live_execution: true,
140
+ customer_billing: true,
141
+ supplier_spending: true,
142
+ fundingMode: "muxo_funded",
143
+ lanes: {
144
+ composio_sdk: Boolean(config.composioApiKey),
145
+ composio_instant: true,
146
+ stripe_projects: true,
147
+ stripe_billing: Boolean(config.stripeSecretKey),
148
+ supermemory_v5: engine.supermemory.isEnabled(),
149
+ microsoft_governance: true,
150
+ },
151
+ billing: {
152
+ subscriptions: "configured",
153
+ prepaid: "configured",
154
+ resources: "configured",
155
+ merchantOfRecord: "muxo_pays_suppliers",
156
+ },
157
+ surfaces: {
158
+ consoleUrl: `${config.baseUrl}/`,
159
+ landingUrl: `${config.baseUrl}/landing`,
160
+ publicWebUrl: config.publicWebUrl,
161
+ docsUrl: config.docsUrl,
162
+ },
163
+ mcpToolsCount: MUXO_MCP_TOOLS.length,
164
+ });
165
+ return;
166
+ }
167
+ if ((pathname === "/.well-known/oauth-protected-resource" ||
168
+ pathname === "/.well-known/oauth-protected-resource/mcp") &&
169
+ req.method === "GET") {
170
+ const requestOrigin = req.headers.host
171
+ ? `http://${req.headers.host}`
172
+ : config.baseUrl;
173
+ const resource = pathname === "/.well-known/oauth-protected-resource/mcp"
174
+ ? `${requestOrigin}/mcp`
175
+ : requestOrigin;
176
+ sendJson(res, 200, {
177
+ resource,
178
+ authorization_servers: [requestOrigin],
179
+ bearer_methods_supported: ["header"],
180
+ scopes_supported: ["muxo:mcp", "muxo:read", "muxo:execute", "muxo:provision"],
181
+ resource_documentation: `${config.docsUrl}/quickstart`,
182
+ mcp_endpoint: `${requestOrigin}/mcp`,
183
+ });
184
+ return;
185
+ }
186
+ if ((pathname === "/api/openapi.json" || pathname === "/openapi.json") &&
187
+ req.method === "GET") {
188
+ sendJson(res, 200, {
189
+ openapi: "3.1.0",
190
+ info: {
191
+ title: "Muxo Unified Agent Execution, Infrastructure, Memory & Governance API",
192
+ version: "1.2.0",
193
+ description: "One governed boundary over Connected Apps (Composio SDK), Instant Tools (Composio Instant), Cloud Infrastructure (Stripe Projects), Supermemory v5 Brain, and Microsoft Agent Governance Toolkit.",
194
+ },
195
+ servers: [{ url: config.baseUrl }],
196
+ paths: {
197
+ "/health": { get: { summary: "Platform health & 4-pillar readiness" } },
198
+ "/mcp": { post: { summary: "Streamable HTTP MCP JSON-RPC 2.0 endpoint (19 tools)" } },
199
+ "/skill.md": { get: { summary: "Canonical agent skill & onboarding markdown" } },
200
+ "/api/v1/agents/signup": { post: { summary: "Autonomous 2-call agent workspace & mk_live_* key signup" } },
201
+ "/api/v1/agents/claim": { post: { summary: "Generate human owner claim link for an agent workspace" } },
202
+ "/api/v1/tools": { get: { summary: "Search unified catalogue across instant.*, app.*, and resource.*" } },
203
+ "/api/v1/tools/{slug}": { get: { summary: "Inspect tool schema, risk level, credit cost, and LLM context URL" } },
204
+ "/api/v1/connections": {
205
+ get: { summary: "List connected OAuth accounts and cloud providers" },
206
+ post: { summary: "Start managed OAuth connection handoff" },
207
+ },
208
+ "/api/v1/connections/wait": { post: { summary: "Wait/poll for browser OAuth handoff completion" } },
209
+ "/api/v1/plans": {
210
+ get: { summary: "List governed action plans" },
211
+ post: { summary: "Create governed action plan with Supermemory recall & Ed25519 signature" },
212
+ },
213
+ "/api/v1/plans/{planId}/approve": { post: { summary: "Approve a pending high-risk action plan" } },
214
+ "/api/v1/plans/{planId}/execute": { post: { summary: "Execute an approved plan and issue HMAC-SHA256 receipt" } },
215
+ "/api/v1/resources": { get: { summary: "List provisioned cloud infrastructure resources" } },
216
+ "/api/v1/resources/env": { get: { summary: "Pull decrypted AES-256-GCM workspace environment secrets" } },
217
+ "/api/v1/memory": {
218
+ get: { summary: "Recall isolated Supermemory v5 workspace brain facts" },
219
+ post: { summary: "Store a workspace memory fact or decision" },
220
+ },
221
+ "/api/v1/governance": { get: { summary: "Inspect Microsoft Agent Governance DID, policy, and Merkle audit chain" } },
222
+ "/api/v1/billing/topup": { post: { summary: "Purchase Muxo credits (User pays Muxo -> Muxo pays suppliers)" } },
223
+ "/api/v1/billing/settlements": { get: { summary: "Inspect Merchant-of-Record supplier settlement ledger" } },
224
+ },
225
+ });
226
+ return;
227
+ }
228
+ if (pathname === "/auth.md" && req.method === "GET") {
229
+ res.writeHead(200, { "Content-Type": "text/markdown; charset=utf-8" });
230
+ res.end(`# Muxo Authentication & OAuth Handoff Guide
231
+
232
+ ## 1. CLI & Autonomous Agent Signup
233
+ \`\`\`bash
234
+ muxo login --signup --name "my-agent"
235
+ \`\`\`
236
+ Or via HTTP:
237
+ \`\`\`bash
238
+ curl -sX POST ${config.baseUrl}/api/v1/agents/signup -H "Content-Type: application/json" -d '{"agentName":"my-agent"}'
239
+ \`\`\`
240
+
241
+ ## 2. OAuth Connection Handoff (Composio Plugin Pattern)
242
+ When \`plan_action\` targets an unconnected \`app.<provider>.*\` tool, Muxo returns \`authHandoff.redirectUrl\`.
243
+ Open the URL in a browser, complete OAuth (which redirects to \`${config.baseUrl}/oauth/callback\`), and call \`wait_for_connection({ provider })\` or \`muxo link <provider> --wait\`.
244
+
245
+ ## 3. Merchant-of-Record Credit Settlement
246
+ Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing topup 1000\`), and Muxo settles wholesale supplier costs across Composio and Stripe Projects from Muxo's master accounts (\`fundingMode: "muxo_funded"\`).
247
+ `);
248
+ return;
249
+ }
250
+ if (pathname === "/api/setup" && req.method === "GET") {
251
+ sendJson(res, 200, {
252
+ ok: true,
253
+ status: "ready",
254
+ mcpToolsCount: MUXO_MCP_TOOLS.length,
255
+ mcpEndpoint: `${config.baseUrl}/mcp`,
256
+ skillUrl: `${config.baseUrl}/skill.md`,
257
+ openApiUrl: `${config.baseUrl}/api/openapi.json`,
258
+ oauthCallbackUrl: `${config.baseUrl}/oauth/callback`,
259
+ plugins: {
260
+ openaiCodex: `${config.baseUrl}/.agents/plugins/marketplace.json`,
261
+ claudeDroid: `${config.baseUrl}/.claude-plugin/marketplace.json`,
262
+ },
263
+ });
264
+ return;
265
+ }
266
+ if ((pathname === "/skill.md" || pathname === "/skills.md") && req.method === "GET") {
267
+ res.writeHead(200, { "Content-Type": "text/markdown; charset=utf-8" });
268
+ res.end(renderSkillMarkdown(config.baseUrl));
269
+ return;
270
+ }
271
+ if (pathname === "/llms.txt" && req.method === "GET") {
272
+ res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
273
+ res.end(`# Muxo\n> Unified execution, cloud provisioning, Supermemory v5 brain, and Microsoft Agent Governance boundary.\n\n- Skill Document: ${config.baseUrl}/skill.md\n- Auth Guide: ${config.baseUrl}/auth.md\n- OpenAPI 3.1 Spec: ${config.baseUrl}/api/openapi.json\n- MCP Endpoint: ${config.baseUrl}/mcp\n- OAuth Callback Handoff: ${config.baseUrl}/oauth/callback\n- Plugin Marketplace (Codex/OpenAI): ${config.baseUrl}/.agents/plugins/marketplace.json\n- Plugin Marketplace (Claude/Droid): ${config.baseUrl}/.claude-plugin/marketplace.json\n- Console (app.muxo.ai): ${config.baseUrl}/\n- Landing & Provider Canvas (muxo.ai): ${config.baseUrl}/landing\n- Documentation (docs.muxo.ai): ${config.docsUrl}\n`);
274
+ return;
275
+ }
276
+ // Serve Installable Muxo Plugin Manifests & Metadata
277
+ const pluginJsonRoutes = {
278
+ "/.agents/plugins/marketplace.json": path.join(ROOT_DIR, ".agents", "plugins", "marketplace.json"),
279
+ "/.claude-plugin/marketplace.json": path.join(ROOT_DIR, ".claude-plugin", "marketplace.json"),
280
+ "/plugins/muxo/.codex-plugin/plugin.json": path.join(ROOT_DIR, "plugins", "muxo", ".codex-plugin", "plugin.json"),
281
+ "/plugins/muxo/.claude-plugin/plugin.json": path.join(ROOT_DIR, "plugins", "muxo", ".claude-plugin", "plugin.json"),
282
+ "/plugins/muxo/.app.json": path.join(ROOT_DIR, "plugins", "muxo", ".app.json"),
283
+ "/plugins/muxo/.mcp.json": path.join(ROOT_DIR, "plugins", "muxo", ".mcp.json"),
284
+ };
285
+ if (pluginJsonRoutes[pathname] && req.method === "GET") {
286
+ const targetFile = pluginJsonRoutes[pathname];
287
+ if (fs.existsSync(targetFile)) {
288
+ sendJson(res, 200, JSON.parse(fs.readFileSync(targetFile, "utf8")));
289
+ return;
290
+ }
291
+ }
292
+ if (pathname === "/api/v1/plugin" && req.method === "GET") {
293
+ const codexManifest = JSON.parse(fs.readFileSync(path.join(ROOT_DIR, "plugins", "muxo", ".codex-plugin", "plugin.json"), "utf8"));
294
+ sendJson(res, 200, {
295
+ ok: true,
296
+ plugin: codexManifest,
297
+ marketplaces: {
298
+ openaiCodex: `${config.baseUrl}/.agents/plugins/marketplace.json`,
299
+ claudeDroid: `${config.baseUrl}/.claude-plugin/marketplace.json`,
300
+ },
301
+ installCommands: {
302
+ codex: "codex plugin add muxo@muxo",
303
+ cliSignup: "muxo login --signup --name my-agent",
304
+ oauthHandoff: "muxo link github --wait",
305
+ },
306
+ });
307
+ return;
308
+ }
309
+ // Web Console UI (app.muxo.ai)
310
+ if ((pathname === "/" || pathname === "/console") && req.method === "GET") {
311
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
312
+ res.end(renderConsoleHtml());
313
+ return;
314
+ }
315
+ // Built-in Interactive Landing & Provider Canvas (muxo.ai)
316
+ if (pathname === "/landing" && req.method === "GET") {
317
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
318
+ res.end(renderLandingHtml());
319
+ return;
320
+ }
321
+ // Autonomous Agent Claim Redemption Route
322
+ if (pathname.startsWith("/claim/") && req.method === "GET") {
323
+ const claimSlug = decodeURIComponent(pathname.slice("/claim/".length));
324
+ const redeemed = store.redeemAgentClaim(claimSlug);
325
+ if (!redeemed) {
326
+ sendJson(res, 404, { ok: false, error: "Invalid or expired agent claim link" });
327
+ return;
328
+ }
329
+ const wantsHtml = url.searchParams.get("format") !== "json" &&
330
+ String(req.headers.accept || "").includes("text/html");
331
+ if (wantsHtml) {
332
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
333
+ res.end(`<!DOCTYPE html>
334
+ <html lang="en">
335
+ <head>
336
+ <meta charset="utf-8" />
337
+ <title>Muxo Agent Workspace Claimed</title>
338
+ <style>
339
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #090a0f; color: #f4f4f6; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
340
+ .card { background: #12141f; border: 1px solid #26293d; border-radius: 14px; padding: 32px; max-width: 480px; text-align: center; box-shadow: 0 20px 50px rgba(0,0,0,0.45); }
341
+ .badge { display: inline-block; background: rgba(45,212,191,0.15); color: #2dd4bf; border: 1px solid rgba(45,212,191,0.35); border-radius: 999px; padding: 4px 12px; font-size: 12px; font-weight: 600; margin-bottom: 16px; }
342
+ h1 { font-size: 22px; margin: 0 0 10px; }
343
+ p { color: #a1a7bb; font-size: 14px; line-height: 1.5; margin: 0 0 20px; }
344
+ code { background: #1c1f30; padding: 3px 7px; border-radius: 6px; color: #e2e8f0; font-size: 12px; }
345
+ .btn { display: inline-block; background: #ff5a1f; color: #fff; text-decoration: none; padding: 10px 18px; border-radius: 8px; font-size: 14px; font-weight: 600; }
346
+ </style>
347
+ </head>
348
+ <body>
349
+ <div class="card">
350
+ <div class="badge">Ownership Bound</div>
351
+ <h1>Workspace Claimed</h1>
352
+ <p>Workspace <code>${redeemed.workspace.name}</code> (${redeemed.workspace.id}) claimed by <strong>${redeemed.targetEmail}</strong>.</p>
353
+ <a class="btn" href="/?claimed=${encodeURIComponent(redeemed.workspace.slug)}">Open Muxo Console →</a>
354
+ </div>
355
+ </body>
356
+ </html>`);
357
+ return;
358
+ }
359
+ sendJson(res, 200, {
360
+ ok: true,
361
+ message: `Workspace '${redeemed.workspace.name}' claimed by ${redeemed.targetEmail}`,
362
+ claim: redeemed,
363
+ });
364
+ return;
365
+ }
366
+ // Browser OAuth Handoff Callback Route (GET /oauth/callback)
367
+ if (pathname === "/oauth/callback" && req.method === "GET") {
368
+ const workspaceId = url.searchParams.get("workspace_id") ||
369
+ url.searchParams.get("user_id") ||
370
+ bootstrap.workspace.id;
371
+ const provider = url.searchParams.get("provider") ||
372
+ url.searchParams.get("toolkit") ||
373
+ url.searchParams.get("appName") ||
374
+ "unknown";
375
+ const connectedAccountId = url.searchParams.get("connected_account_id") ||
376
+ url.searchParams.get("connectedAccountId") ||
377
+ undefined;
378
+ const callbackStatus = url.searchParams.get("status") || "success";
379
+ const handoff = await engine.handleOAuthCallback({
380
+ workspaceId,
381
+ provider,
382
+ connectedAccountId,
383
+ status: callbackStatus,
384
+ });
385
+ const wantsJson = url.searchParams.get("format") === "json" ||
386
+ String(req.headers.accept || "").includes("application/json");
387
+ if (wantsJson) {
388
+ sendJson(res, 200, {
389
+ ok: true,
390
+ handoff,
391
+ message: `${handoff.providerName} OAuth handoff completed (${handoff.status}). Return to your agent or terminal.`,
392
+ });
393
+ return;
394
+ }
395
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
396
+ res.end(`<!DOCTYPE html>
397
+ <html lang="en">
398
+ <head>
399
+ <meta charset="utf-8" />
400
+ <title>Muxo OAuth Handoff Complete</title>
401
+ <style>
402
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #090a0f; color: #f4f4f6; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
403
+ .card { background: #12141f; border: 1px solid #26293d; border-radius: 14px; padding: 32px; max-width: 460px; text-align: center; box-shadow: 0 20px 50px rgba(0,0,0,0.45); }
404
+ .badge { display: inline-block; background: rgba(16,185,129,0.15); color: #34d399; border: 1px solid rgba(16,185,129,0.35); border-radius: 999px; padding: 4px 12px; font-size: 12px; font-weight: 600; margin-bottom: 16px; }
405
+ h1 { font-size: 22px; margin: 0 0 10px; }
406
+ p { color: #a1a7bb; font-size: 14px; line-height: 1.5; margin: 0 0 20px; }
407
+ code { background: #1c1f30; padding: 3px 7px; border-radius: 6px; color: #e2e8f0; font-size: 12px; }
408
+ .btn { display: inline-block; background: #6366f1; color: #fff; text-decoration: none; padding: 10px 18px; border-radius: 8px; font-size: 14px; font-weight: 600; }
409
+ </style>
410
+ </head>
411
+ <body>
412
+ <div class="card">
413
+ <div class="badge">OAuth Handoff Complete (${handoff.status.toUpperCase()})</div>
414
+ <h1>${handoff.providerName} Connected to Muxo</h1>
415
+ <p>Workspace <code>${handoff.workspaceId}</code> is now linked${handoff.externalAccountId ? ` (<code>${handoff.externalAccountId}</code>)` : ""}. You can close this window and return to ChatGPT, Codex, Claude Code, Droid, or your terminal.</p>
416
+ <a class="btn" href="/?connected=${encodeURIComponent(handoff.providerSlug)}">Open Muxo Console</a>
417
+ </div>
418
+ </body>
419
+ </html>`);
420
+ return;
421
+ }
422
+ // Autonomous Agent 2-Call Signup (agents.composio.dev pattern) — Public
423
+ if (pathname === "/api/v1/agents/signup" && req.method === "POST") {
424
+ const body = JSON.parse((await readBody(req)) || "{}");
425
+ const created = store.createAutonomousAgentSignup({
426
+ agentName: body.agentName ? String(body.agentName) : undefined,
427
+ harness: body.harness ? String(body.harness) : undefined,
428
+ });
429
+ sendJson(res, 201, {
430
+ ok: true,
431
+ agentId: created.user.id,
432
+ workspace: {
433
+ id: created.workspace.id,
434
+ name: created.workspace.name,
435
+ slug: created.workspace.slug,
436
+ tier: created.workspace.tier,
437
+ creditsBalance: created.workspace.creditsBalance,
438
+ },
439
+ apiKey: created.apiKey,
440
+ mcpEndpoint: `${config.baseUrl}/mcp`,
441
+ skillUrl: `${config.baseUrl}/skill.md`,
442
+ claimEndpoint: `${config.baseUrl}/api/v1/agents/claim`,
443
+ governanceDid: engine.governance.getStatus(created.workspace).agentDid,
444
+ supermemoryNamespace: engine.supermemory.getWorkspaceNamespace(created.workspace.id),
445
+ });
446
+ return;
447
+ }
448
+ // Streamable HTTP MCP Endpoint (POST /mcp)
449
+ if (pathname === "/mcp" && req.method === "POST") {
450
+ const ctx = resolveContext(req);
451
+ const raw = await readBody(req);
452
+ const rpc = JSON.parse(raw || "{}");
453
+ const response = await handleJsonRpcMcpRequest(engine, ctx, rpc);
454
+ if (!response) {
455
+ res.writeHead(202);
456
+ res.end();
457
+ return;
458
+ }
459
+ sendJson(res, 200, response);
460
+ return;
461
+ }
462
+ // Auth Endpoints
463
+ if (pathname === "/api/v1/auth/register" && req.method === "POST") {
464
+ const body = JSON.parse((await readBody(req)) || "{}");
465
+ const created = store.registerUser({
466
+ email: String(body.email || ""),
467
+ name: String(body.name || "User"),
468
+ password: String(body.password || ""),
469
+ workspaceName: body.workspaceName ? String(body.workspaceName) : undefined,
470
+ });
471
+ sendJson(res, 201, { ok: true, ...created });
472
+ return;
473
+ }
474
+ if (pathname === "/api/v1/auth/login" && req.method === "POST") {
475
+ const body = JSON.parse((await readBody(req)) || "{}");
476
+ const loggedIn = store.loginUser(String(body.email || ""), String(body.password || ""));
477
+ if (!loggedIn) {
478
+ sendJson(res, 401, { ok: false, error: "Invalid email or password" });
479
+ return;
480
+ }
481
+ sendJson(res, 200, { ok: true, ...loggedIn });
482
+ return;
483
+ }
484
+ const ctx = resolveContext(req);
485
+ // Console Bootstrap
486
+ if (pathname === "/api/v1/bootstrap" && req.method === "GET") {
487
+ const org = engine.getOrganization(ctx).organization;
488
+ sendJson(res, 200, {
489
+ ok: true,
490
+ profile: engine.getProfile(ctx),
491
+ organization: org,
492
+ governance: engine.governance.getStatus(),
493
+ supermemory: {
494
+ enabled: engine.supermemory.isEnabled(),
495
+ namespace: engine.supermemory.getWorkspaceNamespace(ctx.workspace.id),
496
+ },
497
+ surfaces: {
498
+ publicWebUrl: config.publicWebUrl,
499
+ docsUrl: config.docsUrl,
500
+ landingUrl: `${config.baseUrl}/landing`,
501
+ },
502
+ apiKeys: store.listApiKeys(ctx.workspace.id),
503
+ defaultApiKey: bootstrap.defaultApiKey || null,
504
+ connections: store.listConnections(ctx.workspace.id),
505
+ resources: store.listResources(ctx.workspace.id),
506
+ plans: store.listPlans(ctx.workspace.id, 25),
507
+ runs: store.listRuns(ctx.workspace.id, 25),
508
+ });
509
+ return;
510
+ }
511
+ // Autonomous Agent Claim Link Creation (Authenticated)
512
+ if (pathname === "/api/v1/agents/claim" && req.method === "POST") {
513
+ const body = JSON.parse((await readBody(req)) || "{}");
514
+ const email = String(body.email || "").trim();
515
+ if (!email || !email.includes("@")) {
516
+ sendJson(res, 400, { ok: false, error: "Valid target email is required" });
517
+ return;
518
+ }
519
+ const claim = store.createAgentClaim({
520
+ workspaceId: ctx.workspace.id,
521
+ email,
522
+ baseUrl: config.baseUrl,
523
+ });
524
+ sendJson(res, 201, { ok: true, claim, ...claim });
525
+ return;
526
+ }
527
+ // Microsoft Agent Governance Status & Audit Verification
528
+ if (pathname === "/api/v1/governance" && req.method === "GET") {
529
+ sendJson(res, 200, {
530
+ ok: true,
531
+ governance: engine.governance.getStatus(),
532
+ workspacePolicy: ctx.workspace.policy,
533
+ });
534
+ return;
535
+ }
536
+ // Supermemory v5 Workspace Brain Endpoints
537
+ if (pathname === "/api/v1/memory" && req.method === "GET") {
538
+ const query = url.searchParams.get("query") ||
539
+ url.searchParams.get("q") ||
540
+ undefined;
541
+ const overview = await engine.getMemoryOverview(ctx, query);
542
+ sendJson(res, 200, { ok: true, ...overview });
543
+ return;
544
+ }
545
+ if (pathname === "/api/v1/memory" && req.method === "POST") {
546
+ const body = JSON.parse((await readBody(req)) || "{}");
547
+ const record = await engine.addWorkspaceMemory(ctx, {
548
+ title: String(body.title || "Workspace Fact"),
549
+ content: String(body.content || ""),
550
+ kind: body.kind || "fact",
551
+ metadata: body.metadata || {},
552
+ });
553
+ sendJson(res, 201, { ok: true, memory: record });
554
+ return;
555
+ }
556
+ if (pathname.startsWith("/api/v1/memory/") && req.method === "DELETE") {
557
+ const id = decodeURIComponent(pathname.slice("/api/v1/memory/".length));
558
+ const deleted = await engine.deleteWorkspaceMemory(ctx, id);
559
+ sendJson(res, 200, { ok: true, ...deleted });
560
+ return;
561
+ }
562
+ // API Keys
563
+ if (pathname === "/api/v1/api-keys" && req.method === "POST") {
564
+ const body = JSON.parse((await readBody(req)) || "{}");
565
+ const created = store.createApiKey({
566
+ workspaceId: ctx.workspace.id,
567
+ name: String(body.name || "API Key"),
568
+ environment: body.environment === "test" ? "test" : "live",
569
+ });
570
+ sendJson(res, 201, { ok: true, ...created });
571
+ return;
572
+ }
573
+ // Profile & Organization (v1 and api/v1)
574
+ if ((pathname === "/api/v1/profile" || pathname === "/v1/profile") && req.method === "GET") {
575
+ sendJson(res, 200, { ok: true, ...engine.getProfile(ctx) });
576
+ return;
577
+ }
578
+ if ((pathname === "/api/v1/organization" || pathname === "/v1/organization") && req.method === "GET") {
579
+ sendJson(res, 200, { ok: true, ...engine.getOrganization(ctx) });
580
+ return;
581
+ }
582
+ // Catalog Search & Inspect
583
+ if ((pathname === "/api/v1/tools" || pathname === "/v1/tools/search") &&
584
+ (req.method === "GET" || req.method === "POST")) {
585
+ const body = req.method === "POST" ? JSON.parse((await readBody(req)) || "{}") : {};
586
+ const query = url.searchParams.get("query") || body.query || undefined;
587
+ const lane = (url.searchParams.get("lane") || body.lane) ||
588
+ "all";
589
+ const riskLevel = (url.searchParams.get("risk_level") || body.risk_level) ||
590
+ undefined;
591
+ const limit = Number(url.searchParams.get("limit") || body.limit || 30);
592
+ const results = await engine.searchTools({ query, lane, riskLevel, limit });
593
+ sendJson(res, 200, { ok: true, ...results });
594
+ return;
595
+ }
596
+ if (pathname.startsWith("/api/v1/tools/") && req.method === "GET") {
597
+ const slug = decodeURIComponent(pathname.slice("/api/v1/tools/".length));
598
+ const tool = await engine.inspectTool(slug);
599
+ sendJson(res, 200, tool);
600
+ return;
601
+ }
602
+ // Connections
603
+ if (pathname === "/api/v1/connections" && req.method === "GET") {
604
+ const syncLive = url.searchParams.get("sync") === "true";
605
+ const provider = url.searchParams.get("provider") || undefined;
606
+ const status = await engine.connectionStatus(ctx, { provider, syncLive });
607
+ sendJson(res, 200, { ok: true, ...status });
608
+ return;
609
+ }
610
+ if (pathname === "/api/v1/connections" && req.method === "POST") {
611
+ const body = JSON.parse((await readBody(req)) || "{}");
612
+ const connection = await engine.startConnection(ctx, {
613
+ provider: String(body.provider || ""),
614
+ lane: body.lane,
615
+ callbackUrl: body.callbackUrl ? String(body.callbackUrl) : undefined,
616
+ });
617
+ sendJson(res, 201, { ok: true, connection });
618
+ return;
619
+ }
620
+ if (pathname === "/api/v1/connections/wait" && req.method === "POST") {
621
+ const body = JSON.parse((await readBody(req)) || "{}");
622
+ const result = await engine.waitForConnection(ctx, {
623
+ provider: String(body.provider || ""),
624
+ timeoutSeconds: body.timeoutSeconds !== undefined
625
+ ? Number(body.timeoutSeconds)
626
+ : body.timeout_seconds !== undefined
627
+ ? Number(body.timeout_seconds)
628
+ : 15,
629
+ });
630
+ sendJson(res, 200, { ok: true, ...result });
631
+ return;
632
+ }
633
+ // Provisioned Resources & Decrypted Vault Env Pull
634
+ if (pathname === "/api/v1/resources" && req.method === "GET") {
635
+ sendJson(res, 200, {
636
+ ok: true,
637
+ resources: store.listResources(ctx.workspace.id),
638
+ });
639
+ return;
640
+ }
641
+ if (pathname === "/api/v1/resources/env" && req.method === "GET") {
642
+ // Also pull any fresh .env from Stripe Projects workdir if present
643
+ const workdirSecrets = await engine.stripeProjects
644
+ .pullEnvVarsFromWorkdir()
645
+ .catch(() => ({}));
646
+ const vaultSecrets = store.getDecryptedWorkspaceEnv(ctx.workspace.id);
647
+ const merged = { ...workdirSecrets, ...vaultSecrets };
648
+ const dotenvLines = [
649
+ `# Muxo Encrypted Vault Export — Workspace ${ctx.workspace.slug} (${ctx.workspace.id})`,
650
+ `# Generated at ${new Date().toISOString()}`,
651
+ ...Object.entries(merged).map(([k, v]) => `${k}=${JSON.stringify(v)}`),
652
+ ];
653
+ sendJson(res, 200, {
654
+ ok: true,
655
+ workspaceId: ctx.workspace.id,
656
+ variables: merged,
657
+ dotenv: dotenvLines.join("\n") + "\n",
658
+ });
659
+ return;
660
+ }
661
+ // Governance Policy
662
+ if (pathname === "/api/v1/policy" && req.method === "POST") {
663
+ const body = JSON.parse((await readBody(req)) || "{}");
664
+ const updated = store.updateWorkspacePolicy(ctx.workspace.id, body);
665
+ sendJson(res, 200, { ok: true, workspace: updated });
666
+ return;
667
+ }
668
+ // Plans & Approvals & Execution
669
+ if (pathname === "/api/v1/plans" && req.method === "GET") {
670
+ sendJson(res, 200, {
671
+ ok: true,
672
+ plans: store.listPlans(ctx.workspace.id, 50),
673
+ });
674
+ return;
675
+ }
676
+ if (pathname === "/api/v1/plans" && req.method === "POST") {
677
+ const body = JSON.parse((await readBody(req)) || "{}");
678
+ const planned = await engine.planAction(ctx, {
679
+ toolSlug: String(body.toolSlug || body.tool_slug || ""),
680
+ input: body.input || {},
681
+ reason: body.reason ? String(body.reason) : undefined,
682
+ });
683
+ sendJson(res, 201, { ok: true, ...planned });
684
+ return;
685
+ }
686
+ const planApproveMatch = pathname.match(/^\/api\/v1\/plans\/([^/]+)\/approve$/);
687
+ if (planApproveMatch && req.method === "POST") {
688
+ const planId = decodeURIComponent(planApproveMatch[1]);
689
+ const plan = engine.approvePlan(ctx, planId, "approved");
690
+ sendJson(res, 200, { ok: true, plan });
691
+ return;
692
+ }
693
+ const planExecuteMatch = pathname.match(/^\/api\/v1\/plans\/([^/]+)\/execute$/);
694
+ if (planExecuteMatch && req.method === "POST") {
695
+ const planId = decodeURIComponent(planExecuteMatch[1]);
696
+ const plan = engine.getPlan(ctx, planId);
697
+ const result = await engine.executePlanForRisk(ctx, planId, plan.riskLevel);
698
+ sendJson(res, 200, { ok: true, ...result });
699
+ return;
700
+ }
701
+ // Runs & Receipts
702
+ if (pathname === "/api/v1/runs" && req.method === "GET") {
703
+ sendJson(res, 200, {
704
+ ok: true,
705
+ runs: store.listRuns(ctx.workspace.id, 50),
706
+ });
707
+ return;
708
+ }
709
+ if (pathname.startsWith("/api/v1/receipts/") && req.method === "GET") {
710
+ const receiptId = decodeURIComponent(pathname.slice("/api/v1/receipts/".length));
711
+ const verified = engine.getReceipt(ctx, receiptId);
712
+ sendJson(res, 200, { ok: true, ...verified });
713
+ return;
714
+ }
715
+ // Live Stripe Billing, Credit Top-Up & Supplier Settlement Ledger
716
+ if (pathname === "/api/v1/billing/ledger" && req.method === "GET") {
717
+ sendJson(res, 200, {
718
+ ok: true,
719
+ entries: store.listLedgerEntries(ctx.workspace.id, 50),
720
+ settlementSummary: store.getSupplierSettlementSummary(ctx.workspace.id),
721
+ });
722
+ return;
723
+ }
724
+ if (pathname === "/api/v1/billing/settlements" && req.method === "GET") {
725
+ sendJson(res, 200, {
726
+ ok: true,
727
+ settlementSummary: store.getSupplierSettlementSummary(ctx.workspace.id),
728
+ entries: store.listLedgerEntries(ctx.workspace.id, 100),
729
+ });
730
+ return;
731
+ }
732
+ if (pathname === "/api/v1/billing/topup" && req.method === "POST") {
733
+ const body = JSON.parse((await readBody(req)) || "{}");
734
+ const credits = Math.max(1, Math.min(1000000, Number(body.credits || 1000)));
735
+ const referenceId = String(body.referenceId || "").trim() ||
736
+ `topup_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
737
+ const usdPaid = (credits * 0.01).toFixed(2);
738
+ const updatedWorkspace = store.addWorkspaceCredits({
739
+ workspaceId: ctx.workspace.id,
740
+ credits,
741
+ referenceId,
742
+ description: String(body.description || "").trim() ||
743
+ `User purchased +${credits.toLocaleString()} Muxo Credits ($${usdPaid} USD -> Muxo Master Wallet)`,
744
+ });
745
+ sendJson(res, 200, {
746
+ ok: true,
747
+ creditsAdded: credits,
748
+ usdPaid: Number(usdPaid),
749
+ workspace: updatedWorkspace,
750
+ settlementSummary: store.getSupplierSettlementSummary(ctx.workspace.id),
751
+ });
752
+ return;
753
+ }
754
+ if (pathname === "/api/v1/billing/checkout" && req.method === "POST") {
755
+ const body = JSON.parse((await readBody(req)) || "{}");
756
+ const kind = body.kind === "credit_topup" ? "credit_topup" : "starter_subscription";
757
+ const session = await engine.stripeBilling.createCheckoutSession({
758
+ workspace: ctx.workspace,
759
+ customerEmail: ctx.user.email,
760
+ kind,
761
+ returnBaseUrl: config.baseUrl,
762
+ });
763
+ sendJson(res, 200, { ok: true, ...session });
764
+ return;
765
+ }
766
+ if (pathname === "/api/v1/billing/verify-session" && req.method === "POST") {
767
+ const body = JSON.parse((await readBody(req)) || "{}");
768
+ const verified = await engine.stripeBilling.verifyAndFulfillCheckoutSession(String(body.sessionId || ""));
769
+ sendJson(res, 200, { ok: true, ...verified });
770
+ return;
771
+ }
772
+ if (pathname === "/api/v1/billing/webhook" && req.method === "POST") {
773
+ const rawBody = await readBody(req);
774
+ const sig = String(req.headers["stripe-signature"] || "");
775
+ if (!engine.stripeBilling.verifyWebhookSignature(rawBody, sig)) {
776
+ sendJson(res, 400, { ok: false, error: "Invalid Stripe webhook signature" });
777
+ return;
778
+ }
779
+ const event = JSON.parse(rawBody || "{}");
780
+ if (event.type === "checkout.session.completed") {
781
+ const sessionObj = event.data?.object;
782
+ if (sessionObj?.id) {
783
+ await engine.stripeBilling.verifyAndFulfillCheckoutSession(String(sessionObj.id));
784
+ }
785
+ }
786
+ sendJson(res, 200, { ok: true, received: true });
787
+ return;
788
+ }
789
+ sendJson(res, 404, { ok: false, error: `Route not found: ${req.method} ${pathname}` });
790
+ }
791
+ catch (err) {
792
+ sendJson(res, 400, {
793
+ ok: false,
794
+ error: String(err?.message || err || "Internal error"),
795
+ });
796
+ }
797
+ });
798
+ return { server, engine, store, defaultApiKey: bootstrap.defaultApiKey };
799
+ }
800
+ // Start server when invoked directly
801
+ const isMain = process.argv[1] &&
802
+ (process.argv[1].endsWith("server.ts") || process.argv[1].endsWith("server.js"));
803
+ if (isMain) {
804
+ const config = getConfig();
805
+ const { server, defaultApiKey } = createMuxoServer(config);
806
+ server.listen(config.port, () => {
807
+ console.log(`\n⚡ Muxo Platform running at ${config.baseUrl}`);
808
+ console.log(` ├─ Web Console: ${config.baseUrl}/`);
809
+ console.log(` ├─ MCP Server: ${config.baseUrl}/mcp`);
810
+ console.log(` ├─ Agent Skill: ${config.baseUrl}/skill.md`);
811
+ console.log(` └─ Health Check: ${config.baseUrl}/health`);
812
+ if (defaultApiKey) {
813
+ console.log(`\n🔑 Initial Workspace API Key created (save this): ${defaultApiKey}\n`);
814
+ }
815
+ });
816
+ }