@muxoai/platform 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -2
- package/dist/clerk.d.ts +35 -0
- package/dist/clerk.js +201 -0
- package/dist/cli.js +456 -39
- package/dist/engine.d.ts +21 -1
- package/dist/engine.js +245 -23
- package/dist/mcp.js +2 -1
- package/dist/policy.d.ts +9 -0
- package/dist/policy.js +73 -0
- package/dist/providers/composio-instant.d.ts +3 -0
- package/dist/providers/composio-instant.js +629 -530
- package/dist/providers/microsoft-governance.d.ts +61 -2
- package/dist/providers/microsoft-governance.js +458 -24
- package/dist/providers/stripe-projects.d.ts +4 -1
- package/dist/providers/stripe-projects.js +64 -10
- package/dist/providers/supermemory.d.ts +26 -5
- package/dist/providers/supermemory.js +136 -26
- package/dist/sdk.d.ts +170 -2
- package/dist/sdk.js +115 -4
- package/dist/server.js +178 -17
- package/dist/store.d.ts +25 -1
- package/dist/store.js +236 -3
- package/dist/types.d.ts +86 -0
- package/dist/ui/console-html.d.ts +23 -0
- package/dist/ui/console-html.js +2440 -2226
- package/dist/ui/design-tokens.d.ts +177 -0
- package/dist/ui/design-tokens.js +210 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,10 @@ import readline from "node:readline";
|
|
|
6
6
|
import { getConfig } from "./config.js";
|
|
7
7
|
import { MuxoEngine } from "./engine.js";
|
|
8
8
|
import { handleJsonRpcMcpRequest } from "./mcp.js";
|
|
9
|
+
import { sanitizePolicyPatch } from "./policy.js";
|
|
10
|
+
import { RING_LABELS } from "./providers/microsoft-governance.js";
|
|
9
11
|
import { BYOK_PROVIDER_CATALOG, MuxoStore } from "./store.js";
|
|
12
|
+
import { MUXO_VERSION } from "./version.js";
|
|
10
13
|
function promptUserLine(question) {
|
|
11
14
|
return new Promise((resolve) => {
|
|
12
15
|
const rl = readline.createInterface({
|
|
@@ -74,8 +77,8 @@ async function runCli() {
|
|
|
74
77
|
const cmd = positional[0] || "help";
|
|
75
78
|
if (flags.version || flags.v || cmd === "version") {
|
|
76
79
|
console.log(flags.json
|
|
77
|
-
? JSON.stringify({ ok: true, name: "@muxoai/cli", version:
|
|
78
|
-
:
|
|
80
|
+
? JSON.stringify({ ok: true, name: "@muxoai/cli", version: MUXO_VERSION }, null, 2)
|
|
81
|
+
: MUXO_VERSION);
|
|
79
82
|
return;
|
|
80
83
|
}
|
|
81
84
|
const savedCliConfig = readCliAuthConfig();
|
|
@@ -85,7 +88,7 @@ async function runCli() {
|
|
|
85
88
|
"";
|
|
86
89
|
const explicitUrlFlag = (typeof flags.url === "string"
|
|
87
90
|
? flags.url
|
|
88
|
-
: process.env.MUXO_API_URL || "").replace(/\/+$/, "");
|
|
91
|
+
: process.env.MUXO_API_URL || process.env.MUXO_CLOUD_URL || "").replace(/\/+$/, "");
|
|
89
92
|
const useLocalDb = Boolean((process.env.MUXO_DB_PATH || flags.local) && !explicitUrlFlag);
|
|
90
93
|
const remoteUrl = useLocalDb
|
|
91
94
|
? ""
|
|
@@ -107,6 +110,9 @@ async function runCli() {
|
|
|
107
110
|
body: opts?.body !== undefined ? JSON.stringify(opts.body) : undefined,
|
|
108
111
|
});
|
|
109
112
|
const data = (await res.json().catch(() => ({})));
|
|
113
|
+
if (opts?.acceptPaymentRequired && res.status === 402 && data.checkoutUrl) {
|
|
114
|
+
return data;
|
|
115
|
+
}
|
|
110
116
|
if (!res.ok && data.error) {
|
|
111
117
|
throw new Error(String(data.error));
|
|
112
118
|
}
|
|
@@ -168,6 +174,23 @@ async function runCli() {
|
|
|
168
174
|
};
|
|
169
175
|
return { store, engine: getEngine(), ctx, tokenAuth };
|
|
170
176
|
};
|
|
177
|
+
const maskKey = (key) => `${key.slice(0, 14)}…`;
|
|
178
|
+
// Hosted Muxo answers purchases with 402 + a Stripe Checkout URL; a self-hosted dev server may grant credits directly.
|
|
179
|
+
const printBillingResult = (data) => {
|
|
180
|
+
if (!data.checkoutUrl) {
|
|
181
|
+
console.log(JSON.stringify(data, null, 2));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
console.log(JSON.stringify({
|
|
185
|
+
ok: true,
|
|
186
|
+
paymentRequired: true,
|
|
187
|
+
kind: data.kind,
|
|
188
|
+
credits: data.credits,
|
|
189
|
+
checkoutUrl: data.checkoutUrl,
|
|
190
|
+
sessionId: data.sessionId,
|
|
191
|
+
next: `Open checkoutUrl to pay with Stripe. Muxo adds the credits once Stripe confirms the payment. Check with: muxo billing verify ${data.sessionId}`,
|
|
192
|
+
}, null, 2));
|
|
193
|
+
};
|
|
171
194
|
// CLI Login / Autonomous External Signup (`muxo login`)
|
|
172
195
|
if (cmd === "login" || cmd === "signup") {
|
|
173
196
|
const explicitKey = typeof flags["api-key"] === "string"
|
|
@@ -200,6 +223,7 @@ async function runCli() {
|
|
|
200
223
|
configPath: cfgPath,
|
|
201
224
|
workspace: ws,
|
|
202
225
|
...authPayload,
|
|
226
|
+
apiKey: maskKey(explicitKey),
|
|
203
227
|
}, null, 2));
|
|
204
228
|
return;
|
|
205
229
|
}
|
|
@@ -224,6 +248,7 @@ async function runCli() {
|
|
|
224
248
|
mode: "api_key",
|
|
225
249
|
configPath: cfgPath,
|
|
226
250
|
...authPayload,
|
|
251
|
+
apiKey: maskKey(explicitKey),
|
|
227
252
|
}, null, 2));
|
|
228
253
|
return;
|
|
229
254
|
}
|
|
@@ -281,11 +306,52 @@ async function runCli() {
|
|
|
281
306
|
return;
|
|
282
307
|
}
|
|
283
308
|
// One-command setup (`muxo setup` / `muxo init` / `muxo install`):
|
|
284
|
-
// 1. Auto-creates or loads ~/.muxo/config.json with 250 starter credits
|
|
309
|
+
// 1. Auto-creates or loads ~/.muxo/config.json with 250 starter credits (or binds an explicit --api-key)
|
|
285
310
|
// 2. Writes .mcp.json in target directory (or ~/.cursor/mcp.json & ~/.factory/mcp.json if present)
|
|
286
311
|
if (cmd === "setup" || cmd === "init" || cmd === "install") {
|
|
312
|
+
const explicitKey = typeof flags["api-key"] === "string"
|
|
313
|
+
? flags["api-key"].trim()
|
|
314
|
+
: typeof flags.key === "string"
|
|
315
|
+
? flags.key.trim()
|
|
316
|
+
: "";
|
|
287
317
|
let activeConfig = savedCliConfig;
|
|
288
|
-
if (
|
|
318
|
+
if (explicitKey) {
|
|
319
|
+
const agentName = typeof flags.name === "string" ? flags.name : "Muxo Agent";
|
|
320
|
+
if (remoteUrl) {
|
|
321
|
+
apiKeyFlag = explicitKey;
|
|
322
|
+
const orgRes = (await remoteFetch("/api/v1/organization").catch(() => ({})));
|
|
323
|
+
const org = orgRes?.organization || orgRes?.workspace || {};
|
|
324
|
+
activeConfig = {
|
|
325
|
+
authenticated: true,
|
|
326
|
+
apiKey: explicitKey,
|
|
327
|
+
workspaceId: org.id || "ws_remote",
|
|
328
|
+
workspaceName: org.name || agentName,
|
|
329
|
+
agentId: "usr_remote",
|
|
330
|
+
governanceDid: org.governanceDid || `did:muxo:${org.id || "ws_remote"}`,
|
|
331
|
+
supermemoryNamespace: `muxo_${org.id || "ws_remote"}`,
|
|
332
|
+
updatedAt: new Date().toISOString(),
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
const { store, engine } = getLocalContext();
|
|
337
|
+
const auth = store.resolveAuthToken(explicitKey);
|
|
338
|
+
if (!auth) {
|
|
339
|
+
throw new Error(`Invalid API key provided to muxo setup: ${explicitKey.slice(0, 12)}...`);
|
|
340
|
+
}
|
|
341
|
+
activeConfig = {
|
|
342
|
+
authenticated: true,
|
|
343
|
+
apiKey: explicitKey,
|
|
344
|
+
workspaceId: auth.workspace.id,
|
|
345
|
+
workspaceName: auth.workspace.name,
|
|
346
|
+
agentId: auth.user.id,
|
|
347
|
+
governanceDid: engine.governance.getStatus(auth.workspace).agentDid,
|
|
348
|
+
supermemoryNamespace: engine.supermemory.getWorkspaceNamespace(auth.workspace.id),
|
|
349
|
+
updatedAt: new Date().toISOString(),
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
writeCliAuthConfig(activeConfig);
|
|
353
|
+
}
|
|
354
|
+
else if (!activeConfig || !activeConfig.apiKey || flags.fresh) {
|
|
289
355
|
const agentName = typeof flags.name === "string" ? flags.name : "Muxo Agent";
|
|
290
356
|
if (remoteUrl) {
|
|
291
357
|
const { authPayload } = await signupHostedWorkspace(agentName, "muxo-setup");
|
|
@@ -310,6 +376,7 @@ async function runCli() {
|
|
|
310
376
|
}
|
|
311
377
|
writeCliAuthConfig(activeConfig);
|
|
312
378
|
}
|
|
379
|
+
const ensuredConfig = activeConfig;
|
|
313
380
|
const mcpServerUrl = remoteUrl
|
|
314
381
|
? `${remoteUrl}/mcp`
|
|
315
382
|
: "https://api.muxo.ai/mcp";
|
|
@@ -317,7 +384,7 @@ async function runCli() {
|
|
|
317
384
|
type: "http",
|
|
318
385
|
url: mcpServerUrl,
|
|
319
386
|
headers: {
|
|
320
|
-
Authorization: `Bearer ${
|
|
387
|
+
Authorization: `Bearer ${ensuredConfig.apiKey}`,
|
|
321
388
|
},
|
|
322
389
|
};
|
|
323
390
|
const targetDir = typeof flags.dir === "string" ? path.resolve(flags.dir) : process.cwd();
|
|
@@ -344,9 +411,9 @@ async function runCli() {
|
|
|
344
411
|
mergeMcpJsonFile(path.join(targetDir, ".mcp.json"));
|
|
345
412
|
const resultPayload = {
|
|
346
413
|
ok: true,
|
|
347
|
-
workspaceId:
|
|
348
|
-
workspaceName:
|
|
349
|
-
apiKey:
|
|
414
|
+
workspaceId: ensuredConfig.workspaceId,
|
|
415
|
+
workspaceName: ensuredConfig.workspaceName,
|
|
416
|
+
apiKey: ensuredConfig.apiKey,
|
|
350
417
|
mcpUrl: mcpServerUrl,
|
|
351
418
|
configPath: getCliConfigPath(),
|
|
352
419
|
configuredFiles: writtenFiles,
|
|
@@ -356,8 +423,8 @@ async function runCli() {
|
|
|
356
423
|
}
|
|
357
424
|
else {
|
|
358
425
|
console.log(`\n✓ Muxo is ready!`);
|
|
359
|
-
console.log(` Workspace : ${
|
|
360
|
-
console.log(` API Key : ${
|
|
426
|
+
console.log(` Workspace : ${ensuredConfig.workspaceName} (${ensuredConfig.workspaceId})`);
|
|
427
|
+
console.log(` API Key : ${maskKey(ensuredConfig.apiKey)} (saved in ${getCliConfigPath()})`);
|
|
361
428
|
console.log(` MCP URL : ${mcpServerUrl}`);
|
|
362
429
|
console.log(` MCP Config: ${writtenFiles.join(", ")}`);
|
|
363
430
|
console.log(`\nTry it now:`);
|
|
@@ -474,15 +541,193 @@ async function runCli() {
|
|
|
474
541
|
return;
|
|
475
542
|
}
|
|
476
543
|
if (cmd === "harness") {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
544
|
+
const checks = [];
|
|
545
|
+
const skip = (reason) => ({ skip: reason });
|
|
546
|
+
const runCheck = async (id, name, fn) => {
|
|
547
|
+
const started = Date.now();
|
|
548
|
+
try {
|
|
549
|
+
const out = await fn();
|
|
550
|
+
checks.push(typeof out === "string"
|
|
551
|
+
? { id, name, status: "pass", detail: out, ms: Date.now() - started }
|
|
552
|
+
: { id, name, status: "skip", detail: out.skip, ms: Date.now() - started });
|
|
553
|
+
}
|
|
554
|
+
catch (err) {
|
|
555
|
+
checks.push({
|
|
556
|
+
id,
|
|
557
|
+
name,
|
|
558
|
+
status: "fail",
|
|
559
|
+
detail: String(err?.message || err),
|
|
560
|
+
ms: Date.now() - started,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
const assertCheck = (cond, message) => {
|
|
565
|
+
if (!cond)
|
|
566
|
+
throw new Error(message);
|
|
567
|
+
};
|
|
568
|
+
const noKeyHint = "No API key. Run `muxo login --signup` to create a workspace.";
|
|
569
|
+
let workspaceId = savedCliConfig?.workspaceId || null;
|
|
570
|
+
if (remoteUrl) {
|
|
571
|
+
let mcpSessionId = "";
|
|
572
|
+
const harnessFetch = async (pathname, init = {}) => {
|
|
573
|
+
const headers = { Accept: "application/json" };
|
|
574
|
+
if (init.body !== undefined)
|
|
575
|
+
headers["Content-Type"] = "application/json";
|
|
576
|
+
if (init.auth !== false && apiKeyFlag)
|
|
577
|
+
headers.Authorization = `Bearer ${apiKeyFlag}`;
|
|
578
|
+
if (pathname === "/mcp" && mcpSessionId)
|
|
579
|
+
headers["Mcp-Session-Id"] = mcpSessionId;
|
|
580
|
+
return fetch(`${remoteUrl}${pathname}`, {
|
|
581
|
+
method: init.method || "GET",
|
|
582
|
+
headers,
|
|
583
|
+
body: init.body !== undefined ? JSON.stringify(init.body) : undefined,
|
|
584
|
+
signal: AbortSignal.timeout(15_000),
|
|
585
|
+
});
|
|
586
|
+
};
|
|
587
|
+
const harnessJson = async (pathname, init) => {
|
|
588
|
+
const res = await harnessFetch(pathname, init);
|
|
589
|
+
const data = (await res.json().catch(() => ({})));
|
|
590
|
+
if (!res.ok) {
|
|
591
|
+
throw new Error(`HTTP ${res.status}${data.error ? `: ${data.error}` : ""}`);
|
|
592
|
+
}
|
|
593
|
+
return data;
|
|
594
|
+
};
|
|
595
|
+
const mcpCall = async (id, method, params = {}) => {
|
|
596
|
+
const res = await harnessFetch("/mcp", {
|
|
597
|
+
method: "POST",
|
|
598
|
+
body: { jsonrpc: "2.0", id, method, params },
|
|
599
|
+
});
|
|
600
|
+
const sid = res.headers.get("mcp-session-id");
|
|
601
|
+
if (sid)
|
|
602
|
+
mcpSessionId = sid;
|
|
603
|
+
const data = (await res.json().catch(() => ({})));
|
|
604
|
+
if (!res.ok || data.error) {
|
|
605
|
+
throw new Error(data.error?.message || `HTTP ${res.status}`);
|
|
606
|
+
}
|
|
607
|
+
return data.result;
|
|
608
|
+
};
|
|
609
|
+
await runCheck("api_health", "API is reachable", async () => {
|
|
610
|
+
const health = await harnessJson("/health", { auth: false });
|
|
611
|
+
assertCheck(health.ok === true, "Health endpoint did not report ok");
|
|
612
|
+
return `${health.service || "muxo"} ${health.version || ""} at ${remoteUrl}`.trim();
|
|
613
|
+
});
|
|
614
|
+
await runCheck("agent_skill", "Agent skill is published", async () => {
|
|
615
|
+
const res = await harnessFetch("/skill.md", { auth: false });
|
|
616
|
+
assertCheck(res.ok, `HTTP ${res.status}`);
|
|
617
|
+
const body = await res.text();
|
|
618
|
+
assertCheck(/execute_(read|write)/.test(body), "skill.md is missing the execute_* tools");
|
|
619
|
+
return `${remoteUrl}/skill.md (${body.length.toLocaleString()} bytes)`;
|
|
620
|
+
});
|
|
621
|
+
await runCheck("mcp_initialize", "MCP server accepts a session", async () => {
|
|
622
|
+
const result = await mcpCall(1, "initialize", {
|
|
623
|
+
protocolVersion: "2025-06-18",
|
|
624
|
+
capabilities: {},
|
|
625
|
+
clientInfo: { name: "muxo-cli-harness", version: MUXO_VERSION },
|
|
626
|
+
});
|
|
627
|
+
assertCheck(result?.serverInfo?.name, "initialize returned no serverInfo");
|
|
628
|
+
return `${result.serverInfo.name} ${result.serverInfo.version || ""} (protocol ${result.protocolVersion})`.trim();
|
|
629
|
+
});
|
|
630
|
+
await runCheck("mcp_tools", "MCP tools are listed", async () => {
|
|
631
|
+
const result = await mcpCall(2, "tools/list");
|
|
632
|
+
const count = Array.isArray(result?.tools) ? result.tools.length : 0;
|
|
633
|
+
assertCheck(count > 0, "tools/list returned no tools");
|
|
634
|
+
return `${count} tools`;
|
|
635
|
+
});
|
|
636
|
+
await runCheck("auth", "API key opens a workspace", async () => {
|
|
637
|
+
if (!apiKeyFlag)
|
|
638
|
+
return skip(noKeyHint);
|
|
639
|
+
const boot = await harnessJson("/api/v1/bootstrap");
|
|
640
|
+
const ws = { ...(boot.organization || {}), ...(boot.profile?.workspace || {}) };
|
|
641
|
+
assertCheck(ws.id, "bootstrap returned no workspace");
|
|
642
|
+
workspaceId = String(ws.id);
|
|
643
|
+
return `${ws.name || ws.id} (${ws.tier || "free"})`;
|
|
644
|
+
});
|
|
645
|
+
await runCheck("governance", "Agents are allowed to act", async () => {
|
|
646
|
+
if (!apiKeyFlag)
|
|
647
|
+
return skip(noKeyHint);
|
|
648
|
+
const res = await harnessJson("/api/v1/governance");
|
|
649
|
+
const g = res.governance || {};
|
|
650
|
+
if (g.killSwitch?.active) {
|
|
651
|
+
throw new Error(`Kill switch is on${g.killSwitch.reason ? ` (${g.killSwitch.reason})` : ""}. Run \`muxo governance resume\`.`);
|
|
652
|
+
}
|
|
653
|
+
const chainOk = g.auditChain?.chainVerified ?? g.auditChainIntegrity ?? g.auditIntegrityValid;
|
|
654
|
+
assertCheck(chainOk !== false, "Audit hash chain failed verification");
|
|
655
|
+
return `Running, audit chain verified, policy ${res.workspacePolicy?.mode || "enforce"}`;
|
|
656
|
+
});
|
|
657
|
+
await runCheck("catalog", "Tool catalog search works", async () => {
|
|
658
|
+
if (!apiKeyFlag)
|
|
659
|
+
return skip(noKeyHint);
|
|
660
|
+
const res = await harnessJson("/api/v1/tools?lane=composio_instant&limit=5");
|
|
661
|
+
const count = Array.isArray(res.tools) ? res.tools.length : 0;
|
|
662
|
+
assertCheck(count > 0, "Catalog search returned no tools");
|
|
663
|
+
return `${count} instant tools returned`;
|
|
664
|
+
});
|
|
480
665
|
}
|
|
666
|
+
else {
|
|
667
|
+
const local = getLocalContext();
|
|
668
|
+
workspaceId = local.ctx.workspace.id;
|
|
669
|
+
await runCheck("local_store", "Local workspace database opens", async () => {
|
|
670
|
+
const ws = local.store.getWorkspace(local.ctx.workspace.id);
|
|
671
|
+
assertCheck(ws, "Workspace not found in local database");
|
|
672
|
+
return `${ws.name} at ${config.dbPath}`;
|
|
673
|
+
});
|
|
674
|
+
await runCheck("mcp_initialize", "MCP server accepts a session", async () => {
|
|
675
|
+
const res = await handleJsonRpcMcpRequest(local.engine, local.ctx, {
|
|
676
|
+
jsonrpc: "2.0",
|
|
677
|
+
id: 1,
|
|
678
|
+
method: "initialize",
|
|
679
|
+
params: { protocolVersion: "2025-06-18", capabilities: {} },
|
|
680
|
+
});
|
|
681
|
+
const info = res?.result?.serverInfo;
|
|
682
|
+
assertCheck(info?.name, "initialize returned no serverInfo");
|
|
683
|
+
return `${info.name} ${info.version || ""}`.trim();
|
|
684
|
+
});
|
|
685
|
+
await runCheck("mcp_tools", "MCP tools are listed", async () => {
|
|
686
|
+
const res = await handleJsonRpcMcpRequest(local.engine, local.ctx, {
|
|
687
|
+
jsonrpc: "2.0",
|
|
688
|
+
id: 2,
|
|
689
|
+
method: "tools/list",
|
|
690
|
+
});
|
|
691
|
+
const count = (res?.result?.tools || []).length;
|
|
692
|
+
assertCheck(count > 0, "tools/list returned no tools");
|
|
693
|
+
return `${count} tools`;
|
|
694
|
+
});
|
|
695
|
+
await runCheck("auth", "API key opens a workspace", async () => {
|
|
696
|
+
if (!apiKeyFlag)
|
|
697
|
+
return skip("No API key. Using the local default workspace.");
|
|
698
|
+
assertCheck(local.tokenAuth, "API key is not valid for this local database");
|
|
699
|
+
return local.ctx.workspace.name;
|
|
700
|
+
});
|
|
701
|
+
await runCheck("governance", "Agents are allowed to act", async () => {
|
|
702
|
+
const ws = local.store.getWorkspace(local.ctx.workspace.id) || local.ctx.workspace;
|
|
703
|
+
const status = local.engine.governance.getGovernanceStatus(ws);
|
|
704
|
+
if (status.killSwitch?.active) {
|
|
705
|
+
throw new Error("Kill switch is on. Run `muxo governance resume`.");
|
|
706
|
+
}
|
|
707
|
+
assertCheck(status.auditChain?.chainVerified !== false, "Audit hash chain failed verification");
|
|
708
|
+
return `Running, audit chain verified, policy ${ws.policy.mode}`;
|
|
709
|
+
});
|
|
710
|
+
await runCheck("catalog", "Tool catalog search works", async () => {
|
|
711
|
+
const res = await local.engine.searchTools({ lane: "composio_instant", limit: 5 });
|
|
712
|
+
assertCheck(res.tools.length > 0, "Catalog search returned no tools");
|
|
713
|
+
return `${res.tools.length} instant tools returned`;
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
const passed = checks.filter((c) => c.status === "pass").length;
|
|
717
|
+
const failed = checks.filter((c) => c.status === "fail").length;
|
|
718
|
+
const skipped = checks.filter((c) => c.status === "skip").length;
|
|
719
|
+
if (failed > 0)
|
|
720
|
+
process.exitCode = 1;
|
|
481
721
|
console.log(JSON.stringify({
|
|
482
|
-
ok:
|
|
483
|
-
version:
|
|
484
|
-
|
|
485
|
-
|
|
722
|
+
ok: failed === 0,
|
|
723
|
+
version: MUXO_VERSION,
|
|
724
|
+
mode: remoteUrl ? "hosted" : "local",
|
|
725
|
+
apiUrl: remoteUrl || null,
|
|
726
|
+
passed,
|
|
727
|
+
failed,
|
|
728
|
+
skipped,
|
|
729
|
+
total: checks.length,
|
|
730
|
+
checks,
|
|
486
731
|
workspaceId,
|
|
487
732
|
data: {
|
|
488
733
|
mcpServers: {
|
|
@@ -960,8 +1205,9 @@ async function runCli() {
|
|
|
960
1205
|
const data = await remoteFetch("/api/v1/billing/topup", {
|
|
961
1206
|
method: "POST",
|
|
962
1207
|
body: { credits },
|
|
1208
|
+
acceptPaymentRequired: true,
|
|
963
1209
|
});
|
|
964
|
-
|
|
1210
|
+
printBillingResult(data);
|
|
965
1211
|
return;
|
|
966
1212
|
}
|
|
967
1213
|
const { store, ctx } = getLocalContext();
|
|
@@ -988,8 +1234,9 @@ async function runCli() {
|
|
|
988
1234
|
const data = await remoteFetch("/api/v1/billing/upgrade", {
|
|
989
1235
|
method: "POST",
|
|
990
1236
|
body: { tier: "starter", bonusCredits: 1000 },
|
|
1237
|
+
acceptPaymentRequired: true,
|
|
991
1238
|
});
|
|
992
|
-
|
|
1239
|
+
printBillingResult(data);
|
|
993
1240
|
return;
|
|
994
1241
|
}
|
|
995
1242
|
const { store, ctx } = getLocalContext();
|
|
@@ -1173,6 +1420,9 @@ async function runCli() {
|
|
|
1173
1420
|
method: "POST",
|
|
1174
1421
|
body: {
|
|
1175
1422
|
prompt: promptText,
|
|
1423
|
+
dryRun: planOnly,
|
|
1424
|
+
planOnly,
|
|
1425
|
+
autoApprove,
|
|
1176
1426
|
autoExecute: !planOnly,
|
|
1177
1427
|
approveRisky: autoApprove,
|
|
1178
1428
|
fundingMode,
|
|
@@ -1257,21 +1507,18 @@ async function runCli() {
|
|
|
1257
1507
|
}
|
|
1258
1508
|
if (choice === "3") {
|
|
1259
1509
|
const action = (await promptUserLine("Type 'upgrade' for Starter Plan or credit amount (default 1000): ")).toLowerCase();
|
|
1260
|
-
|
|
1261
|
-
|
|
1510
|
+
const up = action === "upgrade"
|
|
1511
|
+
? await remoteFetch("/api/v1/billing/upgrade", {
|
|
1262
1512
|
method: "POST",
|
|
1263
1513
|
body: { tier: "starter", bonusCredits: 1000 },
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
else {
|
|
1268
|
-
const cr = Math.max(100, Number(action) || 1000);
|
|
1269
|
-
const up = await remoteFetch("/api/v1/billing/topup", {
|
|
1514
|
+
acceptPaymentRequired: true,
|
|
1515
|
+
})
|
|
1516
|
+
: await remoteFetch("/api/v1/billing/topup", {
|
|
1270
1517
|
method: "POST",
|
|
1271
|
-
body: { credits:
|
|
1518
|
+
body: { credits: Math.max(100, Number(action) || 1000) },
|
|
1519
|
+
acceptPaymentRequired: true,
|
|
1272
1520
|
});
|
|
1273
|
-
|
|
1274
|
-
}
|
|
1521
|
+
printBillingResult(up);
|
|
1275
1522
|
return;
|
|
1276
1523
|
}
|
|
1277
1524
|
if (choice === "4") {
|
|
@@ -1410,6 +1657,47 @@ async function runCli() {
|
|
|
1410
1657
|
}
|
|
1411
1658
|
if (cmd === "memory") {
|
|
1412
1659
|
const sub = positional[1];
|
|
1660
|
+
if (sub === "facts") {
|
|
1661
|
+
const query = positional.slice(2).join(" ") || (typeof flags.query === "string" ? flags.query : "");
|
|
1662
|
+
const includeHistorical = !flags.current;
|
|
1663
|
+
if (remoteUrl) {
|
|
1664
|
+
const params = new URLSearchParams({ historical: includeHistorical ? "true" : "false" });
|
|
1665
|
+
if (query)
|
|
1666
|
+
params.set("query", query);
|
|
1667
|
+
const res = await remoteFetch(`/api/v1/memory/facts?${params.toString()}`);
|
|
1668
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
const { store, ctx } = getLocalContext();
|
|
1672
|
+
const facts = store.listTemporalFacts(ctx.workspace.id, {
|
|
1673
|
+
includeHistorical,
|
|
1674
|
+
query: query || undefined,
|
|
1675
|
+
});
|
|
1676
|
+
console.log(JSON.stringify({
|
|
1677
|
+
ok: true,
|
|
1678
|
+
activeFacts: facts.filter((f) => f.validTo === null),
|
|
1679
|
+
historicalFacts: facts.filter((f) => f.validTo !== null),
|
|
1680
|
+
facts,
|
|
1681
|
+
}, null, 2));
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
if (sub === "forget") {
|
|
1685
|
+
const query = positional.slice(2).join(" ").trim() || String(flags.query || "").trim();
|
|
1686
|
+
if (!query)
|
|
1687
|
+
throw new Error("Usage: muxo memory forget <text>");
|
|
1688
|
+
if (remoteUrl) {
|
|
1689
|
+
const res = await remoteFetch("/api/v1/memory/forget", {
|
|
1690
|
+
method: "POST",
|
|
1691
|
+
body: { query },
|
|
1692
|
+
});
|
|
1693
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1694
|
+
return;
|
|
1695
|
+
}
|
|
1696
|
+
const { engine, ctx } = getLocalContext();
|
|
1697
|
+
const pruned = await engine.forgetWorkspaceMemoryMatching(ctx, query);
|
|
1698
|
+
console.log(JSON.stringify({ ok: true, ...pruned }, null, 2));
|
|
1699
|
+
return;
|
|
1700
|
+
}
|
|
1413
1701
|
if (sub === "add") {
|
|
1414
1702
|
const content = positional.slice(2).join(" ") || String(flags.content || "");
|
|
1415
1703
|
if (!content)
|
|
@@ -1433,8 +1721,26 @@ async function runCli() {
|
|
|
1433
1721
|
console.log(JSON.stringify({ ok: true, memory: entry }, null, 2));
|
|
1434
1722
|
return;
|
|
1435
1723
|
}
|
|
1724
|
+
if (sub === "delete" || sub === "rm" || sub === "remove") {
|
|
1725
|
+
const id = positional[2] || String(flags.id || "");
|
|
1726
|
+
if (!id)
|
|
1727
|
+
throw new Error("Usage: muxo memory delete <memory_id>");
|
|
1728
|
+
if (remoteUrl) {
|
|
1729
|
+
const res = await remoteFetch(`/api/v1/memory/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
1730
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1731
|
+
return;
|
|
1732
|
+
}
|
|
1733
|
+
const { engine, ctx } = getLocalContext();
|
|
1734
|
+
const deleted = await engine.deleteWorkspaceMemory(ctx, id);
|
|
1735
|
+
console.log(JSON.stringify({ ok: true, ...deleted }, null, 2));
|
|
1736
|
+
return;
|
|
1737
|
+
}
|
|
1436
1738
|
if (remoteUrl) {
|
|
1437
|
-
const
|
|
1739
|
+
const query = sub === "recall" || sub === "search"
|
|
1740
|
+
? positional.slice(2).join(" ") || flags.query || undefined
|
|
1741
|
+
: positional.slice(1).join(" ") || flags.query || undefined;
|
|
1742
|
+
const suffix = query ? `?query=${encodeURIComponent(query)}` : "";
|
|
1743
|
+
const res = await remoteFetch(`/api/v1/memory${suffix}`);
|
|
1438
1744
|
console.log(JSON.stringify({
|
|
1439
1745
|
ok: true,
|
|
1440
1746
|
...res,
|
|
@@ -1455,25 +1761,125 @@ async function runCli() {
|
|
|
1455
1761
|
return;
|
|
1456
1762
|
}
|
|
1457
1763
|
if (cmd === "governance") {
|
|
1764
|
+
const sub = positional[1];
|
|
1765
|
+
const ringLabel = (policy) => policy?.executionRing !== undefined
|
|
1766
|
+
? RING_LABELS[policy.executionRing] || `Ring ${policy.executionRing}`
|
|
1767
|
+
: "Per action (set by risk level)";
|
|
1768
|
+
if (sub === "pause" || sub === "kill-switch" || sub === "kill" || sub === "quarantine") {
|
|
1769
|
+
const reason = positional.slice(2).join(" ").trim() ||
|
|
1770
|
+
(typeof flags.reason === "string" ? flags.reason : "") ||
|
|
1771
|
+
"Paused from the Muxo CLI";
|
|
1772
|
+
if (remoteUrl) {
|
|
1773
|
+
const res = await remoteFetch("/api/v1/governance/kill-switch", {
|
|
1774
|
+
method: "POST",
|
|
1775
|
+
body: { action: "quarantine", reason },
|
|
1776
|
+
});
|
|
1777
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
const { engine, ctx } = getLocalContext();
|
|
1781
|
+
const out = await engine.activateWorkspaceKillSwitch(ctx, { reason });
|
|
1782
|
+
console.log(JSON.stringify({ ok: true, ...out }, null, 2));
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1785
|
+
if (sub === "resume") {
|
|
1786
|
+
if (remoteUrl) {
|
|
1787
|
+
const res = await remoteFetch("/api/v1/governance/kill-switch", {
|
|
1788
|
+
method: "POST",
|
|
1789
|
+
body: { action: "resume" },
|
|
1790
|
+
});
|
|
1791
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1792
|
+
return;
|
|
1793
|
+
}
|
|
1794
|
+
const { engine, ctx } = getLocalContext();
|
|
1795
|
+
const out = engine.resumeWorkspaceKillSwitch(ctx);
|
|
1796
|
+
console.log(JSON.stringify({ ok: true, ...out }, null, 2));
|
|
1797
|
+
return;
|
|
1798
|
+
}
|
|
1799
|
+
if (sub === "scan") {
|
|
1800
|
+
const content = positional.slice(2).join(" ").trim() || String(flags.content || "").trim();
|
|
1801
|
+
if (!content)
|
|
1802
|
+
throw new Error("Usage: muxo governance scan <text>");
|
|
1803
|
+
if (remoteUrl) {
|
|
1804
|
+
const res = await remoteFetch("/api/v1/governance/scan-context", {
|
|
1805
|
+
method: "POST",
|
|
1806
|
+
body: { content, sessionId: "cli" },
|
|
1807
|
+
});
|
|
1808
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
const { engine, ctx } = getLocalContext();
|
|
1812
|
+
const scan = engine.governance.scanMemoryContent({
|
|
1813
|
+
workspaceId: ctx.workspace.id,
|
|
1814
|
+
sessionId: "cli",
|
|
1815
|
+
role: "user",
|
|
1816
|
+
content,
|
|
1817
|
+
});
|
|
1818
|
+
console.log(JSON.stringify({ ok: true, scan }, null, 2));
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
if (sub === "policy") {
|
|
1822
|
+
const patch = {};
|
|
1823
|
+
if (typeof flags.mode === "string")
|
|
1824
|
+
patch.mode = flags.mode;
|
|
1825
|
+
if (flags.ring !== undefined)
|
|
1826
|
+
patch.executionRing = Number(flags.ring);
|
|
1827
|
+
if (typeof flags["require-approval"] === "string") {
|
|
1828
|
+
const raw = flags["require-approval"].trim();
|
|
1829
|
+
patch.requireApprovalFor =
|
|
1830
|
+
raw === "none" ? [] : raw.split(",").map((r) => r.trim()).filter(Boolean);
|
|
1831
|
+
}
|
|
1832
|
+
if (flags["block-destructive-sql"] !== undefined) {
|
|
1833
|
+
patch.blockDestructiveSql =
|
|
1834
|
+
flags["block-destructive-sql"] === true || flags["block-destructive-sql"] === "true";
|
|
1835
|
+
}
|
|
1836
|
+
if (flags["max-credits"] !== undefined)
|
|
1837
|
+
patch.maxCreditsPerRun = Number(flags["max-credits"]);
|
|
1838
|
+
if (Object.keys(patch).length === 0) {
|
|
1839
|
+
if (remoteUrl) {
|
|
1840
|
+
const res = await remoteFetch("/api/v1/governance");
|
|
1841
|
+
const policy = res.workspacePolicy || {};
|
|
1842
|
+
console.log(JSON.stringify({ ok: true, ringName: ringLabel(policy), policy }, null, 2));
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
const { store, ctx } = getLocalContext();
|
|
1846
|
+
const policy = (store.getWorkspace(ctx.workspace.id) || ctx.workspace).policy;
|
|
1847
|
+
console.log(JSON.stringify({ ok: true, ringName: ringLabel(policy), policy }, null, 2));
|
|
1848
|
+
return;
|
|
1849
|
+
}
|
|
1850
|
+
if (remoteUrl) {
|
|
1851
|
+
const res = await remoteFetch("/api/v1/policy", { method: "POST", body: patch });
|
|
1852
|
+
const policy = res.workspace?.policy || {};
|
|
1853
|
+
console.log(JSON.stringify({ ok: true, ringName: ringLabel(policy), policy }, null, 2));
|
|
1854
|
+
return;
|
|
1855
|
+
}
|
|
1856
|
+
const { store, ctx } = getLocalContext();
|
|
1857
|
+
const updated = store.updateWorkspacePolicy(ctx.workspace.id, sanitizePolicyPatch(patch));
|
|
1858
|
+
console.log(JSON.stringify({ ok: true, ringName: ringLabel(updated.policy), policy: updated.policy }, null, 2));
|
|
1859
|
+
return;
|
|
1860
|
+
}
|
|
1458
1861
|
if (remoteUrl) {
|
|
1459
1862
|
const res = await remoteFetch("/api/v1/governance");
|
|
1460
1863
|
console.log(JSON.stringify({
|
|
1461
1864
|
ok: true,
|
|
1462
1865
|
did: res.governance?.agentDid,
|
|
1463
|
-
chainValid: res.governance?.
|
|
1464
|
-
|
|
1866
|
+
chainValid: res.governance?.auditChain?.chainVerified ??
|
|
1867
|
+
res.governance?.auditIntegrityValid ??
|
|
1868
|
+
true,
|
|
1869
|
+
ringName: ringLabel(res.workspacePolicy),
|
|
1465
1870
|
...res,
|
|
1466
1871
|
}, null, 2));
|
|
1467
1872
|
return;
|
|
1468
1873
|
}
|
|
1469
|
-
const { engine, ctx } = getLocalContext();
|
|
1470
|
-
const
|
|
1471
|
-
const
|
|
1874
|
+
const { engine, ctx, store } = getLocalContext();
|
|
1875
|
+
const ws = store.getWorkspace(ctx.workspace.id) || ctx.workspace;
|
|
1876
|
+
const status = engine.governance.getGovernanceStatus(ws);
|
|
1877
|
+
const summary = engine.governance.getStatus(ws);
|
|
1472
1878
|
console.log(JSON.stringify({
|
|
1473
1879
|
ok: true,
|
|
1474
1880
|
did: summary.agentDid,
|
|
1475
1881
|
chainValid: summary.auditChainIntegrity,
|
|
1476
|
-
ringName:
|
|
1882
|
+
ringName: ringLabel(ws.policy),
|
|
1477
1883
|
...status,
|
|
1478
1884
|
}, null, 2));
|
|
1479
1885
|
return;
|
|
@@ -1517,6 +1923,9 @@ async function runCli() {
|
|
|
1517
1923
|
method: "POST",
|
|
1518
1924
|
body: {
|
|
1519
1925
|
prompt: promptText,
|
|
1926
|
+
dryRun: planOnly,
|
|
1927
|
+
planOnly,
|
|
1928
|
+
autoApprove,
|
|
1520
1929
|
autoExecute: !planOnly,
|
|
1521
1930
|
approveRisky: autoApprove,
|
|
1522
1931
|
fundingMode,
|
|
@@ -1565,14 +1974,22 @@ Core Commands:
|
|
|
1565
1974
|
muxo receipts [<receipt_id>] List or verify execution audit records
|
|
1566
1975
|
muxo billing [status|topup|upgrade|checkout] Manage credits, upgrade to Starter, or inspect settlements
|
|
1567
1976
|
muxo memory [<query>] Recall Muxo Workspace Memory & hybrid context
|
|
1977
|
+
muxo memory add <text> | delete <id> Save or delete a workspace memory
|
|
1978
|
+
muxo memory facts [<query>] [--current] List temporal facts with their history (or only current facts)
|
|
1979
|
+
muxo memory forget <text> Delete memories and retire facts that match <text>
|
|
1568
1980
|
muxo governance Inspect Muxo Safety & Approvals identity and audit chain
|
|
1981
|
+
muxo governance pause [<reason>] | resume Turn the workspace kill switch on or off
|
|
1982
|
+
muxo governance scan <text> Check text for prompt injection before storing or sending it
|
|
1983
|
+
muxo governance policy [--mode enforce|monitor] [--ring 0-3] [--require-approval write,admin|none]
|
|
1984
|
+
[--block-destructive-sql true|false] [--max-credits <n>]
|
|
1985
|
+
muxo harness Check API, MCP, auth, governance and catalog; print MCP config
|
|
1569
1986
|
muxo serve [--port 4310] Start unified HTTP Console, Landing, OAuth Callback & MCP server
|
|
1570
1987
|
muxo mcp Run stdio MCP server (20 canonical tools)
|
|
1571
1988
|
`);
|
|
1572
1989
|
}
|
|
1573
1990
|
runCli()
|
|
1574
1991
|
.then(() => {
|
|
1575
|
-
process.exit(0);
|
|
1992
|
+
process.exit(Number(process.exitCode ?? 0));
|
|
1576
1993
|
})
|
|
1577
1994
|
.catch((err) => {
|
|
1578
1995
|
console.error("Error:", err?.message || err);
|