@michengai/dsh-codex-pet 0.1.1

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/lib/client.js ADDED
@@ -0,0 +1,2181 @@
1
+ window.__ModuleLoader__.load({id:"@michengai/dsh-codex-pet",factory:function(require){var module={exports:{}};var exports=module.exports;
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name2 in all)
11
+ __defProp(target, name2, { get: all[name2], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/client.tsx
32
+ var client_exports = {};
33
+ __export(client_exports, {
34
+ apply: () => apply,
35
+ inject: () => inject,
36
+ name: () => name
37
+ });
38
+ module.exports = __toCommonJS(client_exports);
39
+
40
+ // src/companion-api.ts
41
+ function createCompanionProvider(handlers) {
42
+ let snapshot = null, active = true, displays = 0, signature = "null";
43
+ const listeners = /* @__PURE__ */ new Set();
44
+ const check = () => {
45
+ if (!active) throw new Error("\u5BA0\u7269\u63A5\u53E3\u5DF2\u5378\u8F7D");
46
+ };
47
+ const publish = (value) => {
48
+ const next = JSON.stringify(value);
49
+ if (next === signature) return;
50
+ signature = next;
51
+ snapshot = structuredClone(value);
52
+ for (const listener of listeners) {
53
+ try {
54
+ listener(structuredClone(snapshot));
55
+ } catch (error) {
56
+ console.error("\u5BA0\u7269\u72B6\u6001\u8BA2\u9605\u5931\u8D25", error);
57
+ }
58
+ }
59
+ };
60
+ const api = Object.freeze({
61
+ version: 1,
62
+ getSnapshot: () => structuredClone(snapshot),
63
+ subscribe(listener) {
64
+ check();
65
+ listeners.add(listener);
66
+ return () => {
67
+ listeners.delete(listener);
68
+ };
69
+ },
70
+ async command(value) {
71
+ check();
72
+ await handlers.command(value);
73
+ },
74
+ async updateConfig(value) {
75
+ check();
76
+ await handlers.updateConfig(value);
77
+ },
78
+ openSettings() {
79
+ check();
80
+ handlers.openSettings();
81
+ },
82
+ acquireDisplay() {
83
+ check();
84
+ displays++;
85
+ handlers.externalDisplay(true);
86
+ let released = false;
87
+ return () => {
88
+ if (released || !active) return;
89
+ released = true;
90
+ displays--;
91
+ handlers.externalDisplay(displays > 0);
92
+ };
93
+ }
94
+ });
95
+ return { api, publish(value) {
96
+ check();
97
+ publish(value);
98
+ }, dispose() {
99
+ if (!active) return;
100
+ active = false;
101
+ publish(null);
102
+ listeners.clear();
103
+ handlers.externalDisplay(false);
104
+ } };
105
+ }
106
+
107
+ // src/ui-locales.ts
108
+ var en = {
109
+ "\u5BA0\u7269": "Pets",
110
+ "\u5BA0\u7269\u8BBE\u7F6E": "Pet settings",
111
+ "\u5173\u95ED\u8BBE\u7F6E": "Close settings",
112
+ "\u9009\u62E9\u5BA0\u7269": "Choose a pet",
113
+ "\u5BA0\u7269\u4F1A\u7BA1\u7406\u5BF9\u8BDD\u4E32\uFF0C\u5E76\u7A81\u51FA\u663E\u793A\u9700\u8981\u5173\u6CE8\u7684\u4E8B\u9879": "Your pet follows conversations and highlights what needs your attention.",
114
+ "\u5237\u65B0\u5BA0\u7269\u5E93": "Refresh pet library",
115
+ "\u521B\u5EFA": "Create",
116
+ "\u663E\u793A\u5BA0\u7269": "Show pet",
117
+ "\u6536\u8D77\u5BA0\u7269": "Hide pet",
118
+ "\u6B63\u5728\u52A0\u8F7D\u5BA0\u7269\u2026": "Loading pets\u2026",
119
+ "\u5DF2\u9009": "Selected",
120
+ "\u9009\u62E9": "Select",
121
+ "\u5DF2\u9009\u62E9": "Selected",
122
+ "\u5C1A\u672A\u52A0\u8F7D\u5BA0\u7269\u3002\u5185\u7F6E\u8D44\u6E90\u7F3A\u5931\uFF0C\u8BF7\u91CD\u65B0\u5B89\u88C5\u5B8C\u6574\u63D2\u4EF6\u3002": "No pets loaded. Built-in assets are missing; reinstall the complete plugin.",
123
+ "DSH \u81EA\u5B9A\u4E49\u5BA0\u7269": "DSH custom pets",
124
+ "\u6B63\u5728\u8BFB\u53D6\u76EE\u5F55\u2026": "Loading folder\u2026",
125
+ "\u6253\u5F00\u6587\u4EF6\u5939": "Open folder",
126
+ "\u5916\u89C2": "Appearance",
127
+ "\u5BA0\u7269\u5927\u5C0F": "Pet size",
128
+ "\u8C03\u6574\u5BA0\u7269\u5927\u5C0F": "Adjust the size of your pet",
129
+ "\u521B\u5EFA\u5BA0\u7269": "Create a pet",
130
+ "\u5BA0\u7269\u63CF\u8FF0": "Pet description",
131
+ "\u4F8B\u5982\uFF1A\u4E00\u53EA\u6234\u7740\u5706\u773C\u955C\u7684\u5C0F\u6D77\u736D\uFF0C\u5B89\u9759\u3001\u597D\u5947\uFF0C\u6BDB\u7ED2\u73A9\u5177\u98CE\u683C\u2026": "For example: a quiet, curious sea otter wearing round glasses, in a plush toy style\u2026",
132
+ "\u5728 DSH \u65B0\u4F1A\u8BDD\u4E2D\u4F7F\u7528\u968F\u63D2\u4EF6\u63D0\u4F9B\u7684 Skill \u521B\u5EFA\uFF0C\u6210\u54C1\u4FDD\u5B58\u5230 DSH \u5BA0\u7269\u76EE\u5F55\u3002\u9700\u8981\u5F53\u524D\u4F1A\u8BDD\u5177\u5907\u56FE\u50CF\u751F\u6210\u5DE5\u5177\u3002": "Create in a new DSH conversation using the bundled Skill. The result is saved to the DSH pet folder. An image generation tool is required in that conversation.",
133
+ "\u8BF7\u5728 DSH \u4E3B\u754C\u9762\u7684\u5BA0\u7269\u8BBE\u7F6E\u4E2D\u53D1\u8D77\u521B\u5EFA\uFF1B\u72EC\u7ACB\u9884\u89C8\u4E0D\u63D0\u4F9B\u4F1A\u8BDD\u670D\u52A1\u3002": "Start creation from pet settings in DSH. The standalone view has no conversation service.",
134
+ "\u53D6\u6D88": "Cancel",
135
+ "\u5728 DSH \u4E2D\u521B\u5EFA": "Create in DSH",
136
+ "\u521B\u5EFA\u5931\u8D25": "Creation failed",
137
+ "\u64CD\u4F5C\u5931\u8D25": "Operation failed",
138
+ "\u5BA0\u7269\u670D\u52A1\u6682\u4E0D\u53EF\u7528": "Pet service is unavailable",
139
+ "\u6253\u5F00\u5173\u8054\u4EFB\u52A1": "Open linked task",
140
+ "\u7A7A\u95F2": "Idle",
141
+ "\u6253\u4E2A\u62DB\u547C": "Wave",
142
+ "\u8DF3\u4E00\u8DF3": "Jump",
143
+ "\u6062\u590D\u5DF2\u5173\u95ED\u901A\u77E5": "Restore dismissed notifications",
144
+ "\u6062\u590D\u5931\u8D25": "Restore failed",
145
+ "\u67E5\u770B\u4EFB\u52A1": "View task",
146
+ "\u63D0\u4EA4\u5931\u8D25": "Submission failed",
147
+ "\u5DE5\u5177\u5BA1\u6279": "Tool approval",
148
+ "\u6B64\u5DE5\u5177\u9700\u8981\u4F60\u7684\u6279\u51C6\u3002": "This tool needs your approval.",
149
+ "\u62D2\u7EDD": "Reject",
150
+ "\u4EC5\u5141\u8BB8\u4E00\u6B21": "Allow once",
151
+ "\u8F93\u5165\u56DE\u7B54\u6216\u8865\u5145\u8BF4\u660E": "Enter an answer or additional details",
152
+ "\u63D0\u4EA4\u56DE\u7B54": "Submit answer",
153
+ "\u8BF7\u6253\u5F00\u4F1A\u8BDD\u5904\u7406\u6B64\u8BF7\u6C42\u3002": "Open the conversation to handle this request.",
154
+ "\u5BA0\u7269\u4F1A\u8BDD\u901A\u77E5": "Pet conversation notifications",
155
+ "\u6536\u8D77\u4F1A\u8BDD": "Collapse conversations",
156
+ "\u5C55\u5F00\u4F1A\u8BDD": "Expand conversations",
157
+ "\u4F1A\u8BDD": "Conversations",
158
+ "\u6700\u65B0\u4F18\u5148": "Newest first",
159
+ "\u6700\u65B0\u6D3B\u52A8\u4F18\u5148": "Latest activity first",
160
+ "\u5F85\u5904\u7406\u4E8B\u9879\u4F18\u5148": "Needs attention first",
161
+ "\u5173\u95ED\u672C\u8F6E\u63D0\u9192\uFF0C\u4EFB\u52A1\u7EE7\u7EED\u8FD0\u884C": "Dismiss this turn\u2019s notification; the task keeps running",
162
+ "\u67E5\u770B\u5E76\u5904\u7406": "View and respond",
163
+ "\u6253\u5F00\u4F1A\u8BDD\u56DE\u590D": "Open conversation to reply",
164
+ "\u505C\u6B62\u5F53\u524D\u8F6E\u6B21": "Stop current turn",
165
+ "\u6B63\u5728\u5DE5\u4F5C": "Working",
166
+ "\u7B49\u5F85\u4F60\u5904\u7406": "Waiting for you",
167
+ "\u4EFB\u52A1\u51FA\u9519\u4E86": "Task failed",
168
+ "\u5DF2\u5B8C\u6210\uFF0C\u5F85\u4F60\u67E5\u770B": "Completed, ready for review",
169
+ "\u5F53\u524D\u4EFB\u52A1": "Current task",
170
+ "\u6709 {count} \u9879\u5BA0\u7269\u8D44\u6E90\u9700\u8981\u68C0\u67E5": "{count} pet resources need attention",
171
+ "\u8FD8\u6709 {count} \u4E2A\u4F1A\u8BDD": "{count} more conversations",
172
+ "\u6062\u590D {count} \u6761\u5DF2\u5173\u95ED\u901A\u77E5": "Restore {count} dismissed notifications",
173
+ "\u5173\u95ED\u901A\u77E5\uFF1A{title}": "Dismiss notification: {title}",
174
+ "\u5904\u7406\u8BF7\u6C42\uFF1A{title}": "Respond to request: {title}",
175
+ "\u56DE\u590D\u4F1A\u8BDD\uFF1A{title}": "Reply to conversation: {title}",
176
+ "\u505C\u6B62\u5F53\u524D\u8F6E\u6B21\uFF1A{title}": "Stop current turn: {title}",
177
+ "{question}\uFF1A\u6587\u5B57\u56DE\u7B54": "{question}: written answer",
178
+ "{name}\uFF0C{status}\uFF1B\u62D6\u52A8\u79FB\u52A8\uFF0C\u53CC\u51FB\u8DF3\u8DC3\uFF0C\u53F3\u952E\u83DC\u5355": "{name}, {status}; drag to move, double-click to jump, right-click for menu",
179
+ "\u4F1A\u8BDD\u670D\u52A1\u5C1A\u672A\u5C31\u7EEA": "Conversation service is not ready",
180
+ "\u5BA0\u7269\u5E93\u5C1A\u672A\u52A0\u8F7D": "Pet library has not loaded",
181
+ "\u8BF7\u56DE\u7B54\u6240\u6709\u95EE\u9898": "Please answer every question",
182
+ "\u95EE\u9898\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u56DE\u7B54": "The questions have changed. Please answer again.",
183
+ "\u9009\u9879\u65E0\u6548": "Invalid option",
184
+ "\u56DE\u7B54\u8FC7\u957F": "Answer is too long",
185
+ "\u5355\u9009\u95EE\u9898\u53EA\u80FD\u63D0\u4EA4\u4E00\u79CD\u56DE\u7B54": "Choose one option or enter one written answer",
186
+ "\u8FD9\u6761\u901A\u77E5\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u4F7F\u7528\u6700\u65B0\u901A\u77E5": "This notification has changed. Use the latest notification.",
187
+ "\u4EFB\u52A1\u72B6\u6001\u5DF2\u53D8\u5316": "Task state has changed",
188
+ "\u5BBF\u4E3B\u672A\u63D0\u4F9B\u505C\u6B62\u4EFB\u52A1\u80FD\u529B": "The host does not support stopping tasks",
189
+ "\u6B63\u5728\u63D0\u4EA4\uFF0C\u8BF7\u52FF\u91CD\u590D\u64CD\u4F5C": "Submitting. Please do not repeat the action.",
190
+ "\u505C\u6B62\u5931\u8D25": "Could not stop the task",
191
+ "\u8BF7\u6C42\u5DF2\u7ED3\u675F\u6216\u5DF2\u66F4\u6362\uFF0C\u8BF7\u67E5\u770B\u6700\u65B0\u4F1A\u8BDD": "The request has ended or changed. Open the latest conversation.",
192
+ "\u8BE5\u8BF7\u6C42\u5DF2\u7ECF\u63D0\u4EA4": "This request has already been submitted",
193
+ "\u6B64\u8BF7\u6C42\u4E0D\u652F\u6301\u8BE5\u64CD\u4F5C": "This action is not supported for this request",
194
+ "\u8BF7\u8F93\u5165 1\u20132000 \u5B57\u7684\u5BA0\u7269\u63CF\u8FF0": "Enter a pet description of 1\u20132000 characters",
195
+ "\u521B\u5EFA\u4F1A\u8BDD\u5C1A\u4E0D\u53EF\u7528\uFF0C\u8BF7\u91CD\u8BD5": "The new conversation is not ready. Please try again.",
196
+ "DSH \u672A\u63A5\u53D7\u5BA0\u7269\u521B\u5EFA\u8BF7\u6C42": "DSH did not accept the pet creation request"
197
+ };
198
+ function translator(language) {
199
+ return (message, values = {}) => {
200
+ const text = /^zh(?:-|$)/i.test(language) ? message : en[message] ?? message;
201
+ return text.replace(/\{(\w+)\}/g, (match, key) => String(values[key] ?? match));
202
+ };
203
+ }
204
+
205
+ // src/client.tsx
206
+ var import_react6 = require("react");
207
+
208
+ // src/library-store.ts
209
+ function createLibraryStore(request2) {
210
+ let snapshot = { library: null, error: "" }, sequence = 0, mutations = 0;
211
+ let timer;
212
+ let reading;
213
+ const listeners = /* @__PURE__ */ new Set();
214
+ const publish = (next) => {
215
+ if (JSON.stringify(snapshot) === JSON.stringify(next)) return;
216
+ snapshot = next;
217
+ for (const listener of listeners) listener();
218
+ };
219
+ const run = async (path, data) => {
220
+ const current = ++sequence;
221
+ if (data !== void 0) mutations++;
222
+ try {
223
+ const library = await request2(path, data);
224
+ if (current === sequence) publish({ library, error: "" });
225
+ } catch (error) {
226
+ if (current === sequence) publish({ ...snapshot, error: error instanceof Error ? error.message : "\u64CD\u4F5C\u5931\u8D25" });
227
+ throw error;
228
+ } finally {
229
+ if (data !== void 0) mutations--;
230
+ }
231
+ };
232
+ const read = () => {
233
+ if (document.hidden || reading || mutations) return;
234
+ reading = run("state").catch(() => {
235
+ }).finally(() => {
236
+ reading = void 0;
237
+ });
238
+ };
239
+ return {
240
+ getSnapshot: () => snapshot,
241
+ subscribe(listener) {
242
+ listeners.add(listener);
243
+ if (listeners.size === 1) {
244
+ read();
245
+ timer = setInterval(read, 2500);
246
+ window.addEventListener("focus", read);
247
+ document.addEventListener("visibilitychange", read);
248
+ }
249
+ return () => {
250
+ listeners.delete(listener);
251
+ if (!listeners.size) {
252
+ clearInterval(timer);
253
+ window.removeEventListener("focus", read);
254
+ document.removeEventListener("visibilitychange", read);
255
+ }
256
+ };
257
+ },
258
+ run
259
+ };
260
+ }
261
+
262
+ // src/plugin-update-ui.tsx
263
+ var import_react2 = require("react");
264
+
265
+ // src/project-icons.tsx
266
+ var import_react = __toESM(require("react"), 1);
267
+ function GithubMark16() {
268
+ return import_react.default.createElement(
269
+ "svg",
270
+ { viewBox: "0 0 16 16", width: 16, height: 16, "aria-hidden": true, focusable: false },
271
+ import_react.default.createElement("path", { fill: "currentColor", d: "M8 0a8 8 0 0 0-2.53 15.59c.4.074.547-.173.547-.385 0-.19-.007-.693-.01-1.36-2.226.484-2.695-1.073-2.695-1.073-.364-.924-.89-1.17-.89-1.17-.726-.496.055-.486.055-.486.803.056 1.225.824 1.225.824.714 1.223 1.872.87 2.328.665.072-.517.28-.87.508-1.07-1.777-.202-3.645-.888-3.645-3.956 0-.874.31-1.588.823-2.148-.083-.202-.357-1.017.078-2.12 0 0 .672-.215 2.2.82A7.65 7.65 0 0 1 8 4.8c.68.003 1.365.092 2.004.27 1.527-1.035 2.197-.82 2.197-.82.437 1.103.162 1.918.08 2.12.513.56.822 1.274.822 2.148 0 3.076-1.872 3.752-3.654 3.95.288.248.544.735.544 1.482 0 1.07-.01 1.932-.01 2.195 0 .214.144.463.55.384A8.001 8.001 0 0 0 8 0Z" })
272
+ );
273
+ }
274
+ function FeedbackMark16() {
275
+ return import_react.default.createElement(
276
+ "svg",
277
+ { viewBox: "0 0 16 16", width: 16, height: 16, fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": true, focusable: false },
278
+ import_react.default.createElement("path", { d: "M10.8239 3.54733V4.78443H4.63437V3.54733H10.8239Z", fill: "currentColor" }),
279
+ import_react.default.createElement("path", { d: "M10.8239 6.12629V7.36338H4.63437V6.12629H10.8239Z", fill: "currentColor" }),
280
+ import_react.default.createElement("path", { d: "M9.073 8.70524V9.94234H4.63437V8.70524H9.073Z", fill: "currentColor" }),
281
+ import_react.default.createElement("path", { d: "M9.13321 0.573526C10.0076 0.573525 10.7179 0.572522 11.285 0.63397C11.8645 0.696791 12.3743 0.831648 12.8193 1.1548C13.0776 1.34246 13.3056 1.57047 13.4933 1.82875C13.8164 2.2737 13.9513 2.7836 14.0141 3.36303C14.0755 3.93015 14.0745 4.64049 14.0745 5.51485V6.1757L12.7327 7.5629V5.51485C12.7327 4.61092 12.732 3.9862 12.6803 3.5081C12.6298 3.0427 12.5379 2.79497 12.4083 2.61654C12.3033 2.47211 12.176 2.34472 12.0315 2.23977C11.8531 2.11016 11.6054 2.01823 11.14 1.96777C10.6618 1.91601 10.0372 1.91539 9.13321 1.91539H6.32658C5.42262 1.91539 4.79796 1.91604 4.31983 1.96777C3.85451 2.01819 3.60672 2.11029 3.42827 2.23977C3.28392 2.34465 3.15643 2.47223 3.0515 2.61654C2.9219 2.79496 2.82997 3.04274 2.7795 3.5081C2.72774 3.9862 2.72712 4.61092 2.72712 5.51485V10.023C2.72712 10.9273 2.72773 11.5525 2.7795 12.0307C2.82992 12.4959 2.92205 12.7429 3.0515 12.9213C3.15645 13.0657 3.28384 13.1931 3.42827 13.2981C3.60676 13.4277 3.85408 13.5206 4.31983 13.5711C4.79797 13.6228 5.42259 13.6234 6.32658 13.6234H6.87057L5.57707 14.9593C5.03527 14.9556 4.57031 14.9467 4.17476 14.9039C3.59508 14.841 3.08558 14.7063 2.64048 14.383C2.38215 14.1953 2.15422 13.9684 1.96653 13.7101C1.64319 13.2649 1.50851 12.7546 1.4457 12.1748C1.38432 11.6076 1.38525 10.8974 1.38525 10.023V5.51485C1.38525 4.64049 1.38426 3.93015 1.4457 3.36303C1.50853 2.78363 1.64341 2.27368 1.96653 1.82875C2.15417 1.57059 2.38228 1.34239 2.64048 1.1548C3.08544 0.831805 3.59533 0.696762 4.17476 0.63397C4.74193 0.572552 5.45218 0.573525 6.32658 0.573526H9.13321Z", fill: "currentColor" }),
282
+ import_react.default.createElement("path", { d: "M14.2193 14.9553H10.0124L11.3744 13.6134H14.2193V14.9553Z", fill: "currentColor" }),
283
+ import_react.default.createElement("path", { d: "M8.24493 13.3711L7.49015 14.8806C7.40148 15.058 7.58961 15.2461 7.76695 15.1574L9.27651 14.4027L14.6147 9.09934L13.5832 8.06775L8.24493 13.3711Z", fill: "currentColor" })
284
+ );
285
+ }
286
+
287
+ // src/update-errors.ts
288
+ var messages = {
289
+ "INVALID_VERSION": [
290
+ "\u65E0\u6CD5\u8BFB\u53D6\u5F53\u524D\u63D2\u4EF6\u7248\u672C\u3002",
291
+ "Could not read the current plugin version."
292
+ ],
293
+ "AUTO_UPDATE_UNAVAILABLE": [
294
+ "\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u81EA\u52A8\u66F4\u65B0\uFF0C\u8BF7\u4F7F\u7528\u624B\u5DE5\u66F4\u65B0\u547D\u4EE4\u3002",
295
+ "Automatic updates are unavailable. Use the manual update command."
296
+ ],
297
+ "UPDATE_TIMEOUT": [
298
+ "\u66F4\u65B0\u8D85\u65F6\uFF0C\u5DF2\u8BF7\u6C42\u53D6\u6D88\uFF1B\u8FDB\u7A0B\u7ED3\u675F\u524D\u4E0D\u80FD\u518D\u6B21\u5B89\u88C5\u3002",
299
+ "The update timed out and cancellation was requested. Wait for the process to exit before retrying."
300
+ ],
301
+ "UNTRUSTED_REQUEST": [
302
+ "\u5DF2\u62D2\u7EDD\u975E\u672C\u673A\u540C\u6E90\u66F4\u65B0\u8BF7\u6C42\u3002",
303
+ "The update request was rejected because it is not from the same local origin."
304
+ ],
305
+ "UPDATE_IN_PROGRESS": [
306
+ "\u5F53\u524D\u63D2\u4EF6\u6B63\u5728\u66F4\u65B0\uFF0C\u8BF7\u7A0D\u5019\u3002",
307
+ "The plugin is being updated. Please wait."
308
+ ],
309
+ "NOT_PUBLISHED": [
310
+ "\u63D2\u4EF6\u5C1A\u672A\u53D1\u5E03\u5230 npm\u3002",
311
+ "The plugin has not been published to npm yet."
312
+ ],
313
+ "REGISTRY_UNAVAILABLE": [
314
+ "\u6682\u65F6\u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u3002",
315
+ "Could not retrieve the latest version. Please try again later."
316
+ ],
317
+ "UPDATE_FAILED": [
318
+ "\u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u67E5\u770B\u670D\u52A1\u7AEF\u65E5\u5FD7\u3002",
319
+ "The update failed. Check the server logs."
320
+ ]
321
+ };
322
+ function updateErrorMessage(code, language) {
323
+ const key = typeof code === "string" && Object.hasOwn(messages, code) ? code : "UPDATE_FAILED";
324
+ return messages[key][/^zh(?:-|$)/i.test(language) ? 0 : 1];
325
+ }
326
+
327
+ // src/shared-plugin-update-ui.ts
328
+ var UPDATE_HEADER = "x-michengai-plugin-update";
329
+ var STYLE_ID = "michengai-plugin-update-ui";
330
+ var CSS = `
331
+ .mpi-version{margin-left:8px;color:var(--dsw-alias-label-tertiary,#9da1aa);font-family:inherit;font-size:12px;font-weight:500;line-height:18px;letter-spacing:0;white-space:nowrap;vertical-align:baseline}.mpi-check{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:28px;padding:0 8px;border:1px solid var(--dsw-alias-border-l2,#4b4d52);border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary,#b8bbc2);font:inherit;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap;cursor:pointer}.mpi-check:hover{background:var(--dsw-alias-interactive-bg-hover,#3a3b3f);color:var(--dsw-alias-label-primary,#fff)}.mpi-check:focus-visible,.mpi-dialog .mpi-action:focus-visible,.mpi-dialog .mpi-dialog-close:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4f8cff);outline-offset:2px}.mpi-icon{display:inline-flex;flex:0 0 auto;width:16px;height:16px;align-items:center;justify-content:center;pointer-events:none}.mpi-icon svg{display:block;width:16px;height:16px}
332
+ .mpi-overlay{position:fixed;inset:0;z-index:2147483647;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(0,0,0,.62)}.mpi-dialog{position:relative;box-sizing:border-box;width:min(680px,100%);max-height:calc(100vh - 48px);overflow:auto;border:1px solid var(--dsw-alias-border-l2,#4b4d52);border-radius:14px;padding:22px;background:var(--dsw-alias-bg-layer-2,var(--dsw-specific-menu,#202124));color:var(--dsw-alias-label-primary,#fff);box-shadow:var(--dsw-shadow-lv3,0 16px 48px rgba(0,0,0,.24));font-family:inherit}.mpi-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.mpi-dialog h2{margin:0;font-size:18px;line-height:26px}.mpi-dialog .mpi-dialog-close{display:inline-flex;flex:0 0 28px;width:28px;height:28px;align-items:center;justify-content:center;padding:0;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary,#b8bbc2);cursor:pointer}.mpi-dialog .mpi-dialog-close:hover{background:var(--dsw-alias-interactive-bg-hover,#3a3b3f);color:var(--dsw-alias-label-primary,#fff)}.mpi-intro{margin:8px 0 18px;color:var(--dsw-alias-label-secondary,#c2c4ca);font-size:13px;line-height:20px}.mpi-meta{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:8px 18px;margin:0 0 16px;font-size:12px;line-height:18px}.mpi-meta dt{color:var(--dsw-alias-label-secondary,#c2c4ca)}.mpi-meta dd{margin:0;font-family:ui-monospace,SFMono-Regular,Consolas,monospace}.mpi-status{margin:0 0 18px;border-radius:7px;padding:12px 14px;background:var(--dsw-alias-bg-layer-3,var(--dsw-specific-menu-item-hover,#252527));font-size:13px;font-weight:600;line-height:20px}.mpi-status[data-kind=error]{color:var(--dsw-alias-state-error-primary,#ff6464)}.mpi-status[data-kind=success]{color:var(--dsw-alias-state-success-primary,#36d67a)}.mpi-manual{border-top:1px solid var(--dsw-alias-border-l2,#4b4d52);padding-top:16px}.mpi-manual h3{margin:0 0 6px;font-size:14px;line-height:20px}.mpi-manual p{margin:0 0 10px;color:var(--dsw-alias-label-secondary,#c2c4ca);font-size:12px;line-height:18px}.mpi-command{display:flex;align-items:center;gap:8px;border:1px solid var(--dsw-alias-border-l2,#4b4d52);border-radius:7px;padding:10px;background:var(--dsw-alias-bg-layer-3,var(--dsw-specific-menu-item-hover,#252527))}.mpi-command code{min-width:0;flex:1;overflow:auto;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;line-height:18px;white-space:nowrap}.mpi-actions{display:flex;align-items:center;justify-content:flex-end;gap:12px;margin-top:18px}.mpi-actions-group{display:flex;gap:8px}.mpi-dialog .mpi-action{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:32px;border:1px solid var(--dsw-alias-border-l2,#4b4d52);border-radius:7px;padding:6px 10px;background:transparent;color:inherit;font:inherit;font-size:12px;cursor:pointer}.mpi-dialog .mpi-action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#414247)}.mpi-dialog .mpi-action:disabled{cursor:not-allowed;opacity:.55}.mpi-dialog .mpi-primary{border-color:var(--dsw-alias-state-business-primary,#4f8cff);background:var(--dsw-alias-state-business-primary,#4f8cff);color:#fff}.mpi-progress{height:4px;margin-top:10px;overflow:hidden;border-radius:99px;background:var(--dsw-alias-border-l2,#4b4d52)}.mpi-progress::after{display:block;width:32%;height:100%;background:var(--dsw-alias-state-business-primary,#4f8cff);content:'';animation:mpi-wave 1.15s ease-in-out infinite}@keyframes mpi-wave{from{transform:translateX(-110%)}to{transform:translateX(330%)}}@media(max-width:560px){.mpi-overlay{padding:10px}.mpi-dialog{max-height:calc(100vh - 20px);padding:16px}.mpi-actions{align-items:stretch}.mpi-actions-group{justify-content:flex-end;flex-wrap:wrap}.mpi-meta{grid-template-columns:1fr;gap:2px}.mpi-meta dd{margin-bottom:6px}}
333
+ `;
334
+ var ZH = {
335
+ unpublished: "\u5C1A\u672A\u53D1\u5E03\u5230 npm\uFF0C\u53D1\u5E03\u540E\u5373\u53EF\u68C0\u67E5\u5E76\u5B89\u88C5\u66F4\u65B0\u3002",
336
+ check: "\u68C0\u67E5\u66F4\u65B0",
337
+ update: "\u66F4\u65B0",
338
+ close: "\u5173\u95ED",
339
+ recheck: "\u91CD\u65B0\u68C0\u67E5",
340
+ auto: "\u81EA\u52A8\u66F4\u65B0",
341
+ updating: "\u6B63\u5728\u66F4\u65B0\u2026",
342
+ copy: "\u590D\u5236\u547D\u4EE4",
343
+ copied: "\u5DF2\u590D\u5236",
344
+ copyFailed: "\u590D\u5236\u5931\u8D25",
345
+ checking: "\u6B63\u5728\u68C0\u67E5\u66F4\u65B0\u2026",
346
+ latest: "\u5DF2\u662F\u6700\u65B0\u7248\u672C",
347
+ found: "\u53D1\u73B0\u65B0\u7248\u672C",
348
+ failed: "\u68C0\u67E5\u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",
349
+ current: "\u8FD0\u884C\u7248\u672C",
350
+ latestLabel: "\u6700\u65B0\u7248\u672C",
351
+ profile: "\u76EE\u6807 profile",
352
+ unknown: "\u672A\u77E5",
353
+ manual: "\u624B\u5DE5\u66F4\u65B0",
354
+ manualHint: "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u65F6\uFF0C\u53EF\u5728\u5F53\u524D DSH \u7EC8\u7AEF\u6267\u884C\u4EE5\u4E0B\u547D\u4EE4\uFF0C\u5B8C\u6210\u540E\u91CD\u542F DSH Web\u3002",
355
+ intro: "\u4EC5\u68C0\u67E5\u5E76\u66F4\u65B0\u5F53\u524D\u63D2\u4EF6\uFF0C\u4E0D\u4F1A\u8054\u52A8\u5B89\u88C5\u5176\u4ED6\u63D2\u4EF6\u3002",
356
+ restart: "\u66F4\u65B0\u5B8C\u6210\uFF0C\u8BF7\u91CD\u542F DSH Web\u3002",
357
+ restarting: "\u66F4\u65B0\u5B8C\u6210\uFF0C\u6B63\u5728\u91CD\u65B0\u52A0\u8F7D DSH\u2026",
358
+ unavailable: "\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u81EA\u52A8\u66F4\u65B0\uFF0C\u8BF7\u4F7F\u7528\u624B\u5DE5\u66F4\u65B0\u547D\u4EE4\u3002"
359
+ };
360
+ var EN = {
361
+ unpublished: "Not published to npm yet. Updates will be available after publication.",
362
+ check: "Check for updates",
363
+ update: "Update",
364
+ close: "Close",
365
+ recheck: "Check again",
366
+ auto: "Update automatically",
367
+ updating: "Updating\u2026",
368
+ copy: "Copy command",
369
+ copied: "Copied",
370
+ copyFailed: "Copy failed",
371
+ checking: "Checking for updates\u2026",
372
+ latest: "You are up to date",
373
+ found: "New version available",
374
+ failed: "Could not check for updates. Try again later.",
375
+ current: "Running version",
376
+ latestLabel: "Latest version",
377
+ profile: "Target profile",
378
+ unknown: "Unknown",
379
+ manual: "Manual update",
380
+ manualHint: "If automatic update fails, run this command in the current DSH terminal, then restart DSH Web.",
381
+ intro: "Only this plugin is checked and updated. Other plugins are not changed.",
382
+ restart: "Update complete. Restart DSH Web.",
383
+ restarting: "Update complete. Reloading DSH\u2026",
384
+ unavailable: "Automatic update is unavailable. Use the manual command."
385
+ };
386
+ function strings(language) {
387
+ return /^zh(?:-|$)/i.test(language) ? ZH : EN;
388
+ }
389
+ function ensureStyle() {
390
+ if (document.getElementById(STYLE_ID) !== null) return;
391
+ const style = document.createElement("style");
392
+ style.id = STYLE_ID;
393
+ style.textContent = CSS;
394
+ (document.head ?? document.documentElement).append(style);
395
+ }
396
+ function validPayload(value) {
397
+ if (value === null || typeof value !== "object") return false;
398
+ const item = value;
399
+ return typeof item.packageName === "string" && typeof item.currentVersion === "string" && typeof item.updateAvailable === "boolean" && typeof item.profileName === "string" && typeof item.canAutoUpdate === "boolean" && typeof item.latestCheckFailed === "boolean" && (item.latestVersion === void 0 || typeof item.latestVersion === "string");
400
+ }
401
+ async function requestStatus(endpoint, method, signal, language = "zh") {
402
+ const signalOption = signal === void 0 ? {} : { signal };
403
+ const response = await fetch(
404
+ endpoint,
405
+ method === "GET" ? { cache: "no-store", ...signalOption } : {
406
+ method: "POST",
407
+ headers: { "content-type": "application/json", [UPDATE_HEADER]: "1" },
408
+ body: "{}",
409
+ ...signalOption
410
+ }
411
+ );
412
+ const value = await response.json();
413
+ if (!response.ok || !validPayload(value))
414
+ throw new Error(updateErrorMessage(value.code, language));
415
+ return value;
416
+ }
417
+ function manualPluginUpdateCommand(profileName, packageName, version) {
418
+ const profile = profileName.trim() === "" ? "" : ` --profile ${profileName.trim()}`;
419
+ return `dsh plugin${profile} add ${packageName}@${version} --registry=https://registry.npmjs.org/`;
420
+ }
421
+ function handlePluginUpdateEscape(event, close) {
422
+ if (event.key !== "Escape") return false;
423
+ event.preventDefault();
424
+ event.stopPropagation();
425
+ event.stopImmediatePropagation();
426
+ close();
427
+ return true;
428
+ }
429
+ function observePluginUpdate(options) {
430
+ if (typeof document === "undefined" || document.body === null)
431
+ return () => {
432
+ };
433
+ ensureStyle();
434
+ const controller = new AbortController();
435
+ let payload;
436
+ let overlay;
437
+ let frame;
438
+ const setButtonContent = (button, label, iconName) => {
439
+ const icon = options.createIcon(iconName);
440
+ icon.classList.add("mpi-icon");
441
+ icon.setAttribute("aria-hidden", "true");
442
+ const text = document.createElement("span");
443
+ text.dataset.mpiLabel = "";
444
+ text.textContent = label;
445
+ button.replaceChildren(icon, text);
446
+ };
447
+ const setButtonLabel = (button, label) => {
448
+ const text = button.querySelector("[data-mpi-label]");
449
+ if (text === null) button.textContent = label;
450
+ else text.textContent = label;
451
+ };
452
+ const applyControls = () => {
453
+ const row = options.root ?? document.querySelector(options.titleRowSelector);
454
+ if (row === null) return;
455
+ const links = row.querySelector(options.linksSelector);
456
+ if (links === null || links.querySelector(`[data-mpi-check="${options.packageName}"]`) !== null)
457
+ return;
458
+ const button = document.createElement("button");
459
+ button.type = "button";
460
+ button.className = "mpi-check";
461
+ button.dataset.mpiCheck = options.packageName;
462
+ setButtonContent(button, strings(options.language).check, "refresh");
463
+ button.addEventListener("click", openDialog);
464
+ links.append(button);
465
+ };
466
+ const load = async () => {
467
+ payload = await requestStatus(
468
+ options.endpoint,
469
+ "GET",
470
+ controller.signal,
471
+ options.language
472
+ );
473
+ applyControls();
474
+ return payload;
475
+ };
476
+ const closeDialog = () => {
477
+ overlay?.remove();
478
+ overlay = void 0;
479
+ };
480
+ function openDialog() {
481
+ closeDialog();
482
+ const text = strings(options.language);
483
+ overlay = document.createElement("div");
484
+ overlay.className = "mpi-overlay";
485
+ const dialog = document.createElement("section");
486
+ dialog.className = "mpi-dialog";
487
+ dialog.setAttribute("role", "dialog");
488
+ dialog.setAttribute("aria-modal", "true");
489
+ dialog.innerHTML = `<header class="mpi-head"><h2></h2><button type="button" class="mpi-dialog-close" data-action="close"></button></header><p class="mpi-intro"></p><dl class="mpi-meta"><dt></dt><dd data-role="current"></dd><dt></dt><dd data-role="latest"></dd><dt></dt><dd data-role="profile"></dd></dl><div class="mpi-status" role="status"></div><div class="mpi-progress" hidden></div><section class="mpi-manual"><h3></h3><p></p><div class="mpi-command"><code></code><button type="button" class="mpi-action" data-action="copy"></button></div></section><footer class="mpi-actions"><div class="mpi-actions-group"><button type="button" class="mpi-action" data-action="check"></button><button type="button" class="mpi-action mpi-primary" data-action="update"></button></div></footer>`;
490
+ const name2 = /^zh(?:-|$)/i.test(options.language) ? options.zhName : options.enName;
491
+ dialog.querySelector("h2").textContent = `${name2} ${text.update}`;
492
+ dialog.querySelector(".mpi-intro").textContent = text.intro;
493
+ const terms = dialog.querySelectorAll("dt");
494
+ terms[0].textContent = text.current;
495
+ terms[1].textContent = text.latestLabel;
496
+ terms[2].textContent = text.profile;
497
+ dialog.querySelector(".mpi-manual h3").textContent = text.manual;
498
+ dialog.querySelector(".mpi-manual p").textContent = text.manualHint;
499
+ const status = dialog.querySelector(".mpi-status");
500
+ const progress = dialog.querySelector(".mpi-progress");
501
+ const command = dialog.querySelector(".mpi-command code");
502
+ const close = dialog.querySelector(
503
+ "[data-action=close]"
504
+ );
505
+ const check = dialog.querySelector(
506
+ "[data-action=check]"
507
+ );
508
+ const update = dialog.querySelector(
509
+ "[data-action=update]"
510
+ );
511
+ const copy = dialog.querySelector("[data-action=copy]");
512
+ setButtonContent(close, text.close, "close");
513
+ close.querySelector("[data-mpi-label]")?.remove();
514
+ close.setAttribute("aria-label", text.close);
515
+ close.title = text.close;
516
+ setButtonContent(check, text.recheck, "refresh");
517
+ setButtonContent(update, text.auto, "download");
518
+ setButtonContent(copy, text.copy, "copy");
519
+ let busy = false;
520
+ const setMessage = (message, kind = "") => {
521
+ status.textContent = message;
522
+ status.dataset.kind = kind;
523
+ };
524
+ const setBusy = (value) => {
525
+ busy = value;
526
+ check.disabled = value;
527
+ copy.disabled = value;
528
+ update.disabled = value || payload?.canAutoUpdate !== true || payload.updateAvailable !== true;
529
+ progress.hidden = !value;
530
+ };
531
+ const render = () => {
532
+ dialog.querySelector("[data-role=current]").textContent = payload === void 0 ? text.unknown : `v${payload.currentVersion}`;
533
+ dialog.querySelector("[data-role=latest]").textContent = payload?.latestVersion === void 0 ? text.unknown : `v${payload.latestVersion}`;
534
+ dialog.querySelector("[data-role=profile]").textContent = payload?.profileName ?? text.unknown;
535
+ command.textContent = manualPluginUpdateCommand(
536
+ payload?.profileName ?? "",
537
+ options.packageName,
538
+ payload?.latestVersion ?? "latest"
539
+ );
540
+ update.disabled = busy || payload?.canAutoUpdate !== true || payload.updateAvailable !== true;
541
+ if (payload === void 0) setMessage(text.checking);
542
+ else if (payload.notPublished) setMessage(text.unpublished);
543
+ else if (payload.latestCheckFailed) setMessage(text.failed, "error");
544
+ else if (payload.updateAvailable)
545
+ setMessage(`${text.found}: v${payload.latestVersion ?? text.unknown}`);
546
+ else setMessage(text.latest, "success");
547
+ if (payload !== void 0 && !payload.canAutoUpdate && payload.updateAvailable)
548
+ setMessage(text.unavailable);
549
+ };
550
+ const checkNow = async () => {
551
+ if (busy) return;
552
+ setBusy(true);
553
+ setMessage(text.checking);
554
+ try {
555
+ await load();
556
+ setBusy(false);
557
+ render();
558
+ } catch (error) {
559
+ setBusy(false);
560
+ setMessage(
561
+ error instanceof Error ? error.message : text.failed,
562
+ "error"
563
+ );
564
+ }
565
+ };
566
+ const updateNow = async () => {
567
+ if (busy) return;
568
+ setBusy(true);
569
+ setButtonLabel(update, text.updating);
570
+ setMessage(text.updating);
571
+ try {
572
+ payload = await requestStatus(
573
+ options.endpoint,
574
+ "POST",
575
+ controller.signal,
576
+ options.language
577
+ );
578
+ if (payload.updatedVersion) payload.updateAvailable = false;
579
+ applyControls();
580
+ render();
581
+ setMessage(
582
+ payload.autoReload === true ? text.restarting : text.restart,
583
+ "success"
584
+ );
585
+ } catch (error) {
586
+ setMessage(
587
+ error instanceof Error ? error.message : text.failed,
588
+ "error"
589
+ );
590
+ } finally {
591
+ setButtonLabel(update, text.auto);
592
+ setBusy(false);
593
+ }
594
+ };
595
+ close.addEventListener("click", closeDialog);
596
+ check.addEventListener("click", () => {
597
+ void checkNow();
598
+ });
599
+ update.addEventListener("click", () => {
600
+ void updateNow();
601
+ });
602
+ copy.addEventListener("click", () => {
603
+ void navigator.clipboard?.writeText(command.textContent ?? "").then(() => {
604
+ setButtonLabel(copy, text.copied);
605
+ setTimeout(() => {
606
+ setButtonLabel(copy, text.copy);
607
+ }, 1400);
608
+ }).catch(() => {
609
+ setButtonLabel(copy, text.copyFailed);
610
+ });
611
+ });
612
+ overlay.addEventListener("click", (event) => {
613
+ if (event.target === overlay) closeDialog();
614
+ });
615
+ overlay.addEventListener(
616
+ "keydown",
617
+ (event) => {
618
+ handlePluginUpdateEscape(event, closeDialog);
619
+ },
620
+ true
621
+ );
622
+ overlay.append(dialog);
623
+ (options.root?.closest("dialog[open]") ?? document.body).append(overlay);
624
+ render();
625
+ close.focus();
626
+ void checkNow();
627
+ }
628
+ const observer = new MutationObserver(() => {
629
+ if (frame !== void 0) return;
630
+ frame = window.requestAnimationFrame(() => {
631
+ frame = void 0;
632
+ applyControls();
633
+ });
634
+ });
635
+ observer.observe(options.root ?? document.body, {
636
+ childList: true,
637
+ subtree: true
638
+ });
639
+ applyControls();
640
+ void load().catch(() => {
641
+ });
642
+ return () => {
643
+ controller.abort();
644
+ observer.disconnect();
645
+ closeDialog();
646
+ if (frame !== void 0) window.cancelAnimationFrame(frame);
647
+ (options.root ?? document).querySelectorAll(
648
+ `[data-mpi-check="${options.packageName}"],.mpi-version[data-package="${options.packageName}"]`
649
+ ).forEach((node) => node.remove());
650
+ };
651
+ }
652
+
653
+ // src/model.ts
654
+ var BASE = "/dsh-codex-pet";
655
+ var BUILTINS = [
656
+ ["codex", "Codex", "The original Codex companion."],
657
+ ["dewey", "Dewey", "A calm companion for focused workspace days."],
658
+ ["fireball", "Fireball", "Hot path energy for fast iteration."],
659
+ ["hoots", "Hoots", "A sharp-eyed owl for polished work in a blink."],
660
+ ["rocky", "Rocky", "A steady rock when the diff gets large."],
661
+ ["seedy", "Seedy", "Small green shoots for new ideas."],
662
+ ["stacky", "Stacky", "A balanced stack for deep work."],
663
+ ["bsod", "BSOD", "A tiny blue-screen gremlin."],
664
+ ["null-signal", "Null Signal", "Quiet signal from the void."]
665
+ ];
666
+ var ANIMATIONS = {
667
+ idle: { row: 0, durations: [280, 110, 110, 140, 140, 320] },
668
+ "running-right": {
669
+ row: 1,
670
+ durations: [120, 120, 120, 120, 120, 120, 120, 220]
671
+ },
672
+ "running-left": {
673
+ row: 2,
674
+ durations: [120, 120, 120, 120, 120, 120, 120, 220]
675
+ },
676
+ waving: { row: 3, durations: [140, 140, 140, 280] },
677
+ jumping: { row: 4, durations: [140, 140, 140, 140, 280] },
678
+ failed: { row: 5, durations: [140, 140, 140, 140, 140, 140, 140, 240] },
679
+ waiting: { row: 6, durations: [150, 150, 150, 150, 150, 260] },
680
+ running: { row: 7, durations: [120, 120, 120, 120, 120, 220] },
681
+ review: { row: 8, durations: [150, 150, 150, 150, 150, 280] }
682
+ };
683
+ var IDLE = { pose: "idle", title: "", text: "" };
684
+ function selectActivity(sessions, current) {
685
+ const ordered = [...sessions].sort(
686
+ (a, b) => Number(b.id === current) - Number(a.id === current)
687
+ );
688
+ const target = ordered.find((s) => s.waiting) ?? ordered.find((s) => s.error) ?? ordered.find((s) => s.completed) ?? ordered.find((s) => s.running);
689
+ if (!target) return IDLE;
690
+ return {
691
+ pose: target.waiting ? "waiting" : target.error ? "failed" : target.completed ? "review" : "running",
692
+ title: target.title ?? "\u5F53\u524D\u4EFB\u52A1",
693
+ text: target.waiting ? "\u7B49\u5F85\u4F60\u5904\u7406" : target.error ? "\u4EFB\u52A1\u51FA\u9519\u4E86" : target.completed ? "\u5DF2\u5B8C\u6210\uFF0C\u5F85\u4F60\u67E5\u770B" : "\u6B63\u5728\u5DE5\u4F5C",
694
+ sessionId: target.id
695
+ };
696
+ }
697
+ function lookCell(dx, dy) {
698
+ if (Math.hypot(dx, dy) < 28) return null;
699
+ const index = Math.round(
700
+ (Math.atan2(dx, -dy) + Math.PI * 2) % (Math.PI * 2) / (Math.PI / 8)
701
+ ) % 16;
702
+ return { row: 9 + Math.floor(index / 8), col: index % 8 };
703
+ }
704
+
705
+ // src/plugin-update-ui.tsx
706
+ var import_jsx_runtime = require("react/jsx-runtime");
707
+ var UPDATE_ICON_PATHS = {
708
+ refresh: ["M13.5 5.5V2.5m0 0h-3m3 0-2.1 2.1A5.5 5.5 0 1 0 13.2 12"],
709
+ download: ["M8 2v8m0 0 3-3m-3 3-3-3M3 13v2h10v-2"],
710
+ copy: ["M5 5h8v8H5z", "M3 3h8"],
711
+ close: ["m4 4 8 8M12 4 4 12"]
712
+ };
713
+ function createPluginUpdateIcon(name2) {
714
+ const element = document.createElement("span");
715
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
716
+ svg.setAttribute("viewBox", "0 0 16 16");
717
+ svg.setAttribute("width", "16");
718
+ svg.setAttribute("height", "16");
719
+ svg.setAttribute("fill", "none");
720
+ svg.setAttribute("stroke", "currentColor");
721
+ svg.setAttribute("stroke-width", "1.5");
722
+ svg.setAttribute("stroke-linecap", "round");
723
+ svg.setAttribute("stroke-linejoin", "round");
724
+ svg.setAttribute("aria-hidden", "true");
725
+ for (const d of UPDATE_ICON_PATHS[name2]) {
726
+ const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
727
+ path.setAttribute("d", d);
728
+ svg.append(path);
729
+ }
730
+ element.append(svg);
731
+ return element;
732
+ }
733
+ function PluginUpdateHeader({ locale }) {
734
+ const language = (0, import_react2.useSyncExternalStore)(
735
+ (fn) => locale?.subscribe(fn) ?? (() => {
736
+ }),
737
+ () => locale?.getSnapshot().active ?? "zh"
738
+ );
739
+ const zh2 = /^zh(?:-|$)/i.test(language);
740
+ const root = (0, import_react2.useRef)(null);
741
+ (0, import_react2.useEffect)(() => {
742
+ if (!root.current) return;
743
+ return observePluginUpdate({
744
+ language,
745
+ root: root.current,
746
+ endpoint: `${BASE}/api/update`,
747
+ packageName: "@michengai/dsh-codex-pet",
748
+ titleRowSelector: ".dcp-project-head",
749
+ linksSelector: ".dcp-project-links",
750
+ zhName: "\u5BA0\u7269",
751
+ enName: "Pets",
752
+ createIcon: createPluginUpdateIcon
753
+ });
754
+ }, [language]);
755
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
756
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `.dcp-project-head{display:flex;align-items:center;justify-content:flex-start;gap:8px 12px;flex-wrap:wrap;margin-bottom:24px}.dcp-project-head h1{display:inline-flex;align-items:baseline;margin:0;white-space:nowrap}.dcp-version{font-size:12px;font-weight:500;line-height:18px;color:var(--dsw-alias-label-tertiary,#9da1aa);margin-left:10px}.dcp-project-links{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.dcp-project-links a,.dcp-project-links button{display:inline-flex;align-items:center;justify-content:center;gap:5px;box-sizing:border-box;min-height:28px;padding:0 8px;border:1px solid var(--dsw-alias-border-l2,#383838);border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary,inherit);font-family:inherit;font-size:12px;font-weight:500;line-height:18px;text-decoration:none;white-space:nowrap;cursor:pointer}.dcp-project-links a:hover,.dcp-project-links button:hover{background:var(--dsw-alias-interactive-bg-hover,#ffffff0a);color:var(--dsw-alias-label-primary,inherit)}.dcp-project-links a:focus-visible,.dcp-project-links button:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4f8cff);outline-offset:2px}.dcp-project-links svg{display:block;flex:none;width:16px;height:16px}` }),
757
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", { ref: root, className: "dcp-project-head", children: [
758
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h1", { children: [
759
+ zh2 ? "\u5BA0\u7269" : "Pets",
760
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dcp-version", children: [
761
+ "v",
762
+ "0.1.1"
763
+ ] })
764
+ ] }),
765
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("nav", { className: "dcp-project-links", children: [
766
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
767
+ "a",
768
+ {
769
+ href: "https://github.com/MichengAI/dsh-codex-pet",
770
+ target: "_blank",
771
+ rel: "noreferrer",
772
+ children: [
773
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GithubMark16, {}),
774
+ "GitHub"
775
+ ]
776
+ }
777
+ ),
778
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
779
+ "a",
780
+ {
781
+ href: "https://github.com/MichengAI/dsh-codex-pet/issues",
782
+ target: "_blank",
783
+ rel: "noreferrer",
784
+ children: [
785
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FeedbackMark16, {}),
786
+ zh2 ? "\u95EE\u9898\u53CD\u9988" : "Issues"
787
+ ]
788
+ }
789
+ )
790
+ ] })
791
+ ] })
792
+ ] });
793
+ }
794
+
795
+ // src/pet-locales.ts
796
+ var zh = {
797
+ codex: ["Codex", "\u6700\u521D\u7684 Codex \u5C0F\u4F19\u4F34\u3002"],
798
+ dewey: ["\u9732\u9732", "\u5B89\u9759\u966A\u4F34\uFF0C\u8BA9\u4F60\u4E13\u6CE8\u6BCF\u4E00\u5929\u3002"],
799
+ fireball: ["\u5C0F\u706B\u7403", "\u6D3B\u529B\u6EE1\u6EE1\uFF0C\u966A\u4F60\u5FEB\u901F\u63A8\u8FDB\u3002"],
800
+ hoots: ["\u5495\u5495", "\u76EE\u5149\u654F\u9510\u7684\u5C0F\u732B\u5934\u9E70\uFF0C\u966A\u4F60\u6253\u78E8\u6BCF\u4E2A\u7EC6\u8282\u3002"],
801
+ rocky: ["\u5C0F\u77F3\u5934", "\u6539\u52A8\u518D\u591A\uFF0C\u4E5F\u6709\u7A33\u7A33\u7684\u966A\u4F34\u3002"],
802
+ seedy: ["\u5C0F\u82BD", "\u4E00\u70B9\u65B0\u7EFF\uFF0C\u966A\u65B0\u60F3\u6CD5\u6162\u6162\u53D1\u82BD\u3002"],
803
+ stacky: ["\u53E0\u53E0", "\u7A33\u7A33\u53E0\u597D\uFF0C\u5B89\u5FC3\u6295\u5165\u6DF1\u5EA6\u5DE5\u4F5C\u3002"],
804
+ bsod: ["\u84DD\u5C4F\u5C0F\u7CBE\u7075", "\u4F4F\u5728\u5C0F\u84DD\u5C4F\u91CC\u7684\u8C03\u76AE\u7CBE\u7075\u3002"],
805
+ "null-signal": ["\u7A7A\u4FE1\u53F7", "\u6765\u81EA\u865A\u7A7A\u7684\u4E00\u70B9\u5B89\u9759\u56DE\u5E94\u3002"]
806
+ };
807
+ function localizePet(pet, locale) {
808
+ if (pet.source !== "builtin") return pet;
809
+ const entry = BUILTINS.find(([id]) => id === pet.id);
810
+ if (!entry) return pet;
811
+ const [name2, description] = /^zh(?:-|$)/i.test(locale) ? zh[entry[0]] : [entry[1], entry[2]];
812
+ return { ...pet, name: name2, description };
813
+ }
814
+
815
+ // node_modules/@radix-ui/react-icons/dist/react-icons.esm.js
816
+ var import_react3 = require("react");
817
+ function _objectWithoutPropertiesLoose(source, excluded) {
818
+ if (source == null) return {};
819
+ var target = {};
820
+ var sourceKeys = Object.keys(source);
821
+ var key, i;
822
+ for (i = 0; i < sourceKeys.length; i++) {
823
+ key = sourceKeys[i];
824
+ if (excluded.indexOf(key) >= 0) continue;
825
+ target[key] = source[key];
826
+ }
827
+ return target;
828
+ }
829
+ var _excluded$i = ["color"];
830
+ var ArrowTopRightIcon = /* @__PURE__ */ (0, import_react3.forwardRef)(function(_ref, forwardedRef) {
831
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$i);
832
+ return (0, import_react3.createElement)("svg", Object.assign({
833
+ width: "15",
834
+ height: "15",
835
+ viewBox: "0 0 15 15",
836
+ fill: "none",
837
+ xmlns: "http://www.w3.org/2000/svg"
838
+ }, props, {
839
+ ref: forwardedRef
840
+ }), (0, import_react3.createElement)("path", {
841
+ d: "M3.64645 11.3536C3.45118 11.1583 3.45118 10.8417 3.64645 10.6465L10.2929 4L6 4C5.72386 4 5.5 3.77614 5.5 3.5C5.5 3.22386 5.72386 3 6 3L11.5 3C11.6326 3 11.7598 3.05268 11.8536 3.14645C11.9473 3.24022 12 3.36739 12 3.5L12 9.00001C12 9.27615 11.7761 9.50001 11.5 9.50001C11.2239 9.50001 11 9.27615 11 9.00001V4.70711L4.35355 11.3536C4.15829 11.5488 3.84171 11.5488 3.64645 11.3536Z",
842
+ fill: color,
843
+ fillRule: "evenodd",
844
+ clipRule: "evenodd"
845
+ }));
846
+ });
847
+ var _excluded$W = ["color"];
848
+ var ChevronDownIcon = /* @__PURE__ */ (0, import_react3.forwardRef)(function(_ref, forwardedRef) {
849
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$W);
850
+ return (0, import_react3.createElement)("svg", Object.assign({
851
+ width: "15",
852
+ height: "15",
853
+ viewBox: "0 0 15 15",
854
+ fill: "none",
855
+ xmlns: "http://www.w3.org/2000/svg"
856
+ }, props, {
857
+ ref: forwardedRef
858
+ }), (0, import_react3.createElement)("path", {
859
+ d: "M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z",
860
+ fill: color,
861
+ fillRule: "evenodd",
862
+ clipRule: "evenodd"
863
+ }));
864
+ });
865
+ var _excluded$1r = ["color"];
866
+ var Cross2Icon = /* @__PURE__ */ (0, import_react3.forwardRef)(function(_ref, forwardedRef) {
867
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$1r);
868
+ return (0, import_react3.createElement)("svg", Object.assign({
869
+ width: "15",
870
+ height: "15",
871
+ viewBox: "0 0 15 15",
872
+ fill: "none",
873
+ xmlns: "http://www.w3.org/2000/svg"
874
+ }, props, {
875
+ ref: forwardedRef
876
+ }), (0, import_react3.createElement)("path", {
877
+ d: "M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z",
878
+ fill: color,
879
+ fillRule: "evenodd",
880
+ clipRule: "evenodd"
881
+ }));
882
+ });
883
+ var _excluded$3a = ["color"];
884
+ var MixerHorizontalIcon = /* @__PURE__ */ (0, import_react3.forwardRef)(function(_ref, forwardedRef) {
885
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$3a);
886
+ return (0, import_react3.createElement)("svg", Object.assign({
887
+ width: "15",
888
+ height: "15",
889
+ viewBox: "0 0 15 15",
890
+ fill: "none",
891
+ xmlns: "http://www.w3.org/2000/svg"
892
+ }, props, {
893
+ ref: forwardedRef
894
+ }), (0, import_react3.createElement)("path", {
895
+ d: "M5.5 3C4.67157 3 4 3.67157 4 4.5C4 5.32843 4.67157 6 5.5 6C6.32843 6 7 5.32843 7 4.5C7 3.67157 6.32843 3 5.5 3ZM3 5C3.01671 5 3.03323 4.99918 3.04952 4.99758C3.28022 6.1399 4.28967 7 5.5 7C6.71033 7 7.71978 6.1399 7.95048 4.99758C7.96677 4.99918 7.98329 5 8 5H13.5C13.7761 5 14 4.77614 14 4.5C14 4.22386 13.7761 4 13.5 4H8C7.98329 4 7.96677 4.00082 7.95048 4.00242C7.71978 2.86009 6.71033 2 5.5 2C4.28967 2 3.28022 2.86009 3.04952 4.00242C3.03323 4.00082 3.01671 4 3 4H1.5C1.22386 4 1 4.22386 1 4.5C1 4.77614 1.22386 5 1.5 5H3ZM11.9505 10.9976C11.7198 12.1399 10.7103 13 9.5 13C8.28967 13 7.28022 12.1399 7.04952 10.9976C7.03323 10.9992 7.01671 11 7 11H1.5C1.22386 11 1 10.7761 1 10.5C1 10.2239 1.22386 10 1.5 10H7C7.01671 10 7.03323 10.0008 7.04952 10.0024C7.28022 8.8601 8.28967 8 9.5 8C10.7103 8 11.7198 8.8601 11.9505 10.0024C11.9668 10.0008 11.9833 10 12 10H13.5C13.7761 10 14 10.2239 14 10.5C14 10.7761 13.7761 11 13.5 11H12C11.9833 11 11.9668 10.9992 11.9505 10.9976ZM8 10.5C8 9.67157 8.67157 9 9.5 9C10.3284 9 11 9.67157 11 10.5C11 11.3284 10.3284 12 9.5 12C8.67157 12 8 11.3284 8 10.5Z",
896
+ fill: color,
897
+ fillRule: "evenodd",
898
+ clipRule: "evenodd"
899
+ }));
900
+ });
901
+ var _excluded$3A = ["color"];
902
+ var QuestionMarkCircledIcon = /* @__PURE__ */ (0, import_react3.forwardRef)(function(_ref, forwardedRef) {
903
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$3A);
904
+ return (0, import_react3.createElement)("svg", Object.assign({
905
+ width: "15",
906
+ height: "15",
907
+ viewBox: "0 0 15 15",
908
+ fill: "none",
909
+ xmlns: "http://www.w3.org/2000/svg"
910
+ }, props, {
911
+ ref: forwardedRef
912
+ }), (0, import_react3.createElement)("path", {
913
+ d: "M0.877075 7.49972C0.877075 3.84204 3.84222 0.876892 7.49991 0.876892C11.1576 0.876892 14.1227 3.84204 14.1227 7.49972C14.1227 11.1574 11.1576 14.1226 7.49991 14.1226C3.84222 14.1226 0.877075 11.1574 0.877075 7.49972ZM7.49991 1.82689C4.36689 1.82689 1.82708 4.36671 1.82708 7.49972C1.82708 10.6327 4.36689 13.1726 7.49991 13.1726C10.6329 13.1726 13.1727 10.6327 13.1727 7.49972C13.1727 4.36671 10.6329 1.82689 7.49991 1.82689ZM8.24993 10.5C8.24993 10.9142 7.91414 11.25 7.49993 11.25C7.08571 11.25 6.74993 10.9142 6.74993 10.5C6.74993 10.0858 7.08571 9.75 7.49993 9.75C7.91414 9.75 8.24993 10.0858 8.24993 10.5ZM6.05003 6.25C6.05003 5.57211 6.63511 4.925 7.50003 4.925C8.36496 4.925 8.95003 5.57211 8.95003 6.25C8.95003 6.74118 8.68002 6.99212 8.21447 7.27494C8.16251 7.30651 8.10258 7.34131 8.03847 7.37854L8.03841 7.37858C7.85521 7.48497 7.63788 7.61119 7.47449 7.73849C7.23214 7.92732 6.95003 8.23198 6.95003 8.7C6.95004 9.00376 7.19628 9.25 7.50004 9.25C7.8024 9.25 8.04778 9.00601 8.05002 8.70417L8.05056 8.7033C8.05924 8.6896 8.08493 8.65735 8.15058 8.6062C8.25207 8.52712 8.36508 8.46163 8.51567 8.37436L8.51571 8.37433C8.59422 8.32883 8.68296 8.27741 8.78559 8.21506C9.32004 7.89038 10.05 7.35382 10.05 6.25C10.05 4.92789 8.93511 3.825 7.50003 3.825C6.06496 3.825 4.95003 4.92789 4.95003 6.25C4.95003 6.55376 5.19628 6.8 5.50003 6.8C5.80379 6.8 6.05003 6.55376 6.05003 6.25Z",
914
+ fill: color,
915
+ fillRule: "evenodd",
916
+ clipRule: "evenodd"
917
+ }));
918
+ });
919
+ var _excluded$3E = ["color"];
920
+ var ReloadIcon = /* @__PURE__ */ (0, import_react3.forwardRef)(function(_ref, forwardedRef) {
921
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$3E);
922
+ return (0, import_react3.createElement)("svg", Object.assign({
923
+ width: "15",
924
+ height: "15",
925
+ viewBox: "0 0 15 15",
926
+ fill: "none",
927
+ xmlns: "http://www.w3.org/2000/svg"
928
+ }, props, {
929
+ ref: forwardedRef
930
+ }), (0, import_react3.createElement)("path", {
931
+ d: "M1.84998 7.49998C1.84998 4.66458 4.05979 1.84998 7.49998 1.84998C10.2783 1.84998 11.6515 3.9064 12.2367 5H10.5C10.2239 5 10 5.22386 10 5.5C10 5.77614 10.2239 6 10.5 6H13.5C13.7761 6 14 5.77614 14 5.5V2.5C14 2.22386 13.7761 2 13.5 2C13.2239 2 13 2.22386 13 2.5V4.31318C12.2955 3.07126 10.6659 0.849976 7.49998 0.849976C3.43716 0.849976 0.849976 4.18537 0.849976 7.49998C0.849976 10.8146 3.43716 14.15 7.49998 14.15C9.44382 14.15 11.0622 13.3808 12.2145 12.2084C12.8315 11.5806 13.3133 10.839 13.6418 10.0407C13.7469 9.78536 13.6251 9.49315 13.3698 9.38806C13.1144 9.28296 12.8222 9.40478 12.7171 9.66014C12.4363 10.3425 12.0251 10.9745 11.5013 11.5074C10.5295 12.4963 9.16504 13.15 7.49998 13.15C4.05979 13.15 1.84998 10.3354 1.84998 7.49998Z",
932
+ fill: color,
933
+ fillRule: "evenodd",
934
+ clipRule: "evenodd"
935
+ }));
936
+ });
937
+ var _excluded$3F = ["color"];
938
+ var ResetIcon = /* @__PURE__ */ (0, import_react3.forwardRef)(function(_ref, forwardedRef) {
939
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$3F);
940
+ return (0, import_react3.createElement)("svg", Object.assign({
941
+ width: "15",
942
+ height: "15",
943
+ viewBox: "0 0 15 15",
944
+ fill: "none",
945
+ xmlns: "http://www.w3.org/2000/svg"
946
+ }, props, {
947
+ ref: forwardedRef
948
+ }), (0, import_react3.createElement)("path", {
949
+ d: "M4.85355 2.14645C5.04882 2.34171 5.04882 2.65829 4.85355 2.85355L3.70711 4H9C11.4853 4 13.5 6.01472 13.5 8.5C13.5 10.9853 11.4853 13 9 13H5C4.72386 13 4.5 12.7761 4.5 12.5C4.5 12.2239 4.72386 12 5 12H9C10.933 12 12.5 10.433 12.5 8.5C12.5 6.567 10.933 5 9 5H3.70711L4.85355 6.14645C5.04882 6.34171 5.04882 6.65829 4.85355 6.85355C4.65829 7.04882 4.34171 7.04882 4.14645 6.85355L2.14645 4.85355C1.95118 4.65829 1.95118 4.34171 2.14645 4.14645L4.14645 2.14645C4.34171 1.95118 4.65829 1.95118 4.85355 2.14645Z",
950
+ fill: color,
951
+ fillRule: "evenodd",
952
+ clipRule: "evenodd"
953
+ }));
954
+ });
955
+ var _excluded$4d = ["color"];
956
+ var StopIcon = /* @__PURE__ */ (0, import_react3.forwardRef)(function(_ref, forwardedRef) {
957
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$4d);
958
+ return (0, import_react3.createElement)("svg", Object.assign({
959
+ width: "15",
960
+ height: "15",
961
+ viewBox: "0 0 15 15",
962
+ fill: "none",
963
+ xmlns: "http://www.w3.org/2000/svg"
964
+ }, props, {
965
+ ref: forwardedRef
966
+ }), (0, import_react3.createElement)("path", {
967
+ d: "M2 3C2 2.44772 2.44772 2 3 2H12C12.5523 2 13 2.44772 13 3V12C13 12.5523 12.5523 13 12 13H3C2.44772 13 2 12.5523 2 12V3ZM12 3H3V12H12V3Z",
968
+ fill: color,
969
+ fillRule: "evenodd",
970
+ clipRule: "evenodd"
971
+ }));
972
+ });
973
+
974
+ // src/notification-tray.tsx
975
+ var import_react4 = require("react");
976
+ var import_jsx_runtime2 = require("react/jsx-runtime");
977
+ function RequestForm({ item, command, language }) {
978
+ const t = translator(language ?? "zh");
979
+ const [answers, setAnswers] = (0, import_react4.useState)({ answers: (item.request?.questions ?? []).map((q) => ({ id: q.id, selected: [] })) });
980
+ const [busy, setBusy] = (0, import_react4.useState)(false), [error, setError] = (0, import_react4.useState)("");
981
+ const request2 = item.request;
982
+ const run = async (value) => {
983
+ setBusy(true);
984
+ setError("");
985
+ try {
986
+ await command(value);
987
+ } catch (e) {
988
+ setError(e instanceof Error ? e.message : t("\u63D0\u4EA4\u5931\u8D25"));
989
+ } finally {
990
+ setBusy(false);
991
+ }
992
+ };
993
+ const base = { id: item.id, token: item.token, requestKey: request2.key };
994
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dcp-request", children: [
995
+ request2.kind === "approval" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
996
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: request2.toolName ?? t("\u5DE5\u5177\u5BA1\u6279") }),
997
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: request2.reason ?? t("\u6B64\u5DE5\u5177\u9700\u8981\u4F60\u7684\u6279\u51C6\u3002") }),
998
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { disabled: busy, onClick: () => void run({ ...base, type: "reject" }), children: t("\u62D2\u7EDD") }),
999
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { disabled: busy, onClick: () => void run({ ...base, type: "approve" }), children: t("\u4EC5\u5141\u8BB8\u4E00\u6B21") })
1000
+ ] }) : request2.questions ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: (event) => {
1001
+ event.preventDefault();
1002
+ void run({ ...base, type: "answer", answers });
1003
+ }, children: [
1004
+ request2.questions.map((q, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("fieldset", { disabled: busy, children: [
1005
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("legend", { children: q.question }),
1006
+ q.detail && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("pre", { children: q.detail }),
1007
+ q.options?.map((option) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
1008
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: q.multiSelect ? "checkbox" : "radio", name: q.id, checked: answers.answers[index].selected.includes(option.label), onChange: (event) => setAnswers((old) => ({ answers: old.answers.map((a, i) => i !== index ? a : { ...a, custom: q.multiSelect ? a.custom : "", selected: q.multiSelect ? event.target.checked ? [...a.selected, option.label] : a.selected.filter((v) => v !== option.label) : [option.label] }) })) }),
1009
+ option.label,
1010
+ option.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("small", { children: option.description })
1011
+ ] }, option.label)),
1012
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("textarea", { "aria-label": t("{question}\uFF1A\u6587\u5B57\u56DE\u7B54", { question: q.question }), value: answers.answers[index].custom ?? "", maxLength: 1e4, placeholder: t("\u8F93\u5165\u56DE\u7B54\u6216\u8865\u5145\u8BF4\u660E"), onChange: (event) => setAnswers((old) => ({ answers: old.answers.map((a, i) => i !== index ? a : { ...a, selected: q.multiSelect ? a.selected : [], custom: event.target.value }) })) })
1013
+ ] }, q.id)),
1014
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { disabled: busy, type: "submit", children: t("\u63D0\u4EA4\u56DE\u7B54") })
1015
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: t("\u8BF7\u6253\u5F00\u4F1A\u8BDD\u5904\u7406\u6B64\u8BF7\u6C42\u3002") }),
1016
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { role: "alert", children: t(error) })
1017
+ ] });
1018
+ }
1019
+ function NotificationTray({ state, command, language }) {
1020
+ const t = translator(language ?? "zh");
1021
+ const [expanded, setExpanded] = (0, import_react4.useState)(false), [detail, setDetail] = (0, import_react4.useState)(null);
1022
+ const [error, setError] = (0, import_react4.useState)("");
1023
+ const [latest, setLatest] = (0, import_react4.useState)(false);
1024
+ const run = async (value) => {
1025
+ setError("");
1026
+ try {
1027
+ await command(value);
1028
+ } catch (e) {
1029
+ setError(e instanceof Error ? e.message : t("\u64CD\u4F5C\u5931\u8D25"));
1030
+ }
1031
+ };
1032
+ const visible = expanded ? state.items : state.items.slice(0, 1);
1033
+ if (state.items.length === 0) return null;
1034
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: "dcp-tray", "aria-label": t("\u5BA0\u7269\u4F1A\u8BDD\u901A\u77E5"), children: [
1035
+ state.items.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("header", { className: "dcp-tray-toolbar", children: [
1036
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { className: "dcp-tray-toggle", "aria-label": expanded ? t("\u6536\u8D77\u4F1A\u8BDD") : t("\u5C55\u5F00\u4F1A\u8BDD"), "aria-expanded": expanded, onClick: () => setExpanded(!expanded), children: [
1037
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("\u4F1A\u8BDD") }),
1038
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dcp-tray-count", children: state.items.length }),
1039
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronDownIcon, { className: expanded ? "is-expanded" : "" })
1040
+ ] }),
1041
+ expanded && state.items.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "dcp-tray-sort", "aria-label": t("\u6700\u65B0\u4F18\u5148"), "aria-pressed": latest, title: latest ? t("\u6700\u65B0\u6D3B\u52A8\u4F18\u5148") : t("\u5F85\u5904\u7406\u4E8B\u9879\u4F18\u5148"), onClick: () => {
1042
+ setLatest(!latest);
1043
+ void run({ type: "sort", latest: !latest });
1044
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MixerHorizontalIcon, {}) })
1045
+ ] }),
1046
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dcp-notice-list", role: "list", children: visible.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("article", { role: "listitem", "data-status": item.pose, children: [
1047
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "dcp-notice-dismiss", "aria-label": t("\u5173\u95ED\u901A\u77E5\uFF1A{title}", { title: item.title }), title: t("\u5173\u95ED\u672C\u8F6E\u63D0\u9192\uFF0C\u4EFB\u52A1\u7EE7\u7EED\u8FD0\u884C"), onClick: () => void run({ type: "dismiss", id: item.id, token: item.token }), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Cross2Icon, {}) }),
1048
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dcp-notice-card", children: [
1049
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { className: "dcp-bubble-link", title: item.title, onClick: () => void run({ type: "open", id: item.id, token: item.token }), children: [
1050
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: item.title }),
1051
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t(item.text) })
1052
+ ] }),
1053
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dcp-notice-actions", children: [
1054
+ item.request ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "dcp-notice-action", "aria-label": t("\u5904\u7406\u8BF7\u6C42\uFF1A{title}", { title: item.title }), title: t("\u67E5\u770B\u5E76\u5904\u7406"), "aria-expanded": detail === item.request.key, onClick: () => {
1055
+ setExpanded(true);
1056
+ setDetail(detail === item.request.key ? null : item.request.key);
1057
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(QuestionMarkCircledIcon, {}) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "dcp-notice-action", "aria-label": t("\u56DE\u590D\u4F1A\u8BDD\uFF1A{title}", { title: item.title }), title: t("\u6253\u5F00\u4F1A\u8BDD\u56DE\u590D"), onClick: () => void run({ type: "open", id: item.id, token: item.token }), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ResetIcon, {}) }),
1058
+ item.pose === "running" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "dcp-notice-action", "aria-label": t("\u505C\u6B62\u5F53\u524D\u8F6E\u6B21\uFF1A{title}", { title: item.title }), title: t("\u505C\u6B62\u5F53\u524D\u8F6E\u6B21"), onClick: () => void run({ type: "stop", id: item.id, token: item.token }), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StopIcon, {}) })
1059
+ ] })
1060
+ ] }),
1061
+ item.request && detail === item.request.key && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RequestForm, { item, command, language }, item.request.key)
1062
+ ] }, item.id)) }),
1063
+ !expanded && state.items.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { onClick: () => setExpanded(true), children: t("\u8FD8\u6709 {count} \u4E2A\u4F1A\u8BDD", { count: state.items.length - 1 }) }),
1064
+ expanded && state.hidden > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { onClick: () => void run({ type: "restore" }), children: t("\u6062\u590D {count} \u6761\u5DF2\u5173\u95ED\u901A\u77E5", { count: state.hidden }) }),
1065
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { role: "alert", children: t(error) })
1066
+ ] });
1067
+ }
1068
+ var trayStyles = `.dcp-tray{pointer-events:auto;position:absolute;right:var(--tray-right,0);left:var(--tray-left,auto);top:var(--tray-top,auto);bottom:var(--tray-bottom,calc(100% + 12px));width:min(296px,calc(100vw - 24px));max-height:var(--tray-height,360px);display:flex;flex-direction:column;overflow:auto;background:var(--pet-card);color:var(--pet-text);border:1px solid var(--pet-line);border-radius:16px;padding:10px;box-shadow:0 6px 28px #0003;font-size:12px}.dcp-tray header,.dcp-notice-heading{display:flex;justify-content:space-between;gap:6px;align-items:center}.dcp-tray article{border-top:1px solid var(--pet-line);padding:8px 0}.dcp-tray button{border-radius:7px;padding:6px!important;white-space:normal;text-align:left}.dcp-tray strong,.dcp-tray span{display:block;overflow-wrap:anywhere}.dcp-tray span,.dcp-tray small{color:var(--pet-muted)}.dcp-tray .dcp-bubble-link{min-width:0;flex:1}.dcp-tray fieldset{min-width:0;border:1px solid var(--pet-line);margin:8px 0;padding:8px}.dcp-tray label{display:block}.dcp-tray label small{display:block;padding-left:20px}.dcp-tray textarea,.dcp-tray select{width:100%;box-sizing:border-box;background:var(--pet-bg);color:var(--pet-text);border:1px solid var(--pet-line);padding:7px;border-radius:6px;font:inherit;margin:5px 0}.dcp-tray textarea{min-height:54px;resize:vertical}.dcp-tray pre{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit;max-height:180px;overflow:auto}.dcp-tray [role=alert]{color:#ef6565}.dcp-tray button:focus-visible,.dcp-tray input:focus-visible{outline:2px solid #4f8fff;outline-offset:2px}`;
1069
+ var polishedTrayStyles = `
1070
+ .dcp-tray{width:min(224px,calc(100vw - 24px));padding:6px;background:transparent;border:0;border-radius:0;box-shadow:none;overflow:auto;scrollbar-width:none;font-family:inherit}
1071
+ .dcp-tray .dcp-tray-toolbar{min-height:24px;padding:0 3px 3px;gap:8px}
1072
+ .dcp-tray .dcp-tray-toggle{display:flex;align-items:center;gap:6px;padding:3px 5px!important;color:var(--pet-muted);font-size:11px}.dcp-tray .dcp-tray-count{font-size:10px}.dcp-tray .dcp-tray-toggle svg{width:12px;height:12px;opacity:.65}.dcp-tray .dcp-tray-toggle svg.is-expanded{transform:rotate(180deg)}
1073
+ .dcp-tray .dcp-tray-sort{display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:5px!important;color:var(--pet-muted)}.dcp-tray-sort[aria-pressed=true]{background:color-mix(in srgb,var(--pet-text) 9%,transparent)}
1074
+ .dcp-tray article{position:relative;padding:0;border:0;margin:5px 0 10px}.dcp-tray article:last-child{margin-bottom:0}
1075
+ .dcp-tray .dcp-notice-card{display:flex;align-items:center;gap:5px;min-height:54px;padding:7px 10px 7px 19px;border-radius:28px;border:1px solid color-mix(in srgb,var(--pet-text) 14%,transparent);background:linear-gradient(180deg,color-mix(in srgb,var(--pet-text) 2%,transparent),transparent),var(--pet-card);box-shadow:inset 0 1px 0 color-mix(in srgb,var(--pet-text) 8%,transparent),0 5px 12px #0003}
1076
+ .dcp-tray .dcp-bubble-link{display:block;min-width:0;flex:1;padding:0!important;border-radius:4px;line-height:1.35}.dcp-tray .dcp-bubble-link:hover{background:transparent}.dcp-tray .dcp-bubble-link strong{font-size:12px;font-weight:600;line-height:1.4;color:var(--pet-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dcp-tray .dcp-bubble-link>span{font-size:11px;line-height:1.4;margin-top:1px;color:var(--pet-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
1077
+ .dcp-tray .dcp-notice-actions{display:flex;align-items:center;flex-shrink:0;gap:6px}.dcp-tray .dcp-notice-action{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:28px;height:28px;padding:6px!important;border-radius:50%;background:color-mix(in srgb,var(--pet-text) 8%,transparent);color:var(--pet-muted)}.dcp-tray .dcp-notice-action svg{width:15px;height:15px}.dcp-tray .dcp-notice-action:hover{background:color-mix(in srgb,var(--pet-text) 15%,transparent);color:var(--pet-text)}
1078
+ .dcp-tray .dcp-notice-dismiss{position:absolute;z-index:1;left:-3px;top:-3px;display:flex;align-items:center;justify-content:center;width:19px;height:19px;padding:4px!important;border-radius:50%;border:1px solid color-mix(in srgb,var(--pet-text) 22%,transparent);background:var(--pet-bg);color:var(--pet-muted)}.dcp-tray .dcp-notice-dismiss svg{width:10px;height:10px}.dcp-tray .dcp-notice-dismiss:hover{background:var(--pet-card);color:var(--pet-text)}
1079
+ .dcp-tray .dcp-request{margin-top:7px;padding:10px;background:var(--pet-card);border:1px solid var(--pet-line);border-radius:14px}.dcp-tray .dcp-request p{overflow-wrap:anywhere}.dcp-tray .dcp-request button{background:color-mix(in srgb,var(--pet-text) 6%,transparent);margin:3px}
1080
+ `;
1081
+
1082
+ // src/ui.tsx
1083
+ var import_react5 = require("react");
1084
+
1085
+ // src/styles.ts
1086
+ var styles = `
1087
+ .dcp{--pet-bg:var(--dsw-alias-bg-base,#181818);--pet-card:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#242424));--pet-line:var(--dsw-alias-border-l2,#343434);--pet-text:var(--dsw-alias-label-primary,#d7d7d7);--pet-muted:var(--dsw-alias-label-secondary,#929292);font-family:Arial,"Microsoft YaHei",sans-serif;color:var(--pet-text);font-size:13px;line-height:1.45;color-scheme:inherit}
1088
+ .dcp *{box-sizing:border-box}.dcp button,.dcp input,.dcp textarea{font:inherit}.dcp button{border:0;color:var(--pet-text);background:transparent;cursor:pointer}.dcp button:disabled{opacity:.4;cursor:default}.dcp button:focus-visible,.dcp input:focus-visible,.dcp textarea:focus-visible{outline:2px solid #9bc8ff;outline-offset:3px}.dcp button:hover:not(:disabled){background:color-mix(in srgb,var(--pet-text) 8%,transparent)}
1089
+ .dcp-page{max-width:768px;margin:0 auto;padding:0 0 32px}.dcp-page h1{font-size:24px;font-weight:600;margin:0 0 32px;line-height:1.3}.dcp-page h2{font-size:14px;font-weight:600;margin:0}.dcp-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:12px}.dcp-sub{color:var(--pet-muted);margin:4px 0 0;font-size:12px}.dcp-actions{display:flex;align-items:center;gap:8px}.dcp .dcp-button{border-radius:7px;padding:5px 9px;background:color-mix(in srgb,var(--pet-text) 3%,transparent);white-space:nowrap;font-weight:500}.dcp .dcp-icon{display:inline-flex;align-items:center;justify-content:center;padding:6px;border-radius:6px}.dcp svg{width:16px;height:16px;flex-shrink:0}
1090
+ .dcp-card{border:1px solid var(--pet-line);border-radius:16px;background:var(--pet-card);overflow:hidden;padding:0 16px}.dcp-row{display:flex;align-items:center;gap:18px;min-height:88px;border-bottom:1px solid var(--pet-line)}.dcp-preview{width:58px;flex-shrink:0;display:flex;justify-content:center;align-items:center}.dcp-info{flex:1;min-width:0}.dcp-name{font-size:13px;font-weight:600;margin-bottom:3px}.dcp-description{font-size:12px;color:var(--pet-muted);overflow-wrap:anywhere}.dcp-folder{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:12px 0}.dcp-path{font-family:Consolas,monospace;font-size:11px;color:var(--pet-muted);overflow-wrap:anywhere}.dcp .dcp-folder-button{display:flex;align-items:center;gap:6px;color:var(--pet-muted);white-space:nowrap}.dcp-appearance{margin-top:48px}.dcp-size{margin-top:14px;min-height:62px;display:flex;align-items:center;justify-content:space-between;padding:12px 16px}.dcp-size label{font-weight:600}.dcp-size input{width:160px;height:2px;accent-color:white;cursor:pointer}.dcp-size small{display:block;font-size:12px;color:var(--pet-muted);font-weight:400;margin-top:2px}.dcp-note{margin:12px 0;color:var(--pet-muted);font-size:12px}.dcp-error{padding:12px;border:1px solid #845344;border-radius:8px;color:#edb7a3;margin:12px 0;font-size:12px}.dcp-empty{padding:32px 0;text-align:center;color:var(--pet-muted)}
1091
+ .dcp-floating{position:fixed;z-index:2147483000;pointer-events:none}.dcp-pet-button{display:block!important;padding:0!important;background:transparent!important;touch-action:none;cursor:grab!important;pointer-events:auto;user-select:none;-webkit-user-select:none}.dcp-pet-button:active{cursor:grabbing!important}.dcp-sprite{background-repeat:no-repeat;pointer-events:none;flex-shrink:0}.dcp-bubble{position:absolute;bottom:calc(100% + 16px);right:0;min-width:160px;max-width:240px;width:max-content;padding:10px 16px!important;border:1px solid var(--pet-line)!important;border-radius:28px!important;background:var(--pet-card)!important;text-align:left;box-shadow:0 2px 12px #0002;pointer-events:auto}.dcp-bubble strong{display:block;max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:12px}.dcp-bubble span{display:block;font-size:12px;color:var(--pet-muted)}.dcp-menu{position:absolute;right:0;bottom:100%;width:160px;padding:6px;border:1px solid var(--pet-line);background:var(--pet-card);border-radius:10px;pointer-events:auto;box-shadow:0 8px 32px #0004}.dcp-menu button{display:block;width:100%;text-align:left;padding:8px;border-radius:5px}.dcp-menu hr{border:0;border-top:1px solid var(--pet-line);margin:5px}
1092
+ .dcp-dialog{color:var(--pet-text);background:var(--pet-card);border:1px solid var(--pet-line);border-radius:16px;width:min(480px,calc(100vw - 32px));padding:24px}.dcp-dialog::backdrop{background:#0008}.dcp-dialog h2{font-size:19px;margin:0 0 12px}.dcp-dialog textarea{display:block;resize:vertical;width:100%;min-height:120px;color:var(--pet-text);background:var(--pet-bg);border:1px solid var(--pet-line);border-radius:8px;padding:12px;margin:16px 0}.dcp-dialog footer{display:flex;justify-content:flex-end;gap:8px}.dcp-dialog .dcp-primary{background:#e6e6e6!important;color:#222!important}.dcp-creation{border-top:1px solid var(--pet-line);padding-top:12px;margin-top:12px}
1093
+ .dcp-light{--pet-bg:#fff;--pet-card:#f7f7f7;--pet-line:#e4e4e4;--pet-text:#252525;--pet-muted:#727272;color-scheme:light}.dcp-light.dcp-light .dcp-size input{accent-color:#222}
1094
+ .dcp-size input{-webkit-appearance:none;appearance:none;background:var(--pet-line);height:2px}.dcp-size input::-webkit-slider-thumb{-webkit-appearance:none;width:20px;height:20px;border-radius:50%;background:var(--pet-text)}
1095
+ @media(max-width:600px){.dcp-page h1{font-size:22px;margin-bottom:24px}.dcp-head{flex-wrap:wrap;gap:10px}.dcp-row{min-height:86px;gap:8px}.dcp-preview{width:44px}.dcp-description{font-size:11px}.dcp-card{padding:0 12px}.dcp-folder{align-items:flex-start}.dcp-folder-button{font-size:11px!important}.dcp-size{padding:12px}.dcp-size input{width:130px}.dcp-appearance{margin-top:32px}}
1096
+ @media(prefers-reduced-motion:reduce){.dcp *{animation:none!important;transition:none!important}}
1097
+ `;
1098
+
1099
+ // src/ui.tsx
1100
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1101
+ async function request(path, data) {
1102
+ const response = await fetch(`${BASE}/api/${path}`, {
1103
+ method: data === void 0 ? "GET" : "POST",
1104
+ headers: data === void 0 ? void 0 : { "content-type": "application/json", "x-dsh-pet": "1" },
1105
+ body: data === void 0 ? void 0 : JSON.stringify(data),
1106
+ signal: AbortSignal.timeout(15e3)
1107
+ });
1108
+ const result = await response.json();
1109
+ if (!response.ok) throw new Error(result.error ?? "\u5BA0\u7269\u670D\u52A1\u6682\u4E0D\u53EF\u7528");
1110
+ return result;
1111
+ }
1112
+ var libraryStore = createLibraryStore(request);
1113
+ function usePetController(locale) {
1114
+ const language = (0, import_react5.useSyncExternalStore)(
1115
+ (listener) => locale ? locale.subscribe(listener) : () => {
1116
+ },
1117
+ () => locale?.getSnapshot().active ?? "zh"
1118
+ );
1119
+ const { library, error } = (0, import_react5.useSyncExternalStore)(
1120
+ libraryStore.subscribe,
1121
+ libraryStore.getSnapshot
1122
+ );
1123
+ const localizedLibrary = (0, import_react5.useMemo)(
1124
+ () => library ? {
1125
+ ...library,
1126
+ pets: library.pets.map((pet) => localizePet(pet, language))
1127
+ } : null,
1128
+ [library, language]
1129
+ );
1130
+ return {
1131
+ library: localizedLibrary,
1132
+ language,
1133
+ error,
1134
+ update: (value) => libraryStore.run("config", value),
1135
+ refresh: () => libraryStore.run("refresh", {}),
1136
+ folder: () => libraryStore.run("open-folder", {})
1137
+ };
1138
+ }
1139
+ function Sprite({
1140
+ pet,
1141
+ size,
1142
+ pose = "idle",
1143
+ animate = false,
1144
+ look = null
1145
+ }) {
1146
+ const element = (0, import_react5.useRef)(null);
1147
+ (0, import_react5.useEffect)(() => {
1148
+ const node = element.current;
1149
+ if (!node) return;
1150
+ const animation = ANIMATIONS[pose];
1151
+ let frame = 0, last = null, id = 0;
1152
+ const reduced = window.matchMedia("(prefers-reduced-motion: reduce)");
1153
+ const paint = () => {
1154
+ const row = pet.version === 2 && look ? look.row : animation.row;
1155
+ const col = pet.version === 2 && look ? look.col : frame;
1156
+ node.style.backgroundPosition = `${-col * size}px ${-row * size * 208 / 192}px`;
1157
+ };
1158
+ paint();
1159
+ const tick = (time) => {
1160
+ if (last === null || document.hidden) last = time;
1161
+ if (!document.hidden && time - last >= animation.durations[frame]) {
1162
+ last = time;
1163
+ frame = (frame + 1) % animation.durations.length;
1164
+ paint();
1165
+ }
1166
+ id = requestAnimationFrame(tick);
1167
+ };
1168
+ if (animate && !look && !reduced.matches) id = requestAnimationFrame(tick);
1169
+ return () => cancelAnimationFrame(id);
1170
+ }, [pet.id, pet.version, size, pose, animate, look]);
1171
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1172
+ "div",
1173
+ {
1174
+ ref: element,
1175
+ className: "dcp-sprite",
1176
+ style: {
1177
+ width: size,
1178
+ height: size * 208 / 192,
1179
+ backgroundImage: `url("${pet.url}")`,
1180
+ backgroundSize: `${size * 8}px ${size * 208 / 192 * (pet.version === 2 ? 11 : 9)}px`
1181
+ }
1182
+ }
1183
+ );
1184
+ }
1185
+ function Settings({
1186
+ controller,
1187
+ create,
1188
+ locale
1189
+ }) {
1190
+ const t = translator(controller.language);
1191
+ const { library, error } = controller;
1192
+ const [busy, setBusy] = (0, import_react5.useState)(false), [showCreate, setShowCreate] = (0, import_react5.useState)(false), [description, setDescription] = (0, import_react5.useState)("");
1193
+ const [size, setSize] = (0, import_react5.useState)(library?.config.size ?? 120);
1194
+ const dialog = (0, import_react5.useRef)(null);
1195
+ const [creationError, setCreationError] = (0, import_react5.useState)("");
1196
+ (0, import_react5.useEffect)(() => {
1197
+ if (library) setSize(library.config.size);
1198
+ }, [library?.config.size]);
1199
+ (0, import_react5.useEffect)(() => {
1200
+ if (showCreate) dialog.current?.showModal();
1201
+ else dialog.current?.close();
1202
+ }, [showCreate]);
1203
+ const act = async (action) => {
1204
+ setBusy(true);
1205
+ try {
1206
+ await action();
1207
+ } catch {
1208
+ } finally {
1209
+ setBusy(false);
1210
+ }
1211
+ };
1212
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dcp dcp-page", children: [
1213
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: styles }),
1214
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PluginUpdateHeader, { locale }),
1215
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("header", { className: "dcp-head", children: [
1216
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
1217
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: t("\u9009\u62E9\u5BA0\u7269") }),
1218
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "dcp-sub", children: t("\u5BA0\u7269\u4F1A\u7BA1\u7406\u5BF9\u8BDD\u4E32\uFF0C\u5E76\u7A81\u51FA\u663E\u793A\u9700\u8981\u5173\u6CE8\u7684\u4E8B\u9879") })
1219
+ ] }),
1220
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dcp-actions", children: [
1221
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1222
+ "button",
1223
+ {
1224
+ className: "dcp-icon",
1225
+ title: t("\u5237\u65B0\u5BA0\u7269\u5E93"),
1226
+ "aria-label": t("\u5237\u65B0\u5BA0\u7269\u5E93"),
1227
+ disabled: busy,
1228
+ onClick: () => void act(controller.refresh),
1229
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ReloadIcon, {})
1230
+ }
1231
+ ),
1232
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1233
+ "button",
1234
+ {
1235
+ className: "dcp-button",
1236
+ disabled: !library || busy,
1237
+ onClick: () => setShowCreate(true),
1238
+ children: t("\u521B\u5EFA")
1239
+ }
1240
+ ),
1241
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1242
+ "button",
1243
+ {
1244
+ className: "dcp-button",
1245
+ disabled: !library || busy,
1246
+ onClick: () => void act(
1247
+ () => controller.update({ visible: !library?.config.visible })
1248
+ ),
1249
+ children: library?.config.visible === false ? t("\u663E\u793A\u5BA0\u7269") : t("\u6536\u8D77\u5BA0\u7269")
1250
+ }
1251
+ )
1252
+ ] })
1253
+ ] }),
1254
+ error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { role: "alert", className: "dcp-error", children: t(error) }),
1255
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dcp-card", children: [
1256
+ !library && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dcp-empty", role: "status", children: t("\u6B63\u5728\u52A0\u8F7D\u5BA0\u7269\u2026") }),
1257
+ library?.pets.map((pet) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dcp-row", children: [
1258
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dcp-preview", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Sprite, { pet, size: 44 }) }),
1259
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dcp-info", children: [
1260
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dcp-name", children: pet.name }),
1261
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dcp-description", children: pet.description })
1262
+ ] }),
1263
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1264
+ "button",
1265
+ {
1266
+ className: "dcp-button",
1267
+ "aria-label": library.config.selected === pet.id ? `${t("\u5DF2\u9009\u62E9")} ${pet.name}` : `${t("\u9009\u62E9")} ${pet.name}`,
1268
+ "aria-pressed": library.config.selected === pet.id,
1269
+ disabled: busy || library.config.selected === pet.id,
1270
+ onClick: () => void act(() => controller.update({ selected: pet.id })),
1271
+ children: library.config.selected === pet.id ? t("\u5DF2\u9009") : t("\u9009\u62E9")
1272
+ }
1273
+ )
1274
+ ] }, pet.id)),
1275
+ library?.pets.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dcp-empty", children: t("\u5C1A\u672A\u52A0\u8F7D\u5BA0\u7269\u3002\u5185\u7F6E\u8D44\u6E90\u7F3A\u5931\uFF0C\u8BF7\u91CD\u65B0\u5B89\u88C5\u5B8C\u6574\u63D2\u4EF6\u3002") }),
1276
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dcp-folder", children: [
1277
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
1278
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: t("DSH \u81EA\u5B9A\u4E49\u5BA0\u7269") }),
1279
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dcp-path", children: library?.customPath ?? t("\u6B63\u5728\u8BFB\u53D6\u76EE\u5F55\u2026") })
1280
+ ] }),
1281
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1282
+ "button",
1283
+ {
1284
+ className: "dcp-folder-button",
1285
+ disabled: !library || busy,
1286
+ onClick: () => void act(controller.folder),
1287
+ children: [
1288
+ t("\u6253\u5F00\u6587\u4EF6\u5939"),
1289
+ " ",
1290
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ArrowTopRightIcon, {})
1291
+ ]
1292
+ }
1293
+ )
1294
+ ] })
1295
+ ] }),
1296
+ !!library?.warnings.length && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("details", { className: "dcp-note", children: [
1297
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("summary", { children: t("\u6709 {count} \u9879\u5BA0\u7269\u8D44\u6E90\u9700\u8981\u68C0\u67E5", {
1298
+ count: library.warnings.length
1299
+ }) }),
1300
+ library.warnings.map((message) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: message }, message))
1301
+ ] }),
1302
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "dcp-appearance", children: [
1303
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: t("\u5916\u89C2") }),
1304
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dcp-card dcp-size", children: [
1305
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { htmlFor: "dcp-size", children: [
1306
+ t("\u5BA0\u7269\u5927\u5C0F"),
1307
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: t("\u8C03\u6574\u5BA0\u7269\u5927\u5C0F") })
1308
+ ] }),
1309
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1310
+ "input",
1311
+ {
1312
+ id: "dcp-size",
1313
+ "aria-label": t("\u5BA0\u7269\u5927\u5C0F"),
1314
+ type: "range",
1315
+ min: "64",
1316
+ max: "224",
1317
+ step: "4",
1318
+ value: size,
1319
+ disabled: !library || busy,
1320
+ onChange: (event) => setSize(Number(event.target.value)),
1321
+ onPointerUp: () => void act(() => controller.update({ size })),
1322
+ onKeyUp: () => void act(() => controller.update({ size }))
1323
+ }
1324
+ )
1325
+ ] })
1326
+ ] }),
1327
+ library?.creation && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dcp-note dcp-creation", role: "status", children: library.creation.message }),
1328
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1329
+ "dialog",
1330
+ {
1331
+ ref: dialog,
1332
+ className: "dcp-dialog",
1333
+ onCancel: () => setShowCreate(false),
1334
+ onClose: () => setShowCreate(false),
1335
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1336
+ "form",
1337
+ {
1338
+ onSubmit: (event) => {
1339
+ event.preventDefault();
1340
+ if (!create) return;
1341
+ setBusy(true);
1342
+ setCreationError("");
1343
+ void create(description).then(() => {
1344
+ setShowCreate(false);
1345
+ setDescription("");
1346
+ }).catch(
1347
+ (error2) => setCreationError(
1348
+ error2 instanceof Error ? error2.message : t("\u521B\u5EFA\u5931\u8D25")
1349
+ )
1350
+ ).finally(() => setBusy(false));
1351
+ },
1352
+ children: [
1353
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: t("\u521B\u5EFA\u5BA0\u7269") }),
1354
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1355
+ "textarea",
1356
+ {
1357
+ autoFocus: true,
1358
+ "aria-label": t("\u5BA0\u7269\u63CF\u8FF0"),
1359
+ placeholder: t(
1360
+ "\u4F8B\u5982\uFF1A\u4E00\u53EA\u6234\u7740\u5706\u773C\u955C\u7684\u5C0F\u6D77\u736D\uFF0C\u5B89\u9759\u3001\u597D\u5947\uFF0C\u6BDB\u7ED2\u73A9\u5177\u98CE\u683C\u2026"
1361
+ ),
1362
+ maxLength: 2e3,
1363
+ value: description,
1364
+ onChange: (event) => setDescription(event.target.value),
1365
+ required: true
1366
+ }
1367
+ ),
1368
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "dcp-note", children: t(
1369
+ "\u5728 DSH \u65B0\u4F1A\u8BDD\u4E2D\u4F7F\u7528\u968F\u63D2\u4EF6\u63D0\u4F9B\u7684 Skill \u521B\u5EFA\uFF0C\u6210\u54C1\u4FDD\u5B58\u5230 DSH \u5BA0\u7269\u76EE\u5F55\u3002\u9700\u8981\u5F53\u524D\u4F1A\u8BDD\u5177\u5907\u56FE\u50CF\u751F\u6210\u5DE5\u5177\u3002"
1370
+ ) }),
1371
+ !create && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "status", children: t(
1372
+ "\u8BF7\u5728 DSH \u4E3B\u754C\u9762\u7684\u5BA0\u7269\u8BBE\u7F6E\u4E2D\u53D1\u8D77\u521B\u5EFA\uFF1B\u72EC\u7ACB\u9884\u89C8\u4E0D\u63D0\u4F9B\u4F1A\u8BDD\u670D\u52A1\u3002"
1373
+ ) }),
1374
+ creationError && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "dcp-error", children: t(creationError) }),
1375
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("footer", { children: [
1376
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1377
+ "button",
1378
+ {
1379
+ type: "button",
1380
+ className: "dcp-button",
1381
+ onClick: () => setShowCreate(false),
1382
+ children: t("\u53D6\u6D88")
1383
+ }
1384
+ ),
1385
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1386
+ "button",
1387
+ {
1388
+ type: "submit",
1389
+ className: "dcp-button dcp-primary",
1390
+ disabled: busy || !description.trim() || !library?.skillAvailable || !create,
1391
+ children: t("\u5728 DSH \u4E2D\u521B\u5EFA")
1392
+ }
1393
+ )
1394
+ ] })
1395
+ ]
1396
+ }
1397
+ )
1398
+ }
1399
+ )
1400
+ ] });
1401
+ }
1402
+ function FloatingPet({
1403
+ pet,
1404
+ config,
1405
+ activity,
1406
+ update,
1407
+ open,
1408
+ settings,
1409
+ tray
1410
+ }) {
1411
+ const t = translator(pet.displayLocale ?? "zh");
1412
+ const root = (0, import_react5.useRef)(null);
1413
+ const drag = (0, import_react5.useRef)(null);
1414
+ const [position, setPosition] = (0, import_react5.useState)({ left: 0, top: 0 }), [action, setAction] = (0, import_react5.useState)(null), [look, setLook] = (0, import_react5.useState)(null), [menu, setMenu] = (0, import_react5.useState)(false);
1415
+ const timer = (0, import_react5.useRef)(null);
1416
+ const [menuError, setMenuError] = (0, import_react5.useState)("");
1417
+ const petHeight = config.size * 208 / 192;
1418
+ const place = (0, import_react5.useCallback)(() => {
1419
+ const width = Math.max(0, innerWidth - config.size - 16), height = Math.max(0, innerHeight - petHeight - 32);
1420
+ setPosition({
1421
+ left: config.position ? config.position.x * width : width,
1422
+ top: config.position ? config.position.y * height : height
1423
+ });
1424
+ }, [config.size, config.position, petHeight]);
1425
+ (0, import_react5.useEffect)(() => {
1426
+ place();
1427
+ window.addEventListener("resize", place);
1428
+ return () => window.removeEventListener("resize", place);
1429
+ }, [place]);
1430
+ const perform = (0, import_react5.useCallback)((pose) => {
1431
+ if (timer.current) clearTimeout(timer.current);
1432
+ setLook(null);
1433
+ setAction(pose);
1434
+ const anim = ANIMATIONS[pose];
1435
+ timer.current = setTimeout(
1436
+ () => setAction(null),
1437
+ anim.durations.reduce((sum, value) => sum + value, 0)
1438
+ );
1439
+ }, []);
1440
+ (0, import_react5.useEffect)(
1441
+ () => () => {
1442
+ if (timer.current) clearTimeout(timer.current);
1443
+ },
1444
+ []
1445
+ );
1446
+ (0, import_react5.useEffect)(() => {
1447
+ const interval = setInterval(() => {
1448
+ if (activity.pose === "idle" && !action && !drag.current && !document.hidden && !window.matchMedia("(prefers-reduced-motion: reduce)").matches)
1449
+ perform(Math.random() < 0.7 ? "waving" : "jumping");
1450
+ }, 18e3);
1451
+ return () => clearInterval(interval);
1452
+ }, [activity.pose, action, perform]);
1453
+ (0, import_react5.useEffect)(() => {
1454
+ const track = (event) => {
1455
+ if (activity.pose !== "idle" || action || drag.current || pet.version !== 2) {
1456
+ setLook(null);
1457
+ return;
1458
+ }
1459
+ const box = root.current?.getBoundingClientRect();
1460
+ if (box)
1461
+ setLook(
1462
+ lookCell(
1463
+ event.clientX - box.left - config.size / 2,
1464
+ event.clientY - box.top - petHeight / 2
1465
+ )
1466
+ );
1467
+ };
1468
+ window.addEventListener("mousemove", track);
1469
+ return () => window.removeEventListener("mousemove", track);
1470
+ }, [activity.pose, action, pet.version, config.size, petHeight]);
1471
+ (0, import_react5.useEffect)(() => {
1472
+ if (!menu) return;
1473
+ const close = (event) => {
1474
+ if (!root.current?.contains(event.target)) setMenu(false);
1475
+ };
1476
+ window.addEventListener("pointerdown", close);
1477
+ return () => window.removeEventListener("pointerdown", close);
1478
+ }, [menu]);
1479
+ const persistPosition = () => update({
1480
+ position: {
1481
+ x: position.left / Math.max(1, innerWidth - config.size - 16),
1482
+ y: position.top / Math.max(1, innerHeight - petHeight - 32)
1483
+ }
1484
+ }).catch(() => {
1485
+ });
1486
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1487
+ "div",
1488
+ {
1489
+ className: "dcp dcp-floating",
1490
+ ref: root,
1491
+ style: {
1492
+ left: position.left,
1493
+ top: position.top,
1494
+ width: config.size,
1495
+ height: petHeight
1496
+ },
1497
+ children: [
1498
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: styles }),
1499
+ tray && !menu && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1500
+ "div",
1501
+ {
1502
+ style: {
1503
+ ["--tray-height"]: `${Math.max(100, Math.min(420, position.top < innerHeight / 2 ? innerHeight - position.top - petHeight - 44 : position.top - 24))}px`,
1504
+ ["--tray-top"]: position.top < innerHeight / 2 ? "calc(100% + 28px)" : "auto",
1505
+ ["--tray-bottom"]: position.top < innerHeight / 2 ? "auto" : "calc(100% + 12px)",
1506
+ ["--tray-right"]: position.left < 296 - config.size ? "auto" : "0",
1507
+ ["--tray-left"]: position.left < 296 - config.size ? "0" : "auto"
1508
+ },
1509
+ children: [
1510
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: trayStyles + polishedTrayStyles }),
1511
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(NotificationTray, { ...tray, language: pet.displayLocale })
1512
+ ]
1513
+ }
1514
+ ),
1515
+ !tray && activity.text && !menu && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1516
+ "button",
1517
+ {
1518
+ className: "dcp-bubble",
1519
+ style: {
1520
+ ...position.top < 84 ? { top: "calc(100% + 28px)", bottom: "auto" } : {},
1521
+ ...position.left < 240 ? { left: 0, right: "auto" } : {}
1522
+ },
1523
+ onClick: open,
1524
+ title: t("\u6253\u5F00\u5173\u8054\u4EFB\u52A1"),
1525
+ children: [
1526
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: activity.title }),
1527
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: t(activity.text) })
1528
+ ]
1529
+ }
1530
+ ),
1531
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1532
+ "button",
1533
+ {
1534
+ className: "dcp-pet-button",
1535
+ "aria-label": t("{name}\uFF0C{status}\uFF1B\u62D6\u52A8\u79FB\u52A8\uFF0C\u53CC\u51FB\u8DF3\u8DC3\uFF0C\u53F3\u952E\u83DC\u5355", {
1536
+ name: pet.name,
1537
+ status: t(activity.text || "\u7A7A\u95F2")
1538
+ }),
1539
+ onContextMenu: (event) => {
1540
+ event.preventDefault();
1541
+ setMenu((value) => !value);
1542
+ },
1543
+ onPointerDown: (event) => {
1544
+ if (event.button !== 0) return;
1545
+ event.currentTarget.setPointerCapture(event.pointerId);
1546
+ drag.current = {
1547
+ x: event.screenX,
1548
+ y: event.screenY,
1549
+ startX: event.screenX,
1550
+ startY: event.screenY,
1551
+ left: position.left,
1552
+ top: position.top,
1553
+ moved: false
1554
+ };
1555
+ setMenu(false);
1556
+ },
1557
+ onPointerMove: (event) => {
1558
+ const point = drag.current;
1559
+ if (!point) return;
1560
+ const dx = event.screenX - point.x, dy = event.screenY - point.y;
1561
+ if (Math.hypot(
1562
+ event.screenX - point.startX,
1563
+ event.screenY - point.startY
1564
+ ) > 4)
1565
+ point.moved = true;
1566
+ if (!point.moved) return;
1567
+ setLook(null);
1568
+ setAction(dx < 0 ? "running-left" : "running-right");
1569
+ setPosition({
1570
+ left: Math.max(
1571
+ 0,
1572
+ Math.min(
1573
+ innerWidth - config.size - 16,
1574
+ point.left + event.screenX - point.startX
1575
+ )
1576
+ ),
1577
+ top: Math.max(
1578
+ 0,
1579
+ Math.min(
1580
+ innerHeight - petHeight - 32,
1581
+ point.top + event.screenY - point.startY
1582
+ )
1583
+ )
1584
+ });
1585
+ point.x = event.screenX;
1586
+ point.y = event.screenY;
1587
+ },
1588
+ onPointerUp: () => {
1589
+ const point = drag.current;
1590
+ drag.current = null;
1591
+ setAction(null);
1592
+ if (point?.moved) void persistPosition();
1593
+ else if (!point?.moved) perform("waving");
1594
+ },
1595
+ onPointerCancel: () => {
1596
+ drag.current = null;
1597
+ setAction(null);
1598
+ },
1599
+ onDoubleClick: () => perform("jumping"),
1600
+ onPointerEnter: () => {
1601
+ if (activity.pose === "idle" && !action && !drag.current)
1602
+ perform("waving");
1603
+ },
1604
+ onKeyDown: (event) => {
1605
+ if (event.key === "Escape") setMenu(false);
1606
+ if (event.key === "ContextMenu" || event.shiftKey && event.key === "F10") {
1607
+ event.preventDefault();
1608
+ setMenu(true);
1609
+ }
1610
+ if (event.key === "Enter") perform("waving");
1611
+ },
1612
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1613
+ Sprite,
1614
+ {
1615
+ pet,
1616
+ size: config.size,
1617
+ pose: action ?? activity.pose,
1618
+ animate: true,
1619
+ look
1620
+ }
1621
+ )
1622
+ }
1623
+ ),
1624
+ menu && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1625
+ "div",
1626
+ {
1627
+ className: "dcp-menu",
1628
+ style: {
1629
+ ...position.top < 220 ? { top: "calc(100% + 28px)", bottom: "auto" } : {},
1630
+ ...position.left < 160 ? { left: 0, right: "auto" } : {}
1631
+ },
1632
+ role: "menu",
1633
+ onKeyDown: (event) => {
1634
+ if (event.key === "Escape") setMenu(false);
1635
+ },
1636
+ children: [
1637
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1638
+ "button",
1639
+ {
1640
+ role: "menuitem",
1641
+ onClick: () => {
1642
+ perform("waving");
1643
+ setMenu(false);
1644
+ },
1645
+ children: t("\u6253\u4E2A\u62DB\u547C")
1646
+ }
1647
+ ),
1648
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1649
+ "button",
1650
+ {
1651
+ role: "menuitem",
1652
+ onClick: () => {
1653
+ perform("jumping");
1654
+ setMenu(false);
1655
+ },
1656
+ children: t("\u8DF3\u4E00\u8DF3")
1657
+ }
1658
+ ),
1659
+ !!tray?.state.hidden && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1660
+ "button",
1661
+ {
1662
+ role: "menuitem",
1663
+ onClick: () => {
1664
+ setMenuError("");
1665
+ void tray.command({ type: "restore" }).then(() => setMenu(false)).catch(
1666
+ (error) => setMenuError(
1667
+ error instanceof Error ? error.message : t("\u6062\u590D\u5931\u8D25")
1668
+ )
1669
+ );
1670
+ },
1671
+ children: t("\u6062\u590D\u5DF2\u5173\u95ED\u901A\u77E5")
1672
+ }
1673
+ ),
1674
+ menuError && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", children: t(menuError) }),
1675
+ activity.sessionId && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1676
+ "button",
1677
+ {
1678
+ role: "menuitem",
1679
+ onClick: () => {
1680
+ open();
1681
+ setMenu(false);
1682
+ },
1683
+ children: t("\u67E5\u770B\u4EFB\u52A1")
1684
+ }
1685
+ ),
1686
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("hr", {}),
1687
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1688
+ "button",
1689
+ {
1690
+ role: "menuitem",
1691
+ onClick: () => {
1692
+ settings();
1693
+ setMenu(false);
1694
+ },
1695
+ children: t("\u5BA0\u7269\u8BBE\u7F6E")
1696
+ }
1697
+ ),
1698
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1699
+ "button",
1700
+ {
1701
+ role: "menuitem",
1702
+ onClick: () => {
1703
+ void update({ visible: false }).catch(() => {
1704
+ });
1705
+ },
1706
+ children: t("\u6536\u8D77\u5BA0\u7269")
1707
+ }
1708
+ )
1709
+ ]
1710
+ }
1711
+ )
1712
+ ]
1713
+ }
1714
+ );
1715
+ }
1716
+ function Companion({
1717
+ controller,
1718
+ activity = IDLE,
1719
+ open = () => {
1720
+ },
1721
+ settings = () => {
1722
+ },
1723
+ tray
1724
+ }) {
1725
+ const t = translator(controller.language);
1726
+ const library = controller.library;
1727
+ const selected = library?.pets.find(
1728
+ (item) => item.id === library.config.selected
1729
+ );
1730
+ const pet = (0, import_react5.useMemo)(
1731
+ () => selected ? { ...selected, displayLocale: controller.language } : void 0,
1732
+ [selected, controller.language]
1733
+ );
1734
+ if (!pet || !library?.config.visible) return null;
1735
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1736
+ FloatingPet,
1737
+ {
1738
+ pet,
1739
+ config: library.config,
1740
+ activity,
1741
+ tray,
1742
+ update: controller.update,
1743
+ open,
1744
+ settings
1745
+ }
1746
+ );
1747
+ }
1748
+
1749
+ // src/notifications.ts
1750
+ var priority = { waiting: 0, failed: 1, review: 2, running: 3 };
1751
+ var lifetime = { failed: 36e5, waiting: 864e5, review: 6048e5 };
1752
+ function validateAnswers(questions, value) {
1753
+ if (!value || !Array.isArray(value.answers) || value.answers.length !== questions.length) throw new Error("\u8BF7\u56DE\u7B54\u6240\u6709\u95EE\u9898");
1754
+ const ids = /* @__PURE__ */ new Set();
1755
+ for (const answer of value.answers) {
1756
+ const question = questions.find((q) => q.id === answer.id);
1757
+ if (!question || ids.has(answer.id) || !Array.isArray(answer.selected)) throw new Error("\u95EE\u9898\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u56DE\u7B54");
1758
+ ids.add(answer.id);
1759
+ if (new Set(answer.selected).size !== answer.selected.length || answer.selected.some((label) => !question.options?.some((option) => option.label === label))) throw new Error("\u9009\u9879\u65E0\u6548");
1760
+ if (answer.custom !== void 0 && (typeof answer.custom !== "string" || answer.custom.length > 1e4)) throw new Error("\u56DE\u7B54\u8FC7\u957F");
1761
+ if (!answer.selected.length && !answer.custom?.trim()) throw new Error("\u8BF7\u56DE\u7B54\u6240\u6709\u95EE\u9898");
1762
+ if (!question.multiSelect && (answer.selected.length > 1 || answer.selected.length > 0 && !!answer.custom?.trim())) throw new Error("\u5355\u9009\u95EE\u9898\u53EA\u80FD\u63D0\u4EA4\u4E00\u79CD\u56DE\u7B54");
1763
+ }
1764
+ return value;
1765
+ }
1766
+ function createNotifications(sessions, pending, notify, now = Date.now) {
1767
+ const records = /* @__PURE__ */ new Map();
1768
+ const bindings = /* @__PURE__ */ new Map();
1769
+ const dismissed = /* @__PURE__ */ new Map();
1770
+ const busy = /* @__PURE__ */ new Set();
1771
+ const answered = /* @__PURE__ */ new Set();
1772
+ let state = { items: [], activity: IDLE, hidden: 0 }, latestFirst = false;
1773
+ let publishing = false;
1774
+ let lastPublished = "";
1775
+ const publish = () => {
1776
+ if (publishing) return;
1777
+ publishing = true;
1778
+ try {
1779
+ const list = sessions.list.getSnapshot(), requests = pending.getSnapshot();
1780
+ const ids = new Set(list.ids.filter((id) => list.byId[id] && list.byId[id].origin !== "subagent"));
1781
+ for (const id of records.keys()) if (!ids.has(id)) {
1782
+ records.delete(id);
1783
+ dismissed.delete(id);
1784
+ }
1785
+ for (const [id, bound] of bindings) if (!ids.has(id)) {
1786
+ bound.off();
1787
+ bindings.delete(id);
1788
+ records.delete(id);
1789
+ dismissed.delete(id);
1790
+ }
1791
+ const items = [];
1792
+ let hidden = 0;
1793
+ for (const id of ids) {
1794
+ const row = list.byId[id];
1795
+ if (!row) continue;
1796
+ const binding = sessions.binding(id);
1797
+ let record = records.get(id);
1798
+ if (!record) {
1799
+ record = { round: 0, running: row.running, completion: !!row.completed, error: null, revision: binding?.eventSource.getSnapshot().revision ?? -1, updatedAt: row.updatedAt ?? now(), lastPose: "" };
1800
+ records.set(id, record);
1801
+ }
1802
+ const previous = bindings.get(id);
1803
+ if (binding && (previous?.binding.session !== binding.session || previous.binding.eventSource !== binding.eventSource)) {
1804
+ previous?.off();
1805
+ record.revision = binding.eventSource.getSnapshot().revision;
1806
+ const offSession = binding.session.subscribe(publish), offEvents = binding.eventSource.subscribe(publish);
1807
+ bindings.set(id, { binding, off: () => {
1808
+ offSession();
1809
+ offEvents();
1810
+ } });
1811
+ }
1812
+ const snapshot = binding?.session.getSnapshot();
1813
+ const running = id === list.current ? snapshot?.running ?? row.running : row.running;
1814
+ if (running && !record.running) {
1815
+ record.round++;
1816
+ record.awaitingStart = true;
1817
+ record.finished = void 0;
1818
+ record.completion = false;
1819
+ record.error = null;
1820
+ record.updatedAt = now();
1821
+ }
1822
+ const events = binding?.eventSource.getSnapshot();
1823
+ if (events && record.revision !== events.revision) {
1824
+ record.revision = events.revision;
1825
+ if (events.change.kind === "append") for (const entry of events.change.entries) {
1826
+ if (entry.type !== "event") continue;
1827
+ if (entry.event.type === "turn/start") {
1828
+ if (!record.awaitingStart) record.round++;
1829
+ record.awaitingStart = false;
1830
+ record.finished = void 0;
1831
+ record.completion = false;
1832
+ record.error = null;
1833
+ }
1834
+ if (entry.event.type === "turn/end") {
1835
+ record.finished = entry.event.data?.reason?.kind;
1836
+ record.completion = record.finished === "completed";
1837
+ record.updatedAt = now();
1838
+ }
1839
+ }
1840
+ }
1841
+ record.running = running;
1842
+ if (snapshot?.lastAgentError && snapshot.lastAgentError !== record.snapshotError) record.error = snapshot.lastAgentError;
1843
+ record.snapshotError = snapshot?.lastAgentError;
1844
+ if (row.completed && !running && (!record.finished || record.finished === "completed")) record.completion = true;
1845
+ const request2 = requests.get(id);
1846
+ const activity = selectActivity([{ id, title: row.title ?? row.displayTitle, running, waiting: !!request2, error: running ? null : record.error, completed: !running && record.completion }]);
1847
+ if (activity.pose === "idle") continue;
1848
+ if (record.lastPose && record.lastPose !== activity.pose || record.requestKey !== request2?.key) record.updatedAt = now();
1849
+ record.lastPose = activity.pose;
1850
+ record.requestKey = request2?.key;
1851
+ const token = `${record.round}:${request2?.key ?? ""}`;
1852
+ if (dismissed.get(id) === token) {
1853
+ hidden++;
1854
+ continue;
1855
+ }
1856
+ const ttl = lifetime[activity.pose];
1857
+ if (ttl && now() - record.updatedAt >= ttl) continue;
1858
+ items.push({ ...activity, id, token, updatedAt: record.updatedAt, request: request2 && typeof request2.key === "string" ? { key: request2.key, kind: String(request2.kind), toolName: request2.toolName, reason: request2.reason, questions: request2.questions } : void 0 });
1859
+ }
1860
+ items.sort((a, b) => (latestFirst ? 0 : priority[a.pose] - priority[b.pose]) || b.updatedAt - a.updatedAt || a.id.localeCompare(b.id));
1861
+ state = { items, hidden, activity: items[0] ?? IDLE };
1862
+ const signature = JSON.stringify(state);
1863
+ if (signature !== lastPublished) {
1864
+ lastPublished = signature;
1865
+ notify(state);
1866
+ }
1867
+ } finally {
1868
+ publishing = false;
1869
+ }
1870
+ };
1871
+ const offList = sessions.list.subscribe(publish), offPending = pending.subscribe(publish);
1872
+ publish();
1873
+ const timer = setInterval(publish, 1e3);
1874
+ return {
1875
+ getSnapshot: () => state,
1876
+ sort(latest) {
1877
+ latestFirst = latest;
1878
+ publish();
1879
+ },
1880
+ async command(command) {
1881
+ if (command.type === "restore") {
1882
+ dismissed.clear();
1883
+ publish();
1884
+ return;
1885
+ }
1886
+ const item = state.items.find((item2) => item2.id === command.id && item2.token === command.token);
1887
+ if (!item) throw new Error("\u8FD9\u6761\u901A\u77E5\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u4F7F\u7528\u6700\u65B0\u901A\u77E5");
1888
+ if (command.type === "dismiss") {
1889
+ dismissed.set(item.id, item.token);
1890
+ publish();
1891
+ return;
1892
+ }
1893
+ if (command.type === "open") {
1894
+ sessions.open(item.id);
1895
+ if (item.pose === "review") dismissed.set(item.id, item.token);
1896
+ publish();
1897
+ return;
1898
+ }
1899
+ if (command.type === "stop") {
1900
+ if (item.pose !== "running") throw new Error("\u4EFB\u52A1\u72B6\u6001\u5DF2\u53D8\u5316");
1901
+ const session = sessions.binding(item.id)?.session;
1902
+ if (!session?.cancel) throw new Error("\u5BBF\u4E3B\u672A\u63D0\u4F9B\u505C\u6B62\u4EFB\u52A1\u80FD\u529B");
1903
+ if (busy.has(item.id)) throw new Error("\u6B63\u5728\u63D0\u4EA4\uFF0C\u8BF7\u52FF\u91CD\u590D\u64CD\u4F5C");
1904
+ busy.add(item.id);
1905
+ try {
1906
+ const result = await session.cancel();
1907
+ if (!result.ok) throw new Error(result.error?.message ?? "\u505C\u6B62\u5931\u8D25");
1908
+ } finally {
1909
+ busy.delete(item.id);
1910
+ }
1911
+ return;
1912
+ }
1913
+ const request2 = pending.getSnapshot().get(item.id);
1914
+ if (!request2 || request2.key !== command.requestKey || request2.sessionId && request2.sessionId !== item.id || !request2.answer) throw new Error("\u8BF7\u6C42\u5DF2\u7ED3\u675F\u6216\u5DF2\u66F4\u6362\uFF0C\u8BF7\u67E5\u770B\u6700\u65B0\u4F1A\u8BDD");
1915
+ if (answered.has(request2.key)) throw new Error("\u8BE5\u8BF7\u6C42\u5DF2\u7ECF\u63D0\u4EA4");
1916
+ if (busy.has(item.id)) throw new Error("\u6B63\u5728\u63D0\u4EA4\uFF0C\u8BF7\u52FF\u91CD\u590D\u64CD\u4F5C");
1917
+ let answer;
1918
+ if (request2.kind === "approval" && (command.type === "approve" || command.type === "reject")) answer = command.type === "approve" ? "allowed-once" : "rejected";
1919
+ else if ((request2.kind === "question" || request2.kind === "plan-review") && command.type === "answer") answer = validateAnswers(request2.questions ?? [], command.answers);
1920
+ else throw new Error("\u6B64\u8BF7\u6C42\u4E0D\u652F\u6301\u8BE5\u64CD\u4F5C");
1921
+ busy.add(item.id);
1922
+ try {
1923
+ await request2.answer(answer);
1924
+ answered.add(request2.key);
1925
+ } finally {
1926
+ busy.delete(item.id);
1927
+ publish();
1928
+ }
1929
+ },
1930
+ dispose() {
1931
+ offList();
1932
+ offPending();
1933
+ clearInterval(timer);
1934
+ for (const value of bindings.values()) value.off();
1935
+ bindings.clear();
1936
+ }
1937
+ };
1938
+ }
1939
+
1940
+ // src/creation.ts
1941
+ async function createPetSession(sessions, description, directory, skill) {
1942
+ if (!description.trim() || description.length > 2e3) throw new Error("\u8BF7\u8F93\u5165 1\u20132000 \u5B57\u7684\u5BA0\u7269\u63CF\u8FF0");
1943
+ const id = await sessions.create({ cwd: directory });
1944
+ sessions.open(id);
1945
+ const binding = sessions.binding(id);
1946
+ if (!binding) throw new Error("\u521B\u5EFA\u4F1A\u8BDD\u5C1A\u4E0D\u53EF\u7528\uFF0C\u8BF7\u91CD\u8BD5");
1947
+ const text = `\u8BF7\u5148\u8BFB\u53D6\u5E76\u9075\u5FAA\u5BA0\u7269\u521B\u5EFA Skill\uFF1A${skill}
1948
+ \u5BA0\u7269\u8981\u6C42\uFF1A${description.trim()}
1949
+ \u6210\u54C1\u4FDD\u5B58\u5230 ${directory} \u4E0B\u7684\u65B0\u76EE\u5F55\uFF0C\u4FDD\u7559\u6240\u6709\u5DF2\u6709\u5BA0\u7269\u3002\u4F7F\u7528 DSH \u5F53\u524D\u914D\u7F6E\u7684\u56FE\u50CF\u5DE5\u5177\u3002\u7F3A\u5C11\u751F\u56FE\u5DE5\u5177\u65F6\u660E\u786E\u8BF4\u660E\uFF0C\u4E0D\u751F\u6210\u5360\u4F4D\u56FE\uFF0C\u4E0D\u865A\u62A5\u5B8C\u6210\u3002`;
1950
+ const result = await binding.session.prompt([{ type: "text", text }], "queue");
1951
+ if (!result.ok) throw new Error(result.error?.message ?? "DSH \u672A\u63A5\u53D7\u5BA0\u7269\u521B\u5EFA\u8BF7\u6C42");
1952
+ }
1953
+
1954
+ // src/settings-icon.ts
1955
+ var PAW = '<circle cx="11" cy="4" r="2"/><circle cx="18" cy="8" r="2"/><circle cx="20" cy="16" r="2"/><path d="M9 10a5 5 0 0 1 5 5v3.5a3.5 3.5 0 0 1-6.84 1.045Q6.52 17.48 4.46 16.84A3.5 3.5 0 0 1 5.5 10Z"/>';
1956
+ function observePetSettingsIcon() {
1957
+ const apply2 = () => {
1958
+ for (const button of document.querySelectorAll(".dcu-settings-link")) {
1959
+ if (!["\u5BA0\u7269", "Pets"].includes(button.textContent?.trim() ?? "")) continue;
1960
+ const svg = button.querySelector("svg");
1961
+ if (!svg || svg.getAttribute("data-pet-icon") === "codex-paw") continue;
1962
+ svg.setAttribute("data-pet-icon", "codex-paw");
1963
+ svg.setAttribute("viewBox", "0 0 24 24");
1964
+ svg.setAttribute("fill", "none");
1965
+ svg.setAttribute("stroke", "currentColor");
1966
+ svg.setAttribute("stroke-linecap", "round");
1967
+ svg.setAttribute("stroke-linejoin", "round");
1968
+ svg.innerHTML = PAW;
1969
+ }
1970
+ };
1971
+ apply2();
1972
+ const observer = new MutationObserver(apply2);
1973
+ observer.observe(document.body, { childList: true, subtree: true });
1974
+ return () => observer.disconnect();
1975
+ }
1976
+
1977
+ // src/client.tsx
1978
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1979
+ var name = "michengai-codex-pet";
1980
+ var inject = ["slots", "sessions", "uiSession", "locale"];
1981
+ function openSettings() {
1982
+ const trigger = document.querySelector("[data-dcu-settings-trigger]");
1983
+ if (trigger)
1984
+ trigger.dispatchEvent(
1985
+ new CustomEvent("dcu-settings-open-section", {
1986
+ bubbles: true,
1987
+ cancelable: true,
1988
+ detail: { labels: ["\u5BA0\u7269", "Pets"] }
1989
+ })
1990
+ );
1991
+ else window.dispatchEvent(new Event("dcp-open-settings"));
1992
+ }
1993
+ function Overlay({
1994
+ sessions,
1995
+ pending,
1996
+ locale
1997
+ }) {
1998
+ const controller = usePetController(locale);
1999
+ const t = translator(controller.language);
2000
+ const settingsDialog = (0, import_react6.useRef)(null);
2001
+ (0, import_react6.useEffect)(() => {
2002
+ const show = () => {
2003
+ if (!settingsDialog.current?.open) settingsDialog.current?.showModal();
2004
+ };
2005
+ window.addEventListener("dcp-open-settings", show);
2006
+ return () => window.removeEventListener("dcp-open-settings", show);
2007
+ }, []);
2008
+ const [state, setState] = (0, import_react6.useState)({
2009
+ items: [],
2010
+ activity: IDLE,
2011
+ hidden: 0
2012
+ });
2013
+ const notifications = (0, import_react6.useRef)(
2014
+ null
2015
+ );
2016
+ (0, import_react6.useEffect)(() => {
2017
+ const engine = createNotifications(sessions, pending, setState);
2018
+ notifications.current = engine;
2019
+ return () => {
2020
+ notifications.current = null;
2021
+ engine.dispose();
2022
+ };
2023
+ }, [sessions, pending]);
2024
+ (0, import_react6.useEffect)(observePetSettingsIcon, []);
2025
+ const command = async (value) => {
2026
+ const engine = notifications.current;
2027
+ if (!engine) throw new Error("\u4F1A\u8BDD\u670D\u52A1\u5C1A\u672A\u5C31\u7EEA");
2028
+ if (value.type === "sort") {
2029
+ engine.sort(value.latest);
2030
+ return;
2031
+ }
2032
+ await engine.command(value);
2033
+ };
2034
+ const [externalDisplay, setExternalDisplay] = (0, import_react6.useState)(false);
2035
+ const actions = (0, import_react6.useRef)({
2036
+ command,
2037
+ updateConfig: controller.update,
2038
+ openSettings
2039
+ });
2040
+ actions.current = { command, updateConfig: controller.update, openSettings };
2041
+ const provider = (0, import_react6.useRef)(
2042
+ null
2043
+ );
2044
+ (0, import_react6.useEffect)(() => {
2045
+ const value = createCompanionProvider({
2046
+ command: (command2) => actions.current.command(command2),
2047
+ updateConfig: (config) => actions.current.updateConfig(config),
2048
+ openSettings: () => actions.current.openSettings(),
2049
+ externalDisplay: setExternalDisplay
2050
+ });
2051
+ provider.current = value;
2052
+ window.dshPet = value.api;
2053
+ window.dispatchEvent(new Event("dsh-pet-ready"));
2054
+ return () => {
2055
+ value.dispose();
2056
+ provider.current = null;
2057
+ if (window.dshPet === value.api) delete window.dshPet;
2058
+ window.dispatchEvent(new Event("dsh-pet-disposed"));
2059
+ };
2060
+ }, []);
2061
+ (0, import_react6.useEffect)(() => {
2062
+ const library = controller.library;
2063
+ provider.current?.publish(
2064
+ library ? {
2065
+ pet: library.pets.find((pet) => pet.id === library.config.selected) ?? null,
2066
+ config: library.config,
2067
+ language: controller.language,
2068
+ notifications: state
2069
+ } : null
2070
+ );
2071
+ }, [controller.library, controller.language, state]);
2072
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2073
+ !externalDisplay && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2074
+ Companion,
2075
+ {
2076
+ controller,
2077
+ activity: state.activity,
2078
+ tray: { state, command },
2079
+ open: () => {
2080
+ if (state.activity.sessionId)
2081
+ sessions.open(state.activity.sessionId);
2082
+ },
2083
+ settings: openSettings
2084
+ }
2085
+ ),
2086
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2087
+ "dialog",
2088
+ {
2089
+ ref: settingsDialog,
2090
+ className: "dcp dcp-dialog",
2091
+ "aria-label": t("\u5BA0\u7269\u8BBE\u7F6E"),
2092
+ style: {
2093
+ width: "min(800px, calc(100vw - 32px))",
2094
+ maxHeight: "85vh",
2095
+ overflow: "auto"
2096
+ },
2097
+ children: [
2098
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2099
+ "button",
2100
+ {
2101
+ type: "button",
2102
+ className: "dcp-button",
2103
+ onClick: () => settingsDialog.current?.close(),
2104
+ children: t("\u5173\u95ED\u8BBE\u7F6E")
2105
+ }
2106
+ ),
2107
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2108
+ Settings,
2109
+ {
2110
+ controller,
2111
+ locale,
2112
+ create: async (description) => {
2113
+ const library = controller.library;
2114
+ if (!library) throw new Error("\u5BA0\u7269\u5E93\u5C1A\u672A\u52A0\u8F7D");
2115
+ await createPetSession(
2116
+ sessions,
2117
+ description,
2118
+ library.customPath,
2119
+ library.skillPath
2120
+ );
2121
+ }
2122
+ }
2123
+ )
2124
+ ]
2125
+ }
2126
+ )
2127
+ ] });
2128
+ }
2129
+ function Page({
2130
+ sessions,
2131
+ locale
2132
+ }) {
2133
+ const controller = usePetController(locale);
2134
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2135
+ Settings,
2136
+ {
2137
+ controller,
2138
+ locale,
2139
+ create: async (description) => {
2140
+ const library = controller.library;
2141
+ if (!library) throw new Error("\u5BA0\u7269\u5E93\u5C1A\u672A\u52A0\u8F7D");
2142
+ await createPetSession(
2143
+ sessions,
2144
+ description,
2145
+ library.customPath,
2146
+ library.skillPath
2147
+ );
2148
+ }
2149
+ }
2150
+ );
2151
+ }
2152
+ function apply(ctx) {
2153
+ ctx.slots.inject(
2154
+ "settings.section",
2155
+ () => ctx.slots.register(
2156
+ {
2157
+ name: "settings.section",
2158
+ id: "codex-pet",
2159
+ label: () => translator(ctx.locale.getSnapshot().active)("\u5BA0\u7269"),
2160
+ order: 12
2161
+ },
2162
+ () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Page, { sessions: ctx.sessions, locale: ctx.locale })
2163
+ )
2164
+ );
2165
+ ctx.slots.inject(
2166
+ "shell.overlay",
2167
+ () => ctx.slots.register(
2168
+ { name: "shell.overlay", id: "michengai-codex-pet", order: 100 },
2169
+ () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2170
+ Overlay,
2171
+ {
2172
+ sessions: ctx.sessions,
2173
+ pending: ctx.uiSession.pendingInteractions,
2174
+ locale: ctx.locale
2175
+ }
2176
+ )
2177
+ )
2178
+ );
2179
+ }
2180
+
2181
+ return module.exports;}});