@mavea/mavea 1.0.7 → 1.0.8

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 CHANGED
@@ -3,8 +3,8 @@
3
3
  # Mavéa
4
4
 
5
5
  <picture>
6
- <source media="(prefers-color-scheme: dark)" srcset="docs/media/mascot-dark.svg" />
7
- <img src="docs/media/mascot-light.svg" width="150" alt="The Mavéa presence" />
6
+ <source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/npm/@mavea/mavea@latest/docs/media/mascot-dark.svg" />
7
+ <img src="https://cdn.jsdelivr.net/npm/@mavea/mavea@latest/docs/media/mascot-light.svg" width="150" alt="The Mavéa presence" />
8
8
  </picture>
9
9
 
10
10
  ### Talk to AI. See what it means.
@@ -20,7 +20,9 @@ and evidence you can check, marking the exact figure each line is about.
20
20
  [See it in motion →](docs/FEATURES.md)
21
21
 
22
22
  <p>
23
- <a href="https://github.com/TryMaveaAI/mavea/actions/workflows/ci.yml"><img src="https://github.com/TryMaveaAI/mavea/actions/workflows/ci.yml/badge.svg" alt="CI status" /></a>
23
+ <!-- No CI status badge: GitHub Actions badges for a PRIVATE repo require authentication, so
24
+ they 404 for anyone viewing this README anonymously (e.g. on npm's package page). Add one
25
+ back the day this repo goes public. -->
24
26
  <img src="https://img.shields.io/badge/React-19-61DAFB?style=flat-square&logo=react&logoColor=black" alt="React 19" />
25
27
  <img src="https://img.shields.io/badge/TypeScript-6-3178C6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript 6" />
26
28
  <img src="https://img.shields.io/badge/Vite-8-646CFF?style=flat-square&logo=vite&logoColor=white" alt="Vite 8" />
package/bin/mavea.mjs CHANGED
@@ -1,11 +1,19 @@
1
1
  #!/usr/bin/env node
2
- // mavea CLI — serves the prebuilt app locally, same-origin proxies included, so `npx mavea`
2
+ // mavea CLI — serves the prebuilt app locally, same-origin proxies included, so `npx @mavea/mavea`
3
3
  // works exactly the way `pnpm dev` does in the source repo (see vite.config.ts, which this
4
4
  // mirrors) without needing Node deps, a clone, or a build step.
5
5
  import { createServer } from 'node:http';
6
6
  import http from 'node:http';
7
7
  import https from 'node:https';
8
- import { createReadStream, existsSync, statSync, mkdirSync, renameSync, unlinkSync } from 'node:fs';
8
+ import {
9
+ createReadStream,
10
+ existsSync,
11
+ statSync,
12
+ mkdirSync,
13
+ renameSync,
14
+ unlinkSync,
15
+ realpathSync,
16
+ } from 'node:fs';
9
17
  import { writeFile } from 'node:fs/promises';
10
18
  import { fileURLToPath } from 'node:url';
11
19
  import { dirname, join, extname, normalize, resolve, sep } from 'node:path';
@@ -48,7 +56,7 @@ export const LOCAL_SECURITY_HEADERS = Object.freeze({
48
56
  });
49
57
 
50
58
  // The ONNX runtime WASM (13MB) and Silero VAD model (2.3MB) are real functional assets voice
51
- // mode needs, not waste — but bundling them into every `npx mavea` download costs everyone that
59
+ // mode needs, not waste — but bundling them into every `npx @mavea/mavea` download costs everyone that
52
60
  // weight even if they never touch voice (most turns are text). Both are ALSO already public,
53
61
  // permanently-versioned npm package assets, so instead of shipping them in dist/ (see the `files`
54
62
  // exclusion in package.json), they're fetched ONCE from jsDelivr's npm CDN the first time voice
@@ -68,7 +76,7 @@ const LAZY_ASSETS = {
68
76
  };
69
77
 
70
78
  // Standard per-OS cache location (the same convention env-paths/XDG use) — persists across
71
- // `npx mavea` invocations (npx's own package cache does NOT persist these, since they're fetched
79
+ // `npx @mavea/mavea` invocations (npx's own package cache does NOT persist these, since they're fetched
72
80
  // at runtime, not installed), so a user only pays the download once, ever, per machine.
73
81
  function lazyCacheDir() {
74
82
  const plat = platform();
@@ -899,12 +907,12 @@ async function offerDockerInstall() {
899
907
 
900
908
  const later =
901
909
  ' To enable voice later: install Docker (https://docker.com/get-started),\n' +
902
- ' then re-run `npx mavea` — it will detect Docker and set voice up for you.';
910
+ ' then re-run `npx @mavea/mavea` — it will detect Docker and set voice up for you.';
903
911
 
904
912
  if (process.platform === 'darwin' && commandExists('brew')) {
905
913
  const yes = await askYesNo(
906
914
  ' Install Docker now via Homebrew? [Y/n] (~600 MB, then launch Docker\n' +
907
- ' Desktop once and re-run `npx mavea` — voice will offer to start itself) ',
915
+ ' Desktop once and re-run `npx @mavea/mavea` — voice will offer to start itself) ',
908
916
  );
909
917
  if (!yes) return console.log(' Skipping.\n' + later);
910
918
  const r = spawn('brew', ['install', '--cask', 'docker'], { stdio: 'inherit' });
@@ -912,7 +920,7 @@ async function offerDockerInstall() {
912
920
  console.log(
913
921
  code === 0
914
922
  ? ' ✓ Docker installed. Launch Docker Desktop once (to accept its service\n' +
915
- ' agreement), then re-run `npx mavea` to enable voice.'
923
+ ' agreement), then re-run `npx @mavea/mavea` to enable voice.'
916
924
  : ' Homebrew install failed.\n' + later,
917
925
  );
918
926
  });
@@ -922,7 +930,7 @@ async function offerDockerInstall() {
922
930
  if (process.platform === 'win32' && commandExists('winget')) {
923
931
  const yes = await askYesNo(
924
932
  ' Install Docker Desktop now via winget? [Y/n] (then launch it once and\n' +
925
- ' re-run `npx mavea` — voice will offer to start itself) ',
933
+ ' re-run `npx @mavea/mavea` — voice will offer to start itself) ',
926
934
  );
927
935
  if (!yes) return console.log(' Skipping.\n' + later);
928
936
  const r = spawn('winget', ['install', '-e', '--id', 'Docker.DockerDesktop'], {
@@ -931,7 +939,7 @@ async function offerDockerInstall() {
931
939
  r.on('exit', (code) => {
932
940
  console.log(
933
941
  code === 0
934
- ? ' ✓ Docker installed. Launch Docker Desktop once, then re-run `npx mavea`.'
942
+ ? ' ✓ Docker installed. Launch Docker Desktop once, then re-run `npx @mavea/mavea`.'
935
943
  : ' winget install failed.\n' + later,
936
944
  );
937
945
  });
@@ -942,7 +950,9 @@ async function offerDockerInstall() {
942
950
  // Docker's install script needs sudo — print it, never run it on the user's behalf.
943
951
  console.log(' To install Docker, run:\n');
944
952
  console.log(' curl -fsSL https://get.docker.com | sh\n');
945
- console.log(' then re-run `npx mavea` — it will detect Docker and set voice up for you.');
953
+ console.log(
954
+ ' then re-run `npx @mavea/mavea` — it will detect Docker and set voice up for you.',
955
+ );
946
956
  return;
947
957
  }
948
958
 
@@ -957,7 +967,9 @@ async function offerDockerStart() {
957
967
  if (process.platform === 'darwin' || process.platform === 'win32') {
958
968
  const yes = await askYesNo(' Start Docker Desktop now? [Y/n] ');
959
969
  if (!yes) {
960
- console.log(' Skipping — captions only. Start Docker Desktop and re-run `npx mavea`.');
970
+ console.log(
971
+ ' Skipping — captions only. Start Docker Desktop and re-run `npx @mavea/mavea`.',
972
+ );
961
973
  return;
962
974
  }
963
975
  if (process.platform === 'darwin') {
@@ -972,14 +984,14 @@ async function offerDockerStart() {
972
984
  const up = await waitForDocker();
973
985
  if (!up) {
974
986
  console.log('\n Docker did not come up in time — captions only for now.');
975
- console.log(' Once Docker Desktop is running, re-run `npx mavea` to enable voice.');
987
+ console.log(' Once Docker Desktop is running, re-run `npx @mavea/mavea` to enable voice.');
976
988
  return;
977
989
  }
978
990
  console.log('✓');
979
991
  startKokoro();
980
992
  return;
981
993
  }
982
- console.log(' Start it (e.g. `sudo systemctl start docker`), then re-run `npx mavea`.');
994
+ console.log(' Start it (e.g. `sudo systemctl start docker`), then re-run `npx @mavea/mavea`.');
983
995
  }
984
996
 
985
997
  async function maybeOfferVoice() {
@@ -988,7 +1000,7 @@ async function maybeOfferVoice() {
988
1000
  if (!existsSync(COMPOSE_FILE) || !process.stdin.isTTY) {
989
1001
  console.log(
990
1002
  "Voice (Kokoro TTS) isn't running — lines will show as captions only. " +
991
- 'Re-run `npx mavea` in a terminal to set it up, or start Kokoro yourself on :8880.',
1003
+ 'Re-run `npx @mavea/mavea` in a terminal to set it up, or start Kokoro yourself on :8880.',
992
1004
  );
993
1005
  return;
994
1006
  }
@@ -997,7 +1009,7 @@ async function maybeOfferVoice() {
997
1009
  console.log(VOICE_INTRO);
998
1010
  const yes = await askYesNo(' Start it now? [Y/n] ');
999
1011
  if (!yes) {
1000
- console.log(' Skipping — captions only. Re-run `npx mavea` any time to enable voice.');
1012
+ console.log(' Skipping — captions only. Re-run `npx @mavea/mavea` any time to enable voice.');
1001
1013
  return;
1002
1014
  }
1003
1015
  startKokoro();
@@ -1016,7 +1028,7 @@ async function main() {
1016
1028
  if (args.help) {
1017
1029
  console.log(`mavea — run the Mavéa app locally
1018
1030
 
1019
- Usage: npx mavea [options]
1031
+ Usage: npx @mavea/mavea [options]
1020
1032
 
1021
1033
  Options:
1022
1034
  --port, -p <n> Port to serve on (default 4173, or $PORT)
@@ -1070,7 +1082,20 @@ Terms, privacy, disclaimer, and third-party notices ship with this package.
1070
1082
  if (args.voice) await maybeOfferVoice();
1071
1083
  }
1072
1084
 
1073
- const isMain = process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url);
1085
+ // npm/npx installs `bin` entries as a symlink (node_modules/.bin/mavea -> ../@mavea/mavea/bin/
1086
+ // mavea.mjs). Node's ESM loader resolves that symlink when setting import.meta.url to this
1087
+ // module's REAL path, but path.resolve(process.argv[1]) does not dereference symlinks — it stays
1088
+ // the symlink's own path, so the two never matched and `npx @mavea/mavea` silently ran main() 0 times.
1089
+ // realpathSync resolves both sides to the same real filesystem path before comparing.
1090
+ function isMainModule() {
1091
+ if (!process.argv[1]) return false;
1092
+ try {
1093
+ return realpathSync(resolve(process.argv[1])) === fileURLToPath(import.meta.url);
1094
+ } catch {
1095
+ return false;
1096
+ }
1097
+ }
1098
+ const isMain = isMainModule();
1074
1099
  if (isMain) {
1075
1100
  void main().catch((error) => {
1076
1101
  console.error(`mavea: ${error instanceof Error ? error.message : String(error)}`);
@@ -0,0 +1,53 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 220" role="img" aria-label="The Mavéa presence">
2
+ <defs>
3
+ <linearGradient id="bell" x1="40" y1="60" x2="160" y2="104" gradientUnits="userSpaceOnUse">
4
+ <stop offset="0" stop-color="#63e0bd" />
5
+ <stop offset="0.5" stop-color="#a4b4ff" />
6
+ <stop offset="1" stop-color="#ffa5c3" />
7
+ </linearGradient>
8
+ <radialGradient id="halo" cx="0.5" cy="0.42" r="0.5">
9
+ <stop offset="0" stop-color="#9eb0ff" stop-opacity="0.34" />
10
+ <stop offset="0.66" stop-color="#9eb0ff" stop-opacity="0" />
11
+ </radialGradient>
12
+ </defs>
13
+ <ellipse cx="100" cy="88" rx="98" ry="96" fill="url(#halo)" />
14
+ <g stroke="#63e0bd" fill="none" stroke-linecap="round">
15
+ <path d="M62 118 C56 142 66 158 56 186" stroke-width="10" opacity="0.2" />
16
+ <path d="M62 118 C56 142 66 158 56 186" stroke-width="3.5" opacity="0.65" />
17
+ </g>
18
+ <g stroke="#a4b4ff" fill="none" stroke-linecap="round">
19
+ <path d="M84 121 C84 146 74 162 84 194" stroke-width="10" opacity="0.2" />
20
+ <path d="M84 121 C84 146 74 162 84 194" stroke-width="3.5" opacity="0.65" />
21
+ </g>
22
+ <g stroke="#c3a5ff" fill="none" stroke-linecap="round">
23
+ <path d="M108 121 C110 144 100 162 110 192" stroke-width="10" opacity="0.2" />
24
+ <path d="M108 121 C110 144 100 162 110 192" stroke-width="3.5" opacity="0.65" />
25
+ </g>
26
+ <g stroke="#ffa5c3" fill="none" stroke-linecap="round">
27
+ <path d="M130 118 C138 140 128 156 138 184" stroke-width="10" opacity="0.2" />
28
+ <path d="M130 118 C138 140 128 156 138 184" stroke-width="3.5" opacity="0.65" />
29
+ </g>
30
+ <g>
31
+ <path d="M38 96 C38 52 62 26 100 26 C138 26 162 52 162 96 C162 110 146 116 100 116 C54 116 38 110 38 96 Z" fill="url(#bell)" opacity="0.9" />
32
+ <path d="M48 88 C48 58 66 38 92 36" fill="none" stroke="#eafff6" stroke-width="4" stroke-linecap="round" opacity="0.5" />
33
+ <path d="M52 74 C70 62 130 62 148 74" fill="none" stroke="#ffffff" stroke-width="5" stroke-linecap="round" opacity="0.1" />
34
+ <path d="M58 56 C76 46 124 46 142 56" fill="none" stroke="#ffffff" stroke-width="4" stroke-linecap="round" opacity="0.08" />
35
+ <g>
36
+ <ellipse cx="66" cy="86" rx="8" ry="5" fill="#ff9fb6" opacity="0.35" />
37
+ <ellipse cx="134" cy="86" rx="8" ry="5" fill="#ff9fb6" opacity="0.35" />
38
+ <g>
39
+ <circle cx="80" cy="72" r="9" fill="#ffffff" />
40
+ <circle cx="80" cy="72.7" r="5.2" fill="#252c55" />
41
+ <circle cx="82.5" cy="69.3" r="2.3" fill="#ffffff" />
42
+ <circle cx="78" cy="75.1" r="1.2" fill="#ffffff" opacity="0.85" />
43
+ </g>
44
+ <g>
45
+ <circle cx="120" cy="72" r="9" fill="#ffffff" />
46
+ <circle cx="120" cy="72.7" r="5.2" fill="#252c55" />
47
+ <circle cx="122.5" cy="69.3" r="2.3" fill="#ffffff" />
48
+ <circle cx="118" cy="75.1" r="1.2" fill="#ffffff" opacity="0.85" />
49
+ </g>
50
+ <path d="M92 91 Q100 97 108 91" fill="none" stroke="#ffffff" stroke-width="3.6" stroke-linecap="round" />
51
+ </g>
52
+ </g>
53
+ </svg>
@@ -0,0 +1,53 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 220" role="img" aria-label="The Mavéa presence">
2
+ <defs>
3
+ <linearGradient id="bell" x1="40" y1="60" x2="160" y2="104" gradientUnits="userSpaceOnUse">
4
+ <stop offset="0" stop-color="#57baa6" />
5
+ <stop offset="0.5" stop-color="#8998d9" />
6
+ <stop offset="1" stop-color="#d08dab" />
7
+ </linearGradient>
8
+ <radialGradient id="halo" cx="0.5" cy="0.42" r="0.5">
9
+ <stop offset="0" stop-color="#8495d9" stop-opacity="0.34" />
10
+ <stop offset="0.66" stop-color="#8495d9" stop-opacity="0" />
11
+ </radialGradient>
12
+ </defs>
13
+ <ellipse cx="100" cy="88" rx="98" ry="96" fill="url(#halo)" />
14
+ <g stroke="#57baa6" fill="none" stroke-linecap="round">
15
+ <path d="M62 118 C56 142 66 158 56 186" stroke-width="10" opacity="0.2" />
16
+ <path d="M62 118 C56 142 66 158 56 186" stroke-width="3.5" opacity="0.65" />
17
+ </g>
18
+ <g stroke="#8998d9" fill="none" stroke-linecap="round">
19
+ <path d="M84 121 C84 146 74 162 84 194" stroke-width="10" opacity="0.2" />
20
+ <path d="M84 121 C84 146 74 162 84 194" stroke-width="3.5" opacity="0.65" />
21
+ </g>
22
+ <g stroke="#a18cd9" fill="none" stroke-linecap="round">
23
+ <path d="M108 121 C110 144 100 162 110 192" stroke-width="10" opacity="0.2" />
24
+ <path d="M108 121 C110 144 100 162 110 192" stroke-width="3.5" opacity="0.65" />
25
+ </g>
26
+ <g stroke="#d08dab" fill="none" stroke-linecap="round">
27
+ <path d="M130 118 C138 140 128 156 138 184" stroke-width="10" opacity="0.2" />
28
+ <path d="M130 118 C138 140 128 156 138 184" stroke-width="3.5" opacity="0.65" />
29
+ </g>
30
+ <g>
31
+ <path d="M38 96 C38 52 62 26 100 26 C138 26 162 52 162 96 C162 110 146 116 100 116 C54 116 38 110 38 96 Z" fill="url(#bell)" opacity="0.9" />
32
+ <path d="M48 88 C48 58 66 38 92 36" fill="none" stroke="#eafff6" stroke-width="4" stroke-linecap="round" opacity="0.5" />
33
+ <path d="M52 74 C70 62 130 62 148 74" fill="none" stroke="#ffffff" stroke-width="5" stroke-linecap="round" opacity="0.1" />
34
+ <path d="M58 56 C76 46 124 46 142 56" fill="none" stroke="#ffffff" stroke-width="4" stroke-linecap="round" opacity="0.08" />
35
+ <g>
36
+ <ellipse cx="66" cy="86" rx="8" ry="5" fill="#ff9fb6" opacity="0.35" />
37
+ <ellipse cx="134" cy="86" rx="8" ry="5" fill="#ff9fb6" opacity="0.35" />
38
+ <g>
39
+ <circle cx="80" cy="72" r="9" fill="#ffffff" />
40
+ <circle cx="80" cy="72.7" r="5.2" fill="#252c55" />
41
+ <circle cx="82.5" cy="69.3" r="2.3" fill="#ffffff" />
42
+ <circle cx="78" cy="75.1" r="1.2" fill="#ffffff" opacity="0.85" />
43
+ </g>
44
+ <g>
45
+ <circle cx="120" cy="72" r="9" fill="#ffffff" />
46
+ <circle cx="120" cy="72.7" r="5.2" fill="#252c55" />
47
+ <circle cx="122.5" cy="69.3" r="2.3" fill="#ffffff" />
48
+ <circle cx="118" cy="75.1" r="1.2" fill="#ffffff" opacity="0.85" />
49
+ </g>
50
+ <path d="M92 91 Q100 97 108 91" fill="none" stroke="#ffffff" stroke-width="3.6" stroke-linecap="round" />
51
+ </g>
52
+ </g>
53
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mavea/mavea",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "type": "module",
5
5
  "description": "Mavéa — an AI Presence interface. Talk to AI. See what it means.",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",
@@ -13,6 +13,7 @@
13
13
  "!dist/ort-wasm-simd-threaded.wasm",
14
14
  "!dist/silero_vad_v5.onnx",
15
15
  "bin",
16
+ "docs/media",
16
17
  "docker-compose.yml",
17
18
  "gateway",
18
19
  "!gateway/.gateway-data/**",