@muxoai/platform 1.3.1 → 1.3.2
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 +33 -0
- package/dist/clerk.js +198 -0
- package/dist/cli.js +422 -26
- 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 +167 -1
- package/dist/sdk.js +113 -2
- package/dist/server.js +176 -16
- 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 +16 -0
- package/dist/ui/console-html.js +2427 -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
|
? ""
|
|
@@ -281,11 +284,52 @@ async function runCli() {
|
|
|
281
284
|
return;
|
|
282
285
|
}
|
|
283
286
|
// One-command setup (`muxo setup` / `muxo init` / `muxo install`):
|
|
284
|
-
// 1. Auto-creates or loads ~/.muxo/config.json with 250 starter credits
|
|
287
|
+
// 1. Auto-creates or loads ~/.muxo/config.json with 250 starter credits (or binds an explicit --api-key)
|
|
285
288
|
// 2. Writes .mcp.json in target directory (or ~/.cursor/mcp.json & ~/.factory/mcp.json if present)
|
|
286
289
|
if (cmd === "setup" || cmd === "init" || cmd === "install") {
|
|
290
|
+
const explicitKey = typeof flags["api-key"] === "string"
|
|
291
|
+
? flags["api-key"].trim()
|
|
292
|
+
: typeof flags.key === "string"
|
|
293
|
+
? flags.key.trim()
|
|
294
|
+
: "";
|
|
287
295
|
let activeConfig = savedCliConfig;
|
|
288
|
-
if (
|
|
296
|
+
if (explicitKey) {
|
|
297
|
+
const agentName = typeof flags.name === "string" ? flags.name : "Muxo Agent";
|
|
298
|
+
if (remoteUrl) {
|
|
299
|
+
apiKeyFlag = explicitKey;
|
|
300
|
+
const orgRes = (await remoteFetch("/api/v1/organization").catch(() => ({})));
|
|
301
|
+
const org = orgRes?.organization || orgRes?.workspace || {};
|
|
302
|
+
activeConfig = {
|
|
303
|
+
authenticated: true,
|
|
304
|
+
apiKey: explicitKey,
|
|
305
|
+
workspaceId: org.id || "ws_remote",
|
|
306
|
+
workspaceName: org.name || agentName,
|
|
307
|
+
agentId: "usr_remote",
|
|
308
|
+
governanceDid: org.governanceDid || `did:muxo:${org.id || "ws_remote"}`,
|
|
309
|
+
supermemoryNamespace: `muxo_${org.id || "ws_remote"}`,
|
|
310
|
+
updatedAt: new Date().toISOString(),
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
const { store, engine } = getLocalContext();
|
|
315
|
+
const auth = store.resolveAuthToken(explicitKey);
|
|
316
|
+
if (!auth) {
|
|
317
|
+
throw new Error(`Invalid API key provided to muxo setup: ${explicitKey.slice(0, 12)}...`);
|
|
318
|
+
}
|
|
319
|
+
activeConfig = {
|
|
320
|
+
authenticated: true,
|
|
321
|
+
apiKey: explicitKey,
|
|
322
|
+
workspaceId: auth.workspace.id,
|
|
323
|
+
workspaceName: auth.workspace.name,
|
|
324
|
+
agentId: auth.user.id,
|
|
325
|
+
governanceDid: engine.governance.getStatus(auth.workspace).agentDid,
|
|
326
|
+
supermemoryNamespace: engine.supermemory.getWorkspaceNamespace(auth.workspace.id),
|
|
327
|
+
updatedAt: new Date().toISOString(),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
writeCliAuthConfig(activeConfig);
|
|
331
|
+
}
|
|
332
|
+
else if (!activeConfig || !activeConfig.apiKey || flags.fresh) {
|
|
289
333
|
const agentName = typeof flags.name === "string" ? flags.name : "Muxo Agent";
|
|
290
334
|
if (remoteUrl) {
|
|
291
335
|
const { authPayload } = await signupHostedWorkspace(agentName, "muxo-setup");
|
|
@@ -310,6 +354,7 @@ async function runCli() {
|
|
|
310
354
|
}
|
|
311
355
|
writeCliAuthConfig(activeConfig);
|
|
312
356
|
}
|
|
357
|
+
const ensuredConfig = activeConfig;
|
|
313
358
|
const mcpServerUrl = remoteUrl
|
|
314
359
|
? `${remoteUrl}/mcp`
|
|
315
360
|
: "https://api.muxo.ai/mcp";
|
|
@@ -317,7 +362,7 @@ async function runCli() {
|
|
|
317
362
|
type: "http",
|
|
318
363
|
url: mcpServerUrl,
|
|
319
364
|
headers: {
|
|
320
|
-
Authorization: `Bearer ${
|
|
365
|
+
Authorization: `Bearer ${ensuredConfig.apiKey}`,
|
|
321
366
|
},
|
|
322
367
|
};
|
|
323
368
|
const targetDir = typeof flags.dir === "string" ? path.resolve(flags.dir) : process.cwd();
|
|
@@ -344,9 +389,9 @@ async function runCli() {
|
|
|
344
389
|
mergeMcpJsonFile(path.join(targetDir, ".mcp.json"));
|
|
345
390
|
const resultPayload = {
|
|
346
391
|
ok: true,
|
|
347
|
-
workspaceId:
|
|
348
|
-
workspaceName:
|
|
349
|
-
apiKey:
|
|
392
|
+
workspaceId: ensuredConfig.workspaceId,
|
|
393
|
+
workspaceName: ensuredConfig.workspaceName,
|
|
394
|
+
apiKey: ensuredConfig.apiKey,
|
|
350
395
|
mcpUrl: mcpServerUrl,
|
|
351
396
|
configPath: getCliConfigPath(),
|
|
352
397
|
configuredFiles: writtenFiles,
|
|
@@ -356,8 +401,8 @@ async function runCli() {
|
|
|
356
401
|
}
|
|
357
402
|
else {
|
|
358
403
|
console.log(`\n✓ Muxo is ready!`);
|
|
359
|
-
console.log(` Workspace : ${
|
|
360
|
-
console.log(` API Key : ${
|
|
404
|
+
console.log(` Workspace : ${ensuredConfig.workspaceName} (${ensuredConfig.workspaceId})`);
|
|
405
|
+
console.log(` API Key : ${ensuredConfig.apiKey}`);
|
|
361
406
|
console.log(` MCP URL : ${mcpServerUrl}`);
|
|
362
407
|
console.log(` MCP Config: ${writtenFiles.join(", ")}`);
|
|
363
408
|
console.log(`\nTry it now:`);
|
|
@@ -474,15 +519,193 @@ async function runCli() {
|
|
|
474
519
|
return;
|
|
475
520
|
}
|
|
476
521
|
if (cmd === "harness") {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
522
|
+
const checks = [];
|
|
523
|
+
const skip = (reason) => ({ skip: reason });
|
|
524
|
+
const runCheck = async (id, name, fn) => {
|
|
525
|
+
const started = Date.now();
|
|
526
|
+
try {
|
|
527
|
+
const out = await fn();
|
|
528
|
+
checks.push(typeof out === "string"
|
|
529
|
+
? { id, name, status: "pass", detail: out, ms: Date.now() - started }
|
|
530
|
+
: { id, name, status: "skip", detail: out.skip, ms: Date.now() - started });
|
|
531
|
+
}
|
|
532
|
+
catch (err) {
|
|
533
|
+
checks.push({
|
|
534
|
+
id,
|
|
535
|
+
name,
|
|
536
|
+
status: "fail",
|
|
537
|
+
detail: String(err?.message || err),
|
|
538
|
+
ms: Date.now() - started,
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
const assertCheck = (cond, message) => {
|
|
543
|
+
if (!cond)
|
|
544
|
+
throw new Error(message);
|
|
545
|
+
};
|
|
546
|
+
const noKeyHint = "No API key. Run `muxo login --signup` to create a workspace.";
|
|
547
|
+
let workspaceId = savedCliConfig?.workspaceId || null;
|
|
548
|
+
if (remoteUrl) {
|
|
549
|
+
let mcpSessionId = "";
|
|
550
|
+
const harnessFetch = async (pathname, init = {}) => {
|
|
551
|
+
const headers = { Accept: "application/json" };
|
|
552
|
+
if (init.body !== undefined)
|
|
553
|
+
headers["Content-Type"] = "application/json";
|
|
554
|
+
if (init.auth !== false && apiKeyFlag)
|
|
555
|
+
headers.Authorization = `Bearer ${apiKeyFlag}`;
|
|
556
|
+
if (pathname === "/mcp" && mcpSessionId)
|
|
557
|
+
headers["Mcp-Session-Id"] = mcpSessionId;
|
|
558
|
+
return fetch(`${remoteUrl}${pathname}`, {
|
|
559
|
+
method: init.method || "GET",
|
|
560
|
+
headers,
|
|
561
|
+
body: init.body !== undefined ? JSON.stringify(init.body) : undefined,
|
|
562
|
+
signal: AbortSignal.timeout(15_000),
|
|
563
|
+
});
|
|
564
|
+
};
|
|
565
|
+
const harnessJson = async (pathname, init) => {
|
|
566
|
+
const res = await harnessFetch(pathname, init);
|
|
567
|
+
const data = (await res.json().catch(() => ({})));
|
|
568
|
+
if (!res.ok) {
|
|
569
|
+
throw new Error(`HTTP ${res.status}${data.error ? `: ${data.error}` : ""}`);
|
|
570
|
+
}
|
|
571
|
+
return data;
|
|
572
|
+
};
|
|
573
|
+
const mcpCall = async (id, method, params = {}) => {
|
|
574
|
+
const res = await harnessFetch("/mcp", {
|
|
575
|
+
method: "POST",
|
|
576
|
+
body: { jsonrpc: "2.0", id, method, params },
|
|
577
|
+
});
|
|
578
|
+
const sid = res.headers.get("mcp-session-id");
|
|
579
|
+
if (sid)
|
|
580
|
+
mcpSessionId = sid;
|
|
581
|
+
const data = (await res.json().catch(() => ({})));
|
|
582
|
+
if (!res.ok || data.error) {
|
|
583
|
+
throw new Error(data.error?.message || `HTTP ${res.status}`);
|
|
584
|
+
}
|
|
585
|
+
return data.result;
|
|
586
|
+
};
|
|
587
|
+
await runCheck("api_health", "API is reachable", async () => {
|
|
588
|
+
const health = await harnessJson("/health", { auth: false });
|
|
589
|
+
assertCheck(health.ok === true, "Health endpoint did not report ok");
|
|
590
|
+
return `${health.service || "muxo"} ${health.version || ""} at ${remoteUrl}`.trim();
|
|
591
|
+
});
|
|
592
|
+
await runCheck("agent_skill", "Agent skill is published", async () => {
|
|
593
|
+
const res = await harnessFetch("/skill.md", { auth: false });
|
|
594
|
+
assertCheck(res.ok, `HTTP ${res.status}`);
|
|
595
|
+
const body = await res.text();
|
|
596
|
+
assertCheck(/execute_(read|write)/.test(body), "skill.md is missing the execute_* tools");
|
|
597
|
+
return `${remoteUrl}/skill.md (${body.length.toLocaleString()} bytes)`;
|
|
598
|
+
});
|
|
599
|
+
await runCheck("mcp_initialize", "MCP server accepts a session", async () => {
|
|
600
|
+
const result = await mcpCall(1, "initialize", {
|
|
601
|
+
protocolVersion: "2025-06-18",
|
|
602
|
+
capabilities: {},
|
|
603
|
+
clientInfo: { name: "muxo-cli-harness", version: MUXO_VERSION },
|
|
604
|
+
});
|
|
605
|
+
assertCheck(result?.serverInfo?.name, "initialize returned no serverInfo");
|
|
606
|
+
return `${result.serverInfo.name} ${result.serverInfo.version || ""} (protocol ${result.protocolVersion})`.trim();
|
|
607
|
+
});
|
|
608
|
+
await runCheck("mcp_tools", "MCP tools are listed", async () => {
|
|
609
|
+
const result = await mcpCall(2, "tools/list");
|
|
610
|
+
const count = Array.isArray(result?.tools) ? result.tools.length : 0;
|
|
611
|
+
assertCheck(count > 0, "tools/list returned no tools");
|
|
612
|
+
return `${count} tools`;
|
|
613
|
+
});
|
|
614
|
+
await runCheck("auth", "API key opens a workspace", async () => {
|
|
615
|
+
if (!apiKeyFlag)
|
|
616
|
+
return skip(noKeyHint);
|
|
617
|
+
const boot = await harnessJson("/api/v1/bootstrap");
|
|
618
|
+
const ws = { ...(boot.organization || {}), ...(boot.profile?.workspace || {}) };
|
|
619
|
+
assertCheck(ws.id, "bootstrap returned no workspace");
|
|
620
|
+
workspaceId = String(ws.id);
|
|
621
|
+
return `${ws.name || ws.id} (${ws.tier || "free"})`;
|
|
622
|
+
});
|
|
623
|
+
await runCheck("governance", "Agents are allowed to act", async () => {
|
|
624
|
+
if (!apiKeyFlag)
|
|
625
|
+
return skip(noKeyHint);
|
|
626
|
+
const res = await harnessJson("/api/v1/governance");
|
|
627
|
+
const g = res.governance || {};
|
|
628
|
+
if (g.killSwitch?.active) {
|
|
629
|
+
throw new Error(`Kill switch is on${g.killSwitch.reason ? ` (${g.killSwitch.reason})` : ""}. Run \`muxo governance resume\`.`);
|
|
630
|
+
}
|
|
631
|
+
const chainOk = g.auditChain?.chainVerified ?? g.auditChainIntegrity ?? g.auditIntegrityValid;
|
|
632
|
+
assertCheck(chainOk !== false, "Audit hash chain failed verification");
|
|
633
|
+
return `Running, audit chain verified, policy ${res.workspacePolicy?.mode || "enforce"}`;
|
|
634
|
+
});
|
|
635
|
+
await runCheck("catalog", "Tool catalog search works", async () => {
|
|
636
|
+
if (!apiKeyFlag)
|
|
637
|
+
return skip(noKeyHint);
|
|
638
|
+
const res = await harnessJson("/api/v1/tools?lane=composio_instant&limit=5");
|
|
639
|
+
const count = Array.isArray(res.tools) ? res.tools.length : 0;
|
|
640
|
+
assertCheck(count > 0, "Catalog search returned no tools");
|
|
641
|
+
return `${count} instant tools returned`;
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
const local = getLocalContext();
|
|
646
|
+
workspaceId = local.ctx.workspace.id;
|
|
647
|
+
await runCheck("local_store", "Local workspace database opens", async () => {
|
|
648
|
+
const ws = local.store.getWorkspace(local.ctx.workspace.id);
|
|
649
|
+
assertCheck(ws, "Workspace not found in local database");
|
|
650
|
+
return `${ws.name} at ${config.dbPath}`;
|
|
651
|
+
});
|
|
652
|
+
await runCheck("mcp_initialize", "MCP server accepts a session", async () => {
|
|
653
|
+
const res = await handleJsonRpcMcpRequest(local.engine, local.ctx, {
|
|
654
|
+
jsonrpc: "2.0",
|
|
655
|
+
id: 1,
|
|
656
|
+
method: "initialize",
|
|
657
|
+
params: { protocolVersion: "2025-06-18", capabilities: {} },
|
|
658
|
+
});
|
|
659
|
+
const info = res?.result?.serverInfo;
|
|
660
|
+
assertCheck(info?.name, "initialize returned no serverInfo");
|
|
661
|
+
return `${info.name} ${info.version || ""}`.trim();
|
|
662
|
+
});
|
|
663
|
+
await runCheck("mcp_tools", "MCP tools are listed", async () => {
|
|
664
|
+
const res = await handleJsonRpcMcpRequest(local.engine, local.ctx, {
|
|
665
|
+
jsonrpc: "2.0",
|
|
666
|
+
id: 2,
|
|
667
|
+
method: "tools/list",
|
|
668
|
+
});
|
|
669
|
+
const count = (res?.result?.tools || []).length;
|
|
670
|
+
assertCheck(count > 0, "tools/list returned no tools");
|
|
671
|
+
return `${count} tools`;
|
|
672
|
+
});
|
|
673
|
+
await runCheck("auth", "API key opens a workspace", async () => {
|
|
674
|
+
if (!apiKeyFlag)
|
|
675
|
+
return skip("No API key. Using the local default workspace.");
|
|
676
|
+
assertCheck(local.tokenAuth, "API key is not valid for this local database");
|
|
677
|
+
return local.ctx.workspace.name;
|
|
678
|
+
});
|
|
679
|
+
await runCheck("governance", "Agents are allowed to act", async () => {
|
|
680
|
+
const ws = local.store.getWorkspace(local.ctx.workspace.id) || local.ctx.workspace;
|
|
681
|
+
const status = local.engine.governance.getGovernanceStatus(ws);
|
|
682
|
+
if (status.killSwitch?.active) {
|
|
683
|
+
throw new Error("Kill switch is on. Run `muxo governance resume`.");
|
|
684
|
+
}
|
|
685
|
+
assertCheck(status.auditChain?.chainVerified !== false, "Audit hash chain failed verification");
|
|
686
|
+
return `Running, audit chain verified, policy ${ws.policy.mode}`;
|
|
687
|
+
});
|
|
688
|
+
await runCheck("catalog", "Tool catalog search works", async () => {
|
|
689
|
+
const res = await local.engine.searchTools({ lane: "composio_instant", limit: 5 });
|
|
690
|
+
assertCheck(res.tools.length > 0, "Catalog search returned no tools");
|
|
691
|
+
return `${res.tools.length} instant tools returned`;
|
|
692
|
+
});
|
|
480
693
|
}
|
|
694
|
+
const passed = checks.filter((c) => c.status === "pass").length;
|
|
695
|
+
const failed = checks.filter((c) => c.status === "fail").length;
|
|
696
|
+
const skipped = checks.filter((c) => c.status === "skip").length;
|
|
697
|
+
if (failed > 0)
|
|
698
|
+
process.exitCode = 1;
|
|
481
699
|
console.log(JSON.stringify({
|
|
482
|
-
ok:
|
|
483
|
-
version:
|
|
484
|
-
|
|
485
|
-
|
|
700
|
+
ok: failed === 0,
|
|
701
|
+
version: MUXO_VERSION,
|
|
702
|
+
mode: remoteUrl ? "hosted" : "local",
|
|
703
|
+
apiUrl: remoteUrl || null,
|
|
704
|
+
passed,
|
|
705
|
+
failed,
|
|
706
|
+
skipped,
|
|
707
|
+
total: checks.length,
|
|
708
|
+
checks,
|
|
486
709
|
workspaceId,
|
|
487
710
|
data: {
|
|
488
711
|
mcpServers: {
|
|
@@ -1173,6 +1396,9 @@ async function runCli() {
|
|
|
1173
1396
|
method: "POST",
|
|
1174
1397
|
body: {
|
|
1175
1398
|
prompt: promptText,
|
|
1399
|
+
dryRun: planOnly,
|
|
1400
|
+
planOnly,
|
|
1401
|
+
autoApprove,
|
|
1176
1402
|
autoExecute: !planOnly,
|
|
1177
1403
|
approveRisky: autoApprove,
|
|
1178
1404
|
fundingMode,
|
|
@@ -1410,6 +1636,47 @@ async function runCli() {
|
|
|
1410
1636
|
}
|
|
1411
1637
|
if (cmd === "memory") {
|
|
1412
1638
|
const sub = positional[1];
|
|
1639
|
+
if (sub === "facts") {
|
|
1640
|
+
const query = positional.slice(2).join(" ") || (typeof flags.query === "string" ? flags.query : "");
|
|
1641
|
+
const includeHistorical = !flags.current;
|
|
1642
|
+
if (remoteUrl) {
|
|
1643
|
+
const params = new URLSearchParams({ historical: includeHistorical ? "true" : "false" });
|
|
1644
|
+
if (query)
|
|
1645
|
+
params.set("query", query);
|
|
1646
|
+
const res = await remoteFetch(`/api/v1/memory/facts?${params.toString()}`);
|
|
1647
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
const { store, ctx } = getLocalContext();
|
|
1651
|
+
const facts = store.listTemporalFacts(ctx.workspace.id, {
|
|
1652
|
+
includeHistorical,
|
|
1653
|
+
query: query || undefined,
|
|
1654
|
+
});
|
|
1655
|
+
console.log(JSON.stringify({
|
|
1656
|
+
ok: true,
|
|
1657
|
+
activeFacts: facts.filter((f) => f.validTo === null),
|
|
1658
|
+
historicalFacts: facts.filter((f) => f.validTo !== null),
|
|
1659
|
+
facts,
|
|
1660
|
+
}, null, 2));
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
if (sub === "forget") {
|
|
1664
|
+
const query = positional.slice(2).join(" ").trim() || String(flags.query || "").trim();
|
|
1665
|
+
if (!query)
|
|
1666
|
+
throw new Error("Usage: muxo memory forget <text>");
|
|
1667
|
+
if (remoteUrl) {
|
|
1668
|
+
const res = await remoteFetch("/api/v1/memory/forget", {
|
|
1669
|
+
method: "POST",
|
|
1670
|
+
body: { query },
|
|
1671
|
+
});
|
|
1672
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1673
|
+
return;
|
|
1674
|
+
}
|
|
1675
|
+
const { engine, ctx } = getLocalContext();
|
|
1676
|
+
const pruned = await engine.forgetWorkspaceMemoryMatching(ctx, query);
|
|
1677
|
+
console.log(JSON.stringify({ ok: true, ...pruned }, null, 2));
|
|
1678
|
+
return;
|
|
1679
|
+
}
|
|
1413
1680
|
if (sub === "add") {
|
|
1414
1681
|
const content = positional.slice(2).join(" ") || String(flags.content || "");
|
|
1415
1682
|
if (!content)
|
|
@@ -1433,8 +1700,26 @@ async function runCli() {
|
|
|
1433
1700
|
console.log(JSON.stringify({ ok: true, memory: entry }, null, 2));
|
|
1434
1701
|
return;
|
|
1435
1702
|
}
|
|
1703
|
+
if (sub === "delete" || sub === "rm" || sub === "remove") {
|
|
1704
|
+
const id = positional[2] || String(flags.id || "");
|
|
1705
|
+
if (!id)
|
|
1706
|
+
throw new Error("Usage: muxo memory delete <memory_id>");
|
|
1707
|
+
if (remoteUrl) {
|
|
1708
|
+
const res = await remoteFetch(`/api/v1/memory/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
1709
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
const { engine, ctx } = getLocalContext();
|
|
1713
|
+
const deleted = await engine.deleteWorkspaceMemory(ctx, id);
|
|
1714
|
+
console.log(JSON.stringify({ ok: true, ...deleted }, null, 2));
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1436
1717
|
if (remoteUrl) {
|
|
1437
|
-
const
|
|
1718
|
+
const query = sub === "recall" || sub === "search"
|
|
1719
|
+
? positional.slice(2).join(" ") || flags.query || undefined
|
|
1720
|
+
: positional.slice(1).join(" ") || flags.query || undefined;
|
|
1721
|
+
const suffix = query ? `?query=${encodeURIComponent(query)}` : "";
|
|
1722
|
+
const res = await remoteFetch(`/api/v1/memory${suffix}`);
|
|
1438
1723
|
console.log(JSON.stringify({
|
|
1439
1724
|
ok: true,
|
|
1440
1725
|
...res,
|
|
@@ -1455,25 +1740,125 @@ async function runCli() {
|
|
|
1455
1740
|
return;
|
|
1456
1741
|
}
|
|
1457
1742
|
if (cmd === "governance") {
|
|
1743
|
+
const sub = positional[1];
|
|
1744
|
+
const ringLabel = (policy) => policy?.executionRing !== undefined
|
|
1745
|
+
? RING_LABELS[policy.executionRing] || `Ring ${policy.executionRing}`
|
|
1746
|
+
: "Per action (set by risk level)";
|
|
1747
|
+
if (sub === "pause" || sub === "kill-switch" || sub === "kill" || sub === "quarantine") {
|
|
1748
|
+
const reason = positional.slice(2).join(" ").trim() ||
|
|
1749
|
+
(typeof flags.reason === "string" ? flags.reason : "") ||
|
|
1750
|
+
"Paused from the Muxo CLI";
|
|
1751
|
+
if (remoteUrl) {
|
|
1752
|
+
const res = await remoteFetch("/api/v1/governance/kill-switch", {
|
|
1753
|
+
method: "POST",
|
|
1754
|
+
body: { action: "quarantine", reason },
|
|
1755
|
+
});
|
|
1756
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1757
|
+
return;
|
|
1758
|
+
}
|
|
1759
|
+
const { engine, ctx } = getLocalContext();
|
|
1760
|
+
const out = await engine.activateWorkspaceKillSwitch(ctx, { reason });
|
|
1761
|
+
console.log(JSON.stringify({ ok: true, ...out }, null, 2));
|
|
1762
|
+
return;
|
|
1763
|
+
}
|
|
1764
|
+
if (sub === "resume") {
|
|
1765
|
+
if (remoteUrl) {
|
|
1766
|
+
const res = await remoteFetch("/api/v1/governance/kill-switch", {
|
|
1767
|
+
method: "POST",
|
|
1768
|
+
body: { action: "resume" },
|
|
1769
|
+
});
|
|
1770
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1771
|
+
return;
|
|
1772
|
+
}
|
|
1773
|
+
const { engine, ctx } = getLocalContext();
|
|
1774
|
+
const out = engine.resumeWorkspaceKillSwitch(ctx);
|
|
1775
|
+
console.log(JSON.stringify({ ok: true, ...out }, null, 2));
|
|
1776
|
+
return;
|
|
1777
|
+
}
|
|
1778
|
+
if (sub === "scan") {
|
|
1779
|
+
const content = positional.slice(2).join(" ").trim() || String(flags.content || "").trim();
|
|
1780
|
+
if (!content)
|
|
1781
|
+
throw new Error("Usage: muxo governance scan <text>");
|
|
1782
|
+
if (remoteUrl) {
|
|
1783
|
+
const res = await remoteFetch("/api/v1/governance/scan-context", {
|
|
1784
|
+
method: "POST",
|
|
1785
|
+
body: { content, sessionId: "cli" },
|
|
1786
|
+
});
|
|
1787
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1788
|
+
return;
|
|
1789
|
+
}
|
|
1790
|
+
const { engine, ctx } = getLocalContext();
|
|
1791
|
+
const scan = engine.governance.scanMemoryContent({
|
|
1792
|
+
workspaceId: ctx.workspace.id,
|
|
1793
|
+
sessionId: "cli",
|
|
1794
|
+
role: "user",
|
|
1795
|
+
content,
|
|
1796
|
+
});
|
|
1797
|
+
console.log(JSON.stringify({ ok: true, scan }, null, 2));
|
|
1798
|
+
return;
|
|
1799
|
+
}
|
|
1800
|
+
if (sub === "policy") {
|
|
1801
|
+
const patch = {};
|
|
1802
|
+
if (typeof flags.mode === "string")
|
|
1803
|
+
patch.mode = flags.mode;
|
|
1804
|
+
if (flags.ring !== undefined)
|
|
1805
|
+
patch.executionRing = Number(flags.ring);
|
|
1806
|
+
if (typeof flags["require-approval"] === "string") {
|
|
1807
|
+
const raw = flags["require-approval"].trim();
|
|
1808
|
+
patch.requireApprovalFor =
|
|
1809
|
+
raw === "none" ? [] : raw.split(",").map((r) => r.trim()).filter(Boolean);
|
|
1810
|
+
}
|
|
1811
|
+
if (flags["block-destructive-sql"] !== undefined) {
|
|
1812
|
+
patch.blockDestructiveSql =
|
|
1813
|
+
flags["block-destructive-sql"] === true || flags["block-destructive-sql"] === "true";
|
|
1814
|
+
}
|
|
1815
|
+
if (flags["max-credits"] !== undefined)
|
|
1816
|
+
patch.maxCreditsPerRun = Number(flags["max-credits"]);
|
|
1817
|
+
if (Object.keys(patch).length === 0) {
|
|
1818
|
+
if (remoteUrl) {
|
|
1819
|
+
const res = await remoteFetch("/api/v1/governance");
|
|
1820
|
+
const policy = res.workspacePolicy || {};
|
|
1821
|
+
console.log(JSON.stringify({ ok: true, ringName: ringLabel(policy), policy }, null, 2));
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
const { store, ctx } = getLocalContext();
|
|
1825
|
+
const policy = (store.getWorkspace(ctx.workspace.id) || ctx.workspace).policy;
|
|
1826
|
+
console.log(JSON.stringify({ ok: true, ringName: ringLabel(policy), policy }, null, 2));
|
|
1827
|
+
return;
|
|
1828
|
+
}
|
|
1829
|
+
if (remoteUrl) {
|
|
1830
|
+
const res = await remoteFetch("/api/v1/policy", { method: "POST", body: patch });
|
|
1831
|
+
const policy = res.workspace?.policy || {};
|
|
1832
|
+
console.log(JSON.stringify({ ok: true, ringName: ringLabel(policy), policy }, null, 2));
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
const { store, ctx } = getLocalContext();
|
|
1836
|
+
const updated = store.updateWorkspacePolicy(ctx.workspace.id, sanitizePolicyPatch(patch));
|
|
1837
|
+
console.log(JSON.stringify({ ok: true, ringName: ringLabel(updated.policy), policy: updated.policy }, null, 2));
|
|
1838
|
+
return;
|
|
1839
|
+
}
|
|
1458
1840
|
if (remoteUrl) {
|
|
1459
1841
|
const res = await remoteFetch("/api/v1/governance");
|
|
1460
1842
|
console.log(JSON.stringify({
|
|
1461
1843
|
ok: true,
|
|
1462
1844
|
did: res.governance?.agentDid,
|
|
1463
|
-
chainValid: res.governance?.
|
|
1464
|
-
|
|
1845
|
+
chainValid: res.governance?.auditChain?.chainVerified ??
|
|
1846
|
+
res.governance?.auditIntegrityValid ??
|
|
1847
|
+
true,
|
|
1848
|
+
ringName: ringLabel(res.workspacePolicy),
|
|
1465
1849
|
...res,
|
|
1466
1850
|
}, null, 2));
|
|
1467
1851
|
return;
|
|
1468
1852
|
}
|
|
1469
|
-
const { engine, ctx } = getLocalContext();
|
|
1470
|
-
const
|
|
1471
|
-
const
|
|
1853
|
+
const { engine, ctx, store } = getLocalContext();
|
|
1854
|
+
const ws = store.getWorkspace(ctx.workspace.id) || ctx.workspace;
|
|
1855
|
+
const status = engine.governance.getGovernanceStatus(ws);
|
|
1856
|
+
const summary = engine.governance.getStatus(ws);
|
|
1472
1857
|
console.log(JSON.stringify({
|
|
1473
1858
|
ok: true,
|
|
1474
1859
|
did: summary.agentDid,
|
|
1475
1860
|
chainValid: summary.auditChainIntegrity,
|
|
1476
|
-
ringName:
|
|
1861
|
+
ringName: ringLabel(ws.policy),
|
|
1477
1862
|
...status,
|
|
1478
1863
|
}, null, 2));
|
|
1479
1864
|
return;
|
|
@@ -1517,6 +1902,9 @@ async function runCli() {
|
|
|
1517
1902
|
method: "POST",
|
|
1518
1903
|
body: {
|
|
1519
1904
|
prompt: promptText,
|
|
1905
|
+
dryRun: planOnly,
|
|
1906
|
+
planOnly,
|
|
1907
|
+
autoApprove,
|
|
1520
1908
|
autoExecute: !planOnly,
|
|
1521
1909
|
approveRisky: autoApprove,
|
|
1522
1910
|
fundingMode,
|
|
@@ -1565,14 +1953,22 @@ Core Commands:
|
|
|
1565
1953
|
muxo receipts [<receipt_id>] List or verify execution audit records
|
|
1566
1954
|
muxo billing [status|topup|upgrade|checkout] Manage credits, upgrade to Starter, or inspect settlements
|
|
1567
1955
|
muxo memory [<query>] Recall Muxo Workspace Memory & hybrid context
|
|
1956
|
+
muxo memory add <text> | delete <id> Save or delete a workspace memory
|
|
1957
|
+
muxo memory facts [<query>] [--current] List temporal facts with their history (or only current facts)
|
|
1958
|
+
muxo memory forget <text> Delete memories and retire facts that match <text>
|
|
1568
1959
|
muxo governance Inspect Muxo Safety & Approvals identity and audit chain
|
|
1960
|
+
muxo governance pause [<reason>] | resume Turn the workspace kill switch on or off
|
|
1961
|
+
muxo governance scan <text> Check text for prompt injection before storing or sending it
|
|
1962
|
+
muxo governance policy [--mode enforce|monitor] [--ring 0-3] [--require-approval write,admin|none]
|
|
1963
|
+
[--block-destructive-sql true|false] [--max-credits <n>]
|
|
1964
|
+
muxo harness Check API, MCP, auth, governance and catalog; print MCP config
|
|
1569
1965
|
muxo serve [--port 4310] Start unified HTTP Console, Landing, OAuth Callback & MCP server
|
|
1570
1966
|
muxo mcp Run stdio MCP server (20 canonical tools)
|
|
1571
1967
|
`);
|
|
1572
1968
|
}
|
|
1573
1969
|
runCli()
|
|
1574
1970
|
.then(() => {
|
|
1575
|
-
process.exit(0);
|
|
1971
|
+
process.exit(Number(process.exitCode ?? 0));
|
|
1576
1972
|
})
|
|
1577
1973
|
.catch((err) => {
|
|
1578
1974
|
console.error("Error:", err?.message || err);
|
package/dist/engine.d.ts
CHANGED
|
@@ -78,6 +78,7 @@ export declare class MuxoEngine {
|
|
|
78
78
|
toolSlug: string;
|
|
79
79
|
input?: Record<string, unknown>;
|
|
80
80
|
reason?: string;
|
|
81
|
+
fundingMode?: "muxo_funded" | "byok";
|
|
81
82
|
}): Promise<{
|
|
82
83
|
plan: ActionPlan;
|
|
83
84
|
tool: MuxoTool;
|
|
@@ -100,26 +101,45 @@ export declare class MuxoEngine {
|
|
|
100
101
|
getMemoryOverview(ctx: ExecutionContext, query?: string): Promise<{
|
|
101
102
|
enabled: boolean;
|
|
102
103
|
namespace: string;
|
|
104
|
+
fundingSource: string;
|
|
103
105
|
context: MemoryContextSummary;
|
|
104
106
|
recentMemories: WorkspaceMemoryRecord[];
|
|
105
107
|
memories: WorkspaceMemoryRecord[];
|
|
108
|
+
temporalFacts: ReturnType<MuxoStore["listTemporalFacts"]>;
|
|
109
|
+
historicalFacts: ReturnType<MuxoStore["listTemporalFacts"]>;
|
|
106
110
|
}>;
|
|
107
111
|
addWorkspaceMemory(ctx: ExecutionContext, params: {
|
|
108
112
|
title: string;
|
|
109
113
|
content: string;
|
|
110
114
|
kind?: WorkspaceMemoryRecord["kind"];
|
|
111
115
|
metadata?: Record<string, unknown>;
|
|
116
|
+
subject?: string;
|
|
117
|
+
predicate?: string;
|
|
118
|
+
object?: string;
|
|
112
119
|
}): Promise<WorkspaceMemoryRecord>;
|
|
113
120
|
deleteWorkspaceMemory(ctx: ExecutionContext, idOrDocId: string): Promise<{
|
|
114
121
|
deleted: boolean;
|
|
115
122
|
record: WorkspaceMemoryRecord | null;
|
|
116
123
|
}>;
|
|
124
|
+
forgetWorkspaceMemoryMatching(ctx: ExecutionContext, query: string): Promise<{
|
|
125
|
+
query: string;
|
|
126
|
+
deletedLocalCount: number;
|
|
127
|
+
invalidatedFactsCount: number;
|
|
128
|
+
deletedRemoteIds: string[];
|
|
129
|
+
deletedMemories: WorkspaceMemoryRecord[];
|
|
130
|
+
invalidatedFacts: ReturnType<MuxoStore["listTemporalFacts"]>;
|
|
131
|
+
}>;
|
|
132
|
+
activateWorkspaceKillSwitch(ctx: ExecutionContext, params: {
|
|
133
|
+
reason: string;
|
|
134
|
+
action?: "terminate" | "quarantine" | "suspend";
|
|
135
|
+
}): Promise<Record<string, unknown>>;
|
|
136
|
+
resumeWorkspaceKillSwitch(ctx: ExecutionContext): Record<string, unknown>;
|
|
117
137
|
executePlanForRisk(ctx: ExecutionContext, planId: string, expectedRisk: RiskLevel): Promise<{
|
|
118
138
|
run: ExecutionRun;
|
|
119
139
|
receipt: ExecutionReceipt;
|
|
120
140
|
}>;
|
|
121
141
|
getRun(ctx: ExecutionContext, runId: string): ExecutionRun;
|
|
122
|
-
cancelRun(ctx: ExecutionContext, runId: string): {
|
|
142
|
+
cancelRun(ctx: ExecutionContext, runId: string, reason?: string): {
|
|
123
143
|
run: ExecutionRun;
|
|
124
144
|
receipt: ExecutionReceipt | null;
|
|
125
145
|
};
|