@linxin666/dsh-pet 0.3.6 → 0.3.10

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.
Files changed (52) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +4 -0
  3. package/README.zh.md +4 -0
  4. package/lib/client.js +187 -88
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +89 -11
  7. package/lib/live2d-vendor.js +106 -95
  8. package/lib/live2d-vendor.js.map +1 -1
  9. package/lib/types/announce.d.ts +53 -0
  10. package/lib/types/announce.d.ts.map +1 -0
  11. package/lib/types/announce.js +80 -0
  12. package/lib/types/client/PetDockEntry.d.ts +14 -5
  13. package/lib/types/client/PetDockEntry.d.ts.map +1 -1
  14. package/lib/types/client/PetDockEntry.js +6 -5
  15. package/lib/types/client/PetSettingsCard.d.ts +2 -1
  16. package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
  17. package/lib/types/client/PetSprite.d.ts +8 -0
  18. package/lib/types/client/PetSprite.d.ts.map +1 -1
  19. package/lib/types/client/PetSprite.js +29 -4
  20. package/lib/types/client/index.d.ts +8 -5
  21. package/lib/types/client/index.d.ts.map +1 -1
  22. package/lib/types/client/index.js +11 -5
  23. package/lib/types/client/locales.d.ts +2 -2
  24. package/lib/types/client/locales.js +2 -2
  25. package/lib/types/client/pet-store.d.ts +1 -1
  26. package/lib/types/client/pet-store.d.ts.map +1 -1
  27. package/lib/types/client/pet-store.js +1 -1
  28. package/lib/types/client/settings-form.d.ts +35 -43
  29. package/lib/types/client/settings-form.d.ts.map +1 -1
  30. package/lib/types/client/settings-form.js +60 -53
  31. package/lib/types/index.d.ts.map +1 -1
  32. package/lib/types/index.js +10 -9
  33. package/lib/types/service.d.ts +18 -0
  34. package/lib/types/service.d.ts.map +1 -1
  35. package/lib/types/service.js +22 -0
  36. package/package.json +17 -13
  37. package/src/announce.ts +103 -0
  38. package/src/client/PetDockEntry.test.tsx +1 -1
  39. package/src/client/PetDockEntry.tsx +15 -4
  40. package/src/client/PetSettingsCard.tsx +2 -1
  41. package/src/client/PetSprite.test.tsx +18 -0
  42. package/src/client/PetSprite.tsx +66 -3
  43. package/src/client/gameplay-hud.test.tsx +1 -1
  44. package/src/client/index.test.tsx +2 -2
  45. package/src/client/index.ts +17 -6
  46. package/src/client/locales.ts +2 -2
  47. package/src/client/pet-store.ts +2 -2
  48. package/src/client/pet.module.css +104 -0
  49. package/src/client/settings-form.ts +78 -92
  50. package/src/dsh-home.ts +1 -1
  51. package/src/index.ts +17 -15
  52. package/src/service.ts +28 -1
package/lib/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { _ as RemarkPicker, a as AFFINITY_MAX, c as applyInteraction, d as emptyAffinity, f as rankOf, g as REMARK_LINE_MAX, h as REMARK_LINES_MAX, i as rowOf, l as applyTurnReward, m as REMARK_KINDS, n as animationForPhase, o as AFFINITY_RANKS, p as BUILTIN_REMARKS, r as defaultPetStateConfig, s as affinityViewOf, t as PetStateMachine, u as defaultAffinityConfig, v as builtinRemark, y as normalizePetRemarks } from "./state-NvDEoCln.js";
2
- import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
3
2
  import z from "schemastery";
4
3
  import { Service } from "@deepseek-ai/cordis";
5
4
  import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, renameSync, statSync, writeFileSync } from "node:fs";
@@ -8,6 +7,67 @@ import { homedir } from "node:os";
8
7
  import { isAbsolute as isAbsolute$1, join as join$1 } from "node:path/posix";
9
8
  import { fileURLToPath } from "node:url";
10
9
  import { readFile } from "node:fs/promises";
