@linxin666/dsh-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.
Files changed (79) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +106 -0
  3. package/assets/whale/pet.json +7 -0
  4. package/assets/whale/previews/failed.gif +0 -0
  5. package/assets/whale/previews/idle.gif +0 -0
  6. package/assets/whale/previews/jumping.gif +0 -0
  7. package/assets/whale/previews/review.gif +0 -0
  8. package/assets/whale/previews/running-left.gif +0 -0
  9. package/assets/whale/previews/running-right.gif +0 -0
  10. package/assets/whale/previews/running.gif +0 -0
  11. package/assets/whale/previews/waiting.gif +0 -0
  12. package/assets/whale/previews/waving.gif +0 -0
  13. package/assets/whale/spritesheet.webp +0 -0
  14. package/cordis.patch.yml +10 -0
  15. package/lib/client.js +1515 -0
  16. package/lib/index.js +642 -0
  17. package/lib/invariant.js +34 -0
  18. package/lib/types/affinity.d.ts +83 -0
  19. package/lib/types/affinity.d.ts.map +1 -0
  20. package/lib/types/client/PetDockEntry.d.ts +44 -0
  21. package/lib/types/client/PetDockEntry.d.ts.map +1 -0
  22. package/lib/types/client/PetSettingsCard.d.ts +67 -0
  23. package/lib/types/client/PetSettingsCard.d.ts.map +1 -0
  24. package/lib/types/client/PluginSettingsCard.d.ts +78 -0
  25. package/lib/types/client/PluginSettingsCard.d.ts.map +1 -0
  26. package/lib/types/client/WhalePet.d.ts +49 -0
  27. package/lib/types/client/WhalePet.d.ts.map +1 -0
  28. package/lib/types/client/index.d.ts +46 -0
  29. package/lib/types/client/index.d.ts.map +1 -0
  30. package/lib/types/client/locales.d.ts +101 -0
  31. package/lib/types/client/locales.d.ts.map +1 -0
  32. package/lib/types/client/pet-store.d.ts +49 -0
  33. package/lib/types/client/pet-store.d.ts.map +1 -0
  34. package/lib/types/client/settings-form.d.ts +119 -0
  35. package/lib/types/client/settings-form.d.ts.map +1 -0
  36. package/lib/types/client/slots-augment.d.ts +19 -0
  37. package/lib/types/client/slots-augment.d.ts.map +1 -0
  38. package/lib/types/client/spritesheet.d.ts +69 -0
  39. package/lib/types/client/spritesheet.d.ts.map +1 -0
  40. package/lib/types/index.d.ts +44 -0
  41. package/lib/types/index.d.ts.map +1 -0
  42. package/lib/types/invariant.d.ts +10 -0
  43. package/lib/types/invariant.d.ts.map +1 -0
  44. package/lib/types/persist.d.ts +45 -0
  45. package/lib/types/persist.d.ts.map +1 -0
  46. package/lib/types/routes.d.ts +22 -0
  47. package/lib/types/routes.d.ts.map +1 -0
  48. package/lib/types/service.d.ts +161 -0
  49. package/lib/types/service.d.ts.map +1 -0
  50. package/lib/types/state.d.ts +80 -0
  51. package/lib/types/state.d.ts.map +1 -0
  52. package/lib/types/treats.d.ts +59 -0
  53. package/lib/types/treats.d.ts.map +1 -0
  54. package/package.json +100 -0
  55. package/src/affinity.test.ts +74 -0
  56. package/src/affinity.ts +144 -0
  57. package/src/client/PetDockEntry.tsx +95 -0
  58. package/src/client/PetSettingsCard.tsx +186 -0
  59. package/src/client/PluginSettingsCard.tsx +207 -0
  60. package/src/client/WhalePet.tsx +342 -0
  61. package/src/client/css-modules.d.ts +6 -0
  62. package/src/client/index.ts +261 -0
  63. package/src/client/locales.ts +108 -0
  64. package/src/client/pet-store.ts +80 -0
  65. package/src/client/pet.module.css +185 -0
  66. package/src/client/settings-card.module.css +277 -0
  67. package/src/client/settings-form.ts +294 -0
  68. package/src/client/slots-augment.ts +27 -0
  69. package/src/client/spritesheet.ts +138 -0
  70. package/src/index.ts +148 -0
  71. package/src/invariant.ts +40 -0
  72. package/src/persist.test.ts +96 -0
  73. package/src/persist.ts +128 -0
  74. package/src/routes.ts +171 -0
  75. package/src/service.ts +389 -0
  76. package/src/state.test.ts +65 -0
  77. package/src/state.ts +156 -0
  78. package/src/treats.test.ts +86 -0
  79. package/src/treats.ts +101 -0
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Staged form model behind the plugin settings card. A card stages what the
3
+ * user types and writes it only when they save — the settings write is a
4
+ * durable, revision-fenced document mutation, so staging keeps what is on
5
+ * screen exactly what a save would store. Mirrors the official
6
+ * ui-plugin-config card-store pattern in a self-contained slice: this
7
+ * package must not depend on a sibling UI package.
8
+ */
9
+ import type { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';
10
+ /** The write one field's staged text performs when the card is saved. */
11
+ export type FieldWrite = {
12
+ kind: 'set';
13
+ value: unknown;
14
+ } | {
15
+ kind: 'clear';
16
+ };
17
+ /** How one field converts between its stored value and its draft text. */
18
+ export interface FieldSpec {
19
+ /** Field name inside the namespace section. */
20
+ field: string;
21
+ /** Render a stored value as draft text; the empty string when the section carries none. */
22
+ format: (value: unknown) => string;
23
+ /**
24
+ * The write this draft text stages, or undefined when the text is not a
25
+ * value this field accepts — which blocks the save rather than discarding it.
26
+ */
27
+ parse: (text: string) => FieldWrite | undefined;
28
+ }
29
+ /** One field as the card renders it. */
30
+ export interface FieldState {
31
+ /** Draft text the control renders. */
32
+ text: string;
33
+ /** Whether saving would leave a user-layer entry for this field. */
34
+ overridden: boolean;
35
+ /** Whether the draft is not a value this field accepts, which blocks saving. */
36
+ invalid: boolean;
37
+ }
38
+ /** Form state every plugin settings card shares. */
39
+ export interface CardShell {
40
+ /** False while the namespace is not served to this client; the card renders nothing. */
41
+ available: boolean;
42
+ /** Whether the Host document accepts writes. */
43
+ writable: boolean;
44
+ /** Whether the form holds edits that a save would write. */
45
+ dirty: boolean;
46
+ /** Whether any staged draft is invalid, which blocks the save. */
47
+ invalid: boolean;
48
+ /** Whether a save is crossing the wire. */
49
+ saving: boolean;
50
+ /** Whether the last save did not land as staged; cleared by the next edit or save. */
51
+ failed: boolean;
52
+ }
53
+ /** The write actions the card's slot entry injects. */
54
+ export interface CardActions {
55
+ /** Stage draft text for one field. */
56
+ edit: (field: string, text: string) => void;
57
+ /** Stage a clear, so saving lets the field re-inherit the composition layer. */
58
+ resetField: (field: string) => void;
59
+ /** Write every staged edit, then re-seed from what the Host accepted. */
60
+ save: () => void;
61
+ /** Drop every staged edit. */
62
+ discard: () => void;
63
+ }
64
+ /** A whole-number field. An empty draft clears the field; any other draft that is not a finite number blocks the save. */
65
+ export declare function numberField(field: string): FieldSpec;
66
+ /** A free-text field. An empty draft clears the field. */
67
+ export declare function textField(field: string): FieldSpec;
68
+ /** A boolean field, edited through true/false draft text. */
69
+ export declare function booleanField(field: string): FieldSpec;
70
+ /**
71
+ * Stages one card's edits over one settings namespace and writes them on save.
72
+ *
73
+ * The Host is the only authority on whether a value was accepted — its
74
+ * validators own the constraints no schema can express — so the outcome is
75
+ * read back from the section rather than predicted here. A save that did not
76
+ * land keeps its drafts, so the user can correct them instead of retyping.
77
+ */
78
+ export declare class CardForm<T> {
79
+ private readonly scope;
80
+ private readonly specs;
81
+ private readonly staged;
82
+ private readonly listeners;
83
+ private saving;
84
+ private failed;
85
+ /** @param scope - the bound settings scope for this card's namespace. */
86
+ constructor(scope: SettingsScope<T>, specs: FieldSpec[]);
87
+ /** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */
88
+ bind<S>(project: () => S): SnapshotStore<S>;
89
+ /** Read the card-level state: what the Host serves, and what a save would do. */
90
+ shell(): CardShell;
91
+ /** Read one field's state from the effective section and its staged draft. */
92
+ field(field: string): FieldState;
93
+ /** The actions the card's slot registration injects. */
94
+ actions(): CardActions;
95
+ /**
96
+ * Write every staged edit, then re-seed from what the Host accepted.
97
+ * @returns settlement after every write and the read-back.
98
+ */
99
+ save(): Promise<void>;
100
+ /**
101
+ * Every staged edit a save would write. An entry whose draft is not a value
102
+ * its field accepts carries no write: the form is still dirty, and the save
103
+ * refuses rather than dropping the edit. A staged edit that matches the
104
+ * effective section is not a write at all.
105
+ * @returns the planned writes, in the order the fields were staged.
106
+ */
107
+ private plan;
108
+ private clear;
109
+ private store;
110
+ private stage;
111
+ private specOf;
112
+ private snapshotOf;
113
+ private sectionValue;
114
+ private baseValue;
115
+ private userLayer;
116
+ private stored;
117
+ private publish;
118
+ }
119
+ //# sourceMappingURL=settings-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-form.d.ts","sourceRoot":"","sources":["../../../src/client/settings-form.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
2
+ interface SlotMap {
3
+ /**
4
+ * The input selector context-chip hole: feature chips rendered right
5
+ * after the workspace selector. Session-maybe: entries stay mounted
6
+ * without a session and hide themselves when their data source is absent.
7
+ */
8
+ 'conversation.input.selector.context': {
9
+ kind: 'list';
10
+ scope: 'session-maybe';
11
+ owner: InputSelectorContextOwnerProps;
12
+ };
13
+ }
14
+ /** Owner share of the input selector context-chip hole (empty by contract). */
15
+ interface InputSelectorContextOwnerProps {
16
+ }
17
+ }
18
+ export {};
19
+ //# sourceMappingURL=slots-augment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slots-augment.d.ts","sourceRoot":"","sources":["../../../src/client/slots-augment.ts"],"names":[],"mappings":"AAUA,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,OAAO;QACf;;;;WAIG;QACH,qCAAqC,EAAE;YACrC,IAAI,EAAE,MAAM,CAAA;YACZ,KAAK,EAAE,eAAe,CAAA;YACtB,KAAK,EAAE,8BAA8B,CAAA;SACtC,CAAA;KACF;IAED,+EAA+E;IAC/E,UAAU,8BAA8B;KAAG;CAC5C"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Whale-girl spritesheet geometry and animation tracks.
3
+ *
4
+ * The atlas follows the Codex/hatch-pet contract: 8 columns × 9 rows of
5
+ * 192×208 cells (1536×1872 total), rows in this order:
6
+ * 0 idle, 1 running-right, 2 running-left, 3 waving, 4 jumping,
7
+ * 5 failed, 6 waiting, 7 running, 8 review
8
+ *
9
+ * Frame counts and per-frame durations are per-track definitions below; the
10
+ * whale-girl atlas is produced by the hatch-pet pipeline, so calibrate
11
+ * `TRACKS` against the actual run (`pet_request.json` frame counts) when the
12
+ * asset lands. Tracks that do not loop hand off to `fallback`.
13
+ * @module @linxin666/dsh-pet/client/spritesheet
14
+ */
15
+ import type { PetAnimation } from '../state.ts';
16
+ /** Atlas cell size in px (Codex contract). */
17
+ export declare const FRAME_WIDTH = 192;
18
+ export declare const FRAME_HEIGHT = 208;
19
+ /** Columns per row (max frames per track). */
20
+ export declare const FRAME_COLUMNS = 8;
21
+ /** One animation track: frame indices into the row + per-frame durations. */
22
+ export interface TrackDef {
23
+ /** Frame indices (columns) played in order; must be < FRAME_COLUMNS. */
24
+ frames: readonly number[];
25
+ /** Per-frame duration in ms; same length as frames. */
26
+ durations: readonly number[];
27
+ /** Whether the track loops; a non-looping track hands off to fallback. */
28
+ loop: boolean;
29
+ /** Track to play after a non-looping track finishes. */
30
+ fallback?: PetAnimation;
31
+ }
32
+ /**
33
+ * Track definitions for the whale-girl. Durations are tuned for a soft,
34
+ * slow-healing feel (roughly 2.5× the earlier fast draft — the pet should
35
+ * breathe, not race); calibrate frame counts against the hatch-pet run when
36
+ * the asset lands (rows may carry 4–8 frames).
37
+ */
38
+ export declare const TRACKS: Record<PetAnimation, TrackDef>;
39
+ /** Row index of one animation track (mirrors state.ts rowOf). */
40
+ export declare function rowOfTrack(animation: PetAnimation): number;
41
+ /**
42
+ * Background-position (px) of one frame cell within the scaled atlas.
43
+ * The background image is scaled by `scale` (element size ÷ cell size), and
44
+ * background-position offsets are applied in SCALED coordinates — using raw
45
+ * atlas coordinates here would drift each frame by the scale factor and
46
+ * render torn/overlapping frames.
47
+ */
48
+ export declare function framePosition(row: number, col: number, scale?: number): {
49
+ x: number;
50
+ y: number;
51
+ };
52
+ /** Total duration of one track, ms. */
53
+ export declare function trackDuration(track: TrackDef): number;
54
+ /**
55
+ * Detect how many frames each row actually carries by scanning the decoded
56
+ * atlas for non-transparent cells (hatch-pet rows may hold 4–8 frames; the
57
+ * unused trailing cells are fully transparent). Rows whose every sample is
58
+ * transparent report 0.
59
+ * @param image - the fully decoded spritesheet (natural size 1536×1872).
60
+ * @returns per-row frame counts, length 9.
61
+ */
62
+ export declare function detectFrameCounts(image: HTMLImageElement): number[];
63
+ /**
64
+ * Trim a track to the actual frame count of its row. A row with 0 detected
65
+ * frames degrades to the first frame (the atlas is still loading or corrupt)
66
+ * so the pet never renders blank.
67
+ */
68
+ export declare function trimTrack(track: TrackDef, frameCount: number): TrackDef;
69
+ //# sourceMappingURL=spritesheet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spritesheet.d.ts","sourceRoot":"","sources":["../../../src/client/spritesheet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C,8CAA8C;AAC9C,eAAO,MAAM,WAAW,MAAM,CAAA;AAC9B,eAAO,MAAM,YAAY,MAAM,CAAA;AAC/B,8CAA8C;AAC9C,eAAO,MAAM,aAAa,IAAI,CAAA;AAE9B,6EAA6E;AAC7E,MAAM,WAAW,QAAQ;IACvB,wEAAwE;IACxE,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IACzB,uDAAuD;IACvD,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B,0EAA0E;IAC1E,IAAI,EAAE,OAAO,CAAA;IACb,wDAAwD;IACxD,QAAQ,CAAC,EAAE,YAAY,CAAA;CACxB;AAED;;;;;GAKG;AACH,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,QAAQ,CAUjD,CAAA;AAED,iEAAiE;AACjE,wBAAgB,UAAU,CAAC,SAAS,EAAE,YAAY,GAAG,MAAM,CAa1D;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAE3F;AAED,uCAAuC;AACvC,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,EAAE,CA6BnE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,QAAQ,CAQvE"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * dsh-pet host half — mounts the pet service and its HTTP routes. The
3
+ * browser half (the `./client` entry) renders the whale-girl companion and
4
+ * drives it through the same-origin `/api/pet/*` JSON endpoints plus the
5
+ * `/pet/whale/*` media route. Install via `dsh plugin --profile web add
6
+ * link:<dsh-web-ui>/packages/dsh-pet`; the cordis.patch.yml inserts this plugin row.
7
+ * @module @linxin666/dsh-pet
8
+ */
9
+ import { Context } from '@deepseek-ai/cordis';
10
+ import { type PetConfig } from './service.ts';
11
+ export { PetService } from './service.ts';
12
+ export type { PetConfig, PetInteractResult, PetStateView, } from './service.ts';
13
+ export { AFFINITY_MAX, AFFINITY_RANKS, applyInteraction, applyTurnReward, emptyAffinity, rankOf, } from './affinity.ts';
14
+ export type { AffinityConfig, AffinityState, InteractionOutcome, PetInteraction, } from './affinity.ts';
15
+ export { animationForPhase, PetStateMachine, rowOf, } from './state.ts';
16
+ export type { ActivityPhase, PetAnimation, PetStateConfig, PetStateInput, PetStateSnapshot, } from './state.ts';
17
+ export { consumeTreat, defaultTreatConfig, emptyTreatLedger, settleTreatGrants, } from './treats.ts';
18
+ export type { TreatConfig, TreatLedger, TreatSettlement } from './treats.ts';
19
+ export { defaultDisplayConfig, emptyPersist, loadPetPersist, petHomeDir, savePetPersist, } from './persist.ts';
20
+ export type { PetDisplayConfig, PetPersist } from './persist.ts';
21
+ export { makePetRoutes, petPackageRoot, PET_API_PREFIX, PET_ASSET_PREFIX, } from './routes.ts';
22
+ /** Stable cordis plugin name (matches cordis.patch.yml insert id). */
23
+ export declare const name = "pet";
24
+ /** Services required before the pet can mount its surfaces. */
25
+ export declare const inject: string[];
26
+ /** Settings section schema: the display fields and name the web settings surface edits. */
27
+ export declare const PET_SETTINGS_SCHEMA: import("@deepseek-ai/schemastery").default<Schemastery.ObjectS<{
28
+ visible: import("@deepseek-ai/schemastery").default<boolean, boolean>;
29
+ size: import("@deepseek-ai/schemastery").default<number, number>;
30
+ right: import("@deepseek-ai/schemastery").default<number, number>;
31
+ bottom: import("@deepseek-ai/schemastery").default<number, number>;
32
+ name: import("@deepseek-ai/schemastery").default<string, string>;
33
+ enabled: import("@deepseek-ai/schemastery").default<boolean, boolean>;
34
+ }>, Schemastery.ObjectT<{
35
+ visible: import("@deepseek-ai/schemastery").default<boolean, boolean>;
36
+ size: import("@deepseek-ai/schemastery").default<number, number>;
37
+ right: import("@deepseek-ai/schemastery").default<number, number>;
38
+ bottom: import("@deepseek-ai/schemastery").default<number, number>;
39
+ name: import("@deepseek-ai/schemastery").default<string, string>;
40
+ enabled: import("@deepseek-ai/schemastery").default<boolean, boolean>;
41
+ }>>;
42
+ /** Register the pet service and its API + asset routes on the context. */
43
+ export declare function apply(ctx: Context, config?: PetConfig): void;
44
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAI7C,OAAO,EAAsC,KAAK,SAAS,EAA2B,MAAM,cAAc,CAAA;AAU1G,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,YAAY,GACb,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,MAAM,GACP,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,cAAc,GACf,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,KAAK,GACN,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,aAAa,EACb,gBAAgB,GACjB,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC5E,OAAO,EACL,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACd,UAAU,EACV,cAAc,GACf,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEhE,OAAO,EACL,aAAa,EACb,cAAc,EACd,cAAc,EACd,gBAAgB,GACjB,MAAM,aAAa,CAAA;AAEpB,sEAAsE;AACtE,eAAO,MAAM,IAAI,QAAQ,CAAA;AAEzB,+DAA+D;AAC/D,eAAO,MAAM,MAAM,UAAgB,CAAA;AAEnC,2FAA2F;AAC3F,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;GAO9B,CAAA;AAEF,0EAA0E;AAC1E,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,SAAc,GAAG,IAAI,CAoDhE"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Package invariants — cheap structural checks run at import time on the
3
+ * host side. Mirrors the pattern used by other dsh plugin packages.
4
+ * @module @linxin666/dsh-pet/invariant
5
+ */
6
+ /** Assert a condition; throws a descriptive Error when violated. */
7
+ export declare function invariant(condition: unknown, message: string): asserts condition;
8
+ /** Run every package invariant once; throws on the first violation. */
9
+ export declare function runPetInvariants(): void;
10
+ //# sourceMappingURL=invariant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariant.d.ts","sourceRoot":"","sources":["../../src/invariant.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,oEAAoE;AACpE,wBAAgB,SAAS,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAIhF;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,IAAI,IAAI,CAkBvC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Pet persistence — tiny JSON store for affinity + display config, written
3
+ * under $DSH_HOME (defaults to ~/.dsh) as `pet.json`. Deliberately minimal:
4
+ * one file, atomic rename write, tolerant read (corrupt file → defaults).
5
+ * @module @linxin666/dsh-pet/persist
6
+ */
7
+ import { type AffinityState } from './affinity.ts';
8
+ import { type TreatLedger } from './treats.ts';
9
+ /** Display configuration the user can tweak. */
10
+ export interface PetDisplayConfig {
11
+ /** Master switch. */
12
+ visible: boolean;
13
+ /** Scale of the rendered pet in px (sprite cell height). */
14
+ size: number;
15
+ /** Horizontal inset from the viewport right edge, px. */
16
+ right: number;
17
+ /** Vertical inset from the viewport bottom edge, px. */
18
+ bottom: number;
19
+ }
20
+ export declare const defaultDisplayConfig: PetDisplayConfig;
21
+ /** Display value bounds (shared by load-time validation and setConfig). */
22
+ export declare const DISPLAY_SIZE_MIN = 32;
23
+ export declare const DISPLAY_SIZE_MAX = 512;
24
+ export declare const DISPLAY_INSET_MAX = 10000;
25
+ /** Everything persisted for the pet. */
26
+ export interface PetPersist {
27
+ /** User-customizable pet display name. */
28
+ name: string;
29
+ affinity: AffinityState;
30
+ /** Treat (小鱼干) stock ledger. */
31
+ treats: TreatLedger;
32
+ display: PetDisplayConfig;
33
+ }
34
+ /** Default pet name (used until the user renames the pet). */
35
+ export declare const DEFAULT_PET_NAME = "\u9CB8\u9C7C\u5A18";
36
+ /** Name constraints. */
37
+ export declare const PET_NAME_MAX_LENGTH = 20;
38
+ export declare function emptyPersist(): PetPersist;
39
+ /** Resolve the persistence directory ($DSH_HOME or ~/.dsh). */
40
+ export declare function petHomeDir(): string;
41
+ /** Load persisted state; missing or corrupt files fall back to defaults. */
42
+ export declare function loadPetPersist(dir?: string): PetPersist;
43
+ /** Atomically persist state (write temp + rename). */
44
+ export declare function savePetPersist(data: PetPersist, dir?: string): void;
45
+ //# sourceMappingURL=persist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../src/persist.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAA+B,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAC/E,OAAO,EAAwC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAA;AAEpF,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B,qBAAqB;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAA;CACf;AAED,eAAO,MAAM,oBAAoB,EAAE,gBAKlC,CAAA;AAED,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAClC,eAAO,MAAM,gBAAgB,MAAM,CAAA;AACnC,eAAO,MAAM,iBAAiB,QAAS,CAAA;AAEvC,wCAAwC;AACxC,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,aAAa,CAAA;IACvB,gCAAgC;IAChC,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,EAAE,gBAAgB,CAAA;CAC1B;AAED,8DAA8D;AAC9D,eAAO,MAAM,gBAAgB,uBAAQ,CAAA;AAErC,wBAAwB;AACxB,eAAO,MAAM,mBAAmB,KAAK,CAAA;AAErC,wBAAgB,YAAY,IAAI,UAAU,CAOzC;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAYD,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAqB,GAAG,UAAU,CAwCrE;AAED,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,GAAE,MAAqB,GAAG,IAAI,CAMjF"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Pet HTTP routes — the browser half talks to the host through plain
3
+ * same-origin JSON endpoints (`/api/pet/*`) and loads the whale-girl atlas
4
+ * from `/pet/whale/*`. The `/plugins/` endpoint only serves client bundles
5
+ * and RPC domains are platform-registered, so the pet serves its own API
6
+ * and media — the same pattern as dsh-remote-web-ui's `/api/pair` family.
7
+ * @module @linxin666/dsh-pet/routes
8
+ */
9
+ import type { WebRoute } from '@deepseek-ai/dsh-host-webserver';
10
+ import type { PetService } from './service.ts';
11
+ /** Browser-facing base path of the pet API. */
12
+ export declare const PET_API_PREFIX = "/api/pet";
13
+ /** Browser-facing base path of the pet asset routes. */
14
+ export declare const PET_ASSET_PREFIX = "/pet/whale";
15
+ /** Absolute package root, resolved from this module's own location (lib/). */
16
+ export declare function petPackageRoot(importMetaUrl: string): string;
17
+ /** Build the full route family (API + assets) for one service + package root. */
18
+ export declare function makePetRoutes(deps: {
19
+ service: PetService;
20
+ packageRoot: string;
21
+ }): WebRoute[];
22
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAG9C,+CAA+C;AAC/C,eAAO,MAAM,cAAc,aAAa,CAAA;AAExC,wDAAwD;AACxD,eAAO,MAAM,gBAAgB,eAAe,CAAA;AAQ5C,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE5D;AAkFD,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,QAAQ,EAAE,CAuD5F"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Pet host service — the `pet.*` RPC domain. Owns the state machine wiring
3
+ * (consumes `activity/status` session events and session lifecycle), the
4
+ * affinity ledger, and the persisted display config. The API gateway maps
5
+ * this service's methods onto `pet.state` / `pet.interact` /
6
+ * `pet.setVisible` / `pet.setConfig` for browser consumers.
7
+ * @module @linxin666/dsh-pet/service
8
+ */
9
+ import { Context, Service } from '@deepseek-ai/cordis';
10
+ import { type AffinityConfig, type PetInteraction } from './affinity.ts';
11
+ import { type PetDisplayConfig } from './persist.ts';
12
+ import { type TreatConfig } from './treats.ts';
13
+ import { type PetStateConfig, type PetStateSnapshot } from './state.ts';
14
+ /** Plugin configuration. */
15
+ export interface PetConfig {
16
+ /** Affinity tuning. */
17
+ affinity?: Partial<AffinityConfig>;
18
+ /** State machine tuning. */
19
+ state?: Partial<PetStateConfig>;
20
+ /** Treat economy tuning. */
21
+ treats?: Partial<TreatConfig>;
22
+ /** Persistence directory override (defaults to $DSH_HOME). */
23
+ persistDir?: string;
24
+ /** Master switch for the plugin (browser half + host routes). */
25
+ enabled?: boolean;
26
+ }
27
+ /**
28
+ * The pet's settings-namespace section: the display fields and name the web
29
+ * settings surface edits. `right`/`bottom` are also updated by drag
30
+ * interactions, which keep the settings document in sync through the service.
31
+ */
32
+ export interface PetSettingsSection {
33
+ /** Master switch. */
34
+ visible: boolean;
35
+ /** Scale of the rendered pet in px (sprite cell height). */
36
+ size: number;
37
+ /** Horizontal inset from the viewport right edge, px. */
38
+ right: number;
39
+ /** Vertical inset from the viewport bottom edge, px. */
40
+ bottom: number;
41
+ /** User-customizable pet display name. */
42
+ name: string;
43
+ /** Master switch for the plugin (browser half + host routes). */
44
+ enabled?: boolean;
45
+ }
46
+ /** Settings namespace of the pet capability. Spelled here rather than imported: the browser half spells the same value. */
47
+ export declare const PET_SETTINGS_NAMESPACE = "pet";
48
+ /** Snapshot returned by `pet.state`. */
49
+ export interface PetStateView {
50
+ animation: PetStateSnapshot['animation'];
51
+ bubble?: string;
52
+ phase: PetStateSnapshot['phase'];
53
+ sessionActive: boolean;
54
+ /** Affinity ledger snapshot. */
55
+ affinity: {
56
+ points: number;
57
+ rank: string;
58
+ rankEmoji: string;
59
+ pets: number;
60
+ feeds: number;
61
+ turns: number;
62
+ /** True while the pet interaction is inside its cooldown. */
63
+ petCooldown: boolean;
64
+ /** True while the feed is inside its cooldown. */
65
+ feedCooldown: boolean;
66
+ };
67
+ /** Display configuration. */
68
+ display: PetDisplayConfig;
69
+ /** User-customizable pet display name. */
70
+ name: string;
71
+ /** Treat (小鱼干) stock snapshot. */
72
+ treats: {
73
+ /** Stocked treats now. */
74
+ stocked: number;
75
+ /** Stock cap. */
76
+ max: number;
77
+ };
78
+ }
79
+ /** Result of `pet.interact`. */
80
+ export interface PetInteractResult {
81
+ /** Reaction copy bubble. */
82
+ reaction: string;
83
+ /** Points gained (0 when inside the cooldown). */
84
+ delta: number;
85
+ /** Full affinity snapshot (same shape as state view). */
86
+ affinity: PetStateView['affinity'];
87
+ }
88
+ declare module '@deepseek-ai/cordis' {
89
+ interface Context {
90
+ pet: PetService;
91
+ }
92
+ }
93
+ /**
94
+ * Cordis service exposing the pet RPC domain. Lazy: nothing is scanned or
95
+ * written until a query or interaction arrives; event listeners update only
96
+ * in-memory state, and persistence happens on interaction/config changes
97
+ * plus every completed turn.
98
+ */
99
+ export declare class PetService extends Service {
100
+ static inject: string[];
101
+ private readonly machine;
102
+ private readonly affinityConfig;
103
+ private readonly treatConfig;
104
+ private readonly persistDir;
105
+ private persist;
106
+ private lastTurnRewardAt;
107
+ private enabled;
108
+ private disposeActivity;
109
+ constructor(ctx: Context, config?: PetConfig);
110
+ /** Whether the pet service consumes session activity while enabled. */
111
+ isEnabled(): boolean;
112
+ /** RPC: current pet state snapshot. */
113
+ state(): Promise<PetStateView>;
114
+ /** Current persisted display config (read-only view). */
115
+ display(): PetDisplayConfig;
116
+ /** Current persisted pet name (read-only view). */
117
+ petName(): string;
118
+ /** Start or stop the session-activity listeners that drive the pet. */
119
+ setEnabled(enabled: boolean): void;
120
+ private syncActivity;
121
+ /** RPC: pet or feed the pet. */
122
+ interact(kind: PetInteraction): Promise<PetInteractResult>;
123
+ /** RPC: show or hide the pet. */
124
+ setVisible(visible: boolean): Promise<{
125
+ ok: true;
126
+ display: PetDisplayConfig;
127
+ }>;
128
+ /** RPC: update display config (size / position). Values are clamped to whole pixels. */
129
+ setConfig(patch: Partial<PetDisplayConfig>): Promise<{
130
+ ok: true;
131
+ display: PetDisplayConfig;
132
+ }>;
133
+ /** RPC: rename the pet (trimmed, 1–20 chars). */
134
+ setName(name: string): Promise<{
135
+ ok: true;
136
+ name: string;
137
+ } | {
138
+ ok: false;
139
+ error: string;
140
+ }>;
141
+ /**
142
+ * Apply a committed settings section to the persisted display config. Called
143
+ * by the settings surface on every change; values are clamped exactly like
144
+ * the setConfig RPC so both write paths converge.
145
+ * @param section - the resolved settings section.
146
+ */
147
+ applySettingsSection(section: PetSettingsSection): void;
148
+ /** Mirror the persisted display config into the settings document (best-effort). */
149
+ private syncSettingsFromPet;
150
+ /** Award the turn reward once per done phase (idempotent per transition). */
151
+ private rewardTurn;
152
+ /**
153
+ * Settle the treat economy (work + time output since the last
154
+ * settlement); persists only when treats were actually granted.
155
+ */
156
+ private settleTreats;
157
+ private view;
158
+ private affinityView;
159
+ private flush;
160
+ }
161
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Pet state machine — pure, clock-injected. Maps the DSH `activity/status`
3
+ * phase vocabulary (session events) onto the 9-state Codex pet
4
+ * animation contract, plus the session lifecycle transitions the web UI
5
+ * exposes (turn end celebration, no-session idle).
6
+ *
7
+ * The machine is deliberately dumb: it holds the last input phase, the
8
+ * animation decision, and a one-shot "celebration" window after `done` so the
9
+ * pet visibly jumps before settling back to idle. Everything here is a pure
10
+ * function of (input, nowMs); persistence and RPC live in the service.
11
+ * @module @linxin666/dsh-pet/state
12
+ */
13
+ /** The DSH `activity/status` phase vocabulary (wire contract of session events). */
14
+ export type ActivityPhase = 'idle' | 'waiting' | 'thinking' | 'tool' | 'done';
15
+ /** The Codex-compatible 9-state animation contract (spritesheet rows). */
16
+ export type PetAnimation = 'idle' | 'running-right' | 'running-left' | 'waving' | 'jumping' | 'failed' | 'waiting' | 'running' | 'review';
17
+ /** One input snapshot consumed by the machine. */
18
+ export interface PetStateInput {
19
+ /** Current activity/status phase of the active session. */
20
+ phase: ActivityPhase;
21
+ /** Human-readable status line (plain text). */
22
+ line?: string;
23
+ /** Playful phrase from the activity tracker, when any. */
24
+ phrase?: string;
25
+ }
26
+ /** Animation decision plus the copy the pet should show. */
27
+ export interface PetStateSnapshot {
28
+ /** Which animation track to play. */
29
+ animation: PetAnimation;
30
+ /** Optional status bubble copy (line or phrase), shown while active. */
31
+ bubble?: string;
32
+ /** Wall-clock ms this animation started (client can sync loops). */
33
+ animationStartedAt: number;
34
+ /** Raw phase, for debugging and client-side rendering decisions. */
35
+ phase: ActivityPhase;
36
+ /** True when there is an active session (pet mounted). */
37
+ sessionActive: boolean;
38
+ }
39
+ /** Machine configuration. */
40
+ export interface PetStateConfig {
41
+ /** Celebration window after `done` before settling to idle, ms (default 2400). */
42
+ celebrateMs: number;
43
+ }
44
+ export declare const defaultPetStateConfig: PetStateConfig;
45
+ /**
46
+ * Map one activity phase onto the animation contract.
47
+ * - thinking / tool → `running` (focused work), with `running-right` as the
48
+ * side-alternating variant the client may use for tool activity.
49
+ * - waiting → `waiting` (expectant pose, needs user input).
50
+ * - done → `jumping` (celebration), then back to `idle` after the window.
51
+ * - idle → `idle` (calm breathing loop).
52
+ * `failed` has no DSH phase source yet; the machine keeps the mapping table
53
+ * so a future error event can light it up.
54
+ */
55
+ export declare function animationForPhase(phase: ActivityPhase): PetAnimation;
56
+ /** The spritesheet row index for one animation track. */
57
+ export declare function rowOf(animation: PetAnimation): number;
58
+ /**
59
+ * PetStateMachine — one instance per host process. Holds only the latest
60
+ * input snapshot and the celebration timing; no storage, no side effects.
61
+ */
62
+ export declare class PetStateMachine {
63
+ private readonly config;
64
+ private readonly now;
65
+ private phase;
66
+ private line;
67
+ private phrase;
68
+ private sessionActive;
69
+ private doneAt;
70
+ constructor(config?: PetStateConfig, now?: () => number);
71
+ /** Consume one `activity/status` session event. */
72
+ onActivityStatus(input: PetStateInput): void;
73
+ /** A session became the active one (or a fresh session started). */
74
+ onSessionActive(): void;
75
+ /** The active session was disposed (or none left). */
76
+ onSessionDisposed(): void;
77
+ /** Render the current animation decision. */
78
+ render(): PetStateSnapshot;
79
+ }
80
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,oFAAoF;AACpF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAA;AAE7E,0EAA0E;AAC1E,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,eAAe,GACf,cAAc,GACd,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,SAAS,GACT,SAAS,GACT,QAAQ,CAAA;AAEZ,kDAAkD;AAClD,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,KAAK,EAAE,aAAa,CAAA;IACpB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,4DAA4D;AAC5D,MAAM,WAAW,gBAAgB;IAC/B,qCAAqC;IACrC,SAAS,EAAE,YAAY,CAAA;IACvB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oEAAoE;IACpE,kBAAkB,EAAE,MAAM,CAAA;IAC1B,oEAAoE;IACpE,KAAK,EAAE,aAAa,CAAA;IACpB,0DAA0D;IAC1D,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,6BAA6B;AAC7B,MAAM,WAAW,cAAc;IAC7B,kFAAkF;IAClF,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,eAAO,MAAM,qBAAqB,EAAE,cAAsC,CAAA;AAE1E;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,CAQpE;AAED,yDAAyD;AACzD,wBAAgB,KAAK,CAAC,SAAS,EAAE,YAAY,GAAG,MAAM,CAarD;AAED;;;GAGG;AACH,qBAAa,eAAe;IAQxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IARtB,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,IAAI,CAAoB;IAChC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,MAAM,CAAoB;gBAGf,MAAM,GAAE,cAAsC,EAC9C,GAAG,GAAE,MAAM,MAAiB;IAG/C,mDAAmD;IACnD,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAO5C,oEAAoE;IACpE,eAAe,IAAI,IAAI;IAIvB,sDAAsD;IACtD,iBAAiB,IAAI,IAAI;IAQzB,6CAA6C;IAC7C,MAAM,IAAI,gBAAgB;CAoB3B"}