@mushi-mushi/core 1.14.0 → 1.16.0

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/CONTRIBUTING.md CHANGED
@@ -58,12 +58,12 @@ packages/
58
58
  react-native/ React Native SDK (MIT)
59
59
  cli/ CLI tool (MIT)
60
60
  mcp/ MCP server for coding agents (MIT)
61
- server/ Supabase Edge Functions (BSL)
62
- agents/ Agentic fix pipeline (BSL)
63
- verify/ Fix verification (BSL)
61
+ server/ Supabase Edge Functions (AGPLv3)
62
+ agents/ Agentic fix pipeline (AGPLv3)
63
+ verify/ Fix verification (AGPLv3)
64
64
  apps/
65
65
  admin/ Admin dashboard (React + Tailwind)
66
- docs/ Documentation site (planned)
66
+ docs/ Documentation site (Nextra — apps/docs)
67
67
  tooling/
68
68
  eslint-config/ Shared ESLint flat config
69
69
  tsconfig/ Shared TypeScript configs
@@ -81,6 +81,30 @@ tooling/
81
81
  ```
82
82
  6. Open a pull request
83
83
 
84
+ ### Documentation (docs-as-code)
85
+
86
+ If your PR changes **user-visible SDK or CLI behavior**, update docs in the **same PR**:
87
+
88
+ | Surface | When to update |
89
+ | --- | --- |
90
+ | `packages/*/README.md` | npm-facing install/API/config changes for that package |
91
+ | `apps/docs/content/**/*.mdx` | Long-form guides, quickstarts, admin console docs |
92
+ | Root `README.md` | Marketing stats only when counts change — run `pnpm check:docs-stats` |
93
+
94
+ Guardrails (run locally before pushing):
95
+
96
+ ```bash
97
+ pnpm check:docs-stats # root README stat badges
98
+ pnpm check:sdk-version-matrix # apps/docs/content/sdks/index.mdx versions
99
+ pnpm check:internal-doc-links # dead /foo links in MDX
100
+ pnpm check:onboarding-drift # phantom MCP env vars / stale tool names
101
+ pnpm check:bundle-docs # @mushi-mushi/web size-limit vs README
102
+ pnpm gen:llms-txt # regenerate apps/docs/public/llms.txt after nav changes
103
+ pnpm gen:mcp-tools-doc # regenerate sdks/mcp-tools.generated.mdx from catalog.ts
104
+ ```
105
+
106
+ README changes on npm packages only appear on [npmjs.com](https://www.npmjs.com) after the next **Changesets publish**.
107
+
84
108
  ## Changesets
85
109
 
86
110
  We use [Changesets](https://github.com/changesets/changesets) for versioning. If your PR modifies a published package (`core`, `web`, `react`, `vue`, `svelte`, `angular`, `react-native`, `cli`, `mcp`), add a changeset:
@@ -93,13 +117,30 @@ Select the affected packages, the semver bump type, and write a summary. The cha
93
117
 
94
118
  ## Release flow
95
119
 
96
- Releases are fully automated. Maintainers don't run `npm publish` by hand.
120
+ Releases are fully automated once the version PR is merged. Maintainers don't run
121
+ `npm publish` by hand for routine bumps. See **[`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md)**
122
+ for the full production runbook (edge functions, admin SPA, docs site, migrations).
97
123
 
98
124
  1. PRs land on `master` with one or more changeset files in `.changeset/`.
