aicodeman 1.46.0 → 1.47.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/dist/ralph-fix-plan-watcher.d.ts +13 -1
- package/dist/ralph-fix-plan-watcher.d.ts.map +1 -1
- package/dist/ralph-fix-plan-watcher.js +21 -3
- package/dist/ralph-fix-plan-watcher.js.map +1 -1
- package/dist/ralph-tracker.d.ts +6 -0
- package/dist/ralph-tracker.d.ts.map +1 -1
- package/dist/ralph-tracker.js +8 -0
- package/dist/ralph-tracker.js.map +1 -1
- package/dist/web/public/admin-ui.js.gz +0 -0
- package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
- package/dist/web/public/{app.3093527f.js → app.fe8a6b4c.js} +16 -16
- package/dist/web/public/app.fe8a6b4c.js.br +0 -0
- package/dist/web/public/app.fe8a6b4c.js.gz +0 -0
- package/dist/web/public/approvals-ui.js.gz +0 -0
- package/dist/web/public/constants.affcdde6.js.gz +0 -0
- package/dist/web/public/cron-ui.js.gz +0 -0
- package/dist/web/public/entrance-animations.js.gz +0 -0
- package/dist/web/public/git-status-ui.js.gz +0 -0
- package/dist/web/public/header-divider.eb2d2463.js.gz +0 -0
- package/dist/web/public/home-sessions.js.gz +0 -0
- package/dist/web/public/host-wake-ui.js.gz +0 -0
- package/dist/web/public/i18n.a618ef4e.js +2 -0
- package/dist/web/public/i18n.a618ef4e.js.br +0 -0
- package/dist/web/public/i18n.a618ef4e.js.gz +0 -0
- package/dist/web/public/{image-input.941386e7.js → image-input.a5d0f8f3.js} +18 -9
- package/dist/web/public/image-input.a5d0f8f3.js.br +0 -0
- package/dist/web/public/image-input.a5d0f8f3.js.gz +0 -0
- package/dist/web/public/index.html +8 -8
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
- package/dist/web/public/{keyboard-accessory.4e8b20ac.js → keyboard-accessory.ff64fafc.js} +5 -1
- package/dist/web/public/keyboard-accessory.ff64fafc.js.br +0 -0
- package/dist/web/public/keyboard-accessory.ff64fafc.js.gz +0 -0
- package/dist/web/public/mobile-handlers.f7c3f692.js.gz +0 -0
- package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
- package/dist/web/public/mobile-overview.js.gz +0 -0
- package/dist/web/public/mobile.1bbd2d67.css.gz +0 -0
- package/dist/web/public/notification-manager.feb82c04.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/panels-ui.4a56ee63.js.gz +0 -0
- package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
- package/dist/web/public/ralph-wizard.b6c0dd19.js.gz +0 -0
- package/dist/web/public/readmymind-ui.js.gz +0 -0
- package/dist/web/public/reboot-restore-ui.js.gz +0 -0
- package/dist/web/public/respawn-ui.d7adcf6a.js.gz +0 -0
- package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
- package/dist/web/public/session-lineage.js.gz +0 -0
- package/dist/web/public/{session-ui.186f9419.js → session-ui.426fb671.js} +6 -6
- package/dist/web/public/session-ui.426fb671.js.br +0 -0
- package/dist/web/public/session-ui.426fb671.js.gz +0 -0
- package/dist/web/public/settings-ui.a191154e.js.gz +0 -0
- package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
- package/dist/web/public/spreadsheet-preview.75c751de.js.gz +0 -0
- package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
- package/dist/web/public/styles.4f0c67a0.css +1 -0
- package/dist/web/public/styles.4f0c67a0.css.br +0 -0
- package/dist/web/public/styles.4f0c67a0.css.gz +0 -0
- package/dist/web/public/subagent-windows.07277a58.js.gz +0 -0
- package/dist/web/public/sw.js +2 -2
- package/dist/web/public/sw.js.br +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/tab-layout-browser.2d6189f7.js.gz +0 -0
- package/dist/web/public/tab-rail-resize.b5cdceaf.js.gz +0 -0
- package/dist/web/public/terminal-keycode229-recovery.98843069.js +1 -0
- package/dist/web/public/terminal-keycode229-recovery.98843069.js.br +0 -0
- package/dist/web/public/terminal-keycode229-recovery.98843069.js.gz +0 -0
- package/dist/web/public/terminal-split.js.gz +0 -0
- package/dist/web/public/terminal-tile.js +8 -6
- package/dist/web/public/terminal-tile.js.br +0 -0
- package/dist/web/public/terminal-tile.js.gz +0 -0
- package/dist/web/public/terminal-ui.7e787829.js.gz +0 -0
- package/dist/web/public/tile-grid.js.gz +0 -0
- package/dist/web/public/ultracode-panel.js.gz +0 -0
- package/dist/web/public/ultracode-windows.js.gz +0 -0
- package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
- package/dist/web/public/vendor/fflate.min.js.gz +0 -0
- package/dist/web/public/vendor/marked.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.276b11d9.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.1be42307.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/voice-input.2342c37b.js.gz +0 -0
- package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
- package/dist/web/public/webview-tabs.js.gz +0 -0
- package/dist/web/public/whats-new.json +8 -9
- package/dist/web/request-body-parser.d.ts +23 -0
- package/dist/web/request-body-parser.d.ts.map +1 -0
- package/dist/web/request-body-parser.js +57 -0
- package/dist/web/request-body-parser.js.map +1 -0
- package/dist/web/routes/file-routes.d.ts +5 -0
- package/dist/web/routes/file-routes.d.ts.map +1 -1
- package/dist/web/routes/file-routes.js +5 -1
- package/dist/web/routes/file-routes.js.map +1 -1
- package/dist/web/routes/ralph-routes.d.ts.map +1 -1
- package/dist/web/routes/ralph-routes.js +45 -2
- package/dist/web/routes/ralph-routes.js.map +1 -1
- package/dist/web/routes/session-routes.d.ts.map +1 -1
- package/dist/web/routes/session-routes.js +5 -0
- package/dist/web/routes/session-routes.js.map +1 -1
- package/dist/web/routes/system-routes.d.ts.map +1 -1
- package/dist/web/routes/system-routes.js +3 -2
- package/dist/web/routes/system-routes.js.map +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +18 -4
- package/dist/web/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/web/public/app.3093527f.js.br +0 -0
- package/dist/web/public/app.3093527f.js.gz +0 -0
- package/dist/web/public/i18n.70265257.js +0 -2
- package/dist/web/public/i18n.70265257.js.br +0 -0
- package/dist/web/public/i18n.70265257.js.gz +0 -0
- package/dist/web/public/image-input.941386e7.js.br +0 -0
- package/dist/web/public/image-input.941386e7.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.4e8b20ac.js.br +0 -0
- package/dist/web/public/keyboard-accessory.4e8b20ac.js.gz +0 -0
- package/dist/web/public/session-ui.186f9419.js.br +0 -0
- package/dist/web/public/session-ui.186f9419.js.gz +0 -0
- package/dist/web/public/styles.7238eae8.css +0 -1
- package/dist/web/public/styles.7238eae8.css.br +0 -0
- package/dist/web/public/styles.7238eae8.css.gz +0 -0
- package/dist/web/public/terminal-keycode229-recovery.af09f99a.js +0 -1
- package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.br +0 -0
- package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.gz +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/web/public/sw.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
// not the current one, so the old constant key meant that cleanup never deleted
|
|
27
27
|
// anything — hashed assets from every release ever deployed accumulated in one
|
|
28
28
|
// bucket until the origin hit its storage quota.
|
|
29
|
-
const BUILD_ID = '
|
|
29
|
+
const BUILD_ID = 'fada7ad2af00';
|
|
30
30
|
const CACHE_NAME = `codeman-${BUILD_ID}`;
|
|
31
31
|
|
|
32
32
|
// Reverse-proxy base path: the worker is served at `<base>/sw.js`, so its own
|
|
@@ -48,7 +48,7 @@ const B = (p) => (p && p[0] === '/' ? SW_BASE + p : p);
|
|
|
48
48
|
// handler caches every successful GET at runtime, but the precache warmed
|
|
49
49
|
// nothing while looking like it did. Deriving it from the same manifest that
|
|
50
50
|
// renames the files is the only thing that keeps the two from drifting again.
|
|
51
|
-
const HASHED_ASSETS = ["styles.
|
|
51
|
+
const HASHED_ASSETS = ["styles.4f0c67a0.css", "mobile.1bbd2d67.css", "constants.affcdde6.js", "i18n.a618ef4e.js", "mobile-handlers.f7c3f692.js", "voice-input.2342c37b.js", "notification-manager.feb82c04.js", "keyboard-accessory.ff64fafc.js", "input-cjk.8bc46081.js", "mobile-ime-preview.2dbaf262.js", "terminal-keycode229-recovery.98843069.js", "sanitize-html.e7147e76.js", "tab-layout-browser.2d6189f7.js", "app.fe8a6b4c.js", "tab-rail-resize.b5cdceaf.js", "header-divider.eb2d2463.js", "terminal-ui.7e787829.js", "respawn-ui.d7adcf6a.js", "ralph-panel.b350e2ef.js", "settings-ui.a191154e.js", "panels-ui.4a56ee63.js", "session-ui.426fb671.js", "ralph-wizard.b6c0dd19.js", "api-client.c9b1cddc.js", "subagent-windows.07277a58.js", "image-input.a5d0f8f3.js", "spreadsheet-preview.75c751de.js", "vendor/xterm-zerolag-input.1be42307.js", "vendor/xterm-predictive-echo.276b11d9.js"];
|
|
52
52
|
|
|
53
53
|
// Core app shell -- cached on install for instant startup
|
|
54
54
|
const APP_SHELL = [
|
package/dist/web/public/sw.js.br
CHANGED
|
Binary file
|
package/dist/web/public/sw.js.gz
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(function(c){"use strict";function T(o,t){const u=Array.from(o),d=Array.from(t);let r=0;const y=Math.min(u.length,d.length);for(;r<y&&u[r]===d[r];)r+=1;return{deleted:u.length-r,inserted:d.slice(r).join("")}}function D(){try{return/Android/i.test(c.navigator?.userAgent||"")?!0:c.matchMedia?.("(pointer: coarse)")?.matches===!0}catch{return!1}}function M(o){if(!D())return null;const t=o?.textarea,u=o?.emitRecovered;if(!t?.addEventListener||!t?.removeEventListener||typeof u!="function")return null;const d=o.isScreenReaderMode,r=o.setTimer||c.setTimeout.bind(c),y=o.clearTimer||c.clearTimeout.bind(c);let i=!1,p=0,x=0,v=!1;const m=[];let g=()=>{};function j(){for(const e of m.splice(0)){if(e.timer!==null){try{y(e.timer)}catch{}e.timer=null}S(e)}}function C(){for(const e of m.splice(0))if(e.active=!1,e.timer!==null){try{y(e.timer)}catch{}e.timer=null}}function S(e){const n=m.indexOf(e);if(n!==-1&&m.splice(n,1),e.timer=null,!(!e.active||i)&&(e.active=!1,!(p>e.snapshot)))try{u(e.data)}catch{}}function k(){p+=1}function K(e){i||e?.type!=="keydown"||(g(e),j(),x=p)}function w(e){if(i||v||e?.isComposing||e.inputType!=="insertText")return;const n=e.data;if(typeof n!="string"||n==="")return;try{if(d?.())return}catch{return}const a={data:n,snapshot:x??p,active:!0,timer:null};m.push(a);try{a.timer=r(()=>S(a),0)}catch{C()}}function O(){let e;try{e=o.getCompositionHelper?.()}catch{return null}const n=e?._handleAnyTextareaChanges,a=e?._coreService;if(typeof n!="function"||typeof a?.triggerDataEvent!="function")return null;let h=t.value;const f=new Set;function R(){if(i||e._isComposing)return;const l=t.value;if(l===h)return;const{deleted:s,inserted:E}=T(h,l);h=l;try{for(let z=0;z<s;z+=1)a.triggerDataEvent("\x7F",!0);E&&(e._dataAlreadySent=E,a.triggerDataEvent(E,!0))}catch{}}return e._handleAnyTextareaChanges=function(){if(i)return n.call(this);f.size===0&&h!==t.value&&(h=t.value);const s={id:null};f.add(s),s.id=r(()=>{f.delete(s),R()},0)},g=l=>{if(f.size!==0){for(const s of f)try{y(s.id)}catch{}f.clear(),!(e._isSendingComposition&&![229,20,16,17,18].includes(l?.keyCode))&&R()}},()=>{g=()=>{},e._handleAnyTextareaChanges!==n&&(e._handleAnyTextareaChanges=n)}}const P=O();function A(){i||(v=!0,C())}function L(){i||(v=!1)}function _(){if(!i){i=!0,C();try{P?.()}catch{}try{t.removeEventListener("input",w,!0),t.removeEventListener("compositionstart",A,!0),t.removeEventListener("compositionend",L,!0)}catch{}}}try{t.addEventListener("input",w,!0),t.addEventListener("compositionstart",A,!0),t.addEventListener("compositionend",L,!0)}catch{return _(),null}return Object.freeze({handleKeyEvent:K,notifyCanonicalData:k,destroy:_})}c.CodemanKeyCode229Recovery=Object.freeze({create:M,editBetween:T})})(typeof window<"u"?window:globalThis);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -344,9 +344,10 @@
|
|
|
344
344
|
if (global.app?.tileShortcutFor?.(ev)) return false;
|
|
345
345
|
// Ctrl+V / Cmd+V: the primary pane's paste trap, aimed at THIS pane, so
|
|
346
346
|
// a pasted image uploads to this pane's session and its path is typed
|
|
347
|
-
// here
|
|
348
|
-
//
|
|
349
|
-
//
|
|
347
|
+
// here. Plain text goes to this pane's session as a Codeman-built
|
|
348
|
+
// bracketed-paste frame; this terminal is only refocused and receives
|
|
349
|
+
// input(framed), which onData delivers. Mirrors terminal-ui.js's own
|
|
350
|
+
// Ctrl+V gate; without it xterm's default only ever pasted text.
|
|
350
351
|
if ((ev.ctrlKey || ev.metaKey) && ev.key === 'v' && ev.type === 'keydown') {
|
|
351
352
|
global.app?._handleImagePaste?.({ terminal: this.terminal, sessionId: this.sessionId });
|
|
352
353
|
return false;
|
|
@@ -646,9 +647,10 @@
|
|
|
646
647
|
// Recovered text goes straight to _onTerminalData(), never through xterm's
|
|
647
648
|
// onData, so it is not counted as xterm's own (see connect()'s onData).
|
|
648
649
|
// Created after terminal.open(): xterm's capture `input` listener on the
|
|
649
|
-
// textarea is registered there, and must run before the controller's.
|
|
650
|
-
//
|
|
651
|
-
//
|
|
650
|
+
// textarea is registered there, and must run before the controller's.
|
|
651
|
+
// create() returns null on a fine pointer (#716): the recovery is for soft
|
|
652
|
+
// keyboards, and on a desktop it delivers a dead-key character twice.
|
|
653
|
+
// A failure leaves xterm's own handling.
|
|
652
654
|
_createKeyCode229Recovery() {
|
|
653
655
|
this._destroyKeyCode229Recovery();
|
|
654
656
|
if (!this.terminal) return;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
2
|
+
"version": "1.47.0",
|
|
3
3
|
"highlights": [
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"Experimental: bounded inspection and guarded submission for agents (#694, opt-in)"
|
|
4
|
+
"The wrapped tab strip uses the room under the toolbar (#721)",
|
|
5
|
+
"Bodyless requests work through Cloudflare Tunnel (#725)",
|
|
6
|
+
"A desktop dead key is typed once, and Ctrl+V stays a paste after a replay (#726, #716)",
|
|
7
|
+
"Remote sessions no longer touch the local disk at their path (#722, #727, #728)",
|
|
8
|
+
"Rendered Markdown fills a resized File Viewer (#730)",
|
|
9
|
+
"A middle click on a file path opens the file (#731)",
|
|
10
|
+
"No more duplicate-key warning on build (#729)"
|
|
12
11
|
]
|
|
13
12
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Accept empty, untyped API POSTs even when a reverse proxy frames them as chunked.
|
|
3
|
+
*
|
|
4
|
+
* Cloudflare Tunnel (cloudflared, Go's HTTP client) forwards a bodyless POST as an HTTP/1.1
|
|
5
|
+
* chunked request with no Content-Type and a zero-length body. Fastify only skips its
|
|
6
|
+
* content-type check for a `Content-Length: 0` request, so this framing was refused 415
|
|
7
|
+
* (`FST_ERR_CTP_INVALID_MEDIA_TYPE`) before the route ran, breaking actions such as opening a
|
|
8
|
+
* saved web tab. This parser lets such a request reach its route with `request.body === undefined`,
|
|
9
|
+
* exactly as a `Content-Length: 0` request does.
|
|
10
|
+
*
|
|
11
|
+
* Scope is POST under `/api/` only: Go frames an empty body of unknown length as chunked for
|
|
12
|
+
* POST, PUT and PATCH and drops it for DELETE, and every PUT/PATCH the frontend sends carries a
|
|
13
|
+
* JSON body. Anything else (another method, a non-API route, a Content-Type, a non-zero
|
|
14
|
+
* Content-Length, or a single body byte) is still the 415 Fastify would have answered.
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ It owns the ROOT `'*'` content-type slot. The JSON, `text/plain` (kept RAW, see the CSRF
|
|
17
|
+
* note in CLAUDE.md) and multipart parsers match first; the web-tab proxy registers its own
|
|
18
|
+
* `'*'` in an encapsulated scope and is unaffected. Fastify refuses a second root `'*'` parser at
|
|
19
|
+
* boot (`FST_ERR_CTP_ALREADY_PRESENT`), so extend this function instead of adding one.
|
|
20
|
+
*/
|
|
21
|
+
import { type FastifyInstance } from 'fastify';
|
|
22
|
+
export declare function installEmptyApiPostParser(app: FastifyInstance): void;
|
|
23
|
+
//# sourceMappingURL=request-body-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-body-parser.d.ts","sourceRoot":"","sources":["../../src/web/request-body-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAc,KAAK,eAAe,EAAuB,MAAM,SAAS,CAAC;AAGhF,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,CAmCpE"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Accept empty, untyped API POSTs even when a reverse proxy frames them as chunked.
|
|
3
|
+
*
|
|
4
|
+
* Cloudflare Tunnel (cloudflared, Go's HTTP client) forwards a bodyless POST as an HTTP/1.1
|
|
5
|
+
* chunked request with no Content-Type and a zero-length body. Fastify only skips its
|
|
6
|
+
* content-type check for a `Content-Length: 0` request, so this framing was refused 415
|
|
7
|
+
* (`FST_ERR_CTP_INVALID_MEDIA_TYPE`) before the route ran, breaking actions such as opening a
|
|
8
|
+
* saved web tab. This parser lets such a request reach its route with `request.body === undefined`,
|
|
9
|
+
* exactly as a `Content-Length: 0` request does.
|
|
10
|
+
*
|
|
11
|
+
* Scope is POST under `/api/` only: Go frames an empty body of unknown length as chunked for
|
|
12
|
+
* POST, PUT and PATCH and drops it for DELETE, and every PUT/PATCH the frontend sends carries a
|
|
13
|
+
* JSON body. Anything else (another method, a non-API route, a Content-Type, a non-zero
|
|
14
|
+
* Content-Length, or a single body byte) is still the 415 Fastify would have answered.
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ It owns the ROOT `'*'` content-type slot. The JSON, `text/plain` (kept RAW, see the CSRF
|
|
17
|
+
* note in CLAUDE.md) and multipart parsers match first; the web-tab proxy registers its own
|
|
18
|
+
* `'*'` in an encapsulated scope and is unaffected. Fastify refuses a second root `'*'` parser at
|
|
19
|
+
* boot (`FST_ERR_CTP_ALREADY_PRESENT`), so extend this function instead of adding one.
|
|
20
|
+
*/
|
|
21
|
+
import { errorCodes } from 'fastify';
|
|
22
|
+
export function installEmptyApiPostParser(app) {
|
|
23
|
+
// Existing JSON, text and multipart parsers take precedence. The webview
|
|
24
|
+
// proxy installs its own parser in an encapsulated scope.
|
|
25
|
+
app.addContentTypeParser('*', async (req, payload) => {
|
|
26
|
+
// Fastify normally skips an unsupported parser on its 404 path. Preserve
|
|
27
|
+
// that behavior, including the unread stream used by referer fallbacks.
|
|
28
|
+
if (req.is404)
|
|
29
|
+
return undefined;
|
|
30
|
+
if (req.method !== 'POST' ||
|
|
31
|
+
!req.routeOptions.url?.startsWith('/api/') ||
|
|
32
|
+
req.headers['content-type'] !== undefined ||
|
|
33
|
+
(req.headers['content-length'] !== undefined && req.headers['content-length'] !== '0')) {
|
|
34
|
+
throw new errorCodes.FST_ERR_CTP_INVALID_MEDIA_TYPE();
|
|
35
|
+
}
|
|
36
|
+
// Wait for the terminating chunk to prove the body is empty. Reject on the
|
|
37
|
+
// first byte instead of buffering an unsupported body. Leave the socket
|
|
38
|
+
// alive so Fastify can send its 415 and close the connection on parser errors.
|
|
39
|
+
try {
|
|
40
|
+
for await (const chunk of payload.iterator({ destroyOnReturn: false })) {
|
|
41
|
+
if (Buffer.byteLength(chunk) > 0)
|
|
42
|
+
throw new errorCodes.FST_ERR_CTP_INVALID_MEDIA_TYPE();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// Match Fastify's body reader: an interrupted request is a client error.
|
|
47
|
+
const err = error;
|
|
48
|
+
if (typeof err.statusCode !== 'number' || err.statusCode < 400)
|
|
49
|
+
err.statusCode = 400;
|
|
50
|
+
throw err;
|
|
51
|
+
}
|
|
52
|
+
// No synthetic JSON or header rewriting: required-body validation still
|
|
53
|
+
// sees the same undefined value as a direct Content-Length: 0 request.
|
|
54
|
+
return undefined;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=request-body-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-body-parser.js","sourceRoot":"","sources":["../../src/web/request-body-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,UAAU,EAA6C,MAAM,SAAS,CAAC;AAGhF,MAAM,UAAU,yBAAyB,CAAC,GAAoB;IAC5D,yEAAyE;IACzE,0DAA0D;IAC1D,GAAG,CAAC,oBAAoB,CAAC,GAAG,EAAE,KAAK,EAAE,GAAmB,EAAE,OAAiB,EAAE,EAAE;QAC7E,yEAAyE;QACzE,wEAAwE;QACxE,IAAI,GAAG,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAEhC,IACE,GAAG,CAAC,MAAM,KAAK,MAAM;YACrB,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC;YAC1C,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,SAAS;YACzC,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,KAAK,SAAS,IAAI,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,KAAK,GAAG,CAAC,EACtF,CAAC;YACD,MAAM,IAAI,UAAU,CAAC,8BAA8B,EAAE,CAAC;QACxD,CAAC;QAED,2EAA2E;QAC3E,wEAAwE;QACxE,+EAA+E;QAC/E,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;gBACvE,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC;oBAAE,MAAM,IAAI,UAAU,CAAC,8BAA8B,EAAE,CAAC;YAC1F,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,yEAAyE;YACzE,MAAM,GAAG,GAAG,KAAwC,CAAC;YACrD,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,IAAI,GAAG,CAAC,UAAU,GAAG,GAAG;gBAAE,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;YACrF,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,wEAAwE;QACxE,uEAAuE;QACvE,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -58,6 +58,11 @@ export declare function sendFileBody(reply: FastifyReply, size: number, rangeHea
|
|
|
58
58
|
* the form is refused instead of guessed.
|
|
59
59
|
*/
|
|
60
60
|
export declare const DOCKER_HOME_PATH_ERROR = "A ~/ path inside a Docker case is the container home, which this server cannot read; use the absolute path";
|
|
61
|
+
/**
|
|
62
|
+
* Whether `candidate` is `root` itself or lies beneath it (both already resolved). The one lexical
|
|
63
|
+
* containment check for workspace confinement; ralph-routes.ts uses it for a remote `@fix_plan.md`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function isPathWithinRoot(root: string, candidate: string): boolean;
|
|
61
66
|
export declare function registerFileRoutes(app: FastifyInstance, ctx: SessionPort & EventPort & ConfigPort): void;
|
|
62
67
|
export {};
|
|
63
68
|
//# sourceMappingURL=file-routes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-routes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/file-routes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAG7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAgE5C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAU5E;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,QAAmB,CAAC;AAgH/D;;;GAGG;AACH,UAAU,cAAc;IACtB,OAAO,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,iGAAiG;AACjG,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,IAC1C,QAAQ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,KAAG,cAAc,CAGhE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAC1C,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,KAAK,cAAc,GAC/D,IAAI,CAyBN;AAoTD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,+GAC2E,CAAC;
|
|
1
|
+
{"version":3,"file":"file-routes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/file-routes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAG7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAgE5C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAU5E;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,QAAmB,CAAC;AAgH/D;;;GAGG;AACH,UAAU,cAAc;IACtB,OAAO,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,iGAAiG;AACjG,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,IAC1C,QAAQ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,KAAG,cAAc,CAGhE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAC1C,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,KAAK,cAAc,GAC/D,IAAI,CAyBN;AAoTD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,+GAC2E,CAAC;AA0L/G;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAGzE;AA8hBD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,IAAI,CA09CxG"}
|
|
@@ -515,7 +515,11 @@ const FILESYSTEM_BINARY_PREVIEW_LIMIT = 50 * 1024 * 1024;
|
|
|
515
515
|
const FILESYSTEM_IMAGE_PREVIEW_EXTENSIONS = new Set(['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp']);
|
|
516
516
|
const FILESYSTEM_TEXT_PREVIEW_EXTENSIONS = new Set(['md', 'txt', 'json']);
|
|
517
517
|
const FILESYSTEM_DOCUMENT_PREVIEW_EXTENSIONS = new Set(['pdf', 'docx', 'pptx']);
|
|
518
|
-
|
|
518
|
+
/**
|
|
519
|
+
* Whether `candidate` is `root` itself or lies beneath it (both already resolved). The one lexical
|
|
520
|
+
* containment check for workspace confinement; ralph-routes.ts uses it for a remote `@fix_plan.md`.
|
|
521
|
+
*/
|
|
522
|
+
export function isPathWithinRoot(root, candidate) {
|
|
519
523
|
const rel = relative(root, candidate);
|
|
520
524
|
return rel === '' || (!isAbsolute(rel) && rel !== '..' && !rel.startsWith(`..${sep}`));
|
|
521
525
|
}
|