dsh-agentic-pet 0.4.3 → 0.4.5
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.zh.md +4 -5
- package/client/pet-settings.js +22 -3
- package/lib/index.js +19 -37
- package/lib/{service-BjTawwUn.js → service-R8qwDx1Q.js} +3331 -2650
- package/lib/tools.js +4 -4
- package/lib/types/actions.d.ts +0 -1
- package/lib/types/driver.d.ts +0 -1
- package/lib/types/index.d.ts +0 -1
- package/lib/types/inner-voice.d.ts +83 -4
- package/lib/types/petdata.d.ts +0 -1
- package/lib/types/registry.d.ts +0 -1
- package/lib/types/service.d.ts +0 -1
- package/lib/types/settings-page.d.ts +0 -1
- package/lib/types/tools.d.ts +2 -2
- package/package.json +1 -1
- package/presets/pet-inner-voice.patch.yml +1 -0
package/README.zh.md
CHANGED
|
@@ -36,13 +36,11 @@ dsh plugin --profile <name> add dsh-agentic-pet
|
|
|
36
36
|
|
|
37
37
|
## 开发
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
日常迭代在本仓库内完成:改 `src/` → 本地构建(tsc + tsdown,工具链与私有包依赖的准备见文档)→ 部署到桌面 profile 的 vendor 目录 → 重启 DeepSeek Harness。**完整手册(含工具链准备、部署/验证/清理命令与已知坑)见 [docs/DEV-DEPLOY.md](docs/DEV-DEPLOY.md)**。
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
2. 本仓库:`scripts\sync-from-monorepo.cmd`——把源码与构建产物镜像进本仓库。
|
|
43
|
-
3. 本仓库提交,然后在本仓库发布(见下文「发布」;先素材包后插件包,手册见 [dsh-pet-assets/PUBLISH.md](../dsh-pet-assets/PUBLISH.md))。
|
|
41
|
+
历史上的构建在 dsh monorepo workspace 内进行(被打包的 `@deepseek-ai/dsh-*` 依赖未发布 npm),经 `scripts\sync-from-monorepo.cmd` 镜像进本仓库——monorepo 侧副本已停在 `0.2.1-rc.3`,该链路已过期,仅留档;直接运行会用旧代码覆盖本仓库。
|
|
44
42
|
|
|
45
|
-
测试:`
|
|
43
|
+
测试:`node_modules/.bin/vitest run`(vitest 及 `js-yaml@4.1.0`、`@deepseek-ai/cordis-plugin-include` 为 ad-hoc 安装,见文档 §4);`tests/registry-service.spec.ts` 等纯函数规格只需 `cordis` 与 `vitest` 即可自持运行。
|
|
46
44
|
|
|
47
45
|
## 发布
|
|
48
46
|
|
|
@@ -60,6 +58,7 @@ git push --follow-tags
|
|
|
60
58
|
|
|
61
59
|
## 文档
|
|
62
60
|
|
|
61
|
+
- 开发与部署手册(本地构建工具链、vendor 部署、测试、发布、已知坑):[docs/DEV-DEPLOY.md](docs/DEV-DEPLOY.md)。
|
|
63
62
|
- 控制面契约(所有宠物实现共同讲述的冻结消费方 API)见项目文档的多宠指南。
|
|
64
63
|
- 说话朗读(BreezeBlue TTS)设计笔记见 monorepo 工作区的 `packages/bundle/pet-app/docs/tts.md`。
|
|
65
64
|
- 已知边界与设计笔记见仓库 wiki 与项目工程文档。
|
package/client/pet-settings.js
CHANGED
|
@@ -233,14 +233,14 @@ window.__ModuleLoader__.load({
|
|
|
233
233
|
update({ innerVoice: { enabled: !(iv.enabled !== false) } })
|
|
234
234
|
} })),
|
|
235
235
|
h('div', { style: row },
|
|
236
|
-
'
|
|
236
|
+
'世界时钟间隔',
|
|
237
237
|
h('input', { style: inputStyle, value: String(iv.wakeIntervalMinutes ?? 2), onChange: function (e) {
|
|
238
238
|
var v = parseInt(e.target.value, 10)
|
|
239
239
|
if (Number.isFinite(v)) update({ innerVoice: { wakeIntervalMinutes: v } })
|
|
240
240
|
} }),
|
|
241
241
|
'分钟'),
|
|
242
242
|
h('div', { style: row },
|
|
243
|
-
'
|
|
243
|
+
'世界时钟唤醒概率',
|
|
244
244
|
h('input', { style: inputStyle, value: String(Math.round(((typeof iv.speakProbability === 'number' ? iv.speakProbability : 0.5)) * 100)), onChange: function (e) {
|
|
245
245
|
var v = parseFloat(e.target.value)
|
|
246
246
|
if (Number.isFinite(v)) update({ innerVoice: { speakProbability: Math.min(100, Math.max(0, v)) / 100 } })
|
|
@@ -260,6 +260,25 @@ window.__ModuleLoader__.load({
|
|
|
260
260
|
if (Number.isFinite(v) && v >= 0) update({ innerVoice: { touchReplyCooldownSeconds: Math.min(600, v) } })
|
|
261
261
|
} }),
|
|
262
262
|
'秒(0 = 不限)'),
|
|
263
|
+
h('div', { style: row }, '自主唤醒遇用户忙',
|
|
264
|
+
(function () {
|
|
265
|
+
var seg = function (active, side) {
|
|
266
|
+
return { padding: '4px 12px', fontSize: 12, cursor: 'pointer',
|
|
267
|
+
border: '1px solid ' + (active ? '#22c55e' : '#c9d4e0'),
|
|
268
|
+
background: active ? '#22c55e' : '#f4f7fa',
|
|
269
|
+
color: active ? '#ffffff' : '#1c2733',
|
|
270
|
+
borderRadius: side === 'left' ? '4px 0 0 4px' : '0 4px 4px 0',
|
|
271
|
+
marginLeft: side === 'right' ? -1 : 0 }
|
|
272
|
+
}
|
|
273
|
+
var policy = iv.selfWakeBusyPolicy === 'defer' ? 'defer' : 'fire'
|
|
274
|
+
return h('div', { style: { display: 'inline-flex' } },
|
|
275
|
+
h('button', { style: seg(policy === 'fire', 'left'), onClick: function () {
|
|
276
|
+
if (policy !== 'fire') update({ innerVoice: { selfWakeBusyPolicy: 'fire' } })
|
|
277
|
+
} }, '到点必醒'),
|
|
278
|
+
h('button', { style: seg(policy === 'defer', 'right'), onClick: function () {
|
|
279
|
+
if (policy !== 'defer') update({ innerVoice: { selfWakeBusyPolicy: 'defer' } })
|
|
280
|
+
} }, '忙时顺延'))
|
|
281
|
+
})()),
|
|
263
282
|
h('div', { style: row }, '会话模式',
|
|
264
283
|
(function () {
|
|
265
284
|
var seg = function (active, side) {
|
|
@@ -286,7 +305,7 @@ window.__ModuleLoader__.load({
|
|
|
286
305
|
else delete next.electron
|
|
287
306
|
update({ innerVoice: { boundSessions: next } })
|
|
288
307
|
} })),
|
|
289
|
-
h(Hint, null, '
|
|
308
|
+
h(Hint, null, '宠物在自己专属的会话里醒来,用气泡和动作自主表达;那条「鲸鱼娘的内心戏」会话可在会话列表查看,也可以直接在那里和它聊天。醒来有两个来源:世界时钟是环境节拍,按上面的间隔和唤醒概率随机轻拍她,用户忙于会话或宠物表达未完成时不会打扰;自主唤醒是她用 pet_schedule_wake 给自己定的闹钟,到点带着当初的打算醒来,不受这个概率影响(上面的「自主唤醒遇用户忙」决定你正忙时她是否照醒,默认到点必醒)。会话模式切换只对新建会话生效:归档旧会话后,她会在下次对话时自动换代重建(旧会话记忆不迁移)。指定会话立即生效——下一次对话就用新绑定的会话;清空后自动回落到她之前的会话(那条若已被归档,会自动创建新的)。')),
|
|
290
309
|
|
|
291
310
|
h(Section, { title: h('span', null, '自由活动 ', h('span', { style: { fontSize: 11, fontWeight: 400, color: 'rgba(127,127,127,.9)' } }, '逻辑驱动')) },
|
|
292
311
|
h('div', { style: row }, '自由活动(宠物自娱)', h(Toggle, { value: pro.idleAnimation !== false, onChange: function () {
|
package/lib/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { c as globalFilePath, d as readJsonl, f as readPetName, h as writePetName, i as installPetDriver, l as readAffectionRaw, m as writeGlobalJson, n as installPetService, p as writeAffectionRaw, r as petHome, s as eventsFile, u as readGlobalJson } from "./service-
|
|
1
|
+
import { c as globalFilePath, d as readJsonl, f as readPetName, h as writePetName, i as installPetDriver, l as readAffectionRaw, m as writeGlobalJson, n as installPetService, p as writeAffectionRaw, r as petHome, s as eventsFile, u as readGlobalJson } from "./service-R8qwDx1Q.js";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import { spawn
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
|
-
import { appendFileSync, existsSync,
|
|
5
|
+
import { appendFileSync, existsSync, readFileSync } from "node:fs";
|
|
6
6
|
import { mkdir, readFile, rm, unlink, writeFile } from "node:fs/promises";
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
8
|
import { dirname, extname, join, normalize, resolve, sep } from "node:path";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
|
-
|
|
10
|
+
// lib/types/settings-page.js
|
|
11
11
|
/**
|
|
12
12
|
* The settings page's host half: local HTTP routes backing the desktop
|
|
13
13
|
* sidebar "桌宠" page (the client half lives in ./client/pet-settings.js and
|
|
@@ -36,6 +36,7 @@ const DEFAULT_SETTINGS = {
|
|
|
36
36
|
speakProbability: .5,
|
|
37
37
|
touchReplyProbability: .3,
|
|
38
38
|
touchReplyCooldownSeconds: 30,
|
|
39
|
+
selfWakeBusyPolicy: "fire",
|
|
39
40
|
boundSessions: {}
|
|
40
41
|
},
|
|
41
42
|
tts: { enabled: false },
|
|
@@ -78,7 +79,7 @@ async function readJsonBody(req) {
|
|
|
78
79
|
let size = 0;
|
|
79
80
|
for await (const chunk of req) {
|
|
80
81
|
size += chunk.length;
|
|
81
|
-
if (size >
|
|
82
|
+
if (size > 1048576) return void 0;
|
|
82
83
|
chunks.push(chunk);
|
|
83
84
|
}
|
|
84
85
|
try {
|
|
@@ -130,6 +131,7 @@ function mergeSettings(current, patch) {
|
|
|
130
131
|
if (typeof v.touchReplyProbability === "number" && Number.isFinite(v.touchReplyProbability)) innerVoice.touchReplyProbability = Math.min(1, Math.max(0, v.touchReplyProbability));
|
|
131
132
|
const replyCooldown = clampNumber(v.touchReplyCooldownSeconds, 0, 600);
|
|
132
133
|
if (replyCooldown !== void 0) innerVoice.touchReplyCooldownSeconds = replyCooldown;
|
|
134
|
+
if (v.selfWakeBusyPolicy === "defer" || v.selfWakeBusyPolicy === "fire") innerVoice.selfWakeBusyPolicy = v.selfWakeBusyPolicy;
|
|
133
135
|
const bound = v.boundSessions;
|
|
134
136
|
if (typeof bound === "object" && bound !== null) {
|
|
135
137
|
const record = {};
|
|
@@ -177,7 +179,8 @@ function openPathInFileManager(path) {
|
|
|
177
179
|
}).unref();
|
|
178
180
|
return;
|
|
179
181
|
}
|
|
180
|
-
|
|
182
|
+
const command = process.platform === "darwin" ? "open" : "xdg-open";
|
|
183
|
+
spawn(command, [path], {
|
|
181
184
|
detached: true,
|
|
182
185
|
stdio: "ignore"
|
|
183
186
|
}).unref();
|
|
@@ -371,8 +374,7 @@ function installSettingsPage(ctx, home, pet) {
|
|
|
371
374
|
}
|
|
372
375
|
});
|
|
373
376
|
}
|
|
374
|
-
|
|
375
|
-
//#region lib/types/index.js
|
|
377
|
+
// lib/types/index.js
|
|
376
378
|
/**
|
|
377
379
|
* dsh-agentic-pet — the pet-surface bundle's runtime glue plugin plus
|
|
378
380
|
* the bundle patch (`cordis.patch.yml`, declared by the `dsh.bundle.patch`
|
|
@@ -433,7 +435,7 @@ const MIME = {
|
|
|
433
435
|
".webmanifest": "application/manifest+json",
|
|
434
436
|
".woff2": "font/woff2"
|
|
435
437
|
};
|
|
436
|
-
const STATIC_MISS_CODES = new Set([
|
|
438
|
+
const STATIC_MISS_CODES = /* @__PURE__ */ new Set([
|
|
437
439
|
"ENOENT",
|
|
438
440
|
"EISDIR",
|
|
439
441
|
"ENOTDIR"
|
|
@@ -477,7 +479,8 @@ function bytesBody(bytes) {
|
|
|
477
479
|
async function servePetStatic(request, distRoot, distIndex, authorizeIndex) {
|
|
478
480
|
const pathname = decodeURIComponent(new URL(request.url).pathname);
|
|
479
481
|
if (!(pathname === "/whale598" || pathname.startsWith(`/whale598/`))) return new Response(null, { status: 404 });
|
|
480
|
-
const
|
|
482
|
+
const relative = pathname === "/whale598" || pathname === `/whale598/` ? "/" : pathname.slice(9);
|
|
483
|
+
const target = resolve(normalize(join(distRoot, relative)));
|
|
481
484
|
if (target !== distRoot && !target.startsWith(distRoot + sep)) return new Response(null, { status: 403 });
|
|
482
485
|
let body;
|
|
483
486
|
let headers;
|
|
@@ -626,7 +629,8 @@ function apply(ctx) {
|
|
|
626
629
|
*/
|
|
627
630
|
const resolveElectronBinary = () => {
|
|
628
631
|
if (process.env.DSH_PET_ELECTRON !== void 0 && process.env.DSH_PET_ELECTRON !== "") return process.env.DSH_PET_ELECTRON;
|
|
629
|
-
const
|
|
632
|
+
const pkgRoot = resolve(join(dirname(fileURLToPath(import.meta.url)), ".."));
|
|
633
|
+
const staged = join(pkgRoot, "electron-bin", process.platform === "win32" ? "electron.exe" : process.platform === "darwin" ? join("Electron.app", "Contents", "MacOS", "Electron") : "electron");
|
|
630
634
|
if (existsSync(staged)) return staged;
|
|
631
635
|
try {
|
|
632
636
|
const require = createRequire(import.meta.url);
|
|
@@ -637,7 +641,8 @@ function apply(ctx) {
|
|
|
637
641
|
let dir = dirname(fileURLToPath(import.meta.url));
|
|
638
642
|
for (let i = 0; i < 8; i += 1) {
|
|
639
643
|
const pkgDir = join(dir, "node_modules", "electron");
|
|
640
|
-
const
|
|
644
|
+
const exe = readFileSync(join(pkgDir, "path.txt"), "utf8").trim();
|
|
645
|
+
const binary = join(pkgDir, "dist", exe);
|
|
641
646
|
if (existsSync(binary)) return binary;
|
|
642
647
|
const parent = dirname(dir);
|
|
643
648
|
if (parent === dir) break;
|
|
@@ -656,31 +661,9 @@ function apply(ctx) {
|
|
|
656
661
|
const carrierDir = resolve(join(dirname(fileURLToPath(import.meta.url)), "..", "carrier"));
|
|
657
662
|
const electronBinary = resolveElectronBinary();
|
|
658
663
|
if (process.env.DSH_PET_NO_SPAWN === "1" || electronBinary === void 0 || !existsSync(join(carrierDir, "package.json"))) return;
|
|
659
|
-
let probeStatus = "unstarted";
|
|
660
|
-
const startsSandboxed = (() => {
|
|
661
|
-
try {
|
|
662
|
-
const probe = spawnSync(electronBinary, ["--version"], {
|
|
663
|
-
env: stripRunAsNode(process.env),
|
|
664
|
-
stdio: "ignore",
|
|
665
|
-
timeout: 5e3
|
|
666
|
-
});
|
|
667
|
-
probeStatus = probe.error === void 0 ? `status=${String(probe.status)}` : `error=${String(probe.error.code ?? probe.error.message)}`;
|
|
668
|
-
return probe.status === 0;
|
|
669
|
-
} catch (error) {
|
|
670
|
-
probeStatus = `throw=${error instanceof Error ? error.message : String(error)}`;
|
|
671
|
-
return false;
|
|
672
|
-
}
|
|
673
|
-
})();
|
|
674
664
|
const launchArgs = [carrierDir];
|
|
675
|
-
if (
|
|
676
|
-
|
|
677
|
-
const carrierUserData = join(dirname(petLocatorPath()), "carrier-userdata");
|
|
678
|
-
try {
|
|
679
|
-
mkdirSync(carrierUserData, { recursive: true });
|
|
680
|
-
} catch {}
|
|
681
|
-
launchArgs.push("--no-sandbox", `--user-data-dir=${carrierUserData}`);
|
|
682
|
-
}
|
|
683
|
-
logCarrier(`spawn binary=${electronBinary} args=${JSON.stringify(launchArgs)} probe=${probeStatus} pid=${String(process.pid)}`);
|
|
665
|
+
if (process.env.DSH_PET_NO_SANDBOX === "1") launchArgs.push("--no-sandbox");
|
|
666
|
+
logCarrier(`spawn binary=${electronBinary} args=${JSON.stringify(launchArgs)} pid=${String(process.pid)}`);
|
|
684
667
|
const child = (() => {
|
|
685
668
|
try {
|
|
686
669
|
return spawn(electronBinary, launchArgs, {
|
|
@@ -743,5 +726,4 @@ function apply(ctx) {
|
|
|
743
726
|
}).catch(() => {});
|
|
744
727
|
}, "pet-surface: locator withdrawal");
|
|
745
728
|
}
|
|
746
|
-
//#endregion
|
|
747
729
|
export { PET_PATH_PREFIX, apply, inject, name, petLocatorPath, servePetStatic };
|