@goodandready/dsh-dsml-artifact-guard 0.2.4 → 0.2.5
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/CHANGELOG.md +9 -1
- package/lib/client.js +4 -4
- package/lib/index.js +16 -5
- package/lib/updater.js +8 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
## 0.2.
|
|
10
|
+
## [0.2.5] - 2026-09-24
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Preflight & Locale Contract**: eliminated nonexistent `locale.get()` call in `lib/client.js`, using injected `props.t` with canonical `ctx.locale.bind(NS)` fallback (#36).
|
|
14
|
+
- **Streaming Buffer & Tag Balancing**: replaced fixed 64-character buffer slicing with delimiter-based tag boundary scanning (`<` and `>`), ensuring DSML parameter tags of arbitrary length preserve open/close tag balance without premature truncation (#37).
|
|
15
|
+
- **One-Click Updater LAN Support**: updated `isTrustedUpdateRequest` to allow same-origin requests matching Host/Origin, enabling one-click updates from LAN and reverse-proxy Web UIs while retaining strict loopback verification for local endpoints (#38).
|
|
16
|
+
- **Dead Code Elimination**: connected `checkRequestMethod` helper to updater POST handler (#39).
|
|
17
|
+
|
|
18
|
+
## [0.2.4] - 2026-09-22
|
|
11
19
|
|
|
12
20
|
### Fixed
|
|
13
21
|
- The settings card no longer waits for the removed `settingsScope` service. It uses `configForms` on current DeepSeek Harness (#41).
|
package/lib/client.js
CHANGED
|
@@ -528,10 +528,10 @@ window.__ModuleLoader__.load({
|
|
|
528
528
|
// title) and view:'page' (the form, bare). The older seat keeps the card.
|
|
529
529
|
function PluginItem(props) {
|
|
530
530
|
if (props && props.view === 'summary') {
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
const tt = typeof props.t === 'function' ? props.t : (k) =>
|
|
531
|
+
const tBind = (props && props.ctx && typeof props.ctx.locale?.bind === 'function')
|
|
532
|
+
? props.ctx.locale.bind(NS)
|
|
533
|
+
: null;
|
|
534
|
+
const tt = typeof props.t === 'function' ? props.t : (typeof tBind === 'function' ? tBind : (k) => en[k] || k);
|
|
535
535
|
return React.createElement('div', {
|
|
536
536
|
'data-dsh-plugin': NS,
|
|
537
537
|
className: 'dsh-dsml-artifact-guard-sub',
|
package/lib/index.js
CHANGED
|
@@ -5,7 +5,6 @@ const TAIL = /(?:<\/|DSML|parameter>\s*)?(?:<\/|DSML|invoke>\s*)?<\/|D
|
|
|
5
5
|
const OPEN_TAG = /<|DSML|(?:tool_calls|invoke|parameter)[^>]*>/gu;
|
|
6
6
|
const CLOSE_TAG = /<\/|DSML|(?:tool_calls|invoke|parameter)>/gu;
|
|
7
7
|
const KEEP = 96;
|
|
8
|
-
const SCAN_BUFFER_SAFE = 64;
|
|
9
8
|
|
|
10
9
|
export const name = '@goodandready/dsh-dsml-artifact-guard';
|
|
11
10
|
export const inject = ['llm', 'settings', 'webServer'];
|
|
@@ -68,10 +67,22 @@ export async function* sanitizeDsmlArtifacts(s, { mode = 'sanitize', onArtifact
|
|
|
68
67
|
p += c.text;
|
|
69
68
|
|
|
70
69
|
scanBuffer += c.text;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
const lastOpen = scanBuffer.lastIndexOf('<');
|
|
71
|
+
const lastClose = scanBuffer.lastIndexOf('>');
|
|
72
|
+
if (lastOpen > lastClose) {
|
|
73
|
+
if (lastOpen > 0) {
|
|
74
|
+
const safe = scanBuffer.slice(0, lastOpen);
|
|
75
|
+
scanBuffer = scanBuffer.slice(lastOpen);
|
|
76
|
+
countTags(safe);
|
|
77
|
+
}
|
|
78
|
+
if (scanBuffer.length > 2048) {
|
|
79
|
+
const cut = scanBuffer.length - 1024;
|
|
80
|
+
countTags(scanBuffer.slice(0, cut));
|
|
81
|
+
scanBuffer = scanBuffer.slice(cut);
|
|
82
|
+
}
|
|
83
|
+
} else if (scanBuffer.length > 0) {
|
|
84
|
+
countTags(scanBuffer);
|
|
85
|
+
scanBuffer = '';
|
|
75
86
|
}
|
|
76
87
|
|
|
77
88
|
if (p.length > KEEP) {
|
package/lib/updater.js
CHANGED
|
@@ -4,6 +4,7 @@ import { readFile } from 'node:fs/promises';
|
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { basename, dirname, isAbsolute, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { checkRequestMethod } from './index.js';
|
|
7
8
|
|
|
8
9
|
const UPDATE_HEADER = 'x-dsh-plugin-update';
|
|
9
10
|
const UPDATE_TIMEOUT_MS = 10 * 60000;
|
|
@@ -24,7 +25,6 @@ export function isLoopback(value) {
|
|
|
24
25
|
|
|
25
26
|
export function isTrustedUpdateRequest(request) {
|
|
26
27
|
if (header(request, UPDATE_HEADER) !== '1') return false;
|
|
27
|
-
if (!isLoopback(request.socket?.remoteAddress)) return false;
|
|
28
28
|
const site = header(request, 'sec-fetch-site');
|
|
29
29
|
if (site !== undefined && site !== 'same-origin') return false;
|
|
30
30
|
const origin = header(request, 'origin');
|
|
@@ -32,8 +32,12 @@ export function isTrustedUpdateRequest(request) {
|
|
|
32
32
|
if (origin === undefined || host === undefined) return false;
|
|
33
33
|
try {
|
|
34
34
|
const url = new URL(origin);
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') return false;
|
|
36
|
+
if (url.host.toLowerCase() !== host.toLowerCase()) return false;
|
|
37
|
+
if (isLoopback(url.hostname)) {
|
|
38
|
+
return isLoopback(request.socket?.remoteAddress);
|
|
39
|
+
}
|
|
40
|
+
return site === 'same-origin';
|
|
37
41
|
} catch {
|
|
38
42
|
return false;
|
|
39
43
|
}
|
|
@@ -218,7 +222,7 @@ export function registerPluginUpdater(ctx, options) {
|
|
|
218
222
|
res.end(req.method === 'HEAD' ? undefined : JSON.stringify(payload));
|
|
219
223
|
return;
|
|
220
224
|
}
|
|
221
|
-
if (req
|
|
225
|
+
if (!checkRequestMethod(req, 'POST')) {
|
|
222
226
|
res.writeHead(405, { allow: 'GET, HEAD, POST' });
|
|
223
227
|
res.end();
|
|
224
228
|
return;
|