mouaif 0.3.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.
Files changed (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +140 -0
  3. package/bin/mouaif.js +281 -0
  4. package/frontend/dist/assets/AgentFilePicker-CcKLJorU.js +1 -0
  5. package/frontend/dist/assets/CliModal-Hs5phmNZ.js +7 -0
  6. package/frontend/dist/assets/DictationPage-BI23lp42.js +2 -0
  7. package/frontend/dist/assets/FileEditor-DDl31c6d.js +2 -0
  8. package/frontend/dist/assets/GitModal-3EC_gpJ5.js +2 -0
  9. package/frontend/dist/assets/Inspector-Ba3R1w04.js +73 -0
  10. package/frontend/dist/assets/SettingsAbout-bvZGDEDw.js +1 -0
  11. package/frontend/dist/assets/SettingsActions-Dk6WX9jv.js +1 -0
  12. package/frontend/dist/assets/SettingsAgents-BNV0MgDB.js +1 -0
  13. package/frontend/dist/assets/SettingsDefaults-DbMmQbzc.js +1 -0
  14. package/frontend/dist/assets/SettingsHiddenContent-BZ2sloH1.js +1 -0
  15. package/frontend/dist/assets/SettingsMcp-DOrfbQd1.js +1 -0
  16. package/frontend/dist/assets/SettingsMcpEdit-BGMQ2CWC.js +3 -0
  17. package/frontend/dist/assets/SettingsMcpRegistry-BywXee_A.js +1 -0
  18. package/frontend/dist/assets/SettingsNotifications-B0LEs11a.js +1 -0
  19. package/frontend/dist/assets/SettingsPricing-BAg33iVF.js +1 -0
  20. package/frontend/dist/assets/SettingsProject-DNrKhCcZ.js +14 -0
  21. package/frontend/dist/assets/SettingsProjects-IqkBfDcm.js +1 -0
  22. package/frontend/dist/assets/SettingsPrompts-BgeiASuk.js +1 -0
  23. package/frontend/dist/assets/SettingsProviders-k0xJN0IK.js +1 -0
  24. package/frontend/dist/assets/SettingsTags-B5kjFdQi.js +1 -0
  25. package/frontend/dist/assets/agentNavigation-BiiCpFz5.js +1 -0
  26. package/frontend/dist/assets/codemirror-Bp6CUUFk.js +30 -0
  27. package/frontend/dist/assets/index-BGvI4n0T.js +61 -0
  28. package/frontend/dist/assets/index-Bgg1gnDf.css +1 -0
  29. package/frontend/dist/assets/index-C1sQFIC-.css +1 -0
  30. package/frontend/dist/assets/index-CANPYzQg.css +1 -0
  31. package/frontend/dist/assets/index-Crn1LdzK.css +1 -0
  32. package/frontend/dist/assets/index-FbCWDPiB.css +1 -0
  33. package/frontend/dist/assets/projectQS-D1cSZ7Gr.js +1 -0
  34. package/frontend/dist/assets/virtual-list-6H9b4K51.js +1 -0
  35. package/frontend/dist/icons/favicon-32.png +0 -0
  36. package/frontend/dist/icons/icon-180-apple.png +0 -0
  37. package/frontend/dist/icons/icon-192.png +0 -0
  38. package/frontend/dist/icons/icon-512.png +0 -0
  39. package/frontend/dist/icons/icon-maskable-512.png +0 -0
  40. package/frontend/dist/index.html +83 -0
  41. package/frontend/dist/manifest.webmanifest +33 -0
  42. package/frontend/dist/sw.js +482 -0
  43. package/package.json +98 -0
  44. package/scripts/patch-zimmerframe.js +58 -0
  45. package/src/access-auth.js +515 -0
  46. package/src/agentFeatures.js +294 -0
  47. package/src/agentFiles.js +164 -0
  48. package/src/agentSkills.js +147 -0
  49. package/src/agents.js +230 -0
  50. package/src/ai-chat.js +21 -0
  51. package/src/ai-endpoints.js +1880 -0
  52. package/src/ai-stream.js +2048 -0
  53. package/src/ai.js +68 -0
  54. package/src/auth.js +391 -0
  55. package/src/chatdb.js +816 -0
  56. package/src/chats.js +275 -0
  57. package/src/custom-actions.js +65 -0
  58. package/src/files.js +431 -0
  59. package/src/hideFileContent.js +327 -0
  60. package/src/http-server.js +535 -0
  61. package/src/index.js +15 -0
  62. package/src/inspector.js +731 -0
  63. package/src/inspectorProfiles.js +503 -0
  64. package/src/live-chat.js +107 -0
  65. package/src/mcp.js +1517 -0
  66. package/src/messages.js +238 -0
  67. package/src/modelList.js +137 -0
  68. package/src/notifications.js +52 -0
  69. package/src/oauth-anthropic.js +280 -0
  70. package/src/oauth-github-copilot.js +417 -0
  71. package/src/oauth-mcp.js +216 -0
  72. package/src/oauth-openrouter.js +285 -0
  73. package/src/package-version.js +20 -0
  74. package/src/projects.js +285 -0
  75. package/src/promptProfiles.js +256 -0
  76. package/src/prompts.js +384 -0
  77. package/src/providerShapes.js +44 -0
  78. package/src/providers/base.js +41 -0
  79. package/src/providers/index.js +25 -0
  80. package/src/push.js +315 -0
  81. package/src/qr.js +192 -0
  82. package/src/restart.js +47 -0
  83. package/src/server-handlers-access.js +306 -0
  84. package/src/server-handlers-actions.js +100 -0
  85. package/src/server-handlers-ai.js +248 -0
  86. package/src/server-handlers-auth.js +273 -0
  87. package/src/server-handlers-chats.js +1436 -0
  88. package/src/server-handlers-git.js +467 -0
  89. package/src/server-handlers-mcp-oauth.js +56 -0
  90. package/src/server-handlers-misc.js +783 -0
  91. package/src/server-handlers-projects.js +289 -0
  92. package/src/server-handlers-prompts.js +259 -0
  93. package/src/server-handlers-push.js +102 -0
  94. package/src/server-handlers-settings.js +406 -0
  95. package/src/server-handlers-tools.js +654 -0
  96. package/src/server-handlers-transcribe.js +399 -0
  97. package/src/server-shared.js +780 -0
  98. package/src/server-web-static.js +191 -0
  99. package/src/settings.js +898 -0
  100. package/src/statusBar.js +541 -0
  101. package/src/tags.js +414 -0
  102. package/src/toolFeedback.js +225 -0
  103. package/src/tools/ask.js +154 -0
  104. package/src/tools/authorization.js +932 -0
  105. package/src/tools/files.js +1150 -0
  106. package/src/tools/progress.js +71 -0
  107. package/src/tools/restart.js +32 -0
  108. package/src/tools/searchEngine.js +957 -0
  109. package/src/tools/shell.js +341 -0
  110. package/src/tools/subagent.js +47 -0
  111. package/src/tools/task.js +234 -0
  112. package/src/tools/webpreview.js +448 -0
  113. package/src/trace.js +103 -0
  114. package/src/transcribe.js +683 -0
  115. package/src/usage.js +389 -0
  116. package/src/util.js +151 -0
@@ -0,0 +1,191 @@
1
+ 'use strict';
2
+
3
+ // Static frontend serving. The mobile UI lives in frontend/ (built by
4
+ // Vite into frontend/dist/) and is served at the root /. Shared
5
+ // helpers + constants live in src/server-shared.js.
6
+
7
+ const path = require('path');
8
+ const fs = require('fs');
9
+ const { sendJSON, WEB_DIR, WEB_DIST } = require('./server-shared.js');
10
+
11
+ const WEB_MIME = {
12
+ '.html': 'text/html; charset=utf-8',
13
+ '.css': 'text/css; charset=utf-8',
14
+ '.js': 'application/javascript; charset=utf-8',
15
+ '.mjs': 'application/javascript; charset=utf-8',
16
+ '.json': 'application/json; charset=utf-8',
17
+ '.webmanifest': 'application/manifest+json; charset=utf-8',
18
+ '.svg': 'image/svg+xml',
19
+ '.png': 'image/png',
20
+ '.webp': 'image/webp',
21
+ '.ico': 'image/x-icon'
22
+ };
23
+
24
+ // Cache-Control for the PWA's static, fingerprinted assets (the
25
+ // hashed JS/CSS rollup emits). These URLs change on every build, so
26
+ // they can be cached forever by the browser; the cache name busts on
27
+ // each release because the hashed filename changes.
28
+ const LONG_LIVED = new Set(['.js', '.css', '.png', '.webp', '.svg', '.ico']);
29
+
30
+ // isInside(dir, abs) — true when `abs` is `dir` itself or lives under it.
31
+ // A plain `abs.startsWith(dir)` also matches a sibling whose name shares
32
+ // the prefix (`/app/frontend-evil` for `/app/frontend`), which is how a
33
+ // prefix test silently stops being a containment test.
34
+ function isInside(dir, abs) {
35
+ const root = path.resolve(dir);
36
+ const target = path.resolve(abs);
37
+ return target === root || target.startsWith(root + path.sep);
38
+ }
39
+
40
+ // Headers the service worker script needs to be installed for the
41
+ // root scope. SW scripts normally inherit their scope from their
42
+ // script URL's directory, but `Service-Worker-Allowed` lets the
43
+ // /sw.js script claim the entire / prefix (which is what
44
+ // we want so navigation + static requests are both handled).
45
+ // `Cache-Control: no-cache` keeps the browser from serving a stale
46
+ // SW after a redeploy; the activate handler then evicts the old
47
+ // cache on the next load.
48
+ function applyPwaHeaders(res, absPath, relPath) {
49
+ const ext = path.extname(absPath).toLowerCase();
50
+ const isSw = relPath === 'sw.js';
51
+ if (isSw) {
52
+ res.setHeader('Service-Worker-Allowed', '/');
53
+ res.setHeader('Cache-Control', 'no-cache');
54
+ return;
55
+ }
56
+ if (LONG_LIVED.has(ext)) {
57
+ // Cap to 1 year so we don't hand out "never expires" assets.
58
+ // The Vite build hashes every entry, so a stale copy will be
59
+ // garbage-collected next deploy anyway.
60
+ res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
61
+ return;
62
+ }
63
+ if (relPath === 'manifest.webmanifest') {
64
+ // Manifests are stable for a release (no content-hash in their
65
+ // URL), so cache briefly — long enough for the install prompt
66
+ // to be available offline, short enough to refresh across
67
+ // deploys.
68
+ res.setHeader('Cache-Control', 'public, max-age=300');
69
+ return;
70
+ }
71
+ }
72
+
73
+ // ---- Content-Security-Policy ------------------------------------------
74
+ //
75
+ // Served with every HTML document (the app shell at `/`, and any SPA
76
+ // fallback that resolves to index.html). The policy is a second line of
77
+ // defence behind the escaping each surface already does: it is what stops
78
+ // a markup-injection bug (like the SVG preview that used to feed a
79
+ // project file's bytes to innerHTML — see
80
+ // docs/features/files-modal-text-and-images.md) from becoming script
81
+ // execution in the app's origin, where the access cookie and the whole
82
+ // `/api/*` surface live.
83
+ //
84
+ // Directive by directive:
85
+ // default-src 'self' everything else falls back to same-origin
86
+ // script-src 'self' no inline script, no eval, no remote script.
87
+ // The bundle is a Vite ESM build at /assets/*;
88
+ // index.html has no inline <script>.
89
+ // style-src 'self' 'unsafe-inline'
90
+ // CodeMirror injects a <style> element at
91
+ // runtime (style-mod), and a few components set
92
+ // style attributes. Styles are not a script
93
+ // execution path, so this stays pragmatic.
94
+ // img-src 'self' data: blob: file previews and pasted images arrive as
95
+ // data: URLs from the API
96
+ // font-src 'self' data: system font stacks, but keep data: for a
97
+ // future webfont
98
+ // media-src 'self' data: blob:
99
+ // connect-src 'self' ws: wss: fetch + EventSource are same-origin; the
100
+ // Inspector's CDP socket is the same-origin
101
+ // `/api/inspector/proxy` WebSocket ('self'
102
+ // covers it in CSP3, listed explicitly for the
103
+ // browsers that do not implement that)
104
+ // worker-src 'self' blob: the service worker is /sw.js (same origin)
105
+ // manifest-src 'self' /manifest.webmanifest
106
+ // frame-src 'self' nothing frames anything today
107
+ // base-uri 'none' no <base> in the app shell, so a <base>
108
+ // injection cannot retarget every relative URL
109
+ // object-src 'none' no <embed>/<object>/<applet>
110
+ // form-action 'self' forms, if added, may only post to us
111
+ // frame-ancestors ... clickjacking guard that still allows a local
112
+ // shell (host app, test harness) to embed the
113
+ // UI over http://localhost / 127.0.0.1 on any
114
+ // port, while remote origins cannot frame it
115
+ const WEB_CSP = [
116
+ "default-src 'self'",
117
+ "script-src 'self'",
118
+ "style-src 'self' 'unsafe-inline'",
119
+ "img-src 'self' data: blob:",
120
+ "font-src 'self' data:",
121
+ "media-src 'self' data: blob:",
122
+ "connect-src 'self' ws: wss:",
123
+ "worker-src 'self' blob:",
124
+ "manifest-src 'self'",
125
+ "frame-src 'self'",
126
+ "base-uri 'none'",
127
+ "object-src 'none'",
128
+ "form-action 'self'",
129
+ "frame-ancestors 'self' http://localhost:* http://127.0.0.1:* https://localhost:* https://127.0.0.1:*"
130
+ ].join('; ');
131
+
132
+ // applyDocumentHeaders(res, absPath) — the headers that only make sense on
133
+ // a document (index.html). `nosniff` rides along: the static layer already
134
+ // sends an explicit Content-Type, and nosniff stops a browser from
135
+ // re-typing an asset that arrives with the wrong one.
136
+ function applyDocumentHeaders(res, absPath) {
137
+ if (path.extname(absPath).toLowerCase() !== '.html') return;
138
+ res.setHeader('Content-Security-Policy', WEB_CSP);
139
+ res.setHeader('X-Content-Type-Options', 'nosniff');
140
+ res.setHeader('Referrer-Policy', 'no-referrer');
141
+ }
142
+
143
+ function serveWebFile(res, absOrRel, opts) {
144
+ const opt = opts || {};
145
+ let abs;
146
+ if (path.isAbsolute(absOrRel)) {
147
+ abs = absOrRel;
148
+ } else if (opt.preferDist) {
149
+ // Look in frontend/dist/<relPath> first, fall back to frontend/<relPath>.
150
+ const inDist = path.join(WEB_DIST, absOrRel);
151
+ if (fs.existsSync(inDist)) abs = inDist;
152
+ else abs = path.join(WEB_DIR, absOrRel);
153
+ } else {
154
+ abs = path.join(WEB_DIR, absOrRel);
155
+ }
156
+ // Allow serving from outside WEB_DIR only when the caller explicitly
157
+ // opted in (used to be for the old virtual-list.js alias; no longer
158
+ // needed now that Vite bundles it).
159
+ //
160
+ // `startsWith` on its own is a prefix test, not a containment test: a
161
+ // sibling directory whose name begins with the same characters
162
+ // (`frontend-evil`) would pass it. Compare against the boundary with a
163
+ // trailing separator. `url.parse` does not decode the path, so an
164
+ // encoded `%2e%2e` arrives here literally and `path.join` keeps it
165
+ // inside; this check is the belt to that suspenders.
166
+ if (!isInside(WEB_DIR, abs) && !opt.allowOutside) {
167
+ return sendJSON(res, 400, { error: 'Bad path' });
168
+ }
169
+ fs.readFile(abs, (err, data) => {
170
+ if (err) return sendJSON(res, 404, { error: 'Not found', path: absOrRel });
171
+ applyPwaHeaders(res, abs, absOrRel);
172
+ applyDocumentHeaders(res, abs);
173
+ res.writeHead(200, { 'Content-Type': WEB_MIME[path.extname(abs)] || 'application/octet-stream' });
174
+ res.end(data);
175
+ });
176
+ }
177
+
178
+ function serveWebRequest(res, relPath) {
179
+ if (!relPath) return serveWebFile(res, 'index.html', { preferDist: true });
180
+ // SPA fallback: if the path is not a known asset type (no extension
181
+ // or an unknown extension), serve index.html so the client-side hash
182
+ // router can handle it. This prevents 404 JSON pages when navigation
183
+ // resolves to a garbage path like '/+ safe +'.
184
+ const ext = path.extname(relPath).toLowerCase();
185
+ if (!ext || !WEB_MIME[ext]) {
186
+ return serveWebFile(res, 'index.html', { preferDist: true });
187
+ }
188
+ return serveWebFile(res, relPath, { preferDist: true });
189
+ }
190
+
191
+ module.exports = { serveWebFile, serveWebRequest, isInside, WEB_CSP };