@aigne/afs-cli 1.11.0-beta.1 → 1.11.0-beta.3
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 +63 -9
- package/dist/_virtual/rolldown_runtime.cjs +29 -0
- package/dist/cli.cjs +251 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.mjs +241 -19
- package/dist/cli.mjs.map +1 -0
- package/dist/commands/exec.cjs +46 -0
- package/dist/commands/exec.mjs +45 -0
- package/dist/commands/exec.mjs.map +1 -0
- package/dist/commands/explain.cjs +244 -0
- package/dist/commands/explain.mjs +242 -0
- package/dist/commands/explain.mjs.map +1 -0
- package/dist/commands/index.cjs +8 -0
- package/dist/commands/index.mjs +10 -0
- package/dist/commands/ls.cjs +141 -0
- package/dist/commands/ls.mjs +140 -0
- package/dist/commands/ls.mjs.map +1 -0
- package/dist/commands/mount.cjs +170 -0
- package/dist/commands/mount.mjs +166 -0
- package/dist/commands/mount.mjs.map +1 -0
- package/dist/commands/read.cjs +65 -0
- package/dist/commands/read.mjs +64 -0
- package/dist/commands/read.mjs.map +1 -0
- package/dist/commands/serve.cjs +141 -0
- package/dist/commands/serve.mjs +140 -0
- package/dist/commands/serve.mjs.map +1 -0
- package/dist/commands/stat.cjs +113 -0
- package/dist/commands/stat.mjs +112 -0
- package/dist/commands/stat.mjs.map +1 -0
- package/dist/commands/write.cjs +52 -0
- package/dist/commands/write.mjs +51 -0
- package/dist/commands/write.mjs.map +1 -0
- package/dist/config/env.cjs +46 -0
- package/dist/config/env.mjs +46 -0
- package/dist/config/env.mjs.map +1 -0
- package/dist/config/loader.cjs +171 -0
- package/dist/config/loader.mjs +169 -0
- package/dist/config/loader.mjs.map +1 -0
- package/dist/config/provider-factory.cjs +92 -0
- package/dist/config/provider-factory.mjs +93 -0
- package/dist/config/provider-factory.mjs.map +1 -0
- package/dist/config/schema.cjs +36 -0
- package/dist/config/schema.mjs +36 -0
- package/dist/config/schema.mjs.map +1 -0
- package/dist/config/uri-parser.cjs +92 -0
- package/dist/config/uri-parser.mjs +92 -0
- package/dist/config/uri-parser.mjs.map +1 -0
- package/dist/errors.cjs +29 -0
- package/dist/errors.mjs +28 -0
- package/dist/errors.mjs.map +1 -0
- package/dist/index.cjs +3 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.mts +1 -3
- package/dist/index.mjs +1 -1
- package/dist/runtime.cjs +82 -0
- package/dist/runtime.mjs +82 -0
- package/dist/runtime.mjs.map +1 -0
- package/dist/version.cjs +9 -0
- package/dist/version.d.cts +5 -0
- package/dist/version.d.cts.map +1 -0
- package/dist/version.d.mts +5 -0
- package/dist/version.d.mts.map +1 -0
- package/dist/version.mjs +9 -0
- package/dist/version.mjs.map +1 -0
- package/package.json +52 -11
- package/.turbo/turbo-build.log +0 -18
- package/.turbo/turbo-check-types.log +0 -4
- package/dist/version--p6A8sKX.mjs +0 -5
- package/src/cli.test.ts +0 -8
- package/src/cli.ts +0 -29
- package/src/index.ts +0 -7
- package/src/version.ts +0 -1
- package/tsconfig.json +0 -16
package/README.md
CHANGED
|
@@ -6,27 +6,81 @@ AFS 命令行工具
|
|
|
6
6
|
|
|
7
7
|
| 命令 | 功能 |
|
|
8
8
|
|------|------|
|
|
9
|
-
| `afs
|
|
10
|
-
| `afs
|
|
11
|
-
| `afs write <path
|
|
12
|
-
| `afs
|
|
9
|
+
| `afs list [path]` (别名: `ls`) | 列出目录内容 |
|
|
10
|
+
| `afs read <path>` | 读取文件内容 |
|
|
11
|
+
| `afs write <path> [--content]` | 写入文件 (--content 或 stdin) |
|
|
12
|
+
| `afs stat <path>` | 获取文件/目录信息 |
|
|
13
13
|
| `afs exec <path> <action>` | 执行操作 |
|
|
14
|
-
| `afs
|
|
14
|
+
| `afs mount list` (别名: `ls`) | 列出挂载配置 |
|
|
15
|
+
| `afs mount add <path> <uri>` | 添加挂载 |
|
|
16
|
+
| `afs mount remove <path>` (别名: `rm`) | 移除挂载 |
|
|
17
|
+
| `afs mount validate` | 验证挂载配置 |
|
|
18
|
+
| `afs explain [topic]` | 解释概念 (mount, uri, /path) |
|
|
19
|
+
| `afs serve` | 启动 HTTP 服务器暴露 AFS 提供者 |
|
|
20
|
+
|
|
21
|
+
## HTTP 服务器和远程挂载
|
|
22
|
+
|
|
23
|
+
### 启动 AFS HTTP 服务器
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# 启动服务器,暴露所有配置的挂载
|
|
27
|
+
afs serve
|
|
28
|
+
|
|
29
|
+
# 自定义主机和端口
|
|
30
|
+
afs serve --host 0.0.0.0 --port 8080
|
|
31
|
+
|
|
32
|
+
# 只读模式(禁用写入操作)
|
|
33
|
+
afs serve --readonly
|
|
34
|
+
|
|
35
|
+
# 启用 CORS 支持
|
|
36
|
+
afs serve --cors
|
|
37
|
+
|
|
38
|
+
# 自定义基础路径
|
|
39
|
+
afs serve --path /api/afs
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 挂载远程 AFS 服务器
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# 添加远程 HTTP 挂载
|
|
46
|
+
afs mount add /remote http://localhost:3000/afs
|
|
47
|
+
|
|
48
|
+
# 添加 HTTPS 挂载
|
|
49
|
+
afs mount add /api https://api.example.com/afs
|
|
50
|
+
|
|
51
|
+
# 带描述的挂载
|
|
52
|
+
afs mount add /remote http://localhost:3000/afs --description "Remote AFS server"
|
|
53
|
+
|
|
54
|
+
# 访问远程挂载
|
|
55
|
+
afs list /remote
|
|
56
|
+
afs read /remote/file.txt
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 支持的 URI 方案
|
|
60
|
+
|
|
61
|
+
| 方案 | 示例 | 说明 |
|
|
62
|
+
|------|------|------|
|
|
63
|
+
| `fs://` | `fs:///path/to/dir` | 本地文件系统 |
|
|
64
|
+
| `git://` | `git:///path/to/repo` | Git 仓库 |
|
|
65
|
+
| `sqlite://` | `sqlite:///path/to/db.sqlite` | SQLite 数据库 |
|
|
66
|
+
| `json://` | `json:///path/to/config.json` | JSON/YAML 文件 |
|
|
67
|
+
| `http://` | `http://localhost:3000/afs` | HTTP 远程 AFS |
|
|
68
|
+
| `https://` | `https://api.example.com/afs` | HTTPS 远程 AFS |
|
|
15
69
|
|
|
16
70
|
## 输出模式
|
|
17
71
|
|
|
18
72
|
```bash
|
|
19
73
|
# 默认: Machine Truth (LLM/脚本友好)
|
|
20
|
-
afs
|
|
74
|
+
afs list /modules/fs
|
|
21
75
|
|
|
22
76
|
# JSON 结构化输出
|
|
23
|
-
afs
|
|
77
|
+
afs list /modules/fs --json
|
|
24
78
|
|
|
25
79
|
# LLM 优化输出
|
|
26
|
-
afs
|
|
80
|
+
afs list /modules/fs --view=llm
|
|
27
81
|
|
|
28
82
|
# 人类友好输出
|
|
29
|
-
afs
|
|
83
|
+
afs list /modules/fs --view=human
|
|
30
84
|
```
|
|
31
85
|
|
|
32
86
|
## 运行模式
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
|
|
29
|
+
exports.__toESM = __toESM;
|
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
3
|
+
const require_version = require('./version.cjs');
|
|
4
|
+
const require_exec = require('./commands/exec.cjs');
|
|
5
|
+
const require_mount = require('./commands/mount.cjs');
|
|
6
|
+
const require_explain = require('./commands/explain.cjs');
|
|
7
|
+
const require_ls = require('./commands/ls.cjs');
|
|
8
|
+
const require_read = require('./commands/read.cjs');
|
|
9
|
+
const require_runtime = require('./runtime.cjs');
|
|
10
|
+
const require_serve = require('./commands/serve.cjs');
|
|
11
|
+
const require_stat = require('./commands/stat.cjs');
|
|
12
|
+
const require_write = require('./commands/write.cjs');
|
|
13
|
+
require('./commands/index.cjs');
|
|
14
|
+
const require_errors = require('./errors.cjs');
|
|
15
|
+
let yargs = require("yargs");
|
|
16
|
+
yargs = require_rolldown_runtime.__toESM(yargs);
|
|
17
|
+
let yargs_helpers = require("yargs/helpers");
|
|
18
|
+
|
|
19
|
+
//#region src/cli.ts
|
|
20
|
+
/**
|
|
21
|
+
* AFS CLI - Command Line Interface
|
|
22
|
+
*
|
|
23
|
+
* Commands:
|
|
24
|
+
* - afs mount list|ls List mount configurations
|
|
25
|
+
* - afs mount add <path> <uri> Add a mount
|
|
26
|
+
* - afs mount remove|rm <path> Remove a mount
|
|
27
|
+
* - afs mount validate Validate mount configuration
|
|
28
|
+
* - afs list|ls [path] List directory
|
|
29
|
+
* - afs stat <path> Get file/directory info
|
|
30
|
+
* - afs read <path> Read file content
|
|
31
|
+
* - afs write <path> Write file content (--content or stdin)
|
|
32
|
+
* - afs exec <path> <action> Execute operation
|
|
33
|
+
* - afs serve Start HTTP server to expose AFS
|
|
34
|
+
*
|
|
35
|
+
* Output modes:
|
|
36
|
+
* - Default: Machine Truth (LLM/script friendly)
|
|
37
|
+
* - --json: Structured JSON
|
|
38
|
+
* - --view=llm: LLM optimized output
|
|
39
|
+
* - --view=human: Human friendly format
|
|
40
|
+
*/
|
|
41
|
+
function getViewType(argv) {
|
|
42
|
+
if (argv.json) return "json";
|
|
43
|
+
if (argv.view) return argv.view;
|
|
44
|
+
return "default";
|
|
45
|
+
}
|
|
46
|
+
async function main() {
|
|
47
|
+
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", {
|
|
48
|
+
type: "boolean",
|
|
49
|
+
description: "Output in JSON format",
|
|
50
|
+
global: true
|
|
51
|
+
}).option("view", {
|
|
52
|
+
type: "string",
|
|
53
|
+
choices: [
|
|
54
|
+
"default",
|
|
55
|
+
"llm",
|
|
56
|
+
"human"
|
|
57
|
+
],
|
|
58
|
+
description: "Output view format",
|
|
59
|
+
global: true
|
|
60
|
+
}).command(["list [path]", "ls [path]"], "List directory contents", (yargs$2) => yargs$2.positional("path", {
|
|
61
|
+
type: "string",
|
|
62
|
+
default: "/",
|
|
63
|
+
description: "Path to list"
|
|
64
|
+
}).option("depth", {
|
|
65
|
+
type: "number",
|
|
66
|
+
default: 1,
|
|
67
|
+
description: "Maximum depth to list"
|
|
68
|
+
}).option("limit", {
|
|
69
|
+
alias: "n",
|
|
70
|
+
type: "number",
|
|
71
|
+
description: "Maximum number of entries to return"
|
|
72
|
+
}).option("max-children", {
|
|
73
|
+
type: "number",
|
|
74
|
+
description: "Maximum children per directory"
|
|
75
|
+
}).option("pattern", {
|
|
76
|
+
alias: "p",
|
|
77
|
+
type: "string",
|
|
78
|
+
description: "Glob pattern to filter entries (e.g., *.ts, **/*.js)"
|
|
79
|
+
}), async (argv) => {
|
|
80
|
+
const result = await require_ls.lsCommand(await require_runtime.createRuntime(), argv.path, {
|
|
81
|
+
maxDepth: argv.depth,
|
|
82
|
+
limit: argv.limit,
|
|
83
|
+
maxChildren: argv["max-children"],
|
|
84
|
+
pattern: argv.pattern
|
|
85
|
+
});
|
|
86
|
+
const view = getViewType(argv);
|
|
87
|
+
console.log(require_ls.formatLsOutput(result, view));
|
|
88
|
+
}).command("stat <path>", "Get file or directory info", (yargs$2) => yargs$2.positional("path", {
|
|
89
|
+
type: "string",
|
|
90
|
+
demandOption: true,
|
|
91
|
+
description: "Path to stat"
|
|
92
|
+
}), async (argv) => {
|
|
93
|
+
const result = await require_stat.statCommand(await require_runtime.createRuntime(), argv.path);
|
|
94
|
+
const view = getViewType(argv);
|
|
95
|
+
console.log(require_stat.formatStatOutput(result, view));
|
|
96
|
+
}).command("read <path>", "Read file content", (yargs$2) => yargs$2.positional("path", {
|
|
97
|
+
type: "string",
|
|
98
|
+
demandOption: true,
|
|
99
|
+
description: "Path to read"
|
|
100
|
+
}), async (argv) => {
|
|
101
|
+
const result = await require_read.readCommand(await require_runtime.createRuntime(), argv.path);
|
|
102
|
+
const view = getViewType(argv);
|
|
103
|
+
console.log(require_read.formatReadOutput(result, view));
|
|
104
|
+
}).command("write <path>", "Write content to file (from --content or stdin)", (yargs$2) => yargs$2.positional("path", {
|
|
105
|
+
type: "string",
|
|
106
|
+
demandOption: true,
|
|
107
|
+
description: "Path to write"
|
|
108
|
+
}).option("content", {
|
|
109
|
+
type: "string",
|
|
110
|
+
description: "Content to write (if not provided, reads from stdin)"
|
|
111
|
+
}).option("append", {
|
|
112
|
+
type: "boolean",
|
|
113
|
+
default: false,
|
|
114
|
+
description: "Append to file instead of overwrite"
|
|
115
|
+
}), async (argv) => {
|
|
116
|
+
let content;
|
|
117
|
+
if (argv.content !== void 0) content = argv.content;
|
|
118
|
+
else {
|
|
119
|
+
const chunks = [];
|
|
120
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
121
|
+
content = Buffer.concat(chunks).toString("utf-8");
|
|
122
|
+
}
|
|
123
|
+
const result = await require_write.writeCommand(await require_runtime.createRuntime(), argv.path, content, { append: argv.append });
|
|
124
|
+
const view = getViewType(argv);
|
|
125
|
+
console.log(require_write.formatWriteOutput(result, view));
|
|
126
|
+
if (!result.success) process.exit(require_errors.ExitCode.RUNTIME_ERROR);
|
|
127
|
+
}).command("exec <path> [action]", "Execute operation on path", (yargs$2) => yargs$2.positional("path", {
|
|
128
|
+
type: "string",
|
|
129
|
+
demandOption: true,
|
|
130
|
+
description: "Path to execute on"
|
|
131
|
+
}).positional("action", {
|
|
132
|
+
type: "string",
|
|
133
|
+
default: "default",
|
|
134
|
+
description: "Action to execute"
|
|
135
|
+
}).option("params", {
|
|
136
|
+
type: "string",
|
|
137
|
+
description: "JSON parameters for the action"
|
|
138
|
+
}), async (argv) => {
|
|
139
|
+
const params = argv.params ? JSON.parse(argv.params) : {};
|
|
140
|
+
const result = await require_exec.execCommand(await require_runtime.createRuntime(), argv.path, argv.action, params);
|
|
141
|
+
const view = getViewType(argv);
|
|
142
|
+
console.log(require_exec.formatExecOutput(result, view));
|
|
143
|
+
if (!result.success) process.exit(require_errors.ExitCode.RUNTIME_ERROR);
|
|
144
|
+
}).command("mount", "Manage mount configurations", (yargs$2) => yargs$2.command(["list", "ls"], "List all mounts", () => {}, async (argv) => {
|
|
145
|
+
const result = await require_mount.mountListCommand(process.cwd());
|
|
146
|
+
const view = getViewType(argv);
|
|
147
|
+
console.log(require_mount.formatMountListOutput(result.mounts, view));
|
|
148
|
+
}).command("add <path> <uri>", "Add a new mount (path=virtual path, uri=data source)", (yargs$3) => yargs$3.positional("path", {
|
|
149
|
+
type: "string",
|
|
150
|
+
demandOption: true,
|
|
151
|
+
description: "Virtual path in AFS namespace (e.g., /src, /data)"
|
|
152
|
+
}).positional("uri", {
|
|
153
|
+
type: "string",
|
|
154
|
+
demandOption: true,
|
|
155
|
+
description: "Data source URI: fs:///local/path, git://repo, sqlite:///db.sqlite"
|
|
156
|
+
}).option("description", {
|
|
157
|
+
type: "string",
|
|
158
|
+
description: "Human-readable description for this mount"
|
|
159
|
+
}), async (argv) => {
|
|
160
|
+
const result = await require_mount.mountAddCommand(process.cwd(), argv.path, argv.uri, { description: argv.description });
|
|
161
|
+
if (getViewType(argv) === "json") console.log(JSON.stringify(result, null, 2));
|
|
162
|
+
else if (result.success) console.log(`Added mount ${argv.path}`);
|
|
163
|
+
else {
|
|
164
|
+
console.error(result.message);
|
|
165
|
+
process.exit(require_errors.ExitCode.RUNTIME_ERROR);
|
|
166
|
+
}
|
|
167
|
+
}).command(["remove <path>", "rm <path>"], "Remove a mount", (yargs$3) => yargs$3.positional("path", {
|
|
168
|
+
type: "string",
|
|
169
|
+
demandOption: true,
|
|
170
|
+
description: "Virtual path to remove (e.g., /src)"
|
|
171
|
+
}), async (argv) => {
|
|
172
|
+
const result = await require_mount.mountRemoveCommand(process.cwd(), argv.path);
|
|
173
|
+
if (getViewType(argv) === "json") console.log(JSON.stringify(result, null, 2));
|
|
174
|
+
else if (result.success) console.log(`Removed mount ${argv.path}`);
|
|
175
|
+
else {
|
|
176
|
+
console.error(result.message);
|
|
177
|
+
process.exit(require_errors.ExitCode.RUNTIME_ERROR);
|
|
178
|
+
}
|
|
179
|
+
}).command("validate", "Validate mount configuration", () => {}, async (argv) => {
|
|
180
|
+
const result = await require_mount.mountValidateCommand(process.cwd());
|
|
181
|
+
if (getViewType(argv) === "json") console.log(JSON.stringify(result, null, 2));
|
|
182
|
+
else if (result.valid) console.log("Configuration is valid");
|
|
183
|
+
else {
|
|
184
|
+
console.error("Configuration has errors:");
|
|
185
|
+
for (const error of result.errors) console.error(` - ${error}`);
|
|
186
|
+
process.exit(require_errors.ExitCode.RUNTIME_ERROR);
|
|
187
|
+
}
|
|
188
|
+
}).demandCommand(1, "Please specify a mount subcommand"), () => {}).command("explain [topic]", "Explain AFS concepts or AFS object", (yargs$2) => yargs$2.positional("topic", {
|
|
189
|
+
type: "string",
|
|
190
|
+
description: "Topic (mount, path, uri) or AFS path (e.g., /modules/src)"
|
|
191
|
+
}), async (argv) => {
|
|
192
|
+
const view = getViewType(argv);
|
|
193
|
+
const topic = argv.topic;
|
|
194
|
+
if (topic?.startsWith("/")) {
|
|
195
|
+
const result = await require_explain.explainPathCommand(await require_runtime.createRuntime(), topic);
|
|
196
|
+
console.log(require_explain.formatPathExplainOutput(result, view));
|
|
197
|
+
} else {
|
|
198
|
+
const result = await require_explain.explainCommand(process.cwd(), topic);
|
|
199
|
+
console.log(require_explain.formatExplainOutput(result, view));
|
|
200
|
+
}
|
|
201
|
+
}).command("serve", "Start HTTP server to expose AFS providers", (yargs$2) => yargs$2.option("host", {
|
|
202
|
+
type: "string",
|
|
203
|
+
default: "localhost",
|
|
204
|
+
description: "Host address to listen on"
|
|
205
|
+
}).option("port", {
|
|
206
|
+
type: "number",
|
|
207
|
+
default: 3e3,
|
|
208
|
+
description: "Port to listen on"
|
|
209
|
+
}).option("path", {
|
|
210
|
+
type: "string",
|
|
211
|
+
default: "/afs",
|
|
212
|
+
description: "Base path for the server"
|
|
213
|
+
}).option("readonly", {
|
|
214
|
+
type: "boolean",
|
|
215
|
+
default: false,
|
|
216
|
+
description: "Run in readonly mode (disable write operations)"
|
|
217
|
+
}).option("cors", {
|
|
218
|
+
type: "boolean",
|
|
219
|
+
default: false,
|
|
220
|
+
description: "Enable CORS support"
|
|
221
|
+
}).option("max-body", {
|
|
222
|
+
type: "number",
|
|
223
|
+
description: "Maximum request body size in bytes (default: 10MB)"
|
|
224
|
+
}), async (argv) => {
|
|
225
|
+
const result = await require_serve.serveCommand({
|
|
226
|
+
host: argv.host,
|
|
227
|
+
port: argv.port,
|
|
228
|
+
path: argv.path,
|
|
229
|
+
readonly: argv.readonly,
|
|
230
|
+
cors: argv.cors,
|
|
231
|
+
maxBodySize: argv["max-body"]
|
|
232
|
+
});
|
|
233
|
+
console.log(require_serve.formatServeOutput(result));
|
|
234
|
+
await new Promise(() => {});
|
|
235
|
+
}).demandCommand(1, "Please specify a command").strict();
|
|
236
|
+
try {
|
|
237
|
+
await cli.parse();
|
|
238
|
+
} catch (error) {
|
|
239
|
+
if (error instanceof require_errors.CLIError) {
|
|
240
|
+
console.error(error.message);
|
|
241
|
+
process.exit(error.exitCode);
|
|
242
|
+
}
|
|
243
|
+
throw error;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
main().catch((error) => {
|
|
247
|
+
console.error("Fatal error:", error.message);
|
|
248
|
+
process.exit(require_errors.ExitCode.RUNTIME_ERROR);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
//#endregion
|
package/dist/cli.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.mjs
CHANGED
|
@@ -1,29 +1,251 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { VERSION } from "./version.mjs";
|
|
3
|
+
import { execCommand, formatExecOutput } from "./commands/exec.mjs";
|
|
4
|
+
import { formatMountListOutput, mountAddCommand, mountListCommand, mountRemoveCommand, mountValidateCommand } from "./commands/mount.mjs";
|
|
5
|
+
import { explainCommand, explainPathCommand, formatExplainOutput, formatPathExplainOutput } from "./commands/explain.mjs";
|
|
6
|
+
import { formatLsOutput, lsCommand } from "./commands/ls.mjs";
|
|
7
|
+
import { formatReadOutput, readCommand } from "./commands/read.mjs";
|
|
8
|
+
import { createRuntime } from "./runtime.mjs";
|
|
9
|
+
import { formatServeOutput, serveCommand } from "./commands/serve.mjs";
|
|
10
|
+
import { formatStatOutput, statCommand } from "./commands/stat.mjs";
|
|
11
|
+
import { formatWriteOutput, writeCommand } from "./commands/write.mjs";
|
|
12
|
+
import "./commands/index.mjs";
|
|
13
|
+
import { CLIError, ExitCode } from "./errors.mjs";
|
|
14
|
+
import yargs from "yargs";
|
|
15
|
+
import { hideBin } from "yargs/helpers";
|
|
3
16
|
|
|
4
17
|
//#region src/cli.ts
|
|
5
18
|
/**
|
|
6
19
|
* AFS CLI - Command Line Interface
|
|
7
20
|
*
|
|
8
|
-
*
|
|
9
|
-
* - afs ls
|
|
10
|
-
* - afs
|
|
11
|
-
* - afs
|
|
12
|
-
* - afs
|
|
13
|
-
* - afs
|
|
14
|
-
* - afs
|
|
21
|
+
* Commands:
|
|
22
|
+
* - afs mount list|ls List mount configurations
|
|
23
|
+
* - afs mount add <path> <uri> Add a mount
|
|
24
|
+
* - afs mount remove|rm <path> Remove a mount
|
|
25
|
+
* - afs mount validate Validate mount configuration
|
|
26
|
+
* - afs list|ls [path] List directory
|
|
27
|
+
* - afs stat <path> Get file/directory info
|
|
28
|
+
* - afs read <path> Read file content
|
|
29
|
+
* - afs write <path> Write file content (--content or stdin)
|
|
30
|
+
* - afs exec <path> <action> Execute operation
|
|
31
|
+
* - afs serve Start HTTP server to expose AFS
|
|
15
32
|
*
|
|
16
|
-
*
|
|
17
|
-
* -
|
|
18
|
-
* - --json:
|
|
19
|
-
* - --view=llm: LLM
|
|
20
|
-
* - --view=human:
|
|
21
|
-
*
|
|
22
|
-
* 运行模式:
|
|
23
|
-
* - 直接模式 (默认): 直接调用 @aigne/afs
|
|
24
|
-
* - daemon 模式 (--daemon): 通过 afsd 代理
|
|
33
|
+
* Output modes:
|
|
34
|
+
* - Default: Machine Truth (LLM/script friendly)
|
|
35
|
+
* - --json: Structured JSON
|
|
36
|
+
* - --view=llm: LLM optimized output
|
|
37
|
+
* - --view=human: Human friendly format
|
|
25
38
|
*/
|
|
26
|
-
|
|
39
|
+
function getViewType(argv) {
|
|
40
|
+
if (argv.json) return "json";
|
|
41
|
+
if (argv.view) return argv.view;
|
|
42
|
+
return "default";
|
|
43
|
+
}
|
|
44
|
+
async function main() {
|
|
45
|
+
const cli = yargs(hideBin(process.argv)).scriptName("afs").version(VERSION).alias("version", "V").help("help").alias("help", "h").usage("$0 <command> [options]").option("json", {
|
|
46
|
+
type: "boolean",
|
|
47
|
+
description: "Output in JSON format",
|
|
48
|
+
global: true
|
|
49
|
+
}).option("view", {
|
|
50
|
+
type: "string",
|
|
51
|
+
choices: [
|
|
52
|
+
"default",
|
|
53
|
+
"llm",
|
|
54
|
+
"human"
|
|
55
|
+
],
|
|
56
|
+
description: "Output view format",
|
|
57
|
+
global: true
|
|
58
|
+
}).command(["list [path]", "ls [path]"], "List directory contents", (yargs$1) => yargs$1.positional("path", {
|
|
59
|
+
type: "string",
|
|
60
|
+
default: "/",
|
|
61
|
+
description: "Path to list"
|
|
62
|
+
}).option("depth", {
|
|
63
|
+
type: "number",
|
|
64
|
+
default: 1,
|
|
65
|
+
description: "Maximum depth to list"
|
|
66
|
+
}).option("limit", {
|
|
67
|
+
alias: "n",
|
|
68
|
+
type: "number",
|
|
69
|
+
description: "Maximum number of entries to return"
|
|
70
|
+
}).option("max-children", {
|
|
71
|
+
type: "number",
|
|
72
|
+
description: "Maximum children per directory"
|
|
73
|
+
}).option("pattern", {
|
|
74
|
+
alias: "p",
|
|
75
|
+
type: "string",
|
|
76
|
+
description: "Glob pattern to filter entries (e.g., *.ts, **/*.js)"
|
|
77
|
+
}), async (argv) => {
|
|
78
|
+
const result = await lsCommand(await createRuntime(), argv.path, {
|
|
79
|
+
maxDepth: argv.depth,
|
|
80
|
+
limit: argv.limit,
|
|
81
|
+
maxChildren: argv["max-children"],
|
|
82
|
+
pattern: argv.pattern
|
|
83
|
+
});
|
|
84
|
+
const view = getViewType(argv);
|
|
85
|
+
console.log(formatLsOutput(result, view));
|
|
86
|
+
}).command("stat <path>", "Get file or directory info", (yargs$1) => yargs$1.positional("path", {
|
|
87
|
+
type: "string",
|
|
88
|
+
demandOption: true,
|
|
89
|
+
description: "Path to stat"
|
|
90
|
+
}), async (argv) => {
|
|
91
|
+
const result = await statCommand(await createRuntime(), argv.path);
|
|
92
|
+
const view = getViewType(argv);
|
|
93
|
+
console.log(formatStatOutput(result, view));
|
|
94
|
+
}).command("read <path>", "Read file content", (yargs$1) => yargs$1.positional("path", {
|
|
95
|
+
type: "string",
|
|
96
|
+
demandOption: true,
|
|
97
|
+
description: "Path to read"
|
|
98
|
+
}), async (argv) => {
|
|
99
|
+
const result = await readCommand(await createRuntime(), argv.path);
|
|
100
|
+
const view = getViewType(argv);
|
|
101
|
+
console.log(formatReadOutput(result, view));
|
|
102
|
+
}).command("write <path>", "Write content to file (from --content or stdin)", (yargs$1) => yargs$1.positional("path", {
|
|
103
|
+
type: "string",
|
|
104
|
+
demandOption: true,
|
|
105
|
+
description: "Path to write"
|
|
106
|
+
}).option("content", {
|
|
107
|
+
type: "string",
|
|
108
|
+
description: "Content to write (if not provided, reads from stdin)"
|
|
109
|
+
}).option("append", {
|
|
110
|
+
type: "boolean",
|
|
111
|
+
default: false,
|
|
112
|
+
description: "Append to file instead of overwrite"
|
|
113
|
+
}), async (argv) => {
|
|
114
|
+
let content;
|
|
115
|
+
if (argv.content !== void 0) content = argv.content;
|
|
116
|
+
else {
|
|
117
|
+
const chunks = [];
|
|
118
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
119
|
+
content = Buffer.concat(chunks).toString("utf-8");
|
|
120
|
+
}
|
|
121
|
+
const result = await writeCommand(await createRuntime(), argv.path, content, { append: argv.append });
|
|
122
|
+
const view = getViewType(argv);
|
|
123
|
+
console.log(formatWriteOutput(result, view));
|
|
124
|
+
if (!result.success) process.exit(ExitCode.RUNTIME_ERROR);
|
|
125
|
+
}).command("exec <path> [action]", "Execute operation on path", (yargs$1) => yargs$1.positional("path", {
|
|
126
|
+
type: "string",
|
|
127
|
+
demandOption: true,
|
|
128
|
+
description: "Path to execute on"
|
|
129
|
+
}).positional("action", {
|
|
130
|
+
type: "string",
|
|
131
|
+
default: "default",
|
|
132
|
+
description: "Action to execute"
|
|
133
|
+
}).option("params", {
|
|
134
|
+
type: "string",
|
|
135
|
+
description: "JSON parameters for the action"
|
|
136
|
+
}), async (argv) => {
|
|
137
|
+
const params = argv.params ? JSON.parse(argv.params) : {};
|
|
138
|
+
const result = await execCommand(await createRuntime(), argv.path, argv.action, params);
|
|
139
|
+
const view = getViewType(argv);
|
|
140
|
+
console.log(formatExecOutput(result, view));
|
|
141
|
+
if (!result.success) process.exit(ExitCode.RUNTIME_ERROR);
|
|
142
|
+
}).command("mount", "Manage mount configurations", (yargs$1) => yargs$1.command(["list", "ls"], "List all mounts", () => {}, async (argv) => {
|
|
143
|
+
const result = await mountListCommand(process.cwd());
|
|
144
|
+
const view = getViewType(argv);
|
|
145
|
+
console.log(formatMountListOutput(result.mounts, view));
|
|
146
|
+
}).command("add <path> <uri>", "Add a new mount (path=virtual path, uri=data source)", (yargs$2) => yargs$2.positional("path", {
|
|
147
|
+
type: "string",
|
|
148
|
+
demandOption: true,
|
|
149
|
+
description: "Virtual path in AFS namespace (e.g., /src, /data)"
|
|
150
|
+
}).positional("uri", {
|
|
151
|
+
type: "string",
|
|
152
|
+
demandOption: true,
|
|
153
|
+
description: "Data source URI: fs:///local/path, git://repo, sqlite:///db.sqlite"
|
|
154
|
+
}).option("description", {
|
|
155
|
+
type: "string",
|
|
156
|
+
description: "Human-readable description for this mount"
|
|
157
|
+
}), async (argv) => {
|
|
158
|
+
const result = await mountAddCommand(process.cwd(), argv.path, argv.uri, { description: argv.description });
|
|
159
|
+
if (getViewType(argv) === "json") console.log(JSON.stringify(result, null, 2));
|
|
160
|
+
else if (result.success) console.log(`Added mount ${argv.path}`);
|
|
161
|
+
else {
|
|
162
|
+
console.error(result.message);
|
|
163
|
+
process.exit(ExitCode.RUNTIME_ERROR);
|
|
164
|
+
}
|
|
165
|
+
}).command(["remove <path>", "rm <path>"], "Remove a mount", (yargs$2) => yargs$2.positional("path", {
|
|
166
|
+
type: "string",
|
|
167
|
+
demandOption: true,
|
|
168
|
+
description: "Virtual path to remove (e.g., /src)"
|
|
169
|
+
}), async (argv) => {
|
|
170
|
+
const result = await mountRemoveCommand(process.cwd(), argv.path);
|
|
171
|
+
if (getViewType(argv) === "json") console.log(JSON.stringify(result, null, 2));
|
|
172
|
+
else if (result.success) console.log(`Removed mount ${argv.path}`);
|
|
173
|
+
else {
|
|
174
|
+
console.error(result.message);
|
|
175
|
+
process.exit(ExitCode.RUNTIME_ERROR);
|
|
176
|
+
}
|
|
177
|
+
}).command("validate", "Validate mount configuration", () => {}, async (argv) => {
|
|
178
|
+
const result = await mountValidateCommand(process.cwd());
|
|
179
|
+
if (getViewType(argv) === "json") console.log(JSON.stringify(result, null, 2));
|
|
180
|
+
else if (result.valid) console.log("Configuration is valid");
|
|
181
|
+
else {
|
|
182
|
+
console.error("Configuration has errors:");
|
|
183
|
+
for (const error of result.errors) console.error(` - ${error}`);
|
|
184
|
+
process.exit(ExitCode.RUNTIME_ERROR);
|
|
185
|
+
}
|
|
186
|
+
}).demandCommand(1, "Please specify a mount subcommand"), () => {}).command("explain [topic]", "Explain AFS concepts or AFS object", (yargs$1) => yargs$1.positional("topic", {
|
|
187
|
+
type: "string",
|
|
188
|
+
description: "Topic (mount, path, uri) or AFS path (e.g., /modules/src)"
|
|
189
|
+
}), async (argv) => {
|
|
190
|
+
const view = getViewType(argv);
|
|
191
|
+
const topic = argv.topic;
|
|
192
|
+
if (topic?.startsWith("/")) {
|
|
193
|
+
const result = await explainPathCommand(await createRuntime(), topic);
|
|
194
|
+
console.log(formatPathExplainOutput(result, view));
|
|
195
|
+
} else {
|
|
196
|
+
const result = await explainCommand(process.cwd(), topic);
|
|
197
|
+
console.log(formatExplainOutput(result, view));
|
|
198
|
+
}
|
|
199
|
+
}).command("serve", "Start HTTP server to expose AFS providers", (yargs$1) => yargs$1.option("host", {
|
|
200
|
+
type: "string",
|
|
201
|
+
default: "localhost",
|
|
202
|
+
description: "Host address to listen on"
|
|
203
|
+
}).option("port", {
|
|
204
|
+
type: "number",
|
|
205
|
+
default: 3e3,
|
|
206
|
+
description: "Port to listen on"
|
|
207
|
+
}).option("path", {
|
|
208
|
+
type: "string",
|
|
209
|
+
default: "/afs",
|
|
210
|
+
description: "Base path for the server"
|
|
211
|
+
}).option("readonly", {
|
|
212
|
+
type: "boolean",
|
|
213
|
+
default: false,
|
|
214
|
+
description: "Run in readonly mode (disable write operations)"
|
|
215
|
+
}).option("cors", {
|
|
216
|
+
type: "boolean",
|
|
217
|
+
default: false,
|
|
218
|
+
description: "Enable CORS support"
|
|
219
|
+
}).option("max-body", {
|
|
220
|
+
type: "number",
|
|
221
|
+
description: "Maximum request body size in bytes (default: 10MB)"
|
|
222
|
+
}), async (argv) => {
|
|
223
|
+
const result = await serveCommand({
|
|
224
|
+
host: argv.host,
|
|
225
|
+
port: argv.port,
|
|
226
|
+
path: argv.path,
|
|
227
|
+
readonly: argv.readonly,
|
|
228
|
+
cors: argv.cors,
|
|
229
|
+
maxBodySize: argv["max-body"]
|
|
230
|
+
});
|
|
231
|
+
console.log(formatServeOutput(result));
|
|
232
|
+
await new Promise(() => {});
|
|
233
|
+
}).demandCommand(1, "Please specify a command").strict();
|
|
234
|
+
try {
|
|
235
|
+
await cli.parse();
|
|
236
|
+
} catch (error) {
|
|
237
|
+
if (error instanceof CLIError) {
|
|
238
|
+
console.error(error.message);
|
|
239
|
+
process.exit(error.exitCode);
|
|
240
|
+
}
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
main().catch((error) => {
|
|
245
|
+
console.error("Fatal error:", error.message);
|
|
246
|
+
process.exit(ExitCode.RUNTIME_ERROR);
|
|
247
|
+
});
|
|
27
248
|
|
|
28
249
|
//#endregion
|
|
29
|
-
export { };
|
|
250
|
+
export { };
|
|
251
|
+
//# sourceMappingURL=cli.mjs.map
|