# 文件系统 OpenViking 提供类 Unix 的文件系统操作来管理上下文。 ## API 参考 ### ls() 列出目录内容。 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | uri | str | 是 | - | Viking URI | | simple | bool | 否 | False | 仅返回相对路径 | | recursive | bool | 否 | False | 递归列出所有子目录 | | output | str | 否 | HTTP:`agent`;SDK:`original` | 输出格式:`agent` 或 `original` | | abs_limit | int | 否 | 256 | `agent` 输出中的摘要长度限制 | | show_all_hidden | bool | 否 | False | 像 `-a` 一样包含隐藏文件 | | node_limit | int | 否 | 1000 | 最大返回节点数 | | limit | int | 否 | None | `node_limit` 的别名 | | sort_by | str | 否 | None | 在应用 `node_limit` 前,分别按 `name` 或 `mtime` 排序目录组和文件组;目录仍优先 | | sort_order | str | 否 | `asc` | 排序方向:`asc` 或 `desc` | **条目结构** ```python { "name": "docs", # 文件/目录名称 "size": 4096, # 大小(字节) "mode": 16877, # 文件模式 "modTime": "2024-01-01T00:00:00Z", # ISO 时间戳 "isDir": True, # 如果是目录则为 True "uri": "viking://resources/docs/", # Viking URI "meta": {} # 可选元数据 } ``` **Python SDK (Embedded / HTTP)** ```python entries = client.ls( "viking://resources/", node_limit=200, sort_by="mtime", sort_order="desc", ) for entry in entries: type_str = "dir" if entry['isDir'] else "file" print(f"{entry['name']} - {type_str}") ``` **TypeScript SDK** ```typescript const entries = await client.list("viking://resources/docs/", { simple: true }); console.log(entries); ``` **Go SDK** ```go entries, err := client.List(ctx, "viking://resources/", nil) if err != nil { return err } for _, entry := range entries { fmt.Println(entry) } ``` **HTTP API** ``` GET /api/v1/fs/ls?uri={uri}&simple={bool}&recursive={bool} ``` ```bash # 基本列表 curl -X GET "http://localhost:1933/api/v1/fs/ls?uri=viking://resources/" \ -H "X-API-Key: your-key" # 简单路径列表 curl -X GET "http://localhost:1933/api/v1/fs/ls?uri=viking://resources/&simple=true" \ -H "X-API-Key: your-key" # 递归列表 curl -X GET "http://localhost:1933/api/v1/fs/ls?uri=viking://resources/&recursive=true" \ -H "X-API-Key: your-key" ``` **CLI** ```bash openviking ls viking://resources/ [--simple] [--recursive] ``` **响应** ```json { "status": "ok", "result": [ { "name": "docs", "size": 4096, "mode": 16877, "modTime": "2024-01-01T00:00:00Z", "isDir": true, "uri": "viking://resources/docs/" } ], "time": 0.1 } ``` --- ### tree() 获取目录树结构。 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | uri | str | 是 | - | Viking URI | | output | str | 否 | HTTP:`agent`;SDK:`original` | 输出格式:`agent` 或 `original` | | abs_limit | int | 否 | HTTP:256;SDK:128 | `agent` 输出中的摘要长度限制 | | show_all_hidden | bool | 否 | False | 像 `-a` 一样包含隐藏文件 | | node_limit | int | 否 | 1000 | 最大返回节点数 | | level_limit | int | 否 | 3 | 最大目录遍历深度 | **Python SDK (Embedded / HTTP)** ```python entries = client.tree("viking://resources/") for entry in entries: type_str = "dir" if entry['isDir'] else "file" print(f"{entry['rel_path']} - {type_str}") ``` **TypeScript SDK** ```typescript const tree = await client.tree("viking://resources/docs/", { nodeLimit: 100 }); console.log(tree); ``` **Go SDK** ```go entries, err := client.Tree(ctx, "viking://resources/", nil) if err != nil { return err } for _, entry := range entries { fmt.Println(entry["rel_path"], entry["isDir"]) } ``` **HTTP API** ``` GET /api/v1/fs/tree?uri={uri} ``` ```bash curl -X GET "http://localhost:1933/api/v1/fs/tree?uri=viking://resources/" \ -H "X-API-Key: your-key" ``` **CLI** ```bash openviking tree viking://resources/my-project/ ``` **响应** ```json { "status": "ok", "result": [ { "name": "docs", "size": 4096, "isDir": true, "rel_path": "docs/", "uri": "viking://resources/docs/" }, { "name": "api.md", "size": 1024, "isDir": false, "rel_path": "docs/api.md", "uri": "viking://resources/docs/api.md" } ], "time": 0.1 } ``` --- ### stat() 获取文件或目录的状态信息。对于目录,会返回目录下的项目计数。 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | uri | str | 是 | - | Viking URI | **Python SDK (Embedded / HTTP)** ```python info = client.stat("viking://resources/docs/api.md") print(f"Size: {info['size']}") print(f"Is directory: {info['isDir']}") # 对于目录,会返回项目计数 dir_info = client.stat("viking://resources/docs") if dir_info.get('isDir'): print(f"Item count: {dir_info.get('count')}") ``` **TypeScript SDK** ```typescript const metadata = await client.stat("viking://resources/docs/api.md"); console.log(metadata); ``` **Go SDK** ```go info, err := client.Stat(ctx, "viking://resources/docs/api.md") if err != nil { return err } fmt.Println(info["size"], info["isDir"]) ``` **HTTP API** ``` GET /api/v1/fs/stat?uri={uri} ``` ```bash curl -X GET "http://localhost:1933/api/v1/fs/stat?uri=viking://resources/docs/api.md" \ -H "X-API-Key: your-key" ``` **CLI** ```bash openviking stat viking://resources/my-project/docs/api.md openviking stat viking://resources/my-project/docs ``` **响应(文件)** ```json { "status": "ok", "result": { "name": "api.md", "size": 1024, "mode": 33188, "modTime": "2024-01-01T00:00:00Z", "isDir": false, "isLocked": false, "uri": "viking://resources/docs/api.md" }, "time": 0.1 } ``` **响应(目录)** ```json { "status": "ok", "result": { "name": "docs", "size": 4096, "mode": 16877, "modTime": "2024-01-01T00:00:00Z", "isDir": true, "isLocked": false, "uri": "viking://resources/docs", "count": 42 }, "time": 0.1 } ``` `isLocked` 字段反映路径当前是否被路径锁持有:路径自身存在有效锁(包括目标路径对应的 exact-path lock),或者任一祖先目录持有 TreeLock。当 LockManager 不可用或查询失败时返回 `false`,调用方可据此避免先写入再观察到 `ResourceBusyError`。 `count` 字段(仅目录)包含该目录下的项目(文件和子目录)估计数量(来自向量索引)。 --- ### attrs() 获取文件或目录的逻辑扩展属性。 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | uri | str | 是 | - | Viking URI | **Python SDK (HTTP)** ```python attrs = client.attrs("viking://resources/docs/api.md") print(attrs["attrs"]["tags"]) ``` **TypeScript SDK** ```typescript const attributes = await client.attrs("viking://resources/docs/api.md"); console.log(attributes); ``` **Go SDK** ```go attrs, err := client.Attrs(ctx, "viking://resources/docs/api.md") if err != nil { return err } metadata := attrs["attrs"].(map[string]any) fmt.Println(metadata["tags"]) ``` **HTTP API** ``` GET /api/v1/fs/attrs?uri={uri} POST /api/v1/fs/attrs/set_tags ``` ```bash curl -X GET "http://localhost:1933/api/v1/fs/attrs?uri=viking://resources/docs/api.md" \ -H "X-API-Key: your-key" curl -X POST "http://localhost:1933/api/v1/fs/attrs/set_tags" \ -H "X-API-Key: your-key" \ -H "Content-Type: application/json" \ -d '{"uri":"viking://resources/docs","tags":["team=search"],"mode":"append","recursive":true}' ``` **CLI** ```bash openviking attrs get viking://resources/docs/api.md openviking attrs get viking://resources/docs/api.md tags openviking attrs get viking://user/alice/memories/experiences/foo.md memory.resource_refs openviking attrs set-tags viking://resources/docs/api.md --tags team=search,env=prod openviking attrs set-tags viking://resources/docs --tags team=search --mode append --recursive ``` 目录目标会更新目录语义记录;`recursive=true` 还会更新已有子文件和子目录语义记录。 **响应(Resource)** ```json { "status": "ok", "result": { "uri": "viking://resources/docs/api.md", "context_type": "resource", "attrs": { "tags": ["team=search", "env=prod"] } } } ``` **响应(Memory)** ```json { "status": "ok", "result": { "uri": "viking://user/alice/memories/experiences/foo.md", "context_type": "memory", "attrs": { "memory": { "memory_type": "experiences", "name": "foo", "tags": ["ui"], "resource_refs": ["viking://resources/docs/api.md"] }, "tags": ["team=search"] } } } ``` `attrs.memory` 来自 `MEMORY_FIELDS` 元信息,已去掉正文内容。`attrs.tags` 是 `attrs set-tags` 和搜索过滤使用的显式检索标签。 --- ### mkdir() 创建目录。 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | uri | str | 是 | - | 新目录的 Viking URI | | description | str | 否 | `null` | 目录初始说明。传入后会写入 `.abstract.md`,并进入目录 L0 向量化队列。 | **Python SDK (Embedded / HTTP)** ```python client.mkdir("viking://resources/new-project/") client.mkdir("viking://resources/new-project/", description="接口文档目录") ``` **TypeScript SDK** ```typescript await client.mkdir("viking://resources/docs/guides/", "Project guides"); ``` **Go SDK** ```go if err := client.Mkdir(ctx, "viking://resources/new-project/", "接口文档目录"); err != nil { return err } ``` **HTTP API** ``` POST /api/v1/fs/mkdir ``` ```bash curl -X POST http://localhost:1933/api/v1/fs/mkdir \ -H "Content-Type: application/json" \ -H "X-API-Key: your-key" \ -d '{ "uri": "viking://resources/new-project/", "description": "接口文档目录" }' ``` **CLI** ```bash openviking mkdir viking://resources/new-project/ openviking mkdir viking://resources/new-project/ --description "接口文档目录" ``` **响应** ```json { "status": "ok", "result": { "uri": "viking://resources/new-project/" }, "time": 0.1 } ``` --- ### rm() 删除文件或目录。递归删除目录时会返回删除的项目估计数量。 `rm` 是幂等操作:删除一个合法但不存在的 URI 仍会成功。 URI 格式非法、scheme 不支持或使用非公开作用域时返回 `INVALID_URI`。 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | uri | str | 是 | - | 要删除的 Viking URI | | recursive | bool | 否 | False | 递归删除目录 | **Python SDK (Embedded / HTTP)** ```python # 删除单个文件 client.rm("viking://resources/docs/old.md") # 递归删除目录 client.rm("viking://resources/old-project/", recursive=True) ``` **TypeScript SDK** ```typescript await client.remove("viking://resources/docs/old.md", { wait: true }); ``` **Go SDK** ```go err := client.Remove(ctx, "viking://resources/old-project/", &openviking.RemoveOptions{ Recursive: true, }) if err != nil { return err } ``` **HTTP API** ``` DELETE /api/v1/fs?uri={uri}&recursive={bool} ``` ```bash # 删除单个文件 curl -X DELETE "http://localhost:1933/api/v1/fs?uri=viking://resources/docs/old.md" \ -H "X-API-Key: your-key" # 递归删除目录 curl -X DELETE "http://localhost:1933/api/v1/fs?uri=viking://resources/old-project/&recursive=true" \ -H "X-API-Key: your-key" ``` **CLI** ```bash openviking rm viking://resources/old.md [--recursive] ``` **响应(单个文件)** ```json { "status": "ok", "result": { "uri": "viking://resources/docs/old.md" }, "time": 0.1 } ``` **响应(递归删除)** ```json { "status": "ok", "result": { "uri": "viking://resources/old-project/", "estimated_deleted_count": 42 }, "time": 0.1 } ``` `estimated_deleted_count` 字段(递归删除时)包含删除的项目(文件和目录)估计数量(来自向量索引)。CLI 会在输出中显示此信息。 删除 `viking://resources/...` 时,响应可能包含 `memory_cleanup`,表示删除前已清理引用该资源 URI 的用户记忆。 --- ### mv() 移动文件或目录。 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | from_uri | str | 是 | - | 源 Viking URI | | to_uri | str | 是 | - | 目标 Viking URI | **Python SDK (Embedded / HTTP)** ```python client.mv( "viking://resources/old-name/", "viking://resources/new-name/" ) ``` **TypeScript SDK** ```typescript await client.move( "viking://resources/docs/old.md", "viking://resources/docs/new.md", ); ``` **Go SDK** ```go if err := client.Move(ctx, "viking://resources/old-name/", "viking://resources/new-name/"); err != nil { return err } ``` **HTTP API** ``` POST /api/v1/fs/mv ``` ```bash curl -X POST http://localhost:1933/api/v1/fs/mv \ -H "Content-Type: application/json" \ -H "X-API-Key: your-key" \ -d '{ "from_uri": "viking://resources/old-name/", "to_uri": "viking://resources/new-name/" }' ``` **CLI** ```bash openviking mv viking://resources/old-name/ viking://resources/new-name/ ``` **响应** ```json { "status": "ok", "result": { "from": "viking://resources/old-name/", "to": "viking://resources/new-name/" }, "time": 0.1 } ``` ## 相关文档 - [Viking URI](../concepts/04-viking-uri.md) - URI 规范 - [Context Layers](../concepts/03-context-layers.md) - L0/L1/L2 - [Resources](02-resources.md) - 资源管理