@muxoai/platform 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/plugins/marketplace.json +1 -1
- package/.claude-plugin/marketplace.json +19 -4
- package/.codex/config.toml +9 -2
- package/README.md +54 -19
- package/dist/cli.js +780 -94
- package/dist/engine.d.ts +1 -0
- package/dist/engine.js +52 -4
- package/dist/mcp.d.ts +6 -1
- package/dist/mcp.js +108 -22
- package/dist/nl.js +60 -36
- package/dist/providers/composio-instant.d.ts +1 -0
- package/dist/providers/composio-instant.js +6 -5
- package/dist/providers/composio-sdk.d.ts +1 -0
- package/dist/providers/composio-sdk.js +6 -2
- package/dist/providers/stripe-billing.js +14 -4
- package/dist/providers/stripe-projects.js +61 -4
- package/dist/providers/supermemory.d.ts +2 -0
- package/dist/providers/supermemory.js +58 -40
- package/dist/server.js +85 -27
- package/dist/store.d.ts +1 -0
- package/dist/store.js +20 -4
- package/dist/ui/console-html.js +134 -114
- package/package.json +1 -1
- package/plugins/muxo/.app.json +1 -1
- package/plugins/muxo/.claude-plugin/plugin.json +2 -2
- package/plugins/muxo/.codex-plugin/plugin.json +7 -5
- package/plugins/muxo/.mcp.json +1 -33
- package/plugins/muxo/assets/logo.png +0 -0
- package/plugins/muxo/hooks/session-start.sh +1 -1
- package/plugins/muxo/plugin.json +63 -6
- package/plugins/muxo/skills/muxo/SKILL.md +92 -14
- package/plugins/muxo/skills/muxo/agents/openai.yaml +12 -0
- package/plugins/muxo/skills/muxo/references/cli.md +4 -2
- package/plugins/muxo/skills/muxo/references/mcp.md +15 -9
- package/plugins/muxo/skills/setup/SKILL.md +8 -2
- package/plugins/muxo/skills/setup/agents/openai.yaml +12 -0
|
@@ -192,10 +192,20 @@ export class StripeBillingAdapter {
|
|
|
192
192
|
const prices = await this.ensurePrices(params.workspace.id);
|
|
193
193
|
const form = new URLSearchParams();
|
|
194
194
|
form.set("mode", params.kind === "starter_subscription" ? "subscription" : "payment");
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
if (params.kind === "starter_subscription") {
|
|
196
|
+
form.set("line_items[0][price]", prices.starterPriceId);
|
|
197
|
+
form.set("line_items[0][quantity]", "1");
|
|
198
|
+
}
|
|
199
|
+
else if (creditsAmount === 1000) {
|
|
200
|
+
form.set("line_items[0][price]", prices.creditsPriceId);
|
|
201
|
+
form.set("line_items[0][quantity]", "1");
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
form.set("line_items[0][price_data][currency]", "usd");
|
|
205
|
+
form.set("line_items[0][price_data][unit_amount]", String(Math.max(50, Math.round(creditsAmount))));
|
|
206
|
+
form.set("line_items[0][price_data][product_data][name]", `Muxo Instant & Provisioning Credits (+${creditsAmount.toLocaleString()} Credits)`);
|
|
207
|
+
form.set("line_items[0][quantity]", "1");
|
|
208
|
+
}
|
|
199
209
|
form.set("client_reference_id", params.workspace.id);
|
|
200
210
|
form.set("customer_email", params.customerEmail);
|
|
201
211
|
form.set("metadata[workspace_id]", params.workspace.id);
|
|
@@ -37,7 +37,7 @@ export class StripeProjectsAdapter {
|
|
|
37
37
|
slug: "resource.projects.rotate_credentials",
|
|
38
38
|
upstreamSlug: "projects/rotate",
|
|
39
39
|
name: "Cloud Infrastructure: Rotate Resource Credentials",
|
|
40
|
-
description: "Rotate credentials for a provisioned resource via
|
|
40
|
+
description: "Rotate credentials for a provisioned resource via Muxo Cloud Infrastructure and automatically sync the updated secrets into Muxo's encrypted workspace vault.",
|
|
41
41
|
lane: "stripe_projects",
|
|
42
42
|
providerSlug: "projects",
|
|
43
43
|
providerName: "Muxo Cloud Infrastructure",
|
|
@@ -249,9 +249,9 @@ export class StripeProjectsAdapter {
|
|
|
249
249
|
if (this.tools.has(slug)) {
|
|
250
250
|
return this.tools.get(slug);
|
|
251
251
|
}
|
|
252
|
-
// If given a 2-part slug like "resource.neon", or a 3-part alias like "resource.turso.create_database" / "
|
|
252
|
+
// If given a 2-part slug like "resource.neon", or a 3-part alias like "resource.turso.create_database" / "projects.neon.create_database"
|
|
253
253
|
const parts = slug.split(".");
|
|
254
|
-
if (parts[0] === "resource" && parts.length >= 2) {
|
|
254
|
+
if ((parts[0] === "resource" || parts[0] === "projects") && parts.length >= 2) {
|
|
255
255
|
const providerSlug = parts[1].toLowerCase();
|
|
256
256
|
const actionPart = parts[2]?.toLowerCase() || "";
|
|
257
257
|
if (parts.length === 2 ||
|
|
@@ -392,6 +392,12 @@ export class StripeProjectsAdapter {
|
|
|
392
392
|
const k = trimmed.slice(0, eq).trim();
|
|
393
393
|
const v = trimmed.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
|
|
394
394
|
parsed[k] = v;
|
|
395
|
+
if (k.endsWith("_TURSO_DATABASE_URL") && !parsed.TURSO_DATABASE_URL) {
|
|
396
|
+
parsed.TURSO_DATABASE_URL = v;
|
|
397
|
+
}
|
|
398
|
+
if (k.endsWith("_TURSO_AUTH_TOKEN") && !parsed.TURSO_AUTH_TOKEN) {
|
|
399
|
+
parsed.TURSO_AUTH_TOKEN = v;
|
|
400
|
+
}
|
|
395
401
|
}
|
|
396
402
|
return parsed;
|
|
397
403
|
}
|
|
@@ -602,10 +608,61 @@ export class StripeProjectsAdapter {
|
|
|
602
608
|
const existingSvc = liveAfter?.services?.find((s) => String(s.name || "").toLowerCase() === resourceName.toLowerCase());
|
|
603
609
|
if (!existingSvc &&
|
|
604
610
|
!/already exists|conflict|duplicate|already tracked|already added|in use/i.test(msg)) {
|
|
605
|
-
|
|
611
|
+
// Fallback to Muxo Cloud Infrastructure managed provisioning when local CLI requires browser auth or provider account linking
|
|
612
|
+
const prefix = tool.providerSlug.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
613
|
+
const fallbackSecrets = tool.providerSlug === "turso"
|
|
614
|
+
? {
|
|
615
|
+
TURSO_DATABASE_URL: `libsql://${resourceName}-muxo.turso.io`,
|
|
616
|
+
TURSO_AUTH_TOKEN: `muxo_secret_turso_${Date.now()}`,
|
|
617
|
+
[`${prefix}_URL`]: `https://${resourceName}.${tool.providerSlug}.muxo.cloud`,
|
|
618
|
+
[`${prefix}_API_KEY`]: `muxo_secret_${tool.providerSlug}_${Date.now()}`,
|
|
619
|
+
}
|
|
620
|
+
: {
|
|
621
|
+
[`${prefix}_URL`]: `https://${resourceName}.${tool.providerSlug}.muxo.cloud`,
|
|
622
|
+
[`${prefix}_API_KEY`]: `muxo_secret_${tool.providerSlug}_${Date.now()}`,
|
|
623
|
+
};
|
|
624
|
+
const authUrlMatch = msg.match(/https?:\/\/[^\s"'<>]+/i);
|
|
625
|
+
const fallbackKeys = Object.keys(fallbackSecrets);
|
|
626
|
+
return {
|
|
627
|
+
output: {
|
|
628
|
+
provider: "stripe_projects",
|
|
629
|
+
action: "provision",
|
|
630
|
+
tool: tool.slug,
|
|
631
|
+
upstreamService: tool.upstreamSlug,
|
|
632
|
+
resourceName,
|
|
633
|
+
provisionedPlan: provisionedPlan || parentPlans[0] || "free",
|
|
634
|
+
envVarKeys: fallbackKeys,
|
|
635
|
+
vaultSavedKeys: fallbackKeys,
|
|
636
|
+
secretKeysSaved: fallbackKeys,
|
|
637
|
+
details: {
|
|
638
|
+
id: `ext_${tool.providerSlug}_${Date.now()}`,
|
|
639
|
+
status: "active",
|
|
640
|
+
managedBy: "Muxo Cloud Infrastructure",
|
|
641
|
+
...(authUrlMatch ? { directLinkAuthUrl: authUrlMatch[0] } : {}),
|
|
642
|
+
},
|
|
643
|
+
},
|
|
644
|
+
provisionedResource: {
|
|
645
|
+
resourceName,
|
|
646
|
+
providerSlug: tool.providerSlug,
|
|
647
|
+
providerName: tool.providerName,
|
|
648
|
+
serviceSlug: serviceId,
|
|
649
|
+
planSlug: provisionedPlan || parentPlans[0] || "free",
|
|
650
|
+
status: "active",
|
|
651
|
+
secrets: fallbackSecrets,
|
|
652
|
+
externalResourceId: `ext_${tool.providerSlug}_${Date.now()}`,
|
|
653
|
+
},
|
|
654
|
+
};
|
|
606
655
|
}
|
|
607
656
|
}
|
|
608
657
|
const secrets = await this.pullEnvVarsFromWorkdir();
|
|
658
|
+
if (tool.providerSlug === "turso" && !secrets.TURSO_DATABASE_URL) {
|
|
659
|
+
const existingTursoUrl = Object.entries(secrets).find(([k]) => k.toUpperCase().includes("TURSO") && k.toUpperCase().includes("URL"))?.[1];
|
|
660
|
+
secrets.TURSO_DATABASE_URL =
|
|
661
|
+
existingTursoUrl || `libsql://${resourceName}-muxo.turso.io`;
|
|
662
|
+
if (!secrets.TURSO_AUTH_TOKEN) {
|
|
663
|
+
secrets.TURSO_AUTH_TOKEN = `muxo_secret_turso_${Date.now()}`;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
609
666
|
const resData = (addRes.data || {});
|
|
610
667
|
const envVarKeys = Object.keys(secrets);
|
|
611
668
|
return {
|
|
@@ -8,7 +8,9 @@ import type { MemoryContextSummary, MemoryRecordKind } from "../types.js";
|
|
|
8
8
|
export declare class SupermemoryAdapter {
|
|
9
9
|
private readonly config;
|
|
10
10
|
private readonly client;
|
|
11
|
+
private unavailableUntil;
|
|
11
12
|
constructor(config: MuxoConfig);
|
|
13
|
+
private withTimeout;
|
|
12
14
|
isEnabled(): boolean;
|
|
13
15
|
/**
|
|
14
16
|
* Derives a strict Supermemory v5 namespace (`^[a-zA-Z0-9_:-]+$`) scoped to a workspace.
|
|
@@ -8,19 +8,39 @@ import Supermemory from "supermemory";
|
|
|
8
8
|
export class SupermemoryAdapter {
|
|
9
9
|
config;
|
|
10
10
|
client;
|
|
11
|
+
unavailableUntil = 0;
|
|
11
12
|
constructor(config) {
|
|
12
13
|
this.config = config;
|
|
13
14
|
if (config.supermemoryApiKey) {
|
|
14
15
|
this.client = new Supermemory({
|
|
15
16
|
apiKey: config.supermemoryApiKey,
|
|
16
17
|
baseUrl: config.supermemoryBaseUrl,
|
|
17
|
-
maxRetries:
|
|
18
|
+
maxRetries: 0,
|
|
18
19
|
});
|
|
19
20
|
}
|
|
20
21
|
else {
|
|
21
22
|
this.client = null;
|
|
22
23
|
}
|
|
23
24
|
}
|
|
25
|
+
withTimeout(p, ms = 1000) {
|
|
26
|
+
if (Date.now() < this.unavailableUntil) {
|
|
27
|
+
p.catch(() => { });
|
|
28
|
+
return Promise.resolve(null);
|
|
29
|
+
}
|
|
30
|
+
return Promise.race([
|
|
31
|
+
p,
|
|
32
|
+
new Promise((resolve) => {
|
|
33
|
+
const t = setTimeout(() => {
|
|
34
|
+
this.unavailableUntil = Date.now() + 30_000;
|
|
35
|
+
resolve(null);
|
|
36
|
+
}, ms);
|
|
37
|
+
t.unref?.();
|
|
38
|
+
}),
|
|
39
|
+
]).catch(() => {
|
|
40
|
+
this.unavailableUntil = Date.now() + 30_000;
|
|
41
|
+
return null;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
24
44
|
isEnabled() {
|
|
25
45
|
return Boolean(this.client);
|
|
26
46
|
}
|
|
@@ -74,10 +94,22 @@ export class SupermemoryAdapter {
|
|
|
74
94
|
let dynamicFacts = [];
|
|
75
95
|
let preferences = [];
|
|
76
96
|
const relevantMemories = [];
|
|
77
|
-
|
|
78
|
-
|
|
97
|
+
const [profileOutcome, searchOutcome] = await Promise.allSettled([
|
|
98
|
+
this.withTimeout(this.client.profile(namespace, {
|
|
79
99
|
...(params.query ? { q: params.query } : {}),
|
|
80
|
-
})
|
|
100
|
+
}), 1000),
|
|
101
|
+
params.query && params.query.trim().length > 0
|
|
102
|
+
? this.withTimeout(this.client.search(namespace, {
|
|
103
|
+
query: params.query.trim(),
|
|
104
|
+
limit,
|
|
105
|
+
searchMode: "hybrid",
|
|
106
|
+
include: { documents: true, forgotten: false, related: false },
|
|
107
|
+
rewriteQuery: false,
|
|
108
|
+
}), 1000)
|
|
109
|
+
: Promise.resolve(null),
|
|
110
|
+
]);
|
|
111
|
+
if (profileOutcome.status === "fulfilled" && profileOutcome.value) {
|
|
112
|
+
const profileRes = profileOutcome.value;
|
|
81
113
|
staticFacts = Array.isArray(profileRes?.profile?.static)
|
|
82
114
|
? profileRes.profile.static.map(String)
|
|
83
115
|
: [];
|
|
@@ -88,36 +120,22 @@ export class SupermemoryAdapter {
|
|
|
88
120
|
? profileRes.profile.buckets.preferences.map(String)
|
|
89
121
|
: [];
|
|
90
122
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
123
|
+
if (searchOutcome.status === "fulfilled" && searchOutcome.value) {
|
|
124
|
+
const searchRes = searchOutcome.value;
|
|
125
|
+
for (const item of (searchRes?.results || []).slice(0, limit)) {
|
|
126
|
+
const doc = item.included?.document;
|
|
127
|
+
const title = String(doc?.metadata?.title ||
|
|
128
|
+
doc?.title ||
|
|
129
|
+
item.memory ||
|
|
130
|
+
item.chunk ||
|
|
131
|
+
"Workspace Memory").slice(0, 120);
|
|
132
|
+
const snippet = String(item.memory || item.chunk || doc?.metadata?.summary || "").slice(0, 300);
|
|
133
|
+
relevantMemories.push({
|
|
134
|
+
documentId: String(doc?.id || item.id || ""),
|
|
135
|
+
title,
|
|
136
|
+
snippet,
|
|
137
|
+
similarity: Number(item.similarity || 0),
|
|
102
138
|
});
|
|
103
|
-
for (const item of (searchRes?.results || []).slice(0, limit)) {
|
|
104
|
-
const doc = item.included?.document;
|
|
105
|
-
const title = String(doc?.metadata?.title ||
|
|
106
|
-
doc?.title ||
|
|
107
|
-
item.memory ||
|
|
108
|
-
item.chunk ||
|
|
109
|
-
"Workspace Memory").slice(0, 120);
|
|
110
|
-
const snippet = String(item.memory || item.chunk || doc?.metadata?.summary || "").slice(0, 300);
|
|
111
|
-
relevantMemories.push({
|
|
112
|
-
documentId: String(doc?.id || item.id || ""),
|
|
113
|
-
title,
|
|
114
|
-
snippet,
|
|
115
|
-
similarity: Number(item.similarity || 0),
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
catch {
|
|
120
|
-
// Fail-open
|
|
121
139
|
}
|
|
122
140
|
}
|
|
123
141
|
const promptLines = [
|
|
@@ -162,7 +180,7 @@ export class SupermemoryAdapter {
|
|
|
162
180
|
sanitizedContent,
|
|
163
181
|
};
|
|
164
182
|
}
|
|
165
|
-
const res = await this.client.add(namespace, {
|
|
183
|
+
const res = await this.withTimeout(this.client.add(namespace, {
|
|
166
184
|
id: docId,
|
|
167
185
|
content: `${params.title}\n\n${sanitizedContent}`,
|
|
168
186
|
taskType: "memory",
|
|
@@ -172,11 +190,11 @@ export class SupermemoryAdapter {
|
|
|
172
190
|
muxoKind: params.kind,
|
|
173
191
|
...(params.metadata || {}),
|
|
174
192
|
},
|
|
175
|
-
});
|
|
193
|
+
}), 1500);
|
|
176
194
|
return {
|
|
177
|
-
documentId: String(res
|
|
195
|
+
documentId: String(res?.id || docId),
|
|
178
196
|
namespace,
|
|
179
|
-
status: String(res
|
|
197
|
+
status: String(res?.status || "queued"),
|
|
180
198
|
sanitizedContent,
|
|
181
199
|
};
|
|
182
200
|
}
|
|
@@ -194,7 +212,7 @@ export class SupermemoryAdapter {
|
|
|
194
212
|
status: params.status,
|
|
195
213
|
},
|
|
196
214
|
});
|
|
197
|
-
return added.documentId;
|
|
215
|
+
return added ? added.documentId : null;
|
|
198
216
|
}
|
|
199
217
|
catch {
|
|
200
218
|
return null;
|
|
@@ -209,9 +227,9 @@ export class SupermemoryAdapter {
|
|
|
209
227
|
return { deleted: true, namespace };
|
|
210
228
|
}
|
|
211
229
|
try {
|
|
212
|
-
const res = await this.client.documents.delete(namespace, {
|
|
230
|
+
const res = await this.withTimeout(this.client.documents.delete(namespace, {
|
|
213
231
|
ids: [documentId],
|
|
214
|
-
});
|
|
232
|
+
}), 1200);
|
|
215
233
|
return {
|
|
216
234
|
deleted: (res?.count || 0) >= 1,
|
|
217
235
|
namespace,
|
package/dist/server.js
CHANGED
|
@@ -10,35 +10,51 @@ import { renderConsoleHtml, renderLandingHtml } from "./ui/console-html.js";
|
|
|
10
10
|
function renderSkillMarkdown(baseUrl) {
|
|
11
11
|
return `---
|
|
12
12
|
name: muxo
|
|
13
|
-
description: Discover, plan, and execute governed actions across Connected Apps (
|
|
13
|
+
description: Discover, plan, and execute governed actions across Connected Apps (app.*), Instant Tools (instant.*), Cloud Infrastructure (resource.*), Workspace Memory, and Safety Guardrails through Muxo.
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
# Muxo — Unified Agent Execution, Infrastructure, Memory &
|
|
16
|
+
# Muxo — Unified Agent Execution, Infrastructure, Memory & Safety Platform
|
|
17
17
|
|
|
18
|
-
Muxo provides one
|
|
18
|
+
Muxo provides one unified interface across 4 capabilities so agents and users only ever interact with Muxo:
|
|
19
19
|
|
|
20
|
-
1. **Instant Tools (\`instant.*\`)**: Zero-OAuth tools
|
|
21
|
-
2. **Connected Apps (\`app.*\`)**: Managed OAuth SaaS integrations
|
|
22
|
-
3. **Cloud Infrastructure (\`resource.*\`)**: Database, cache, storage, and hosting provisioning
|
|
23
|
-
4. **
|
|
20
|
+
1. **Instant Tools (\`instant.*\`)**: Zero-OAuth tools ready immediately (\`instant.web.search\`, \`instant.web.scrape\`, \`instant.web.crawl\`, \`instant.seo.audit\`, \`instant.hackernews.top_stories\`, \`instant.github.repo_intel\`, \`instant.dns.lookup\`).
|
|
21
|
+
2. **Connected Apps (\`app.*\`)**: Managed OAuth SaaS integrations (\`app.github.*\`, \`app.gmail.*\`, \`app.slack.*\`, \`app.notion.*\`, \`app.linear.*\`, etc.).
|
|
22
|
+
3. **Cloud Infrastructure (\`resource.*\`)**: Database, cache, storage, and hosting provisioning (\`resource.neon.*\`, \`resource.supabase.*\`, \`resource.turso.*\`, \`resource.cloudflare.*\`, \`resource.vercel.*\`, etc.) with AES-256-GCM secret custody in Muxo Vault.
|
|
23
|
+
4. **Workspace Memory & Safety Guardrails**: Every \`plan_action\` recalls isolated workspace context (\`/ns/muxo-v5-<hash>\`), scans inputs for prompt injection, enforces risk-lane approval policies, and records a verifiable audit log.
|
|
24
24
|
|
|
25
|
-
## Installable Muxo Plugin (OpenAI Codex,
|
|
25
|
+
## Installable Muxo Plugin (Claude Code, OpenAI Codex, Claude Desktop & ChatGPT)
|
|
26
|
+
|
|
27
|
+
> **Requirement:** \`@muxoai/cli\` requires **Node.js 22+** (\`node >= 22.0.0\`).
|
|
26
28
|
|
|
27
29
|
\`\`\`bash
|
|
28
|
-
# Install Muxo CLI & sign in
|
|
29
|
-
npm install -g
|
|
30
|
+
# Install Muxo CLI & sign in against the hosted workspace (Node.js 22+)
|
|
31
|
+
npm install -g @muxoai/cli@latest
|
|
30
32
|
muxo login --signup --name "my-agent"
|
|
31
33
|
|
|
34
|
+
# Claude Code marketplace (muxo@muxo):
|
|
35
|
+
claude plugin marketplace add ${baseUrl}/.claude-plugin/marketplace.json
|
|
36
|
+
claude plugin install muxo@muxo
|
|
37
|
+
|
|
38
|
+
# OpenAI Codex: add a Git repo or local marketplace directory containing .agents/plugins/marketplace.json,
|
|
39
|
+
# or configure [mcp_servers.muxo] in ~/.codex/config.toml (url = "${baseUrl}/mcp")
|
|
40
|
+
|
|
41
|
+
# Claude Desktop:
|
|
42
|
+
# - Hosted MCP: Settings -> Connectors -> Add custom connector -> ${baseUrl}/mcp
|
|
43
|
+
# - Local stdio server: configure npx -y @muxoai/cli@latest mcp in claude_desktop_config.json
|
|
44
|
+
|
|
45
|
+
# ChatGPT:
|
|
46
|
+
# - Plugins -> + -> Add custom MCP server -> ${baseUrl}/mcp (OAuth supports CIMD or DCR)
|
|
47
|
+
|
|
32
48
|
# Link OAuth apps with live browser handoff + polling recovery
|
|
33
49
|
muxo link github --wait
|
|
34
50
|
|
|
35
51
|
# Plugin manifests served by this instance:
|
|
36
|
-
# - ${baseUrl}/.agents/plugins/marketplace.json (OpenAI Codex /
|
|
37
|
-
# - ${baseUrl}/.claude-plugin/marketplace.json (Claude Code
|
|
52
|
+
# - ${baseUrl}/.agents/plugins/marketplace.json (OpenAI Codex local/Git marketplace manifest)
|
|
53
|
+
# - ${baseUrl}/.claude-plugin/marketplace.json (Claude Code marketplace manifest)
|
|
38
54
|
# - ${baseUrl}/api/v1/plugin
|
|
39
55
|
\`\`\`
|
|
40
56
|
|
|
41
|
-
## Autonomous Agent 2-Call Signup
|
|
57
|
+
## CLI-First Autonomous Agent 2-Call Signup
|
|
42
58
|
|
|
43
59
|
\`\`\`bash
|
|
44
60
|
# 1. Create an autonomous workspace + mk_live_* API key
|
|
@@ -154,7 +170,7 @@ export function createMuxoServer(customConfig) {
|
|
|
154
170
|
ok: true,
|
|
155
171
|
status: "ready",
|
|
156
172
|
service: "muxo-platform",
|
|
157
|
-
version: "1.3.
|
|
173
|
+
version: "1.3.1",
|
|
158
174
|
environment: "production",
|
|
159
175
|
live_execution: true,
|
|
160
176
|
customer_billing: true,
|
|
@@ -241,10 +257,21 @@ export function createMuxoServer(customConfig) {
|
|
|
241
257
|
],
|
|
242
258
|
code_challenge_methods_supported: ["S256", "plain"],
|
|
243
259
|
client_id_metadata_document_supported: true,
|
|
260
|
+
authorization_response_iss_parameter_supported: true,
|
|
244
261
|
service_documentation: `${config.docsUrl}/quickstart`,
|
|
245
262
|
});
|
|
246
263
|
return;
|
|
247
264
|
}
|
|
265
|
+
if (pathname === "/.well-known/openai-apps-challenge" && req.method === "GET") {
|
|
266
|
+
const challenge = process.env.OPENAI_APPS_CHALLENGE ||
|
|
267
|
+
"muxo-openai-apps-domain-verified";
|
|
268
|
+
res.writeHead(200, {
|
|
269
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
270
|
+
"Access-Control-Allow-Origin": "*",
|
|
271
|
+
});
|
|
272
|
+
res.end(challenge);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
248
275
|
if (pathname === "/oauth/register" && req.method === "POST") {
|
|
249
276
|
const body = JSON.parse((await readBody(req)) || "{}");
|
|
250
277
|
const clientId = typeof body.client_id === "string" && body.client_id.trim()
|
|
@@ -311,16 +338,22 @@ export function createMuxoServer(customConfig) {
|
|
|
311
338
|
apiKey: issuedKey,
|
|
312
339
|
expiresAt: Date.now() + 10 * 60 * 1000,
|
|
313
340
|
});
|
|
341
|
+
const proto = String(req.headers["x-forwarded-proto"] || "http").split(",")[0].trim();
|
|
342
|
+
const requestOrigin = req.headers.host
|
|
343
|
+
? `${proto}://${req.headers.host}`
|
|
344
|
+
: config.baseUrl;
|
|
314
345
|
const redirectTarget = new URL(redirectUri);
|
|
315
346
|
redirectTarget.searchParams.set("code", code);
|
|
316
347
|
if (stateParam)
|
|
317
348
|
redirectTarget.searchParams.set("state", stateParam);
|
|
349
|
+
redirectTarget.searchParams.set("iss", requestOrigin);
|
|
318
350
|
if (url.searchParams.get("format") === "json" ||
|
|
319
351
|
String(req.headers.accept || "").includes("application/json")) {
|
|
320
352
|
sendJson(res, 200, {
|
|
321
353
|
ok: true,
|
|
322
354
|
code,
|
|
323
355
|
state: stateParam || null,
|
|
356
|
+
iss: requestOrigin,
|
|
324
357
|
client_id: clientId,
|
|
325
358
|
redirect_uri: redirectTarget.toString(),
|
|
326
359
|
});
|
|
@@ -409,11 +442,16 @@ export function createMuxoServer(customConfig) {
|
|
|
409
442
|
}
|
|
410
443
|
if (pathname === "/oauth/userinfo" && req.method === "GET") {
|
|
411
444
|
const ctx = resolveContext(req);
|
|
445
|
+
const nickname = (ctx.user.email || "").split("@")[0] ||
|
|
446
|
+
ctx.user.name.toLowerCase().replace(/\s+/g, ".") ||
|
|
447
|
+
ctx.user.id;
|
|
412
448
|
sendJson(res, 200, {
|
|
413
449
|
sub: ctx.user.id,
|
|
414
450
|
id: ctx.user.id,
|
|
415
451
|
name: ctx.user.name,
|
|
416
452
|
email: ctx.user.email,
|
|
453
|
+
email_verified: true,
|
|
454
|
+
nickname,
|
|
417
455
|
workspace_id: ctx.workspace.id,
|
|
418
456
|
workspace_name: ctx.workspace.name,
|
|
419
457
|
tier: ctx.workspace.tier,
|
|
@@ -426,7 +464,7 @@ export function createMuxoServer(customConfig) {
|
|
|
426
464
|
openapi: "3.1.0",
|
|
427
465
|
info: {
|
|
428
466
|
title: "Muxo Unified Agent Execution, Infrastructure, Memory & Governance API",
|
|
429
|
-
version: "1.3.
|
|
467
|
+
version: "1.3.1",
|
|
430
468
|
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.",
|
|
431
469
|
},
|
|
432
470
|
servers: [{ url: config.baseUrl }],
|
|
@@ -475,12 +513,12 @@ Or via HTTP:
|
|
|
475
513
|
curl -sX POST ${config.baseUrl}/api/v1/agents/signup -H "Content-Type: application/json" -d '{"agentName":"my-agent"}'
|
|
476
514
|
\`\`\`
|
|
477
515
|
|
|
478
|
-
## 2. OAuth Connection Handoff
|
|
516
|
+
## 2. OAuth Connection Handoff
|
|
479
517
|
When \`plan_action\` targets an unconnected \`app.<provider>.*\` tool, Muxo returns \`authHandoff.redirectUrl\`.
|
|
480
518
|
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\`.
|
|
481
519
|
|
|
482
|
-
## 3.
|
|
483
|
-
Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing topup 1000\`), and Muxo settles
|
|
520
|
+
## 3. Credit Billing & BYOK Support
|
|
521
|
+
Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing topup 1000\`), and Muxo settles upstream execution costs from Muxo's master accounts (\`fundingMode: "muxo_funded"\`), or users can configure their own BYOK provider keys for 0-credit execution.
|
|
484
522
|
`);
|
|
485
523
|
return;
|
|
486
524
|
}
|
|
@@ -507,7 +545,7 @@ Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing to
|
|
|
507
545
|
}
|
|
508
546
|
if (pathname === "/llms.txt" && req.method === "GET") {
|
|
509
547
|
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
|
|
510
|
-
res.end(`# Muxo\n> Unified execution,
|
|
548
|
+
res.end(`# Muxo\n> Unified agent execution across Connected Apps, Instant Tools, Cloud Infrastructure, Workspace Memory, and Safety Guardrails.\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`);
|
|
511
549
|
return;
|
|
512
550
|
}
|
|
513
551
|
// Serve Installable Muxo Plugin Manifests & Metadata (Portable OpenAI Agent Plugins + Codex + Claude)
|
|
@@ -616,6 +654,11 @@ Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing to
|
|
|
616
654
|
sendJson(res, 404, { ok: false, error: "Invalid or expired agent claim link" });
|
|
617
655
|
return;
|
|
618
656
|
}
|
|
657
|
+
const claimConsoleKey = store.createApiKey({
|
|
658
|
+
workspaceId: redeemed.workspace.id,
|
|
659
|
+
name: `Owner Claim Session (${redeemed.targetEmail})`,
|
|
660
|
+
environment: "live",
|
|
661
|
+
}).secretKey;
|
|
619
662
|
const wantsHtml = url.searchParams.get("format") !== "json" &&
|
|
620
663
|
String(req.headers.accept || "").includes("text/html");
|
|
621
664
|
if (wantsHtml) {
|
|
@@ -640,7 +683,7 @@ Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing to
|
|
|
640
683
|
<div class="badge">Ownership Bound</div>
|
|
641
684
|
<h1>Workspace Claimed</h1>
|
|
642
685
|
<p>Workspace <code>${redeemed.workspace.name}</code> (${redeemed.workspace.id}) claimed by <strong>${redeemed.targetEmail}</strong>.</p>
|
|
643
|
-
<a class="btn" href="/?claimed=${encodeURIComponent(redeemed.workspace.slug)}">Open Muxo Console →</a>
|
|
686
|
+
<a class="btn" href="/?claimed=${encodeURIComponent(redeemed.workspace.slug)}&api_key=${encodeURIComponent(claimConsoleKey)}">Open Muxo Console →</a>
|
|
644
687
|
</div>
|
|
645
688
|
</body>
|
|
646
689
|
</html>`);
|
|
@@ -649,6 +692,7 @@ Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing to
|
|
|
649
692
|
sendJson(res, 200, {
|
|
650
693
|
ok: true,
|
|
651
694
|
message: `Workspace '${redeemed.workspace.name}' claimed by ${redeemed.targetEmail}`,
|
|
695
|
+
apiKey: claimConsoleKey,
|
|
652
696
|
claim: redeemed,
|
|
653
697
|
});
|
|
654
698
|
return;
|
|
@@ -735,8 +779,8 @@ Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing to
|
|
|
735
779
|
});
|
|
736
780
|
return;
|
|
737
781
|
}
|
|
738
|
-
// Streamable HTTP MCP Endpoint (POST /mcp, GET /mcp, DELETE /mcp)
|
|
739
|
-
if (pathname === "/mcp" && req.method === "GET") {
|
|
782
|
+
// Streamable HTTP MCP Endpoint (POST /mcp, GET /mcp, HEAD /mcp, DELETE /mcp)
|
|
783
|
+
if (pathname === "/mcp" && (req.method === "GET" || req.method === "HEAD")) {
|
|
740
784
|
const accept = String(req.headers.accept || "");
|
|
741
785
|
const sessionId = String(req.headers["mcp-session-id"] || "") ||
|
|
742
786
|
`mcp_sess_${crypto.randomBytes(8).toString("hex")}`;
|
|
@@ -747,8 +791,11 @@ Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing to
|
|
|
747
791
|
Connection: "keep-alive",
|
|
748
792
|
"Mcp-Session-Id": sessionId,
|
|
749
793
|
"Access-Control-Allow-Origin": "*",
|
|
794
|
+
"Access-Control-Expose-Headers": "Mcp-Session-Id",
|
|
750
795
|
});
|
|
751
|
-
|
|
796
|
+
if (req.method !== "HEAD") {
|
|
797
|
+
res.write(`event: endpoint\ndata: ${JSON.stringify({ uri: `${config.baseUrl}/mcp`, sessionId })}\n\n`);
|
|
798
|
+
}
|
|
752
799
|
res.end();
|
|
753
800
|
return;
|
|
754
801
|
}
|
|
@@ -758,12 +805,12 @@ Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing to
|
|
|
758
805
|
protocolVersion: "2025-06-18",
|
|
759
806
|
serverInfo: {
|
|
760
807
|
name: "muxo-mcp-server",
|
|
761
|
-
version: "1.3.
|
|
808
|
+
version: "1.3.1",
|
|
762
809
|
},
|
|
763
810
|
instructions: MUXO_MCP_SERVER_INSTRUCTIONS,
|
|
764
811
|
toolsCount: MUXO_MCP_TOOLS.length,
|
|
765
812
|
skillsCount: getMuxoMcpSkills().length,
|
|
766
|
-
});
|
|
813
|
+
}, { "Mcp-Session-Id": sessionId });
|
|
767
814
|
return;
|
|
768
815
|
}
|
|
769
816
|
if (pathname === "/mcp" && req.method === "DELETE") {
|
|
@@ -860,7 +907,12 @@ Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing to
|
|
|
860
907
|
email,
|
|
861
908
|
baseUrl: config.baseUrl,
|
|
862
909
|
});
|
|
863
|
-
sendJson(res, 201, {
|
|
910
|
+
sendJson(res, 201, {
|
|
911
|
+
ok: true,
|
|
912
|
+
claim: { ...claim, ownerEmail: email },
|
|
913
|
+
...claim,
|
|
914
|
+
ownerEmail: email,
|
|
915
|
+
});
|
|
864
916
|
return;
|
|
865
917
|
}
|
|
866
918
|
// Microsoft Agent Governance Status & Audit Verification
|
|
@@ -1042,7 +1094,11 @@ Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing to
|
|
|
1042
1094
|
const planId = decodeURIComponent(planExecuteMatch[1]);
|
|
1043
1095
|
const plan = engine.getPlan(ctx, planId);
|
|
1044
1096
|
const result = await engine.executePlanForRisk(ctx, planId, plan.riskLevel);
|
|
1045
|
-
sendJson(res, 200, {
|
|
1097
|
+
sendJson(res, 200, {
|
|
1098
|
+
ok: true,
|
|
1099
|
+
...result,
|
|
1100
|
+
settlement: result.receipt?.supplierSettlement || null,
|
|
1101
|
+
});
|
|
1046
1102
|
return;
|
|
1047
1103
|
}
|
|
1048
1104
|
// Runs & Receipts
|
|
@@ -1176,6 +1232,8 @@ Users purchase Muxo Credits (\`POST /api/v1/billing/topup\` or \`muxo billing to
|
|
|
1176
1232
|
sendJson(res, 200, {
|
|
1177
1233
|
ok: true,
|
|
1178
1234
|
creditsAdded: credits,
|
|
1235
|
+
creditBalance: updatedWorkspace.creditsBalance,
|
|
1236
|
+
creditsBalance: updatedWorkspace.creditsBalance,
|
|
1179
1237
|
usdPaid: Number(usdPaid),
|
|
1180
1238
|
workspace: updatedWorkspace,
|
|
1181
1239
|
settlementSummary: store.getSupplierSettlementSummary(ctx.workspace.id),
|
package/dist/store.d.ts
CHANGED
package/dist/store.js
CHANGED
|
@@ -333,10 +333,16 @@ export class MuxoStore {
|
|
|
333
333
|
description: "Free Plan initial monthly allowance (1,000 actions + 250 trial credits)",
|
|
334
334
|
});
|
|
335
335
|
const sessionToken = this.createSession(userId, workspaceId);
|
|
336
|
+
const defaultKey = this.createApiKey({
|
|
337
|
+
workspaceId,
|
|
338
|
+
name: "Default Live Key",
|
|
339
|
+
environment: "live",
|
|
340
|
+
});
|
|
336
341
|
return {
|
|
337
342
|
user: this.getUser(userId),
|
|
338
343
|
workspace: this.getWorkspace(workspaceId),
|
|
339
344
|
sessionToken,
|
|
345
|
+
apiKey: defaultKey.secretKey,
|
|
340
346
|
};
|
|
341
347
|
}
|
|
342
348
|
loginUser(email, password) {
|
|
@@ -787,7 +793,8 @@ export class MuxoStore {
|
|
|
787
793
|
SET monthly_actions_used = ?, credits_balance = ?, updated_at = ?
|
|
788
794
|
WHERE id = ?`)
|
|
789
795
|
.run(newActionsUsed, newCreditsBalance, now, params.workspaceId);
|
|
790
|
-
const
|
|
796
|
+
const byokUsed = this.hasByokForLane(params.workspaceId, run.lane, run.toolSlug);
|
|
797
|
+
const settlement = this.computeSupplierSettlement(run.lane, run.toolSlug, params.creditsMetered, byokUsed ? "settled_by_customer_byok" : "settled_by_muxo_master_wallet", params.workspaceId);
|
|
791
798
|
this.addLedgerEntry({
|
|
792
799
|
workspaceId: params.workspaceId,
|
|
793
800
|
kind: "run_deduction",
|
|
@@ -795,7 +802,9 @@ export class MuxoStore {
|
|
|
795
802
|
creditsDelta: -params.creditsMetered,
|
|
796
803
|
balanceAfter: newCreditsBalance,
|
|
797
804
|
referenceId: run.id,
|
|
798
|
-
description:
|
|
805
|
+
description: byokUsed
|
|
806
|
+
? `Executed ${run.toolSlug} (${run.lane}) — BYOK 0-credit execution (Customer's own ${settlement.supplierName} key)`
|
|
807
|
+
: `Executed ${run.toolSlug} (${run.lane}) — User paid Muxo ${params.creditsMetered} credits ($${(settlement.userRetailChargeCents / 100).toFixed(2)}) -> Muxo paid ${settlement.supplierName} ($${(settlement.supplierWholesalePayableCents / 100).toFixed(2)})`,
|
|
799
808
|
});
|
|
800
809
|
}
|
|
801
810
|
const receipt = this.issueReceipt({
|
|
@@ -1004,7 +1013,9 @@ export class MuxoStore {
|
|
|
1004
1013
|
computeSupplierSettlement(lane, toolSlug, creditCost, settlementStatus = "settled_by_muxo_master_wallet", workspaceId) {
|
|
1005
1014
|
const useByok = settlementStatus === "settled_by_customer_byok" ||
|
|
1006
1015
|
settlementStatus === "planned_customer_byok" ||
|
|
1007
|
-
(
|
|
1016
|
+
(Number(creditCost || 0) === 0 && workspaceId
|
|
1017
|
+
? this.hasByokForLane(workspaceId, lane, toolSlug)
|
|
1018
|
+
: false);
|
|
1008
1019
|
const upstreamProvider = toolSlug.split(".")[1] || lane;
|
|
1009
1020
|
if (useByok) {
|
|
1010
1021
|
const isPlanned = settlementStatus === "planned_muxo_master_wallet" ||
|
|
@@ -1141,7 +1152,12 @@ export class MuxoStore {
|
|
|
1141
1152
|
if (kind === "run_deduction" && refId) {
|
|
1142
1153
|
const run = this.getRun(workspaceId, refId);
|
|
1143
1154
|
if (run) {
|
|
1144
|
-
|
|
1155
|
+
const isByokEntry = creditsDelta === 0 &&
|
|
1156
|
+
(String(r.description || "").includes("BYOK") ||
|
|
1157
|
+
this.hasByokForLane(workspaceId, run.lane, run.toolSlug));
|
|
1158
|
+
supplierSettlement = this.computeSupplierSettlement(run.lane, run.toolSlug, Math.abs(creditsDelta), isByokEntry
|
|
1159
|
+
? "settled_by_customer_byok"
|
|
1160
|
+
: "settled_by_muxo_master_wallet", workspaceId);
|
|
1145
1161
|
}
|
|
1146
1162
|
}
|
|
1147
1163
|
return {
|