dsh-kaomoji 0.1.2 → 0.1.4
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/CHANGELOG.md +15 -0
- package/README.en.md +1 -1
- package/README.md +1 -1
- package/lib/client.js +20 -9
- package/lib/index.js +35 -14
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/lang/zh-CN/
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.4] - 2026-09-25
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- 设置卡片在保存失败时直接显示 Host 返回的真实原因(例如文件不可写、来源不受信任),
|
|
15
|
+
不再只显示通用的“保存失败”,便于定位服务器端问题。
|
|
16
|
+
|
|
17
|
+
## [0.1.3] - 2026-09-13
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- `maxPerTurn` 之前对输出没有实际约束力:提示词写死「一个」,调到 2/3 也不会变。
|
|
22
|
+
现在 `frequent` 会按该上限在回复里分散放置多个颜文字,`auto` 在存在多个
|
|
23
|
+
情绪点时也会用到上限;回复很短时自动少放。
|
|
24
|
+
|
|
10
25
|
## [0.1.2] - 2026-09-10
|
|
11
26
|
|
|
12
27
|
### Changed
|
package/README.en.md
CHANGED
|
@@ -104,7 +104,7 @@ Example `cordis.patch.yml`:
|
|
|
104
104
|
| --- | --- | --- | --- |
|
|
105
105
|
| `mode` | `'off' \| 'auto' \| 'frequent'` | `'auto'` | `off` disables; `auto` adds one to greetings, casual chat, recommendations and empathetic replies; `frequent` adds one to every conversational reply (code-only/formal replies excluded) |
|
|
106
106
|
| `placement` | `'inline' \| 'end'` | `'inline'` | Put the kaomoji after the best-matching sentence, or at the reply end |
|
|
107
|
-
| `maxPerTurn` | `number` (1–5) | `1` | Max kaomoji per reply |
|
|
107
|
+
| `maxPerTurn` | `number` (1–5) | `1` | Max kaomoji per reply; `frequent` distributes that many across different sentences (fewer in very short replies) |
|
|
108
108
|
| `customPrompt` | `string` | `''` | Extra style/scene guidance; cannot change mode, whitelist or limits |
|
|
109
109
|
| `settingsFile` | `string` | `~/.dsh/dsh-kaomoji.json` | (advanced) user-settings file path |
|
|
110
110
|
| `settingsAuthority` | `'trusted-host' \| 'loopback'` | `'trusted-host'` | Settings RPC trust scope: by default the local Host plus declared trusted hosts (Tailscale/LAN) may write; set `loopback` to restrict to the local machine |
|
package/README.md
CHANGED
|
@@ -120,7 +120,7 @@ pnpm add file:C:\path\to\dsh-kaomoji
|
|
|
120
120
|
| --- | --- | --- | --- |
|
|
121
121
|
| `mode` | `'off' \| 'auto' \| 'frequent'` | `'auto'` | `off` 关闭;`auto` 寒暄/闲聊/推荐建议/共情回复都会带一个;`frequent` 每条对话回复都带一个(两者都跳过纯代码 / 正式技术交付) |
|
|
122
122
|
| `placement` | `'inline' \| 'end'` | `'inline'` | 放在情绪最贴切的句子/短段后,或固定在回复末尾 |
|
|
123
|
-
| `maxPerTurn` | `number`(1–5) | `1` |
|
|
123
|
+
| `maxPerTurn` | `number`(1–5) | `1` | 每条回复的颜文字数量上限;`frequent` 会按这个数量分散放在不同句子后,回复太短时自动减少 |
|
|
124
124
|
| `customPrompt` | `string` | `''` | 附加风格/场景说明;不能改变模式、白名单或数量上限 |
|
|
125
125
|
| `settingsFile` | `string` | `~/.dsh/dsh-kaomoji.json` | (进阶)用户设置持久化文件路径 |
|
|
126
126
|
| `settingsAuthority` | `'trusted-host' \| 'loopback'` | `'trusted-host'` | 设置 RPC 信任范围:默认允许本机与 Host 声明的受信主机(Tailscale/局域网)保存设置;改成 `loopback` 则仅本机可改 |
|
package/lib/client.js
CHANGED
|
@@ -230,7 +230,9 @@ window.__ModuleLoader__.load({
|
|
|
230
230
|
};
|
|
231
231
|
|
|
232
232
|
const publish = (patch) => {
|
|
233
|
-
snapshot =
|
|
233
|
+
snapshot = patch.saveError === null
|
|
234
|
+
? { ...snapshot, ...patch, saveErrorMessage: null }
|
|
235
|
+
: { ...snapshot, ...patch };
|
|
234
236
|
emit();
|
|
235
237
|
};
|
|
236
238
|
|
|
@@ -240,11 +242,12 @@ window.__ModuleLoader__.load({
|
|
|
240
242
|
return task;
|
|
241
243
|
};
|
|
242
244
|
|
|
243
|
-
const fail = (code) => {
|
|
245
|
+
const fail = (code, message) => {
|
|
244
246
|
publish({
|
|
245
247
|
status: "unavailable",
|
|
246
248
|
writable: false,
|
|
247
249
|
saveError: code,
|
|
250
|
+
saveErrorMessage: message || null,
|
|
248
251
|
justSaved: false,
|
|
249
252
|
});
|
|
250
253
|
};
|
|
@@ -253,11 +256,17 @@ window.__ModuleLoader__.load({
|
|
|
253
256
|
try {
|
|
254
257
|
const result = await rpc.call(RPC_CHANNEL, endpoint, payload);
|
|
255
258
|
if (result && result.ok === true) return { value: result.value };
|
|
256
|
-
const
|
|
257
|
-
return {
|
|
259
|
+
const error = (result && result.error) || {};
|
|
260
|
+
return {
|
|
261
|
+
error: error.code === "forbidden" ? "forbidden" : "rejected",
|
|
262
|
+
message: typeof error.message === "string" ? error.message : undefined,
|
|
263
|
+
};
|
|
258
264
|
} catch (error) {
|
|
259
265
|
const message = String((error && error.message) || error || "");
|
|
260
|
-
return {
|
|
266
|
+
return {
|
|
267
|
+
error: /403|forbidden/i.test(message) ? "forbidden" : "unreachable",
|
|
268
|
+
message,
|
|
269
|
+
};
|
|
261
270
|
}
|
|
262
271
|
};
|
|
263
272
|
|
|
@@ -270,7 +279,7 @@ window.__ModuleLoader__.load({
|
|
|
270
279
|
async refresh() {
|
|
271
280
|
const result = await callRpc("get", {});
|
|
272
281
|
if (result.error !== undefined) {
|
|
273
|
-
fail(result.error === "forbidden" ? "forbidden" : "load");
|
|
282
|
+
fail(result.error === "forbidden" ? "forbidden" : "load", result.message);
|
|
274
283
|
return;
|
|
275
284
|
}
|
|
276
285
|
const value = result.value;
|
|
@@ -297,7 +306,7 @@ window.__ModuleLoader__.load({
|
|
|
297
306
|
expectedRevision: snapshot.revision,
|
|
298
307
|
});
|
|
299
308
|
if (result.error !== undefined) {
|
|
300
|
-
fail(result.error === "forbidden" ? "forbidden" : "save");
|
|
309
|
+
fail(result.error === "forbidden" ? "forbidden" : "save", result.message);
|
|
301
310
|
return;
|
|
302
311
|
}
|
|
303
312
|
const value = result.value;
|
|
@@ -316,7 +325,7 @@ window.__ModuleLoader__.load({
|
|
|
316
325
|
publish({ saveError: null, justSaved: false });
|
|
317
326
|
const result = await callRpc("reset", { expectedRevision: snapshot.revision });
|
|
318
327
|
if (result.error !== undefined) {
|
|
319
|
-
fail(result.error === "forbidden" ? "forbidden" : "save");
|
|
328
|
+
fail(result.error === "forbidden" ? "forbidden" : "save", result.message);
|
|
320
329
|
return;
|
|
321
330
|
}
|
|
322
331
|
const value = result.value;
|
|
@@ -348,7 +357,9 @@ window.__ModuleLoader__.load({
|
|
|
348
357
|
const statusText = state.saveError
|
|
349
358
|
? state.saveError === "forbidden"
|
|
350
359
|
? t("status.forbidden")
|
|
351
|
-
:
|
|
360
|
+
: state.saveErrorMessage
|
|
361
|
+
? `${t("status.error")} ${state.saveErrorMessage}`
|
|
362
|
+
: t("status.error")
|
|
352
363
|
: state.status === "loading"
|
|
353
364
|
? t("status.loading")
|
|
354
365
|
: !state.writable
|
package/lib/index.js
CHANGED
|
@@ -144,20 +144,32 @@ export function buildGuidance(config) {
|
|
|
144
144
|
const settings = normalizeConfig(config);
|
|
145
145
|
if (settings.mode === "off") return "";
|
|
146
146
|
|
|
147
|
+
const cap = settings.maxPerTurn;
|
|
147
148
|
const modeLines = {
|
|
148
149
|
auto: [
|
|
149
|
-
"Most conversational replies should include
|
|
150
|
+
"Most conversational replies should include a fitting kaomoji — greetings, casual chat, empathy, everyday recommendations or shopping advice, and practical how-to answers.",
|
|
151
|
+
cap === 1
|
|
152
|
+
? "Use one kaomoji in those replies."
|
|
153
|
+
: `Use one kaomoji when the mood fits, and up to ${String(cap)} when the reply has several distinct emotional beats.`,
|
|
150
154
|
"Skip it only when the reply is purely code, a formal/technical deliverable, or serious/high-stakes content.",
|
|
151
|
-
"One per reply is usually enough; never replace real content with it.",
|
|
152
155
|
],
|
|
153
156
|
frequent: [
|
|
154
|
-
"In every conversational reply — except code-only output, formal/technical deliverables, or tool calls — include
|
|
157
|
+
"In every conversational reply — except code-only output, formal/technical deliverables, or tool calls — include fitting kaomoji.",
|
|
158
|
+
cap === 1
|
|
159
|
+
? "Use exactly one kaomoji."
|
|
160
|
+
: `Use ${String(cap)} kaomoji, one after each of ${String(cap)} different emotion-carrying sentences; use fewer only when the reply is very short.`,
|
|
155
161
|
],
|
|
156
162
|
};
|
|
157
|
-
const placementLine =
|
|
158
|
-
|
|
163
|
+
const placementLine = settings.placement === "end"
|
|
164
|
+
? cap === 1
|
|
159
165
|
? "Put the kaomoji at the very end of the reply (same line after a space, or on its own line)."
|
|
160
|
-
: "Put
|
|
166
|
+
: "Put each kaomoji at the end of a different paragraph (after the sentence it matches), not all on the final line."
|
|
167
|
+
: cap === 1
|
|
168
|
+
? "Put it right after the sentence or short paragraph whose mood it matches best."
|
|
169
|
+
: "Put each kaomoji right after a different sentence or short paragraph whose mood it matches best.";
|
|
170
|
+
const spreadLine = cap > 1
|
|
171
|
+
? "Distribute the kaomoji across the reply; never put two in the same sentence, and do not stack them all at the very end."
|
|
172
|
+
: "Never replace real content with a kaomoji.";
|
|
161
173
|
|
|
162
174
|
const poolLines = CATALOG.map(
|
|
163
175
|
(group) => `${group.label}: ${group.examples.join(" | ")}`,
|
|
@@ -168,7 +180,8 @@ export function buildGuidance(config) {
|
|
|
168
180
|
"[dsh-kaomoji] Kaomoji guidance for this reply:",
|
|
169
181
|
...modeLines[settings.mode],
|
|
170
182
|
placementLine,
|
|
171
|
-
|
|
183
|
+
spreadLine,
|
|
184
|
+
`Never exceed ${String(cap)} kaomoji in one reply.`,
|
|
172
185
|
"Never place a kaomoji inside code blocks, inline code, links, tables, or tool output.",
|
|
173
186
|
"Use only the literal kaomoji listed below, copied character-for-character; do not invent, mutate, or re-combine them.",
|
|
174
187
|
...poolLines,
|
|
@@ -359,10 +372,9 @@ function createSettingsRpcHandler(ctx, settingsFile, getState, commit) {
|
|
|
359
372
|
return rpcError("bad-request", `Unknown dsh-kaomoji settings operation: ${endpoint}`);
|
|
360
373
|
});
|
|
361
374
|
} catch (error) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
);
|
|
365
|
-
return rpcError("settings-rejected", "The Host rejected the kaomoji settings.");
|
|
375
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
376
|
+
console.warn(`[dsh-kaomoji] settings rpc failed: ${reason}`);
|
|
377
|
+
return rpcError("settings-rejected", `The Host rejected the kaomoji settings: ${reason}`);
|
|
366
378
|
}
|
|
367
379
|
};
|
|
368
380
|
}
|
|
@@ -410,7 +422,7 @@ export function apply(ctx, config = {}) {
|
|
|
410
422
|
|
|
411
423
|
// 设置卡片通过 loopback RPC 读写 ~/.dsh/dsh-kaomoji.json;写入后立即
|
|
412
424
|
// 更新提示词段(emit system-prompt/change),无需重启。
|
|
413
|
-
|
|
425
|
+
const registerSettingsRpc = (connectionCtx) => {
|
|
414
426
|
const handler = createSettingsRpcHandler(ctx, settingsFile, getState, adoptSettings);
|
|
415
427
|
connectionCtx.effect(
|
|
416
428
|
() =>
|
|
@@ -419,9 +431,18 @@ export function apply(ctx, config = {}) {
|
|
|
419
431
|
}),
|
|
420
432
|
"dsh-kaomoji: settings rpc",
|
|
421
433
|
);
|
|
422
|
-
|
|
434
|
+
console.log(
|
|
435
|
+
`[dsh-kaomoji] settings rpc 已注册(channel=${SETTINGS_RPC_CHANNEL}, authority=${authority})`,
|
|
436
|
+
);
|
|
437
|
+
};
|
|
438
|
+
// connection 服务在多数部署里此刻已可用;拿不到再等 inject(旧版行为)。
|
|
439
|
+
if (typeof ctx.get === "function" && ctx.get("connection") !== undefined) {
|
|
440
|
+
registerSettingsRpc(ctx);
|
|
441
|
+
} else {
|
|
442
|
+
ctx.inject(["connection"], registerSettingsRpc);
|
|
443
|
+
}
|
|
423
444
|
|
|
424
|
-
|
|
445
|
+
console.log(
|
|
425
446
|
`[dsh-kaomoji] 已挂载(mode=${currentSettings.mode}, placement=${currentSettings.placement}, authority=${authority}, settingsFile=${settingsFile})`,
|
|
426
447
|
);
|
|
427
448
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-kaomoji",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Add mood-aware Japanese kaomoji to DeepSeek Harness (dsh) replies; prompt-injection plugin with a curated library from kaomojiya.org.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|