@aigne/afs-cli 1.11.0-beta.2 → 1.11.0-beta.4
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/README.md +240 -12
- package/dist/cli.cjs +144 -26
- package/dist/cli.mjs +144 -26
- package/dist/cli.mjs.map +1 -1
- package/dist/commands/index.cjs +1 -0
- package/dist/commands/index.mjs +1 -0
- package/dist/commands/ls.cjs +12 -5
- package/dist/commands/ls.mjs +13 -5
- package/dist/commands/ls.mjs.map +1 -1
- package/dist/commands/mount.cjs +53 -17
- package/dist/commands/mount.mjs +53 -17
- package/dist/commands/mount.mjs.map +1 -1
- package/dist/commands/serve.cjs +142 -0
- package/dist/commands/serve.mjs +141 -0
- package/dist/commands/serve.mjs.map +1 -0
- package/dist/config/loader.cjs +28 -6
- package/dist/config/loader.mjs +28 -6
- package/dist/config/loader.mjs.map +1 -1
- package/dist/config/provider-factory.cjs +19 -1
- package/dist/config/provider-factory.mjs +19 -1
- package/dist/config/provider-factory.mjs.map +1 -1
- package/dist/config/schema.cjs +70 -3
- package/dist/config/schema.mjs +69 -3
- package/dist/config/schema.mjs.map +1 -1
- package/dist/config/uri-parser.cjs +17 -0
- package/dist/config/uri-parser.mjs +17 -0
- package/dist/config/uri-parser.mjs.map +1 -1
- package/dist/explorer/actions.cjs +246 -0
- package/dist/explorer/actions.mjs +240 -0
- package/dist/explorer/actions.mjs.map +1 -0
- package/dist/explorer/components/dialog.cjs +231 -0
- package/dist/explorer/components/dialog.mjs +232 -0
- package/dist/explorer/components/dialog.mjs.map +1 -0
- package/dist/explorer/components/file-list.cjs +107 -0
- package/dist/explorer/components/file-list.mjs +107 -0
- package/dist/explorer/components/file-list.mjs.map +1 -0
- package/dist/explorer/components/function-bar.cjs +55 -0
- package/dist/explorer/components/function-bar.mjs +55 -0
- package/dist/explorer/components/function-bar.mjs.map +1 -0
- package/dist/explorer/components/index.cjs +5 -0
- package/dist/explorer/components/index.mjs +7 -0
- package/dist/explorer/components/metadata-panel.cjs +122 -0
- package/dist/explorer/components/metadata-panel.mjs +122 -0
- package/dist/explorer/components/metadata-panel.mjs.map +1 -0
- package/dist/explorer/components/status-bar.cjs +53 -0
- package/dist/explorer/components/status-bar.mjs +54 -0
- package/dist/explorer/components/status-bar.mjs.map +1 -0
- package/dist/explorer/keybindings.cjs +214 -0
- package/dist/explorer/keybindings.mjs +213 -0
- package/dist/explorer/keybindings.mjs.map +1 -0
- package/dist/explorer/screen.cjs +200 -0
- package/dist/explorer/screen.mjs +199 -0
- package/dist/explorer/screen.mjs.map +1 -0
- package/dist/explorer/state.cjs +53 -0
- package/dist/explorer/state.mjs +53 -0
- package/dist/explorer/state.mjs.map +1 -0
- package/dist/explorer/theme.cjs +158 -0
- package/dist/explorer/theme.mjs +155 -0
- package/dist/explorer/theme.mjs.map +1 -0
- package/dist/path-utils.cjs +104 -0
- package/dist/path-utils.mjs +104 -0
- package/dist/path-utils.mjs.map +1 -0
- package/dist/runtime.cjs +47 -33
- package/dist/runtime.mjs +47 -33
- package/dist/runtime.mjs.map +1 -1
- package/dist/ui/header.cjs +60 -0
- package/dist/ui/header.mjs +59 -0
- package/dist/ui/header.mjs.map +1 -0
- package/dist/ui/index.cjs +17 -0
- package/dist/ui/index.mjs +15 -0
- package/dist/ui/index.mjs.map +1 -0
- package/dist/ui/terminal.cjs +97 -0
- package/dist/ui/terminal.mjs +95 -0
- package/dist/ui/terminal.mjs.map +1 -0
- package/package.json +9 -6
package/README.md
CHANGED
|
@@ -1,42 +1,213 @@
|
|
|
1
1
|
# @aigne/afs-cli
|
|
2
2
|
|
|
3
|
-
AFS 命令行工具
|
|
3
|
+
AFS 命令行工具 - AFS-UI 的文本投影 (reference implementation)
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @aigne/afs-cli
|
|
9
|
+
# 或
|
|
10
|
+
pnpm add -g @aigne/afs-cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 快速开始
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# 配置挂载点
|
|
17
|
+
afs mount add /src fs:///path/to/project/src
|
|
18
|
+
afs mount add /docs fs:///path/to/docs
|
|
19
|
+
|
|
20
|
+
# 列出目录
|
|
21
|
+
afs list /src
|
|
22
|
+
|
|
23
|
+
# 读取文件
|
|
24
|
+
afs read /src/index.ts
|
|
25
|
+
|
|
26
|
+
# 搜索内容
|
|
27
|
+
afs search /src "TODO"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 配置文件
|
|
31
|
+
|
|
32
|
+
AFS CLI 使用 `.afs-config/config.toml` 配置挂载点和服务器设置。
|
|
33
|
+
|
|
34
|
+
### 配置文件位置
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
~/.afs-config/config.toml # 用户级 (最低优先级)
|
|
38
|
+
<project>/.afs-config/config.toml # 项目级
|
|
39
|
+
<subdir>/.afs-config/config.toml # 子目录级 (最高优先级)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 配置示例
|
|
43
|
+
|
|
44
|
+
```toml
|
|
45
|
+
# 本地文件系统
|
|
46
|
+
[[mounts]]
|
|
47
|
+
path = "/src"
|
|
48
|
+
uri = "fs:///Users/dev/project/src"
|
|
49
|
+
description = "项目源码"
|
|
50
|
+
|
|
51
|
+
# Git 仓库
|
|
52
|
+
[[mounts]]
|
|
53
|
+
path = "/upstream"
|
|
54
|
+
uri = "git:///path/to/repo?branch=main"
|
|
55
|
+
access_mode = "readonly"
|
|
56
|
+
|
|
57
|
+
# SQLite 数据库
|
|
58
|
+
[[mounts]]
|
|
59
|
+
path = "/db"
|
|
60
|
+
uri = "sqlite:///path/to/app.db"
|
|
61
|
+
|
|
62
|
+
# 远程 AFS 服务器
|
|
63
|
+
[[mounts]]
|
|
64
|
+
path = "/remote"
|
|
65
|
+
uri = "https://afs.example.com/afs"
|
|
66
|
+
|
|
67
|
+
# HTTP 服务器配置
|
|
68
|
+
[serve]
|
|
69
|
+
host = "localhost"
|
|
70
|
+
port = 3000
|
|
71
|
+
path = "/afs"
|
|
72
|
+
readonly = false
|
|
73
|
+
cors = false
|
|
74
|
+
max_body_size = 10485760 # 10MB
|
|
75
|
+
```
|
|
4
76
|
|
|
5
77
|
## 命令
|
|
6
78
|
|
|
79
|
+
### 文件操作
|
|
80
|
+
|
|
7
81
|
| 命令 | 功能 |
|
|
8
82
|
|------|------|
|
|
9
83
|
| `afs list [path]` (别名: `ls`) | 列出目录内容 |
|
|
10
84
|
| `afs read <path>` | 读取文件内容 |
|
|
11
85
|
| `afs write <path> [--content]` | 写入文件 (--content 或 stdin) |
|
|
12
|
-
| `afs stat <path>` |
|
|
86
|
+
| `afs stat <path>` | 获取文件/目录元信息 |
|
|
87
|
+
| `afs search <path> <query>` | 搜索文件内容 |
|
|
13
88
|
| `afs exec <path> <action>` | 执行操作 |
|
|
89
|
+
|
|
90
|
+
### 挂载管理
|
|
91
|
+
|
|
92
|
+
| 命令 | 功能 |
|
|
93
|
+
|------|------|
|
|
14
94
|
| `afs mount list` (别名: `ls`) | 列出挂载配置 |
|
|
15
95
|
| `afs mount add <path> <uri>` | 添加挂载 |
|
|
16
96
|
| `afs mount remove <path>` (别名: `rm`) | 移除挂载 |
|
|
17
97
|
| `afs mount validate` | 验证挂载配置 |
|
|
18
|
-
|
|
98
|
+
|
|
99
|
+
### 其他命令
|
|
100
|
+
|
|
101
|
+
| 命令 | 功能 |
|
|
102
|
+
|------|------|
|
|
103
|
+
| `afs explain [topic]` | 解释概念 (命令或路径) |
|
|
104
|
+
| `afs serve` | 启动 HTTP 服务器 |
|
|
105
|
+
|
|
106
|
+
## 支持的 URI 方案
|
|
107
|
+
|
|
108
|
+
| 方案 | 示例 | 说明 |
|
|
109
|
+
|------|------|------|
|
|
110
|
+
| `fs://` | `fs:///path/to/dir` | 本地文件系统 |
|
|
111
|
+
| `git://` | `git:///path/to/repo?branch=main` | Git 仓库 |
|
|
112
|
+
| `sqlite://` | `sqlite:///path/to/db.sqlite` | SQLite 数据库 |
|
|
113
|
+
| `json://` | `json:///path/to/config.json` | JSON/YAML 文件 |
|
|
114
|
+
| `http://` | `http://localhost:3000/afs` | HTTP 远程 AFS |
|
|
115
|
+
| `https://` | `https://api.example.com/afs` | HTTPS 远程 AFS |
|
|
116
|
+
|
|
117
|
+
## HTTP 服务器
|
|
118
|
+
|
|
119
|
+
### 启动服务器
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# 使用配置文件中的设置启动
|
|
123
|
+
afs serve
|
|
124
|
+
|
|
125
|
+
# 自定义主机和端口
|
|
126
|
+
afs serve --host 0.0.0.0 --port 8080
|
|
127
|
+
|
|
128
|
+
# 只读模式(禁用写入操作)
|
|
129
|
+
afs serve --readonly
|
|
130
|
+
|
|
131
|
+
# 启用 CORS 支持
|
|
132
|
+
afs serve --cors
|
|
133
|
+
|
|
134
|
+
# 自定义基础路径
|
|
135
|
+
afs serve --path /api/afs
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 服务器选项
|
|
139
|
+
|
|
140
|
+
| 选项 | 默认值 | 说明 |
|
|
141
|
+
|------|--------|------|
|
|
142
|
+
| `--host` | localhost | 监听主机地址 |
|
|
143
|
+
| `--port` | 3000 | 监听端口 |
|
|
144
|
+
| `--path` | /afs | 服务路径前缀 |
|
|
145
|
+
| `--readonly` | false | 只读模式 |
|
|
146
|
+
| `--cors` | false | 启用 CORS |
|
|
147
|
+
| `--maxBodySize` | 10MB | 最大请求体大小 |
|
|
148
|
+
|
|
149
|
+
### 配置优先级
|
|
150
|
+
|
|
151
|
+
`命令行参数 > config.toml > 默认值`
|
|
152
|
+
|
|
153
|
+
### 挂载远程服务器
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# 添加远程 HTTP 挂载
|
|
157
|
+
afs mount add /remote http://localhost:3000/afs
|
|
158
|
+
|
|
159
|
+
# 添加 HTTPS 挂载
|
|
160
|
+
afs mount add /api https://api.example.com/afs
|
|
161
|
+
|
|
162
|
+
# 访问远程挂载
|
|
163
|
+
afs list /remote
|
|
164
|
+
afs read /remote/file.txt
|
|
165
|
+
```
|
|
19
166
|
|
|
20
167
|
## 输出模式
|
|
21
168
|
|
|
22
169
|
```bash
|
|
23
170
|
# 默认: Machine Truth (LLM/脚本友好)
|
|
24
|
-
afs list /
|
|
171
|
+
afs list /src
|
|
172
|
+
# 输出: 每行一个路径
|
|
25
173
|
|
|
26
174
|
# JSON 结构化输出
|
|
27
|
-
afs list /
|
|
175
|
+
afs list /src --json
|
|
28
176
|
|
|
29
|
-
# LLM 优化输出
|
|
30
|
-
afs list /
|
|
177
|
+
# LLM 优化输出 (token 高效)
|
|
178
|
+
afs list /src --view=llm
|
|
31
179
|
|
|
32
|
-
# 人类友好输出
|
|
33
|
-
afs list /
|
|
180
|
+
# 人类友好输出 (树形结构)
|
|
181
|
+
afs list /src --view=human
|
|
34
182
|
```
|
|
35
183
|
|
|
36
|
-
|
|
184
|
+
### 输出模式对比
|
|
185
|
+
|
|
186
|
+
| 模式 | 特点 | 适用场景 |
|
|
187
|
+
|------|------|----------|
|
|
188
|
+
| default | 每行一个路径,pipe-safe | 脚本、grep、awk |
|
|
189
|
+
| json | 结构化 JSON | 程序解析 |
|
|
190
|
+
| llm | 语义事实,token 高效 | LLM/Agent |
|
|
191
|
+
| human | 树形结构,带图标 | 人类阅读 |
|
|
192
|
+
|
|
193
|
+
## explain 命令
|
|
194
|
+
|
|
195
|
+
explain 是 AFS CLI 的一等公民,专为 LLM/Agent 设计:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# 解释命令行为
|
|
199
|
+
afs explain afs ls
|
|
200
|
+
|
|
201
|
+
# 解释 AFS 对象
|
|
202
|
+
afs explain /src/index.ts
|
|
37
203
|
|
|
38
|
-
|
|
39
|
-
|
|
204
|
+
# JSON 输出 (供 agent 缓存)
|
|
205
|
+
afs explain --json afs read
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**explain vs help**:
|
|
209
|
+
- `help`: 解决"我怎么用" - 面向人类
|
|
210
|
+
- `explain`: 解决"它到底做了什么" - 面向 LLM/Agent,输出稳定可解析
|
|
40
211
|
|
|
41
212
|
## 退出码
|
|
42
213
|
|
|
@@ -47,3 +218,60 @@ afs list /modules/fs --view=human
|
|
|
47
218
|
| 2 | 参数错误 |
|
|
48
219
|
| 3 | 资源未找到 |
|
|
49
220
|
| 4 | 权限拒绝 |
|
|
221
|
+
| 5 | 运行时错误 |
|
|
222
|
+
|
|
223
|
+
## 使用场景
|
|
224
|
+
|
|
225
|
+
### 本地开发
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# 配置项目挂载
|
|
229
|
+
afs mount add /src fs://$(pwd)/src
|
|
230
|
+
afs mount add /docs fs://$(pwd)/docs
|
|
231
|
+
|
|
232
|
+
# 启动开发服务器供团队访问
|
|
233
|
+
afs serve --host 0.0.0.0 --port 3000
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### CI/CD 测试
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
# 启动测试数据服务器
|
|
240
|
+
afs serve --readonly --port 8080 &
|
|
241
|
+
|
|
242
|
+
# 测试用例访问
|
|
243
|
+
curl http://localhost:8080/afs/rpc \
|
|
244
|
+
-d '{"method":"read","params":{"path":"/test-fixtures/data.json"}}'
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### 临时文件共享
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
# 快速共享当前目录
|
|
251
|
+
afs mount add /share fs://$(pwd)
|
|
252
|
+
afs serve --host 0.0.0.0
|
|
253
|
+
|
|
254
|
+
# 其他人访问
|
|
255
|
+
afs mount add /remote-share http://your-ip:3000/afs
|
|
256
|
+
afs list /remote-share
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### 使用配置文件
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
# 创建配置
|
|
263
|
+
cat > .afs-config/config.toml << 'EOF'
|
|
264
|
+
[[mounts]]
|
|
265
|
+
path = "/data"
|
|
266
|
+
uri = "fs:///var/data"
|
|
267
|
+
|
|
268
|
+
[serve]
|
|
269
|
+
host = "0.0.0.0"
|
|
270
|
+
port = 8080
|
|
271
|
+
readonly = true
|
|
272
|
+
cors = true
|
|
273
|
+
EOF
|
|
274
|
+
|
|
275
|
+
# 直接启动,无需参数
|
|
276
|
+
afs serve
|
|
277
|
+
```
|
package/dist/cli.cjs
CHANGED
|
@@ -2,15 +2,19 @@
|
|
|
2
2
|
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
3
3
|
const require_version = require('./version.cjs');
|
|
4
4
|
const require_exec = require('./commands/exec.cjs');
|
|
5
|
+
const require_loader = require('./config/loader.cjs');
|
|
6
|
+
const require_index = require('./ui/index.cjs');
|
|
5
7
|
const require_mount = require('./commands/mount.cjs');
|
|
6
8
|
const require_explain = require('./commands/explain.cjs');
|
|
7
9
|
const require_ls = require('./commands/ls.cjs');
|
|
8
10
|
const require_read = require('./commands/read.cjs');
|
|
11
|
+
const require_runtime = require('./runtime.cjs');
|
|
12
|
+
const require_serve = require('./commands/serve.cjs');
|
|
9
13
|
const require_stat = require('./commands/stat.cjs');
|
|
10
14
|
const require_write = require('./commands/write.cjs');
|
|
11
15
|
require('./commands/index.cjs');
|
|
12
16
|
const require_errors = require('./errors.cjs');
|
|
13
|
-
const
|
|
17
|
+
const require_screen = require('./explorer/screen.cjs');
|
|
14
18
|
let yargs = require("yargs");
|
|
15
19
|
yargs = require_rolldown_runtime.__toESM(yargs);
|
|
16
20
|
let yargs_helpers = require("yargs/helpers");
|
|
@@ -29,19 +33,59 @@ let yargs_helpers = require("yargs/helpers");
|
|
|
29
33
|
* - afs read <path> Read file content
|
|
30
34
|
* - afs write <path> Write file content (--content or stdin)
|
|
31
35
|
* - afs exec <path> <action> Execute operation
|
|
36
|
+
* - afs serve Start HTTP server to expose AFS
|
|
37
|
+
* - afs explore [path] Interactive TUI file explorer
|
|
32
38
|
*
|
|
33
|
-
* Output modes:
|
|
34
|
-
* -
|
|
39
|
+
* Output modes (default: human):
|
|
40
|
+
* - --view=human: Human friendly format with colors (default)
|
|
41
|
+
* - --view=llm: LLM optimized output (token-efficient)
|
|
42
|
+
* - --view=default: Machine truth (script/pipe friendly)
|
|
35
43
|
* - --json: Structured JSON
|
|
36
|
-
* - --view=llm: LLM optimized output
|
|
37
|
-
* - --view=human: Human friendly format
|
|
38
44
|
*/
|
|
39
45
|
function getViewType(argv) {
|
|
40
46
|
if (argv.json) return "json";
|
|
41
47
|
if (argv.view) return argv.view;
|
|
42
|
-
return "
|
|
48
|
+
return "human";
|
|
49
|
+
}
|
|
50
|
+
let headerShown = false;
|
|
51
|
+
/**
|
|
52
|
+
* Show header if in human view mode and not already shown
|
|
53
|
+
*/
|
|
54
|
+
async function maybeShowHeader(view) {
|
|
55
|
+
if (view !== "human" || headerShown || !require_index.shouldShowHeader()) return;
|
|
56
|
+
headerShown = true;
|
|
57
|
+
try {
|
|
58
|
+
require_index.printHeader({
|
|
59
|
+
version: require_version.VERSION,
|
|
60
|
+
mountCount: (await new require_loader.ConfigLoader().load(process.cwd())).mounts.length
|
|
61
|
+
});
|
|
62
|
+
} catch {
|
|
63
|
+
require_index.printHeader({
|
|
64
|
+
version: require_version.VERSION,
|
|
65
|
+
mountCount: 0
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function showHeaderIfNeeded() {
|
|
70
|
+
const args = process.argv.slice(2);
|
|
71
|
+
if ((args.length === 0 || args.includes("--help") || args.includes("-h") || args.length === 1 && [
|
|
72
|
+
"help",
|
|
73
|
+
"mount",
|
|
74
|
+
"explain"
|
|
75
|
+
].includes(args[0])) && require_index.shouldShowHeader()) try {
|
|
76
|
+
require_index.printHeader({
|
|
77
|
+
version: require_version.VERSION,
|
|
78
|
+
mountCount: (await new require_loader.ConfigLoader().load(process.cwd())).mounts.length
|
|
79
|
+
});
|
|
80
|
+
} catch {
|
|
81
|
+
require_index.printHeader({
|
|
82
|
+
version: require_version.VERSION,
|
|
83
|
+
mountCount: 0
|
|
84
|
+
});
|
|
85
|
+
}
|
|
43
86
|
}
|
|
44
87
|
async function main() {
|
|
88
|
+
await showHeaderIfNeeded();
|
|
45
89
|
const cli = (0, yargs.default)((0, yargs_helpers.hideBin)(process.argv)).scriptName("afs").version(require_version.VERSION).alias("version", "V").help("help").alias("help", "h").usage("$0 <command> [options]").option("json", {
|
|
46
90
|
type: "boolean",
|
|
47
91
|
description: "Output in JSON format",
|
|
@@ -53,7 +97,8 @@ async function main() {
|
|
|
53
97
|
"llm",
|
|
54
98
|
"human"
|
|
55
99
|
],
|
|
56
|
-
|
|
100
|
+
default: "human",
|
|
101
|
+
description: "Output format (llm for AI agents, default for scripts)",
|
|
57
102
|
global: true
|
|
58
103
|
}).command(["list [path]", "ls [path]"], "List directory contents", (yargs$2) => yargs$2.positional("path", {
|
|
59
104
|
type: "string",
|
|
@@ -75,29 +120,32 @@ async function main() {
|
|
|
75
120
|
type: "string",
|
|
76
121
|
description: "Glob pattern to filter entries (e.g., *.ts, **/*.js)"
|
|
77
122
|
}), async (argv) => {
|
|
123
|
+
const view = getViewType(argv);
|
|
124
|
+
await maybeShowHeader(view);
|
|
78
125
|
const result = await require_ls.lsCommand(await require_runtime.createRuntime(), argv.path, {
|
|
79
126
|
maxDepth: argv.depth,
|
|
80
127
|
limit: argv.limit,
|
|
81
128
|
maxChildren: argv["max-children"],
|
|
82
129
|
pattern: argv.pattern
|
|
83
130
|
});
|
|
84
|
-
const view = getViewType(argv);
|
|
85
131
|
console.log(require_ls.formatLsOutput(result, view));
|
|
86
132
|
}).command("stat <path>", "Get file or directory info", (yargs$2) => yargs$2.positional("path", {
|
|
87
133
|
type: "string",
|
|
88
134
|
demandOption: true,
|
|
89
135
|
description: "Path to stat"
|
|
90
136
|
}), async (argv) => {
|
|
91
|
-
const result = await require_stat.statCommand(await require_runtime.createRuntime(), argv.path);
|
|
92
137
|
const view = getViewType(argv);
|
|
138
|
+
await maybeShowHeader(view);
|
|
139
|
+
const result = await require_stat.statCommand(await require_runtime.createRuntime(), argv.path);
|
|
93
140
|
console.log(require_stat.formatStatOutput(result, view));
|
|
94
141
|
}).command("read <path>", "Read file content", (yargs$2) => yargs$2.positional("path", {
|
|
95
142
|
type: "string",
|
|
96
143
|
demandOption: true,
|
|
97
144
|
description: "Path to read"
|
|
98
145
|
}), async (argv) => {
|
|
99
|
-
const result = await require_read.readCommand(await require_runtime.createRuntime(), argv.path);
|
|
100
146
|
const view = getViewType(argv);
|
|
147
|
+
await maybeShowHeader(view);
|
|
148
|
+
const result = await require_read.readCommand(await require_runtime.createRuntime(), argv.path);
|
|
101
149
|
console.log(require_read.formatReadOutput(result, view));
|
|
102
150
|
}).command("write <path>", "Write content to file (from --content or stdin)", (yargs$2) => yargs$2.positional("path", {
|
|
103
151
|
type: "string",
|
|
@@ -111,6 +159,8 @@ async function main() {
|
|
|
111
159
|
default: false,
|
|
112
160
|
description: "Append to file instead of overwrite"
|
|
113
161
|
}), async (argv) => {
|
|
162
|
+
const view = getViewType(argv);
|
|
163
|
+
await maybeShowHeader(view);
|
|
114
164
|
let content;
|
|
115
165
|
if (argv.content !== void 0) content = argv.content;
|
|
116
166
|
else {
|
|
@@ -119,7 +169,6 @@ async function main() {
|
|
|
119
169
|
content = Buffer.concat(chunks).toString("utf-8");
|
|
120
170
|
}
|
|
121
171
|
const result = await require_write.writeCommand(await require_runtime.createRuntime(), argv.path, content, { append: argv.append });
|
|
122
|
-
const view = getViewType(argv);
|
|
123
172
|
console.log(require_write.formatWriteOutput(result, view));
|
|
124
173
|
if (!result.success) process.exit(require_errors.ExitCode.RUNTIME_ERROR);
|
|
125
174
|
}).command("exec <path> [action]", "Execute operation on path", (yargs$2) => yargs$2.positional("path", {
|
|
@@ -134,14 +183,16 @@ async function main() {
|
|
|
134
183
|
type: "string",
|
|
135
184
|
description: "JSON parameters for the action"
|
|
136
185
|
}), async (argv) => {
|
|
186
|
+
const view = getViewType(argv);
|
|
187
|
+
await maybeShowHeader(view);
|
|
137
188
|
const params = argv.params ? JSON.parse(argv.params) : {};
|
|
138
189
|
const result = await require_exec.execCommand(await require_runtime.createRuntime(), argv.path, argv.action, params);
|
|
139
|
-
const view = getViewType(argv);
|
|
140
190
|
console.log(require_exec.formatExecOutput(result, view));
|
|
141
191
|
if (!result.success) process.exit(require_errors.ExitCode.RUNTIME_ERROR);
|
|
142
192
|
}).command("mount", "Manage mount configurations", (yargs$2) => yargs$2.command(["list", "ls"], "List all mounts", () => {}, async (argv) => {
|
|
143
|
-
const result = await require_mount.mountListCommand(process.cwd());
|
|
144
193
|
const view = getViewType(argv);
|
|
194
|
+
await maybeShowHeader(view);
|
|
195
|
+
const result = await require_mount.mountListCommand(process.cwd());
|
|
145
196
|
console.log(require_mount.formatMountListOutput(result.mounts, view));
|
|
146
197
|
}).command("add <path> <uri>", "Add a new mount (path=virtual path, uri=data source)", (yargs$3) => yargs$3.positional("path", {
|
|
147
198
|
type: "string",
|
|
@@ -155,11 +206,16 @@ async function main() {
|
|
|
155
206
|
type: "string",
|
|
156
207
|
description: "Human-readable description for this mount"
|
|
157
208
|
}), async (argv) => {
|
|
209
|
+
const view = getViewType(argv);
|
|
210
|
+
await maybeShowHeader(view);
|
|
158
211
|
const result = await require_mount.mountAddCommand(process.cwd(), argv.path, argv.uri, { description: argv.description });
|
|
159
|
-
if (
|
|
160
|
-
else if (result.success)
|
|
161
|
-
|
|
162
|
-
console.
|
|
212
|
+
if (view === "json") console.log(JSON.stringify(result, null, 2));
|
|
213
|
+
else if (result.success) {
|
|
214
|
+
const msg = view === "human" ? `${require_index.colors.success("Added mount")} ${require_index.colors.cyan(result.normalizedPath)}` : `Added mount ${result.normalizedPath}`;
|
|
215
|
+
console.log(msg);
|
|
216
|
+
} else {
|
|
217
|
+
const msg = view === "human" ? require_index.colors.error(result.message) : result.message;
|
|
218
|
+
console.error(msg);
|
|
163
219
|
process.exit(require_errors.ExitCode.RUNTIME_ERROR);
|
|
164
220
|
}
|
|
165
221
|
}).command(["remove <path>", "rm <path>"], "Remove a mount", (yargs$3) => yargs$3.positional("path", {
|
|
@@ -167,20 +223,33 @@ async function main() {
|
|
|
167
223
|
demandOption: true,
|
|
168
224
|
description: "Virtual path to remove (e.g., /src)"
|
|
169
225
|
}), async (argv) => {
|
|
226
|
+
const view = getViewType(argv);
|
|
227
|
+
await maybeShowHeader(view);
|
|
170
228
|
const result = await require_mount.mountRemoveCommand(process.cwd(), argv.path);
|
|
171
|
-
if (
|
|
172
|
-
else if (result.success)
|
|
173
|
-
|
|
174
|
-
console.
|
|
229
|
+
if (view === "json") console.log(JSON.stringify(result, null, 2));
|
|
230
|
+
else if (result.success) {
|
|
231
|
+
const msg = view === "human" ? `${require_index.colors.success("Removed mount")} ${require_index.colors.cyan(argv.path)}` : `Removed mount ${argv.path}`;
|
|
232
|
+
console.log(msg);
|
|
233
|
+
} else {
|
|
234
|
+
const msg = view === "human" ? require_index.colors.error(result.message) : result.message;
|
|
235
|
+
console.error(msg);
|
|
175
236
|
process.exit(require_errors.ExitCode.RUNTIME_ERROR);
|
|
176
237
|
}
|
|
177
238
|
}).command("validate", "Validate mount configuration", () => {}, async (argv) => {
|
|
239
|
+
const view = getViewType(argv);
|
|
240
|
+
await maybeShowHeader(view);
|
|
178
241
|
const result = await require_mount.mountValidateCommand(process.cwd());
|
|
179
|
-
if (
|
|
180
|
-
else if (result.valid)
|
|
181
|
-
|
|
182
|
-
console.
|
|
183
|
-
|
|
242
|
+
if (view === "json") console.log(JSON.stringify(result, null, 2));
|
|
243
|
+
else if (result.valid) {
|
|
244
|
+
const msg = view === "human" ? require_index.colors.success("Configuration is valid") : "Configuration is valid";
|
|
245
|
+
console.log(msg);
|
|
246
|
+
} else {
|
|
247
|
+
const titleMsg = view === "human" ? require_index.colors.error("Configuration has errors:") : "Configuration has errors:";
|
|
248
|
+
console.error(titleMsg);
|
|
249
|
+
for (const error of result.errors) {
|
|
250
|
+
const errMsg = view === "human" ? ` ${require_index.colors.dim("-")} ${require_index.colors.error(error)}` : ` - ${error}`;
|
|
251
|
+
console.error(errMsg);
|
|
252
|
+
}
|
|
184
253
|
process.exit(require_errors.ExitCode.RUNTIME_ERROR);
|
|
185
254
|
}
|
|
186
255
|
}).demandCommand(1, "Please specify a mount subcommand"), () => {}).command("explain [topic]", "Explain AFS concepts or AFS object", (yargs$2) => yargs$2.positional("topic", {
|
|
@@ -188,6 +257,7 @@ async function main() {
|
|
|
188
257
|
description: "Topic (mount, path, uri) or AFS path (e.g., /modules/src)"
|
|
189
258
|
}), async (argv) => {
|
|
190
259
|
const view = getViewType(argv);
|
|
260
|
+
await maybeShowHeader(view);
|
|
191
261
|
const topic = argv.topic;
|
|
192
262
|
if (topic?.startsWith("/")) {
|
|
193
263
|
const result = await require_explain.explainPathCommand(await require_runtime.createRuntime(), topic);
|
|
@@ -196,6 +266,54 @@ async function main() {
|
|
|
196
266
|
const result = await require_explain.explainCommand(process.cwd(), topic);
|
|
197
267
|
console.log(require_explain.formatExplainOutput(result, view));
|
|
198
268
|
}
|
|
269
|
+
}).command("serve", "Start HTTP server to expose AFS providers", (yargs$2) => yargs$2.option("host", {
|
|
270
|
+
type: "string",
|
|
271
|
+
default: "localhost",
|
|
272
|
+
description: "Host address to listen on"
|
|
273
|
+
}).option("port", {
|
|
274
|
+
type: "number",
|
|
275
|
+
default: 3e3,
|
|
276
|
+
description: "Port to listen on"
|
|
277
|
+
}).option("path", {
|
|
278
|
+
type: "string",
|
|
279
|
+
default: "/afs",
|
|
280
|
+
description: "Base path for the server"
|
|
281
|
+
}).option("readonly", {
|
|
282
|
+
type: "boolean",
|
|
283
|
+
default: false,
|
|
284
|
+
description: "Run in readonly mode (disable write operations)"
|
|
285
|
+
}).option("cors", {
|
|
286
|
+
type: "boolean",
|
|
287
|
+
default: false,
|
|
288
|
+
description: "Enable CORS support"
|
|
289
|
+
}).option("max-body", {
|
|
290
|
+
type: "number",
|
|
291
|
+
description: "Maximum request body size in bytes (default: 10MB)"
|
|
292
|
+
}), async (argv) => {
|
|
293
|
+
await maybeShowHeader(getViewType(argv));
|
|
294
|
+
const result = await require_serve.serveCommand({
|
|
295
|
+
host: argv.host,
|
|
296
|
+
port: argv.port,
|
|
297
|
+
path: argv.path,
|
|
298
|
+
readonly: argv.readonly,
|
|
299
|
+
cors: argv.cors,
|
|
300
|
+
maxBodySize: argv["max-body"]
|
|
301
|
+
});
|
|
302
|
+
console.log(require_serve.formatServeOutput(result));
|
|
303
|
+
await new Promise(() => {});
|
|
304
|
+
}).command("explore [path]", "Interactive TUI file explorer (PC Tools style)", (yargs$2) => yargs$2.positional("path", {
|
|
305
|
+
type: "string",
|
|
306
|
+
default: "/",
|
|
307
|
+
description: "Starting path to explore"
|
|
308
|
+
}), async (argv) => {
|
|
309
|
+
const configLoader = new require_loader.ConfigLoader();
|
|
310
|
+
const config = await configLoader.load(process.cwd());
|
|
311
|
+
await require_screen.createExplorerScreen({
|
|
312
|
+
runtime: await require_runtime.createRuntime(process.cwd(), { configLoader }),
|
|
313
|
+
startPath: argv.path,
|
|
314
|
+
version: require_version.VERSION,
|
|
315
|
+
mountCount: config.mounts.length
|
|
316
|
+
});
|
|
199
317
|
}).demandCommand(1, "Please specify a command").strict();
|
|
200
318
|
try {
|
|
201
319
|
await cli.parse();
|