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.
- package/LICENSE +21 -0
- package/README.md +140 -0
- package/bin/mouaif.js +281 -0
- package/frontend/dist/assets/AgentFilePicker-CcKLJorU.js +1 -0
- package/frontend/dist/assets/CliModal-Hs5phmNZ.js +7 -0
- package/frontend/dist/assets/DictationPage-BI23lp42.js +2 -0
- package/frontend/dist/assets/FileEditor-DDl31c6d.js +2 -0
- package/frontend/dist/assets/GitModal-3EC_gpJ5.js +2 -0
- package/frontend/dist/assets/Inspector-Ba3R1w04.js +73 -0
- package/frontend/dist/assets/SettingsAbout-bvZGDEDw.js +1 -0
- package/frontend/dist/assets/SettingsActions-Dk6WX9jv.js +1 -0
- package/frontend/dist/assets/SettingsAgents-BNV0MgDB.js +1 -0
- package/frontend/dist/assets/SettingsDefaults-DbMmQbzc.js +1 -0
- package/frontend/dist/assets/SettingsHiddenContent-BZ2sloH1.js +1 -0
- package/frontend/dist/assets/SettingsMcp-DOrfbQd1.js +1 -0
- package/frontend/dist/assets/SettingsMcpEdit-BGMQ2CWC.js +3 -0
- package/frontend/dist/assets/SettingsMcpRegistry-BywXee_A.js +1 -0
- package/frontend/dist/assets/SettingsNotifications-B0LEs11a.js +1 -0
- package/frontend/dist/assets/SettingsPricing-BAg33iVF.js +1 -0
- package/frontend/dist/assets/SettingsProject-DNrKhCcZ.js +14 -0
- package/frontend/dist/assets/SettingsProjects-IqkBfDcm.js +1 -0
- package/frontend/dist/assets/SettingsPrompts-BgeiASuk.js +1 -0
- package/frontend/dist/assets/SettingsProviders-k0xJN0IK.js +1 -0
- package/frontend/dist/assets/SettingsTags-B5kjFdQi.js +1 -0
- package/frontend/dist/assets/agentNavigation-BiiCpFz5.js +1 -0
- package/frontend/dist/assets/codemirror-Bp6CUUFk.js +30 -0
- package/frontend/dist/assets/index-BGvI4n0T.js +61 -0
- package/frontend/dist/assets/index-Bgg1gnDf.css +1 -0
- package/frontend/dist/assets/index-C1sQFIC-.css +1 -0
- package/frontend/dist/assets/index-CANPYzQg.css +1 -0
- package/frontend/dist/assets/index-Crn1LdzK.css +1 -0
- package/frontend/dist/assets/index-FbCWDPiB.css +1 -0
- package/frontend/dist/assets/projectQS-D1cSZ7Gr.js +1 -0
- package/frontend/dist/assets/virtual-list-6H9b4K51.js +1 -0
- package/frontend/dist/icons/favicon-32.png +0 -0
- package/frontend/dist/icons/icon-180-apple.png +0 -0
- package/frontend/dist/icons/icon-192.png +0 -0
- package/frontend/dist/icons/icon-512.png +0 -0
- package/frontend/dist/icons/icon-maskable-512.png +0 -0
- package/frontend/dist/index.html +83 -0
- package/frontend/dist/manifest.webmanifest +33 -0
- package/frontend/dist/sw.js +482 -0
- package/package.json +98 -0
- package/scripts/patch-zimmerframe.js +58 -0
- package/src/access-auth.js +515 -0
- package/src/agentFeatures.js +294 -0
- package/src/agentFiles.js +164 -0
- package/src/agentSkills.js +147 -0
- package/src/agents.js +230 -0
- package/src/ai-chat.js +21 -0
- package/src/ai-endpoints.js +1880 -0
- package/src/ai-stream.js +2048 -0
- package/src/ai.js +68 -0
- package/src/auth.js +391 -0
- package/src/chatdb.js +816 -0
- package/src/chats.js +275 -0
- package/src/custom-actions.js +65 -0
- package/src/files.js +431 -0
- package/src/hideFileContent.js +327 -0
- package/src/http-server.js +535 -0
- package/src/index.js +15 -0
- package/src/inspector.js +731 -0
- package/src/inspectorProfiles.js +503 -0
- package/src/live-chat.js +107 -0
- package/src/mcp.js +1517 -0
- package/src/messages.js +238 -0
- package/src/modelList.js +137 -0
- package/src/notifications.js +52 -0
- package/src/oauth-anthropic.js +280 -0
- package/src/oauth-github-copilot.js +417 -0
- package/src/oauth-mcp.js +216 -0
- package/src/oauth-openrouter.js +285 -0
- package/src/package-version.js +20 -0
- package/src/projects.js +285 -0
- package/src/promptProfiles.js +256 -0
- package/src/prompts.js +384 -0
- package/src/providerShapes.js +44 -0
- package/src/providers/base.js +41 -0
- package/src/providers/index.js +25 -0
- package/src/push.js +315 -0
- package/src/qr.js +192 -0
- package/src/restart.js +47 -0
- package/src/server-handlers-access.js +306 -0
- package/src/server-handlers-actions.js +100 -0
- package/src/server-handlers-ai.js +248 -0
- package/src/server-handlers-auth.js +273 -0
- package/src/server-handlers-chats.js +1436 -0
- package/src/server-handlers-git.js +467 -0
- package/src/server-handlers-mcp-oauth.js +56 -0
- package/src/server-handlers-misc.js +783 -0
- package/src/server-handlers-projects.js +289 -0
- package/src/server-handlers-prompts.js +259 -0
- package/src/server-handlers-push.js +102 -0
- package/src/server-handlers-settings.js +406 -0
- package/src/server-handlers-tools.js +654 -0
- package/src/server-handlers-transcribe.js +399 -0
- package/src/server-shared.js +780 -0
- package/src/server-web-static.js +191 -0
- package/src/settings.js +898 -0
- package/src/statusBar.js +541 -0
- package/src/tags.js +414 -0
- package/src/toolFeedback.js +225 -0
- package/src/tools/ask.js +154 -0
- package/src/tools/authorization.js +932 -0
- package/src/tools/files.js +1150 -0
- package/src/tools/progress.js +71 -0
- package/src/tools/restart.js +32 -0
- package/src/tools/searchEngine.js +957 -0
- package/src/tools/shell.js +341 -0
- package/src/tools/subagent.js +47 -0
- package/src/tools/task.js +234 -0
- package/src/tools/webpreview.js +448 -0
- package/src/trace.js +103 -0
- package/src/transcribe.js +683 -0
- package/src/usage.js +389 -0
- 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 };
|