99
- 2. `release.yml` runs on every push to `master`. It opens (or updates) a `chore: version packages` PR that bumps every affected `package.json`, rolls up the changelogs, and deletes the consumed changesets.
100
- 3. Merging that "Version Packages" PR re-fires `release.yml`. The publish step authenticates to npm via **OpenID Connect (OIDC) Trusted Publishers** — no long-lived `NPM_TOKEN` is exchanged — and every tarball ships with a **Sigstore provenance attestation** uploaded to the public transparency log.
125
+ Orphaned changesets (only ignored packages) fail `pnpm check:changeset-orphans`.
126
+ 2. `release.yml` runs on every push to `master`. It opens (or updates) a
127
+ **`chore: version packages`** PR on `changeset-release/master` that bumps
128
+ affected `package.json` files, rolls up changelogs, and deletes consumed
129
+ changesets.
130
+ 3. **Wait for CI on the version PR.** If checks don't appear (bot-branch
131
+ suppression), push an empty commit to `changeset-release/master`. If
132
+ `check:sdk-version-matrix` fails, run `pnpm gen:sdk-version-matrix` on that
133
+ branch and commit `apps/docs/content/sdks/index.mdx`.
134
+ 4. Merge the version PR. The publish step uses **OIDC Trusted Publishers** +
135
+ Sigstore provenance (with `NPM_TOKEN` only for brand-new package bootstrap).
136
+ 5. **Manually dispatch Release** unless a run starts within ~2 minutes:
137
+ **Actions → Release → Run workflow → `master`**. Squash-merges attributed to
138
+ `github-actions[bot]` usually suppress the auto `push` trigger — manual
139
+ dispatch is the normal path, not a fallback of last resort.
101
140
 
102
- If GitHub's anti-loop protection suppresses the auto re-fire (the squash merge can be attributed to `github-actions[bot]`), trigger the workflow manually: **Actions → release → Run workflow → master**.
141
+ ```bash
142
+ gh workflow run release.yml --ref master
143
+ ```
103
144
 
104
145
  ### Adding a brand-new publishable package
105
146
 
@@ -146,7 +187,7 @@ chore: bump dependencies
146
187
  ## License
147
188
 
148
189
  - SDK packages are MIT — your contributions will be MIT-licensed
149
- - Server/agents/verify are BSL 1.1 — contributions to those packages fall under BSL
190
+ - Server/agents/verify are AGPLv3 — contributions to those packages fall under AGPLv3
150
191
 
151
192
  ## Questions?
152
193
 
package/dist/index.cjs CHANGED
@@ -43,6 +43,7 @@ function formatBytes(n) {
43
43
  }
44
44
 
45
45
  // src/api-client.ts
46
+ var MUSHI_USER_TOKEN_HEADER = "X-Mushi-User-Token";
46
47
  var DEFAULT_API_ENDPOINT = "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api";
47
48
  var MUSHI_INTERNAL_HEADER = "X-Mushi-Internal";
48
49
  var MUSHI_INTERNAL_INIT_MARKER = "__mushiInternal";
@@ -54,13 +55,15 @@ function createApiClient(options) {
54
55
  apiKey,
55
56
  apiEndpoint = DEFAULT_API_ENDPOINT,
56
57
  timeout = DEFAULT_TIMEOUT,
57
- maxRetries = DEFAULT_MAX_RETRIES
58
+ maxRetries = DEFAULT_MAX_RETRIES,
59
+ getUserToken
58
60
  } = options;
59
61
  let baseUrl = apiEndpoint.replace(/\/$/, "");
