@sparkelf/dsh-knowledge-base 0.0.0-stage → 0.1.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 (67) hide show
  1. package/LICENSE +21 -0
  2. package/SKILL.md +147 -0
  3. package/cordis.patch.yml +5 -0
  4. package/i18n/zh.json +10 -0
  5. package/lib/client.js +18308 -0
  6. package/lib/client.js.map +1 -0
  7. package/lib/index.js +6005 -0
  8. package/lib/types/api.d.ts +620 -0
  9. package/lib/types/client/KnowledgeAudit.d.ts +39 -0
  10. package/lib/types/client/KnowledgeContextMenu.d.ts +121 -0
  11. package/lib/types/client/KnowledgeCreateDialog.d.ts +134 -0
  12. package/lib/types/client/KnowledgeFileTree.d.ts +117 -0
  13. package/lib/types/client/KnowledgeHome.d.ts +102 -0
  14. package/lib/types/client/KnowledgeIndexing.d.ts +60 -0
  15. package/lib/types/client/KnowledgeListing.d.ts +174 -0
  16. package/lib/types/client/KnowledgeLoading.d.ts +41 -0
  17. package/lib/types/client/KnowledgeMenuIcon.d.ts +27 -0
  18. package/lib/types/client/KnowledgePanel.d.ts +58 -0
  19. package/lib/types/client/KnowledgePermissionOverview.d.ts +147 -0
  20. package/lib/types/client/KnowledgePermissions.d.ts +47 -0
  21. package/lib/types/client/KnowledgeProgressPanel.d.ts +53 -0
  22. package/lib/types/client/KnowledgeReferencePicker.d.ts +81 -0
  23. package/lib/types/client/KnowledgeSearch.d.ts +83 -0
  24. package/lib/types/client/KnowledgeSectionHeader.d.ts +71 -0
  25. package/lib/types/client/KnowledgeSelectionBar.d.ts +45 -0
  26. package/lib/types/client/KnowledgeSettings.d.ts +96 -0
  27. package/lib/types/client/KnowledgeSettingsSection.d.ts +21 -0
  28. package/lib/types/client/KnowledgeShareDialog.d.ts +70 -0
  29. package/lib/types/client/KnowledgeTemplates.d.ts +43 -0
  30. package/lib/types/client/KnowledgeTrash.d.ts +62 -0
  31. package/lib/types/client/MenuGlyphs.d.ts +37 -0
  32. package/lib/types/client/auditPaging.d.ts +40 -0
  33. package/lib/types/client/departmentFolders.d.ts +57 -0
  34. package/lib/types/client/deployTarget.d.ts +34 -0
  35. package/lib/types/client/index.d.ts +40 -0
  36. package/lib/types/client/insertReadiness.d.ts +60 -0
  37. package/lib/types/client/knowledgeMenuCopy.d.ts +23 -0
  38. package/lib/types/client/locales.d.ts +505 -0
  39. package/lib/types/client/openInSidebar.d.ts +62 -0
  40. package/lib/types/client/ownerLabel.d.ts +39 -0
  41. package/lib/types/client/paging.d.ts +69 -0
  42. package/lib/types/client/permissionRows.d.ts +265 -0
  43. package/lib/types/client/progressRules.d.ts +54 -0
  44. package/lib/types/client/referenceTargets.d.ts +60 -0
  45. package/lib/types/client/roleSummary.d.ts +47 -0
  46. package/lib/types/client/saveAudit.d.ts +87 -0
  47. package/lib/types/client/shareRelations.d.ts +81 -0
  48. package/lib/types/client/useFavorites.d.ts +49 -0
  49. package/lib/types/client/useFileDrop.d.ts +171 -0
  50. package/lib/types/client/useFileDropHook.d.ts +64 -0
  51. package/lib/types/client/usePinnedPaths.d.ts +39 -0
  52. package/lib/types/client/useTreeState.d.ts +46 -0
  53. package/lib/types/client/useViewMode.d.ts +39 -0
  54. package/lib/types/deploy.d.ts +209 -0
  55. package/lib/types/extract.d.ts +144 -0
  56. package/lib/types/extractionQueue.d.ts +154 -0
  57. package/lib/types/index.d.ts +899 -0
  58. package/lib/types/permissions.d.ts +237 -0
  59. package/lib/types/protocol.d.ts +229 -0
  60. package/lib/types/remote.d.ts +105 -0
  61. package/lib/types/trash.d.ts +142 -0
  62. package/lib/types/viewMetadata.d.ts +20 -0
  63. package/lib/types/views.d.ts +923 -0
  64. package/package.json +109 -4
  65. package/skills/kb-organize/SKILL.md +365 -0
  66. package/skills/kb-organize/i18n/zh.json +10 -0
  67. package/README.md +0 -3
