jishushell 0.4.30 → 0.5.15

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 (182) hide show
  1. package/apps/anythingllm-container.yaml +287 -0
  2. package/apps/browserless-chromium-container.yaml +18 -6
  3. package/apps/filebrowser-container.yaml +163 -0
  4. package/apps/openclaw-binary.yaml +8 -0
  5. package/apps/openclaw-container.yaml +9 -1
  6. package/apps/openclaw-with-searxng-container.yaml +4 -0
  7. package/apps/searxng-container.yaml +5 -4
  8. package/apps/weknora-container.yaml +471 -0
  9. package/dist/cli/panel.js.map +1 -1
  10. package/dist/config.d.ts +19 -0
  11. package/dist/config.js +99 -1
  12. package/dist/config.js.map +1 -1
  13. package/dist/install.js +3 -3
  14. package/dist/install.js.map +1 -1
  15. package/dist/routes/auth.js +2 -2
  16. package/dist/routes/auth.js.map +1 -1
  17. package/dist/routes/backup.js +64 -11
  18. package/dist/routes/backup.js.map +1 -1
  19. package/dist/routes/external-mounts.d.ts +17 -0
  20. package/dist/routes/external-mounts.js +73 -0
  21. package/dist/routes/external-mounts.js.map +1 -0
  22. package/dist/routes/file-mounts.d.ts +13 -0
  23. package/dist/routes/file-mounts.js +90 -0
  24. package/dist/routes/file-mounts.js.map +1 -0
  25. package/dist/routes/files-organize.d.ts +28 -0
  26. package/dist/routes/files-organize.js +167 -0
  27. package/dist/routes/files-organize.js.map +1 -0
  28. package/dist/routes/files.d.ts +31 -0
  29. package/dist/routes/files.js +321 -0
  30. package/dist/routes/files.js.map +1 -0
  31. package/dist/routes/instances.js +45 -7
  32. package/dist/routes/instances.js.map +1 -1
  33. package/dist/routes/internal.d.ts +2 -0
  34. package/dist/routes/internal.js +59 -0
  35. package/dist/routes/internal.js.map +1 -0
  36. package/dist/routes/setup.js +9 -9
  37. package/dist/routes/setup.js.map +1 -1
  38. package/dist/routes/system.js +1 -1
  39. package/dist/routes/system.js.map +1 -1
  40. package/dist/routes/webdav.d.ts +17 -0
  41. package/dist/routes/webdav.js +114 -0
  42. package/dist/routes/webdav.js.map +1 -0
  43. package/dist/server.js +341 -3
  44. package/dist/server.js.map +1 -1
  45. package/dist/services/app/app-compiler.d.ts +1 -1
  46. package/dist/services/app/app-compiler.js +5 -5
  47. package/dist/services/app/app-compiler.js.map +1 -1
  48. package/dist/services/app/app-manager.d.ts +1 -0
  49. package/dist/services/app/app-manager.js +172 -41
  50. package/dist/services/app/app-manager.js.map +1 -1
  51. package/dist/services/app/custom-manager.js.map +1 -1
  52. package/dist/services/app/hermes-agent-manager.js +1 -0
  53. package/dist/services/app/hermes-agent-manager.js.map +1 -1
  54. package/dist/services/app/ollama-manager.js +1 -1
  55. package/dist/services/app/ollama-manager.js.map +1 -1
  56. package/dist/services/app/openclaw-manager.js +20 -3
  57. package/dist/services/app/openclaw-manager.js.map +1 -1
  58. package/dist/services/app/platform-transform.d.ts +32 -0
  59. package/dist/services/app/platform-transform.js +65 -0
  60. package/dist/services/app/platform-transform.js.map +1 -0
  61. package/dist/services/app-passwords.d.ts +61 -0
  62. package/dist/services/app-passwords.js +173 -0
  63. package/dist/services/app-passwords.js.map +1 -0
  64. package/dist/services/backup-manager.d.ts +11 -0
  65. package/dist/services/backup-manager.js +177 -4
  66. package/dist/services/backup-manager.js.map +1 -1
  67. package/dist/services/connection-apply.d.ts +2 -0
  68. package/dist/services/connection-apply.js +55 -1
  69. package/dist/services/connection-apply.js.map +1 -1
  70. package/dist/services/connection-resolver.js +1 -1
  71. package/dist/services/connection-resolver.js.map +1 -1
  72. package/dist/services/connection-transactor.d.ts +2 -0
  73. package/dist/services/connection-transactor.js +12 -2
  74. package/dist/services/connection-transactor.js.map +1 -1
  75. package/dist/services/external-mounts.d.ts +40 -0
  76. package/dist/services/external-mounts.js +187 -0
  77. package/dist/services/external-mounts.js.map +1 -0
  78. package/dist/services/files-manager.d.ts +252 -0
  79. package/dist/services/files-manager.js +1075 -0
  80. package/dist/services/files-manager.js.map +1 -0
  81. package/dist/services/files-mounts.d.ts +42 -0
  82. package/dist/services/files-mounts.js +207 -0
  83. package/dist/services/files-mounts.js.map +1 -0
  84. package/dist/services/instance-manager.js +1 -23
  85. package/dist/services/instance-manager.js.map +1 -1
  86. package/dist/services/llm-proxy/index.js.map +1 -1
  87. package/dist/services/llm-proxy/ssrf.js +6 -2
  88. package/dist/services/llm-proxy/ssrf.js.map +1 -1
  89. package/dist/services/nomad-manager.d.ts +4 -0
  90. package/dist/services/nomad-manager.js +53 -19
  91. package/dist/services/nomad-manager.js.map +1 -1
  92. package/dist/services/organize/applier.d.ts +46 -0
  93. package/dist/services/organize/applier.js +218 -0
  94. package/dist/services/organize/applier.js.map +1 -0
  95. package/dist/services/organize/rules.d.ts +57 -0
  96. package/dist/services/organize/rules.js +286 -0
  97. package/dist/services/organize/rules.js.map +1 -0
  98. package/dist/services/organize/scanner.d.ts +50 -0
  99. package/dist/services/organize/scanner.js +366 -0
  100. package/dist/services/organize/scanner.js.map +1 -0
  101. package/dist/services/organize/store.d.ts +14 -0
  102. package/dist/services/organize/store.js +82 -0
  103. package/dist/services/organize/store.js.map +1 -0
  104. package/dist/services/panel-manager.js +20 -1
  105. package/dist/services/panel-manager.js.map +1 -1
  106. package/dist/services/process-manager.js +3 -2
  107. package/dist/services/process-manager.js.map +1 -1
  108. package/dist/services/runtime/adapters/hermes.js +1 -1
  109. package/dist/services/runtime/adapters/hermes.js.map +1 -1
  110. package/dist/services/runtime/adapters/openclaw-routes.d.ts +8 -2
  111. package/dist/services/runtime/adapters/openclaw-routes.js +68 -0
  112. package/dist/services/runtime/adapters/openclaw-routes.js.map +1 -1
  113. package/dist/services/runtime/adapters/openclaw.d.ts +90 -0
  114. package/dist/services/runtime/adapters/openclaw.js +957 -45
  115. package/dist/services/runtime/adapters/openclaw.js.map +1 -1
  116. package/dist/services/runtime/instance.d.ts +1 -1
  117. package/dist/services/runtime/instance.js +1 -1
  118. package/dist/services/runtime/instance.js.map +1 -1
  119. package/dist/services/runtime/mcp-shims/anythingllm-shim.d.ts +46 -0
  120. package/dist/services/runtime/mcp-shims/anythingllm-shim.js +281 -0
  121. package/dist/services/runtime/mcp-shims/anythingllm-shim.js.map +1 -0
  122. package/dist/services/runtime/mcp-shims/drive-shim.d.ts +54 -0
  123. package/dist/services/runtime/mcp-shims/drive-shim.js +489 -0
  124. package/dist/services/runtime/mcp-shims/drive-shim.js.map +1 -0
  125. package/dist/services/runtime/types.d.ts +31 -0
  126. package/dist/services/setup-manager.js +93 -18
  127. package/dist/services/setup-manager.js.map +1 -1
  128. package/dist/services/suggestions.js.map +1 -1
  129. package/dist/services/webdav/server.d.ts +24 -0
  130. package/dist/services/webdav/server.js +420 -0
  131. package/dist/services/webdav/server.js.map +1 -0
  132. package/dist/services/webdav/xml-builder.d.ts +73 -0
  133. package/dist/services/webdav/xml-builder.js +156 -0
  134. package/dist/services/webdav/xml-builder.js.map +1 -0
  135. package/dist/services/workspace-builder.d.ts +29 -0
  136. package/dist/services/workspace-builder.js +188 -0
  137. package/dist/services/workspace-builder.js.map +1 -0
  138. package/dist/types.d.ts +60 -0
  139. package/dist/utils/path-locks.d.ts +30 -0
  140. package/dist/utils/path-locks.js +63 -0
  141. package/dist/utils/path-locks.js.map +1 -0
  142. package/dist/utils/path-safety.d.ts +41 -0
  143. package/dist/utils/path-safety.js +119 -0
  144. package/dist/utils/path-safety.js.map +1 -0
  145. package/dist/utils/safe-write.d.ts +24 -0
  146. package/dist/utils/safe-write.js +82 -0
  147. package/dist/utils/safe-write.js.map +1 -0
  148. package/package.json +16 -1
  149. package/public/assets/Dashboard-BdWPtroF.js +1 -0
  150. package/public/assets/{HermesChatPanel-_GHoklgo.js → HermesChatPanel-B_2HlVBQ.js} +1 -1
  151. package/public/assets/{HermesConfigForm-anDnwUp_.js → HermesConfigForm-DVlhg3WV.js} +2 -2
  152. package/public/assets/{InitPassword-ZU9_-hDr.js → InitPassword-D7glTExX.js} +1 -1
  153. package/public/assets/InstanceDetail-CxSy2cpe.js +92 -0
  154. package/public/assets/{Login-BItXqYAJ.js → Login-Cfr5c2sv.js} +1 -1
  155. package/public/assets/NewInstance-BIYDmJis.js +1 -0
  156. package/public/assets/{ProviderRecommendations-DFYj7Fb6.js → ProviderRecommendations-BuRnvRcI.js} +1 -1
  157. package/public/assets/{Settings-Bttc6QmM.js → Settings-Cc-tYBil.js} +1 -1
  158. package/public/assets/{Setup-Bsxx1zgj.js → Setup-lGZEk5jq.js} +1 -1
  159. package/public/assets/{WeixinLoginPanel-DPZpAKgO.js → WeixinLoginPanel-CoGqzxeV.js} +2 -2
  160. package/public/assets/index-87IJXG-w.css +1 -0
  161. package/public/assets/index-BZc5zH7u.js +19 -0
  162. package/public/assets/{registry-5s2UB6is.js → registry-BWnkJgZ1.js} +2 -2
  163. package/public/assets/{usePolling-Do5Erqm_.js → usePolling-CwwT9KrC.js} +1 -1
  164. package/public/assets/{vendor-i18n-ucpM0OR0.js → vendor-i18n-y9V7Sfuu.js} +1 -1
  165. package/public/assets/{vendor-react-Bk1hRGiY.js → vendor-react-BWrEVJVb.js} +6 -6
  166. package/public/index.html +4 -4
  167. package/scripts/check-app-spec.mjs +18 -4
  168. package/scripts/check-new-file-tests.mjs +230 -0
  169. package/scripts/check-quarantine-expiry.mjs +105 -0
  170. package/scripts/perf/README.md +49 -0
  171. package/scripts/perf/auth.js +99 -0
  172. package/scripts/perf/config.js +63 -0
  173. package/scripts/perf/instances.js +143 -0
  174. package/scripts/perf/proxy.js +96 -0
  175. package/scripts/smoke/files-w1.sh +142 -0
  176. package/scripts/smoke-backend.mjs +122 -0
  177. package/scripts/smoke-post-publish.mjs +346 -0
  178. package/public/assets/Dashboard-rkWp-CXd.js +0 -1
  179. package/public/assets/InstanceDetail-CN0FH1aw.js +0 -92
  180. package/public/assets/NewInstance-BousE6kY.js +0 -1
  181. package/public/assets/index-8xZy1z5k.css +0 -1
  182. package/public/assets/index-Dw3HhUYE.js +0 -19
