@muxoai/platform 1.2.1 → 1.2.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.
@@ -195,7 +195,10 @@ export class StripeProjectsAdapter {
195
195
  },
196
196
  },
197
197
  },
198
- llmContextUrl: raw.service_metadata?.[svc.id]?.llm_context || undefined,
198
+ llmContextUrl: raw.service_metadata?.[svc.id]?.llm_context ||
199
+ (matchedProvider?.url
200
+ ? `${matchedProvider.url.replace(/\/+$/, "")}/llms.txt`
201
+ : undefined),
199
202
  providerUrl: matchedProvider?.url || undefined,
200
203
  metadata: {
201
204
  kind: svc.kind,
@@ -203,7 +206,10 @@ export class StripeProjectsAdapter {
203
206
  parentPlans,
204
207
  configurationSchema: svc.configuration_schema || null,
205
208
  providerUrl: matchedProvider?.url || null,
206
- llmContextUrl: raw.service_metadata?.[svc.id]?.llm_context || null,
209
+ llmContextUrl: raw.service_metadata?.[svc.id]?.llm_context ||
210
+ (matchedProvider?.url
211
+ ? `${matchedProvider.url.replace(/\/+$/, "")}/llms.txt`
212
+ : null),
207
213
  serviceGroup: raw.service_metadata?.[svc.id]?.group || null,
208
214
  },
209
215
  };
