@muxoai/sdk 1.3.0 → 1.4.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/.agents/plugins/marketplace.json +2 -2
- package/.claude-plugin/marketplace.json +19 -4
- package/.codex/config.toml +9 -2
- package/ARCHITECTURE.md +16 -6
- package/README.md +69 -24
- package/dist/clerk.d.ts +35 -0
- package/dist/clerk.js +201 -0
- package/dist/cli.js +1677 -103
- package/dist/composio-catalog.d.ts +234 -0
- package/dist/composio-catalog.js +1894 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.js +27 -1
- package/dist/durable-workflow.d.ts +112 -0
- package/dist/durable-workflow.js +284 -0
- package/dist/engine.d.ts +377 -6
- package/dist/engine.js +1919 -94
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/mcp-schema.d.ts +286 -0
- package/dist/mcp-schema.js +2580 -0
- package/dist/mcp.d.ts +2 -25
- package/dist/mcp.js +1008 -507
- package/dist/memory-graph.d.ts +45 -0
- package/dist/memory-graph.js +293 -0
- package/dist/nl.js +214 -35
- package/dist/oauth.d.ts +32 -0
- package/dist/oauth.js +134 -0
- package/dist/oss-suite.d.ts +217 -0
- package/dist/oss-suite.js +836 -0
- package/dist/policy.d.ts +190 -0
- package/dist/policy.js +1597 -0
- package/dist/providers/composio-instant.d.ts +4 -0
- package/dist/providers/composio-instant.js +890 -535
- package/dist/providers/composio-sdk.d.ts +126 -5
- package/dist/providers/composio-sdk.js +902 -79
- package/dist/providers/microsoft-governance.d.ts +89 -3
- package/dist/providers/microsoft-governance.js +673 -26
- package/dist/providers/stripe-billing.d.ts +42 -0
- package/dist/providers/stripe-billing.js +244 -5
- package/dist/providers/stripe-projects.d.ts +459 -4
- package/dist/providers/stripe-projects.js +2674 -122
- package/dist/providers/supermemory.d.ts +102 -6
- package/dist/providers/supermemory.js +609 -55
- package/dist/provisioning-managed.d.ts +50 -0
- package/dist/provisioning-managed.js +155 -0
- package/dist/sdk.d.ts +728 -7
- package/dist/sdk.js +539 -10
- package/dist/server.js +2744 -321
- package/dist/store.d.ts +138 -6
- package/dist/store.js +932 -58
- package/dist/types.d.ts +330 -4
- package/dist/ui/console-html.d.ts +62 -0
- package/dist/ui/console-html.js +3742 -2228
- 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 +6 -5
- package/plugins/muxo/.app.json +1 -1
- package/plugins/muxo/.claude-plugin/plugin.json +3 -3
- package/plugins/muxo/.codex-plugin/plugin.json +19 -10
- package/plugins/muxo/.cursor-plugin/plugin.json +30 -0
- package/plugins/muxo/.mcp.json +1 -33
- package/plugins/muxo/assets/logo.png +0 -0
- package/plugins/muxo/hooks/session-start.sh +16 -4
- package/plugins/muxo/hooks/user-prompt-submit.sh +14 -1
- package/plugins/muxo/mcp.json +0 -10
- package/plugins/muxo/plugin.json +65 -8
- package/plugins/muxo/skills/muxo/SKILL.md +142 -14
- package/plugins/muxo/skills/muxo/agents/openai.yaml +12 -0
- package/plugins/muxo/skills/muxo/references/cli.md +9 -3
- package/plugins/muxo/skills/muxo/references/mcp.md +22 -10
- package/plugins/muxo/skills/muxo-activity-summary/SKILL.md +81 -0
- package/plugins/muxo/skills/setup/SKILL.md +17 -3
- package/plugins/muxo/skills/setup/agents/openai.yaml +12 -0
- package/src/catalogues/stripe-projects-catalog.json +140 -0
package/dist/oauth.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { MCP_TOOLS_OAUTH_SCOPE } from "./mcp-schema.js";
|
|
2
|
+
/** Shared OAuth 2.1 (PKCE + consent) helpers for the Node server and the edge worker. */
|
|
3
|
+
export const DEFAULT_OAUTH_SCOPE = `${MCP_TOOLS_OAUTH_SCOPE} muxo:mcp muxo:read muxo:execute muxo:provision`;
|
|
4
|
+
export const PKCE_VERIFIER_PATTERN = /^[A-Za-z0-9._~-]{43,128}$/;
|
|
5
|
+
export const OAUTH_CODE_TTL_MS = 10 * 60 * 1000;
|
|
6
|
+
/** API keys minted through OAuth do not expire; this is the advisory lifetime clients see. */
|
|
7
|
+
export const OAUTH_ACCESS_TOKEN_TTL_SECONDS = 2_592_000;
|
|
8
|
+
export const LOOPBACK_CLIENT_NAME = "An app on this computer";
|
|
9
|
+
const BLOCKED_REDIRECT_SCHEMES = new Set(["javascript:", "data:", "file:", "vbscript:", "about:", "blob:", "ftp:"]);
|
|
10
|
+
export function base64UrlEncode(bytes) {
|
|
11
|
+
let binary = "";
|
|
12
|
+
for (const b of bytes)
|
|
13
|
+
binary += String.fromCharCode(b);
|
|
14
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
15
|
+
}
|
|
16
|
+
export async function pkceS256(verifier) {
|
|
17
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
|
|
18
|
+
return base64UrlEncode(new Uint8Array(digest));
|
|
19
|
+
}
|
|
20
|
+
export function timingSafeEqualText(a, b) {
|
|
21
|
+
if (a.length !== b.length)
|
|
22
|
+
return false;
|
|
23
|
+
let diff = 0;
|
|
24
|
+
for (let i = 0; i < a.length; i++)
|
|
25
|
+
diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
26
|
+
return diff === 0;
|
|
27
|
+
}
|
|
28
|
+
/** Checks a token-endpoint code_verifier against the challenge stored with the authorization code. */
|
|
29
|
+
export async function verifyPkce(verifier, challenge, method) {
|
|
30
|
+
if (!PKCE_VERIFIER_PATTERN.test(verifier))
|
|
31
|
+
return "missing";
|
|
32
|
+
const computed = method === "S256" ? await pkceS256(verifier) : verifier;
|
|
33
|
+
return timingSafeEqualText(computed, challenge) ? "ok" : "mismatch";
|
|
34
|
+
}
|
|
35
|
+
export function oauthClientName(redirect, clientId) {
|
|
36
|
+
const host = redirect.hostname.toLowerCase();
|
|
37
|
+
if (host === "chatgpt.com" || host.endsWith(".chatgpt.com") || host.endsWith(".openai.com"))
|
|
38
|
+
return "ChatGPT";
|
|
39
|
+
if (host === "claude.ai" || host.endsWith(".claude.ai") || host.endsWith(".anthropic.com"))
|
|
40
|
+
return "Claude";
|
|
41
|
+
if (host === "127.0.0.1" || host === "localhost" || host === "[::1]")
|
|
42
|
+
return LOOPBACK_CLIENT_NAME;
|
|
43
|
+
if (redirect.protocol !== "https:" && redirect.protocol !== "http:")
|
|
44
|
+
return redirect.protocol.replace(/:$/, "");
|
|
45
|
+
return clientId.length <= 64 && /^[\w.-]+$/.test(clientId) && !clientId.startsWith("muxo_dcr_") ? clientId : host;
|
|
46
|
+
}
|
|
47
|
+
/** Name of the workspace API key minted for an OAuth connection, as listed in the console. */
|
|
48
|
+
export function oauthConnectionKeyName(clientName) {
|
|
49
|
+
return `${clientName === LOOPBACK_CLIENT_NAME ? "Local app" : clientName} connection`;
|
|
50
|
+
}
|
|
51
|
+
/** Origin shown on the consent screen; app-scheme redirects have no origin, so show the scheme. */
|
|
52
|
+
export function oauthRedirectOrigin(redirectUri) {
|
|
53
|
+
const target = new URL(redirectUri);
|
|
54
|
+
return target.origin === "null" ? target.protocol : target.origin;
|
|
55
|
+
}
|
|
56
|
+
export function parseAuthorizeRequest(params) {
|
|
57
|
+
const responseType = params.get("response_type");
|
|
58
|
+
if (responseType && responseType !== "code")
|
|
59
|
+
return { error: "Only response_type=code is supported." };
|
|
60
|
+
const redirectUri = (params.get("redirect_uri") || "").trim();
|
|
61
|
+
if (!redirectUri || redirectUri.length > 2048)
|
|
62
|
+
return { error: "A valid redirect_uri is required." };
|
|
63
|
+
let redirect;
|
|
64
|
+
try {
|
|
65
|
+
redirect = new URL(redirectUri);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return { error: "redirect_uri is not a valid URL." };
|
|
69
|
+
}
|
|
70
|
+
const loopback = ["127.0.0.1", "localhost", "[::1]"].includes(redirect.hostname);
|
|
71
|
+
if (redirect.hash ||
|
|
72
|
+
BLOCKED_REDIRECT_SCHEMES.has(redirect.protocol) ||
|
|
73
|
+
(redirect.protocol === "http:" && !loopback)) {
|
|
74
|
+
return { error: "redirect_uri must use https, a loopback http address, or an app scheme." };
|
|
75
|
+
}
|
|
76
|
+
const clientId = (params.get("client_id") || "muxo-mcp-client").trim().slice(0, 256);
|
|
77
|
+
const codeChallenge = (params.get("code_challenge") || "").trim() || null;
|
|
78
|
+
const rawMethod = (params.get("code_challenge_method") || "").trim();
|
|
79
|
+
if (codeChallenge && !PKCE_VERIFIER_PATTERN.test(codeChallenge)) {
|
|
80
|
+
return { error: "code_challenge is malformed." };
|
|
81
|
+
}
|
|
82
|
+
if (rawMethod && rawMethod !== "S256" && rawMethod !== "plain") {
|
|
83
|
+
return { error: "code_challenge_method must be S256 or plain." };
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
clientId,
|
|
87
|
+
clientName: oauthClientName(redirect, clientId),
|
|
88
|
+
redirectUri,
|
|
89
|
+
state: (params.get("state") || "").slice(0, 1024),
|
|
90
|
+
codeChallenge,
|
|
91
|
+
codeChallengeMethod: codeChallenge ? (rawMethod === "S256" ? "S256" : "plain") : null,
|
|
92
|
+
scope: (params.get("scope") || DEFAULT_OAUTH_SCOPE).slice(0, 512),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/** Parses a token-endpoint body (form or JSON) and HTTP Basic client credentials into one parameter set. */
|
|
96
|
+
export function parseOAuthFormBody(rawBody, contentType, authorizationHeader) {
|
|
97
|
+
const params = new URLSearchParams();
|
|
98
|
+
if (contentType.includes("application/json")) {
|
|
99
|
+
let body = {};
|
|
100
|
+
try {
|
|
101
|
+
const parsed = JSON.parse(rawBody || "{}");
|
|
102
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
103
|
+
body = parsed;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
body = {};
|
|
107
|
+
}
|
|
108
|
+
for (const [k, v] of Object.entries(body))
|
|
109
|
+
if (typeof v === "string")
|
|
110
|
+
params.set(k, v);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
for (const [k, v] of new URLSearchParams(rawBody))
|
|
114
|
+
params.set(k, v);
|
|
115
|
+
}
|
|
116
|
+
const basic = authorizationHeader.match(/^basic\s+(.+)$/i);
|
|
117
|
+
if (basic && !params.get("client_id")) {
|
|
118
|
+
try {
|
|
119
|
+
const decoded = atob(basic[1].trim());
|
|
120
|
+
params.set("client_id", decodeURIComponent(decoded.split(":")[0] || ""));
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Public clients do not need client credentials, so a malformed header is ignored.
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return params;
|
|
127
|
+
}
|
|
128
|
+
export function oauthSecretToken(prefix) {
|
|
129
|
+
const bytes = new Uint8Array(24);
|
|
130
|
+
crypto.getRandomValues(bytes);
|
|
131
|
+
return `${prefix}_${Array.from(bytes)
|
|
132
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
133
|
+
.join("")}`;
|
|
134
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Open-Source & Commercial Enterprise Suite (Runtime-Agnostic: Node.js + Cloudflare Workers):
|
|
3
|
+
* 1. AWS Cedar & Open Policy Agent (OPA / Rego) Policy-as-Code Compiler & Evaluator
|
|
4
|
+
* 2. OpenTelemetry (OTel GenAI / MCP Semantic Conventions) OTLP JSON & Langfuse Trace Exporter
|
|
5
|
+
* 3. Turnkey Commercial Business Saga Playbooks (backed by Temporal-compatible DurableWorkflows)
|
|
6
|
+
* 4. FinOps & Commercial ROI Unit-Economics Analytics
|
|
7
|
+
*/
|
|
8
|
+
import { type DurableWorkflow } from "./durable-workflow.js";
|
|
9
|
+
import type { ActionPlan, ByokKeyRecord, ExecutionReceipt, ExecutionRun, GovernancePolicy, HumanFriendlyExplanation, ProviderLane, ProvisionedResource, RiskLevel, TemporalGraphFact, Workspace } from "./types.js";
|
|
10
|
+
export interface CompiledPolicyAsCodeBundle {
|
|
11
|
+
workspaceId: string;
|
|
12
|
+
workspaceSlug: string;
|
|
13
|
+
generatedAt: string;
|
|
14
|
+
engines: ["aws-cedar-4.x", "open-policy-agent-rego-v1"];
|
|
15
|
+
cedarSchemaVersion: "4.0";
|
|
16
|
+
cedarPolicyText: string;
|
|
17
|
+
opaRegoText: string;
|
|
18
|
+
statements: Array<{
|
|
19
|
+
id: string;
|
|
20
|
+
effect: "permit" | "forbid";
|
|
21
|
+
description: string;
|
|
22
|
+
statement: string;
|
|
23
|
+
}>;
|
|
24
|
+
cedar: {
|
|
25
|
+
schemaNamespace: "Muxo";
|
|
26
|
+
statementsCount: number;
|
|
27
|
+
policyText: string;
|
|
28
|
+
statements: Array<{
|
|
29
|
+
id: string;
|
|
30
|
+
effect: "permit" | "forbid";
|
|
31
|
+
description: string;
|
|
32
|
+
statement: string;
|
|
33
|
+
}>;
|
|
34
|
+
};
|
|
35
|
+
opa: {
|
|
36
|
+
packageName: "muxo.authz";
|
|
37
|
+
rulesCount: number;
|
|
38
|
+
regoText: string;
|
|
39
|
+
};
|
|
40
|
+
plainEnglishSummary: string[];
|
|
41
|
+
explanation: HumanFriendlyExplanation;
|
|
42
|
+
}
|
|
43
|
+
export interface PolicyAsCodeEvaluationResult {
|
|
44
|
+
workspaceId: string;
|
|
45
|
+
toolSlug: string;
|
|
46
|
+
riskLevel: RiskLevel;
|
|
47
|
+
creditCost: number;
|
|
48
|
+
allowed: boolean;
|
|
49
|
+
decision: "ALLOW" | "DENY" | "REQUIRE_APPROVAL";
|
|
50
|
+
policyDecision: "allow" | "deny" | "require_approval";
|
|
51
|
+
cedarResult: {
|
|
52
|
+
decision: "ALLOW" | "DENY";
|
|
53
|
+
determiningPolicies: string[];
|
|
54
|
+
errors: string[];
|
|
55
|
+
};
|
|
56
|
+
opaResult: {
|
|
57
|
+
allow: boolean;
|
|
58
|
+
decision: "allow" | "deny" | "review";
|
|
59
|
+
denyReasons: string[];
|
|
60
|
+
reviewReasons: string[];
|
|
61
|
+
};
|
|
62
|
+
matchedStatements: string[];
|
|
63
|
+
remediationForLlm: string;
|
|
64
|
+
compiledBundle: CompiledPolicyAsCodeBundle;
|
|
65
|
+
}
|
|
66
|
+
export declare function compileWorkspacePolicyToCedarAndRego(policy: GovernancePolicy, workspace: Pick<Workspace, "id" | "slug" | "name">): CompiledPolicyAsCodeBundle;
|
|
67
|
+
export declare function evaluateCedarAndOpaPolicy(params: {
|
|
68
|
+
policy: GovernancePolicy;
|
|
69
|
+
workspace: Pick<Workspace, "id" | "slug" | "name">;
|
|
70
|
+
toolSlug: string;
|
|
71
|
+
input?: Record<string, unknown>;
|
|
72
|
+
riskLevel?: RiskLevel;
|
|
73
|
+
creditCost?: number;
|
|
74
|
+
lane?: string;
|
|
75
|
+
}): PolicyAsCodeEvaluationResult;
|
|
76
|
+
export interface OtelSpanAttribute {
|
|
77
|
+
key: string;
|
|
78
|
+
value: {
|
|
79
|
+
stringValue?: string;
|
|
80
|
+
intValue?: number;
|
|
81
|
+
boolValue?: boolean;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export interface OtelTraceExportBundle {
|
|
85
|
+
workspaceId: string;
|
|
86
|
+
workspaceSlug: string;
|
|
87
|
+
exportedAt: string;
|
|
88
|
+
protocol: "OTLP/HTTP-JSON-v1";
|
|
89
|
+
semanticConventions: ["gen_ai.1.29.0", "mcp.2026-07-28", "muxo.governance.v5"];
|
|
90
|
+
w3cTraceParent: string;
|
|
91
|
+
w3cTraceContextSample: string;
|
|
92
|
+
spansCount: number;
|
|
93
|
+
otlpPayload: {
|
|
94
|
+
resourceSpans: OtelTraceExportBundle["resourceSpans"];
|
|
95
|
+
};
|
|
96
|
+
resourceSpans: Array<{
|
|
97
|
+
resource: {
|
|
98
|
+
attributes: OtelSpanAttribute[];
|
|
99
|
+
};
|
|
100
|
+
scopeSpans: Array<{
|
|
101
|
+
scope: {
|
|
102
|
+
name: string;
|
|
103
|
+
version: string;
|
|
104
|
+
};
|
|
105
|
+
spans: Array<{
|
|
106
|
+
traceId: string;
|
|
107
|
+
spanId: string;
|
|
108
|
+
parentSpanId?: string;
|
|
109
|
+
traceparent: string;
|
|
110
|
+
name: string;
|
|
111
|
+
kind: "SPAN_KIND_SERVER" | "SPAN_KIND_CLIENT";
|
|
112
|
+
startTimeUnixNano: string;
|
|
113
|
+
endTimeUnixNano: string;
|
|
114
|
+
status: {
|
|
115
|
+
code: "STATUS_CODE_OK" | "STATUS_CODE_ERROR";
|
|
116
|
+
message?: string;
|
|
117
|
+
};
|
|
118
|
+
attributes: OtelSpanAttribute[];
|
|
119
|
+
}>;
|
|
120
|
+
}>;
|
|
121
|
+
}>;
|
|
122
|
+
langfuseBatch: Array<{
|
|
123
|
+
id: string;
|
|
124
|
+
type: "trace-create" | "span-create";
|
|
125
|
+
timestamp: string;
|
|
126
|
+
body: Record<string, unknown>;
|
|
127
|
+
}>;
|
|
128
|
+
}
|
|
129
|
+
export declare function buildOtelTraceExport(params: {
|
|
130
|
+
workspace: Pick<Workspace, "id" | "slug" | "name" | "tier">;
|
|
131
|
+
runs: ExecutionRun[];
|
|
132
|
+
receipts: ExecutionReceipt[];
|
|
133
|
+
plans?: ActionPlan[];
|
|
134
|
+
version?: string;
|
|
135
|
+
}): OtelTraceExportBundle;
|
|
136
|
+
export interface CommercialPlaybookDefinition {
|
|
137
|
+
slug: "fullstack-cloud-bootstrap" | "competitor-seo-growth-brief" | "incident-containment-audit" | "customer-release-readiness";
|
|
138
|
+
name: string;
|
|
139
|
+
persona: "Engineering & DevOps" | "Marketing & Growth" | "SecOps & Compliance" | "Product & Founders";
|
|
140
|
+
summary: string;
|
|
141
|
+
commercialValue: string;
|
|
142
|
+
estimatedMinutesSaved: number;
|
|
143
|
+
creditCost: number;
|
|
144
|
+
defaultProvider: string;
|
|
145
|
+
defaultServiceRef: string;
|
|
146
|
+
steps: Array<{
|
|
147
|
+
name: string;
|
|
148
|
+
toolSlug: string;
|
|
149
|
+
primitive: "step.do" | "step.waitForEvent";
|
|
150
|
+
compensationAction?: string;
|
|
151
|
+
description: string;
|
|
152
|
+
}>;
|
|
153
|
+
}
|
|
154
|
+
export declare const MUXO_COMMERCIAL_PLAYBOOKS: CommercialPlaybookDefinition[];
|
|
155
|
+
export declare function getCommercialPlaybook(slug: string): CommercialPlaybookDefinition | null;
|
|
156
|
+
export declare function buildPlaybookSagaExecution(params: {
|
|
157
|
+
id: string;
|
|
158
|
+
workspaceId: string;
|
|
159
|
+
workspaceSlug: string;
|
|
160
|
+
playbook: CommercialPlaybookDefinition;
|
|
161
|
+
input?: Record<string, unknown>;
|
|
162
|
+
}): {
|
|
163
|
+
playbook: CommercialPlaybookDefinition;
|
|
164
|
+
workflow: DurableWorkflow;
|
|
165
|
+
temporalFact: {
|
|
166
|
+
subject: string;
|
|
167
|
+
predicate: string;
|
|
168
|
+
object: string;
|
|
169
|
+
summary: string;
|
|
170
|
+
episodeId: string;
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
export interface CommercialRoiReport {
|
|
174
|
+
workspaceId: string;
|
|
175
|
+
workspaceSlug: string;
|
|
176
|
+
workspaceName: string;
|
|
177
|
+
tier: string;
|
|
178
|
+
generatedAt: string;
|
|
179
|
+
unitEconomics: {
|
|
180
|
+
creditsBalance: number;
|
|
181
|
+
totalRunsAnalyzed: number;
|
|
182
|
+
succeededRunsCount: number;
|
|
183
|
+
byokZeroCreditRunsCount: number;
|
|
184
|
+
managedFundedRunsCount: number;
|
|
185
|
+
totalCreditsConsumed: number;
|
|
186
|
+
byokCreditsSaved: number;
|
|
187
|
+
byokDollarsSavedUsd: number;
|
|
188
|
+
estimatedEngineeringMinutesSaved: number;
|
|
189
|
+
estimatedEngineeringHoursSaved: number;
|
|
190
|
+
estimatedLaborValueSavedUsd: number;
|
|
191
|
+
preventedPolicyViolationsCount: number;
|
|
192
|
+
activeCloudResourcesCount: number;
|
|
193
|
+
activeBiTemporalFactsCount: number;
|
|
194
|
+
configuredByokProviders: string[];
|
|
195
|
+
};
|
|
196
|
+
laneBreakdown: Record<ProviderLane, {
|
|
197
|
+
runsCount: number;
|
|
198
|
+
creditsConsumed: number;
|
|
199
|
+
estimatedMinutesSaved: number;
|
|
200
|
+
}>;
|
|
201
|
+
recommendations: Array<{
|
|
202
|
+
id: string;
|
|
203
|
+
category: "byok_savings" | "cloud_consolidation" | "governance_safety" | "playbook_automation";
|
|
204
|
+
title: string;
|
|
205
|
+
impact: string;
|
|
206
|
+
actionCommand: string;
|
|
207
|
+
}>;
|
|
208
|
+
explanation: HumanFriendlyExplanation;
|
|
209
|
+
}
|
|
210
|
+
export declare function buildCommercialRoiReport(params: {
|
|
211
|
+
workspace: Workspace;
|
|
212
|
+
runs: ExecutionRun[];
|
|
213
|
+
plans?: ActionPlan[];
|
|
214
|
+
resources: ProvisionedResource[];
|
|
215
|
+
byokKeys: ByokKeyRecord[];
|
|
216
|
+
temporalFacts: TemporalGraphFact[];
|
|
217
|
+
}): CommercialRoiReport;
|