package/package.json CHANGED
@@ -1,6 +1,111 @@
1
1
  {
2
2
  "name": "@sparkelf/dsh-knowledge-base",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "DataOps-backed knowledge base for DeepSeek Harness: a left-sidebar destination, Settings configuration, and index tooling over a mounted NAS view.",
5
+ "type": "module",
6
+ "main": "./lib/index.js",
7
+ "types": "./lib/types/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/types/index.d.ts",
11
+ "default": "./lib/index.js"
12
+ },
13
+ "./client": {
14
+ "types": "./lib/types/client/index.d.ts",
15
+ "default": "./lib/client.js"
16
+ },
17
+ "./package.json": "./package.json"
18
+ },
19
+ "dsh": {
20
+ "bundle": {
21
+ "patch": "./cordis.patch.yml"
22
+ },
23
+ "client": {
24
+ "platform": "web",
25
+ "inject": [
26
+ "@deepseek-ai/dsh-client-ui-settings",
27
+ "@deepseek-ai/dsh-client-locale",
28
+ "@deepseek-ai/dsh-client-ui-primitives",
29
+ "@deepseek-ai/dsh-client-ui-slots",
30
+ "@deepseek-ai/dsh-client-ui-renderer",
31
+ "@deepseek-ai/dsh-client-ui-sidebar",
32
+ "@deepseek-ai/dsh-client-ui-layout",
33
+ "@deepseek-ai/dsh-client-ui-session"
34
+ ]
35
+ }
36
+ },
37
+ "files": [
38
+ "lib/index.js",
39
+ "lib/client.js",
40
+ "lib/client.js.map",
41
+ "lib/types/**/*.d.ts",
42
+ "cordis.patch.yml",
43
+ "README.md",
44
+ "LICENSE",
45
+ "SKILL.md",
46
+ "i18n/*.json",
47
+ "skills/**/SKILL.md",
48
+ "skills/**/i18n/*.json"
49
+ ],
50
+ "scripts": {
51
+ "build": "rm -rf lib && tsc -p tsconfig.build.json && tsdown",
52
+ "bundle": "tsdown",
53
+ "prepack": "pnpm run build"
54
+ },
55
+ "engines": {
56
+ "node": "^22.19.0 || >=24.0.0"
57
+ },
58
+ "license": "MIT",
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "git+https://github.com/SparkElf/dsh-plugins-plus.git",
62
+ "directory": "packages/knowledge-base"
63
+ },
64
+ "publishConfig": {
65
+ "access": "public"
66
+ },
67
+ "dependencies": {
68
+ "@deepseek-ai/schemastery": "^3.18.2"
69
+ },
70
+ "peerDependencies": {
71
+ "@deepseek-ai/cordis": "^4.0.4",
72
+ "@deepseek-ai/dsh-client-locale": ">=0.1.7-rc.2",
73
+ "@deepseek-ai/dsh-client-ui-primitives": ">=0.1.7-rc.2",
74
+ "@deepseek-ai/dsh-client-ui-renderer": ">=0.1.7-rc.2",
75
+ "@deepseek-ai/dsh-client-ui-settings": ">=0.1.7-rc.2",
76
+ "@deepseek-ai/dsh-client-ui-slots": ">=0.1.7-rc.2",
77
+ "@deepseek-ai/dsh-credentials": ">=0.1.7-rc.2",
78
+ "@deepseek-ai/dsh-host-webserver": ">=0.1.7-rc.2",
79
+ "@deepseek-ai/dsh-tools": ">=0.1.7-rc.2",
80
+ "react": ">=18.2.0 <20",
81
+ "@deepseek-ai/dsh-client-ui-sidebar": ">=0.2.1-alpha.2",
82
+ "@deepseek-ai/dsh-client-ui-layout": ">=0.2.1-alpha.2",
83
+ "dsh-better-sidebar": ">=0.25.0",
84
+ "@deepseek-ai/dsh-client-ui-session": ">=0.2.1-alpha.2"
85
+ },
86
+ "devDependencies": {
87
+ "@deepseek-ai/cordis": "4.0.4",
88
+ "@deepseek-ai/dsh-client-locale": "0.1.7-rc.2",
89
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.2",
90
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.2",
91
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.7-rc.2",
92
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.2",
93
+ "@deepseek-ai/dsh-credentials": "0.1.7-rc.2",
94
+ "@deepseek-ai/dsh-tools": "0.1.7-rc.2",
95
+ "@types/react": "~18.3.1",
96
+ "jsdom": "^26.1.0",
97
+ "lightningcss": "^1.32.0",
98
+ "react": "^18.2.0",
99
+ "react-dom": "^18.2.0",
100
+ "tsdown": "^0.22.2",
101
+ "@deepseek-ai/dsh-client-ui-sidebar": "0.2.1-alpha.2",
102
+ "@deepseek-ai/dsh-client-ui-layout": "0.2.1-alpha.2",
103
+ "dsh-better-sidebar": "0.25.0",
104
+ "@deepseek-ai/dsh-client-ui-session": "0.2.1-alpha.2"
105
+ },
106
+ "peerDependenciesMeta": {
107
+ "dsh-better-sidebar": {
108
+ "optional": true
109
+ }
110
+ }
111
+ }
@@ -0,0 +1,365 @@
1
+ ---
2
+ name: kb-organize
3
+ description: 整理知识库、归档文档、生成索引、按内容分类归类时使用。适用于「整理一下知识库」「帮我归档」「把这些文档分类归并」「生成目录索引」「建个知识体系」等请求:先读整理偏好,再逐篇读内容理解,按主题建分层文件夹并移动文档,最后为每层写一份层索引 md。缺 md 文本副本的文档会先补索引。
4
+ ---
5
+
6
+ # 知识库整理 — 分层归类与层索引
7
+
8
+ 把一个知识库目录从「一堆平铺的文件」整理成「按主题分层的文件夹 + 每层一份索引 md」。核心是三件事:**读懂每篇文档在讲什么**、**按内容而不是文件名分层**、**每层留一份能被人和模型直接用的索引**。
9
+
10
+ 整理偏好写在 `kb-organize-preferences.md`:工作区那份是权威,个人知识库里的副本是同步产物。
11
+
12
+ ## 一、开始之前:先读偏好,再问两个问题
13
+
14
+ ### 1. 先读既有偏好(必做第一步)
15
+
16
+ ```bash
17
+ cat /workspace/kb-organize-preferences.md 2>/dev/null || echo "NO_PREFERENCES"
18
+ ```
19
+
20
+ 工作区缺失时读个人库副本(换设备时靠它)。
21
+
22
+ **个人库副本的路径有两个形态,别混用**——这是同一个文件,但在两个树里名字不同:
23
+
24
+ | 用途 | 路径形态 | 示例 |
25
+ | --- | --- | --- |
26
+ | **读**(`read` / `list`)= 视图路径 | `personal/<文件名>`,**不带 uid** | `personal/kb-organize-preferences.md` |
27
+ | **写**(`create` / `edit` / `upload`)= 权威路径 | `personal/<uid>/<文件名>`,**必须带 uid** | `personal/260afb31-…/kb-organize-preferences.md` |
28
+
29
+ ```bash
30
+ # 读:视图路径,不带 uid
31
+ curl -sS -X POST http://127.0.0.1:3080/knowledge-base/api/read \
32
+ -H 'content-type: application/json' \
33
+ -d '{"path":"personal/kb-organize-preferences.md"}'
34
+
35
+ # 写:权威路径,必须带 uid(uid 从 status 的 caller.userId 取,见第六节)
36
+ # {"relPath":"personal/<uid>/kb-organize-preferences.md", ...}
37
+ ```
38
+
39
+ **为什么**:视图里的 `personal/` 已经隐去了 uid(一个用户的视图里只可能有自己的文件),所以读侧带上 uid 会 404;而权威树是所有人共用的一棵树,去掉 uid 就会落到 `personal/` 根下,**写入成功但视图里永远看不到**。这两个坑都实测复现过。
40
+
41
+ 工作区文件是权威:两份都存在且不一致时,用工作区那份,并把差异告诉用户。只有工作区缺失时才采用个人库副本。
42
+
43
+ 读到的偏好决定后面怎么建目录:`分类粒度`、`命名语言`、`已有分类` 三栏直接约束你的分层方案。**不要无视既有分类另起一套**,那会让同一个库出现两套并存的分类。
44
+
45
+ ### 2. 问用户两个问题(一次问完,不要逐条追问)
46
+
47
+ > 开始整理前,我先确认两件事:
48
+ >
49
+ > 1. **这批知识有什么背景?** 例如属于哪些业务领域、有没有已知的大类划分、哪些文档必须放在一起、哪些是废弃稿。
50
+ > 2. **分类和命名上有什么偏好?** 例如分几层、用中文还是英文、文件夹名偏好(`涉边偷渡类` 还是 `border-crossing`)、索引文件想不想包含摘要。
51
+
52
+ 用户不答或说「你看着办」时,采用**保守默认**并在结果里说明:
53
+
54
+ | 维度 | 保守默认 |
55
+ | --- | --- |
56
+ | 层数 | 最多两层(一级大类 + 必要时二级子类) |
57
+ | 命名 | 中文、`…类` 或业务名词,不用序号前缀 |
58
+ | 归类依据 | 文档正文主题,不按文件名猜 |
59
+ | 不确定的文档 | 留在 `待归类/`,不硬塞 |
60
+
61
+ 保守默认要写进偏好文件,下次整理就不必再猜。
62
+
63
+ ## 二、摸清现状:找出所有文档与缺失的索引
64
+
65
+ ### 1. 列出要整理的目录
66
+
67
+ `list` 每次只返回一层,要逐层展开:
68
+
69
+ ```bash
70
+ curl -sS -X POST http://127.0.0.1:3080/knowledge-base/api/list \
71
+ -H 'content-type: application/json' \
72
+ -d '{"path":""}'
73
+ ```
74
+
75
+ `path` 用**视图路径**(`global`、`global/子目录`、`personal`、`department`)。省略时列根层,返回三个桶。
76
+
77
+ 返回的 `entries` 里每项有 `relPath`、`name`、`isDir`、`mtimeMs`、`size`。目录项用它的 `relPath` 继续往下列。
78
+
79
+ ### 2. 找出缺 md 文本副本的文档
80
+
81
+ 知识库里 `.md` 是正文本身;`.docx`/`.pdf`/`.xlsx`/`.pptx` 这类原件**上传时**会由插件尝试在旁边生成一份同名 `.md` 副本(`报告.docx` → `报告.docx.md`),检索与阅读都靠它。
82
+
83
+ 判断规则:
84
+
85
+ - 目录里存在 `X.docx` 但**没有** `X.docx.md` → 该文档缺文本副本
86
+ - 缺副本的文档读不出正文,**无法按内容归类**
87
+
88
+ `list` 返回的 `entries` 只给名字,用名字判断即可:原件扩展名是 `.pdf/.doc/.docx/.xls/.xlsx/.ppt/.pptx/.odt/.ods/.odp/.rtf`,且同目录下没有 `原件名.md`,就是缺副本。
89
+
90
+ ### 3. 补文本副本(能补则补,补不了如实记录)
91
+
92
+ **唯一会生成 `.md` 副本的入口是 `upload`**:它写原件后调用抽取器。`kb_index` 工具不生成副本(它只重新统计文件数),**不要指望它**。
93
+
94
+ 补副本 = 用 `upload` 重放同一个原件(同名会覆盖原件、重新触发抽取):
95
+
96
+ ```bash
97
+ # 单文件:先取回原件字节,再以 base64 上传
98
+ python3 -c "
99
+ import base64, json
100
+ data = open('/path/to/local/报告.docx','rb').read()
101
+ print(json.dumps({
102
+ 'relPath': 'global/涉边偷渡类/报告.docx',
103
+ 'encoding': 'base64',
104
+ 'content': base64.b64encode(data).decode(),
105
+ }))" | curl -sS -X POST http://127.0.0.1:3080/knowledge-base/api/upload \
106
+ -H 'content-type: application/json' -d @-
107
+ ```
108
+
109
+ 响应里的 `extraction` 字段说明结果:
110
+
111
+ | `extraction` | 含义 | 下一步 |
112
+ | --- | --- | --- |
113
+ | `{"markdown":"…/报告.docx.md"}` | 补成功 | 重新 `list` 确认副本出现 |
114
+ | `{"markdown":"","reason":"no-extractor-succeeded: …"}` | 抽取器都不可用 | 记入「未归类」,不要重试到死 |
115
+
116
+ **抽取能力取决于部署**:`.pdf` 优先走 MinerU(需要配置 `mineruPort` 且服务在跑),其余格式靠 LibreOffice 或 Python 库。这些都不在时 `reason` 会列出尝试过的抽取器。
117
+
118
+ 补不了副本时**不要卡住整个整理**:把这些文档列进「未归类/」,在最终报告里写清「缺文本副本、当前环境无可用抽取器」。**不要把文件名当内容去猜分类**。
119
+
120
+ 你也可以直接读原件的 `.md` 副本判断内容;如果用户手上就有原文档,让用户重新从界面上传一次是最省事的补法。
121
+
122
+ ## 三、逐篇读内容,归纳主题
123
+
124
+ ### 读一篇文档
125
+
126
+ ```bash
127
+ curl -sS -X POST http://127.0.0.1:3080/knowledge-base/api/read \
128
+ -H 'content-type: application/json' \
129
+ -d '{"path":"global/a.md"}'
130
+ ```
131
+
132
+ 返回 `{"kind":"text","content":"…","truncated":false,"mtimeMs":…}`。`truncated` 为 true 表示只读到前一段,需要换更窄的范围或按小节读。
133
+
134
+ ### 读的时候记什么
135
+
136
+ 每篇至少提炼三样,写进后面的索引:
137
+
138
+ 1. **一句话主题** —— 这篇在讲什么,10-30 字
139
+ 2. **归属大类** —— 落到哪个主题(`涉边偷渡类`、`经济犯罪类`、`队伍管理类`…)
140
+ 3. **可复用的辨别信息** —— 文种(方案/通报/台账/讲话稿)、时间、涉及单位
141
+
142
+ **必须读正文再分类。** 文件名经常不准确(`通知1.md`、`材料(3).md`),只按名字归类等于没整理。内容相近的文档放同一层;一篇跨两个主题时归到**主要用途**那一类,在索引摘要里注明另一面。
143
+
144
+ ### 分类粒度
145
+
146
+ - 一类**少于 3 篇**就别单独建文件夹,并入相邻类或放 `待归类/`
147
+ - 一类**超过 20 篇**才考虑拆二级
148
+ - 一级类目建议 3-8 个;超过 10 个说明分得太细,人记不住
149
+
150
+ ## 四、建立分层目录并移动文档
151
+
152
+ ### 路径规则(最容易踩错的地方)
153
+
154
+ `create` 与 `move` 的 `relPath` 相对**权威树根**,`list` 与 `read` 用**视图路径**。三个桶的目录不一定已经在权威树里建好,所以先建桶再建子目录,**逐级建**(不要指望一次建出多层):
155
+
156
+ | 桶 | 写入用的权威路径 | 读取用的视图路径 |
157
+ | --- | --- | --- |
158
+ | `global` | `global/<类目>/<文件>` | 同左 |
159
+ | `department` | `department/<部门码>/…` | `department/<…>`(不带部门码) |
160
+ | `personal` | `personal/<uid>/<文件>` | `personal/<文件>`(**不带 uid**) |
161
+
162
+ `personal` 桶是唯一「写带 uid、读不带 uid」的:视图里的 `personal/` 已经隐去了 uid,所以读侧不要带。写侧少写 uid 会落到 `actual/personal/` 根下,视图映射不到,表现为「写了但看不见」。uid 从 `status` 的 `caller.userId` 取。
163
+
164
+ ```bash
165
+ # 1) 建一级类目(桶已存在时跳过)
166
+ curl -sS -X POST http://127.0.0.1:3080/knowledge-base/api/create \
167
+ -H 'content-type: application/json' \
168
+ -d '{"relPath":"global/涉边偷渡类","kind":"directory"}'
169
+
170
+ # 2) 需要二级时再建
171
+ curl -sS -X POST http://127.0.0.1:3080/knowledge-base/api/create \
172
+ -H 'content-type: application/json' \
173
+ -d '{"relPath":"global/涉边偷渡类/案件复盘","kind":"directory"}'
174
+ ```
175
+
176
+ `create` 返回 `409 a document or folder already exists` 说明该层已存在,继续下一步即可,不要当失败。
177
+
178
+ ### 移动文档
179
+
180
+ ```bash
181
+ curl -sS -X POST http://127.0.0.1:3080/knowledge-base/api/move \
182
+ -H 'content-type: application/json' \
183
+ -d '{"from":"global/a.md","to":"global/涉边偷渡类"}'
184
+ ```
185
+
186
+ `to` 是**目标目录**,不是完整目标路径。文件名保持不变:`move` 只负责换个位置,不能借它改名(要改名用 `rename`)。返回里的 `delta` 是视图同步结果。
187
+
188
+ 移动前确认:
189
+
190
+ 1. `from` 与 `to` 都要有写权限,否则会 403
191
+ 2. 同名文件已在目标层时先停下,问用户是否覆盖或改名,不要盲目移
192
+ 3. 成批移动时**一次一批、每批后校验**,不要一口气移完再检查
193
+
194
+ ### 移动后校验
195
+
196
+ 每一批移动后重新 `list` 目标层,确认文件都在预期位置、源层已清空。视图是授权结果的镜像,`delta` 里 `unlinked` 非空是正常的(旧位置解链)。
197
+
198
+ ## 五、写每层的层索引
199
+
200
+ ### 索引文件名
201
+
202
+ 每层一个固定名字:**`_index.md`**。根层也写一份。
203
+
204
+ ### 索引内容(三段,缺一不可)
205
+
206
+ ```markdown
207
+ # 涉边偷渡类
208
+
209
+ 本层收录边境管控、偷渡案件、口岸查验相关的方案、通报与台账,共 12 篇。
210
+
211
+ ## 子条目
212
+
213
+ | 文档 | 摘要 | 路径 |
214
+ | --- | --- | --- |
215
+ | 边境管控方案.md | 2026 年边境管控总体方案,含三道防线部署 | 涉边偷渡类/边境管控方案.md |
216
+ | 偷渡案件通报.md | 二季度偷渡案件情况通报,含 7 起典型案例 | 涉边偷渡类/偷渡案件通报.md |
217
+
218
+ ## 子目录
219
+
220
+ - [`案件复盘`](案件复盘/_index.md) — 5 篇案件复盘与复盘纪要
221
+
222
+ ---
223
+
224
+ 更新于 2026-10-21
225
+ ```
226
+
227
+ 要求:
228
+
229
+ - **本层简介**:一段话说清这一层收什么、为什么这些放一起
230
+ - **子条目**:每篇一行,`摘要` 是一句话(不是文件名重复),`路径` 用**本层内的相对路径**
231
+ - **子目录**:链接指向下一层的 `_index.md`,写清那层收什么、多少篇
232
+ - **更新时间**:`更新于 YYYY-MM-DD`,每次重写都要改
233
+
234
+ ### 怎么写
235
+
236
+ 用 `create` 写;已存在则用 `edit` 覆盖(`create` 遇到已存在会 409):
237
+
238
+ ```bash
239
+ curl -sS -X POST http://127.0.0.1:3080/knowledge-base/api/create \
240
+ -H 'content-type: application/json' \
241
+ -d '{"relPath":"global/涉边偷渡类/_index.md","content":"# 涉边偷渡类\n\n…"}'
242
+ ```
243
+
244
+ 内容较长时用文件传参更稳(见下节),避免 shell 转义问题。
245
+
246
+ **顺序很重要**:先移完这一层所有文档,再写这一层的索引。否则索引里的路径会指向还没移过去的文件。
247
+
248
+ ### 根层索引
249
+
250
+ 整理完成后,在整理根写 `_index.md`,列出所有一级类目与总数:
251
+
252
+ ```markdown
253
+ # 知识库总索引
254
+
255
+ 共 3 个类目、48 篇文档。
256
+
257
+ | 类目 | 篇数 | 说明 |
258
+ | --- | --- | --- |
259
+ | [涉边偷渡类](涉边偷渡类/_index.md) | 12 | 边境管控、偷渡案件、口岸查验 |
260
+ | [经济犯罪类](经济犯罪类/_index.md) | 21 | 涉税、非法集资、传销 |
261
+ | [待归类](待归类/_index.md) | 15 | 尚未确定归属 |
262
+
263
+ ---
264
+
265
+ 更新于 2026-10-21
266
+ ```
267
+
268
+ ## 六、记录整理偏好
269
+
270
+ 偏好文件:`/workspace/kb-organize-preferences.md`(**权威**),个人库副本 `personal/kb-organize-preferences.md`(同步产物)。
271
+
272
+ 写入时机:用户回答了那两个问题之后、以及整理结束时(把这次实际采用的方案固化下来,下次直接复用)。
273
+
274
+ ```bash
275
+ cat > /workspace/kb-organize-preferences.md <<'EOF'
276
+ # 知识库整理偏好
277
+
278
+ 更新于 2026-10-21
279
+
280
+ ## 背景先验
281
+
282
+ - 本库主要覆盖涉边偷渡与经济犯罪两类业务
283
+ - 每周新增通报,月度台账独立成册
284
+
285
+ ## 分类偏好
286
+
287
+ - 粒度:两层(一级大类 + 必要时二级)
288
+ - 命名:中文、以「类」结尾
289
+ - 已有分类:涉边偷渡类 / 经济犯罪类 / 队伍管理类
290
+ - 未定归属:放 `待归类/`,不硬塞
291
+
292
+ ## 索引偏好
293
+
294
+ - 每层 `_index.md`,含简介 + 子条目表 + 更新时间
295
+ - 摘要写一句话主题,不复述文件名
296
+ EOF
297
+ ```
298
+
299
+ 同步到个人库。**写用权威路径,必须带调用者的 uid**——`create`/`edit` 的 `relPath` 相对权威树根,少写 uid 会落到 `actual/personal/` 下、视图里看不到:
300
+
301
+ ```bash
302
+ # 取 uid(视图树只显示 personal/,权威树才带 uid)
303
+ UID_KB=$(curl -sS -X POST http://127.0.0.1:3080/knowledge-base/api/status \
304
+ -H 'content-type: application/json' -d '{}' | python3 -c 'import json,sys;print(json.load(sys.stdin)["caller"]["userId"])')
305
+
306
+ python3 -c "
307
+ import json
308
+ print(json.dumps({
309
+ 'relPath': 'personal/$UID_KB/kb-organize-preferences.md',
310
+ 'content': open('/workspace/kb-organize-preferences.md').read(),
311
+ }))" | curl -sS -X POST http://127.0.0.1:3080/knowledge-base/api/create \
312
+ -H 'content-type: application/json' -d @-
313
+ ```
314
+
315
+ `create` 报 `already exists` 时改用 `edit`:
316
+
317
+ ```bash
318
+ python3 -c "
319
+ import json
320
+ print(json.dumps({
321
+ 'relPath': 'personal/$UID_KB/kb-organize-preferences.md',
322
+ 'content': open('/workspace/kb-organize-preferences.md').read(),
323
+ }))" | curl -sS -X POST http://127.0.0.1:3080/knowledge-base/api/edit \
324
+ -H 'content-type: application/json' -d @-
325
+ ```
326
+
327
+ 写完用**视图路径**校验一遍,两处都读得到才算同步成功:
328
+
329
+ ```bash
330
+ curl -sS -X POST http://127.0.0.1:3080/knowledge-base/api/read \
331
+ -H 'content-type: application/json' \
332
+ -d '{"path":"personal/kb-organize-preferences.md"}'
333
+ ```
334
+
335
+ 两处内容保持一致。工作区那份是权威:先写它,再同步副本。
336
+
337
+ ## 七、收尾与汇报
338
+
339
+ 整理完成后向用户报告:
340
+
341
+ 1. **分类结果**:建了哪些层、每层多少篇
342
+ 2. **移动清单**:哪些文件从哪移到哪(移了很多时给汇总,不要逐条刷屏)
343
+ 3. **未归类**:`待归类/` 里有什么、为什么没能归类(缺文本副本、内容不明、跨类)
344
+ 4. **偏好**:这次用了什么默认、写在哪个文件
345
+ 5. **下一步建议**:需要用户确认的分类、需要补材料的文档
346
+
347
+ ## 八、边界与红线
348
+
349
+ - **只整理,不删内容。** 不调用 `trash.remove`。要删先问用户
350
+ - **不跨桶移动。** `global` / `department` / `personal` 之间移动等于改变可见范围,必须用户明确同意且两侧都有写权限
351
+ - **不改文档正文。** 整理只动位置和新增索引文件,不改原文(`edit` 只用来写 `_index.md` 和偏好文件)
352
+ - **不猜权限。** 403 是正确结果,报告「该路径需要写权限」而不是绕过
353
+ - **大库分批。** 超过 50 篇时按类目分批处理,每批结束汇报进度,不要静默跑很久
354
+ - **整理前先确认范围。** 「整理知识库」可能指整个库,也可能只指某个目录。范围不明时先 `list` 根层,把看到的结构给用户,让他指定范围
355
+
356
+ ## 九、本技能的安装方式(维护者读)
357
+
358
+ 这份技能住在 `packages/knowledge-base/skills/kb-organize/`,通过 **工作区根 `~/.agents/skills/kb-organize` 的软链接**被技能中心发现。走这条路径的原因:本仓库的 `knowledge-base` 技能是在 `src/index.ts` 里以 **code-registered provider** 注册的,而技能中心只扫描固定的几类根目录(工作区根 `.agents/skills`、`$DSH_HOME/skills` 等),不会扫描包内的 `skills/` 子目录。
359
+
360
+ 若要让这个技能**随 npm 包一起发布**(而不是只在本机工作区可见),需要两处改动,缺一不可:
361
+
362
+ 1. `packages/knowledge-base/package.json` 的 `files` 数组加入 `"skills/**"`(当前只列了 `lib/**`、`cordis.patch.yml`、`README.md`、`LICENSE`,技能文件不会进包);
363
+ 2. `packages/knowledge-base/src/index.ts` 增加**第二个** skill provider(现有 `knowledgeBaseSkillProvider()` 只注册 `knowledge-base` 一个),并在 `apply()` 的 `inject(['skills'], …)` 回调里与现有 provider 一起注册。
364
+
365
+ 在此之前,新机器上要么手动建软链接,要么跑 `scripts/sync-harness-skills.sh`。**不要为此去改 profile 的 `cordis.patch.yml`**:`dsh-plus` 的能力引导会整文件覆盖它。
@@ -0,0 +1,10 @@
1
+ {
2
+ "_meta": {
3
+ "sourceHash": "manual",
4
+ "model": "deepseek-v4.1-flash",
5
+ "translatedAt": "2026-10-21T00:00:00.000Z"
6
+ },
7
+ "title": "知识库整理",
8
+ "description": "整理知识库、归档文档、生成索引、按内容分类归并时使用;先读整理偏好,逐篇读内容归纳主题,建分层文件夹并移动文档,每层写一份层索引 md,缺 md 文本副本的文档先补索引。",
9
+ "summary": "把平铺的知识库整理成按主题分层的文件夹,并为根层与每个子层生成 _index.md 层索引(简介、子条目摘要与相对路径、子目录链接、更新时间)。整理偏好记录在工作区 kb-organize-preferences.md 并同步到个人知识库;开始前先读偏好并询问用户背景与命名偏好,用户不答则采用保守默认。"
10
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.