@tanweilabs/daiti 0.0.2 → 0.0.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/README.md +8 -4
- package/artifacts/manifest.json +12 -12
- package/artifacts/{tanweilabs-daiti-im-0.0.2-16f94aa853b3.tgz → tanweilabs-daiti-im-0.0.3-52e45084fd59.tgz} +0 -0
- package/artifacts/{tanweilabs-daiti-loading-0.0.2-fc449733ecaa.tgz → tanweilabs-daiti-loading-0.0.3-b61364395143.tgz} +0 -0
- package/artifacts/tanweilabs-daiti-preferences-0.0.3-8137cd254b7b.tgz +0 -0
- package/artifacts/tanweilabs-daiti-ui-0.0.3-5625684c363a.tgz +0 -0
- package/docs/validation.md +32 -1
- package/lib/cli.mjs +50 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/artifacts/tanweilabs-daiti-preferences-0.0.2-a0b22ddd8594.tgz +0 -0
- package/artifacts/tanweilabs-daiti-ui-0.0.2-3c9ee486f937.tgz +0 -0
package/README.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
在你的电脑上运行,通过网页或微信使用的个人助理。基于 DeepSeek Harness 和 DSH-IM,通过独立插件提供单主会话、助理设置和首次使用流程。
|
|
4
4
|
|
|
5
|
-
**0.0.
|
|
5
|
+
**0.0.3 为开发者预览版。** 本包不包含个人记忆、历史会话、密钥或 IM 登录数据。
|
|
6
6
|
|
|
7
7
|
## 安装
|
|
8
8
|
|
|
9
9
|
需要 Node.js `^22.19.0` 或 `>=24.0.0`:
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
|
-
npm install -g @tanweilabs/daiti@0.0.
|
|
12
|
+
npm install -g @tanweilabs/daiti@0.0.3
|
|
13
13
|
daiti start
|
|
14
14
|
```
|
|
15
15
|
|
|
@@ -63,7 +63,11 @@ PowerShell 对应设置 `$env:DAITI_HOME = "$HOME\.daiti-preview"`。测试时
|
|
|
63
63
|
|
|
64
64
|
适配包固定 DSH-IM 4.21.0,构建时复用其源码和运行时构造扩展点;不修改原包文件,也不修改 Harness 核心。这些扩展点不是稳定公开 API,上游升级需要契约测试。原许可证保存在适配包中。
|
|
65
65
|
|
|
66
|
-
0.0.2 已验证主会话绑定与连接健康状态,微信与网页共用会话已由用户实际验收。
|
|
66
|
+
0.0.2 已验证主会话绑定与连接健康状态,微信与网页共用会话已由用户实际验收。0.0.3 在此基础上修复了新装实例的插件层顺序问题(此前全新 `DAITI_HOME` 首次启动会因 `dshIm` 重复注册而失败),并默认启用实验性的 Agent Team 层。
|
|
67
|
+
|
|
68
|
+
## Agent Team
|
|
69
|
+
|
|
70
|
+
0.0.3 起,profile 默认挂载 `@deepseek-ai/dsh-experimental-agent-team-profile` 与 `-web-profile`:主会话可以作为 Team Lead 用 `spawn_teammate` 建立具名成员,成员是有独立会话的 durable 子代理,通过共享任务板与 `send_message`/`wait_agent` 协作;浏览器侧由官方 Agent Team 面板展示名册与任务板。该层为官方实验特性,不承诺稳定;启用后 Harness 的全局 `subagent`/`subagent_fork` 工具被 Team 工具替代(`workflow` 不受影响),而"标准模式"预设内的子代理工具是否同时生效仍待真实会话验收。
|
|
67
71
|
|
|
68
72
|
## 开发和本地打包
|
|
69
73
|
|
|
@@ -75,7 +79,7 @@ npm run pack:local
|
|
|
75
79
|
|
|
76
80
|
构建将四个插件打包到 `artifacts/`,生成文件名和 SHA-256 清单。`pack:local` 在 `.local/releases/` 生成 CLI 安装包;包含运行入口、插件包和文档,不包含仓库工作目录、上游源码、个人配置或测试数据。
|
|
77
81
|
|
|
78
|
-
未发布的本地安装包可用 `npm install -g /path/to/tanweilabs-daiti-0.0.
|
|
82
|
+
未发布的本地安装包可用 `npm install -g /path/to/tanweilabs-daiti-0.0.3.tgz` 安装,随后使用 `daiti start`。安装仍需联网获取声明的运行依赖。
|
|
79
83
|
|
|
80
84
|
- `bin/`、`lib/`:CLI 和后台进程管理。
|
|
81
85
|
- `packages/assistant-ui/`:界面、首次设置和助理配置。
|
package/artifacts/manifest.json
CHANGED
|
@@ -2,27 +2,27 @@
|
|
|
2
2
|
"plugins": [
|
|
3
3
|
{
|
|
4
4
|
"name": "@tanweilabs/daiti-ui",
|
|
5
|
-
"version": "0.0.
|
|
6
|
-
"file": "tanweilabs-daiti-ui-0.0.
|
|
7
|
-
"sha256": "
|
|
5
|
+
"version": "0.0.3",
|
|
6
|
+
"file": "tanweilabs-daiti-ui-0.0.3-5625684c363a.tgz",
|
|
7
|
+
"sha256": "5625684c363a28b912cb6862c2063f2c304dfa02039127a16dd1a7a1b0a7f6e5"
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
"name": "@tanweilabs/daiti-preferences",
|
|
11
|
-
"version": "0.0.
|
|
12
|
-
"file": "tanweilabs-daiti-preferences-0.0.
|
|
13
|
-
"sha256": "
|
|
11
|
+
"version": "0.0.3",
|
|
12
|
+
"file": "tanweilabs-daiti-preferences-0.0.3-8137cd254b7b.tgz",
|
|
13
|
+
"sha256": "8137cd254b7be52ff8219be31bcfd466d50a727b5a888d1b1324e5017a5b0797"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"name": "@tanweilabs/daiti-loading",
|
|
17
|
-
"version": "0.0.
|
|
18
|
-
"file": "tanweilabs-daiti-loading-0.0.
|
|
19
|
-
"sha256": "
|
|
17
|
+
"version": "0.0.3",
|
|
18
|
+
"file": "tanweilabs-daiti-loading-0.0.3-b61364395143.tgz",
|
|
19
|
+
"sha256": "b613643951436c2e565b953a6a04a7d0c2cdcc619fae6bc98d7cddb535b27b77"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"name": "@tanweilabs/daiti-im",
|
|
23
|
-
"version": "0.0.
|
|
24
|
-
"file": "tanweilabs-daiti-im-0.0.
|
|
25
|
-
"sha256": "
|
|
23
|
+
"version": "0.0.3",
|
|
24
|
+
"file": "tanweilabs-daiti-im-0.0.3-52e45084fd59.tgz",
|
|
25
|
+
"sha256": "52e45084fd59d83bc9abba3c4a06fcab2578fe7430e99619a1fa490cb339dbb2"
|
|
26
26
|
}
|
|
27
27
|
]
|
|
28
28
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/validation.md
CHANGED
|
@@ -27,10 +27,41 @@
|
|
|
27
27
|
|
|
28
28
|
18项自动测试通过,其中9项为IM路由、本人私聊限制、缺主会话拒绝、目录同一性及真实上游 ask 路径。隔离 Host probe 已通过实际 modernHarnessApi、HarnessClient 和 BotWorkspaceStore 的绑定及持久化回读。真实账号启动时发现大小写不同但指向同目录的路径误判,改为文件系统身份比较并增加回归测试。修复后账号显示1/1在线,状态healthy且error为空,绑定ID与网页主ID一致;旧独立微信会话文件哈希仍与备份一致。未主动发送真实微信消息;跨端模型回复待用户验证。本地修复未发布npm。
|
|
29
29
|
|
|
30
|
-
## 2026-09-21
|
|
30
|
+
## 2026-09-21 自动端口选择(随 0.0.2 发布)
|
|
31
31
|
|
|
32
32
|
- 默认启动先尝试 3086;被占用时由操作系统分配空闲本机端口,实际端口用于就绪校验、状态查询和浏览器地址。显式 `--port` 冲突时明确报错。
|
|
33
33
|
- 同一 DAITI_HOME 的已认证服务优先复用,不因端口参数重复启动。
|
|
34
34
|
- `npm test` 20 项通过,`npm run build` 通过。
|
|
35
35
|
- 独立 `.local/acceptance` 实例真实启动:3086 已占用时选择 55957,重复启动保持同一实例;停止后显式 3086 报错且未创建服务;再次默认启动选择 56049,主会话 ID 不变;最后测试服务已停止,个人 3086 服务仍就绪。
|
|
36
36
|
- 端口探测与 Harness 绑定之间存在很短的竞争窗口;本次没有覆盖其他进程恰在该窗口抢占新端口的情形。
|
|
37
|
+
|
|
38
|
+
## 2026-09-21 浏览器标签页标题(0.0.3)
|
|
39
|
+
|
|
40
|
+
- 背景:Harness 在客户端构建时写死 `DSH_CLIENT_TITLE`,标签页显示为 `会话标题 — DeepSeek Harness`;打包成个人助理后应以产品名呈现。
|
|
41
|
+
- 改动:`packages/assistant-ui/document-title.js` 在插件装载期间接管 `document.title`,忽略后续写入并在卸载时释放;文案常量为 `代体`,可传 `title` 覆盖。
|
|
42
|
+
- 未改上游文件,也未重新构建 Harness 前端;产品名仍来自官方构建产物,仅在运行时被接管。
|
|
43
|
+
- `npm test` 25 项通过(含 5 项标题接管:接管、忽略后续写入、卸载释放、自定义/空文案、无 document 时不崩);`npm run build` 通过,`@tanweilabs/daiti-ui` 升到 0.0.3。
|
|
44
|
+
- 已确认:`.local/acceptance` 实例重新安装后,profile 内 `client.cjs` 含接管代码;个人 3086 服务未被改动。
|
|
45
|
+
- 未验证:没有在真实浏览器里确认标签页文字与首屏闪烁;接管发生在客户端插件加载后,Harness 自带 title 在此之前可能短暂可见。
|
|
46
|
+
|
|
47
|
+
## 2026-09-21 忙碌时默认插话(0.0.3,未发布)
|
|
48
|
+
|
|
49
|
+
- 背景:Harness `ui-conversation` 的 `busyEnter` 默认是 `queue`(助理忙碌时回车排队),代体要改成忙碌时插话(`steer`)。上游注册该命名空间时不传 composition `base`、也不读入口 config,所以 profile patch 层无法直接改这个默认值。
|
|
50
|
+
- 改动:`packages/assistant-ui/busy-enter-default.js` 在插件启动时通过官方 settings 服务(`ctx.settings.describe()` / `update()`)把 `ui-conversation.busyEnter` 写成 `steer`;字段已存在于命名空间的用户层(用户在设置页选过)时不覆盖,因此重启幂等、用户显式选择优先。`onboarding-host.js` 调用安装,`package.json` 的 `files` 增加该模块。
|
|
51
|
+
- 未改上游文件与 `node_modules`,未新增依赖;写的是官方用户设置文档 `$DSH_HOME/settings.yaml`(即设置页/模型页写的那份),YAML 格式、注释保留、revision 与校验仍由上游负责。
|
|
52
|
+
- `npm test` 36 项通过(新增 11 项:字段与取值、无用户选择时写入、显式选择保留、已是 steer 不重写、等命名空间注册、写失败重试与放弃、dispose 后停止、无 settings 服务不崩、`apply` 接线);`npm run build` 通过,4 个插件包。`@tanweilabs/daiti-ui` 维持 0.0.3(0.0.3 尚未发布,与标签页标题同批)。
|
|
53
|
+
- 独立 `DAITI_HOME` 验收(`.local/acceptance`,已有 onboarding 数据但无 settings 文档):启动后生成 `runtime/settings.yaml`,内容 `ui-conversation:` / ` busyEnter: steer`;重启后该文件哈希与 mtime 均未变、主会话 ID 不变;手工改成 `queue` 再启动仍是 `queue`(用户选择未被覆盖);测试服务已停止,个人 3086 未被改动。
|
|
54
|
+
- 隔离 probe(`.local/busy-enter-probe.mjs`,一次性脚本,未随包发布)用真实 `@deepseek-ai/dsh-settings-file` 与真实 `ui-conversation` host 装载验收实例的 `runtime/`:`ctx.settings.get('ui-conversation')` 为 `{busyEnter:'steer'}`,`describe()` 中 `value` 与 `user` 都是 steer。
|
|
55
|
+
- 未验证:没有在真实浏览器与真实模型回合里确认忙碌时回车的实际投递;上游 `resolveSubmitMode('steer', true, 'enter', true) === 'steer'` 目前只是源码阅读结论。
|
|
56
|
+
- 另发现(已在本版修复,见下节):全新空 `DAITI_HOME` 的首次安装启动失败,`service "dshIm" has been registered at <dsh-im-host>`;当前工作区和已打包的 `@tanweilabs/daiti@0.0.2` 都能复现,原因是 profile 的 `dsh.profile.bundles` 中 `@tanweilabs/daiti-im` 排在 `@xmanrui/dsh-im` 之前。手工把 `@xmanrui/dsh-im` 提前后同一目录可正常启动,本功能的验收就是在该顺序下完成的。
|
|
57
|
+
|
|
58
|
+
## 2026-09-21 新装启动修复与 Agent Team 开启(0.0.3)
|
|
59
|
+
|
|
60
|
+
- 修复新装崩溃:`lib/cli.mjs` 的 `setup()` 现在把 profile 的 `dsh.profile.bundles` 规范成固定顺序(`dsh-base`、`dsh-web-app`、`@xmanrui/dsh-im`、Agent Team 两层、`daiti-loading`、`daiti-preferences`、`daiti-ui`、`daiti-im` 最后)。两个顺序是承重的:上游 IM 必须在适配器之前,Team 层必须在 UI 层之前。未知 bundle 保留原相对位置并排在已知层之后;必需的 IM bundle 解析不到时直接报错,不再静默排出会导致重复注册的顺序。
|
|
61
|
+
- 开启 Agent Team:`setup()` 把 `@deepseek-ai/dsh-experimental-agent-team-profile` 与 `-web-profile` 写进 profile 依赖(版本取自本包依赖树的 `0.1.6-alpha.2`)并执行 `pnpm install --ignore-scripts`,再按上述顺序加入 `bundles`;解析不到时告警并跳过,不阻塞安装。
|
|
62
|
+
- `npm test` 37 项通过(新增 1 项覆盖 bundle 顺序、未知 bundle 保留与必需 bundle 缺失报错);`npm run build` 通过,4 个插件包均为 0.0.3。
|
|
63
|
+
- 全新空 `DAITI_HOME` 端到端验收(`.local/fresh-003`,端口 3095):首次安装完成、服务就绪,`service.log` 无 `has been registered` 失败;profile 顺序为 `dsh-base → dsh-web-app → @xmanrui/dsh-im → agent-team-profile → agent-team-web-profile → daiti-ui → daiti-im`;5 个 `@deepseek-ai/dsh-experimental-*` 包已装入 profile 的 `node_modules`。
|
|
64
|
+
- `--dump-config` 确认:base 的四个子代理工具行已 `disabled: true`,Team 层 `agent-team` 与 `tool-agent-team` 行已插入。
|
|
65
|
+
- 未验证(发布前已知):真实的浏览器会话里 Team 工具是否按预期出现;"标准模式"预设内自带的子代理工具行不受 profile patch 影响,可能与 Team 的 `list_agents`/`send_message` 同名共存(参数不同),需要真实会话验收;Team 策略会引导 Lead 使用 `wait_agent`(10s–1h),是否加重主会话阻塞待观察。
|
|
66
|
+
|
|
67
|
+
## 2026-09-21 自动端口选择(0.0.2)
|
package/lib/cli.mjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
|
2
|
-
import { spawn } from 'node:child_process';
|
|
2
|
+
import { spawn, execFile } from 'node:child_process';
|
|
3
3
|
import { createRequire } from 'node:module';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { randomBytes } from 'node:crypto';
|
|
8
|
+
import { promisify } from 'node:util';
|
|
8
9
|
import { selectPort } from './ports.mjs';
|
|
9
10
|
export const root = fileURLToPath(new URL('../', import.meta.url));
|
|
10
11
|
export const pause = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
@@ -47,6 +48,50 @@ function run(args, p) {
|
|
|
47
48
|
child.once('error', reject); child.once('exit', code => code === 0 ? resolve() : reject(new Error(`Harness setup exited ${code}`)));
|
|
48
49
|
});
|
|
49
50
|
}
|
|
51
|
+
const execFileAsync = promisify(execFile);
|
|
52
|
+
/** Team runs on the experimental Agent Team profile plus its Web panel, in that order. */
|
|
53
|
+
const teamBundles = ['@deepseek-ai/dsh-experimental-agent-team-profile', '@deepseek-ai/dsh-experimental-agent-team-web-profile'];
|
|
54
|
+
/** The Team layer must sit on the IM bundles; the adapter last so its disable wins. */
|
|
55
|
+
const bundleOrder = ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-web-app', '@xmanrui/dsh-im', ...teamBundles, '@tanweilabs/daiti-loading', '@tanweilabs/daiti-preferences', '@tanweilabs/daiti-ui'];
|
|
56
|
+
/**
|
|
57
|
+
* Order the profile's bundle layers so each patch applies on the layer it targets.
|
|
58
|
+
*
|
|
59
|
+
* Two orderings are load-bearing. `@xmanrui/dsh-im` must precede
|
|
60
|
+
* `@tanweilabs/daiti-im`, because the adapter disables the upstream IM entry it
|
|
61
|
+
* replaces; reversed, both register the `dshIm` service and the profile fails to
|
|
62
|
+
* load. The Agent Team layer must precede the UI layer, which patches rows the
|
|
63
|
+
* Team layer installs. Unknown bundles keep their relative position at the end.
|
|
64
|
+
*/
|
|
65
|
+
export function orderedBundles(bundles, available = () => true) {
|
|
66
|
+
const unique = [...new Set(bundles)];
|
|
67
|
+
for (const name of ['@xmanrui/dsh-im', '@tanweilabs/daiti-im']) {
|
|
68
|
+
if (unique.includes(name) && !available(name)) throw new Error(`Profile bundle ${name} is unavailable; run npm ci.`);
|
|
69
|
+
}
|
|
70
|
+
const known = bundleOrder.filter(name => unique.includes(name) && available(name));
|
|
71
|
+
if (known.includes('@xmanrui/dsh-im') && known.includes('@tanweilabs/daiti-im') && known.indexOf('@xmanrui/dsh-im') > known.indexOf('@tanweilabs/daiti-im')) throw new Error('Profile bundle order would register the IM service twice.');
|
|
72
|
+
return [...known, ...unique.filter(name => !bundleOrder.includes(name))];
|
|
73
|
+
}
|
|
74
|
+
async function pinTeamBundles(profile) {
|
|
75
|
+
const require = createRequire(path.join(root, 'package.json'));
|
|
76
|
+
const versions = {};
|
|
77
|
+
for (const name of teamBundles) {
|
|
78
|
+
try { versions[name] = JSON.parse(await fs.readFile(require.resolve(`${name}/package.json`), 'utf8')).version; }
|
|
79
|
+
catch { return { pinned: false, reason: `cannot resolve ${name}; install dependencies with npm ci` }; }
|
|
80
|
+
}
|
|
81
|
+
const manifestPath = path.join(profile, 'package.json');
|
|
82
|
+
const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
|
|
83
|
+
const dependencies = { ...manifest.dependencies };
|
|
84
|
+
let changed = false;
|
|
85
|
+
for (const [name, version] of Object.entries(versions)) {
|
|
86
|
+
if (dependencies[name] !== version) { dependencies[name] = version; changed = true; }
|
|
87
|
+
}
|
|
88
|
+
if (!changed) return { pinned: true, changed: false };
|
|
89
|
+
manifest.dependencies = dependencies;
|
|
90
|
+
await atomicJson(manifestPath, manifest);
|
|
91
|
+
// `install` runs after `shrinkwrap` in the official plugin command, so mirror both.
|
|
92
|
+
await execFileAsync('pnpm', ['install', '--ignore-scripts'], { cwd: profile, env: { ...process.env, PATH: runtimePath() } });
|
|
93
|
+
return { pinned: true, changed: true };
|
|
94
|
+
}
|
|
50
95
|
export async function control(state, action = 'status') {
|
|
51
96
|
if (!state) return null;
|
|
52
97
|
try {
|
|
@@ -79,6 +124,10 @@ export async function setup(p) {
|
|
|
79
124
|
const profileData=await readJson(profileManifest);
|
|
80
125
|
const bundles=profileData.dsh.profile.bundles;
|
|
81
126
|
for(const plugin of manifest.plugins)if(!bundles.includes(plugin.name))bundles.push(plugin.name);
|
|
127
|
+
const team=await pinTeamBundles(profile);
|
|
128
|
+
if(team.pinned){for(const name of teamBundles)if(!bundles.includes(name))bundles.push(name);}
|
|
129
|
+
else console.warn(`Agent Team unavailable: ${team.reason}. Starting without Team tools.`);
|
|
130
|
+
profileData.dsh.profile.bundles=orderedBundles(bundles,name=>{try{createRequire(path.join(profile,'package.json')).resolve(`${name}/package.json`);return true;}catch{return false;}});
|
|
82
131
|
await atomicJson(profileManifest,profileData);
|
|
83
132
|
const patch = path.join(profile, 'cordis.patch.yml');
|
|
84
133
|
try { await fs.copyFile(patch, `${patch}.before-daiti-${Date.now()}`); } catch (e) { if (e.code !== 'ENOENT') throw e; }
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanweilabs/daiti",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@tanweilabs/daiti",
|
|
9
|
-
"version": "0.0.
|
|
9
|
+
"version": "0.0.3",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@deepseek-ai/dsh": "0.1.6-alpha.2",
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|