10
+ //#region src/announce.ts
11
+ /** Default freshness window. */
12
+ const ANNOUNCE_DEFAULT_TTL_MS = 1e4;
13
+ /**
14
+ * Hard TTL ceiling. A repeating announcer (dsh-usage) declares its poll
15
+ * cadence as the TTL, so an `always`-mode bubble stays continuous across
16
+ * polls; the ceiling means a source that dies unmounts its bubble within at
17
+ * most one missed refresh cycle rather than lingering forever.
18
+ */
19
+ const ANNOUNCE_MAX_TTL_MS = 72e5;
20
+ /** Hard bounds: lengths and the TTL range (1 s .. 60 s). */
21
+ const TITLE_MAX = 80;
22
+ const TEXT_MAX = 120;
23
+ const SOURCE_MAX = 64;
24
+ function boundedString(value, max) {
25
+ if (typeof value !== "string") return void 0;
26
+ const trimmed = value.trim();
27
+ if (trimmed === "") return void 0;
28
+ return trimmed.length <= max ? trimmed : trimmed.slice(0, max);
29
+ }
30
+ /**
31
+ * Validate one announce payload. Unknown fields are dropped, oversized text
32
+ * is truncated, and anything structurally wrong resolves to undefined — a
33
+ * malformed announcement never reaches the pet's bubble surface.
34
+ * @param input - the payload a sibling plugin passed to `pet.announce`.
35
+ * @param now - epoch ms the announcement arrived.
36
+ */
37
+ function parseAnnouncement(input, now) {
38
+ if (typeof input !== "object" || input === null) return void 0;
39
+ const data = input;
40
+ const source = boundedString(data.source, SOURCE_MAX);
41
+ const title = boundedString(data.title, TITLE_MAX);
42
+ if (source === void 0 || title === void 0) return void 0;
43
+ const kind = data.kind === "balance" || data.kind === "cost" || data.kind === "plan" ? data.kind : void 0;
44
+ if (kind === void 0) return void 0;
45
+ const amount = boundedString(data.amount, TEXT_MAX);
46
+ const resetAt = boundedString(data.resetAt, TEXT_MAX);
47
+ const note = boundedString(data.note, TITLE_MAX);
48
+ const percent = typeof data.percent === "number" && Number.isFinite(data.percent) ? Math.max(0, Math.min(100, data.percent)) : void 0;
49
+ if ((kind === "balance" || kind === "cost") && amount === void 0) return void 0;
50
+ if (kind === "plan" && percent === void 0) return void 0;
51
+ const tone = data.tone === "warn" || data.tone === "low" ? data.tone : "ok";
52
+ const ttlMs = typeof data.ttlMs === "number" && Number.isFinite(data.ttlMs) ? Math.max(1e3, Math.min(ANNOUNCE_MAX_TTL_MS, data.ttlMs)) : ANNOUNCE_DEFAULT_TTL_MS;
53
+ return {
54
+ source,
55
+ kind,
56
+ title,
57
+ ...amount !== void 0 ? { amount } : {},
58
+ ...percent !== void 0 ? { percent } : {},
59
+ ...resetAt !== void 0 ? { resetAt } : {},
60
+ ...note !== void 0 ? { note } : {},
61
+ tone,
62
+ ttlMs,
63
+ at: now
64
+ };
65
+ }
66
+ /** Whether an announcement is still fresh at `now`. */
67
+ function announcementFresh(announcement, now) {
68
+ return now - announcement.at < announcement.ttlMs;
69
+ }
70
+ //#endregion
11
71
  //#region src/chatter.ts
12
72
  /** While a scene persists, its copy advances on this cadence (ms). */
13
73
  const STATUS_ROTATE_MS = 4e3;
@@ -4090,6 +4150,8 @@ var PetService = class extends Service {
4090
4150
  enabled;
4091
4151
  /** Status-decoration master switch (M5, #567); mirrored from settings. */
4092
4152
  decorationEnabled;
4153
+ /** The freshest plugin-authored announcement (dsh-usage linkage). */
4154
+ announcement;
4093
4155
  disposeActivity;
4094
4156
  /** Session whose most recent meaningful event currently drives the global pet. */
4095
4157
  displaySession;
@@ -4167,6 +4229,18 @@ var PetService = class extends Service {
4167
4229
  async state(currentSessionId) {
4168
4230
  return this.view(currentSessionId);
4169
4231
  }
4232
+ /**
4233
+ * RPC: one plugin-authored announcement bubble (dsh-usage linkage). The
4234
+ * payload is validated into a bounded PetAnnouncement; a malformed one is
4235
+ * dropped silently — a sibling plugin's bug must never surface as pet
4236
+ * breakage. The announcement is in-memory only.
4237
+ */
4238
+ announce(input) {
4239
+ const parsed = parseAnnouncement(input, Date.now());
4240
+ if (parsed === void 0) return { ok: false };
4241
+ this.announcement = parsed;
4242
+ return { ok: true };
4243
+ }
4170
4244
  /** Current persisted display config (read-only view). */
4171
4245
  display() {
4172
4246
  return { ...this.ledger.snapshot.display };
@@ -4646,6 +4720,7 @@ var PetService = class extends Service {
4646
4720
  settleGameplay(state, gameplayDef, Date.now(), { sessionActive: snapshot.sessionActive });
4647
4721
  gameplay = this.gameplayViewOf(state);
4648
4722
  }
4723
+ const announcement = this.announcement !== void 0 && announcementFresh(this.announcement, Date.now()) ? this.announcement : void 0;
4649
4724
  return {
4650
4725
  animation: snapshot.animation,
4651
4726
  ...snapshot.bubble === void 0 ? {} : { bubble: snapshot.bubble },
@@ -4653,6 +4728,7 @@ var PetService = class extends Service {
4653
4728
  sessionActive: snapshot.sessionActive,
4654
4729
  sessions,
4655
4730
  ...decoration === void 0 ? {} : { decoration },
4731
+ ...announcement === void 0 ? {} : { announcement },
4656
4732
  affinity: this.ledger.affinityView(Date.now()),
4657
4733
  display: { ...this.ledger.snapshot.display },
4658
4734
  pet: {
@@ -5466,16 +5542,18 @@ function applyImpl(ctx, config = {}) {
5466
5542
  disposeRoutes = void 0;
5467
5543
  }
5468
5544
  };
5469
- installSettingsSection(ctx, settingsNamespace("pet"), makePetSettingsSchema(service.selectedPetId()), base, {
5470
- setSource: (source) => {
5471
- current = source;
5472
- },
5473
- onChange: () => {
5474
- const section = current();
5475
- service.applySettingsSection(section);
5476
- service.setEnabled(section.enabled ?? true);
5477
- syncRoutes();
5478
- }
5545
+ ctx.inject(["settings"], (settingsCtx) => {
5546
+ settingsCtx.settings.installSection(ctx, "pet", makePetSettingsSchema(service.selectedPetId()), base, {
5547
+ setSource: (source) => {
5548
+ current = source;
5549
+ },
5550
+ onChange: () => {
5551
+ const section = current();
5552
+ service.applySettingsSection(section);
5553
+ service.setEnabled(section.enabled ?? true);
5554
+ syncRoutes();
5555
+ }
5556
+ });
5479
5557
  });
5480
5558
  syncRoutes();
5481
5559
  }