dsh-agent-persona 0.1.4 → 0.1.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/CHANGELOG.md CHANGED
@@ -4,6 +4,29 @@ All notable changes to this project are documented here.
4
4
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.1.5] - 2026-10-20
8
+
9
+ ### Changed
10
+
11
+ - **适配最新版 DSH `0.2.1-rc.2`。** 在 0.2.1-rc.2 上实测通过:设置页的人设列表、新建、保存
12
+ (`listPersonas` / `savePersona`,正文按 `MAX_TEXT_BYTES` 的 64 KiB 上限测了 6 KB 长文)与
13
+ system prompt 注入都正常;0.1.4 为 0.2.0-rc.2 补的 strict codec 契约(`create`/`decode`/`encode`)
14
+ 与图标命名在 0.2.1-rc.2 上没有变化,所以那次适配继续有效。
15
+ `dsh.compatibility.dshReleases` 补上 `0.2.1-rc.2`(与 `0.1.5-rc.1`、`0.1.5-rc.2`、`0.2.0-rc.2`
16
+ 并列 `compatible`);宿主代码并不读取这个字段,它服务于插件市场/商店的版本提示,补上是为了让
17
+ "跑过哪些版本"与事实一致。
18
+ - 宿主对**每一个**工具调用都会跑 `tools.guard`(0.2.1-rc.2 上实测 `compress` 也被拦),于是下面那条
19
+ 守卫的误判从"偶尔"变成"常态"。
20
+
21
+ ### Fixed
22
+
23
+ - **只读工具不再因为参数里出现人设存储路径而被拒绝。** `personaStoreGuardReason` 原来只看参数里有没有那个
24
+ 路径,于是 `read`、`grep`、`compress` 这类根本不能改写存储的调用也会被拒绝,并回一条"工具不能写入或删除它",
25
+ 等于让会话连解释这个文件都做不到(同一个会话里 `compress` 就被挡过一次)。现在按工具名判断写意图:
26
+ `write`/`edit`/`multiedit`/`apply_patch` 等"参数即目标路径"的工具,路径指向存储才拒绝;`bash`/`pwsh`
27
+ 等命令类工具仍要求同一个字符串里同时出现写特征(`rm`、`>`、`cp` 等);其余只读工具一律放行。
28
+ 存储保护本身没有放松:直接写存储、命令里删/覆盖存储,仍然照旧拒绝。
29
+
7
30
  ## [0.1.4] - 2026-10-08
8
31
 
9
32
  ### Fixed
package/README.md CHANGED
@@ -51,9 +51,9 @@ DSH 会把工作区指令(`AGENTS.md` 之类)变成一条 **user 角色**的
51
51
 
52
52
  ## 装
53
53
 
54
- **实测过的 DSH 版本:`0.1.5-rc.1`(作者的开发环境)与 `0.1.5-rc.2`。** `package.json` 的 `dsh.compatibility`
55
- 声明的就是这两项 —— 含义是"我们在这些版本上跑过",**不是**对更早或更新版本做过兼容工作的承诺;
56
- 其它版本请自行验证。
54
+ **实测过的 DSH 版本:`0.1.5-rc.1`(作者的开发环境)、`0.1.5-rc.2`、`0.2.0-rc.2` 与最新版
55
+ `0.2.1-rc.2`。** `package.json` 的 `dsh.compatibility` 声明的就是这四项 —— 含义是"我们在这些版本上跑过",
56
+ **不是**对更早或更新版本做过兼容工作的承诺;其它版本请自行验证。
57
57
 
58
58
  侧边栏卡片还需要 **`dsh-better-sidebar`**:没装它时,「注册到 dsh-better-sidebar」这个开关不会出现
59
59
  (没有可注册的地方),插件其余功能照常。
package/README_EN.md CHANGED
@@ -61,9 +61,9 @@ workspace cannot touch this layer.
61
61
 
62
62
  ## Install
63
63
 
