@linxin666/dsh-pet 0.1.18 → 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 +12 -5
- package/README.zh.md +12 -5
- package/lib/client.js +95 -26
- package/lib/client.js.map +1 -1
- package/lib/index.js +144 -31
- package/lib/invariant.js +2 -2
- package/lib/state-Diiq8vjk.js +394 -0
- package/lib/types/affinity.d.ts +39 -11
- package/lib/types/affinity.d.ts.map +1 -1
- package/lib/types/affinity.js +21 -7
- 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 +5 -0
- package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PetSettingsCard.js +9 -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 +22 -15
- 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 +45 -14
- 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 +8 -0
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/settings-form.js +15 -1
- package/lib/types/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/event-projection.d.ts.map +1 -1
- package/lib/types/event-projection.js +3 -1
- package/lib/types/index.d.ts +6 -3
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +15 -12
- package/lib/types/invariant.js +2 -2
- package/lib/types/ledger.d.ts +16 -1
- package/lib/types/ledger.d.ts.map +1 -1
- package/lib/types/ledger.js +31 -6
- 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.d.ts +10 -0
- package/lib/types/registry.d.ts.map +1 -1
- package/lib/types/registry.js +3 -0
- package/lib/types/remarks.d.ts +56 -0
- package/lib/types/remarks.d.ts.map +1 -0
- package/lib/types/remarks.js +157 -0
- package/lib/types/routes.js +2 -2
- package/lib/types/service.d.ts +44 -3
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +100 -23
- package/lib/types/state.d.ts.map +1 -1
- package/lib/types/state.js +5 -5
- package/lib/types/treats.d.ts +3 -0
- package/lib/types/treats.d.ts.map +1 -1
- package/lib/types/treats.js +5 -2
- package/package.json +1 -1
- package/src/affinity.test.ts +19 -0
- package/src/affinity.ts +22 -7
- package/src/client/PetDockEntry.tsx +3 -0
- package/src/client/PetSettingsCard.tsx +8 -0
- package/src/client/PetSprite.test.tsx +89 -3
- package/src/client/PetSprite.tsx +36 -12
- package/src/client/index.ts +40 -11
- package/src/client/locales.ts +2 -0
- package/src/client/pet.module.css +52 -10
- package/src/client/settings-form.ts +15 -1
- package/src/client/spritesheet.ts +3 -13
- package/src/event-projection.ts +3 -1
- package/src/index.ts +16 -2
- package/src/ledger.test.ts +40 -9
- package/src/ledger.ts +33 -4
- package/src/mount-once.ts +48 -0
- package/src/persist.test.ts +1 -1
- package/src/registry.test.ts +27 -0
- package/src/registry.ts +12 -0
- package/src/remarks.test.ts +89 -0
- package/src/remarks.ts +177 -0
- package/src/service.ts +124 -18
- package/src/state.test.ts +9 -0
- package/src/state.ts +5 -5
- package/src/treats.test.ts +13 -11
- package/src/treats.ts +5 -2
- package/lib/state-CFyJv0sQ.js +0 -213
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as AFFINITY_MAX, c as applyInteraction, d as emptyAffinity, f as rankOf, i as rowOf, l as applyTurnReward, n as animationForPhase, o as AFFINITY_RANKS, r as defaultPetStateConfig, s as affinityViewOf, t as PetStateMachine, u as defaultAffinityConfig } from "./state-
|
|
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-Diiq8vjk.js";
|
|
2
2
|
import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
3
3
|
import z from "schemastery";
|
|
4
4
|
import { Service } from "@deepseek-ai/cordis";
|
|
@@ -117,10 +117,7 @@ function projectOfficialEvent(event, runtime) {
|
|
|
117
117
|
phase: "waiting",
|
|
118
118
|
line: "等待继续"
|
|
119
119
|
} };
|
|
120
|
-
case "aborted": return { input: {
|
|
121
|
-
phase: "idle",
|
|
122
|
-
line: "已停止"
|
|
123
|
-
} };
|
|
120
|
+
case "aborted": return { input: { phase: "idle" } };
|
|
124
121
|
default: return { input: { phase: "idle" } };
|
|
125
122
|
}
|
|
126
123
|
default: return;
|
|
@@ -129,8 +126,8 @@ function projectOfficialEvent(event, runtime) {
|
|
|
129
126
|
//#endregion
|
|
130
127
|
//#region src/treats.ts
|
|
131
128
|
const defaultTreatConfig = {
|
|
132
|
-
turnsPerTreat:
|
|
133
|
-
timeTreatMs:
|
|
129
|
+
turnsPerTreat: 30,
|
|
130
|
+
timeTreatMs: 300 * 6e4,
|
|
134
131
|
maxTreats: 20
|
|
135
132
|
};
|
|
136
133
|
function emptyTreatLedger() {
|
|
@@ -217,6 +214,8 @@ function consumeTreat(ledger) {
|
|
|
217
214
|
var PetLedger = class {
|
|
218
215
|
affinityConfig;
|
|
219
216
|
treatConfig;
|
|
217
|
+
/** Round-robin reaction picker; rebuilt when the selected pet changes. */
|
|
218
|
+
picker;
|
|
220
219
|
current;
|
|
221
220
|
/** Completed turns already rewarded, per session (turn numbers are per-session). */
|
|
222
221
|
rewardedTurns = /* @__PURE__ */ new Map();
|
|
@@ -231,6 +230,7 @@ var PetLedger = class {
|
|
|
231
230
|
...defaultTreatConfig,
|
|
232
231
|
...config.treats ?? {}
|
|
233
232
|
};
|
|
233
|
+
this.picker = new RemarkPicker(config.remarks);
|
|
234
234
|
this.current = persist;
|
|
235
235
|
}
|
|
236
236
|
/** Affinity cooldown/rank tuning (read-only). */
|
|
@@ -251,6 +251,13 @@ var PetLedger = class {
|
|
|
251
251
|
this.dirty = false;
|
|
252
252
|
return was;
|
|
253
253
|
}
|
|
254
|
+
/**
|
|
255
|
+
* Drop a session's rewarded-turn bookkeeping once that session is disposed,
|
|
256
|
+
* so the per-session map does not grow without bound.
|
|
257
|
+
*/
|
|
258
|
+
forgetSession(sessionId) {
|
|
259
|
+
this.rewardedTurns.delete(sessionId);
|
|
260
|
+
}
|
|
254
261
|
/** Replace the display block (clamping stays a caller concern). */
|
|
255
262
|
setDisplay(display) {
|
|
256
263
|
this.current = {
|
|
@@ -280,9 +287,16 @@ var PetLedger = class {
|
|
|
280
287
|
this.dirty = true;
|
|
281
288
|
}
|
|
282
289
|
/**
|
|
290
|
+
* Swap the reaction pools to another pet's custom remarks (called on pet
|
|
291
|
+
* selection). Slots the pet does not declare fall back to built-ins.
|
|
292
|
+
*/
|
|
293
|
+
setRemarks(remarks) {
|
|
294
|
+
this.picker = new RemarkPicker(remarks);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
283
297
|
* Settle the treat economy (work + time output since the last settlement).
|
|
284
298
|
* A zero-gain first settlement still starts the time clock (anchor write),
|
|
285
|
-
* which is how the
|
|
299
|
+
* which is how the time output can ever accrue. Returns true when
|
|
286
300
|
* the in-memory ledger changed and should be persisted.
|
|
287
301
|
*/
|
|
288
302
|
settleTreats(nowMs) {
|
|
@@ -332,14 +346,14 @@ var PetLedger = class {
|
|
|
332
346
|
if (kind === "feed") this.settleTreats(nowMs);
|
|
333
347
|
const outcome = applyInteraction(this.current.affinity, kind, nowMs, this.affinityConfig);
|
|
334
348
|
if (kind === "feed" && !outcome.accepted) return {
|
|
335
|
-
reaction:
|
|
349
|
+
reaction: this.picker.pick("feedCooldown"),
|
|
336
350
|
delta: 0,
|
|
337
351
|
affinity: this.affinityView(nowMs)
|
|
338
352
|
};
|
|
339
353
|
if (kind === "feed") {
|
|
340
354
|
const consume = consumeTreat(this.current.treats);
|
|
341
355
|
if (!consume.ok) return {
|
|
342
|
-
reaction: "
|
|
356
|
+
reaction: this.picker.pick("noTreats"),
|
|
343
357
|
delta: 0,
|
|
344
358
|
affinity: this.affinityView(nowMs)
|
|
345
359
|
};
|
|
@@ -357,7 +371,7 @@ var PetLedger = class {
|
|
|
357
371
|
this.dirty = true;
|
|
358
372
|
}
|
|
359
373
|
return {
|
|
360
|
-
reaction: outcome.
|
|
374
|
+
reaction: this.picker.pick(outcome.accepted ? kind : "petCooldown"),
|
|
361
375
|
delta: outcome.delta,
|
|
362
376
|
affinity: this.affinityView(nowMs)
|
|
363
377
|
};
|
|
@@ -464,7 +478,7 @@ function loadPetPersist(dir = petHomeDir()) {
|
|
|
464
478
|
const base = emptyPersist();
|
|
465
479
|
const rawAffinity = parsed.affinity ?? {};
|
|
466
480
|
const affinity = {
|
|
467
|
-
points: clamp(finiteNum(rawAffinity.points, 0),
|
|
481
|
+
points: clamp(finiteNum(rawAffinity.points, 0), AFFINITY_MAX),
|
|
468
482
|
lastPetAt: clamp(finiteNum(rawAffinity.lastPetAt, 0), Number.MAX_SAFE_INTEGER),
|
|
469
483
|
lastFeedAt: clamp(finiteNum(rawAffinity.lastFeedAt, 0), Number.MAX_SAFE_INTEGER),
|
|
470
484
|
pets: clamp(finiteNum(rawAffinity.pets, 0), Number.MAX_SAFE_INTEGER),
|
|
@@ -728,6 +742,7 @@ function resolvePetManifest(raw, dir, options = {}) {
|
|
|
728
742
|
const rows = DEFAULT_FRAME_COUNTS.map((fallback, index) => {
|
|
729
743
|
return finiteInt(Array.isArray(source.frames) ? source.frames[index] : void 0, fallback, columns);
|
|
730
744
|
});
|
|
745
|
+
const remarks = normalizePetRemarks(source.remarks, (message) => warn("manifest " + id + ": " + message));
|
|
731
746
|
const trackOverrides = typeof source.tracks === "object" && source.tracks !== null ? source.tracks : {};
|
|
732
747
|
const tracks = {};
|
|
733
748
|
for (const [row, animation] of PET_ROW_ORDER.entries()) {
|
|
@@ -758,7 +773,8 @@ function resolvePetManifest(raw, dir, options = {}) {
|
|
|
758
773
|
atlasUrl: assetUrl(assetPrefix, id, spritesheet),
|
|
759
774
|
manifestUrl: assetUrl(assetPrefix, id, "pet.json"),
|
|
760
775
|
dir,
|
|
761
|
-
spritesheetPath: spritesheetPath.join("/")
|
|
776
|
+
spritesheetPath: spritesheetPath.join("/"),
|
|
777
|
+
...remarks === void 0 ? {} : { remarks }
|
|
762
778
|
};
|
|
763
779
|
}
|
|
764
780
|
/** Scan one directory of pet folders; entries come back in name order. */
|
|
@@ -852,6 +868,8 @@ function petEntryView(entry) {
|
|
|
852
868
|
manifestUrl: entry.manifestUrl
|
|
853
869
|
};
|
|
854
870
|
}
|
|
871
|
+
/** Hard cap on simultaneously displayed session bubbles (most recent first). */
|
|
872
|
+
const MAX_SESSION_BUBBLES = 12;
|
|
855
873
|
/**
|
|
856
874
|
* Cordis service exposing the pet RPC domain. Lazy: nothing is scanned or
|
|
857
875
|
* written until an economic event or interaction arrives; event listeners
|
|
@@ -861,6 +879,7 @@ function petEntryView(entry) {
|
|
|
861
879
|
var PetService = class extends Service {
|
|
862
880
|
static inject = [];
|
|
863
881
|
machine;
|
|
882
|
+
stateConfig;
|
|
864
883
|
ledger;
|
|
865
884
|
registry;
|
|
866
885
|
persistDir;
|
|
@@ -868,7 +887,12 @@ var PetService = class extends Service {
|
|
|
868
887
|
disposeActivity;
|
|
869
888
|
/** Session whose most recent meaningful event currently drives the global pet. */
|
|
870
889
|
displaySession;
|
|
871
|
-
|
|
890
|
+
/**
|
|
891
|
+
* Per-session activity, most recent last (Map insertion order). Bounded by
|
|
892
|
+
* MAX_SESSION_BUBBLES so a burst of sessions cannot grow it without bound;
|
|
893
|
+
* disposed sessions are removed by the 'session/disposed' listener.
|
|
894
|
+
*/
|
|
895
|
+
sessionActivity = /* @__PURE__ */ new Map();
|
|
872
896
|
constructor(ctx, config = {}) {
|
|
873
897
|
super(ctx, "pet");
|
|
874
898
|
this.persistDir = config.persistDir ?? petHomeDir();
|
|
@@ -882,15 +906,18 @@ var PetService = class extends Service {
|
|
|
882
906
|
...persist,
|
|
883
907
|
petId: this.registry.defaultEntry().id
|
|
884
908
|
};
|
|
909
|
+
const selected = this.registry.byId(persist.petId) ?? this.registry.defaultEntry();
|
|
885
910
|
const ledgerConfig = {
|
|
886
911
|
affinity: config.affinity,
|
|
887
|
-
treats: config.treats
|
|
912
|
+
treats: config.treats,
|
|
913
|
+
remarks: selected.remarks
|
|
888
914
|
};
|
|
889
915
|
this.ledger = new PetLedger(persist, ledgerConfig);
|
|
890
|
-
this.
|
|
916
|
+
this.stateConfig = {
|
|
891
917
|
...defaultPetStateConfig,
|
|
892
918
|
...config.state ?? {}
|
|
893
|
-
}
|
|
919
|
+
};
|
|
920
|
+
this.machine = new PetStateMachine(this.stateConfig);
|
|
894
921
|
this.enabled = config.enabled ?? true;
|
|
895
922
|
this.syncActivity();
|
|
896
923
|
}
|
|
@@ -936,6 +963,7 @@ var PetService = class extends Service {
|
|
|
936
963
|
error: "unknown-pet"
|
|
937
964
|
};
|
|
938
965
|
this.ledger.setPetId(entry.id);
|
|
966
|
+
this.ledger.setRemarks(entry.remarks);
|
|
939
967
|
this.flush();
|
|
940
968
|
this.syncSettingsFromPet();
|
|
941
969
|
return {
|
|
@@ -956,7 +984,7 @@ var PetService = class extends Service {
|
|
|
956
984
|
if (!this.enabled) return;
|
|
957
985
|
this.disposeActivity = (() => {
|
|
958
986
|
const disposers = [this.ctx.on("session/event", (session, event) => {
|
|
959
|
-
const runtime = this.
|
|
987
|
+
const runtime = this.activityOf(session).runtime;
|
|
960
988
|
if (event.type === "activity/status") {
|
|
961
989
|
const payload = event.data ?? {};
|
|
962
990
|
if (typeof payload.phase !== "string" || !isActivityPhase(payload.phase)) return;
|
|
@@ -974,26 +1002,52 @@ var PetService = class extends Service {
|
|
|
974
1002
|
this.applyActivity(session, transition.input);
|
|
975
1003
|
if (transition.completedTurn !== void 0) this.rewardTurn(String(session.id), transition.completedTurn);
|
|
976
1004
|
}), this.ctx.on("session/disposed", (session) => {
|
|
1005
|
+
this.ledger.forgetSession(String(session.id));
|
|
1006
|
+
this.sessionActivity.delete(session);
|
|
977
1007
|
if (session !== this.displaySession) return;
|
|
978
1008
|
this.displaySession = void 0;
|
|
979
|
-
this.
|
|
1009
|
+
const remaining = [...this.sessionActivity.entries()].at(-1);
|
|
1010
|
+
if (remaining !== void 0) {
|
|
1011
|
+
const [nextSession, activity] = remaining;
|
|
1012
|
+
this.displaySession = nextSession;
|
|
1013
|
+
if (activity.lastInput !== void 0) this.machine.onActivityStatus(activity.lastInput);
|
|
1014
|
+
this.machine.onSessionActive();
|
|
1015
|
+
} else this.machine.onSessionDisposed();
|
|
980
1016
|
})];
|
|
981
1017
|
return () => {
|
|
982
1018
|
for (const dispose of disposers) dispose();
|
|
983
1019
|
};
|
|
984
1020
|
})();
|
|
985
1021
|
}
|
|
986
|
-
/** Return the
|
|
987
|
-
|
|
988
|
-
let
|
|
989
|
-
if (
|
|
990
|
-
|
|
991
|
-
|
|
1022
|
+
/** Return the per-session activity record, creating it on first sight. */
|
|
1023
|
+
activityOf(session) {
|
|
1024
|
+
let activity = this.sessionActivity.get(session);
|
|
1025
|
+
if (activity === void 0) {
|
|
1026
|
+
activity = {
|
|
1027
|
+
runtime: emptyProjectionRuntime(),
|
|
1028
|
+
machine: new PetStateMachine(this.stateConfig)
|
|
1029
|
+
};
|
|
1030
|
+
this.sessionActivity.set(session, activity);
|
|
992
1031
|
}
|
|
993
|
-
return
|
|
1032
|
+
return activity;
|
|
994
1033
|
}
|
|
995
|
-
/**
|
|
1034
|
+
/**
|
|
1035
|
+
* Commit one activity: the session's own machine renders its bubble, and
|
|
1036
|
+
* the session becomes the host-global display session (most recent
|
|
1037
|
+
* meaningful event wins the sprite animation).
|
|
1038
|
+
*/
|
|
996
1039
|
applyActivity(session, input) {
|
|
1040
|
+
const activity = this.activityOf(session);
|
|
1041
|
+
activity.lastInput = input;
|
|
1042
|
+
activity.machine.onActivityStatus(input);
|
|
1043
|
+
activity.machine.onSessionActive();
|
|
1044
|
+
this.sessionActivity.delete(session);
|
|
1045
|
+
this.sessionActivity.set(session, activity);
|
|
1046
|
+
while (this.sessionActivity.size > 12) {
|
|
1047
|
+
const oldest = this.sessionActivity.keys().next().value;
|
|
1048
|
+
if (oldest === void 0) break;
|
|
1049
|
+
this.sessionActivity.delete(oldest);
|
|
1050
|
+
}
|
|
997
1051
|
this.displaySession = session;
|
|
998
1052
|
this.machine.onActivityStatus(input);
|
|
999
1053
|
this.machine.onSessionActive();
|
|
@@ -1060,8 +1114,11 @@ var PetService = class extends Service {
|
|
|
1060
1114
|
* @param section - the resolved settings section.
|
|
1061
1115
|
*/
|
|
1062
1116
|
applySettingsSection(section) {
|
|
1063
|
-
|
|
1064
|
-
|
|
1117
|
+
const selected = typeof section.petId === "string" ? this.registry.byId(section.petId) : void 0;
|
|
1118
|
+
if (selected !== void 0) {
|
|
1119
|
+
this.ledger.setPetId(selected.id);
|
|
1120
|
+
this.ledger.setRemarks(selected.remarks);
|
|
1121
|
+
} else if (section.petId !== void 0) this.syncSettingsFromPet();
|
|
1065
1122
|
const next = { ...this.ledger.snapshot.display };
|
|
1066
1123
|
next.visible = section.visible && (section.enabled ?? true);
|
|
1067
1124
|
next.size = Math.round(Math.min(512, Math.max(32, section.size)));
|
|
@@ -1094,11 +1151,25 @@ var PetService = class extends Service {
|
|
|
1094
1151
|
view() {
|
|
1095
1152
|
const snapshot = this.machine.render();
|
|
1096
1153
|
const entry = this.activeEntry();
|
|
1154
|
+
const sessions = [];
|
|
1155
|
+
for (const [session, activity] of [...this.sessionActivity.entries()].reverse()) {
|
|
1156
|
+
if (sessions.length >= 12) break;
|
|
1157
|
+
if (session.header?.origin === "subagent") continue;
|
|
1158
|
+
const perSession = activity.machine.render();
|
|
1159
|
+
if (perSession.bubble === void 0) continue;
|
|
1160
|
+
sessions.push({
|
|
1161
|
+
sessionId: String(session.id),
|
|
1162
|
+
animation: perSession.animation,
|
|
1163
|
+
bubble: perSession.bubble,
|
|
1164
|
+
phase: perSession.phase
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1097
1167
|
return {
|
|
1098
1168
|
animation: snapshot.animation,
|
|
1099
1169
|
...snapshot.bubble === void 0 ? {} : { bubble: snapshot.bubble },
|
|
1100
1170
|
phase: snapshot.phase,
|
|
1101
1171
|
sessionActive: snapshot.sessionActive,
|
|
1172
|
+
sessions,
|
|
1102
1173
|
affinity: this.ledger.affinityView(Date.now()),
|
|
1103
1174
|
display: { ...this.ledger.snapshot.display },
|
|
1104
1175
|
pet: {
|
|
@@ -1386,6 +1457,47 @@ function makePetRoutes(deps) {
|
|
|
1386
1457
|
return [...apiRoutes, assetRoute];
|
|
1387
1458
|
}
|
|
1388
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
|
|
1389
1501
|
//#region src/index.ts
|
|
1390
1502
|
/** Stable cordis plugin name (matches cordis.patch.yml insert id). */
|
|
1391
1503
|
const name = "pet";
|
|
@@ -1410,7 +1522,8 @@ function makePetSettingsSchema(fallbackPetId) {
|
|
|
1410
1522
|
});
|
|
1411
1523
|
}
|
|
1412
1524
|
/** Register the pet service and its API + asset routes on the context. */
|
|
1413
|
-
|
|
1525
|
+
const apply = mountOnce("@linxin666/dsh-pet", applyImpl);
|
|
1526
|
+
function applyImpl(ctx, config = {}) {
|
|
1414
1527
|
const registry = config.registry ?? loadPetRegistry({
|
|
1415
1528
|
packageRoot: petPackageRoot(import.meta.url),
|
|
1416
1529
|
...config.pets === void 0 ? {} : { extra: config.pets }
|
|
@@ -1457,4 +1570,4 @@ function apply(ctx, config = {}) {
|
|
|
1457
1570
|
syncRoutes();
|
|
1458
1571
|
}
|
|
1459
1572
|
//#endregion
|
|
1460
|
-
export { AFFINITY_MAX, AFFINITY_RANKS, DEFAULT_FRAME_COUNTS, DEFAULT_PET_CELL, DEFAULT_PET_COLUMNS, DEFAULT_PET_ID, DEFAULT_PET_NAME, DEFAULT_PET_ROW_COUNT, DEFAULT_TRACK_PATTERNS, PET_API_PREFIX, PET_ASSET_PREFIX, PET_NAME_MAX_LENGTH, PET_ROW_ORDER, PetService, PetStateMachine, animationForPhase, apply, applyInteraction, applyTurnReward, codexPetsDir, consumeTreat, defaultDisplayConfig, defaultTreatConfig, emptyAffinity, emptyPersist, emptyTreatLedger, inject, loadPetPersist, loadPetRegistry, makePetRoutes, makePetSettingsSchema, name, petEntryView, petHomeDir, petPackageRoot, rankOf, resolvePetManifest, rowOf, savePetPersist, settleTreatGrants };
|
|
1573
|
+
export { AFFINITY_MAX, AFFINITY_RANKS, BUILTIN_REMARKS, DEFAULT_FRAME_COUNTS, DEFAULT_PET_CELL, DEFAULT_PET_COLUMNS, DEFAULT_PET_ID, DEFAULT_PET_NAME, DEFAULT_PET_ROW_COUNT, DEFAULT_TRACK_PATTERNS, MAX_SESSION_BUBBLES, PET_API_PREFIX, PET_ASSET_PREFIX, PET_NAME_MAX_LENGTH, PET_ROW_ORDER, PetService, PetStateMachine, REMARK_KINDS, REMARK_LINES_MAX, REMARK_LINE_MAX, RemarkPicker, animationForPhase, apply, applyInteraction, applyTurnReward, builtinRemark, codexPetsDir, consumeTreat, defaultDisplayConfig, defaultTreatConfig, emptyAffinity, emptyPersist, emptyTreatLedger, inject, loadPetPersist, loadPetRegistry, makePetRoutes, makePetSettingsSchema, name, normalizePetRemarks, petEntryView, petHomeDir, petPackageRoot, rankOf, resolvePetManifest, rowOf, savePetPersist, settleTreatGrants };
|
package/lib/invariant.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as animationForPhase, o as AFFINITY_RANKS, u as defaultAffinityConfig } from "./state-
|
|
1
|
+
import { a as AFFINITY_MAX, n as animationForPhase, o as AFFINITY_RANKS, u as defaultAffinityConfig } from "./state-Diiq8vjk.js";
|
|
2
2
|
//#region src/invariant.ts
|
|
3
3
|
/**
|
|
4
4
|
* Package invariants — cheap structural checks run at import time on the
|
|
@@ -11,7 +11,7 @@ function invariant(condition, message) {
|
|
|
11
11
|
}
|
|
12
12
|
/** Run every package invariant once; throws on the first violation. */
|
|
13
13
|
function runPetInvariants() {
|
|
14
|
-
invariant(
|
|
14
|
+
invariant(AFFINITY_MAX > 0, "AFFINITY_MAX must be positive");
|
|
15
15
|
invariant(AFFINITY_RANKS.length > 0 && AFFINITY_RANKS[0].min === 0, "AFFINITY_RANKS must start at 0");
|
|
16
16
|
invariant(defaultAffinityConfig.turnReward > 0, "turnReward must be positive");
|
|
17
17
|
invariant(defaultAffinityConfig.feedCooldownMs > defaultAffinityConfig.petCooldownMs, "feed cooldown must exceed pet cooldown");
|