@linxin666/dsh-pet 0.1.18 → 0.1.19
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.i18n.yaml +2 -2
- package/README.md +12 -5
- package/README.zh.md +12 -5
- package/lib/client.js +48 -11
- package/lib/client.js.map +1 -1
- package/lib/index.js +100 -30
- package/lib/invariant.js +2 -2
- package/lib/state-Diiq8vjk.js +394 -0
- package/lib/types/affinity.d.ts +31 -3
- package/lib/types/affinity.d.ts.map +1 -1
- package/lib/types/affinity.js +21 -7
- package/lib/types/client/PetSettingsCard.d.ts +5 -0
- package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PetSettingsCard.js +7 -0
- package/lib/types/client/PetSprite.d.ts.map +1 -1
- package/lib/types/client/PetSprite.js +8 -2
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +14 -8
- package/lib/types/client/settings-form.d.ts +8 -0
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/settings-form.js +15 -1
- package/lib/types/event-projection.d.ts.map +1 -1
- package/lib/types/event-projection.js +3 -1
- package/lib/types/index.d.ts +4 -2
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +2 -1
- package/lib/types/ledger.d.ts +16 -1
- package/lib/types/ledger.d.ts.map +1 -1
- package/lib/types/ledger.js +29 -4
- package/lib/types/registry.d.ts +10 -0
- package/lib/types/registry.d.ts.map +1 -1
- package/lib/types/registry.js +3 -0
- package/lib/types/remarks.d.ts +56 -0
- package/lib/types/remarks.d.ts.map +1 -0
- package/lib/types/remarks.js +157 -0
- package/lib/types/service.d.ts +40 -3
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +90 -18
- package/lib/types/state.js +5 -5
- package/lib/types/treats.d.ts +3 -0
- package/lib/types/treats.d.ts.map +1 -1
- package/lib/types/treats.js +5 -2
- package/package.json +1 -1
- package/src/affinity.test.ts +19 -0
- package/src/affinity.ts +22 -7
- package/src/client/PetSettingsCard.tsx +8 -0
- package/src/client/PetSprite.test.tsx +33 -0
- package/src/client/PetSprite.tsx +16 -1
- package/src/client/index.ts +14 -8
- package/src/client/pet.module.css +19 -0
- package/src/client/settings-form.ts +15 -1
- package/src/event-projection.ts +3 -1
- package/src/index.ts +12 -1
- package/src/ledger.test.ts +40 -9
- package/src/ledger.ts +33 -4
- package/src/persist.test.ts +1 -1
- package/src/registry.test.ts +27 -0
- package/src/registry.ts +12 -0
- package/src/remarks.test.ts +89 -0
- package/src/remarks.ts +177 -0
- package/src/service.ts +116 -18
- package/src/state.test.ts +9 -0
- package/src/state.ts +5 -5
- package/src/treats.test.ts +13 -11
- package/src/treats.ts +5 -2
- package/lib/state-CFyJv0sQ.js +0 -213
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# node scripts/verify-docs.mjs --write <dir>
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 75de064887be4289018547fba722851afd98dd5a
|
|
6
|
+
README.zh.md: 9e396eca9b5a47425aeee972ec7a95a7e7da81ac
|
package/README.md
CHANGED
|
@@ -18,12 +18,13 @@ Re-implemented from the pet feature of the Codex desktop app, as an official DSH
|
|
|
18
18
|
| State animation | Official session activity → 9-state animation: `thinking → running`, `tool → running-right`, `review → review`, `waiting → waiting`, `done → jumping`, `failed → failed` |
|
|
19
19
|
| Head-pat interaction | Click the pet → bubble feedback + affinity +1 (10s cooldown) |
|
|
20
20
|
| Feeding | Hover panel 喂食 (Feed) → consumes 1 dried fish + affinity +5 (30s cooldown) |
|
|
21
|
-
| Treat economy | Dried-fish stock (cap 20): +1 every
|
|
22
|
-
| Affinity | +1 per round completed;
|
|
21
|
+
| Treat economy | Dried-fish stock (cap 20): +1 every 30 rounds of work, +1 every 300 minutes (5 hours) — 10x rarer than the original cadence |
|
|
22
|
+
| Affinity | +1 per round completed; 9 levels: 幼鲸 → 伙伴 → 挚友 → 深海羁绊 → 心有灵犀 → 传说羁绊 → 神话羁绊 → 永恒之契 → 鲸生共渡 (capped at 999,999,999) |
|
|
23
23
|
| Dragging | Hold and drag the pet to reposition; position persisted |
|
|
24
24
|
| Hide/Summon | Hover panel 隐藏 (Hide); after hiding, a 召唤{name} (Summon {name}) button appears |
|
|
25
|
-
|
|
|
26
|
-
|
|
|
25
|
+
| Witty remarks | Built-in remark library (10 lines per event) plus per-pet custom lines from a manifest remarks block — community PRs give their pet its own voice |
|
|
26
|
+
| Status bubbles | Each concurrently active session gets its own bubble, stacked above the pet (up to 12); transient interaction feedback temporarily takes priority |
|
|
27
|
+
| Multi-session activity | The pet is host-global: the most recent meaningful event drives the sprite animation while every active session reports its own state in a separate bubble; completed turns from every session contribute affinity and treats |
|
|
27
28
|
|
|
28
29
|
## Pet contract
|
|
29
30
|
|
|
@@ -40,11 +41,16 @@ A pet is a directory holding one `pet.json` manifest and one atlas image. Nothin
|
|
|
40
41
|
"frames": [6, 8, 8, 4, 5, 8, 6, 6, 6], // optional per-row frame counts
|
|
41
42
|
"tracks": { // optional per-track rhythm overrides
|
|
42
43
|
"idle": { "durations": [400, 400, 500, 400, 400, 500] }
|
|
44
|
+
},
|
|
45
|
+
"remarks": { // optional witty remarks (one line or a pool per slot)
|
|
46
|
+
"pet": "摸摸水獭的头~",
|
|
47
|
+
"feed": ["小鱼干真香", "再来一条~"]
|
|
43
48
|
}
|
|
44
49
|
}
|
|
45
50
|
```
|
|
46
51
|
|
|
47
52
|
- The atlas is an 8-column × 9-row grid (192×208 cells by default); rows are fixed in this order: 0 idle, 1 running-right, 2 running-left, 3 waving, 4 jumping, 5 failed, 6 waiting, 7 running, 8 review. Unused cells stay fully transparent.
|
|
53
|
+
- The optional remarks block overrides the reaction bubbles the pet speaks on pet / petCooldown / feed / feedCooldown / noTreats events. Each slot accepts one line or a pool of lines (cycled round-robin); a declared slot replaces the built-in pool for that slot only. This is how community contributions give their pet its own witty voice.
|
|
48
54
|
- `frames` counts the used columns per row (defaults to the hatch-pet contract table `[6, 8, 8, 4, 5, 8, 6, 6, 6]`); `tracks` overrides per-frame durations (cycled to the row's frame count), `loop`, and `fallback` per animation (defaults: everything loops; `jumping` and `failed` hold their last frame, then fall back to `idle`).
|
|
49
55
|
|
|
50
56
|
Where pets come from (later sources override earlier ones on id collision):
|
|
@@ -76,6 +82,7 @@ dsh-pet/
|
|
|
76
82
|
| |-- registry.ts # multi-pet contract: manifest scan + normalization (assets + custom pets)
|
|
77
83
|
| |-- service.ts # PetService: pet selection + state machine + affinity + config
|
|
78
84
|
| |-- state.ts # pet state machine: projected session activity → 9 state animations
|
|
85
|
+
| |-- remarks.ts # witty-remark library: built-in pools + per-pet overrides + picker
|
|
79
86
|
| |-- affinity.ts # affinity ledger (pure functions + cooldowns)
|
|
80
87
|
| |-- treats.ts # dried-fish stock ledger
|
|
81
88
|
| |-- persist.ts # persistence ($DSH_HOME/pet.json: selection + per-pet names, atomic write)
|
|
@@ -106,7 +113,7 @@ global React root (createRoot → document.body) <-- polling 2s -- pet-client (b
|
|
|
106
113
|
- **Status source**: the host projects official `turn/start`, `step/start`, `assistant/chunk`, `assistant/message`, `tool/call`, `tool/result`, and `turn/end` events into waiting/thinking/tool/review/done/failed states. Optional legacy `activity/status` events remain a compatibility input.
|
|
107
114
|
- **Registry**: the host normalizes every manifest into a full render definition (geometry, per-row frame counts, per-track durations) and serves it over `/api/pet/pets`; the browser half renders any entry from that definition and carries no per-pet code.
|
|
108
115
|
- **Selection & naming**: `petId` lives in the settings namespace; per-pet names live in `pet.json` under `names`, edited through the hover-panel rename of the active pet. Legacy installs migrate their flat `name` onto the whale girl.
|
|
109
|
-
- **Multi-session semantics**: the API and browser mount are host-global and expose no foreground-session identity
|
|
116
|
+
- **Multi-session semantics**: the API and browser mount are host-global and expose no foreground-session identity. Concurrent sessions each keep their own projected state: the most recent meaningful event drives the sprite animation, while every active session reports its stage in its own bubble (the state view's sessions list, capped at 12 most-recent). Every session's completed turns are still rewarded independently; disposing a session removes its bubble, and disposing the display session falls back to the most recent remaining one.
|
|
110
117
|
- **Mount point**: `document.body` (global React root, always shown: no session / new session / mid-session — the old mount point `conversation.composer.dock` only rendered in an active session, hiding the pet in new sessions); the component uses `createPortal` internally to render the global floating layer.
|
|
111
118
|
- **Rendering**: CSS sprite (background-position) per-frame animation; frame durations come from the served definition's tracks.
|
|
112
119
|
- **Communication**: browser ↔ host over the same-origin `/api/pet/*` JSON endpoints (state/pets/interact/set-visible/set-config/set-name/set-pet); each pet's atlas loads from `/pet/<id>/<spritesheetPath>` — the plugin self-sufficiently provides its own API and assets (the same pattern as dsh-remote-web-ui's `/api/pair`).
|
package/README.zh.md
CHANGED
|
@@ -18,12 +18,13 @@
|
|
|
18
18
|
| 状态动画 | 官方会话活动 → 9 态动画:`thinking → running`、`tool → running-right`、`review → review`、`waiting → waiting`、`done → jumping`、`failed → failed` |
|
|
19
19
|
| 摸头互动 | 点击宠物 → 气泡反馈 + 亲密度 +1(10s 冷却) |
|
|
20
20
|
| 喂食 | 悬浮面板 喂食 → 消耗 1 条小鱼干 + 亲密度 +5(30s 冷却) |
|
|
21
|
-
| 小鱼干经济 | 库存(上限 20):每工作
|
|
22
|
-
| 亲密度 | 每完成一轮 +1;
|
|
21
|
+
| 小鱼干经济 | 库存(上限 20):每工作 30 轮 +1,每 300 分钟(5 小时)+1 —— 获取难度为原来的 10 倍 |
|
|
22
|
+
| 亲密度 | 每完成一轮 +1;9 级:幼鲸 → 伙伴 → 挚友 → 深海羁绊 → 心有灵犀 → 传说羁绊 → 神话羁绊 → 永恒之契 → 鲸生共渡(上限 999,999,999) |
|
|
23
23
|
| 拖动 | 按住拖动宠物换位置;位置持久化 |
|
|
24
24
|
| 隐藏/召唤 | 悬浮面板 隐藏;隐藏后出现 召唤{name} 按钮 |
|
|
25
|
-
|
|
|
26
|
-
|
|
|
25
|
+
| 妙语库 | 内置默认妙语库(每类事件 10 句)+ 宠物 manifest 的 remarks 块自定义台词——社区 PR 可以给自家宠物配上专属妙语 |
|
|
26
|
+
| 状态气泡 | 并行会话各自一个气泡,在宠物头顶堆叠(最多 12 个);瞬时互动反馈临时优先 |
|
|
27
|
+
| 多会话活动 | 宠物是宿主全局的:最近一次有意义事件驱动精灵动画,同时每个活动会话用自己的气泡报告各自状态;每个会话完成的轮次都计入亲密度与小鱼干 |
|
|
27
28
|
|
|
28
29
|
## 宠物契约
|
|
29
30
|
|
|
@@ -40,11 +41,16 @@
|
|
|
40
41
|
"frames": [6, 8, 8, 4, 5, 8, 6, 6, 6], // 可选的每行帧数
|
|
41
42
|
"tracks": { // 可选的每轨节奏覆盖
|
|
42
43
|
"idle": { "durations": [400, 400, 500, 400, 400, 500] }
|
|
44
|
+
},
|
|
45
|
+
"remarks": { // 可选妙语(每个槽位一行或多行)
|
|
46
|
+
"pet": "摸摸水獭的头~",
|
|
47
|
+
"feed": ["小鱼干真香", "再来一条~"]
|
|
43
48
|
}
|
|
44
49
|
}
|
|
45
50
|
```
|
|
46
51
|
|
|
47
52
|
- 图集是 8 列 × 9 行网格(默认 192×208 单元格);行序固定:0 idle、1 running-right、2 running-left、3 waving、4 jumping、5 failed、6 waiting、7 running、8 review。未使用的格子保持全透明。
|
|
53
|
+
- 可选 remarks 块覆盖宠物在 pet(摸头)/ petCooldown / feed(喂食)/ feedCooldown / noTreats(缺粮)事件上的气泡台词。每个槽位接受一句或一组台词(轮询循环);声明过的槽位只替换该槽位的内置默认池。社区贡献就是这样给自家宠物配上专属妙语的。
|
|
48
54
|
- `frames` 记录每行用到的列数(缺省按 hatch-pet 契约表 `[6, 8, 8, 4, 5, 8, 6, 6, 6]`);`tracks` 按动画覆盖每帧时长(按该行帧数循环补足)、`loop` 与 `fallback`(默认:全部循环;`jumping` 与 `failed` 停在最后一帧后回到 `idle`)。
|
|
49
55
|
|
|
50
56
|
宠物的来源(后注册的来源在同 id 冲突时覆盖前者):
|
|
@@ -76,6 +82,7 @@ dsh-pet/
|
|
|
76
82
|
| |-- registry.ts # 多宠物契约:manifest 扫描 + 归一化(内置 + 自定义宠物)
|
|
77
83
|
| |-- service.ts # PetService:宠物选择 + 状态机 + 亲密度 + 配置
|
|
78
84
|
| |-- state.ts # 宠物状态机:会话活动投影 → 9 态动画
|
|
85
|
+
| |-- remarks.ts # 妙语库:内置默认池 + 每宠物覆盖 + 轮询选取
|
|
79
86
|
| |-- affinity.ts # 亲密度账本(纯函数 + 冷却)
|
|
80
87
|
| |-- treats.ts # 小鱼干库存账本
|
|
81
88
|
| |-- persist.ts # 持久化($DSH_HOME/pet.json:选择 + 每宠物名字,原子写入)
|
|
@@ -106,7 +113,7 @@ dsh-pet/
|
|
|
106
113
|
- **状态来源**:宿主把官方 `turn/start`、`step/start`、`assistant/chunk`、`assistant/message`、`tool/call`、`tool/result`、`turn/end` 事件投影为 waiting/thinking/tool/review/done/failed 状态。可选兼容 `activity/status` 事件仍作为输入。
|
|
107
114
|
- **注册表**:宿主把每份 manifest 归一化为完整渲染定义(几何、每行帧数、每轨时长),经 `/api/pet/pets` 下发;浏览器半区用该定义渲染任意条目,不携带任何宠物专属代码。
|
|
108
115
|
- **选择与命名**:`petId` 存于设置命名空间;每只宠物的名字存于 `pet.json` 的 `names`,通过悬浮面板对当前宠物改名编辑。旧版安装的平铺 `name` 自动迁移到鲸鱼娘名下。
|
|
109
|
-
- **多会话语义**:API
|
|
116
|
+
- **多会话语义**:API 与浏览器挂载都是宿主全局的,不暴露前台会话身份。并行会话各自保留投影状态:最近一次有意义事件驱动精灵动画,同时每个活动会话在独立气泡里报告自己的阶段(state 视图的 sessions 列表,最多保留最近 12 个)。每个会话完成的轮次仍独立计奖;销毁会话移除它的气泡,销毁当前显示会话则回退到最近仍在活动的会话。
|
|
110
117
|
- **挂载点**:`document.body`(全局 React 根,始终显示:无会话 / 新会话 / 会话中都可见——旧挂载点 `conversation.composer.dock` 只在活动会话里渲染,新会话里宠物消失);组件内部用 `createPortal` 渲染全局浮层。
|
|
111
118
|
- **渲染**:CSS 精灵(background-position)逐帧动画;帧时长来自下发定义里的轨道表。
|
|
112
119
|
- **通信**:浏览器 ↔ 宿主走同源 `/api/pet/*` JSON 端点(state/pets/interact/set-visible/set-config/set-name/set-pet);每只宠物的图集从 `/pet/<id>/<spritesheetPath>` 加载——插件自给自足地提供自己的 API 与资源(与 dsh-remote-web-ui 的 `/api/pair` 同一模式)。
|
package/lib/client.js
CHANGED
|
@@ -107,7 +107,7 @@ window.__ModuleLoader__.load({
|
|
|
107
107
|
}
|
|
108
108
|
//#endregion
|
|
109
109
|
//#region \0dsh-css:packages/dsh-pet/src/client/pet.module.css.mjs
|
|
110
|
-
const css$2 = ".kz2Bea_float{pointer-events:auto;-webkit-user-select:none;user-select:none;flex-direction:column;align-items:center;display:flex;position:fixed}.kz2Bea_sprite{image-rendering:auto;touch-action:none;position:relative}.kz2Bea_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 kz2Bea_pet-bubble-pop;position:absolute;bottom:100%;box-shadow:0 2px 8px #00000040}.kz2Bea_bubblePet{background:#f472b6eb}.kz2Bea_bubbleFeed{background:#38bdf8eb}.kz2Bea_bubbleStatus{text-overflow:ellipsis;background:#0f172ae6;border:1px solid #7dd3fc80;max-width:min(280px,100vw - 24px);animation:none;overflow:hidden}@keyframes kz2Bea_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)}}.kz2Bea_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}.kz2Bea_panel:after{content:\"\";height:14px;position:absolute;top:100%;left:0;right:0}.kz2Bea_rankRow{white-space:nowrap;justify-content:space-between;gap:10px;display:flex}.kz2Bea_nameCell{font-weight:600}.kz2Bea_renameRow{align-items:center;gap:6px;display:flex}.kz2Bea_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}.kz2Bea_nameInput:focus{border-color:#38bdf8;box-shadow:0 0 0 2px #38bdf873}.kz2Bea_actions{gap:6px;display:flex}.kz2Bea_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}.kz2Bea_action:hover{filter:brightness(1.08)}.kz2Bea_action:active{filter:brightness(.94)}.kz2Bea_action:focus-visible{outline:none;box-shadow:0 0 0 2px #38bdf8d9}.kz2Bea_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}.kz2Bea_summon:hover{color:#bae6fd;background:#0f172ae6;border-color:#7dd3fcf2}.kz2Bea_summon:active{color:#7dd3fc;border-color:#7dd3fccc}.kz2Bea_summon:focus-visible{outline:none;box-shadow:0 0 0 2px #38bdf8d9}@media (prefers-reduced-motion:reduce){.kz2Bea_bubble{opacity:1;animation:none}.kz2Bea_action,.kz2Bea_summon{transition:none}}";
|
|
110
|
+
const css$2 = ".kz2Bea_float{pointer-events:auto;-webkit-user-select:none;user-select:none;flex-direction:column;align-items:center;display:flex;position:fixed}.kz2Bea_sprite{image-rendering:auto;touch-action:none;position:relative}.kz2Bea_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 kz2Bea_pet-bubble-pop;position:absolute;bottom:100%;box-shadow:0 2px 8px #00000040}.kz2Bea_bubblePet{background:#f472b6eb}.kz2Bea_bubbleFeed{background:#38bdf8eb}.kz2Bea_bubbleStatus{text-overflow:ellipsis;background:#0f172ae6;border:1px solid #7dd3fc80;max-width:min(280px,100vw - 24px);animation:none;overflow:hidden}.kz2Bea_bubbleStack{pointer-events:none;flex-direction:column;align-items:center;gap:4px;display:flex;position:absolute;bottom:100%}.kz2Bea_bubbleStack .kz2Bea_bubble{margin-bottom:0;position:relative;bottom:auto}@keyframes kz2Bea_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)}}.kz2Bea_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}.kz2Bea_panel:after{content:\"\";height:14px;position:absolute;top:100%;left:0;right:0}.kz2Bea_rankRow{white-space:nowrap;justify-content:space-between;gap:10px;display:flex}.kz2Bea_nameCell{font-weight:600}.kz2Bea_renameRow{align-items:center;gap:6px;display:flex}.kz2Bea_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}.kz2Bea_nameInput:focus{border-color:#38bdf8;box-shadow:0 0 0 2px #38bdf873}.kz2Bea_actions{gap:6px;display:flex}.kz2Bea_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}.kz2Bea_action:hover{filter:brightness(1.08)}.kz2Bea_action:active{filter:brightness(.94)}.kz2Bea_action:focus-visible{outline:none;box-shadow:0 0 0 2px #38bdf8d9}.kz2Bea_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}.kz2Bea_summon:hover{color:#bae6fd;background:#0f172ae6;border-color:#7dd3fcf2}.kz2Bea_summon:active{color:#7dd3fc;border-color:#7dd3fccc}.kz2Bea_summon:focus-visible{outline:none;box-shadow:0 0 0 2px #38bdf8d9}@media (prefers-reduced-motion:reduce){.kz2Bea_bubble{opacity:1;animation:none}.kz2Bea_action,.kz2Bea_summon{transition:none}}";
|
|
111
111
|
const tagId$2 = "@linxin666/dsh-pet/pet.module.css";
|
|
112
112
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
113
113
|
const tag = document.createElement("style");
|
|
@@ -122,6 +122,7 @@ window.__ModuleLoader__.load({
|
|
|
122
122
|
"bubble": "kz2Bea_bubble",
|
|
123
123
|
"bubbleFeed": "kz2Bea_bubbleFeed",
|
|
124
124
|
"bubblePet": "kz2Bea_bubblePet",
|
|
125
|
+
"bubbleStack": "kz2Bea_bubbleStack",
|
|
125
126
|
"bubbleStatus": "kz2Bea_bubbleStatus",
|
|
126
127
|
"float": "kz2Bea_float",
|
|
127
128
|
"nameCell": "kz2Bea_nameCell",
|
|
@@ -288,7 +289,8 @@ window.__ModuleLoader__.load({
|
|
|
288
289
|
};
|
|
289
290
|
const spriteWidth = Math.round(cell.width * spriteScale);
|
|
290
291
|
const spriteHeight = Math.round(cell.height * spriteScale);
|
|
291
|
-
const
|
|
292
|
+
const sessionBubbles = snapshot?.sessions ?? [];
|
|
293
|
+
const statusBubble = feedback === null && !hovered && sessionBubbles.length === 0 ? snapshot?.bubble : void 0;
|
|
292
294
|
const displayName = snapshot?.name ?? definition.displayName;
|
|
293
295
|
return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
294
296
|
ref: floatRef,
|
|
@@ -335,6 +337,15 @@ window.__ModuleLoader__.load({
|
|
|
335
337
|
className: clsx(pet_module_css_default.bubble, feedback.kind === "feed" ? pet_module_css_default.bubbleFeed : pet_module_css_default.bubblePet),
|
|
336
338
|
children: feedback.text
|
|
337
339
|
}, feedback.at),
|
|
340
|
+
feedback === null && !hovered && sessionBubbles.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
341
|
+
className: pet_module_css_default.bubbleStack,
|
|
342
|
+
role: "status",
|
|
343
|
+
"aria-live": "polite",
|
|
344
|
+
children: sessionBubbles.map((session) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
345
|
+
className: clsx(pet_module_css_default.bubble, pet_module_css_default.bubbleStatus),
|
|
346
|
+
children: session.bubble
|
|
347
|
+
}, session.sessionId))
|
|
348
|
+
}),
|
|
338
349
|
statusBubble !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
339
350
|
className: clsx(pet_module_css_default.bubble, pet_module_css_default.bubbleStatus),
|
|
340
351
|
role: "status",
|
|
@@ -878,6 +889,9 @@ window.__ModuleLoader__.load({
|
|
|
878
889
|
specs;
|
|
879
890
|
staged = /* @__PURE__ */ new Map();
|
|
880
891
|
listeners = /* @__PURE__ */ new Set();
|
|
892
|
+
/** The scope subscription installed in the constructor; released by dispose(). */
|
|
893
|
+
disposeScope;
|
|
894
|
+
disposed = false;
|
|
881
895
|
saving = false;
|
|
882
896
|
failed = false;
|
|
883
897
|
failedReason;
|
|
@@ -885,10 +899,20 @@ window.__ModuleLoader__.load({
|
|
|
885
899
|
constructor(scope, specs) {
|
|
886
900
|
this.scope = scope;
|
|
887
901
|
this.specs = new Map(specs.map((spec) => [spec.field, spec]));
|
|
888
|
-
scope.subscribe(() => {
|
|
902
|
+
this.disposeScope = scope.subscribe(() => {
|
|
889
903
|
this.publish();
|
|
890
904
|
});
|
|
891
905
|
}
|
|
906
|
+
/**
|
|
907
|
+
* Release the scope subscription and every bound store listener. The card
|
|
908
|
+
* must call this on teardown; later calls are no-ops.
|
|
909
|
+
*/
|
|
910
|
+
dispose() {
|
|
911
|
+
if (this.disposed) return;
|
|
912
|
+
this.disposed = true;
|
|
913
|
+
this.disposeScope();
|
|
914
|
+
this.listeners.clear();
|
|
915
|
+
}
|
|
892
916
|
/** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */
|
|
893
917
|
bind(project) {
|
|
894
918
|
const store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(project());
|
|
@@ -1168,6 +1192,13 @@ window.__ModuleLoader__.load({
|
|
|
1168
1192
|
...this.form.actions()
|
|
1169
1193
|
};
|
|
1170
1194
|
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Release the card's scope subscription and bound stores; the slot
|
|
1197
|
+
* disposer calls this on teardown.
|
|
1198
|
+
*/
|
|
1199
|
+
dispose() {
|
|
1200
|
+
this.form.dispose();
|
|
1201
|
+
}
|
|
1171
1202
|
};
|
|
1172
1203
|
/**
|
|
1173
1204
|
* Render the pet settings card.
|
|
@@ -1461,14 +1492,20 @@ window.__ModuleLoader__.load({
|
|
|
1461
1492
|
return snapshot.status === "ready" ? snapshot.value?.enabled ?? true : snapshot.status === "unavailable";
|
|
1462
1493
|
};
|
|
1463
1494
|
const petSettings = new PetSettingsCardController(settingsScope);
|
|
1464
|
-
ctx.slots.inject("settings.section", () =>
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1495
|
+
ctx.slots.inject("settings.section", () => {
|
|
1496
|
+
const unregister = ctx.slots.register({
|
|
1497
|
+
name: "settings.section",
|
|
1498
|
+
id: "pet",
|
|
1499
|
+
order: 130,
|
|
1500
|
+
label: () => ctx.locale.bind("pet")("settings.title"),
|
|
1501
|
+
locale: "pet",
|
|
1502
|
+
inject: () => petSettings.inject()
|
|
1503
|
+
}, PetSettingsSection);
|
|
1504
|
+
return () => {
|
|
1505
|
+
petSettings.dispose();
|
|
1506
|
+
unregister();
|
|
1507
|
+
};
|
|
1508
|
+
});
|
|
1472
1509
|
let disposeUi;
|
|
1473
1510
|
const syncUi = () => {
|
|
1474
1511
|
if (enabled() && disposeUi === void 0) {
|