dsh-managed-agent 0.1.1 → 0.2.1

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.
Files changed (3) hide show
  1. package/README.md +71 -124
  2. package/package.json +10 -19
  3. package/LICENSE +0 -21
package/README.md CHANGED
@@ -1,72 +1,48 @@
1
- # dsh-managed-agent
1
+ # dsh-managed-agent —— 受管设备代理(M2)
2
2
 
3
- [![CI](https://github.com/tableau-China/dsh-managed-agent/actions/workflows/ci.yml/badge.svg)](https://github.com/tableau-China/dsh-managed-agent/actions/workflows/ci.yml)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
3
+ > 员工机上唯一的受管插件。它把「这台机器是什么状态」报给集中管理平台,
4
+ > 并在本地提供一个**只读**状态页。
5
+ >
6
+ > **已发布**:<https://github.com/tableau-China/dsh-managed-agent>(当前 v0.2.1,MIT)。
7
+ > 本目录是**源码主本**(含集成测试与市场打包);GitHub 仓库是发布快照。
8
+ > 平台侧设计见 [集中管理平台方案设计](../../docs/集中管理平台方案设计.md) §7;
9
+ > 版本进度见 [实施进度](../../docs/集中管理平台-实施进度.md)。
5
10
 
6
- > DeepSeek Harness(DSH)受管设备代理插件。
7
- > 把「这台机器在不在管、配置有没有被改、版本是不是落后」变成平台侧可见的事实,
8
- > 并在本机提供一个**只读**状态页。
9
-
10
- 配套的管理平台(人员 / 设备 / 注册码 / 用量 / 模型授权 / 审计)是独立服务端,不在本仓库。
11
- 本插件只依赖平台的两个 HTTP 接口,契约见下文,可对接任何同契约实现。
12
-
13
- - 零运行时依赖(只用 Node 内置模块)
14
- - 只上报**事实与计数**:不上报提示词、回复、文件内容、工具参数、工作区路径
15
- - 采集是**旁路**:任何异常只记日志,绝不影响会话
16
- - 本机只读:不提供任何修改配置或管理他人的入口
17
-
18
- ---
19
-
20
- ## 它做什么(四件事)
11
+ ## 它做什么(四件事,全是旁路)
21
12
 
22
13
  | # | 行为 | 说明 |
23
14
  |---|---|---|
24
- | 1 | 读设备凭据 | `~/.dsh/managed-agent.json`(0600),由平台的注册流程下发 |
25
- | 2 | 周期上报**事实** | DSH 版本、profile patch 指纹、插件清单、机器名 |
15
+ | 1 | 读设备凭据 | `~/.dsh/managed-agent.json`(`node admin/enroll.mjs` 生成,0600) |
16
+ | 2 | 周期上报**事实** | DSH 版本、patch 指纹、插件清单、机器名 |
26
17
  | 3 | 按平台返回处理状态 | `pending` 待审批 / `revoked` 已吊销 / `401` 凭据失效 / 网络不可达 |
27
18
  | 4 | 本地只读状态页 | `/managed-agent/v1/`(挂在 DSH 自带 WebServer 上,受浏览器门禁保护) |
28
19
 
29
- **绝不做的事**:不上报提示词、回复、文件内容、工具参数、工作区路径;
30
- 不在本机判定合规(判定权在平台,见下文);不提供任何写入口。
20
+ **绝不做的事**:不上报提示词、回复、文件内容、工具参数、工作区路径;不提供任何修改入口;
21
+ 不在本机判定合规(判定权在服务端,见下文)。
31
22
 
32
- ## 安装
33
-
34
- 插件以 DSH bundle 形式分发(`dsh.bundle.patch`),三种装法任选:
23
+ ## 安装(员工机)
35
24
 
36
25
  ```bash
37
- # 方式一:本地 link(开发/内网 tgz 分发均可)
38
- # 1) 放进 profile 的依赖
39
- # "dsh-managed-agent": "link:/path/to/dsh-managed-agent"
40
- # 2) 加进 profile 的 dsh.profile.bundles 列表
41
- # 3) 建软链:ln -s /path/to/dsh-managed-agent ~/.dsh/profiles/<profile>/node_modules/dsh-managed-agent
42
-
43
- # 方式二:从企业插件市场索引安装(DSH 官方 Discover 页)
44
- # profile 的 cordis.patch.yml 里配置内网索引:
45
- # - id: plugin-market
46
- # config:
47
- # indexes: ["http://dsh-admin.intra/api/v1/market/index.json"]
48
-
49
- # 方式三:直接从 GitHub Release 下载 tgz(不需要 npm 账号)
50
- curl -LO https://github.com/tableau-China/dsh-managed-agent/releases/download/v0.1.1/dsh-managed-agent-0.1.1.tgz
51
- # 然后在 profile 里 npm install /path/to/dsh-managed-agent-0.1.1.tgz
26
+ # 1) 把插件放进 profile(内网 npm 源或本地 tgz,M8 才做市场索引)
27
+ # 在 <DSH_HOME>/profiles/<profile>/package.json 的 dependencies 加:
28
+ # "dsh-managed-agent": "link:/path/to/dsh_enterprise_suite/plugins/dsh-managed-agent"
29
+ # 并在 dsh.profile.bundles 里追加 "dsh-managed-agent"
30
+
31
+ # 2) 让 Loader 插入插件(cordis.patch.yml)
32
+ - insert:
33
+ - id: managed-agent
34
+ name: dsh-managed-agent
35
+ config:
36
+ enabled: true
37
+ heartbeatMinutes: 15
38
+
39
+ # 3) 注册本机(拿到设备令牌)
40
+ node admin/enroll.mjs --platform https://dsh-admin.intra
41
+
42
+ # 4) 重启 DSH;状态页:http://127.0.0.1:<dsh 端口>/managed-agent/v1/
52
43
  ```
53
44
 
54
- > 公共 npm 上暂未发布(`npm publish` 需要维护者账号)。内网部署推荐用企业插件市场索引
55
- > 或上面的 tgz;对外开源用户也可以先下载 Release 里的 tgz。
56
-
57
- 装好后重启 DSH,插件会在启动时上报一次,之后按 `heartbeatMinutes` 周期上报。
58
-
59
- ## 配置
60
-
61
- 在 profile 的 `cordis.patch.yml` 里按 id 覆盖:
62
-
63
- ```yaml
64
- - id: managed-agent
65
- name: dsh-managed-agent
66
- config:
67
- enabled: true
68
- heartbeatMinutes: 15
69
- ```
45
+ ## 配置项
70
46
 
71
47
  | 键 | 默认 | 说明 |
72
48
  |---|---|---|
@@ -77,7 +53,7 @@ curl -LO https://github.com/tableau-China/dsh-managed-agent/releases/download/v0
77
53
  | `patchFile` | `''` | 指纹来源;留空用 `<DSH_HOME>/profiles/<profile>/cordis.patch.yml` |
78
54
  | `profile` | `desktop` | profile 名 |
79
55
  | `machineLabel` | hostname | 机器显示名 |
80
- | `dshVersion` | 自动 | 版本号;留空依次尝试宿主服务 → 环境变量 → `<DSH_HOME>/app-version` |
56
+ | `dshVersion` | 自动 | 版本号;留空依次尝试宿主服务 → 环境变量 → `<DSH_HOME>/app-version` 文件 |
81
57
  | `statusPath` | `/managed-agent/v1` | 本地只读状态页前缀 |
82
58
  | `timeoutMs` | `10000` | 单次请求超时 |
83
59
 
@@ -96,70 +72,53 @@ DSH 插件列表里显示"异常"。官方插件(如 `@deepseek-ai/dsh-session
96
72
 
97
73
  所以本插件把默认值与范围约束放在内部的 `normalizeConfig()`,在 `apply` 里先归一化再使用。
98
74
 
99
- ## 与平台的契约
100
-
101
- ### 1. 设备凭据文件(`<DSH_HOME>/managed-agent.json`,0600)
102
-
103
- ```jsonc
104
- {
105
- "schema": 1,
106
- "endpoint": "https://dsh-admin.intra/api/v1", // 必须带 API 前缀
107
- "machineId": "9f3c1a2b-…", // 本机安装 UUID
108
- "machineLabel": "dev-zhang.mbp",
109
- "employee": "EMP0042",
110
- "deviceToken": "dshdev-…", // 平台签发的设备令牌
111
- "status": "active"
112
- }
113
- ```
114
-
115
- > 老凭据若 `endpoint` 没有 `/api/v1`,插件会自动补齐(避免"凭据有效但一直 offline")。
75
+ ## 两个约定(踩过坑,写下来)
116
76
 
117
- ### 2. 心跳
77
+ 1. **`endpoint` 必须带 API 前缀**(`http://host:8788/api/v1`)。插件按 `${endpoint}/heartbeat` 拼地址;
78
+ 老凭据若没有 `/api/v1`,插件会自动补齐(避免"凭据有效但一直 offline")。
79
+ 2. **DSH 版本从 `<DSH_HOME>/app-version` 读**。官方没有稳定的版本服务,所以由部署脚本
80
+ (`deploy/install.mjs`)在安装时写入;读不到就报 `unknown`,平台不会因此误判"版本落后"。
118
81
 
119
- ```http
120
- POST {endpoint}/heartbeat
121
- Authorization: Bearer <deviceToken>
122
- Content-Type: application/json
82
+ ## 上报内容(可审计清单)
123
83
 
84
+ ```jsonc
124
85
  {
125
86
  "schema": 1,
126
87
  "kind": "dsh-managed-agent/heartbeat",
127
88
  "machineLabel": "dev-zhang.mbp",
128
89
  "dshVersion": "0.2.1-rc.3",
129
- "patchFingerprint": "sha256:…",
130
- "plugins": [{ "name": "dsh-managed-agent", "version": "0.1.0" }],
90
+ "patchFingerprint": "sha256:…", // profile 的 cordis.patch.yml 内容哈希
91
+ "plugins": [{ "name": "dsh-managed-agent", "version": "0.2.1" }],
131
92
  "reportedAt": "2026-10-28T…Z"
132
93
  }
133
94
  ```
134
95
 
135
- 平台返回:
96
+ **没有**工作区路径、会话 id、提示词、回复、文件内容、凭据。这一点有测试守着
97
+ (`test/verify.mjs` 里有一条断言:payload 不含 `cwd/prompt/content/workspace`)。
136
98
 
137
- ```jsonc
138
- { "ok": true, "status": "active", "employee": "EMP0042", "compliance": "ok" }
139
- ```
99
+ ## 合规判定为什么在服务端
140
100
 
141
- | 平台返回 | 插件行为 |
142
- |---|---|
143
- | `200` | 记 `ok`,清空待发快照 |
144
- | `403 {"error":"pending"}` | 记 `pending`,**不清凭据**(批准后自动恢复) |
145
- | `403 {"error":"revoked"}` | **清除本地令牌**(文件保留工号/机器信息用于展示),停止上报 |
146
- | `401` | 记 `unauthorized`,保留待发,提示重新注册 |
147
- | 其它 / 网络不可达 | 记 `offline`,把**最新一份**心跳写入 `managed-agent-pending.json`,下周期补发 |
101
+ | 现象 | 谁判定 | 依据 |
102
+ |---|---|---|
103
+ | `ok` | 平台 | 指纹与基线一致、版本达标 |
104
+ | `drifted` | 平台 | 指纹 ≠ 基线(基线=平台统一值,或该设备首次心跳) |
105
+ | `outdated` | 平台 | `dshVersion` < `settings.compliance.minDshVersion` |
106
+ | `revoked` | 平台 | 设备被吊销(离职/手工撤销) |
148
107
 
149
- > 为什么只保留最新一份、而不是事件队列:心跳是**状态快照**,不是事件流。
150
- > 重放三小时前的快照只会把 `lastSeenAt` 写成过去时,让平台误判"这台机器三小时前还活着"。
108
+ 插件只把平台返回的 `compliance` **原样展示**。理由:客户端能改,客户端永远不是判定方。
109
+ 这是方案 §10「patch 漂移可被发现(发现≠阻止,是证据不是边界)」的落地方式。
151
110
 
152
- ## 合规判定为什么在平台侧
111
+ ## 失败与恢复
153
112
 
154
- | 结果 | 判定依据(平台) |
113
+ | 情况 | 行为 |
155
114
  |---|---|
156
- | `ok` | 指纹与基线一致、版本达标 |
157
- | `drifted` | 指纹 ≠ 基线(基线 = 平台统一值,或该设备首次心跳) |
158
- | `outdated` | `dshVersion` < 平台要求的最低版本 |
159
- | `revoked` | 设备被吊销 |
115
+ | 平台不可达 / 5xx | 记 `offline`,把**最新一份**心跳写入 `managed-agent-pending.json`,下个周期补发 |
116
+ | 401 凭据失效 | 记 `unauthorized`,保留待发,提示重新注册 |
117
+ | 403 `pending` | 记 `pending`,**不清凭据**(批准后自动恢复) |
118
+ | 403 `revoked` | 清除本地令牌(文件保留工号/机器信息用于展示),停止上报,提示联系平台组 |
160
119
 
161
- 插件只把平台返回的 `compliance` **原样展示**。理由:客户端能改,客户端永远不是判定方。
162
- 这是"配置漂移可被发现(发现≠阻止,是证据不是边界)"的落地方式。
120
+ **为什么只保留最新一份心跳、而不是事件队列**:心跳是状态快照,不是事件流。
121
+ 重放三小时前的快照只会把 `lastSeenAt` 写成过去时,让平台误判这台机器"三小时前还活着"。
163
122
 
164
123
  ## 本地状态页
165
124
 
@@ -168,34 +127,22 @@ Content-Type: application/json
168
127
  - 其它方法 → `405 read-only`
169
128
 
170
129
  显示:工号、机器 ID、平台地址、最后上报时间、上报结果、合规状态、DSH 版本、
171
- patch 指纹前 23 位、插件数、待发心跳。**没有**任何修改入口。
130
+ patch 指纹前 23 位、插件数、待发心跳。**没有**任何修改入口(插件不是管控点)。
172
131
 
173
132
  ## 自检
174
133
 
175
134
  ```bash
176
- node test/verify.mjs # 25 项单元检查,不需要 DSH、不需要平台、不需要外网
177
- ```
178
-
179
- 可选集成检查(连真实平台跑一次心跳):
180
-
181
- ```bash
182
- MANAGED_AGENT_PLATFORM=http://127.0.0.1:8788/api/v1 \
183
- MANAGED_AGENT_TOKEN=dshdev-… \
184
- node test/verify.mjs
135
+ node plugins/dsh-managed-agent/test/verify.mjs
185
136
  ```
186
137
 
187
- CI 在 Node 22 / 24 上跑单元检查(见 `.github/workflows/ci.yml`)。
138
+ 34 项:单元(假宿主/假 fetch:采集内容、失败重放、pending/revoked/401 处理、状态页只读、
139
+ `apply` 路由与清理)+ 集成(真实服务端起注册与心跳,验证 **改坏 patch → 平台判 drifted**、
140
+ 版本落后 → outdated、恢复 → ok、合规变化进审计、离职 → 插件清凭据)。
188
141
 
189
- ## 已知限制
142
+ ## 已知限制(M2 范围)
190
143
 
191
- 1. **没有 React 设置页**:状态页由宿主直接输出 HTML(零构建、零依赖)。
192
- 要做进 DSH 设置界面需要 `dsh.client` + 前端打包,属后续版本。
144
+ 1. **没有 React 客户端设置页**:状态页由宿主直接提供 HTML(零构建、零依赖)。
145
+ 若要做进 DSH 设置界面,需要 `dsh.client` + esbuild 打包 React 组件(后续版本)。
193
146
  2. **插件清单**取 profile 的 `bundles + dependencies` 元数据,不是运行时加载器快照。
194
- 3. **不含用量**:用量由另一条采集通道负责(`dsh-usage-telemetry`),本插件只报状态。
195
- 4. 待审批 / 吊销的提示只写日志与状态页,未做桌面通知。
196
- 5. DSH 没有稳定的版本服务,`dshVersion` 依赖部署脚本写入 `<DSH_HOME>/app-version`;
197
- 读不到时报 `unknown`,平台不会因此误判"版本落后"。
198
-
199
- ## License
200
-
201
- MIT © XILEJUN
147
+ 3. **上报不含用量**:用量是 M3 的事,且由 `dsh-usage-telemetry` 走另一条通道。
148
+ 4. 待审批/吊销的提示只写日志与状态页,未做桌面通知。
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-managed-agent",
3
- "version": "0.1.1",
4
- "description": "受管设备代理(DSH 插件):读取本机设备凭据,周期上报 DSH 版本 / patch 指纹 / 插件清单,并提供本地只读状态页。只上报状态与计数,不上报提示词、回复、文件内容或凭据。",
3
+ "version": "0.2.1",
4
+ "description": "受管设备代理:读取本机设备凭据,周期上报 DSH 版本 / patch 指纹 / 插件清单,并提供本地只读状态页。只上报状态与计数,不上报提示词、回复、文件内容或凭据。",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "exports": {
@@ -11,8 +11,7 @@
11
11
  "files": [
12
12
  "index.js",
13
13
  "cordis.patch.yml",
14
- "README.md",
15
- "LICENSE"
14
+ "README.md"
16
15
  ],
17
16
  "engines": {
18
17
  "node": ">=22"
@@ -23,22 +22,9 @@
23
22
  "plugin",
24
23
  "managed",
25
24
  "compliance",
26
- "heartbeat",
27
- "device"
25
+ "heartbeat"
28
26
  ],
29
- "author": "XILEJUN (https://github.com/tableau-China)",
30
27
  "license": "MIT",
31
- "repository": {
32
- "type": "git",
33
- "url": "git+https://github.com/tableau-China/dsh-managed-agent.git"
34
- },
35
- "homepage": "https://github.com/tableau-China/dsh-managed-agent#readme",
36
- "bugs": {
37
- "url": "https://github.com/tableau-China/dsh-managed-agent/issues"
38
- },
39
- "scripts": {
40
- "test": "node test/verify.mjs"
41
- },
42
28
  "dsh": {
43
29
  "bundle": {
44
30
  "patch": "./cordis.patch.yml"
@@ -46,5 +32,10 @@
46
32
  },
47
33
  "peerDependencies": {
48
34
  "@deepseek-ai/cordis": "^4.0.1"
49
- }
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/tableau-China/dsh-managed-agent.git"
39
+ },
40
+ "homepage": "https://github.com/tableau-China/dsh-managed-agent#readme"
50
41
  }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 XILEJUN (https://github.com/tableau-China)
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.