@linxin666/dsh-pet 0.1.19 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +3 -3
- package/README.zh.md +3 -3
- package/lib/client.js +54 -22
- package/lib/client.js.map +1 -1
- package/lib/index.js +44 -1
- package/lib/types/affinity.d.ts +18 -18
- package/lib/types/affinity.d.ts.map +1 -1
- package/lib/types/affinity.js +1 -1
- package/lib/types/client/PetDockEntry.d.ts +2 -0
- package/lib/types/client/PetDockEntry.d.ts.map +1 -1
- package/lib/types/client/PetDockEntry.js +2 -2
- package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PetSettingsCard.js +2 -2
- package/lib/types/client/PetSprite.d.ts +2 -0
- package/lib/types/client/PetSprite.d.ts.map +1 -1
- package/lib/types/client/PetSprite.js +17 -16
- package/lib/types/client/PluginSettingsCard.d.ts +1 -1
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +31 -6
- package/lib/types/client/locales.d.ts +82 -80
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +2 -0
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/spritesheet.d.ts +1 -1
- package/lib/types/client/spritesheet.d.ts.map +1 -1
- package/lib/types/client/spritesheet.js +3 -12
- package/lib/types/index.d.ts +2 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +15 -13
- package/lib/types/invariant.js +2 -2
- package/lib/types/ledger.d.ts.map +1 -1
- package/lib/types/ledger.js +3 -3
- package/lib/types/mount-once.d.ts +25 -0
- package/lib/types/mount-once.d.ts.map +1 -0
- package/lib/types/mount-once.js +42 -0
- package/lib/types/persist.js +3 -3
- package/lib/types/registry.js +1 -1
- package/lib/types/remarks.d.ts.map +1 -1
- package/lib/types/routes.js +2 -2
- package/lib/types/service.d.ts +10 -6
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +11 -6
- package/lib/types/state.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/client/PetDockEntry.tsx +3 -0
- package/src/client/PetSprite.test.tsx +56 -3
- package/src/client/PetSprite.tsx +26 -17
- package/src/client/index.ts +26 -3
- package/src/client/locales.ts +2 -0
- package/src/client/pet.module.css +35 -12
- package/src/client/spritesheet.ts +3 -13
- package/src/index.ts +4 -1
- package/src/mount-once.ts +48 -0
- package/src/service.ts +15 -7
package/lib/index.js
CHANGED
|
@@ -1154,6 +1154,7 @@ var PetService = class extends Service {
|
|
|
1154
1154
|
const sessions = [];
|
|
1155
1155
|
for (const [session, activity] of [...this.sessionActivity.entries()].reverse()) {
|
|
1156
1156
|
if (sessions.length >= 12) break;
|
|
1157
|
+
if (session.header?.origin === "subagent") continue;
|
|
1157
1158
|
const perSession = activity.machine.render();
|
|
1158
1159
|
if (perSession.bubble === void 0) continue;
|
|
1159
1160
|
sessions.push({
|
|
@@ -1456,6 +1457,47 @@ function makePetRoutes(deps) {
|
|
|
1456
1457
|
return [...apiRoutes, assetRoute];
|
|
1457
1458
|
}
|
|
1458
1459
|
//#endregion
|
|
1460
|
+
//#region src/mount-once.ts
|
|
1461
|
+
/**
|
|
1462
|
+
* Host single-instance guard shared by the plugin family. The family bundle
|
|
1463
|
+
* (dsh-web-ui-all / dsh-skins) namespaces every child row id (web-ui-*), so
|
|
1464
|
+
* the loader accepts a standalone install of the same package side by side;
|
|
1465
|
+
* without this guard the second instance would still re-register the same
|
|
1466
|
+
* webserver routes, tools, settings namespaces, and system-prompt sections
|
|
1467
|
+
* and fail the boot. mountOnce makes the second host apply a no-op for the
|
|
1468
|
+
* lifetime of the first instance (the browser half is already deduped by
|
|
1469
|
+
* package name in the client module host).
|
|
1470
|
+
*
|
|
1471
|
+
* The registry rides a global symbol so two module instances of the same
|
|
1472
|
+
* package (npm copy vs repository link) still share one verdict. cordis
|
|
1473
|
+
* `ctx.effect` runs its callback immediately and treats the callback's
|
|
1474
|
+
* return value as the fiber disposer, so the unmarker is returned, not run.
|
|
1475
|
+
*/
|
|
1476
|
+
const MOUNTED = Symbol.for("dsh-web-ui.mounted-plugins");
|
|
1477
|
+
function mountedSet() {
|
|
1478
|
+
const registry = globalThis;
|
|
1479
|
+
return registry[MOUNTED] ??= /* @__PURE__ */ new Set();
|
|
1480
|
+
}
|
|
1481
|
+
/**
|
|
1482
|
+
* Wrap a cordis plugin apply so the package runs at most once per process.
|
|
1483
|
+
* The first mount registers normally and unmarks when its fiber disposes;
|
|
1484
|
+
* any later mount of the same package name is a no-op.
|
|
1485
|
+
* @param packageName - npm package identity shared by every install source.
|
|
1486
|
+
* @param fn - the original plugin apply.
|
|
1487
|
+
* @returns an apply of the same shape.
|
|
1488
|
+
*/
|
|
1489
|
+
function mountOnce(packageName, fn) {
|
|
1490
|
+
return ((...args) => {
|
|
1491
|
+
const mounted = mountedSet();
|
|
1492
|
+
if (mounted.has(packageName)) return;
|
|
1493
|
+
mounted.add(packageName);
|
|
1494
|
+
args[0]?.effect?.(() => () => {
|
|
1495
|
+
mounted.delete(packageName);
|
|
1496
|
+
});
|
|
1497
|
+
return fn(...args);
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
//#endregion
|
|
1459
1501
|
//#region src/index.ts
|
|
1460
1502
|
/** Stable cordis plugin name (matches cordis.patch.yml insert id). */
|
|
1461
1503
|
const name = "pet";
|
|
@@ -1480,7 +1522,8 @@ function makePetSettingsSchema(fallbackPetId) {
|
|
|
1480
1522
|
});
|
|
1481
1523
|
}
|
|
1482
1524
|
/** Register the pet service and its API + asset routes on the context. */
|
|
1483
|
-
|
|
1525
|
+
const apply = mountOnce("@linxin666/dsh-pet", applyImpl);
|
|
1526
|
+
function applyImpl(ctx, config = {}) {
|
|
1484
1527
|
const registry = config.registry ?? loadPetRegistry({
|
|
1485
1528
|
packageRoot: petPackageRoot(import.meta.url),
|
|
1486
1529
|
...config.pets === void 0 ? {} : { extra: config.pets }
|
package/lib/types/affinity.d.ts
CHANGED
|
@@ -36,40 +36,40 @@ export declare const AFFINITY_MAX = 999999999;
|
|
|
36
36
|
* characters); they read as a growing star trail alongside the rank name. */
|
|
37
37
|
export declare const AFFINITY_RANKS: readonly [{
|
|
38
38
|
readonly min: 0;
|
|
39
|
-
readonly name:
|
|
40
|
-
readonly emoji:
|
|
39
|
+
readonly name: '幼鲸';
|
|
40
|
+
readonly emoji: '*';
|
|
41
41
|
}, {
|
|
42
42
|
readonly min: 25;
|
|
43
|
-
readonly name:
|
|
44
|
-
readonly emoji:
|
|
43
|
+
readonly name: '伙伴';
|
|
44
|
+
readonly emoji: '**';
|
|
45
45
|
}, {
|
|
46
46
|
readonly min: 50;
|
|
47
|
-
readonly name:
|
|
48
|
-
readonly emoji:
|
|
47
|
+
readonly name: '挚友';
|
|
48
|
+
readonly emoji: '***';
|
|
49
49
|
}, {
|
|
50
50
|
readonly min: 80;
|
|
51
|
-
readonly name:
|
|
52
|
-
readonly emoji:
|
|
51
|
+
readonly name: '深海羁绊';
|
|
52
|
+
readonly emoji: '****';
|
|
53
53
|
}, {
|
|
54
54
|
readonly min: 200;
|
|
55
|
-
readonly name:
|
|
56
|
-
readonly emoji:
|
|
55
|
+
readonly name: '心有灵犀';
|
|
56
|
+
readonly emoji: '*****';
|
|
57
57
|
}, {
|
|
58
58
|
readonly min: 500;
|
|
59
|
-
readonly name:
|
|
60
|
-
readonly emoji:
|
|
59
|
+
readonly name: '传说羁绊';
|
|
60
|
+
readonly emoji: '******';
|
|
61
61
|
}, {
|
|
62
62
|
readonly min: 2000;
|
|
63
|
-
readonly name:
|
|
64
|
-
readonly emoji:
|
|
63
|
+
readonly name: '神话羁绊';
|
|
64
|
+
readonly emoji: '*******';
|
|
65
65
|
}, {
|
|
66
66
|
readonly min: 10000;
|
|
67
|
-
readonly name:
|
|
68
|
-
readonly emoji:
|
|
67
|
+
readonly name: '永恒之契';
|
|
68
|
+
readonly emoji: '********';
|
|
69
69
|
}, {
|
|
70
70
|
readonly min: 100000;
|
|
71
|
-
readonly name:
|
|
72
|
-
readonly emoji:
|
|
71
|
+
readonly name: '鲸生共渡';
|
|
72
|
+
readonly emoji: '*********';
|
|
73
73
|
}];
|
|
74
74
|
/** Interaction tuning (all in points / ms). */
|
|
75
75
|
export interface AffinityConfig {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"affinity.d.ts","sourceRoot":"","sources":["../../src/affinity.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,uDAAuD;AACvD,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,CAAA;AAE3C,mCAAmC;AACnC,MAAM,WAAW,aAAa;IAC5B,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAA;IACjB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,YAAc,CAAA;AAEvC;;;;8EAI8E;AAC9E,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"affinity.d.ts","sourceRoot":"","sources":["../../src/affinity.ts"],"names":[],"mappings":"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"}
|
package/lib/types/affinity.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* built-in pool); the ledger layers per-pet custom remarks on top.
|
|
8
8
|
* @module @linxin666/dsh-pet/affinity
|
|
9
9
|
*/
|
|
10
|
-
import { builtinRemark } from
|
|
10
|
+
import { builtinRemark } from './remarks.js';
|
|
11
11
|
/**
|
|
12
12
|
* Affinity points cap. Historically 100; removed so long-term companions
|
|
13
13
|
* keep growing — the default limit is now the full 999,999,999 range.
|
|
@@ -32,6 +32,8 @@ export interface PetInjected {
|
|
|
32
32
|
dragEnd: (right: number, bottom: number) => void;
|
|
33
33
|
/** Rename the selected pet (persisted by the host). */
|
|
34
34
|
rename: (name: string) => void;
|
|
35
|
+
/** Navigate the GUI to the session a bubble reports on. */
|
|
36
|
+
openSession: (sessionId: string) => void;
|
|
35
37
|
/** Clear the reaction bubble. */
|
|
36
38
|
feedbackDone: () => void;
|
|
37
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PetDockEntry.d.ts","sourceRoot":"","sources":["../../../src/client/PetDockEntry.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAmC,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEtD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IAC1B,6EAA6E;IAC7E,KAAK,EAAE,gBAAgB,CAAA;IACvB,kFAAkF;IAClF,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,8BAA8B;IAC9B,GAAG,EAAE,MAAM,IAAI,CAAA;IACf,uBAAuB;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,uBAAuB;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,qCAAqC;IACrC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,uDAAuD;IACvD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,iCAAiC;IACjC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAC3B,WAAW,GACT,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;AAI1B;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"PetDockEntry.d.ts","sourceRoot":"","sources":["../../../src/client/PetDockEntry.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAmC,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEtD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IAC1B,6EAA6E;IAC7E,KAAK,EAAE,gBAAgB,CAAA;IACvB,kFAAkF;IAClF,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,8BAA8B;IAC9B,GAAG,EAAE,MAAM,IAAI,CAAA;IACf,uBAAuB;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,uBAAuB;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,qCAAqC;IACrC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,uDAAuD;IACvD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,2DAA2D;IAC3D,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,iCAAiC;IACjC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAC3B,WAAW,GACT,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;AAI1B;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAqDnE"}
|
|
@@ -12,7 +12,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
12
12
|
* @module @linxin666/dsh-pet/client/PetDockEntry
|
|
13
13
|
*/
|
|
14
14
|
import { useEffect, useSyncExternalStore } from 'react';
|
|
15
|
-
import { PetSprite } from
|
|
15
|
+
import { PetSprite } from './PetSprite.js';
|
|
16
16
|
import styles from './pet.module.css';
|
|
17
17
|
const DEFAULT_DISPLAY = { visible: true, size: 160, right: 24, bottom: 20 };
|
|
18
18
|
/**
|
|
@@ -35,7 +35,7 @@ export function PetDockEntry(props) {
|
|
|
35
35
|
if (visible) {
|
|
36
36
|
return (_jsx("span", { "data-pet-dock": true, "data-testid": "pet-dock", children: snapshot === null || definition === null
|
|
37
37
|
? null
|
|
38
|
-
: (_jsx(PetSprite, { snapshot: snapshot, definition: definition, display: snapshot.display, feedback: feedback, onPet: props.pet, onFeed: props.feed, onHide: props.hide, onDragEnd: props.dragEnd, onRename: props.rename, onFeedbackDone: props.feedbackDone, t: props.t })) }));
|
|
38
|
+
: (_jsx(PetSprite, { snapshot: snapshot, definition: definition, display: snapshot.display, feedback: feedback, onPet: props.pet, onFeed: props.feed, onHide: props.hide, onDragEnd: props.dragEnd, onRename: props.rename, onOpenSession: props.openSession, onFeedbackDone: props.feedbackDone, t: props.t })) }));
|
|
39
39
|
}
|
|
40
40
|
const display = snapshot?.display ?? DEFAULT_DISPLAY;
|
|
41
41
|
return (_jsx("button", { type: "button", className: styles.summon, style: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PetSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PetSettingsCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAI1F,OAAO,EAAoD,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAG1J,+EAA+E;AAC/E,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qBAAqB;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,0CAA0C;AAC1C,MAAM,WAAW,oBAAqB,SAAQ,SAAS;IACrD,4BAA4B;IAC5B,OAAO,EAAE,cAAc,CAAA;IACvB,qBAAqB;IACrB,OAAO,EAAE,cAAc,CAAA;IACvB,iBAAiB;IACjB,IAAI,EAAE,cAAc,CAAA;IACpB,mBAAmB;IACnB,KAAK,EAAE,cAAc,CAAA;IACrB,oBAAoB;IACpB,MAAM,EAAE,cAAc,CAAA;IACtB,oBAAoB;IACpB,KAAK,EAAE,cAAc,CAAA;IACrB,wEAAwE;IACxE,UAAU,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CACxD;AAED,gEAAgE;AAChE,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,KAAK,EAAE;QACL,iEAAiE;QACjE,eAAe,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAA;KACrD,CAAA;CACF;AAeD,2DAA2D;AAC3D,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAI3D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,QAAQ,CAAI;IAEpB,uEAAuE;
|
|
1
|
+
{"version":3,"file":"PetSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PetSettingsCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAI1F,OAAO,EAAoD,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAG1J,+EAA+E;AAC/E,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qBAAqB;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,0CAA0C;AAC1C,MAAM,WAAW,oBAAqB,SAAQ,SAAS;IACrD,4BAA4B;IAC5B,OAAO,EAAE,cAAc,CAAA;IACvB,qBAAqB;IACrB,OAAO,EAAE,cAAc,CAAA;IACvB,iBAAiB;IACjB,IAAI,EAAE,cAAc,CAAA;IACpB,mBAAmB;IACnB,KAAK,EAAE,cAAc,CAAA;IACrB,oBAAoB;IACpB,MAAM,EAAE,cAAc,CAAA;IACtB,oBAAoB;IACpB,KAAK,EAAE,cAAc,CAAA;IACrB,wEAAwE;IACxE,UAAU,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CACxD;AAED,gEAAgE;AAChE,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,KAAK,EAAE;QACL,iEAAiE;QACjE,eAAe,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAA;KACrD,CAAA;CACF;AAeD,2DAA2D;AAC3D,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAI3D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,QAAQ,CAAI;IAEpB,uEAAuE;IACvE,YAAY,KAAK,EAAE,aAAa,CAAC,WAAW,CAAC,EAW5C;IAED,0EAA0E;YAC5D,QAAQ;IAgBtB,OAAO,CAAC,UAAU;IAalB;;;OAGG;IACH,MAAM,IAAI,mBAAmB,CAE5B;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI,CAEd;CACF;AAED,0DAA0D;AAC1D,MAAM,MAAM,oBAAoB,GAC9B,WAAW,CAAC,KAAK,CAAC,GAChB,UAAU,CAAC,mBAAmB,CAAC,CAAA;AAEnC;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,+BAuF1D;AAED,8DAA8D;AAC9D,MAAM,MAAM,uBAAuB,GACjC,YAAY,CAAC,kBAAkB,CAAC,GAC9B,WAAW,CAAC,KAAK,CAAC,GAClB,UAAU,CAAC,mBAAmB,CAAC,CAAA;AAEnC,mEAAmE;AACnE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,SAAS,CAO5E"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { PluginSettingsCard, ValueField, BooleanField, ChoiceField } from
|
|
3
|
-
import { CardForm, booleanField, choiceField, numberField } from
|
|
2
|
+
import { PluginSettingsCard, ValueField, BooleanField, ChoiceField } from './PluginSettingsCard.js';
|
|
3
|
+
import { CardForm, booleanField, choiceField, numberField } from './settings-form.js';
|
|
4
4
|
import sectionCss from './settings-section.module.css';
|
|
5
5
|
/** Fetch the registry list (the same data the sprite renders from). */
|
|
6
6
|
async function fetchPetChoices() {
|
|
@@ -35,6 +35,8 @@ export interface PetSpriteProps {
|
|
|
35
35
|
onDragEnd: (right: number, bottom: number) => void;
|
|
36
36
|
/** Rename the selected pet (persisted by the host). */
|
|
37
37
|
onRename: (name: string) => void;
|
|
38
|
+
/** Navigate to the session one status bubble reports on. */
|
|
39
|
+
onOpenSession: (sessionId: string) => void;
|
|
38
40
|
/** Clear the reaction bubble (after its CSS animation). */
|
|
39
41
|
onFeedbackDone: () => void;
|
|
40
42
|
/** Locale translate seat (namespace-bound). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PetSprite.d.ts","sourceRoot":"","sources":["../../../src/client/PetSprite.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAqC,WAAW,EAAE,MAAM,OAAO,CAAA;AAG3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAGjD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,8EAA8E;IAC9E,UAAU,EAAE,aAAa,CAAA;IACzB,qDAAqD;IACrD,OAAO,EAAE,gBAAgB,CAAA;IACzB,sCAAsC;IACtC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAA;IAC5B,8BAA8B;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAClD,uDAAuD;IACvD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,2DAA2D;IAC3D,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,+CAA+C;IAC/C,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;CAC1B;AAOD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"PetSprite.d.ts","sourceRoot":"","sources":["../../../src/client/PetSprite.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAqC,WAAW,EAAE,MAAM,OAAO,CAAA;AAG3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAGjD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,8EAA8E;IAC9E,UAAU,EAAE,aAAa,CAAA;IACzB,qDAAqD;IACrD,OAAO,EAAE,gBAAgB,CAAA;IACzB,sCAAsC;IACtC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAA;IAC5B,8BAA8B;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAClD,uDAAuD;IACvD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,4DAA4D;IAC5D,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,2DAA2D;IAC3D,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,+CAA+C;IAC/C,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;CAC1B;AAOD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,WAAW,CA6T5D"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* Pet sprite companion component — the browser half's centerpiece. Renders a
|
|
4
4
|
* fixed-position floating sprite (React portal onto document.body), plays
|
|
@@ -12,7 +12,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
12
12
|
import { useEffect, useRef, useState } from 'react';
|
|
13
13
|
import { createPortal } from 'react-dom';
|
|
14
14
|
import clsx from 'clsx';
|
|
15
|
-
import { framePosition, rowOfTrack, trimTrack } from
|
|
15
|
+
import { framePosition, rowOfTrack, trimTrack } from './spritesheet.js';
|
|
16
16
|
import styles from './pet.module.css';
|
|
17
17
|
/** Clamp a drag offset inside the viewport with a margin. */
|
|
18
18
|
function clampOffset(value, max) {
|
|
@@ -88,10 +88,9 @@ export function PetSprite(props) {
|
|
|
88
88
|
const tick = (ts) => {
|
|
89
89
|
const delta = ts - last;
|
|
90
90
|
last = ts;
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
const track = trimTrack(tracks[animation], rows[row] ?? tracks[animation].frames.length);
|
|
91
|
+
// row/track come from the effect scope: they were computed once above
|
|
92
|
+
// and this effect re-runs when animation/tracks/rows change, so the
|
|
93
|
+
// per-frame recompute (trimTrack slices fresh arrays) is pure waste.
|
|
95
94
|
const st = frameRef.current;
|
|
96
95
|
if (st.track !== animation) {
|
|
97
96
|
st.track = animation;
|
|
@@ -176,9 +175,10 @@ export function PetSprite(props) {
|
|
|
176
175
|
const spriteHeight = Math.round(cell.height * spriteScale);
|
|
177
176
|
// Concurrent sessions each render their own bubble (stacked above the
|
|
178
177
|
// sprite); the legacy single 'bubble' is the fallback when the host serves
|
|
179
|
-
// no per-session list.
|
|
178
|
+
// no per-session list. The hover panel now sits beside the sprite, so the
|
|
179
|
+
// bubbles stay visible and clickable while hovering — no region swap.
|
|
180
180
|
const sessionBubbles = snapshot?.sessions ?? [];
|
|
181
|
-
const statusBubble = feedback === null &&
|
|
181
|
+
const statusBubble = feedback === null && sessionBubbles.length === 0
|
|
182
182
|
? snapshot?.bubble
|
|
183
183
|
: undefined;
|
|
184
184
|
const displayName = snapshot?.name ?? definition.displayName;
|
|
@@ -186,13 +186,14 @@ export function PetSprite(props) {
|
|
|
186
186
|
clearHideTimer();
|
|
187
187
|
setHovered(true);
|
|
188
188
|
}, onPointerLeave: (e) => {
|
|
189
|
-
// The panel
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
// bridge ('.panel::after') keeps the pointer inside the hit
|
|
195
|
-
// the grace period covers a slow mouse crossing the
|
|
189
|
+
// The panel renders OUTSIDE the container's box (absolute, beside
|
|
190
|
+
// the sprite), so moving onto it fires pointerleave on the container.
|
|
191
|
+
// Treat a target still inside the container's DOM (the overflowed
|
|
192
|
+
// panel) as "still hovering"; otherwise give the pointer a short
|
|
193
|
+
// grace period to reach the panel across the gap beside the sprite.
|
|
194
|
+
// The bridge ('.panel::after') keeps the pointer inside the hit
|
|
195
|
+
// area, and the grace period covers a slow mouse crossing the
|
|
196
|
+
// remaining sliver.
|
|
196
197
|
const next = e.relatedTarget;
|
|
197
198
|
if (next instanceof Node && floatRef.current?.contains(next))
|
|
198
199
|
return;
|
|
@@ -212,7 +213,7 @@ export function PetSprite(props) {
|
|
|
212
213
|
if (draggedRef.current)
|
|
213
214
|
return;
|
|
214
215
|
props.onPet();
|
|
215
|
-
}, role: "button", "aria-label": definition.displayName }), feedback !== null && (_jsx("div", { className: clsx(styles.bubble, feedback.kind === 'feed' ? styles.bubbleFeed : styles.bubblePet), children: feedback.text }, feedback.at)), feedback === null &&
|
|
216
|
+
}, role: "button", "aria-label": definition.displayName }), feedback !== null && (_jsx("div", { className: clsx(styles.bubble, feedback.kind === 'feed' ? styles.bubbleFeed : styles.bubblePet), children: feedback.text }, feedback.at)), feedback === null && sessionBubbles.length > 0 && (_jsx("div", { className: styles.bubbleStack, children: sessionBubbles.map(session => (_jsx("button", { type: "button", className: clsx(styles.bubble, styles.bubbleStatus, styles.bubbleClickable), title: props.t('pet.openSessionHint'), onClick: () => { props.onOpenSession(session.sessionId); }, children: session.bubble }, session.sessionId))) })), statusBubble !== undefined && (_jsx("div", { className: clsx(styles.bubble, styles.bubbleStatus), role: "status", "aria-live": "polite", children: statusBubble })), hovered && dragRef.current === null && (_jsx("div", { className: styles.panel, onPointerEnter: () => {
|
|
216
217
|
// Reaching the panel (or its bridge) must cancel any hide timer
|
|
217
218
|
// the container's pointerleave may have armed while the pointer
|
|
218
219
|
// crossed the sliver between the sprite and the panel.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { type ReactNode } from 'react';
|
|
10
10
|
import type { CardShell } from './settings-form.ts';
|
|
11
11
|
/** Copy keys the card chrome itself reads; every consumer locale carries this shared vocabulary. */
|
|
12
|
-
export declare const CARD_COPY_KEYS: readonly [
|
|
12
|
+
export declare const CARD_COPY_KEYS: readonly ['settings.collapse', 'settings.expand', 'settings.notExposed', 'settings.unsaved', 'settings.readOnly', 'settings.saveFailed', 'settings.discard', 'settings.save', 'settings.saving'];
|
|
13
13
|
/** Copy key the card chrome itself reads. */
|
|
14
14
|
export type CardCopyKey = (typeof CARD_COPY_KEYS)[number];
|
|
15
15
|
/** Key domain for the plugin's own copy (inferred per consumer). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAGnD,oGAAoG;AACpG,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* @module @linxin666/dsh-pet/client
|
|
12
12
|
*/
|
|
13
13
|
import type { ClientContext, SettingsScope, SettingsScopeSpec } from '@deepseek-ai/dsh-client-runtime/client';
|
|
14
|
-
/** Required services. */
|
|
14
|
+
/** Required services (sessions powers bubble-to-session navigation). */
|
|
15
15
|
export declare const inject: string[];
|
|
16
16
|
/** Re-exported for consumers that type against the injected face. */
|
|
17
17
|
export type { PetInjected, PetDockEntryProps } from './PetDockEntry.tsx';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAwB,aAAa,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;AA6DnI,wEAAwE;AACxE,eAAO,MAAM,MAAM,UAA2E,CAAA;AAE9F,qEAAqE;AACrE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACxE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC7D,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AACtF,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AACpE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf;;;;WAIG;QACH,aAAa,CAAC,EAAE;YAAE,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;SAAE,CAAA;KAC1E;CACF;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAiN9C"}
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { createElement } from 'react';
|
|
14
14
|
import { createRoot } from 'react-dom/client';
|
|
15
|
-
import { createPetStore } from
|
|
16
|
-
import { PetDockEntry } from
|
|
17
|
-
import { PetSettingsSection, PetSettingsCardController } from
|
|
18
|
-
import { NS, en, zh, t } from
|
|
15
|
+
import { createPetStore } from './pet-store.js';
|
|
16
|
+
import { PetDockEntry } from './PetDockEntry.js';
|
|
17
|
+
import { PetSettingsSection, PetSettingsCardController } from './PetSettingsCard.js';
|
|
18
|
+
import { NS, en, zh, t } from './locales.js';
|
|
19
19
|
/** Same-origin JSON fetch helper (GET without body, POST with JSON body). */
|
|
20
20
|
async function petFetch(path, body) {
|
|
21
21
|
const response = await fetch(path, body === undefined
|
|
@@ -44,8 +44,8 @@ const petApi = {
|
|
|
44
44
|
const POLL_MS = 2000;
|
|
45
45
|
/** Settings namespace the pet settings card edits (the Host plugin registers it). */
|
|
46
46
|
const PET_SETTINGS_NS = 'pet';
|
|
47
|
-
/** Required services. */
|
|
48
|
-
export const inject = ['slots', 'locale', 'connection', 'settingsScope', 'remote'];
|
|
47
|
+
/** Required services (sessions powers bubble-to-session navigation). */
|
|
48
|
+
export const inject = ['slots', 'locale', 'connection', 'settingsScope', 'remote', 'sessions'];
|
|
49
49
|
/**
|
|
50
50
|
* Client plugin body: register dictionaries, mount the global pet entry and
|
|
51
51
|
* poll loop while the plugin is enabled, and seat the settings card as a
|
|
@@ -100,6 +100,11 @@ export function apply(ctx) {
|
|
|
100
100
|
// tick tries again. After it lands, one list feeds both the sprite and
|
|
101
101
|
// the settings card's choices.
|
|
102
102
|
let petsLoaded = false;
|
|
103
|
+
// Latest-wins guard: the 2s tick, visibility recovery, and
|
|
104
|
+
// interaction-triggered refreshes can overlap; only the newest
|
|
105
|
+
// response may publish, so a slow older one can never roll the
|
|
106
|
+
// snapshot back.
|
|
107
|
+
let stateSeq = 0;
|
|
103
108
|
const pollNow = () => {
|
|
104
109
|
if (!petsLoaded) {
|
|
105
110
|
petApi.pets().then((list) => {
|
|
@@ -109,9 +114,15 @@ export function apply(ctx) {
|
|
|
109
114
|
// Retry on the next poll tick.
|
|
110
115
|
});
|
|
111
116
|
}
|
|
117
|
+
const seq = stateSeq + 1;
|
|
118
|
+
stateSeq = seq;
|
|
112
119
|
petApi.state().then((snapshot) => {
|
|
120
|
+
if (seq !== stateSeq)
|
|
121
|
+
return;
|
|
113
122
|
setSnapshot(snapshot);
|
|
114
123
|
}, () => {
|
|
124
|
+
if (seq !== stateSeq)
|
|
125
|
+
return;
|
|
115
126
|
setState('error', 'pet.state transport error');
|
|
116
127
|
});
|
|
117
128
|
};
|
|
@@ -149,9 +160,23 @@ export function apply(ctx) {
|
|
|
149
160
|
document.removeEventListener('visibilitychange', onVisibility);
|
|
150
161
|
};
|
|
151
162
|
}, 'pet: poll');
|
|
163
|
+
// Clicking a session bubble jumps the GUI to that session. A bubble
|
|
164
|
+
// can outlive its disposed session by one poll tick, and the sessions
|
|
165
|
+
// service fails loud on unknown ids, so consult the live list first.
|
|
166
|
+
// The pet's type program also loads the host-side dsh-session package
|
|
167
|
+
// through the service types, whose Context merge declares a different
|
|
168
|
+
// 'sessions' face; pin the browser runtime's outward face here.
|
|
169
|
+
const sessions = ctx.sessions;
|
|
170
|
+
const openSession = (sessionId) => {
|
|
171
|
+
const list = sessions.list.getSnapshot();
|
|
172
|
+
if (list.byId[sessionId] === undefined)
|
|
173
|
+
return;
|
|
174
|
+
sessions.open(sessionId);
|
|
175
|
+
};
|
|
152
176
|
const injected = () => ({
|
|
153
177
|
store: petStore,
|
|
154
178
|
ensure: pollNow,
|
|
179
|
+
openSession,
|
|
155
180
|
pet: () => {
|
|
156
181
|
petApi.interact('pet').then((result) => {
|
|
157
182
|
setFeedback({
|
|
@@ -6,89 +6,91 @@
|
|
|
6
6
|
export declare const NS = "pet";
|
|
7
7
|
/** Chinese copy. */
|
|
8
8
|
export declare const zh: {
|
|
9
|
-
readonly 'pet.feed':
|
|
10
|
-
readonly 'pet.hide':
|
|
11
|
-
readonly 'pet.rename':
|
|
12
|
-
readonly 'pet.confirm':
|
|
13
|
-
readonly 'pet.namePlaceholder':
|
|
14
|
-
readonly 'pet.summon':
|
|
15
|
-
readonly 'pet.rank':
|
|
16
|
-
readonly 'pet.points':
|
|
17
|
-
readonly 'pet.treats':
|
|
18
|
-
readonly 'pet.state.loading':
|
|
19
|
-
readonly 'pet.state.error':
|
|
20
|
-
readonly '
|
|
21
|
-
readonly 'settings.
|
|
22
|
-
readonly 'settings.
|
|
23
|
-
readonly 'settings.
|
|
24
|
-
readonly 'settings.
|
|
25
|
-
readonly 'settings.
|
|
26
|
-
readonly 'settings.
|
|
27
|
-
readonly 'settings.
|
|
28
|
-
readonly 'settings.
|
|
29
|
-
readonly 'settings.
|
|
30
|
-
readonly 'settings.
|
|
31
|
-
readonly 'settings.
|
|
32
|
-
readonly 'settings.
|
|
33
|
-
readonly 'settings.
|
|
34
|
-
readonly 'settings.
|
|
35
|
-
readonly 'settings.
|
|
36
|
-
readonly 'settings.
|
|
37
|
-
readonly 'settings.
|
|
38
|
-
readonly 'settings.
|
|
39
|
-
readonly 'settings.
|
|
40
|
-
readonly 'settings.
|
|
41
|
-
readonly 'settings.
|
|
42
|
-
readonly 'settings.
|
|
43
|
-
readonly 'settings.
|
|
44
|
-
readonly 'settings.
|
|
45
|
-
readonly 'settings.
|
|
46
|
-
readonly 'settings.
|
|
47
|
-
readonly 'settings.
|
|
48
|
-
readonly 'settings.
|
|
9
|
+
readonly 'pet.feed': '喂食';
|
|
10
|
+
readonly 'pet.hide': '隐藏';
|
|
11
|
+
readonly 'pet.rename': '改名';
|
|
12
|
+
readonly 'pet.confirm': '确定';
|
|
13
|
+
readonly 'pet.namePlaceholder': '输入新名字';
|
|
14
|
+
readonly 'pet.summon': '召唤{name}';
|
|
15
|
+
readonly 'pet.rank': '亲密度 {rank}';
|
|
16
|
+
readonly 'pet.points': '{points} 点';
|
|
17
|
+
readonly 'pet.treats': '小鱼干 ×{n}';
|
|
18
|
+
readonly 'pet.state.loading': '宠物正在赶来…';
|
|
19
|
+
readonly 'pet.state.error': '宠物迷路了(连接失败)';
|
|
20
|
+
readonly 'pet.openSessionHint': '点击跳转到对应会话';
|
|
21
|
+
readonly 'settings.title': '宠物';
|
|
22
|
+
readonly 'settings.description': '选择宠物并调整它的显示布局。';
|
|
23
|
+
readonly 'settings.pet': '宠物';
|
|
24
|
+
readonly 'settings.petHint': '选择显示哪只宠物;每只宠物独立命名,可在宠物悬浮面板改名。';
|
|
25
|
+
readonly 'settings.enabled': '启用宠物';
|
|
26
|
+
readonly 'settings.enabledHint': '关闭后隐藏宠物并停止轮询,可在设置里重新启用。';
|
|
27
|
+
readonly 'settings.visible': '显示宠物';
|
|
28
|
+
readonly 'settings.visibleHint': '关闭后宠物隐藏,可从聊天输入区重新召唤。';
|
|
29
|
+
readonly 'settings.size': '大小(px)';
|
|
30
|
+
readonly 'settings.sizeHint': '精灵单元高度,范围 32–512。';
|
|
31
|
+
readonly 'settings.right': '距右侧(px)';
|
|
32
|
+
readonly 'settings.rightHint': '距视口右边缘的水平内缩距离。';
|
|
33
|
+
readonly 'settings.bottom': '距底部(px)';
|
|
34
|
+
readonly 'settings.bottomHint': '距视口底边的垂直内缩距离。';
|
|
35
|
+
readonly 'settings.inherit': '继承';
|
|
36
|
+
readonly 'settings.on': '开';
|
|
37
|
+
readonly 'settings.off': '关';
|
|
38
|
+
readonly 'settings.overridden': '已覆盖';
|
|
39
|
+
readonly 'settings.reset': '恢复默认';
|
|
40
|
+
readonly 'settings.notExposed': '当前 DSH 版本未向设置页暴露本插件的配置命名空间,表单不可用。可编辑 ~/.dsh/settings.yaml 直接配置,或为 dsh-host-apiproxy 的 WEB_SETTINGS_NAMESPACES 白名单补充本命名空间后重启。';
|
|
41
|
+
readonly 'settings.readOnly': '当前部署的设置只读。';
|
|
42
|
+
readonly 'settings.expand': '展开设置';
|
|
43
|
+
readonly 'settings.collapse': '收起设置';
|
|
44
|
+
readonly 'settings.save': '保存';
|
|
45
|
+
readonly 'settings.saving': '保存中…';
|
|
46
|
+
readonly 'settings.discard': '放弃';
|
|
47
|
+
readonly 'settings.unsaved': '未保存';
|
|
48
|
+
readonly 'settings.saveFailed': '部署未接受这些值,已保留供你修改。';
|
|
49
|
+
readonly 'settings.invalidNumber': '请输入数字,留空则使用默认值。';
|
|
49
50
|
};
|
|
50
51
|
/** English copy. */
|
|
51
52
|
export declare const en: {
|
|
52
|
-
readonly 'pet.feed':
|
|
53
|
-
readonly 'pet.hide':
|
|
54
|
-
readonly 'pet.rename':
|
|
55
|
-
readonly 'pet.confirm':
|
|
56
|
-
readonly 'pet.namePlaceholder':
|
|
57
|
-
readonly 'pet.summon':
|
|
58
|
-
readonly 'pet.rank':
|
|
59
|
-
readonly 'pet.points':
|
|
60
|
-
readonly 'pet.treats':
|
|
61
|
-
readonly 'pet.state.loading':
|
|
62
|
-
readonly 'pet.state.error':
|
|
63
|
-
readonly '
|
|
64
|
-
readonly 'settings.
|
|
65
|
-
readonly 'settings.
|
|
66
|
-
readonly 'settings.
|
|
67
|
-
readonly 'settings.
|
|
68
|
-
readonly 'settings.
|
|
69
|
-
readonly 'settings.
|
|
70
|
-
readonly 'settings.
|
|
71
|
-
readonly 'settings.
|
|
72
|
-
readonly 'settings.
|
|
73
|
-
readonly 'settings.
|
|
74
|
-
readonly 'settings.
|
|
75
|
-
readonly 'settings.
|
|
76
|
-
readonly 'settings.
|
|
77
|
-
readonly 'settings.
|
|
78
|
-
readonly 'settings.
|
|
79
|
-
readonly 'settings.
|
|
80
|
-
readonly 'settings.
|
|
81
|
-
readonly 'settings.
|
|
82
|
-
readonly 'settings.
|
|
83
|
-
readonly 'settings.
|
|
84
|
-
readonly 'settings.
|
|
85
|
-
readonly 'settings.
|
|
86
|
-
readonly 'settings.
|
|
87
|
-
readonly 'settings.
|
|
88
|
-
readonly 'settings.
|
|
89
|
-
readonly 'settings.
|
|
90
|
-
readonly 'settings.
|
|
91
|
-
readonly 'settings.
|
|
53
|
+
readonly 'pet.feed': 'Feed';
|
|
54
|
+
readonly 'pet.hide': 'Hide';
|
|
55
|
+
readonly 'pet.rename': 'Rename';
|
|
56
|
+
readonly 'pet.confirm': 'OK';
|
|
57
|
+
readonly 'pet.namePlaceholder': 'Enter a new name';
|
|
58
|
+
readonly 'pet.summon': 'Summon {name}';
|
|
59
|
+
readonly 'pet.rank': 'Affinity {rank}';
|
|
60
|
+
readonly 'pet.points': '{points} pts';
|
|
61
|
+
readonly 'pet.treats': 'Treats ×{n}';
|
|
62
|
+
readonly 'pet.state.loading': 'The pet is on its way…';
|
|
63
|
+
readonly 'pet.state.error': 'The pet is lost (connection failed)';
|
|
64
|
+
readonly 'pet.openSessionHint': 'Click to jump to this session';
|
|
65
|
+
readonly 'settings.title': 'Pet';
|
|
66
|
+
readonly 'settings.description': 'Pick a pet and tune its display layout.';
|
|
67
|
+
readonly 'settings.pet': 'Pet';
|
|
68
|
+
readonly 'settings.petHint': 'Choose which pet shows. Names are stored per pet; rename from the pet hover panel.';
|
|
69
|
+
readonly 'settings.enabled': 'Enable the pet';
|
|
70
|
+
readonly 'settings.enabledHint': 'When off, the pet hides and polling stops; re-enable it here.';
|
|
71
|
+
readonly 'settings.visible': 'Show the pet';
|
|
72
|
+
readonly 'settings.visibleHint': 'When off, the pet hides; summon it again from the input row.';
|
|
73
|
+
readonly 'settings.size': 'Size (px)';
|
|
74
|
+
readonly 'settings.sizeHint': 'Sprite cell height, 32–512.';
|
|
75
|
+
readonly 'settings.right': 'Right inset (px)';
|
|
76
|
+
readonly 'settings.rightHint': 'Horizontal inset from the viewport right edge.';
|
|
77
|
+
readonly 'settings.bottom': 'Bottom inset (px)';
|
|
78
|
+
readonly 'settings.bottomHint': 'Vertical inset from the viewport bottom edge.';
|
|
79
|
+
readonly 'settings.inherit': 'Inherit';
|
|
80
|
+
readonly 'settings.on': 'On';
|
|
81
|
+
readonly 'settings.off': 'Off';
|
|
82
|
+
readonly 'settings.overridden': 'Overridden';
|
|
83
|
+
readonly 'settings.reset': 'Reset to default';
|
|
84
|
+
readonly 'settings.notExposed': 'This DSH version does not expose this plugin\'s settings namespace to the configuration page, so the form is unavailable. Edit ~/.dsh/settings.yaml directly, or add the namespace to dsh-host-apiproxy\'s WEB_SETTINGS_NAMESPACES allowlist and restart.';
|
|
85
|
+
readonly 'settings.readOnly': 'This deployment stores settings read-only.';
|
|
86
|
+
readonly 'settings.expand': 'Show settings';
|
|
87
|
+
readonly 'settings.collapse': 'Hide settings';
|
|
88
|
+
readonly 'settings.save': 'Save';
|
|
89
|
+
readonly 'settings.saving': 'Saving…';
|
|
90
|
+
readonly 'settings.discard': 'Discard';
|
|
91
|
+
readonly 'settings.unsaved': 'Unsaved';
|
|
92
|
+
readonly 'settings.saveFailed': 'The deployment did not accept these values; they were left for you to correct.';
|
|
93
|
+
readonly 'settings.invalidNumber': 'Enter a number, or leave blank to use the default.';
|
|
92
94
|
};
|
|
93
95
|
/** Key union for this namespace. */
|
|
94
96
|
export type PetKey = keyof typeof zh;
|