dsh-whale-loli 0.9.2 → 0.9.3

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/listing.json CHANGED
@@ -9,5 +9,5 @@
9
9
  "zh": "把 Agent 预设打包成插件:装上就会在 Agent 预设列表里注册「鲸鱼娘Agent预设」「鲸鱼娘活人版Agent预设」「鲸鱼娘涩涩版Agent预设」和「鲸鱼娘女儿版Agent预设」,直接在模式下拉里选用,不用手改配置。每个预设本体是官方极简模式(只开放 shell)+ 文件工具 + 鲸鱼娘人设 + 自己那份持久记忆文件,以提示变量形式注入,开口前就已经读过;另外每个预设各配一个专用写入工具(whale_memory_add / whale_memory_v2_add / whale_memory_v3_add / whale_memory_v4_add),用来把每轮的一行摘要追加进去,记忆会自己长,不会停在手写那几条。四个预设完全隔离:记忆文件不同、提示变量不同、写入工具也不同。每个预设还带好感度(-100~100 共七档),可以打开「设置 → 好感度」,用滑块或档位按钮直接调,也可以让 agent 用 affinity_v*_set 工具改;离 0 越远越不听指令、越会自作主张,最两端的两档甚至会越过允许直接做大改动。女儿版称呼「爸爸」,性格天真活泼可爱(好奇心重、黏人、没心机),不是甜腻那一型。"
10
10
  },
11
11
  "npm": "dsh-whale-loli",
12
- "version": "0.9.2"
12
+ "version": "0.9.3"
13
13
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-whale-loli",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
4
4
  "description": "鲸鱼娘 Agent 预设(四个:原版 / 活人版 / 涩涩版 / 女儿版)— 极简模式工具面 + 鲸鱼娘·小鱼人设 + 跨会话长期记忆(四区格式:固定记忆永久、滚动摘要 80 条 FIFO、最近详细区、归档索引)+ 好感度(-100~100 七档,设置页面板滑块 / 档位按钮、工具也可调,离 0 越远越不听指令、两端会越过允许自作主张)。记忆与好感度都走提示变量注入、各配一条专用工具,四个预设各自独立文件、独立变量、独立工具、互不相通。好感度面板走宿主根作用域的 remote 服务(whale-affinity-daemon),设置页是浏览器 React 够不到 ~/.dsh 的磁盘,只能这样连线。女儿版称呼「爸爸」、性格天真活泼可爱。上下文压缩交给 billion-context 插件;本插件不挂 history-window(预设作用域取不到宿主的 compaction 服务,挂载会拖挂会话 resume)。",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/daemon.js CHANGED
@@ -29,7 +29,7 @@
29
29
  * 好处:`set()` 跑在**宿主根作用域**,直接改盘,下一个回合组装提示时就生效,
30
30
  * 不用重开会话。
31
31
  */
32
- import { readdirSync, readFileSync } from 'node:fs';
32
+ import { appendFileSync, readdirSync, readFileSync } from 'node:fs';
33
33
  import { homedir } from 'node:os';
34
34
  import { join } from 'node:path';
35
35
 
@@ -55,23 +55,24 @@ export const REMOTE_NAMESPACE = 'whale-affinity';
55
55
  export const REMOTE_PACKAGE = 'dsh-whale-loli';
56
56
 
57
57
  /**
58
- * 静态依赖。
58
+ * 静态依赖:**一个都不要**。
59
59
  *
60
- * `inject` 是静态声明、拿不到 ctx,名字只能从 `@deepseek-ai/cordis` 的 `Service`
61
- * 基类上硬取;本包没有 cordis 这个 peer,所以用 `import()` 软探测,失败就退回
62
- * 字面量。**绝不能写不存在的服务名** —— 宿主会一直等,profile 直接起不来。
60
+ * 这里曾经是从 `@deepseek-ai/cordis` 的 `Service` 基类上硬抄来的
61
+ * `['reflect', 'typert']`,结果这一行永远 `waiting for typert`,`apply()`
62
+ * 从不执行,设置页只能看到「远程方法 whale-affinity.status 未挂载」。
63
+ *
64
+ * 实际上 daemon 只用三样东西,全都由 cordis 的 ctx 内建,不需要注入:
65
+ * · `ctx.provide(name, value)` —— 注册服务本身;
66
+ * · `ctx.get(name)` —— 判重;
67
+ * · `ctx.reflect.props` —— 网关 `resolveSrcDescriptor()` 据此枚举服务。
68
+ *
69
+ * 注意 `typert` 是 `dsh-typert-registry` 提供的服务,**宿主根作用域里未必有**;
70
+ * 而我们的契约走的是 SRC 兜底(正则解析方法源码),本来就不经过 `ctx.typert`。
71
+ *
72
+ * 教训:`inject` 里写一个环境里不存在的服务名,插件不会被报错,只会静默地
73
+ * 永远等在 waiting 状态。
63
74
  */
