@muxoai/platform 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.agents/plugins/marketplace.json +2 -2
  2. package/.claude-plugin/marketplace.json +2 -2
  3. package/ARCHITECTURE.md +16 -6
  4. package/README.md +1 -1
  5. package/dist/cli.js +317 -10
  6. package/dist/composio-catalog.d.ts +58 -0
  7. package/dist/composio-catalog.js +474 -0
  8. package/dist/config.d.ts +10 -0
  9. package/dist/config.js +16 -0
  10. package/dist/durable-workflow.d.ts +45 -0
  11. package/dist/durable-workflow.js +90 -0
  12. package/dist/engine.d.ts +276 -5
  13. package/dist/engine.js +1261 -71
  14. package/dist/mcp-schema.d.ts +125 -0
  15. package/dist/mcp-schema.js +1076 -0
  16. package/dist/mcp.d.ts +2 -30
  17. package/dist/mcp.js +505 -539
  18. package/dist/memory-graph.d.ts +21 -0
  19. package/dist/memory-graph.js +173 -0
  20. package/dist/nl.js +155 -0
  21. package/dist/oauth.d.ts +32 -0
  22. package/dist/oauth.js +134 -0
  23. package/dist/policy.d.ts +75 -1
  24. package/dist/policy.js +1119 -0
  25. package/dist/providers/composio-instant.js +225 -5
  26. package/dist/providers/composio-sdk.d.ts +68 -5
  27. package/dist/providers/composio-sdk.js +683 -78
  28. package/dist/providers/microsoft-governance.d.ts +28 -1
  29. package/dist/providers/microsoft-governance.js +224 -11
  30. package/dist/providers/stripe-billing.d.ts +42 -0
  31. package/dist/providers/stripe-billing.js +230 -1
  32. package/dist/providers/stripe-projects.d.ts +451 -3
  33. package/dist/providers/stripe-projects.js +2106 -87
  34. package/dist/providers/supermemory.d.ts +74 -1
  35. package/dist/providers/supermemory.js +426 -0
  36. package/dist/provisioning-managed.d.ts +50 -0
  37. package/dist/provisioning-managed.js +155 -0
  38. package/dist/sdk.d.ts +440 -3
  39. package/dist/sdk.js +305 -3
  40. package/dist/server.js +1841 -232
  41. package/dist/store.d.ts +113 -6
  42. package/dist/store.js +675 -52
  43. package/dist/types.d.ts +192 -3
  44. package/dist/ui/console-html.d.ts +10 -1
  45. package/dist/ui/console-html.js +1082 -452
  46. package/dist/version.d.ts +1 -1
  47. package/dist/version.js +1 -1
  48. package/package.json +2 -2
  49. package/plugins/muxo/.claude-plugin/plugin.json +1 -1
  50. package/plugins/muxo/.codex-plugin/plugin.json +1 -1
  51. package/plugins/muxo/plugin.json +2 -2
  52. package/plugins/muxo/skills/muxo/SKILL.md +42 -1
  53. package/plugins/muxo/skills/muxo/references/mcp.md +3 -2
  54. package/plugins/muxo/skills/setup/SKILL.md +8 -0
@@ -1,5 +1,5 @@
1
1
  import type { MuxoConfig } from "../config.js";
