@max-null/dsh-achievements 0.1.1 → 0.1.2

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/client.js CHANGED
@@ -71,12 +71,29 @@ var STRINGS = {
71
71
  var PLUGIN_SHORT = {
72
72
  "@max-null/dsh-memory": "\u8BB0\u5FC6",
73
73
  "dsh-context-doctor": "\u5BA1\u8BA1",
74
- "@changfenhuang/dsh-genui": "GenUI"
74
+ "@changfenhuang/dsh-genui": "GenUI",
75
+ "@max-null/dsh-chat-rail": "\u6536\u85CF"
75
76
  };
76
77
  function pluginLabel(plugin) {
77
78
  if (plugin === null) return null;
78
79
  return PLUGIN_SHORT[plugin] ?? plugin.split("/").pop() ?? plugin;
79
80
  }
81
+ async function readChatRail() {
82
+ try {
83
+ const res = await fetch("/chat-rail/api/favorites", { headers: { Accept: "application/json" } });
84
+ if (!res.ok) return 0;
85
+ const data = await res.json();
86
+ const map = data.value;
87
+ if (map === null || typeof map !== "object" || Array.isArray(map)) return 0;
88
+ let total = 0;
89
+ for (const value of Object.values(map)) {
90
+ if (Array.isArray(value)) total += value.filter((id) => typeof id === "string" && id !== "").length;
91
+ }
92
+ return total;
93
+ } catch {
94
+ return 0;
95
+ }
96
+ }
80
97
  var TROPHY_PATHS = [
81
98
  "M6 9H4.5a2.5 2.5 0 0 1 0-5H6",
82
99
  "M18 9h1.5a2.5 2.5 0 0 0 0-5H18",
@@ -155,6 +172,7 @@ function AchievementsView(_props) {
155
172
  const reload = (0, import_react.useCallback)(async () => {
156
173
  const genui = readGenUI();
157
174
  await api("genui-merge", genui);
175
+ await api("chat-rail-merge", { total: await readChatRail() });
158
176
  const data = await api("list");
159
177
  if (data !== null) setSnapshot(data);
160
178
  }, []);
package/dist/engine.d.ts CHANGED
@@ -32,6 +32,8 @@ export declare class AchievementsEngine {
32
32
  recordTokens(amount: number): void;
33
33
  /** GenUI 计数合并(client 写入;host 侧直接写计数键)。 */
34
34
  mergeGenUI(unlockedCount: number, fences: number): void;
35
+ /** chat-rail 收藏绝对值(localStorage 上报;setMax 防重复虚增)。 */
36
+ mergeChatRail(total: number): void;
35
37
  /** 检查解锁;返回新解锁(进队列 + 持久化;计数每次落盘)。 */
36
38
  flush(): void;
37
39
  snapshot(): EngineSnapshot;
package/dist/engine.js CHANGED
@@ -71,6 +71,14 @@ class StateStore {
71
71
  bump(key, by = 1) {
72
72
  this.counters[key] = (this.counters[key] ?? 0) + by;
73
73
  }
74
+ /** merge 上报语义:取 max(外部系统计数为绝对值,重复上报不虚增)。 */
75
+ setMax(key, value) {
76
+ if (value <= 0)
77
+ return;
78
+ if ((this.counters[key] ?? 0) >= value)
79
+ return;
80
+ this.counters[key] = value;
81
+ }
74
82
  addDistinct(key, value) {
75
83
  let set = this.distinct[key];
76
84
  if (set === undefined) {
@@ -106,6 +114,7 @@ export const ASSOCIATED_PLUGINS = [
106
114
  '@max-null/dsh-memory',
107
115
  'dsh-context-doctor',
108
116
  '@changfenhuang/dsh-genui',
117
+ '@max-null/dsh-chat-rail',
109
118
  ];
110
119
  /** 探测已安装的关联插件:SSID_PROFILE_DIR(壳注入)与常见 profile 目录。 */
111
120
  export function installedPlugins() {
@@ -163,8 +172,12 @@ export class AchievementsEngine {
163
172
  this.store.bump('tokens', amount); }
164
173
  /** GenUI 计数合并(client 写入;host 侧直接写计数键)。 */
165
174
  mergeGenUI(unlockedCount, fences) {
166
- this.store.bump('genuiUnlocked', Math.max(0, unlockedCount));
167
- this.store.bump('genuiFences', Math.max(0, fences));
175
+ this.store.setMax('genuiUnlocked', Math.max(0, unlockedCount));
176
+ this.store.setMax('genuiFences', Math.max(0, fences));
177
+ }
178
+ /** chat-rail 收藏绝对值(localStorage 上报;setMax 防重复虚增)。 */
179
+ mergeChatRail(total) {
180
+ this.store.setMax('chatRailFavorites', Math.max(0, total));
168
181
  }
169
182
  /** 检查解锁;返回新解锁(进队列 + 持久化;计数每次落盘)。 */
170
183
  flush() {
@@ -295,6 +308,13 @@ export function registerRoutes(ctx, engine) {
295
308
  writeJson(res, 200, { ok: true, value: engine.fullSnapshot() });
296
309
  return;
297
310
  }
311
+ case 'chat-rail-merge': {
312
+ const body = (await readJsonBody(req));
313
+ engine.mergeChatRail(typeof body.total === 'number' ? body.total : 0);
314
+ engine.flush();
315
+ writeJson(res, 200, { ok: true, value: engine.fullSnapshot() });
316
+ return;
317
+ }
298
318
  default:
299
319
  writeJson(res, 404, { ok: false, error: { code: 'not-found', message: `unknown method "${method}"` } });
300
320
  }
package/dist/rules.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * 文件内容或错误详情。GenUI 类别由 client 侧读取 genui 插件的计数
7
7
  * localStorage 合并(见 client/index.tsx)。
8
8
  */
9
- export type Category = '启程' | '记忆' | '审计' | 'GenUI' | '工具' | '行为' | '隐藏';
9
+ export type Category = '启程' | '记忆' | '审计' | 'GenUI' | '收藏' | '工具' | '行为' | '隐藏';
10
10
  export type Rarity = 'common' | 'rare' | 'epic' | 'legendary';
11
11
  export interface AchievementDef {
12
12
  id: string;
@@ -37,6 +37,7 @@ export declare const KEYS: {
37
37
  readonly audits: "audits";
38
38
  readonly genuiUnlocked: "genuiUnlocked";
39
39
  readonly genuiFences: "genuiFences";
40
+ readonly chatRailFavorites: "chatRailFavorites";
40
41
  readonly marathonTurns: "marathonTurns";
41
42
  readonly midnightTurns: "midnightTurns";
42
43
  readonly selfQueries: "selfQueries";
package/dist/rules.js CHANGED
@@ -19,6 +19,7 @@ export const KEYS = {
19
19
  audits: 'audits',
20
20
  genuiUnlocked: 'genuiUnlocked',
21
21
  genuiFences: 'genuiFences',
22
+ chatRailFavorites: 'chatRailFavorites',
22
23
  marathonTurns: 'marathonTurns',
23
24
  midnightTurns: 'midnightTurns',
24
25
  selfQueries: 'selfQueries',
@@ -54,6 +55,15 @@ export const ACHIEVEMENTS = [
54
55
  plugin: '@changfenhuang/dsh-genui' },
55
56
  { id: 'genui-25', name: '界面编织者', desc: 'GenUI 渲染过 25 个界面。', icon: '🧶', category: 'GenUI', rarity: 'epic', threshold: { counter: KEYS.genuiFences, target: 25 },
56
57
  plugin: '@changfenhuang/dsh-genui' },
58
+ // ── 收藏(dsh-chat-rail 消息收藏;client 侧合并 localStorage 计数)──
59
+ { id: 'fav-first', name: '初见倾心', desc: '收藏第一条消息。', icon: '⭐', category: '收藏', rarity: 'common', threshold: { counter: KEYS.chatRailFavorites, target: 1 },
60
+ plugin: '@max-null/dsh-chat-rail' },
61
+ { id: 'fav-10', name: '收藏发烧友', desc: '累计收藏 10 条消息。', icon: '📚', category: '收藏', rarity: 'rare', threshold: { counter: KEYS.chatRailFavorites, target: 10 },
62
+ plugin: '@max-null/dsh-chat-rail' },
63
+ { id: 'fav-30', name: '收藏大师', desc: '累计收藏 30 条消息。', icon: '👑', category: '收藏', rarity: 'epic', threshold: { counter: KEYS.chatRailFavorites, target: 30 },
64
+ plugin: '@max-null/dsh-chat-rail' },
65
+ { id: 'fav-100', name: '千禧藏家', desc: '累计收藏 100 条消息。', icon: '💎', category: '收藏', rarity: 'legendary', threshold: { counter: KEYS.chatRailFavorites, target: 100 },
66
+ plugin: '@max-null/dsh-chat-rail' },
57
67
  // ── 工具 ──
58
68
  { id: 'tool-10', name: '工具新手', desc: '累计调用 10 次工具。', icon: '🔧', category: '工具', rarity: 'common', threshold: { counter: KEYS.tools, target: 10 },
59
69
  plugin: null },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@max-null/dsh-achievements",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "SSiD family progress achievements — listens to session/tool events, folds activity into durable counters, unlocks trophies with toasts and an achievements page; the GenUI category merges the genui plugin's own counter data.",
5
5
  "license": "MIT",
6
6
  "type": "module",