@linxin666/dsh-pet 0.1.7 → 0.1.9
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/README.md +4 -4
- package/lib/client.js +56 -18
- package/lib/client.js.map +1 -1
- package/lib/types/client/PetDockEntry.d.ts +10 -7
- package/lib/types/client/PetDockEntry.d.ts.map +1 -1
- package/lib/types/client/PetDockEntry.js +14 -5
- package/lib/types/client/WhalePet.d.ts.map +1 -1
- package/lib/types/client/WhalePet.js +10 -3
- package/lib/types/client/index.d.ts +11 -11
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +30 -27
- package/lib/types/client/locales.d.ts +16 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +27 -0
- package/package.json +1 -1
- package/src/client/PetDockEntry.tsx +17 -9
- package/src/client/WhalePet.tsx +13 -3
- package/src/client/index.ts +30 -28
- package/src/client/locales.ts +29 -0
- package/src/client/pet.module.css +14 -0
package/README.md
CHANGED
|
@@ -47,8 +47,8 @@ dsh-pet/
|
|
|
47
47
|
| |-- persist.ts # 持久化($DSH_HOME/pet.json,原子写入)
|
|
48
48
|
| |-- routes.ts # /api/pet/* JSON API + /pet/whale/* 素材静态路由
|
|
49
49
|
| `-- client/ # 浏览器半区
|
|
50
|
-
| |-- index.ts #
|
|
51
|
-
| |-- PetDockEntry.tsx #
|
|
50
|
+
| |-- index.ts # 全局挂载(createRoot → body)+ 轮询(800ms)+ 交互接线(fetch)
|
|
51
|
+
| |-- PetDockEntry.tsx # 全局浮层入口(document.body,无会话/新会话/会话中全程显示)
|
|
52
52
|
| |-- WhalePet.tsx # 浮层组件(portal + rAF 帧动画 + 拖动)
|
|
53
53
|
| |-- spritesheet.ts # 图集几何 + 每状态动画轨道(帧/时长)
|
|
54
54
|
| `-- pet.module.css
|
|
@@ -61,13 +61,13 @@ dsh-pet/
|
|
|
61
61
|
```
|
|
62
62
|
activity/status session 事件(原 working-activity 插件发布) --> PetService(host)
|
|
63
63
|
| /api/pet/* JSON
|
|
64
|
-
|
|
64
|
+
global React root(createRoot → document.body) <-- 轮询 800ms -- pet-client(浏览器)
|
|
65
65
|
|
|
|
66
66
|
WhalePet 浮层(portal + rAF)
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
- **状态源**:监听 `activity/status` 会话事件(phase: idle/waiting/thinking/tool/done + 状态短语),由 host 半区消费;该事件曾由 working-activity 插件发布,插件已从本仓库移除,未安装时宠物只随会话生命周期变化。
|
|
70
|
-
- **挂载点**:`
|
|
70
|
+
- **挂载点**:`document.body`(全局 React root,无会话/新会话/会话中全程显示——旧挂载点 `conversation.composer.dock` 只在活跃会话渲染,导致新会话界面看不到宠物),组件内部 `createPortal` 渲染全局浮层。
|
|
71
71
|
- **渲染**:CSS sprite(background-position)逐帧动画,帧时长来自 `spritesheet.ts` 的轨道定义。
|
|
72
72
|
- **通信**:浏览器 ↔ host 走同源 `/api/pet/*` JSON 端点(state/interact/set-visible/set-config),图集从 `/pet/whale/spritesheet.webp` 加载——RPC 域与 `/plugins/` 静态服务都是平台注册的,插件自足地提供自己的 API 与素材(与 dsh-remote-web-ui 的 `/api/pair` 同一模式)。
|
|
73
73
|
|
package/lib/client.js
CHANGED
|
@@ -4,8 +4,9 @@ window.__ModuleLoader__.load({
|
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
-
let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
|
|
8
7
|
let react = require("react");
|
|
8
|
+
let react_dom_client = require("react-dom/client");
|
|
9
|
+
let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
|
|
9
10
|
let react_dom = require("react-dom");
|
|
10
11
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
11
12
|
//#region src/client/pet-store.ts
|
|
@@ -304,7 +305,7 @@ window.__ModuleLoader__.load({
|
|
|
304
305
|
}
|
|
305
306
|
//#endregion
|
|
306
307
|
//#region \0dsh-css:/home/runner/work/dsh-web-ui/dsh-web-ui/packages/dsh-pet/src/client/pet.module.css.mjs
|
|
307
|
-
const css$1 = ".l0P8iq_float{pointer-events:auto;-webkit-user-select:none;user-select:none;flex-direction:column;align-items:center;display:flex;position:fixed}.l0P8iq_sprite{image-rendering:auto;touch-action:none;position:relative}.l0P8iq_bubble{white-space:nowrap;color:#fff;pointer-events:none;border-radius:999px;margin-bottom:6px;padding:4px 10px;font-size:12px;line-height:1.4;animation:2.6s ease-out forwards l0P8iq_pet-bubble-pop;position:absolute;bottom:100%;box-shadow:0 2px 8px #00000040}.l0P8iq_bubblePet{background:#f472b6eb}.l0P8iq_bubbleFeed{background:#38bdf8eb}@keyframes l0P8iq_pet-bubble-pop{0%{opacity:0;transform:translateY(6px)scale(.85)}15%{opacity:1;transform:translateY(0)scale(1.05)}25%{transform:translateY(0)scale(1)}75%{opacity:1}to{opacity:0;transform:translateY(-8px)scale(.95)}}.l0P8iq_panel{color:#e2e8f0;backdrop-filter:blur(6px);background:#0f172aeb;border:1px solid #94a3b859;border-radius:10px;flex-direction:column;gap:6px;min-width:132px;padding:8px 10px;font-size:12px;display:flex;position:absolute;bottom:100%;box-shadow:0 4px 16px #00000059}.l0P8iq_rankRow{white-space:nowrap;justify-content:space-between;gap:10px;display:flex}.l0P8iq_nameCell{font-weight:600}.l0P8iq_renameRow{align-items:center;gap:6px;display:flex}.l0P8iq_nameInput{color:#e2e8f0;background:#1e293be6;border:1px solid #7dd3fc80;border-radius:6px;outline:none;flex:1;min-width:0;padding:3px 6px;font-size:12px}.l0P8iq_nameInput:focus{border-color:#38bdf8;box-shadow:0 0 0 2px #38bdf873}.l0P8iq_actions{gap:6px;display:flex}.l0P8iq_action{cursor:pointer;color:#0f172a;background:linear-gradient(#7dd3fc,#38bdf8);border:none;border-radius:6px;flex:1;padding:4px 8px;font-size:12px;transition:filter .12s,box-shadow .12s}.l0P8iq_action:hover{filter:brightness(1.08)}.l0P8iq_action:active{filter:brightness(.94)}.l0P8iq_action:focus-visible{outline:none;box-shadow:0 0 0 2px #38bdf8d9}.l0P8iq_summon{color:#7dd3fc;cursor:pointer;background:#0f172abf;border:1px dashed #7dd3fc99;border-radius:999px;padding:2px 10px;font-size:11px;transition:border-color .12s,color .12s,background .12s,box-shadow .12s}.l0P8iq_summon:hover{color:#bae6fd;background:#0f172ae6;border-color:#7dd3fcf2}.l0P8iq_summon:active{color:#7dd3fc;border-color:#7dd3fccc}.l0P8iq_summon:focus-visible{outline:none;box-shadow:0 0 0 2px #38bdf8d9}@media (prefers-reduced-motion:reduce){.l0P8iq_bubble{opacity:1;animation:none}.l0P8iq_action,.l0P8iq_summon{transition:none}}";
|
|
308
|
+
const css$1 = ".l0P8iq_float{pointer-events:auto;-webkit-user-select:none;user-select:none;flex-direction:column;align-items:center;display:flex;position:fixed}.l0P8iq_sprite{image-rendering:auto;touch-action:none;position:relative}.l0P8iq_bubble{white-space:nowrap;color:#fff;pointer-events:none;border-radius:999px;margin-bottom:6px;padding:4px 10px;font-size:12px;line-height:1.4;animation:2.6s ease-out forwards l0P8iq_pet-bubble-pop;position:absolute;bottom:100%;box-shadow:0 2px 8px #00000040}.l0P8iq_bubblePet{background:#f472b6eb}.l0P8iq_bubbleFeed{background:#38bdf8eb}@keyframes l0P8iq_pet-bubble-pop{0%{opacity:0;transform:translateY(6px)scale(.85)}15%{opacity:1;transform:translateY(0)scale(1.05)}25%{transform:translateY(0)scale(1)}75%{opacity:1}to{opacity:0;transform:translateY(-8px)scale(.95)}}.l0P8iq_panel{color:#e2e8f0;backdrop-filter:blur(6px);background:#0f172aeb;border:1px solid #94a3b859;border-radius:10px;flex-direction:column;gap:6px;min-width:132px;padding:8px 10px;font-size:12px;display:flex;position:absolute;bottom:100%;box-shadow:0 4px 16px #00000059}.l0P8iq_panel:after{content:\"\";height:14px;position:absolute;top:100%;left:0;right:0}.l0P8iq_rankRow{white-space:nowrap;justify-content:space-between;gap:10px;display:flex}.l0P8iq_nameCell{font-weight:600}.l0P8iq_renameRow{align-items:center;gap:6px;display:flex}.l0P8iq_nameInput{color:#e2e8f0;background:#1e293be6;border:1px solid #7dd3fc80;border-radius:6px;outline:none;flex:1;min-width:0;padding:3px 6px;font-size:12px}.l0P8iq_nameInput:focus{border-color:#38bdf8;box-shadow:0 0 0 2px #38bdf873}.l0P8iq_actions{gap:6px;display:flex}.l0P8iq_action{cursor:pointer;color:#0f172a;background:linear-gradient(#7dd3fc,#38bdf8);border:none;border-radius:6px;flex:1;padding:4px 8px;font-size:12px;transition:filter .12s,box-shadow .12s}.l0P8iq_action:hover{filter:brightness(1.08)}.l0P8iq_action:active{filter:brightness(.94)}.l0P8iq_action:focus-visible{outline:none;box-shadow:0 0 0 2px #38bdf8d9}.l0P8iq_summon{color:#7dd3fc;cursor:pointer;background:#0f172abf;border:1px dashed #7dd3fc99;border-radius:999px;padding:2px 10px;font-size:11px;transition:border-color .12s,color .12s,background .12s,box-shadow .12s}.l0P8iq_summon:hover{color:#bae6fd;background:#0f172ae6;border-color:#7dd3fcf2}.l0P8iq_summon:active{color:#7dd3fc;border-color:#7dd3fccc}.l0P8iq_summon:focus-visible{outline:none;box-shadow:0 0 0 2px #38bdf8d9}@media (prefers-reduced-motion:reduce){.l0P8iq_bubble{opacity:1;animation:none}.l0P8iq_action,.l0P8iq_summon{transition:none}}";
|
|
308
309
|
const tagId$1 = "@linxin666/dsh-pet/pet.module.css";
|
|
309
310
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
310
311
|
const tag = document.createElement("style");
|
|
@@ -502,7 +503,7 @@ window.__ModuleLoader__.load({
|
|
|
502
503
|
const next = e.relatedTarget;
|
|
503
504
|
if (next instanceof Node && floatRef.current?.contains(next)) return;
|
|
504
505
|
clearHideTimer();
|
|
505
|
-
hideTimerRef.current = window.setTimeout(() => setHovered(false),
|
|
506
|
+
hideTimerRef.current = window.setTimeout(() => setHovered(false), 300);
|
|
506
507
|
},
|
|
507
508
|
children: [
|
|
508
509
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -533,6 +534,9 @@ window.__ModuleLoader__.load({
|
|
|
533
534
|
}, feedback.at),
|
|
534
535
|
hovered && dragRef.current === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
535
536
|
className: pet_module_css_default.panel,
|
|
537
|
+
onPointerEnter: () => {
|
|
538
|
+
clearHideTimer();
|
|
539
|
+
},
|
|
536
540
|
children: renaming ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
537
541
|
className: pet_module_css_default.renameRow,
|
|
538
542
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
@@ -609,10 +613,13 @@ window.__ModuleLoader__.load({
|
|
|
609
613
|
//#endregion
|
|
610
614
|
//#region src/client/PetDockEntry.tsx
|
|
611
615
|
/**
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
+
* Global floating pet entry. The pet is host-global (its state, display and
|
|
617
|
+
* interactions live on `/api/pet/*` endpoints with no session dimension), so
|
|
618
|
+
* it must not ride a session-scoped slot — on the new-conversation screen no
|
|
619
|
+
* session exists to scope a slot by, and the pet would vanish (issue #48).
|
|
620
|
+
* The client half therefore mounts this entry straight onto `document.body`
|
|
621
|
+
* (see index.ts): while visible it renders the floating WhalePet (a portal),
|
|
622
|
+
* while hidden it renders a fixed-position summon button.
|
|
616
623
|
* @module @linxin666/dsh-pet/client/PetDockEntry
|
|
617
624
|
*/
|
|
618
625
|
const DEFAULT_DISPLAY = {
|
|
@@ -653,9 +660,16 @@ window.__ModuleLoader__.load({
|
|
|
653
660
|
t: props.t
|
|
654
661
|
})
|
|
655
662
|
});
|
|
663
|
+
const display = snapshot?.display ?? DEFAULT_DISPLAY;
|
|
656
664
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
657
665
|
type: "button",
|
|
658
666
|
className: pet_module_css_default.summon,
|
|
667
|
+
style: {
|
|
668
|
+
position: "fixed",
|
|
669
|
+
right: display.right,
|
|
670
|
+
bottom: display.bottom,
|
|
671
|
+
zIndex: 2147483e3
|
|
672
|
+
},
|
|
659
673
|
onClick: props.summon,
|
|
660
674
|
"data-testid": "pet-summon",
|
|
661
675
|
children: props.t("pet.summon", { name: snapshot?.name ?? "鲸鱼娘" })
|
|
@@ -1353,6 +1367,28 @@ window.__ModuleLoader__.load({
|
|
|
1353
1367
|
"settings.saveFailed": "The deployment did not accept these values; they were left for you to correct.",
|
|
1354
1368
|
"settings.invalidNumber": "Enter a number, or leave blank to use the default."
|
|
1355
1369
|
};
|
|
1370
|
+
/**
|
|
1371
|
+
* Active dictionary, picked by the document language at call time. The pet
|
|
1372
|
+
* mounts as a global floating surface (not a session-scoped slot), so it has
|
|
1373
|
+
* no framework locale seat and resolves its copy the same tiny way the
|
|
1374
|
+
* task-board's DOM-injected surface does.
|
|
1375
|
+
*/
|
|
1376
|
+
function dictionary() {
|
|
1377
|
+
return (typeof document !== "undefined" ? document.documentElement.lang : "zh").toLowerCase().startsWith("en") ? en : zh;
|
|
1378
|
+
}
|
|
1379
|
+
/**
|
|
1380
|
+
* Translate a key with optional `{name}` template params. Mirrors the slot
|
|
1381
|
+
* `Translate` contract `(key, params?) => string` so it can be handed to the
|
|
1382
|
+
* same components that used to receive the framework-injected `t` seat. The
|
|
1383
|
+
* key is typed loosely (`string`) so the function is assignable to the slot's
|
|
1384
|
+
* `TranslateNS<'pet'>` (whose key domain also spans the shared common
|
|
1385
|
+
* vocabulary); a missing key degrades to the key itself rather than throwing.
|
|
1386
|
+
*/
|
|
1387
|
+
function t(key, params) {
|
|
1388
|
+
let text = dictionary()[key] ?? key;
|
|
1389
|
+
if (params !== void 0) for (const [name, value] of Object.entries(params)) text = text.replaceAll(`{${name}}`, String(value));
|
|
1390
|
+
return text;
|
|
1391
|
+
}
|
|
1356
1392
|
//#endregion
|
|
1357
1393
|
//#region src/client/index.ts
|
|
1358
1394
|
/** Same-origin JSON fetch helper (GET without body, POST with JSON body). */
|
|
@@ -1386,9 +1422,9 @@ window.__ModuleLoader__.load({
|
|
|
1386
1422
|
"remote"
|
|
1387
1423
|
];
|
|
1388
1424
|
/**
|
|
1389
|
-
* Client plugin body: register dictionaries, mount the
|
|
1390
|
-
* loop while the plugin is enabled, and seat the settings card in the
|
|
1391
|
-
* plugin group.
|
|
1425
|
+
* Client plugin body: register dictionaries, mount the global pet entry and
|
|
1426
|
+
* poll loop while the plugin is enabled, and seat the settings card in the
|
|
1427
|
+
* Web UI plugin group.
|
|
1392
1428
|
* @param ctx - client root context.
|
|
1393
1429
|
*/
|
|
1394
1430
|
function apply(ctx) {
|
|
@@ -1495,15 +1531,17 @@ window.__ModuleLoader__.load({
|
|
|
1495
1531
|
setFeedback(null);
|
|
1496
1532
|
}
|
|
1497
1533
|
});
|
|
1498
|
-
const
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1534
|
+
const container = document.createElement("div");
|
|
1535
|
+
container.dataset.dshPetRoot = "";
|
|
1536
|
+
document.body.appendChild(container);
|
|
1537
|
+
const petRoot = (0, react_dom_client.createRoot)(container);
|
|
1538
|
+
petRoot.render((0, react.createElement)(PetDockEntry, {
|
|
1539
|
+
...injected(),
|
|
1540
|
+
t
|
|
1541
|
+
}));
|
|
1505
1542
|
disposeUi = () => {
|
|
1506
|
-
|
|
1543
|
+
petRoot.unmount();
|
|
1544
|
+
container.remove();
|
|
1507
1545
|
disposePoll();
|
|
1508
1546
|
disposeUi = void 0;
|
|
1509
1547
|
};
|