2
- import type { MemoryContextSummary, MemoryRecordKind } from "../types.js";
2
+ import type { GovernancePolicy, HumanFriendlyExplanation, LanguageMode, MemoryContextSummary, MemoryRecordKind, TemporalGraphFact, WorkspaceMemoryRecord } from "../types.js";
3
3
  /**
4
4
  * Supermemory v5 Contextual Brain & Context-Aware Tool Call Adapter.
5
5
  * Uses deterministic per-workspace namespaces (`/ns/muxo-v5-<hash>/...`)
@@ -85,3 +85,76 @@ export declare class SupermemoryAdapter {
85
85
  fundingSource: "muxo_funded" | "customer_byok_supermemory" | "local_fallback";
86
86
  }>;
87
87
  }
88
+ export interface ActiveMemoryDefaults {
89
+ defaultRegion?: string;
90
+ defaultGithubOwner?: string;
91
+ defaultGithubRepo?: string;
92
+ defaultGithubFullRepo?: string;
93
+ defaultSlackChannel?: string;
94
+ defaultEmail?: string;
95
+ defaultDomain?: string;
96
+ defaultUrl?: string;
97
+ defaultPlan?: string;
98
+ [key: string]: unknown;
99
+ }
100
+ export declare function extractActiveMemoryDefaults(params: {
101
+ memories?: WorkspaceMemoryRecord[];
102
+ temporalFacts?: TemporalGraphFact[];
103
+ preferences?: string[];
104
+ staticFacts?: string[];
105
+ }): {
106
+ activeDefaults: ActiveMemoryDefaults;
107
+ activeGuardrails: string[];
108
+ };
109
+ export declare function applyActiveMemoryToToolInput(params: {
110
+ toolSlug: string;
111
+ input: Record<string, unknown>;
112
+ activeDefaults?: ActiveMemoryDefaults;
113
+ }): {
114
+ mergedInput: Record<string, unknown>;
115
+ autoFilledInput: Record<string, unknown>;
116
+ explanations: string[];
117
+ };
118
+ export declare function parseNaturalLanguageMemoryInstruction(prompt: string): {
119
+ isMemoryInstruction: boolean;
120
+ title: string;
121
+ content: string;
122
+ kind: MemoryRecordKind;
123
+ extractedDefaults: ActiveMemoryDefaults;
124
+ temporalFacts: Array<{
125
+ subject: string;
126
+ predicate: string;
127
+ object: string;
128
+ summary: string;
129
+ }>;
130
+ humanSummary: string;
131
+ };
132
+ export declare function explainMemoryContext(params: {
133
+ memory: MemoryContextSummary;
134
+ localCount?: number;
135
+ activeTemporalCount?: number;
136
+ historicalTemporalCount?: number;
137
+ policy?: Partial<GovernancePolicy> | null;
138
+ languageMode?: LanguageMode;
139
+ }): HumanFriendlyExplanation;
140
+ /**
141
+ * Deterministic 64-dimensional semantic feature-hashing embedding vector
142
+ * compatible with Cloudflare Vectorize / Workers AI (`@cf/baai/bge-base-en-v1.5`) hybrid recall.
143
+ */
144
+ export declare function computeSemanticEmbedding(text: string, dimensions?: number): number[];
145
+ export declare function cosineSimilarity(vecA: number[], vecB: number[]): number;
146
+ export declare function rankMemoriesHybrid(params: {
147
+ query: string;
148
+ memories: WorkspaceMemoryRecord[];
149
+ temporalFacts?: TemporalGraphFact[];
150
+ limit?: number;
151
+ }): {
152
+ rankedMemories: Array<WorkspaceMemoryRecord & {
153
+ hybridScore: number;
154
+ vectorSimilarity: number;
155
+ lexicalOverlap: number;
156
+ }>;
157
+ vectorDimensions: number;
158
+ embeddingModel: string;
159
+ topScore: number;
160
+ };
@@ -1,5 +1,6 @@
1
1
  import crypto from "node:crypto";
2
2
  import Supermemory from "supermemory";
3
+ import { formatHumanFriendlyExplanation } from "../policy.js";
3
4
  // Profile buckets can hold plain strings or memory objects depending on API version.