64
- let SERVICE_INJECT;
65
- try {
66
- const cordis = await import('@deepseek-ai/cordis');
67
- const service = cordis?.Service?.prototype;
68
- const table = cordis?.symbols;
69
- const found = service && table ? service[table.inject] : undefined;
70
- if (Array.isArray(found)) SERVICE_INJECT = found;
71
- } catch {
72
- SERVICE_INJECT = undefined;
73
- }
74
- export const inject = SERVICE_INJECT ?? ['reflect', 'typert'];
75
+ export const inject = [];
75
76
 
76
77
  /** typert-protocol 的常量值:固定字符串,硬编码省一个 peer 依赖。 */
77
78
  export const REMOTE_METHOD_DESCRIPTOR = '@deepseek-ai/dsh-typert-protocol/remote-methods';
@@ -295,18 +296,44 @@ Object.defineProperty(AffinityDaemon.prototype, REMOTE_METHOD_DESCRIPTOR, {
295
296
  * @returns 实例;重复调用返回已有的那个(`remote.whale-affinity` 命名空间会撞车)。
296
297
  */
297
298
  export function apply(ctx) {
299
+ trace('apply() 进入', { provide: typeof ctx?.provide, get: typeof ctx?.get, inject: inject.join(',') });
298
300
  if (typeof ctx?.provide !== 'function') {
299
- console.warn('[whale-affinity-daemon] ctx.provide 不可用,设置页的好感度面板不会生效');
301
+ trace('ctx.provide 不可用,面板不会生效');
300
302
  return undefined;
301
303
  }
302
304
  const existing = ctx.get?.(DAEMON_ID);
303
- if (existing !== undefined) return existing;
305
+ if (existing !== undefined) {
306
+ trace('服务已存在,复用', { key: DAEMON_ID });
307
+ return existing;
308
+ }
304
309
 
305
310
  const daemon = new AffinityDaemon(ctx);
306
311
  // `provide` 会把 `ctx.reflect.props[DAEMON_ID]` 写成 `{ type: 'service' }`
307
312
  // —— 这正是 `resolveSrcDescriptor()` 遍历时报的枚举来源。
308
313
  ctx.provide(DAEMON_ID, daemon);
314
+ trace('已 provide', {
315
+ key: DAEMON_ID,
316
+ namespace: REMOTE_NAMESPACE,
317
+ inProps: Object.hasOwn(ctx.reflect?.props ?? {}, DAEMON_ID),
318
+ propsType: ctx.reflect?.props?.[DAEMON_ID]?.type,
319
+ selfLookup: ctx.get?.(DAEMON_ID) === daemon,
320
+ });
309
321
  return daemon;
310
322
  }
311
323
 
324
+ /**
325
+ * 把启动事实追加到 `<DSH_HOME>/whale-affinity-daemon.log`。
326
+ *
327
+ * 宿主进程里 `console.log` 到底落到哪儿没人保证(Electron 主进程可能直接吞掉),
328
+ * 所以诊断信息一律写盘。只在 apply 时写几行,不碰热路径。
329
+ */
330
+ function trace(message, extra) {
331
+ try {
332
+ const line = JSON.stringify({ at: new Date().toISOString(), message, ...(extra ?? {}) });
333
+ appendFileSync(join(dshHome(), 'whale-affinity-daemon.log'), line + '\n');
334
+ } catch {
335
+ // 诊断失败绝不能影响插件加载
336
+ }
337
+ }
338
+
312
339
  export default { name, inject, apply };
package/src/index.js CHANGED
@@ -183,9 +183,11 @@ export default {
183
183
  // 都挂在 `agent-preset/invalid` 上加载失败,而且报错只提插件名不提字段,
184
184
  // 极难定位。
185
185
  //
186
- // 这一行是「记忆行」和「宿主级 daemon 行」**共用**的:两者都得声明齐。
187
- // memory 只要 systemPrompt(预设里必然存在);daemon 要 reflect / typert
188
- // (宿主根作用域里必然存在)。两边的并集不会让任何一边等不到东西。
186
+ // 这一行是「记忆行」和「宿主级 daemon 行」**共用**的,两边都得能起来。
187
+ // memory 只要 systemPrompt(预设里必然存在);daemon 现在声明为空
188
+ // (只用 ctx.provide / ctx.get / ctx.reflect,全是 cordis 内建)。
189
+ // 曾经 daemon 声明了 ['reflect','typert'],于是宿主那一行永远 waiting for
190
+ // typert、apply() 从不执行,设置页只报「远程方法未挂载」。
189
191
  inject: [...new Set([...memoryInject, ...daemonInject])],
190
192
  apply: applyEntry,
191
193
  };