@@ -0,0 +1,321 @@
1
+ import { FilesError, } from "../services/files-manager.js";
2
+ const MAX_UPLOAD_BYTES = 50 * 1024 * 1024; // matches FilesManager default
3
+ export async function filesRoutes(app, deps) {
4
+ const { filesManager } = deps;
5
+ // ── Route-scoped parser ───────────────────────────
6
+ // Pass-through: hand the raw payload stream straight to the handler.
7
+ // Do NOT use parseAs:'buffer' — that would read the whole body into memory.
8
+ app.addContentTypeParser("application/octet-stream", (_req, payload, done) => done(null, payload));
9
+ // W2 PR-3: /api/files/* is the panel-internal substrate for the drive_*
10
+ // MCP shim only. Browser users now manage files via the Filebrowser app
11
+ // mounted at /apps/filebrowser/*. Reject any request that didn't pass
12
+ // the X-Jishushell-Internal-Token check in server.ts auth middleware.
13
+ // Return 404 rather than 401 so unauthenticated probes can't fingerprint
14
+ // the surface.
15
+ app.addHook("onRequest", async (request, reply) => {
16
+ if (!request.internalCallerInstance) {
17
+ return reply.status(404).send();
18
+ }
19
+ });
20
+ // ── GET /api/files (list) ─────────────────────────
21
+ app.get("/api/files", async (req, reply) => {
22
+ const path = decodeOrEmpty(req.query.path);
23
+ const showHidden = req.query.show_hidden === "true";
24
+ try {
25
+ const result = await filesManager.list(path, { showHidden });
26
+ reply.send(result);
27
+ }
28
+ catch (e) {
29
+ sendFilesError(reply, e);
30
+ }
31
+ });
32
+ // ── GET /api/files/raw ────────────────────────────
33
+ app.get("/api/files/raw", async (req, reply) => {
34
+ const path = decodeOrEmpty(req.query.path);
35
+ try {
36
+ // readStream returns a lazy stream factory — no fd opened yet
37
+ const r = await filesManager.readStream(path);
38
+ // Conditional GET (weak ETag) — answer without opening the file
39
+ const ifNoneMatch = req.headers["if-none-match"];
40
+ if (typeof ifNoneMatch === "string" && weakETagMatch(ifNoneMatch, r.etag)) {
41
+ reply.code(304);
42
+ reply.header("ETag", r.etag);
43
+ return reply.send();
44
+ }
45
+ reply.header("Content-Type", r.mime);
46
+ reply.header("Content-Length", String(r.size));
47
+ reply.header("ETag", r.etag);
48
+ reply.header("Last-Modified", new Date(r.mtime * 1000).toUTCString());
49
+ reply.header("Cache-Control", "private, max-age=0");
50
+ reply.header("Content-Disposition", `inline; filename*=UTF-8''${encodeRfc5987(basename(path))}`);
51
+ // Open the fd only now, just before piping
52
+ return reply.send(r.openStream());
53
+ }
54
+ catch (e) {
55
+ sendFilesError(reply, e);
56
+ }
57
+ });
58
+ // ── GET /api/files/preview ────────────────────────
59
+ app.get("/api/files/preview", async (req, reply) => {
60
+ const path = decodeOrEmpty(req.query.path);
61
+ const maxKb = parsePositiveInt(req.query.max_kb, 256) ?? 256;
62
+ const maxBytes = maxKb * 1024;
63
+ try {
64
+ const r = await filesManager.readSmall(path, maxBytes);
65
+ // Response is a JSON envelope; the underlying file's mime is in the body.
66
+ reply.header("ETag", r.etag);
67
+ reply.send({
68
+ path,
69
+ mime: r.mime,
70
+ size: r.size,
71
+ truncated: r.truncated,
72
+ content: r.buf.toString("utf8"),
73
+ });
74
+ }
75
+ catch (e) {
76
+ sendFilesError(reply, e);
77
+ }
78
+ });
79
+ // ── GET /api/files/quota ──────────────────────────
80
+ app.get("/api/files/quota", async (_req, reply) => {
81
+ try {
82
+ const q = await filesManager.quota();
83
+ reply.send(q);
84
+ }
85
+ catch (e) {
86
+ sendFilesError(reply, e);
87
+ }
88
+ });
89
+ // ── PUT /api/files (upload) ───────────────────────
90
+ app.put("/api/files", { bodyLimit: MAX_UPLOAD_BYTES }, async (req, reply) => {
91
+ // Reject non-octet-stream up front for a clean 415
92
+ const ct = (req.headers["content-type"] || "")
93
+ .split(";")[0]
94
+ .trim()
95
+ .toLowerCase();
96
+ if (ct !== "application/octet-stream") {
97
+ return reply
98
+ .code(415)
99
+ .send({
100
+ error: "Content-Type must be application/octet-stream",
101
+ code: "unsupported-media-type",
102
+ });
103
+ }
104
+ const path = decodeOrEmpty(req.query.path);
105
+ const overwrite = req.query.overwrite === "true";
106
+ const ifMatch = req.headers["if-match"];
107
+ // Content-Length is mandatory: chunked uploads (no length) would let
108
+ // a client stream gigabytes before we hit the in-flight size guard,
109
+ // and the resulting "write past limit then soft-delete" path is
110
+ // dangerous when disk is near-full. Reject up front per spec.
111
+ const cl = req.headers["content-length"];
112
+ const clNum = typeof cl === "string" ? Number.parseInt(cl, 10) : Number.NaN;
113
+ if (!Number.isFinite(clNum) || clNum < 0) {
114
+ return reply.code(411).send({
115
+ error: "Content-Length header is required",
116
+ code: "length-required",
117
+ });
118
+ }
119
+ if (clNum > MAX_UPLOAD_BYTES) {
120
+ return reply.code(413).send({
121
+ error: `Content-Length ${clNum} exceeds max ${MAX_UPLOAD_BYTES}`,
122
+ code: "too-large",
123
+ });
124
+ }
125
+ // The route-scoped parser passes payload as the request body (Readable)
126
+ const body = req.body;
127
+ if (!body) {
128
+ return reply
129
+ .code(400)
130
+ .send({ error: "missing request body", code: "no-body" });
131
+ }
132
+ try {
133
+ const result = await filesManager.writeStream(path, body, {
134
+ overwrite,
135
+ ifMatch: typeof ifMatch === "string" ? ifMatch : undefined,
136
+ expectedSize: clNum,
137
+ });
138
+ reply.code(overwrite ? 200 : 201).send({
139
+ path,
140
+ etag: result.etag,
141
+ size: result.size,
142
+ mime: result.mime,
143
+ });
144
+ }
145
+ catch (e) {
146
+ sendFilesError(reply, e);
147
+ }
148
+ });
149
+ // ── POST /api/files/mkdir ─────────────────────────
150
+ app.post("/api/files/mkdir", async (req, reply) => {
151
+ const p = req.body?.path ?? "";
152
+ try {
153
+ await filesManager.mkdir(p);
154
+ reply.code(201).send({ path: p });
155
+ }
156
+ catch (e) {
157
+ sendFilesError(reply, e);
158
+ }
159
+ });
160
+ // ── POST /api/files/move ──────────────────────────
161
+ app.post("/api/files/move", async (req, reply) => {
162
+ const from = req.body?.from ?? "";
163
+ const to = req.body?.to ?? "";
164
+ const overwrite = req.body?.overwrite === true;
165
+ try {
166
+ await filesManager.move(from, to, overwrite);
167
+ reply.send({ from, to });
168
+ }
169
+ catch (e) {
170
+ sendFilesError(reply, e);
171
+ }
172
+ });
173
+ // ── DELETE /api/files ─────────────────────────────
174
+ app.delete("/api/files", async (req, reply) => {
175
+ const path = decodeOrEmpty(req.query.path);
176
+ try {
177
+ await filesManager.remove(path);
178
+ reply.code(204).send();
179
+ }
180
+ catch (e) {
181
+ sendFilesError(reply, e);
182
+ }
183
+ });
184
+ // ── GET /api/files/search ─────────────────────────
185
+ app.get("/api/files/search", async (req, reply) => {
186
+ const q = (req.query.q ?? "").trim();
187
+ if (!q) {
188
+ return reply.code(400).send({ detail: "q required" });
189
+ }
190
+ const rawLimit = parsePositiveInt(req.query.limit, 20) ?? 20;
191
+ const limit = Math.min(Math.max(rawLimit, 1), 100);
192
+ const pathPrefix = decodeOrEmpty(req.query.path) || undefined;
193
+ try {
194
+ const hits = await filesManager.searchIndex(q, { limit, pathPrefix });
195
+ reply.send({ hits });
196
+ }
197
+ catch (e) {
198
+ sendFilesError(reply, e);
199
+ }
200
+ });
201
+ // ── GET /api/files/meta ───────────────────────────
202
+ app.get("/api/files/meta", async (req, reply) => {
203
+ const { sha, path } = req.query;
204
+ if (sha && path) {
205
+ return reply.code(400).send({ detail: "provide sha or path, not both" });
206
+ }
207
+ if (!sha && !path) {
208
+ return reply.code(400).send({ detail: "sha or path required" });
209
+ }
210
+ if (sha && !/^[a-f0-9]{64}$/i.test(sha)) {
211
+ return reply.code(400).send({ detail: "sha must be a 64-char hex string" });
212
+ }
213
+ try {
214
+ const meta = await filesManager.getMeta({
215
+ sha256: sha,
216
+ path: path ? decodeOrEmpty(path) : undefined,
217
+ });
218
+ reply.send(meta);
219
+ }
220
+ catch (e) {
221
+ sendFilesError(reply, e);
222
+ }
223
+ });
224
+ // ── PUT /api/files/meta ───────────────────────────
225
+ // 96KB body cap: Agent A enforces 64KB on the serialized result;
226
+ // the slack covers merged result growth.
227
+ app.put("/api/files/meta", { bodyLimit: 96 * 1024 }, async (req, reply) => {
228
+ const { sha } = req.query;
229
+ if (!sha) {
230
+ return reply.code(400).send({ detail: "sha required" });
231
+ }
232
+ if (!/^[a-f0-9]{64}$/i.test(sha)) {
233
+ return reply.code(400).send({ detail: "sha must be a 64-char hex string" });
234
+ }
235
+ const merge = (req.query.merge ?? "").toLowerCase() !== "false";
236
+ const body = req.body;
237
+ if (body === null ||
238
+ body === undefined ||
239
+ typeof body !== "object" ||
240
+ Array.isArray(body)) {
241
+ return reply.code(400).send({ detail: "body must be a JSON object" });
242
+ }
243
+ try {
244
+ const result = await filesManager.setMeta(sha, body, { merge });
245
+ reply.send(result);
246
+ }
247
+ catch (e) {
248
+ if (e instanceof FilesError && e.httpStatus === 413) {
249
+ return reply.code(413).send({ error: e.message, code: e.code });
250
+ }
251
+ sendFilesError(reply, e);
252
+ }
253
+ });
254
+ // ── POST /api/files/reindex ───────────────────────
255
+ // Potentially long-running — no timeout; let it finish.
256
+ app.post("/api/files/reindex", async (req, reply) => {
257
+ const pathPrefix = decodeOrEmpty(req.query.path) || undefined;
258
+ try {
259
+ const result = await filesManager.reindex({ pathPrefix });
260
+ reply.send(result);
261
+ }
262
+ catch (e) {
263
+ sendFilesError(reply, e);
264
+ }
265
+ });
266
+ // ── GET /api/files/resolve ────────────────────────
267
+ // Returns the absolute host filesystem path for a files/-relative path,
268
+ // plus existence + stat. Used by the drive MCP shim so agents can hand
269
+ // a real filesystem path to IM channel plugins (Feishu / WeChat / ...)
270
+ // that send files. Host==container by buildVolumes(), so the same
271
+ // string is valid inside the OpenClaw container.
272
+ app.get("/api/files/resolve", async (req, reply) => {
273
+ const rel = decodeOrEmpty(req.query.path);
274
+ try {
275
+ const info = await filesManager.resolveLocalPath(rel);
276
+ reply.send(info);
277
+ }
278
+ catch (e) {
279
+ sendFilesError(reply, e);
280
+ }
281
+ });
282
+ }
283
+ // ── Helpers ──────────────────────────────────────────
284
+ function decodeOrEmpty(input) {
285
+ if (!input)
286
+ return "";
287
+ // Fastify already URL-decodes query strings; this is just a defensive type guard.
288
+ return input;
289
+ }
290
+ function parsePositiveInt(s, def) {
291
+ if (s === undefined || s === null)
292
+ return def;
293
+ const n = Number.parseInt(s, 10);
294
+ if (Number.isFinite(n) && n >= 0)
295
+ return n;
296
+ return def;
297
+ }
298
+ function basename(p) {
299
+ if (!p)
300
+ return "";
301
+ const idx = p.lastIndexOf("/");
302
+ return idx === -1 ? p : p.slice(idx + 1);
303
+ }
304
+ function encodeRfc5987(s) {
305
+ // RFC 5987 encoding for filename* parameter
306
+ return encodeURIComponent(s).replace(/['()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
307
+ }
308
+ function weakETagMatch(provided, current) {
309
+ const strip = (x) => x.replace(/^W\//, "");
310
+ return strip(provided) === strip(current);
311
+ }
312
+ function sendFilesError(reply, e) {
313
+ if (e instanceof FilesError) {
314
+ reply.code(e.httpStatus).send({ error: e.message, code: e.code });
315
+ return;
316
+ }
317
+ const err = e;
318
+ console.error("[files-routes] unexpected:", err.message);
319
+ reply.code(500).send({ error: "internal error", code: err.code ?? "internal" });
320
+ }
321
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/routes/files.ts"],"names":[],"mappings":"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"}
@@ -269,6 +269,20 @@ function capabilityProxyBootstrap(proxyBasePath) {
269
269
  "var _lr=location.replace.bind(location);",
270
270
  "location.assign=function(u){return _la(rw(u));};",
271
271
  "location.replace=function(u){return _lr(rw(u));};",
272
+ // --- frame-busting defense ---
273
+ // Embedded SPAs (e.g. WeKnora) frequently do
274
+ // window.top.location.href = '/login'
275
+ // when they see a 401, intending to log the user out. Inside our
276
+ // capability proxy iframe `top` is the panel's main window — that
277
+ // tears the user away from the instance detail page entirely.
278
+ // Redirect `top`/`parent` to the iframe's own window so the
279
+ // navigation stays inside the embed. Safe because the iframe IS
280
+ // same-origin as the panel (our reverse proxy serves it from the
281
+ // panel's host); cross-origin access would throw and fail closed.
282
+ "try{",
283
+ "Object.defineProperty(window,'top',{configurable:true,get:function(){return window;}});",
284
+ "Object.defineProperty(window,'parent',{configurable:true,get:function(){return window;}});",
285
+ "}catch(_e){}",
272
286
  // --- dynamic property assignment: img.src = '/static/...' ---
273
287
  "function patchProp(tag,prop){",
274
288
  "var d=Object.getOwnPropertyDescriptor(tag.prototype,prop);",
@@ -598,6 +612,21 @@ async function proxyProvidedCapability(req, reply) {
598
612
  if (HOP_BY_HOP.has(normalizedKey) || normalizedKey === "content-length" || normalizedKey === "content-encoding") {
599
613
  return;
600
614
  }
615
+ // When we rewrite the response body (HTML/CSS/JS), the upstream ETag /
616
+ // Cache-Control values describe the *original* upstream bytes — but the
617
+ // body the browser receives is post-rewrite (proxy-prefixed paths, JS
618
+ // hard-coded redirect targets, etc.). Honoring the upstream cache hints
619
+ // lets the browser pin a stale rewrite indefinitely: e.g. an early
620
+ // visit that pre-dated the JS rewrite gets cached and survives across
621
+ // panel restarts, breaking the auth redirect logic until a hard refresh.
622
+ // Strip cache validators and force revalidation on every load.
623
+ if (willRewriteBody && (normalizedKey === "cache-control" ||
624
+ normalizedKey === "etag" ||
625
+ normalizedKey === "last-modified" ||
626
+ normalizedKey === "expires" ||
627
+ normalizedKey === "pragma")) {
628
+ return;
629
+ }
601
630
  if (willInjectHtml && (normalizedKey === "content-security-policy" ||
602
631
  normalizedKey === "content-security-policy-report-only" ||
603
632
  normalizedKey === "x-frame-options")) {
@@ -627,6 +656,10 @@ async function proxyProvidedCapability(req, reply) {
627
656
  return reply.send();
628
657
  }
629
658
  if (willRewriteBody) {
659
+ // Pair with the cache-validator strip above.
660
+ reply.header("cache-control", "no-cache, no-store, must-revalidate");
661
+ reply.header("pragma", "no-cache");
662
+ reply.header("expires", "0");
630
663
  let extraHeadHtml = "";
631
664
  if (req.params.capability === "browserless-debugger") {
632
665
  extraHeadHtml = browserlessDebuggerBootstrap(req.params.id);
@@ -645,11 +678,16 @@ async function proxyProvidedCapability(req, reply) {
645
678
  // emit Clear-Site-Data so the browser drops the SW + its cache and
646
679
  // reloads through the proxy. We mark the success with a long-lived
647
680
  // cookie scoped to the proxy path to avoid a reload loop.
648
- const cookieHeader = (req.headers.cookie || "").toString();
649
- const swCleaned = /(?:^|;\s*)cap_proxy_sw_clean=1(?:;|$)/.test(cookieHeader);
650
- if (!swCleaned) {
651
- reply.header("Clear-Site-Data", '"cache", "storage"');
652
- reply.header("Set-Cookie", `cap_proxy_sw_clean=1; Path=${proxyBasePath}; Max-Age=2592000; SameSite=Lax`);
681
+ // Gate to HTML only — JS/CSS sub-resources also flow through this branch
682
+ // now that we rewrite JS bundles, and emitting Clear-Site-Data on a JS
683
+ // response would clear storage mid-page-load.
684
+ if (willInjectHtml) {
685
+ const cookieHeader = (req.headers.cookie || "").toString();
686
+ const swCleaned = /(?:^|;\s*)cap_proxy_sw_clean=1(?:;|$)/.test(cookieHeader);
687
+ if (!swCleaned) {
688
+ reply.header("Clear-Site-Data", '"cache", "storage"');
689
+ reply.header("Set-Cookie", `cap_proxy_sw_clean=1; Path=${proxyBasePath}; Max-Age=2592000; SameSite=Lax`);
690
+ }
653
691
  }
654
692
  const rawBody = await upstream.text();
655
693
  req.raw.off("close", onClientClose);
@@ -1625,7 +1663,7 @@ export async function instanceRoutes(app) {
1625
1663
  return { lines: logLines };
1626
1664
  });
1627
1665
  // Admin: re-encrypt all instance secrets with current AES key
1628
- app.post("/api/admin/migrate-secrets", async (_req, reply) => {
1666
+ app.post("/api/admin/migrate-secrets", async (_req, _reply) => {
1629
1667
  const { getAesKey, getJwtSecret } = await import("../config.js");
1630
1668
  const { scryptSync, createDecipheriv, createCipheriv, randomBytes } = await import("crypto");
1631
1669
  const { readFileSync, existsSync: fsExistsSync } = await import("fs");
@@ -1775,7 +1813,7 @@ export async function instanceRoutes(app) {
1775
1813
  const consumerAgentType = String(meta?.agentType ?? "");
1776
1814
  const consumerIsAgent = consumerAgentType === "hermes" || consumerAgentType === "openclaw";
1777
1815
  const requires = (specInfo.spec.requires ?? []).map((r) => {
1778
- const isCategoryToken = ["llm", "search", "browser", "mcp"].includes(r.capability);
1816
+ const isCategoryToken = ["llm", "search", "browser", "mcp", "files", "knowledge"].includes(r.capability);
1779
1817
  const candidates = isCategoryToken
1780
1818
  ? Object.entries(capabilityRegistry.snapshot().providersByCapability ?? {})
1781
1819
  .filter(([cap]) => cap.startsWith(r.capability + "-") || cap === r.capability)