60
62
  async function request(method, path, body, retries = maxRetries, internalKind, extraHeaders) {
61
63
  const url = `${baseUrl}${path}`;
62
64
  const controller = new AbortController();
63
65
  const timer = setTimeout(() => controller.abort(), timeout);
66
+ const userToken = getUserToken?.() ?? null;
64
67
  try {
65
68
  const response = await fetch(url, {
66
69
  method,
@@ -68,6 +71,7 @@ function createApiClient(options) {
68
71
  "Content-Type": "application/json",
69
72
  "X-Mushi-Api-Key": apiKey,
70
73
  "X-Mushi-Project": projectId,
74
+ ...userToken ? { [MUSHI_USER_TOKEN_HEADER]: userToken } : {},
71
75
  ...internalKind ? { [MUSHI_INTERNAL_HEADER]: internalKind } : {},
72
76
  ...extraHeaders
73
77
  },
@@ -170,6 +174,19 @@ function createApiClient(options) {
170
174
  async getSdkConfig() {
171
175
  return request("GET", "/v1/sdk/config", void 0, maxRetries, "sdk-config");
172
176
  },
177
+ async askAssistant(input) {
178
+ return request(
179
+ "POST",
180
+ "/v1/sdk/assistant",
181
+ {
182
+ message: input.message,
183
+ threadId: input.threadId ?? null,
184
+ context: input.context ?? null
185
+ },
186
+ 1,
187
+ "community"
188
+ );
189
+ },
173
190
  async getLatestSdkVersion(packageName) {
174
191
  const query = new URLSearchParams({ package: packageName }).toString();
175
192
  return request("GET", `/v1/sdk/latest-version?${query}`, void 0, maxRetries, "sdk-config");
@@ -447,6 +464,60 @@ function writeCache(storage, projectId, entry) {
447
464
  }
448
465
  }
449
466
 
467
+ // src/env-config.ts
468
+ function first(...values) {
469
+ return values.find((v) => v !== void 0 && v !== "");
470
+ }
471
+ function tryImportMetaEnv(key) {
472
+ try {
473
+ const env = undefined;
474
+ return typeof env === "object" && env !== null ? env[key] : void 0;
475
+ } catch {
476
+ return void 0;
477
+ }
478
+ }
479
+ function readProcessEnv(read) {
480
+ try {
481
+ return read();
482
+ } catch {
483
+ return void 0;
484
+ }
485
+ }
486
+ function resolveEnvConfig() {
487
+ const projectId = first(
488
+ tryImportMetaEnv("VITE_MUSHI_PROJECT_ID"),
489
+ tryImportMetaEnv("NEXT_PUBLIC_MUSHI_PROJECT_ID"),
490
+ tryImportMetaEnv("NUXT_PUBLIC_MUSHI_PROJECT_ID"),
491
+ tryImportMetaEnv("EXPO_PUBLIC_MUSHI_PROJECT_ID"),
492
+ readProcessEnv(() => process.env.NEXT_PUBLIC_MUSHI_PROJECT_ID),
493
+ readProcessEnv(() => process.env.EXPO_PUBLIC_MUSHI_PROJECT_ID),
494
+ readProcessEnv(() => process.env.MUSHI_PROJECT_ID)
495
+ );
496
+ const apiKey = first(
497
+ tryImportMetaEnv("VITE_MUSHI_API_KEY"),
498
+ tryImportMetaEnv("NEXT_PUBLIC_MUSHI_API_KEY"),
499
+ tryImportMetaEnv("NUXT_PUBLIC_MUSHI_API_KEY"),
500
+ tryImportMetaEnv("EXPO_PUBLIC_MUSHI_API_KEY"),
501
+ readProcessEnv(() => process.env.NEXT_PUBLIC_MUSHI_API_KEY),
502
+ readProcessEnv(() => process.env.EXPO_PUBLIC_MUSHI_API_KEY),
503
+ readProcessEnv(() => process.env.MUSHI_API_KEY)
504
+ );
505
+ const apiEndpoint = first(
506
+ tryImportMetaEnv("VITE_MUSHI_API_ENDPOINT"),
507
+ tryImportMetaEnv("NEXT_PUBLIC_MUSHI_API_ENDPOINT"),
508
+ tryImportMetaEnv("NUXT_PUBLIC_MUSHI_API_ENDPOINT"),
509
+ tryImportMetaEnv("EXPO_PUBLIC_MUSHI_API_ENDPOINT"),
510
+ readProcessEnv(() => process.env.NEXT_PUBLIC_MUSHI_API_ENDPOINT),
511
+ readProcessEnv(() => process.env.EXPO_PUBLIC_MUSHI_API_ENDPOINT),
512
+ readProcessEnv(() => process.env.MUSHI_API_ENDPOINT)
513
+ );
514
+ const result = {};
515
+ if (projectId) result.projectId = projectId;
516
+ if (apiKey) result.apiKey = apiKey;
517
+ if (apiEndpoint) result.apiEndpoint = apiEndpoint;
518
+ return result;
519
+ }
520
+
450
521
  // src/pre-filter.ts
451
522
  var DEFAULT_MIN_LENGTH = 10;
452
523
  var DEFAULT_MAX_LENGTH = 2e3;
@@ -579,20 +650,27 @@ function formatPretty(entry) {
579
650
  function formatJson(entry) {
580
651
  return JSON.stringify(entry);
581
652
  }
582
- function emit(level, formatted) {
583
- switch (level) {
584
- case "error":
585
- case "fatal":
653
+ function makeEmitter(destination) {
654
+ if (destination === "stderr") {
655
+ return (level, formatted) => {
586
656
  console.error(formatted);
587
- break;
588
- case "warn":
589
- console.warn(formatted);
590
- break;
591
- default:
592
- console.log(formatted);
657
+ };
593
658
  }
659
+ return (level, formatted) => {
660
+ switch (level) {
661
+ case "error":
662
+ case "fatal":
663
+ console.error(formatted);
664
+ break;
665
+ case "warn":
666
+ console.warn(formatted);
667
+ break;
668
+ default:
669
+ console.log(formatted);
670
+ }
671
+ };
594
672
  }
595
- function buildLogger(scope, minLevel, baseMeta, formatter) {
673
+ function buildLogger(scope, minLevel, baseMeta, formatter, emit) {
596
674
  let currentLevel = minLevel;
597
675
  function log(level, msg, meta) {
598
676
  if (LEVEL_VALUE[level] < LEVEL_VALUE[currentLevel]) return;
@@ -617,7 +695,8 @@ function buildLogger(scope, minLevel, baseMeta, formatter) {
617
695
  `${scope}:${childScope}`,
618
696
  currentLevel,
619
697
  { ...baseMeta, ...childMeta },
620
- formatter
698
+ formatter,
699
+ emit
621
700
  );
622
701
  },
623
702
  setLevel(level) {
@@ -630,11 +709,13 @@ function createLogger(options) {
630
709
  scope,
631
710
  level = "info",
632
711
  meta = {},
633
- format = "auto"
712
+ format = "auto",
713
+ destination = "stdout"
634
714
  } = options;
635
715
  const resolvedFormat = format === "auto" ? detectFormat() : format;
636
716
  const formatter = resolvedFormat === "json" ? formatJson : formatPretty;
637
- return buildLogger(scope, level, meta, formatter);
717
+ const emit = makeEmitter(destination);
718
+ return buildLogger(scope, level, meta, formatter, emit);
638
719
  }
639
720
  var noopLogger = {
640
721
  debug: () => {
@@ -1492,12 +1573,176 @@ function normaliseThrown(thrown) {
1492
1573
  return { name: "Error", message: String(thrown) };
1493
1574
  }
1494
1575
 
1576
+ // src/design-tokens.ts
1577
+ var MUSHI_COLORS_LIGHT = {
1578
+ paper: "#F8F4ED",
1579
+ paperRaised: "#FFFFFF",
1580
+ ink: "#0E0D0B",
1581
+ inkMuted: "#5C5852",
1582
+ inkFaint: "#9A9489",
1583
+ inkDim: "#6E6760",
1584
+ rule: "rgba(14,13,11,0.10)",
1585
+ ruleStrong: "rgba(14,13,11,0.16)",
1586
+ accent: "#E03C2C",
1587
+ accentWash: "rgba(224,60,44,0.08)",
1588
+ accentInk: "#7A1F15",
1589
+ ok: "#16A34A",
1590
+ danger: "#DC2626"
1591
+ };
1592
+ var MUSHI_COLORS_DARK = {
1593
+ paper: "#0F0E0C",
1594
+ paperRaised: "#1A1815",
1595
+ ink: "#F2EBDD",
1596
+ inkMuted: "#928B7E",
1597
+ inkFaint: "#5A5650",
1598
+ inkDim: "#7A7268",
1599
+ rule: "rgba(242,235,221,0.10)",
1600
+ ruleStrong: "rgba(242,235,221,0.18)",
1601
+ accent: "#FF5A47",
1602
+ accentWash: "rgba(255,90,71,0.12)",
1603
+ accentInk: "#FFE5E0",
1604
+ ok: "#4ADE80",
1605
+ danger: "#F87171"
1606
+ };
1607
+ function mushiPalette(mode) {
1608
+ return mode === "dark" ? MUSHI_COLORS_DARK : MUSHI_COLORS_LIGHT;
1609
+ }
1610
+ var MUSHI_SPACING = {
1611
+ hairline: 2,
1612
+ tight: 4,
1613
+ snug: 8,
1614
+ comfy: 12,
1615
+ roomy: 16,
1616
+ lounge: 20,
1617
+ open: 24,
1618
+ wide: 32
1619
+ };
1620
+ var MUSHI_RADIUS = {
1621
+ none: 0,
1622
+ control: 4,
1623
+ card: 10,
1624
+ sheet: 16,
1625
+ pill: 999
1626
+ };
1627
+ var MUSHI_TYPE = {
1628
+ fontDisplay: `'Iowan Old Style', 'Palatino Linotype', 'Palatino', 'Book Antiqua', 'Cambria', Georgia, 'Times New Roman', serif`,
1629
+ fontBody: `system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI Variable Display', 'Segoe UI', sans-serif`,
1630
+ fontMono: `ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, 'Liberation Mono', monospace`,
1631
+ sizeBody: 14,
1632
+ sizeLabel: 12,
1633
+ sizeTitle: 16,
1634
+ lineBody: 1.55
1635
+ };
1636
+ var MUSHI_Z = {
1637
+ base: 99999,
1638
+ /** banner sits one below the trigger so an open FAB overlaps it */
1639
+ banner: 99998,
1640
+ /** report/assistant panel sits one above the trigger */
1641
+ panel: 1e5,
1642
+ /** element-selector overlay — always on top */
1643
+ overlay: 2147483647
1644
+ };
1645
+ var MUSHI_MOTION = {
1646
+ easeStamp: "cubic-bezier(0.22, 1, 0.36, 1)",
1647
+ durationFast: 200,
1648
+ durationPanel: 300
1649
+ };
1650
+ var MUSHI_GEOMETRY = {
1651
+ bannerHeight: 36,
1652
+ fabSize: 52,
1653
+ edgeTabWidth: 28,
1654
+ /** default gutter from the screen edge (added on top of safe-area insets) */
1655
+ gutter: 24,
1656
+ panelWidth: 384,
1657
+ /** below this viewport width the panel becomes a full-width bottom sheet */
1658
+ panelSheetBreakpoint: 480
1659
+ };
1660
+ var MUSHI_COPY = {
1661
+ bannerLabel: "Beta",
1662
+ bannerMessage: "Help us improve \u2014 your feedback shapes what we ship.",
1663
+ bugCta: "Report a bug",
1664
+ featureCta: "Feature request",
1665
+ triggerText: "\u{1F41B}",
1666
+ panelTitle: "Send feedback",
1667
+ myReportsTab: "My reports",
1668
+ assistantTab: "Ask"
1669
+ };
1670
+ function mushiTokens(mode) {
1671
+ return {
1672
+ mode,
1673
+ colors: mushiPalette(mode),
1674
+ spacing: MUSHI_SPACING,
1675
+ radius: MUSHI_RADIUS,
1676
+ type: MUSHI_TYPE,
1677
+ z: MUSHI_Z,
1678
+ motion: MUSHI_MOTION,
1679
+ geometry: MUSHI_GEOMETRY,
1680
+ copy: MUSHI_COPY
1681
+ };
1682
+ }
1683
+
1684
+ // src/identity.ts
1685
+ var MUSHI_IDENTITY_TOKEN_PREFIX = "mushi.identity";
1686
+ function buildIdentityClaims(input) {
1687
+ const now = Math.floor(Date.now() / 1e3);
1688
+ const ttl = input.ttlSeconds && input.ttlSeconds > 0 ? Math.min(input.ttlSeconds, 3600) : 600;
1689
+ return {
1690
+ projectId: input.projectId,
1691
+ sub: input.userId,
1692
+ ...input.email ? { email: input.email } : {},
1693
+ ...input.name ? { name: input.name } : {},
1694
+ iat: now,
1695
+ exp: now + ttl
1696
+ };
1697
+ }
1698
+ function base64UrlDecode(segment) {
1699
+ const pad = segment.length % 4 === 0 ? "" : "=".repeat(4 - segment.length % 4);
1700
+ const base64 = segment.replace(/-/g, "+").replace(/_/g, "/") + pad;
1701
+ if (typeof atob === "function") return atob(base64);
1702
+ const B = globalThis.Buffer;
1703
+ if (B) return B.from(base64, "base64").toString("binary");
1704
+ return "";
1705
+ }
1706
+ function parseIdentityToken(token) {
1707
+ if (typeof token !== "string") return null;
1708
+ const parts = token.split(".");
1709
+ if (parts.length !== 3) return null;
1710
+ try {
1711
+ const json = base64UrlDecode(parts[1]);
1712
+ const payload = JSON.parse(json);
1713
+ const projectId = typeof payload.projectId === "string" ? payload.projectId : void 0;
1714
+ const sub = typeof payload.sub === "string" ? payload.sub : void 0;
1715
+ if (!projectId || !sub) return null;
1716
+ return {
1717
+ projectId,
1718
+ sub,
1719
+ ...typeof payload.email === "string" ? { email: payload.email } : {},
1720
+ ...typeof payload.name === "string" ? { name: payload.name } : {},
1721
+ ...typeof payload.iat === "number" ? { iat: payload.iat } : {},
1722
+ ...typeof payload.exp === "number" ? { exp: payload.exp } : {}
1723
+ };
1724
+ } catch {
1725
+ return null;
1726
+ }
1727
+ }
1728
+
1495
1729
  exports.DEFAULT_API_ENDPOINT = DEFAULT_API_ENDPOINT;
1496
1730
  exports.MAX_REPORT_PAYLOAD_BYTES = MAX_REPORT_PAYLOAD_BYTES;
1497
1731
  exports.MAX_SCREENSHOT_DATA_URL_BYTES = MAX_SCREENSHOT_DATA_URL_BYTES;
1732
+ exports.MUSHI_COLORS_DARK = MUSHI_COLORS_DARK;
1733
+ exports.MUSHI_COLORS_LIGHT = MUSHI_COLORS_LIGHT;
1734
+ exports.MUSHI_COPY = MUSHI_COPY;
1735
+ exports.MUSHI_GEOMETRY = MUSHI_GEOMETRY;
1736
+ exports.MUSHI_IDENTITY_TOKEN_PREFIX = MUSHI_IDENTITY_TOKEN_PREFIX;
1498
1737
  exports.MUSHI_INTERNAL_HEADER = MUSHI_INTERNAL_HEADER;
1499
1738
  exports.MUSHI_INTERNAL_INIT_MARKER = MUSHI_INTERNAL_INIT_MARKER;
1739
+ exports.MUSHI_MOTION = MUSHI_MOTION;
1740
+ exports.MUSHI_RADIUS = MUSHI_RADIUS;
1741
+ exports.MUSHI_SPACING = MUSHI_SPACING;
1742
+ exports.MUSHI_TYPE = MUSHI_TYPE;
1743
+ exports.MUSHI_Z = MUSHI_Z;
1500
1744
  exports.REGION_ENDPOINTS = REGION_ENDPOINTS;
1745
+ exports.buildIdentityClaims = buildIdentityClaims;
1501
1746
  exports.captureEnvironment = captureEnvironment;
1502
1747
  exports.checkReportPayloadSize = checkReportPayloadSize;
1503
1748
  exports.createApiClient = createApiClient;
@@ -1512,9 +1757,13 @@ exports.formatBytes = formatBytes;
1512
1757
  exports.getDeviceFingerprintHash = getDeviceFingerprintHash;
1513
1758
  exports.getReporterToken = getReporterToken;
1514
1759
  exports.getSessionId = getSessionId;
1760
+ exports.mushiPalette = mushiPalette;
1761
+ exports.mushiTokens = mushiTokens;
1515
1762
  exports.newUuid = newUuid;
1516
1763
  exports.noopLogger = noopLogger;
1517
1764
  exports.normaliseThrown = normaliseThrown;
1765
+ exports.parseIdentityToken = parseIdentityToken;
1766
+ exports.resolveEnvConfig = resolveEnvConfig;
1518
1767
  exports.resolveRegionEndpoint = resolveRegionEndpoint;
1519
1768
  exports.scrubPii = scrubPii;
1520
1769
  //# sourceMappingURL=index.cjs.map