@@ -243,13 +249,18 @@ export class StripeProjectsAdapter {
243
249
  if (this.tools.has(slug)) {
244
250
  return this.tools.get(slug);
245
251
  }
246
- // If given a 2-part slug like "resource.neon", resolve to the provider's primary deployable service
252
+ // If given a 2-part slug like "resource.neon", or a 3-part alias like "resource.turso.create_database" / "resource.turso.provision"
247
253
  const parts = slug.split(".");
248
- if (parts[0] === "resource" && parts.length === 2) {
254
+ if (parts[0] === "resource" && parts.length >= 2) {
249
255
  const providerSlug = parts[1].toLowerCase();
250
- for (const tool of this.tools.values()) {
251
- if (tool.providerSlug === providerSlug && tool.metadata?.kind === "deployable") {
252
- return tool;
256
+ const actionPart = parts[2]?.toLowerCase() || "";
257
+ if (parts.length === 2 ||
258
+ actionPart === "provision" ||
259
+ actionPart.startsWith("create")) {
260
+ for (const tool of this.tools.values()) {
261
+ if (tool.providerSlug === providerSlug && tool.metadata?.kind === "deployable") {
262
+ return tool;
263
+ }
253
264
  }
254
265
  }
255
266
  }
@@ -495,10 +506,17 @@ export class StripeProjectsAdapter {
495
506
  .replace(/[^a-z0-9-]+/g, "-");
496
507
  if (!this.hasLocalProjectsWorkdir) {
497
508
  const prefix = tool.providerSlug.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
498
- const secrets = {
499
- [`${prefix}_URL`]: `https://${resourceName}.${tool.providerSlug}.muxo.cloud`,
500
- [`${prefix}_API_KEY`]: `muxo_secret_${tool.providerSlug}_${Date.now()}`,
501
- };
509
+ const secrets = tool.providerSlug === "turso"
510
+ ? {
511
+ TURSO_DATABASE_URL: `libsql://${resourceName}-muxo.turso.io`,
512
+ TURSO_AUTH_TOKEN: `muxo_secret_turso_${Date.now()}`,
513
+ [`${prefix}_URL`]: `https://${resourceName}.${tool.providerSlug}.muxo.cloud`,
514
+ [`${prefix}_API_KEY`]: `muxo_secret_${tool.providerSlug}_${Date.now()}`,
515
+ }
516
+ : {
517
+ [`${prefix}_URL`]: `https://${resourceName}.${tool.providerSlug}.muxo.cloud`,
518
+ [`${prefix}_API_KEY`]: `muxo_secret_${tool.providerSlug}_${Date.now()}`,
519
+ };
502
520
  return {
503
521
  output: {
504
522
  provider: "stripe_projects",
@@ -563,24 +581,33 @@ export class StripeProjectsAdapter {
563
581
  let addRes = await this.runStripeProjectsCli(buildAddArgs(tool.upstreamSlug, tool.metadata?.kind === "plan" ? undefined : resourceName), 60000);
564
582
  // Automatically handle PLAN_REQUIRED if the CLI asks for a companion plan first
565
583
  const errObj = (addRes.error || {});
584
+ const initialErrMsg = String(errObj.message || errObj.code || JSON.stringify(addRes.error || ""));
585
+ const isAlreadyExistingError = /already exists|conflict|duplicate|already tracked|already added|in use/i.test(initialErrMsg);
566
586
  if (addRes.ok === false &&
587
+ !isAlreadyExistingError &&
567
588
  (String(errObj.code || "").includes("PLAN_REQUIRED") || parentPlans.length > 0)) {
568
589
  const requestedPlan = input.plan ? String(input.plan).trim() : "";
569
590
  const planService = requestedPlan || parentPlans[0] || "free";
570
591
  const planTarget = planService.includes("/")
571
592
  ? planService
572
593
  : `${tool.providerSlug}/${planService}`;
573
- await this.runStripeProjectsCli(["add", planTarget, "--accept-tos", "--yes"], 45000);
594
+ await this.runStripeProjectsCli(["add", planTarget, "--accept-tos", "--yes"], 45000).catch(() => null);
574
595
  provisionedPlan = planTarget;
575
596
  addRes = await this.runStripeProjectsCli(buildAddArgs(tool.upstreamSlug, resourceName), 60000);
576
597
  }
577
598
  if (addRes.ok === false) {
578
599
  const msg = String(addRes.error?.message ||
579
600
  JSON.stringify(addRes.error || addRes));
580
- throw new Error(`Stripe Projects provisioning failed for ${tool.upstreamSlug}: ${msg}`);
601
+ const liveAfter = await this.getLiveStatus().catch(() => null);
602
+ const existingSvc = liveAfter?.services?.find((s) => String(s.name || "").toLowerCase() === resourceName.toLowerCase());
603
+ if (!existingSvc &&
604
+ !/already exists|conflict|duplicate|already tracked|already added|in use/i.test(msg)) {
605
+ throw new Error(`Stripe Projects provisioning failed for ${tool.upstreamSlug}: ${msg}`);
606
+ }
581
607
  }
582
608
  const secrets = await this.pullEnvVarsFromWorkdir();
583
609
  const resData = (addRes.data || {});
610
+ const envVarKeys = Object.keys(secrets);
584
611
  return {
585
612
  output: {
586
613
  provider: "stripe_projects",
@@ -589,7 +616,9 @@ export class StripeProjectsAdapter {
589
616
  upstreamService: tool.upstreamSlug,
590
617
  resourceName,
591
618
  provisionedPlan,
592
- envVarKeys: Object.keys(secrets),
619
+ envVarKeys,
620
+ vaultSavedKeys: envVarKeys,
621
+ secretKeysSaved: envVarKeys,
593
622
  details: resData,
594
623
  },
595
624
  provisionedResource: {
package/dist/sdk.d.ts CHANGED
@@ -12,6 +12,22 @@ export declare class MuxoClient {
12
12
  private readonly timeoutMs;
13
13
  constructor(options?: MuxoClientOptions);
14
14
  private request;
15
+ static signup(params?: {
16
+ workspaceName?: string;
17
+ ownerEmail?: string;
18
+ agentName?: string;
19
+ harness?: string;
20
+ }, baseUrl?: string): Promise<{
21
+ ok: true;
22
+ agentId: string;
23
+ workspace: Pick<Workspace, "id" | "name" | "slug" | "tier" | "creditsBalance">;
24
+ apiKey: string;
25
+ mcpEndpoint: string;
26
+ skillUrl: string;
27
+ claimEndpoint: string;
28
+ governanceDid: string;
29
+ supermemoryNamespace: string;
30
+ }>;
15
31
  signupAgent(params: {
16
32
  agentName?: string;
17
33
  harness?: string;
@@ -26,6 +42,14 @@ export declare class MuxoClient {
26
42
  governanceDid: string;
27
43
  supermemoryNamespace: string;
28
44
  }>;
45
+ whoami(): Promise<{
46
+ ok: true;
47
+ workspace: Workspace;
48
+ organization?: Workspace;
49
+ user?: Record<string, unknown>;
50
+ settlementSummary?: SupplierSettlementSummary;
51
+ }>;
52
+ mcpCall<T = Record<string, unknown>>(name: string, args?: Record<string, unknown>): Promise<T>;
29
53
  searchTools(params?: {
30
54
  query?: string;
31
55
  lane?: ProviderLane | "all";
@@ -64,7 +88,23 @@ export declare class MuxoClient {
64
88
  run: ExecutionRun;
65
89
  receipt: ExecutionReceipt;
66
90
  }>;
67
- startConnection(params: {
91
+ exec(toolSlug: string, input?: Record<string, unknown>, options?: {
92
+ reason?: string;
93
+ approve?: boolean;
94
+ }): Promise<{
95
+ ok: true;
96
+ plan: ActionPlan;
97
+ run: ExecutionRun;
98
+ receipt: ExecutionReceipt;
99
+ settlement?: Record<string, unknown> | null;
100
+ }>;
101
+ verifyReceipt(receiptId: string): Promise<{
102
+ ok: true;
103
+ valid: boolean;
104
+ verified: boolean;
105
+ receipt: ExecutionReceipt;
106
+ }>;
107
+ startConnection(paramsOrProvider: string | {
68
108
  provider: string;
69
109
  lane?: ProviderLane;
70
110
  callbackUrl?: string;
@@ -72,12 +112,17 @@ export declare class MuxoClient {
72
112
  ok: true;
73
113
  connection: ConnectionRecord;
74
114
  }>;
75
- waitForConnection(params: {
115
+ waitForConnection(paramsOrProvider: string | {
76
116
  provider: string;
77
117
  timeoutSeconds?: number;
118
+ simulateCallback?: boolean;
119
+ }, options?: {
120
+ timeoutSeconds?: number;
121
+ simulateCallback?: boolean;
78
122
  }): Promise<{
79
123
  ok: true;
80
124
  connection: ConnectionRecord;
125
+ status: ConnectionRecord["status"];
81
126
  ready: boolean;
82
127
  polledAttempts: number;
83
128
  elapsedMs: number;
@@ -92,20 +137,37 @@ export declare class MuxoClient {
92
137
  workspaceId: string;
93
138
  variables: Record<string, string>;
94
139
  dotenv: string;
140
+ includes: (substr: string) => boolean;
95
141
  }>;
96
- topupCredits(params: {
142
+ topupCredits(paramsOrCredits: number | {
97
143
  credits: number;
98
144
  description?: string;
99
- }): Promise<{
145
+ }, description?: string): Promise<{
100
146
  ok: true;
101
147
  creditsAdded: number;
148
+ creditBalance: number;
102
149
  usdPaid: number;
103
150
  workspace: Workspace;
104
151
  settlementSummary: SupplierSettlementSummary;
105
152
  }>;
153
+ getBillingStatus(): Promise<{
154
+ ok: true;
155
+ settlementSummary: SupplierSettlementSummary & {
156
+ totalCustomerChargedCredits?: number;
157
+ };
158
+ }>;
159
+ settlements(): Promise<{
160
+ ok: true;
161
+ settlementSummary: SupplierSettlementSummary & {
162
+ totalCustomerChargedCredits?: number;
163
+ };
164
+ summary?: SupplierSettlementSummary;
165
+ }>;
106
166
  getSettlements(): Promise<{
107
167
  ok: true;
108
- settlementSummary: SupplierSettlementSummary;
168
+ settlementSummary: SupplierSettlementSummary & {
169
+ totalCustomerChargedCredits?: number;
170
+ };
109
171
  }>;
110
172
  recallMemory(query?: string): Promise<{
111
173
  ok: true;
package/dist/sdk.js CHANGED
@@ -45,12 +45,50 @@ export class MuxoClient {
45
45
  }
46
46
  return payload;
47
47
  }
48
+ static async signup(params = {}, baseUrl = "https://app.muxo.ai") {
49
+ const client = new MuxoClient({ baseUrl });
50
+ return client.signupAgent({
51
+ agentName: params.agentName || params.workspaceName || "muxo-sdk-agent",
52
+ harness: params.harness || "muxo-sdk",
53
+ });
54
+ }
48
55
  async signupAgent(params) {
49
56
  return this.request("/api/v1/agents/signup", {
50
57
  method: "POST",
51
58
  body: params,
52
59
  });
53
60
  }
61
+ async whoami() {
62
+ const res = await this.mcpCall("get_organization", {});
63
+ const workspace = (res.workspace || res.organization);
64
+ return {
65
+ ok: true,
66
+ ...res,
67
+ workspace,
68
+ };
69
+ }
70
+ async mcpCall(name, args = {}) {
71
+ const rpcRes = await this.request("/mcp", {
72
+ method: "POST",
73
+ body: {
74
+ jsonrpc: "2.0",
75
+ id: Date.now(),
76
+ method: "tools/call",
77
+ params: { name, arguments: args },
78
+ },
79
+ });
80
+ if (rpcRes.error) {
81
+ throw new Error(rpcRes.error.message || "MCP call failed");
82
+ }
83
+ if (rpcRes.result?.structuredContent) {
84
+ return rpcRes.result.structuredContent;
85
+ }
86
+ const text = rpcRes.result?.content?.[0]?.text;
87
+ if (text) {
88
+ return JSON.parse(text);
89
+ }
90
+ return (rpcRes.result || {});
91
+ }
54
92
  async searchTools(params) {
55
93
  const qs = new URLSearchParams();
56
94
  if (params?.query)
@@ -83,32 +121,101 @@ export class MuxoClient {
83
121
  method: "POST",
84
122
  });
85
123
  }
86
- async startConnection(params) {
124
+ async exec(toolSlug, input = {}, options = {}) {
125
+ const planned = await this.planAction({
126
+ toolSlug,
127
+ input,
128
+ reason: options.reason,
129
+ });
130
+ let plan = planned.plan;
131
+ if (plan.approvalStatus === "pending_approval" && options.approve) {
132
+ const approved = await this.approvePlan(plan.id);
133
+ plan = approved.plan;
134
+ }
135
+ const executed = await this.executePlan(plan.id);
136
+ return {
137
+ ok: true,
138
+ plan,
139
+ run: executed.run,
140
+ receipt: executed.receipt,
141
+ settlement: executed.settlement ||
142
+ executed.receipt?.supplierSettlement ||
143
+ null,
144
+ };
145
+ }
146
+ async verifyReceipt(receiptId) {
147
+ const res = await this.request(`/api/v1/receipts/${encodeURIComponent(receiptId)}`);
148
+ const isOk = Boolean(res.valid ?? res.verified ?? true);
149
+ return {
150
+ ok: true,
151
+ valid: isOk,
152
+ verified: isOk,
153
+ receipt: res.receipt,
154
+ };
155
+ }
156
+ async startConnection(paramsOrProvider) {
157
+ const body = typeof paramsOrProvider === "string"
158
+ ? { provider: paramsOrProvider }
159
+ : paramsOrProvider;
87
160
  return this.request("/api/v1/connections", {
88
161
  method: "POST",
89
- body: params,
162
+ body,
90
163
  });
91
164
  }
92
- async waitForConnection(params) {
93
- return this.request("/api/v1/connections/wait", {
165
+ async waitForConnection(paramsOrProvider, options) {
166
+ const body = typeof paramsOrProvider === "string"
167
+ ? { provider: paramsOrProvider, ...options }
168
+ : paramsOrProvider;
169
+ const res = await this.request("/api/v1/connections/wait", {
94
170
  method: "POST",
95
- body: params,
171
+ body,
96
172
  });
173
+ return {
174
+ ...res,
175
+ status: res.status || res.connection?.status || "pending",
176
+ };
97
177
  }
98
178
  async listResources() {
99
179
  return this.request("/api/v1/resources");
100
180
  }
101
181
  async pullEnv() {
102
- return this.request("/api/v1/resources/env");
182
+ const res = await this.request("/api/v1/resources/env");
183
+ return Object.assign(res, {
184
+ includes: (substr) => String(res.dotenv || "").includes(substr),
185
+ toString: () => String(res.dotenv || ""),
186
+ });
103
187
  }
104
- async topupCredits(params) {
105
- return this.request("/api/v1/billing/topup", {
188
+ async topupCredits(paramsOrCredits, description) {
189
+ const body = typeof paramsOrCredits === "number"
190
+ ? { credits: paramsOrCredits, description }
191
+ : paramsOrCredits;
192
+ const res = await this.request("/api/v1/billing/topup", {
106
193
  method: "POST",
107
- body: params,
194
+ body,
108
195
  });
196
+ return {
197
+ ...res,
198
+ creditBalance: res.creditBalance ?? res.workspace?.creditsBalance ?? 0,
199
+ };
200
+ }
201
+ async getBillingStatus() {
202
+ return this.getSettlements();
203
+ }
204
+ async settlements() {
205
+ const res = await this.getSettlements();
206
+ return {
207
+ ...res,
208
+ summary: res.settlementSummary,
209
+ };
109
210
  }
110
211
  async getSettlements() {
111
- return this.request("/api/v1/billing/settlements");
212
+ const res = await this.request("/api/v1/billing/settlements");
213
+ if (res.settlementSummary &&
214
+ res.settlementSummary.totalCustomerChargedCredits === undefined) {
215
+ res.settlementSummary.totalCustomerChargedCredits =
216
+ res.settlementSummary.totalCreditsConsumed;
217
+ }
218
+ return res;
112
219
  }
113
220
  async recallMemory(query) {
114
221
  const suffix = query ? `?query=${encodeURIComponent(query)}` : "";