@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 +5 -3
- package/bin/mavea.mjs +42 -17
- package/docs/media/mascot-dark.svg +53 -0
- package/docs/media/mascot-light.svg +53 -0
- package/package.json +2 -1
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
|
-
|
|
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 {
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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.
|
|
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/**",
|