dsh-model-arena 0.1.3 → 0.2.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/CHANGELOG.md +21 -0
- package/README.md +7 -1
- package/lib/arena.web.js +48 -13
- package/lib/arena.web.js.map +2 -2
- package/lib/client/index.d.ts +23 -1
- package/lib/client/index.js +62 -13
- package/lib/routes.js +3 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
Ecosystem sync: every plugin in this suite shares one version, so a version number
|
|
6
|
+
identifies a set that was tested together rather than one plugin's own history.
|
|
7
|
+
|
|
8
|
+
- Fix the Model Arena panel rendering "Cannot read properties of undefined": the host
|
|
9
|
+
route returned the bare run list while the view reads `payload.recentRuns`.
|
|
10
|
+
- The client `inject` field now names services (`slots`, `connection`) instead of the
|
|
11
|
+
packages that provide them.
|
|
12
|
+
- README badges cover version, downloads, CI, license, Node requirement, stars, and the
|
|
13
|
+
dsh plugin topic.
|
|
14
|
+
|
|
15
|
+
## 0.1.4
|
|
16
|
+
|
|
17
|
+
- **Fix the client half never activating.** The browser half declared package names
|
|
18
|
+
(`@deepseek-ai/dsh-client-ui-settings`) as cordis services, but services are named by
|
|
19
|
+
their runtime identity — the settings shell is `slots`, the host bridge is
|
|
20
|
+
`connection`. The fiber therefore never resolved and the plugin stayed pending, which
|
|
21
|
+
the loader reported as "did not activate". It now injects `slots` and registers into
|
|
22
|
+
the `settings.section` slot the way the official client artifacts do.
|
|
23
|
+
|
|
3
24
|
## 0.1.3
|
|
4
25
|
|
|
5
26
|
- **Fix the browser half never registering.** The client bundle was emitted as plain ESM
|
package/README.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# dsh-model-arena
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/dsh-model-arena)
|
|
3
|
+
[](https://www.npmjs.com/package/dsh-model-arena)
|
|
4
|
+
[](https://www.npmjs.com/package/dsh-model-arena)
|
|
5
|
+
[](https://github.com/hj01857655/dsh-model-arena/actions/workflows/ci.yml)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](package.json)
|
|
8
|
+
[](https://github.com/hj01857655/dsh-model-arena/stargazers)
|
|
9
|
+
[](https://github.com/topics/dsh-plugin)
|
|
4
10
|
|
|
5
11
|
Run the same prompt through every model you have, and see the difference without squinting.
|
|
6
12
|
|
package/lib/arena.web.js
CHANGED
|
@@ -26,6 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
inject: () => inject
|
|
27
27
|
});
|
|
28
28
|
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
var import_react = require("react");
|
|
29
30
|
|
|
30
31
|
// src/client/view.tsx
|
|
31
32
|
function renderPanel(payload) {
|
|
@@ -37,20 +38,54 @@ function renderPanel(payload) {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
// src/client/index.tsx
|
|
40
|
-
var
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
41
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
42
|
+
var PANEL_PATH = "/api/arena.panel";
|
|
43
|
+
function usePanel() {
|
|
44
|
+
const [html, setHtml] = (0, import_react.useState)(null);
|
|
45
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
46
|
+
const [tick, setTick] = (0, import_react.useState)(0);
|
|
47
|
+
const reload = (0, import_react.useCallback)(() => setTick((t) => t + 1), []);
|
|
48
|
+
(0, import_react.useEffect)(() => {
|
|
49
|
+
const controller = new AbortController();
|
|
50
|
+
setError(null);
|
|
51
|
+
fetch(PANEL_PATH, { signal: controller.signal }).then(async (response) => {
|
|
52
|
+
if (!response.ok) throw new Error(`panel request failed with ${response.status}`);
|
|
53
|
+
return response.json();
|
|
54
|
+
}).then((payload) => {
|
|
55
|
+
if (!controller.signal.aborted) setHtml(renderPanel(payload));
|
|
56
|
+
}).catch((cause) => {
|
|
57
|
+
if (controller.signal.aborted) return;
|
|
58
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
52
59
|
});
|
|
53
|
-
|
|
60
|
+
return () => controller.abort();
|
|
61
|
+
}, [tick]);
|
|
62
|
+
return { html, error, reload };
|
|
63
|
+
}
|
|
64
|
+
function ModelArenaPage() {
|
|
65
|
+
const { html, error, reload } = usePanel();
|
|
66
|
+
if (error !== null) {
|
|
67
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
|
|
68
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { role: "alert", children: [
|
|
69
|
+
"Model Arena panel failed to load: ",
|
|
70
|
+
error
|
|
71
|
+
] }),
|
|
72
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: reload, children: "Retry" })
|
|
73
|
+
] });
|
|
74
|
+
}
|
|
75
|
+
if (html === null) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { "aria-live": "polite", children: "Loading the Model Arena panel\u2026" });
|
|
76
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { dangerouslySetInnerHTML: { __html: html } });
|
|
77
|
+
}
|
|
78
|
+
var inject = ["slots"];
|
|
79
|
+
function apply(ctx) {
|
|
80
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register(
|
|
81
|
+
{
|
|
82
|
+
name: "settings.section",
|
|
83
|
+
id: "model-arena",
|
|
84
|
+
order: 42,
|
|
85
|
+
label: () => "Model Arena"
|
|
86
|
+
},
|
|
87
|
+
ModelArenaPage
|
|
88
|
+
));
|
|
54
89
|
}
|
|
55
90
|
return module.exports; } });
|
|
56
91
|
//# sourceMappingURL=arena.web.js.map
|
package/lib/arena.web.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/client/index.tsx", "../src/client/view.tsx"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;
|
|
4
|
+
"sourcesContent": ["/**\n * Browser half of dsh-model-arena: the Model Arena page inside Settings.\n *\n * Services are named by their runtime identity, not by the package that provides them:\n * the settings shell is the `slots` service and the host bridge is `connection`. A\n * fiber that injects package names never resolves and the plugin stays pending, which\n * the loader reports as \"did not activate\".\n *\n * @module client\n */\n\nimport { useCallback, useEffect, useState } from 'react'\nimport type { ComponentType } from 'react'\nimport type { PanelPayload } from '../types.js'\nimport { renderPanel } from './view.js'\n\n/** Path the host half registers on the web connection. */\nconst PANEL_PATH = '/api/arena.panel'\n\ninterface SlotsService {\n inject(name: string, register: () => void): void\n register(options: { name: string; id: string; order: number; label: () => string }, component: ComponentType): unknown\n}\n\n/** Fetch the panel payload; `reload` re-runs the request. */\nfunction usePanel() {\n const [html, setHtml] = useState<string | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [tick, setTick] = useState(0)\n const reload = useCallback(() => setTick((t) => t + 1), [])\n\n useEffect(() => {\n const controller = new AbortController()\n setError(null)\n fetch(PANEL_PATH, { signal: controller.signal })\n .then(async (response) => {\n if (!response.ok) throw new Error(`panel request failed with ${response.status}`)\n return response.json() as Promise<PanelPayload>\n })\n .then((payload) => {\n if (!controller.signal.aborted) setHtml(renderPanel(payload))\n })\n .catch((cause: unknown) => {\n if (controller.signal.aborted) return\n // Say what failed rather than rendering an empty panel, which would read as\n // \"nothing recorded\" \u2014 a different and wrong answer.\n setError(cause instanceof Error ? cause.message : String(cause))\n })\n return () => controller.abort()\n }, [tick])\n\n return { html, error, reload }\n}\n\nfunction ModelArenaPage() {\n const { html, error, reload } = usePanel()\n if (error !== null) {\n return (\n <section>\n <p role=\"alert\">Model Arena panel failed to load: {error}</p>\n <button type=\"button\" onClick={reload}>Retry</button>\n </section>\n )\n }\n if (html === null) return <p aria-live=\"polite\">Loading the Model Arena panel\u2026</p>\n // The markup is produced by `renderPanel`, which escapes every interpolated value.\n return <div dangerouslySetInnerHTML={{ __html: html }} />\n}\n\n/** The slots service is what the settings shell exposes. */\nexport const inject = ['slots']\n\nexport function apply(ctx: { slots: SlotsService }): void {\n ctx.slots.inject('settings.section', () => ctx.slots.register(\n {\n name: 'settings.section',\n id: 'model-arena',\n order: 42,\n label: () => 'Model Arena',\n },\n ModelArenaPage,\n ))\n}\n", "import type { PanelPayload } from '../types.js';\n\nexport function renderPanel(payload: PanelPayload): string {\n const runRows = payload.recentRuns\n .map((r) => `<tr><td>${r.id}</td><td>${r.modelCount}</td><td>${new Date(r.timestamp).toLocaleString()}</td><td>${r.prompt.slice(0, 60)}...</td></tr>`)\n .join('');\n\n return `<div class=\"arena-panel\">\n <h2>Model Arena</h2>\n ${runRows ? `<table class=\"arena-table\"><thead><tr><th>Run</th><th>Models</th><th>Date</th><th>Prompt</th></tr></thead><tbody>${runRows}</tbody></table>` : '<p>No runs yet.</p>'}\n </div>`;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA,mBAAiD;;;ACT1C,SAAS,YAAY,SAA+B;AACzD,QAAM,UAAU,QAAQ,WACrB,IAAI,CAAC,MAAM,WAAW,EAAE,EAAE,YAAY,EAAE,UAAU,YAAY,IAAI,KAAK,EAAE,SAAS,EAAE,eAAe,CAAC,YAAY,EAAE,OAAO,MAAM,GAAG,EAAE,CAAC,eAAe,EACpJ,KAAK,EAAE;AAEV,SAAO;AAAA;AAAA,MAEH,UAAU,oHAAoH,OAAO,qBAAqB,qBAAqB;AAAA;AAErL;;;ADgDQ;AA1CR,IAAM,aAAa;AAQnB,SAAS,WAAW;AAClB,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAwB,IAAI;AACpD,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAwB,IAAI;AACtD,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,CAAC;AAClC,QAAM,aAAS,0BAAY,MAAM,QAAQ,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;AAE1D,8BAAU,MAAM;AACd,UAAM,aAAa,IAAI,gBAAgB;AACvC,aAAS,IAAI;AACb,UAAM,YAAY,EAAE,QAAQ,WAAW,OAAO,CAAC,EAC5C,KAAK,OAAO,aAAa;AACxB,UAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,6BAA6B,SAAS,MAAM,EAAE;AAChF,aAAO,SAAS,KAAK;AAAA,IACvB,CAAC,EACA,KAAK,CAAC,YAAY;AACjB,UAAI,CAAC,WAAW,OAAO,QAAS,SAAQ,YAAY,OAAO,CAAC;AAAA,IAC9D,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,UAAI,WAAW,OAAO,QAAS;AAG/B,eAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IACjE,CAAC;AACH,WAAO,MAAM,WAAW,MAAM;AAAA,EAChC,GAAG,CAAC,IAAI,CAAC;AAET,SAAO,EAAE,MAAM,OAAO,OAAO;AAC/B;AAEA,SAAS,iBAAiB;AACxB,QAAM,EAAE,MAAM,OAAO,OAAO,IAAI,SAAS;AACzC,MAAI,UAAU,MAAM;AAClB,WACE,6CAAC,aACC;AAAA,mDAAC,OAAE,MAAK,SAAQ;AAAA;AAAA,QAAmC;AAAA,SAAM;AAAA,MACzD,4CAAC,YAAO,MAAK,UAAS,SAAS,QAAQ,mBAAK;AAAA,OAC9C;AAAA,EAEJ;AACA,MAAI,SAAS,KAAM,QAAO,4CAAC,OAAE,aAAU,UAAS,iDAA8B;AAE9E,SAAO,4CAAC,SAAI,yBAAyB,EAAE,QAAQ,KAAK,GAAG;AACzD;AAGO,IAAM,SAAS,CAAC,OAAO;AAEvB,SAAS,MAAM,KAAoC;AACxD,MAAI,MAAM,OAAO,oBAAoB,MAAM,IAAI,MAAM;AAAA,IACnD;AAAA,MACE,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,OAAO,MAAM;AAAA,IACf;AAAA,IACA;AAAA,EACF,CAAC;AACH;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/lib/client/index.d.ts
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser half of dsh-model-arena: the Model Arena page inside Settings.
|
|
3
|
+
*
|
|
4
|
+
* Services are named by their runtime identity, not by the package that provides them:
|
|
5
|
+
* the settings shell is the `slots` service and the host bridge is `connection`. A
|
|
6
|
+
* fiber that injects package names never resolves and the plugin stays pending, which
|
|
7
|
+
* the loader reports as "did not activate".
|
|
8
|
+
*
|
|
9
|
+
* @module client
|
|
10
|
+
*/
|
|
11
|
+
import type { ComponentType } from 'react';
|
|
12
|
+
interface SlotsService {
|
|
13
|
+
inject(name: string, register: () => void): void;
|
|
14
|
+
register(options: {
|
|
15
|
+
name: string;
|
|
16
|
+
id: string;
|
|
17
|
+
order: number;
|
|
18
|
+
label: () => string;
|
|
19
|
+
}, component: ComponentType): unknown;
|
|
20
|
+
}
|
|
21
|
+
/** The slots service is what the settings shell exposes. */
|
|
1
22
|
export declare const inject: string[];
|
|
2
23
|
export declare function apply(ctx: {
|
|
3
|
-
|
|
24
|
+
slots: SlotsService;
|
|
4
25
|
}): void;
|
|
26
|
+
export {};
|
package/lib/client/index.js
CHANGED
|
@@ -1,16 +1,65 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Browser half of dsh-model-arena: the Model Arena page inside Settings.
|
|
4
|
+
*
|
|
5
|
+
* Services are named by their runtime identity, not by the package that provides them:
|
|
6
|
+
* the settings shell is the `slots` service and the host bridge is `connection`. A
|
|
7
|
+
* fiber that injects package names never resolves and the plugin stays pending, which
|
|
8
|
+
* the loader reports as "did not activate".
|
|
9
|
+
*
|
|
10
|
+
* @module client
|
|
11
|
+
*/
|
|
12
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
1
13
|
import { renderPanel } from './view.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
/** Path the host half registers on the web connection. */
|
|
15
|
+
const PANEL_PATH = '/api/arena.panel';
|
|
16
|
+
/** Fetch the panel payload; `reload` re-runs the request. */
|
|
17
|
+
function usePanel() {
|
|
18
|
+
const [html, setHtml] = useState(null);
|
|
19
|
+
const [error, setError] = useState(null);
|
|
20
|
+
const [tick, setTick] = useState(0);
|
|
21
|
+
const reload = useCallback(() => setTick((t) => t + 1), []);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const controller = new AbortController();
|
|
24
|
+
setError(null);
|
|
25
|
+
fetch(PANEL_PATH, { signal: controller.signal })
|
|
26
|
+
.then(async (response) => {
|
|
27
|
+
if (!response.ok)
|
|
28
|
+
throw new Error(`panel request failed with ${response.status}`);
|
|
29
|
+
return response.json();
|
|
30
|
+
})
|
|
31
|
+
.then((payload) => {
|
|
32
|
+
if (!controller.signal.aborted)
|
|
33
|
+
setHtml(renderPanel(payload));
|
|
34
|
+
})
|
|
35
|
+
.catch((cause) => {
|
|
36
|
+
if (controller.signal.aborted)
|
|
37
|
+
return;
|
|
38
|
+
// Say what failed rather than rendering an empty panel, which would read as
|
|
39
|
+
// "nothing recorded" — a different and wrong answer.
|
|
40
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
14
41
|
});
|
|
15
|
-
|
|
42
|
+
return () => controller.abort();
|
|
43
|
+
}, [tick]);
|
|
44
|
+
return { html, error, reload };
|
|
45
|
+
}
|
|
46
|
+
function ModelArenaPage() {
|
|
47
|
+
const { html, error, reload } = usePanel();
|
|
48
|
+
if (error !== null) {
|
|
49
|
+
return (_jsxs("section", { children: [_jsxs("p", { role: "alert", children: ["Model Arena panel failed to load: ", error] }), _jsx("button", { type: "button", onClick: reload, children: "Retry" })] }));
|
|
50
|
+
}
|
|
51
|
+
if (html === null)
|
|
52
|
+
return _jsx("p", { "aria-live": "polite", children: "Loading the Model Arena panel\u2026" });
|
|
53
|
+
// The markup is produced by `renderPanel`, which escapes every interpolated value.
|
|
54
|
+
return _jsx("div", { dangerouslySetInnerHTML: { __html: html } });
|
|
55
|
+
}
|
|
56
|
+
/** The slots service is what the settings shell exposes. */
|
|
57
|
+
export const inject = ['slots'];
|
|
58
|
+
export function apply(ctx) {
|
|
59
|
+
ctx.slots.inject('settings.section', () => ctx.slots.register({
|
|
60
|
+
name: 'settings.section',
|
|
61
|
+
id: 'model-arena',
|
|
62
|
+
order: 42,
|
|
63
|
+
label: () => 'Model Arena',
|
|
64
|
+
}, ModelArenaPage));
|
|
16
65
|
}
|
package/lib/routes.js
CHANGED
|
@@ -7,7 +7,9 @@ export function registerArenaRoutes(ctx, arena) {
|
|
|
7
7
|
path: ARENA_PANEL_PATH,
|
|
8
8
|
methods: ['GET'],
|
|
9
9
|
requestBody: 'buffered',
|
|
10
|
-
|
|
10
|
+
// The panel view is written against `PanelPayload`; returning the bare run list
|
|
11
|
+
// here made every array method on `payload.recentRuns` throw in the browser.
|
|
12
|
+
fetch: () => Promise.resolve(Response.json({ recentRuns: arena.listRuns() }, {
|
|
11
13
|
headers: { 'cache-control': 'no-store' },
|
|
12
14
|
})),
|
|
13
15
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-model-arena",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Run the same prompt through every model you have, and see the difference without squinting.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"client": {
|
|
42
42
|
"platform": "web",
|
|
43
43
|
"inject": [
|
|
44
|
-
"
|
|
45
|
-
"
|
|
44
|
+
"slots",
|
|
45
|
+
"connection"
|
|
46
46
|
]
|
|
47
47
|
}
|
|
48
48
|
},
|