4
5
  function toFactTexts(items) {
5
6
  if (!Array.isArray(items))
@@ -209,6 +210,20 @@ export class SupermemoryAdapter {
209
210
  if (preferences.length > 0) {
210
211
  mdLines.push("### Preferences", ...preferences.map((f) => `- ${f}`));
211
212
  }
213
+ const inferred = extractActiveMemoryDefaults({
214
+ preferences,
215
+ staticFacts: [
216
+ ...staticFacts,
217
+ ...dynamicFacts,
218
+ ...relevantMemories.map((m) => `${m.title}: ${m.snippet}`),
219
+ ],
220
+ });
221
+ if (Object.keys(inferred.activeDefaults).length > 0) {
222
+ promptLines.push(`Active Memory Defaults: ${Object.entries(inferred.activeDefaults)
223
+ .map(([k, v]) => `${k}=${String(v)}`)
224
+ .join(", ")}`);
225
+ mdLines.push("### Active Defaults (Auto-Fill)", ...Object.entries(inferred.activeDefaults).map(([k, v]) => `- **${k}**: \`${String(v)}\``));
226
+ }
212
227
  return {
213
228
  enabled: true,
214
229
  namespace,
@@ -224,6 +239,8 @@ export class SupermemoryAdapter {
224
239
  preferences,
225
240
  },
226
241
  relevantMemories,
242
+ activeDefaults: inferred.activeDefaults,
243
+ activeGuardrails: inferred.activeGuardrails,
227
244
  };
228
245
  }
229
246
  /**
@@ -350,3 +367,412 @@ export class SupermemoryAdapter {
350
367
  };
351
368
  }
352
369
  }
370
+ export function extractActiveMemoryDefaults(params) {
371
+ const activeDefaults = {};
372
+ const activeGuardrails = [];
373
+ const activeFacts = (params.temporalFacts || []).filter((f) => f.validTo === null);
374
+ for (const fact of activeFacts) {
375
+ const subj = String(fact.subject || "").toLowerCase();
376
+ const pred = String(fact.predicate || "").toLowerCase();
377
+ const obj = String(fact.object || "").trim();
378
+ if (!obj)
379
+ continue;
380
+ if (subj === "workspace_guardrail" || pred === "enforces_rule") {
381
+ if (!activeGuardrails.includes(obj))
382
+ activeGuardrails.push(obj);
383
+ continue;
384
+ }
385
+ if ((subj.includes("region") || pred.includes("region")) &&
386
+ !activeDefaults.defaultRegion) {
387
+ const regToken = obj.match(/\b((?:aws-)?(?:us|eu|ap|sa|ca|me|af)-(?:east|west|central|north|south|northeast|southeast)-[1-9])\b/i);
388
+ if (regToken) {
389
+ activeDefaults.defaultRegion = regToken[1].toLowerCase();
390
+ }
391
+ else if (!/\s/.test(obj)) {
392
+ activeDefaults.defaultRegion = obj;
393
+ }
394
+ }
395
+ if ((subj.includes("github") || subj.includes("repo") || pred.includes("repo")) &&
396
+ obj.includes("/") &&
397
+ !activeDefaults.defaultGithubFullRepo) {
398
+ const [owner, repo] = obj.split("/");
399
+ if (owner && repo) {
400
+ activeDefaults.defaultGithubOwner = owner.trim();
401
+ activeDefaults.defaultGithubRepo = repo.trim();
402
+ activeDefaults.defaultGithubFullRepo = `${owner.trim()}/${repo.trim()}`;
403
+ }
404
+ }
405
+ if ((subj.includes("slack") || pred.includes("channel")) &&
406
+ !activeDefaults.defaultSlackChannel) {
407
+ activeDefaults.defaultSlackChannel = obj.replace(/^#/, "").trim();
408
+ }
409
+ if ((subj.includes("email") || pred.includes("email")) &&
410
+ obj.includes("@") &&
411
+ !activeDefaults.defaultEmail) {
412
+ activeDefaults.defaultEmail = obj;
413
+ }
414
+ if ((subj.includes("domain") || pred.includes("domain")) &&
415
+ !activeDefaults.defaultDomain) {
416
+ activeDefaults.defaultDomain = obj.replace(/^https?:\/\//i, "").replace(/\/.*$/, "");
417
+ }
418
+ }
419
+ const textCorpus = [
420
+ ...(params.memories || []).map((m) => `${m.title}: ${m.content}`),
421
+ ...(params.preferences || []),
422
+ ...(params.staticFacts || []),
423
+ ];
424
+ for (const rawText of textCorpus) {
425
+ const text = String(rawText || "");
426
+ if (!activeDefaults.defaultRegion) {
427
+ const regMatch = text.match(/\b((?:aws-)?(?:us|eu|ap|sa|ca|me|af)-(?:east|west|central|north|south|northeast|southeast)-[1-9])\b/i);
428
+ if (regMatch) {
429
+ activeDefaults.defaultRegion = regMatch[1].toLowerCase();
430
+ }
431
+ }
432
+ if (!activeDefaults.defaultGithubFullRepo) {
433
+ const repoMatch = text.match(/(?:default\s+(?:github\s+)?repo(?:sitory)?|github\s+repo(?:sitory)?|primary\s+repo(?:sitory)?|repo\s+is)\s*(?:is|:|=)?\s*["'`]?([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)["'`]?/i) ||
434
+ text.match(/\bgithub\.com\/([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)\b/i);
435
+ if (repoMatch) {
436
+ const [owner, repo] = repoMatch[1].split("/");
437
+ if (owner && repo) {
438
+ activeDefaults.defaultGithubOwner = owner;
439
+ activeDefaults.defaultGithubRepo = repo;
440
+ activeDefaults.defaultGithubFullRepo = `${owner}/${repo}`;
441
+ }
442
+ }
443
+ }
444
+ if (!activeDefaults.defaultSlackChannel) {
445
+ const slackMatch = text.match(/(?:default\s+(?:slack\s+)?channel|slack\s+channel|post\s+to\s+channel)\s*(?:is|:|=)?\s*#?([a-z0-9_-]{2,40})\b/i) || text.match(/\B#([a-z][a-z0-9_-]{2,35})\b/);
446
+ if (slackMatch) {
447
+ activeDefaults.defaultSlackChannel = slackMatch[1].toLowerCase();
448
+ }
449
+ }
450
+ if (!activeDefaults.defaultEmail) {
451
+ const emailMatch = text.match(/(?:default\s+(?:recipient\s+|alert\s+)?email|send\s+emails?\s+to|notify\s+email|recipient_email)\s*(?:is|:|=)?\s*([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})/i);
452
+ if (emailMatch) {
453
+ activeDefaults.defaultEmail = emailMatch[1];
454
+ }
455
+ }
456
+ if (!activeDefaults.defaultDomain) {
457
+ const domainMatch = text.match(/(?:default\s+domain|primary\s+domain|company\s+domain)\s*(?:is|:|=)?\s*(?:https?:\/\/)?([a-z0-9.-]+\.[a-z]{2,})\b/i);
458
+ if (domainMatch) {
459
+ activeDefaults.defaultDomain = domainMatch[1].toLowerCase();
460
+ }
461
+ }
462
+ if (/workspace\s+guardrail/i.test(text)) {
463
+ const cleaned = text.replace(/^.*?Workspace Guardrail:\s*/i, "").trim();
464
+ if (cleaned && !activeGuardrails.includes(cleaned)) {
465
+ activeGuardrails.push(cleaned);
466
+ }
467
+ }
468
+ }
469
+ return {
470
+ activeDefaults,
471
+ activeGuardrails,
472
+ };
473
+ }
474
+ export function applyActiveMemoryToToolInput(params) {
475
+ const mergedInput = { ...(params.input || {}) };
476
+ const autoFilledInput = {};
477
+ const explanations = [];
478
+ const defaults = params.activeDefaults || {};
479
+ const slug = String(params.toolSlug || "").toLowerCase();
480
+ // 1. Cloud provisioning tools: auto-fill region if not explicitly provided
481
+ if (slug.startsWith("resource.") && defaults.defaultRegion) {
482
+ if (!mergedInput.region || String(mergedInput.region).trim() === "") {
483
+ mergedInput.region = defaults.defaultRegion;
484
+ autoFilledInput.region = defaults.defaultRegion;
485
+ explanations.push(`Auto-filled region="${defaults.defaultRegion}" from Supermemory`);
486
+ }
487
+ }
488
+ // 2. GitHub tools: auto-fill owner & repo if missing or generic placeholder
489
+ if ((slug.startsWith("app.github.") || slug === "instant.github.repo_intel") &&
490
+ defaults.defaultGithubOwner &&
491
+ defaults.defaultGithubRepo) {
492
+ const isGenericPlaceholder = mergedInput.owner === "muxo-ai" && mergedInput.repo === "platform";
493
+ if (!mergedInput.owner || isGenericPlaceholder) {
494
+ mergedInput.owner = defaults.defaultGithubOwner;
495
+ autoFilledInput.owner = defaults.defaultGithubOwner;
496
+ }
497
+ if (!mergedInput.repo || isGenericPlaceholder) {
498
+ mergedInput.repo = defaults.defaultGithubRepo;
499
+ autoFilledInput.repo = defaults.defaultGithubRepo;
500
+ }
501
+ if (autoFilledInput.owner || autoFilledInput.repo) {
502
+ explanations.push(`Auto-filled GitHub repo "${defaults.defaultGithubOwner}/${defaults.defaultGithubRepo}" from Supermemory`);
503
+ }
504
+ }
505
+ // 3. Slack tools: auto-fill channel if missing or generic placeholder ("general")
506
+ if (slug.startsWith("app.slack.") && defaults.defaultSlackChannel) {
507
+ if (!mergedInput.channel || mergedInput.channel === "general") {
508
+ mergedInput.channel = defaults.defaultSlackChannel;
509
+ autoFilledInput.channel = defaults.defaultSlackChannel;
510
+ explanations.push(`Auto-filled Slack channel "#${defaults.defaultSlackChannel}" from Supermemory`);
511
+ }
512
+ }
513
+ // 4. Gmail send_email: auto-fill recipient_email if missing or placeholder
514
+ if (slug === "app.gmail.send_email" && defaults.defaultEmail) {
515
+ if (!mergedInput.recipient_email ||
516
+ mergedInput.recipient_email === "team@example.com") {
517
+ mergedInput.recipient_email = defaults.defaultEmail;
518
+ autoFilledInput.recipient_email = defaults.defaultEmail;
519
+ explanations.push(`Auto-filled recipient_email="${defaults.defaultEmail}" from Supermemory`);
520
+ }
521
+ }
522
+ // 5. DNS / Domain tools: auto-fill domain if missing or example.com
523
+ if ((slug === "instant.dns.resolve" || slug === "instant.dns.lookup") &&
524
+ defaults.defaultDomain) {
525
+ if (!mergedInput.domain || mergedInput.domain === "example.com") {
526
+ mergedInput.domain = defaults.defaultDomain;
527
+ autoFilledInput.domain = defaults.defaultDomain;
528
+ explanations.push(`Auto-filled domain="${defaults.defaultDomain}" from Supermemory`);
529
+ }
530
+ }
531
+ // 6. SEO / Web tools: auto-fill url from defaultDomain if missing or generic placeholder
532
+ if ((slug === "instant.seo.audit" ||
533
+ slug === "instant.web.scrape" ||
534
+ slug === "instant.web.crawl") &&
535
+ defaults.defaultDomain) {
536
+ if (!mergedInput.url ||
537
+ mergedInput.url === "https://example.com") {
538
+ const normalizedUrl = defaults.defaultDomain.startsWith("http")
539
+ ? defaults.defaultDomain
540
+ : `https://${defaults.defaultDomain}`;
541
+ mergedInput.url = normalizedUrl;
542
+ autoFilledInput.url = normalizedUrl;
543
+ explanations.push(`Auto-filled url="${normalizedUrl}" from Supermemory`);
544
+ }
545
+ }
546
+ return {
547
+ mergedInput,
548
+ autoFilledInput,
549
+ explanations,
550
+ };
551
+ }
552
+ export function parseNaturalLanguageMemoryInstruction(prompt) {
553
+ const cleanPrompt = String(prompt || "").trim();
554
+ const isMemoryInstruction = /^(?:hey\s+muxo[,:\s]*)?(?:please\s+)?(?:remember(?:\s+that)?|save\s+to\s+memory|store\s+in\s+memory|note\s+that|set\s+(?:our\s+|my\s+)?default|our\s+default\s+(?:github\s+repo|repo|region|slack\s+channel|email|domain)\s+is|my\s+default\s+(?:github\s+repo|repo|region|slack\s+channel|email|domain)\s+is)\b/i.test(cleanPrompt);
555
+ const normalizedBody = cleanPrompt
556
+ .replace(/^(?:hey\s+muxo[,:\s]*)?(?:please\s+)?(?:remember(?:\s+that)?|save\s+to\s+memory|store\s+in\s+memory|note\s+that)[:\s]*/i, "")
557
+ .trim();
558
+ const { activeDefaults } = extractActiveMemoryDefaults({
559
+ preferences: [cleanPrompt],
560
+ staticFacts: [normalizedBody],
561
+ });
562
+ const temporalFacts = [];
563
+ const learnedParts = [];
564
+ if (activeDefaults.defaultRegion) {
565
+ temporalFacts.push({
566
+ subject: "workspace:default_region",
567
+ predicate: "prefers_region",
568
+ object: activeDefaults.defaultRegion,
569
+ summary: `Default cloud region is ${activeDefaults.defaultRegion}`,
570
+ });
571
+ learnedParts.push(`default cloud region = ${activeDefaults.defaultRegion}`);
572
+ }
573
+ if (activeDefaults.defaultGithubFullRepo) {
574
+ temporalFacts.push({
575
+ subject: "workspace:default_github_repo",
576
+ predicate: "prefers_repo",
577
+ object: activeDefaults.defaultGithubFullRepo,
578
+ summary: `Default GitHub repository is ${activeDefaults.defaultGithubFullRepo}`,
579
+ });
580
+ learnedParts.push(`default GitHub repo = ${activeDefaults.defaultGithubFullRepo}`);
581
+ }
582
+ if (activeDefaults.defaultSlackChannel) {
583
+ temporalFacts.push({
584
+ subject: "workspace:default_slack_channel",
585
+ predicate: "prefers_channel",
586
+ object: activeDefaults.defaultSlackChannel,
587
+ summary: `Default Slack channel is #${activeDefaults.defaultSlackChannel}`,
588
+ });
589
+ learnedParts.push(`default Slack channel = #${activeDefaults.defaultSlackChannel}`);
590
+ }
591
+ if (activeDefaults.defaultEmail) {
592
+ temporalFacts.push({
593
+ subject: "workspace:default_email",
594
+ predicate: "prefers_email",
595
+ object: activeDefaults.defaultEmail,
596
+ summary: `Default notification email is ${activeDefaults.defaultEmail}`,
597
+ });
598
+ learnedParts.push(`default email = ${activeDefaults.defaultEmail}`);
599
+ }
600
+ if (activeDefaults.defaultDomain) {
601
+ temporalFacts.push({
602
+ subject: "workspace:default_domain",
603
+ predicate: "prefers_domain",
604
+ object: activeDefaults.defaultDomain,
605
+ summary: `Default workspace domain is ${activeDefaults.defaultDomain}`,
606
+ });
607
+ learnedParts.push(`default domain = ${activeDefaults.defaultDomain}`);
608
+ }
609
+ if (temporalFacts.length === 0 && isMemoryInstruction && normalizedBody) {
610
+ temporalFacts.push({
611
+ subject: "workspace:operator_preference",
612
+ predicate: "remembers",
613
+ object: normalizedBody.slice(0, 140),
614
+ summary: normalizedBody.slice(0, 180),
615
+ });
616
+ }
617
+ const title = learnedParts.length > 0
618
+ ? `Learned Default: ${learnedParts.join(", ").slice(0, 80)}`
619
+ : `Remembered Preference: ${(normalizedBody || cleanPrompt).slice(0, 72)}`;
620
+ const humanSummary = learnedParts.length > 0
621
+ ? `Remembered in Supermemory and enabled auto-fill for: ${learnedParts.join(" · ")}.`
622
+ : `Saved to Supermemory: "${normalizedBody || cleanPrompt}"`;
623
+ return {
624
+ isMemoryInstruction,
625
+ title,
626
+ content: normalizedBody || cleanPrompt,
627
+ kind: "preference",
628
+ extractedDefaults: activeDefaults,
629
+ temporalFacts,
630
+ humanSummary,
631
+ };
632
+ }
633
+ export function explainMemoryContext(params) {
634
+ const mem = params.memory;
635
+ const defaultsEntries = Object.entries(mem.activeDefaults || {});
636
+ const defaultsPlain = defaultsEntries.length > 0
637
+ ? `Learned defaults active (${defaultsEntries.map(([k, v]) => `${k}: ${String(v)}`).join(", ")}) and automatically fill into matching tool calls.`
638
+ : "No learned defaults set yet (say 'Remember our default region is us-east-1' or 'Remember our default repo is owner/repo' to set one).";
639
+ const factsCount = (mem.staticFacts?.length || 0) +
640
+ (mem.dynamicContext?.length || 0) +
641
+ (params.localCount || 0);
642
+ const scanSafe = mem.contextPoisoningScan?.safe !== false;
643
+ const headline = defaultsEntries.length > 0
644
+ ? `Muxo Memory active with ${defaultsEntries.length} auto-fill default${defaultsEntries.length === 1 ? "" : "s"} and ${factsCount} stored workspace item${factsCount === 1 ? "" : "s"}.`
645
+ : `Muxo Memory active with ${factsCount} stored workspace item${factsCount === 1 ? "" : "s"}.`;
646
+ const nonTechnical = [
647
+ headline,
648
+ defaultsPlain,
649
+ mem.recalledMemories && mem.recalledMemories.length > 0
650
+ ? `Recalled ${mem.recalledMemories.length} relevant memory note${mem.recalledMemories.length === 1 ? "" : "s"} for this context.`
651
+ : "All stored memories are secret-scrubbed so API keys and passwords are never saved.",
652
+ scanSafe
653
+ ? "Memory safety check: Clean (no prompt-injection or poisoning patterns detected)."
654
+ : `Memory safety warning: ${mem.contextPoisoningScan?.findingsCount || 1} suspicious pattern(s) flagged (${mem.contextPoisoningScan?.riskLevel || "medium"}).`,
655
+ ].join(" ");
656
+ const technical = `namespace=${mem.namespace} | enabled=${mem.enabled} | fundingSource=${mem.fundingSource || "local_fallback"} | staticFacts=${mem.staticFacts?.length || 0} | dynamicContext=${mem.dynamicContext?.length || 0} | recalledMemories=${mem.recalledMemories?.length || 0} | localRecords=${params.localCount ?? 0} | temporalGraph=(active=${params.activeTemporalCount ?? (mem.temporalFacts?.length || 0)}, superseded=${params.historicalTemporalCount ?? 0}) | activeDefaults=${JSON.stringify(mem.activeDefaults || {})} | contextPoisoning=(safe=${scanSafe}, risk=${mem.contextPoisoningScan?.riskLevel || "none"}, findings=${mem.contextPoisoningScan?.findingsCount || 0})`;
657
+ return formatHumanFriendlyExplanation({
658
+ headline,
659
+ nonTechnical,
660
+ technical,
661
+ policy: params.policy,
662
+ languageMode: params.languageMode,
663
+ });
664
+ }
665
+ /**
666
+ * Deterministic 64-dimensional semantic feature-hashing embedding vector
667
+ * compatible with Cloudflare Vectorize / Workers AI (`@cf/baai/bge-base-en-v1.5`) hybrid recall.
668
+ */
669
+ export function computeSemanticEmbedding(text, dimensions = 64) {
670
+ const vec = new Array(dimensions).fill(0);
671
+ const normalized = String(text || "")
672
+ .toLowerCase()
673
+ .replace(/[^a-z0-9_./#@-\s]/g, " ");
674
+ const tokens = normalized
675
+ .split(/\s+/)
676
+ .map((t) => t.trim())
677
+ .filter((t) => t.length >= 2);
678
+ if (tokens.length === 0)
679
+ return vec;
680
+ // Semantic concept synonym expansion so related queries ("db"/"postgres", "mail"/"email", "repo"/"github") map to shared vector dimensions
681
+ const expandedTokens = [...tokens];
682
+ for (const tok of tokens) {
683
+ if (/^(postgres|postgresql|neon|supabase|sql|db|database)$/.test(tok)) {
684
+ expandedTokens.push("concept_database", "concept_postgres");
685
+ }
686
+ if (/^(redis|upstash|cache|kv)$/.test(tok)) {
687
+ expandedTokens.push("concept_cache", "concept_redis");
688
+ }
689
+ if (/^(repo|repository|github|git|pr|issue)$/.test(tok)) {
690
+ expandedTokens.push("concept_github", "concept_repo");
691
+ }
692
+ if (/^(region|us-east-1|us-west-2|eu-central-1|zone|datacenter)$/.test(tok)) {
693
+ expandedTokens.push("concept_region", "concept_cloud");
694
+ }
695
+ if (/^(slack|channel|chat|alert|incident)$/.test(tok)) {
696
+ expandedTokens.push("concept_slack", "concept_messaging");
697
+ }
698
+ if (/^(email|gmail|inbox|recipient|mail)$/.test(tok)) {
699
+ expandedTokens.push("concept_email", "concept_communication");
700
+ }
701
+ }
702
+ for (let i = 0; i < expandedTokens.length; i++) {
703
+ const feature = expandedTokens[i];
704
+ const digest = crypto.createHash("md5").update(feature).digest();
705
+ const dimIdx = digest[0] % dimensions;
706
+ const sign = (digest[1] & 1) === 0 ? 1 : -1;
707
+ const weight = feature.startsWith("concept_") ? 1.5 : 1.0;
708
+ vec[dimIdx] += sign * weight;
709
+ // Character trigram projection for sub-word resilience
710
+ for (let c = 0; c <= feature.length - 3; c++) {
711
+ const tri = feature.slice(c, c + 3);
712
+ const triDigest = crypto.createHash("md5").update(`tri:${tri}`).digest();
713
+ const triIdx = triDigest[0] % dimensions;
714
+ const triSign = (triDigest[1] & 1) === 0 ? 0.35 : -0.35;
715
+ vec[triIdx] += triSign;
716
+ }
717
+ }
718
+ const norm = Math.sqrt(vec.reduce((acc, v) => acc + v * v, 0));
719
+ if (norm > 0) {
720
+ for (let d = 0; d < dimensions; d++) {
721
+ vec[d] = Number((vec[d] / norm).toFixed(6));
722
+ }
723
+ }
724
+ return vec;
725
+ }
726
+ export function cosineSimilarity(vecA, vecB) {
727
+ const len = Math.min(vecA.length, vecB.length);
728
+ if (len === 0)
729
+ return 0;
730
+ let dot = 0;
731
+ let normA = 0;
732
+ let normB = 0;
733
+ for (let i = 0; i < len; i++) {
734
+ dot += vecA[i] * vecB[i];
735
+ normA += vecA[i] * vecA[i];
736
+ normB += vecB[i] * vecB[i];
737
+ }
738
+ if (normA === 0 || normB === 0)
739
+ return 0;
740
+ return Math.max(0, Math.min(1, dot / (Math.sqrt(normA) * Math.sqrt(normB))));
741
+ }
742
+ export function rankMemoriesHybrid(params) {
743
+ const q = String(params.query || "").trim();
744
+ const qVec = computeSemanticEmbedding(q);
745
+ const qTokens = q
746
+ .toLowerCase()
747
+ .split(/[^a-z0-9_./#@-]+/)
748
+ .filter((t) => t.length >= 2);
749
+ const nowMs = Date.now();
750
+ const scored = (params.memories || []).map((mem) => {
751
+ const corpus = `${mem.title} ${mem.content} ${mem.kind}`;
752
+ const docVec = computeSemanticEmbedding(corpus);
753
+ const vectorSim = q ? cosineSimilarity(qVec, docVec) : 0.5;
754
+ const lowerCorpus = corpus.toLowerCase();
755
+ const matchedTokens = qTokens.length > 0
756
+ ? qTokens.filter((tok) => lowerCorpus.includes(tok)).length
757
+ : 1;
758
+ const lexicalOverlap = qTokens.length > 0 ? matchedTokens / qTokens.length : 0.5;
759
+ const ageHours = Math.max(0, (nowMs - new Date(mem.createdAt || nowMs).getTime()) / 3_600_000);
760
+ const recencyWeight = 1 / (1 + ageHours / 168); // 1-week half-life
761
+ const hybridScore = Number((0.5 * vectorSim + 0.35 * lexicalOverlap + 0.15 * recencyWeight).toFixed(4));
762
+ return {
763
+ ...mem,
764
+ hybridScore,
765
+ vectorSimilarity: Number(vectorSim.toFixed(4)),
766
+ lexicalOverlap: Number(lexicalOverlap.toFixed(4)),
767
+ };
768
+ });
769
+ scored.sort((a, b) => b.hybridScore - a.hybridScore);
770
+ const limit = Math.max(1, Math.min(50, params.limit || 10));
771
+ const top = scored.slice(0, limit);
772
+ return {
773
+ rankedMemories: top,
774
+ vectorDimensions: 64,
775
+ embeddingModel: "@cf/baai/bge-base-en-v1.5 (cloudflare-vectorize-hybrid)",
776
+ topScore: top[0]?.hybridScore || 0,
777
+ };
778
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Muxo-managed stand-ins for Stripe v2 Provisioning objects, returned when no Stripe key is
3
+ * configured so both the Node server and the edge worker answer with the same shapes.
4
+ */
5
+ export type ManagedProvisioningObject = Record<string, unknown> & {
6
+ source: "muxo_managed";
7
+ };
8
+ export type ManagedResourceAction = "remove" | "unlink" | "rotate_credentials" | "submit_information";
9
+ export declare function managedProviderConnectionList(): ManagedProvisioningObject;
10
+ export declare function managedProviderConnectionUnlink(id: string): ManagedProvisioningObject;
11
+ export declare function managedProviderConnectionRequest(params: {
12
+ id?: string;
13
+ provider?: string;
14
+ requestStatus?: string;
15
+ }): ManagedProvisioningObject;
16
+ export declare function managedResource(params: {
17
+ id?: string;
18
+ provider?: string;
19
+ serviceRef?: string;
20
+ name?: string | null;
21
+ environment?: string;
22
+ catalog?: string;
23
+ status?: string;
24
+ }): ManagedProvisioningObject;
25
+ export declare function managedResourceAction(id: string, action: ManagedResourceAction): ManagedProvisioningObject;
26
+ export declare function managedConnectedAccount(params: {
27
+ id?: string;
28
+ contactEmail?: string;
29
+ displayName?: string;
30
+ country?: string;
31
+ entityType?: "individual" | "company";
32
+ }): ManagedProvisioningObject;
33
+ export declare function managedConnectedAccountLink(account: string): ManagedProvisioningObject;
34
+ export declare function managedConnectedAccountSession(params: {
35
+ account: string;
36
+ enableAccountManagement?: boolean;
37
+ enableNotificationBanner?: boolean;
38
+ }): ManagedProvisioningObject;
39
+ export declare function managedPaymentMethodRequest(params: {
40
+ publicWebUrl: string;
41
+ livemode: boolean;
42
+ }): ManagedProvisioningObject;
43
+ export declare const DEFAULT_PROVISIONING_EVENT_TYPES: string[];
44
+ export declare function managedEventDestination(params: {
45
+ url: string;
46
+ name?: string;
47
+ events?: string[];
48
+ }): ManagedProvisioningObject;
49
+ /** What Muxo does with a Stripe v2 thin event, keyed by event type. */
50
+ export declare function provisioningEventAction(eventType: string, hasRelatedObject: boolean): string;