64
- **Tested against DSH `0.1.5-rc.1` (the author's development environment) and `0.1.5-rc.2`.** That is what
65
- `package.json`'s `dsh.compatibility` declares — it means "we ran on these", not a promise of compatibility work
66
- for older or newer releases; please verify on yours.
64
+ **Tested against DSH `0.1.5-rc.1` (the author's development environment), `0.1.5-rc.2`, `0.2.0-rc.2` and
65
+ the current `0.2.1-rc.2`.** That is what `package.json`'s `dsh.compatibility` declares — it means "we ran on
66
+ these", not a promise of compatibility work for older or newer releases; please verify on yours.
67
67
 
68
68
  The sidebar card additionally needs **`dsh-better-sidebar`**: without it the `注册到 dsh-better-sidebar` switch is not
69
69
  shown at all (there is nothing to register into), and everything else works as usual.
package/lib/index.js CHANGED
@@ -221,6 +221,10 @@ export const backupStoreFile = (storePath, stamp) => {
221
221
  /** Write features that turn "mentions the store" into "writes the store" inside one shell command. */
222
222
  const STORE_WRITE_MARKERS = ['>', 'rm ', 'rm\t', 'mv ', 'cp ', 'chmod', 'chflags', 'truncate', 'sed -i', 'tee ', 'write(', 'unlink(', 'rename('];
223
223
  const STORE_REFUSAL = '人设存储由 agent-persona 插件管理:工具不能写入或删除它。需要修改人设时,请让用户在「设置 → Agent 人设」里操作。';
224
+ /** Tools whose own arguments name the file they write, so a store path in them is the target. */
225
+ const STORE_PATH_TOOLS = new Set(['write', 'edit', 'multiedit', 'apply_patch', 'create_file', 'delete_file', 'move_file']);
226
+ /** Tools that run a command line, where the store only matters next to a write feature. */
227
+ const STORE_SHELL_TOOLS = new Set(['bash', 'pwsh', 'shell', 'exec', 'terminal', 'run_command']);
224
228
  /** Every string nested anywhere in a tool call's arguments, to a bounded depth. */
225
229
  const stringsIn = (value, out = [], depth = 0) => {
226
230
  if (depth > 6 || value === null || value === undefined)
@@ -251,23 +255,32 @@ const stringsIn = (value, out = [], depth = 0) => {
251
255
  * whole command, so a read and a write of the store in one line is refused as a unit.
252
256
  */
253
257
  export const personaStoreGuardReason = (execution, storePath) => {
258
+ const name = String(execution?.name ?? '');
259
+ const shell = STORE_SHELL_TOOLS.has(name);
260
+ // A read-only call cannot rewrite the store, so a path that merely appears in its arguments is not a
261
+ // write. Refusing those (`read`, `grep`, `compress`, ...) turned the guard into a trap for honest work:
262
+ // any tool whose arguments quoted the store path was denied with a message about writing it.
263
+ if (!shell && !STORE_PATH_TOOLS.has(name))
264
+ return undefined;
254
265
  const values = stringsIn(execution?.arguments);
255
266
  const target = resolve(storePath);
256
- if (values.some((value) => {
267
+ const base = basename(storePath);
268
+ const dir = dirname(storePath);
269
+ const pointsAtStore = values.some((value) => {
257
270
  try {
258
271
  return resolve(value) === target;
259
272
  }
260
273
  catch {
261
274
  return false;
262
275
  }
263
- }))
264
- return STORE_REFUSAL;
265
- const base = basename(storePath);
266
- const dir = dirname(storePath);
267
- if (values.some((value) => (value.includes(base) || value.includes(dir))
268
- && STORE_WRITE_MARKERS.some((marker) => value.includes(marker))))
269
- return STORE_REFUSAL;
270
- return undefined;
276
+ });
277
+ const nearStore = values.some((value) => value.includes(base) || value.includes(dir));
278
+ const writes = values.some((value) => STORE_WRITE_MARKERS.some((marker) => value.includes(marker)));
279
+ // A tool that names its own target writes exactly what it points at; a shell command has to mention a
280
+ // write feature before the path inside it counts.
281
+ if (shell)
282
+ return nearStore && writes ? STORE_REFUSAL : undefined;
283
+ return pointsAtStore || (nearStore && writes) ? STORE_REFUSAL : undefined;
271
284
  };
272
285
  export const sanitizePersona = (text, warn = () => { }) => {
273
286
  const dropped = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-agent-persona",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Workspace personas for DeepSeek Harness (DSH): create many system-prompt personas and scope each one by workspace path or session id (exact / prefix / regex / contains), managed from a Web settings page with Markdown editing and AI tuning.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -82,7 +82,8 @@
82
82
  "dshReleases": {
83
83
  "0.1.5-rc.1": "compatible",
84
84
  "0.1.5-rc.2": "compatible",
85
- "0.2.0-rc.2": "compatible"
85
+ "0.2.0-rc.2": "compatible",
86
+ "0.2.1-rc.2": "compatible"
86
87
  }
87
88
  }
88
89
  },