Files

175 lines
9.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: docsys
description: 操作公司 MxsDoc / DocSystem 网络文档系统(http://172.1.4.31:8100/DocSystem)的文件系统——仓库浏览、目录创建/删除/重命名、文件上传/删除/重命名/移动/复制、以及按文件名或正文搜索。当用户提到"文档系统""DocSystem""MxsDoc""文档库""上传文件到文档系统""在文档系统里建目录/搜文件"时使用。
agent_created: true
---
# DocSystem 文档系统操作 Skill
通过纯 HTTP 调用 MxsDoc(DocSystem)后端接口,让 AI 直接操作公司文档系统的文件系统:
浏览、建目录、删除、重命名、移动、复制、上传、下载、搜索。
底层是一个零依赖的 Python CLI:只用标准库,不需要 pip 安装任何东西。
## 首次配置(凭证)
凭证不写在代码里,从 `~/.docsys/config.json` 或环境变量读取。首次使用先建这个文件:
```json
{
"baseUrl": "http://172.1.4.31:8100/DocSystem",
"user": "your.name@company.com",
"password": "your-password"
}
```
也可用环境变量 `DOCSYS_BASE_URL` / `DOCSYS_USER` / `DOCSYS_PASSWORD`,或命令行 `--base-url` / `--user` / `--password` 临时覆盖。
未配置时 CLI 会直接提示配置文件路径,不会用空账号去撞登录接口。
## 快速开始
```bash
PY="C:/Users/occul/.workbuddy/binaries/python/versions/3.13.12/python.exe"
SK="C:/Users/occul/WorkBuddy/docsys-skill/docsys"
$PY "$SK/scripts/docsys.py" login # 登录并缓存会话(首次执行即可)
$PY "$SK/scripts/docsys.py" repos # 列出可访问仓库
$PY "$SK/scripts/docsys.py" ls "意见与反馈" / # 列出仓库根目录
```
会话 cookie 缓存在 `~/.docsys/session.json`,过期时会自动重新登录,不需要每次显式 login。
## ⚠️ 默认仓库约定
**未指定仓库时一律使用 `研发管理配置库`(id=2)。** 用户说"上传个文件""搜一下 XX"而没提别的库时,不要反问,直接对这个库操作。
```bash
$PY "$SK/scripts/docsys.py" ls # = ls 研发管理配置库 /
$PY "$SK/scripts/docsys.py" ls /Sunyard # 路径以 / 开头,仓库自动取默认
$PY "$SK/scripts/docsys.py" ls 1 / # 显式切到其他库才带仓库参数
$PY "$SK/scripts/docsys.py" search 详细设计 # 默认搜默认库
$PY "$SK/scripts/docsys.py" search 详细设计 --all-repos # 例外:搜全部库
```
`repos` 命令会给默认库打 `← 默认` 标记。默认库可用环境变量 `DOCSYS_DEFAULT_REPO` 覆盖。
**判定规则**:第一个位置参数若以 `/` 或 `./` 开头 → 视为路径,仓库取默认;否则视为仓库名/id。所以 `ls /Sunyard` 和 `ls 研发管理配置库 /Sunyard` 等价。
内部实现是"位置参数整体左移一位",所以 `touch /a/b.txt "内容"` 这类后面还带可选参数的命令也不会错位。
## 命令一览
`<repo>` 全部可省略(省略即默认库):
| 命令 | 说明 |
|---|---|
| `login` / `logout` / `whoami` | 会话管理 |
| `repos` | 列出可访问仓库(id + 名称,标注默认) |
| `ls [repo] [path]` | 列出目录内容 |
| `tree [repo] [path] [--depth N]` | 递归列目录树 |
| `mkdir [repo] <path> [-p]` | 创建目录;默认要求父目录已存在,`-p` 递归创建中间目录 |
| `touch [repo] <path> [content]` | 创建文本文件;`content=@file --file x.txt` 从本地读内容 |
| `rename [repo] <path> <new_name>` | 重命名(不能跨目录) |
| `rm [repo] <path>` | 删除文件或目录(目录为递归删除) |
| `mv [repo] <src> <dst>` | 移动/改名。`dst` 是已存在目录则移入其中,否则视为目标完整路径 |
| `cp [repo] <src> <dst>` | 复制,语义同 `mv` |
| `upload [repo] <remote_dir> <local_file> [--name X]` | 上传本地文件 |
| `download [repo] <path> <local_file>` | 下载;`local_file` 为 `-` 时输出到 stdout |
| `cat [repo] <path>` | 读取文本文件内容 |
| `search <keyword> [--repo R] [--all-repos] [--path P]` | 按文件名或正文搜索;默认搜默认库,`--all-repos` 搜全部 |
| `auth [repo] [path]` | 查看当前账号在该目录的权限 |
全局参数:`--json`(结构化输出,推荐 AI 解析用)、`--base-url`、`--user`、`--password`。
## 用法约定(给 AI 的操作说明)
**0. 仓库默认就是「研发管理配置库」(id=2)。** 用户没指名别的仓库时不要反问、不要先跑 `repos` 确认,直接操作。切库时才带 repo 参数。
**1. 仓库也可以用 id 或名称指定**,名称支持子串匹配:
```
$PY ... ls 1 / # 按 id
$PY ... ls 常用工具 / # 按名称
$PY ... ls 研发 / # 子串,唯一匹配
```
**2. 路径一律用 `/a/b/c` 形式**,前导斜杠可省略,仓库根写 `/` 或留空。
单独给路径时(`ls /Sunyard`)脚本会自动识别为"默认库的该路径",不会误判成仓库名。
**3. 要解析用户输入("研发库的 2024 归档目录")时,先用 `repos` + `search` / `tree` 定位,不要猜。**
**4. 破坏性操作(`rm`、覆盖式 `mv`/`cp`)执行前先向用户确认**,并优先用 `ls` 或 `auth` 确认目标存在且有权限。
**5. 推荐加 `--json`**,输出结构稳定:
```json
[{"name":"t1.txt","fullPath":"_SELFTEST/t1.txt","type":"file","size":35,"mtime":"2026-10-20 14:33","docId":202070828624}]
```
## 权限边界(当前账号实测)
账号 `qian.huang@sunyard.com` 实测:
**权限是逐目录授予的,不是仓库级。** 同一个仓库里不同目录可以完全不同:
| 目录 | 访问 | 新增 | 编辑 | 删除 | 下载 |
|---|---|---|---|---|---|
| 研发管理配置库 `/`(根) | ✅ | ❌ | ❌ | ❌ | ❌ |
| 研发管理配置库 `/Sunyard/Docs/开发流程` | ✅ | ❌ | ❌ | ❌ | ✅ |
| **研发管理配置库 `/Sunyard/Dev/产品/系统研发/工具`** | ✅ | ✅ | ✅ | ✅ | ✅ |
| 意见与反馈 `/`(根) | ✅ | ✅ | ✅ | ❌ | ❌ |
所以**不要凭仓库名推断权限**,任何写操作前先跑 `auth <path>` 确认。
已验证可完整 CRUD 的目录:`/Sunyard/Dev/产品/系统研发/工具/测试`(增删改 + 下载全开)。
服务端权限不足时返回中文错误,CLI 原样透出:
```
[docsys] 您没有该目录的删除权限,请联系管理员
```
遇到这类报错不要反复重试、也不要自作主张换到别的目录/仓库,直接告诉用户需要管理员授权。
注意:重命名和移动在服务端按"删除 + 新增"鉴权,所以即使有新增权限也可能被拒。
## 接口契约(排障用)
全部为 `POST {BASE}/...`,`{BASE} = http://172.1.4.31:8100/DocSystem`,表单编码,
需要带 `X-Requested-With: XMLHttpRequest`,会话靠 cookie(`JSESSIONID` / `dstoken` / `dsuser`)。
登录密码先做 base64 编码再提交。响应统一为 `{status:"ok"|"fail", data, msgInfo}`。
| 接口 | 参数 |
|---|---|
| `User/login.do` | `userName`, `pwd`(base64), `rememberMe` |
| `Repos/getReposList.do` | 无 |
| `Repos/getSubDocList.do` | `vid`, `docId`, `path`, `name`, `sort`, `needLockState` |
| `Repos/getUserDocAuth.do` | `docId`, `reposId`, `path`, `name` |
| `Doc/addDoc.do` | `reposId`, `type`(1文件/2目录), `pid`, `path`, `name`, `content`(**实测 content 被忽略,建出来恒为 0 字节空文件**) |
| `Doc/renameDoc.do` | `reposId`, `docId`, `pid`, `type`, `level`, `path`, `name`, `dstName` |
| `Doc/deleteDoc.do` | `reposId`, `docId`, `pid`, `path`, `name` |
| `Doc/moveDoc.do` | `reposId`, `docId`, `type`, `srcLevel`, `dstLevel`, `srcPid`, `dstPid`, `srcPath`, `srcName`, `dstPath`, `dstName` |
| `Doc/copyDoc.do` | 同 `moveDoc` |
| `Doc/uploadDoc.do` | multipart:`reposId`, `path`, `name`, `size`, `checkSum`(md5), `uploadFile`, `commitMsg`, `dirPath` |
| `Doc/downloadDocPrepare.do` | `reposId`, `docId`, `pid`, `path`, `name`, `downloadType` |
| `Doc/downloadDoc.do` | GET:`vid`, `path`, `name`, `targetPath`, `targetName`, `deleteFlag`, `encryptEn=1` |
| `Doc/searchDoc.do` | `searchWord`, `sort`, `reposId`, `path` |
| `Doc/getDocContent.do` | `reposId`, `docId`, `pid`, `path`, `name`(返回纯文本,响应开头有 `ok` 前缀) |
### 路径语义(最容易踩的坑)
- 节点字段 `path` 是**它所在目录**的路径:根目录下为 `""`,其余以 `/` 结尾,如 `_SELFTEST/sub/`。
节点完整路径 = `path + name`。
- **列举**:`getSubDocList` 只看 `path + name` 拼接结果,`docId` 不参与定位。
要列 `_SELFTEST` 的子项,必须传 `path=_SELFTEST/`(或 `path=_SELFTEST/` 且 `name=` 空)。
- **写入**(addDoc / uploadDoc / moveDoc 的 `dstPath`):要传**父目录完整路径 + `/`**,
例如往 `_SELFTEST` 下建文件,`path` 应为 `_SELFTEST/`,而不是节点自身的 `""`。
- **删除 / 重命名**:传节点自身的 `path` 与 `name`。
### 其他服务端怪癖
- **`addDoc.do` 忽略 `content`**:新建文件永远得到 0 字节空文件,响应里 `size=0`,
`getDocContent` 也读不到内容。要写内容必须走 `uploadDoc.do`(CLI 的 `touch` 已自动改为走上传通道)。
- **`getDocContent.do` 返回纯文本**且开头带 `ok` 两个字符前缀,解析要剥掉;空文件时只返回 `ok`。
- **`getDocFileLink.do` 不可用**:链接指向 `tmp/History/rdata/<commitId>/...` 历史目录,文件不存在会 500。
下载必须走 `downloadDocPrepare.do` → `downloadDoc.do`。
## 文件
- `scripts/docsys.py` — CLI 实现(Python 3 标准库,零依赖)
- `README.md` — 逆向出的完整接口文档