pdlab-cli 0.1.1 → 0.2.0
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 +62 -5
- package/dist/index.js +436 -127
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,7 +17,13 @@ npm install -g pdlab-cli
|
|
|
17
17
|
## 快速开始
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
|
|
20
|
+
pdlab login
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
默认连官方部署 `https://1836.online`,装完直接就能用。
|
|
24
|
+
自建实例才需要指定地址,指定过一次之后会记在配置文件里:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
21
27
|
pdlab login --api-url https://your-1836-instance.example.com
|
|
22
28
|
```
|
|
23
29
|
|
|
@@ -27,6 +33,7 @@ pdlab login --api-url https://your-1836-instance.example.com
|
|
|
27
33
|
```bash
|
|
28
34
|
pdlab whoami # 看看当前是谁
|
|
29
35
|
pdlab project list # 列出项目
|
|
36
|
+
pdlab schema # 一次性 JSON 输出全部命令、参数、权限要求、示例和退出码含义——给 agent/脚本用
|
|
30
37
|
```
|
|
31
38
|
|
|
32
39
|
## 命令
|
|
@@ -38,20 +45,36 @@ pdlab project list # 列出项目
|
|
|
38
45
|
| `pdlab logout` | 清除本地凭证(不撤销服务端的,见下方「撤销凭证」) |
|
|
39
46
|
| `pdlab whoami` | 查看当前登录账号 |
|
|
40
47
|
| `pdlab config get` / `set api-url <url>` | 查看/修改本地配置 |
|
|
48
|
+
| `pdlab schema` | JSON 输出完整命令树 + 权限要求 + 示例 + 退出码含义 |
|
|
41
49
|
| `pdlab project list \| get \| create \| update \| delete` | 项目的增删改查 |
|
|
50
|
+
| `pdlab project join \| leave <id>` | 报名共建 / 撤回申请或退出共建 |
|
|
51
|
+
| `pdlab project member review \| set-role \| remove <projectId> <userId>` | 审核报名、设置协作者角色、移除参与者(仅项目发起人本人) |
|
|
52
|
+
| `pdlab project revenue <id>` | 查看项目的积分分成明细(只读) |
|
|
42
53
|
| `pdlab post list \| get \| create \| update \| delete` | 内容的增删改查 |
|
|
54
|
+
| `pdlab post review <id> --action approve\|reject` | 审核一条待审内容 |
|
|
43
55
|
|
|
44
|
-
任何命令加 `--help`
|
|
56
|
+
任何命令加 `--help` 看具体参数——示例已经直接打在 `--help` 末尾,不用等一次报错才能看到。
|
|
45
57
|
|
|
46
58
|
### 例子
|
|
47
59
|
|
|
48
60
|
```bash
|
|
49
|
-
#
|
|
61
|
+
# 按状态 / 关键词 / 分类标签筛选项目,翻页
|
|
50
62
|
pdlab project list --status active
|
|
63
|
+
pdlab project list --q "钠电"
|
|
64
|
+
pdlab project list --taxonomy tax_1 --taxonomy tax_2 # 可重复传,多个取交集
|
|
65
|
+
pdlab project list --limit 10 --cursor <上一页返回的 nextCursor>
|
|
51
66
|
|
|
52
67
|
# 创建项目(需要项目创建权限,即「1836发起人」角色)
|
|
53
68
|
pdlab project create --title "钠电储能原型" --description "第一阶段验证"
|
|
54
69
|
|
|
70
|
+
# 报名共建 / 退出
|
|
71
|
+
pdlab project join proj_123
|
|
72
|
+
pdlab project leave proj_123
|
|
73
|
+
|
|
74
|
+
# 项目发起人审核报名、提拔协作者
|
|
75
|
+
pdlab project member review proj_123 user_456 --status approved
|
|
76
|
+
pdlab project member set-role proj_123 user_456 --role maintainer
|
|
77
|
+
|
|
55
78
|
# 往自己参与的项目发布内容(共建者发布后进待审队列)
|
|
56
79
|
pdlab post create \
|
|
57
80
|
--project-id <项目 id> \
|
|
@@ -61,8 +84,40 @@ pdlab post create \
|
|
|
61
84
|
|
|
62
85
|
# 只看某个项目下的内容
|
|
63
86
|
pdlab post list --project-id <项目 id>
|
|
87
|
+
|
|
88
|
+
# 审核待审内容(需要 content:review 权限)
|
|
89
|
+
pdlab post review post_123 --action approve
|
|
90
|
+
pdlab post review post_123 --action reject --comment "缺少数据来源,请补充引用"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 分页
|
|
94
|
+
|
|
95
|
+
`project list` / `post list` 默认单页 30 条(上限 100),响应里的 `nextCursor` 非 `null`
|
|
96
|
+
就表示还有下一页,把它传给下一次调用的 `--cursor` 继续翻页;`nextCursor` 为 `null`
|
|
97
|
+
表示已经是最后一页。CLI 不会替你自动拉全量——那样一次调用可能悄悄发出几十次请求。
|
|
98
|
+
|
|
99
|
+
### 报错与退出码
|
|
100
|
+
|
|
101
|
+
失败时,一个 JSON 对象会打到 stderr(不是人类可读的长句),方便脚本/agent 解析:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{ "error": "无权限执行此操作", "code": "forbidden", "status": 403 }
|
|
64
105
|
```
|
|
65
106
|
|
|
107
|
+
校验类错误还会带上 `fields`(哪个字段、什么问题)和 `hint`(对应命令的示例)。
|
|
108
|
+
退出码和 `code` 一一对应,`pdlab schema` 的 `exitCodes` 字段里也有同一份:
|
|
109
|
+
|
|
110
|
+
| 退出码 | `code` | 含义 | 建议的处理 |
|
|
111
|
+
|---|---|---|---|
|
|
112
|
+
| 0 | — | 成功 | — |
|
|
113
|
+
| 2 | `validation` | 参数校验失败(本地或服务端) | 按 `fields`/`hint` 改参数重试 |
|
|
114
|
+
| 3 | `unauthenticated` | 未登录或 token 已失效 | 跑 `pdlab login` |
|
|
115
|
+
| 4 | `forbidden` | 无权限 | 不要重试,告知用户 |
|
|
116
|
+
| 5 | `not_found` | 资源不存在 | 检查 id 是否正确 |
|
|
117
|
+
| 6 | `conflict` | 状态冲突(如重复审核) | 不要重试,状态已经变了 |
|
|
118
|
+
| 7 | `network` | 连不上 API 服务器 | 检查 `--api-url`/网络后重试 |
|
|
119
|
+
| 1 | `unknown` / 未分类 | 其他 | 按错误信息人工排查 |
|
|
120
|
+
|
|
66
121
|
## 配置
|
|
67
122
|
|
|
68
123
|
配置存在 `~/.pdlab/config.json`(目录 `0700`、文件 `0600`):
|
|
@@ -71,8 +126,10 @@ pdlab post list --project-id <项目 id>
|
|
|
71
126
|
{ "apiUrl": "https://your-1836-instance.example.com", "token": "pdlab_…" }
|
|
72
127
|
```
|
|
73
128
|
|
|
74
|
-
API 地址的解析顺序:`--api-url` 参数 > `PDLAB_API_URL` 环境变量 >
|
|
75
|
-
|
|
129
|
+
API 地址的解析顺序:`--api-url` 参数 > `PDLAB_API_URL` 环境变量 > 配置文件 > 默认地址
|
|
130
|
+
(`https://1836.online`)。所有命令都支持 `--api-url`,
|
|
131
|
+
包括 `project` / `post` 这些资源命令。`pdlab config get` 会同时打出配置文件里写了什么、
|
|
132
|
+
以及这次实际会用哪个地址。
|
|
76
133
|
|
|
77
134
|
读命令(`project list` / `get`、`post list` / `get`)会在**已登录时带上凭证**,
|
|
78
135
|
可见范围因此按你的身份走:有审核权限才能 `post list --status pending`,
|
package/dist/index.js
CHANGED
|
@@ -35,8 +35,20 @@ var import_open = __toESM(require("open"));
|
|
|
35
35
|
var import_fs = require("fs");
|
|
36
36
|
var import_os = require("os");
|
|
37
37
|
var import_path = require("path");
|
|
38
|
+
|
|
39
|
+
// src/cli-error.ts
|
|
40
|
+
var CliError = class extends Error {
|
|
41
|
+
constructor(message, code = "unauthenticated") {
|
|
42
|
+
super(message);
|
|
43
|
+
this.code = code;
|
|
44
|
+
}
|
|
45
|
+
code;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// src/config.ts
|
|
38
49
|
var CONFIG_DIR = process.env.PDLAB_CONFIG_DIR ?? (0, import_path.join)((0, import_os.homedir)(), ".pdlab");
|
|
39
50
|
var CONFIG_FILE = (0, import_path.join)(CONFIG_DIR, "config.json");
|
|
51
|
+
var DEFAULT_API_URL = "https://1836.online";
|
|
40
52
|
function readConfig() {
|
|
41
53
|
if (!(0, import_fs.existsSync)(CONFIG_FILE)) return {};
|
|
42
54
|
try {
|
|
@@ -55,11 +67,7 @@ function updateConfig(patch) {
|
|
|
55
67
|
return next;
|
|
56
68
|
}
|
|
57
69
|
function resolveApiUrl(flagValue) {
|
|
58
|
-
const apiUrl = flagValue ?? process.env.PDLAB_API_URL ?? readConfig().apiUrl;
|
|
59
|
-
if (!apiUrl) {
|
|
60
|
-
console.error("\u672A\u914D\u7F6E API \u5730\u5740\u3002\u8BF7\u5148\u8FD0\u884C `pdlab login` / `pdlab register`\uFF0C\u6216\u8BBE\u7F6E PDLAB_API_URL \u73AF\u5883\u53D8\u91CF\u3002");
|
|
61
|
-
process.exit(1);
|
|
62
|
-
}
|
|
70
|
+
const apiUrl = flagValue ?? process.env.PDLAB_API_URL ?? readConfig().apiUrl ?? DEFAULT_API_URL;
|
|
63
71
|
return apiUrl.replace(/\/+$/, "");
|
|
64
72
|
}
|
|
65
73
|
function optionalToken() {
|
|
@@ -68,28 +76,53 @@ function optionalToken() {
|
|
|
68
76
|
function requireToken() {
|
|
69
77
|
const token = readConfig().token;
|
|
70
78
|
if (!token) {
|
|
71
|
-
|
|
72
|
-
process.exit(1);
|
|
79
|
+
throw new CliError("\u5C1A\u672A\u767B\u5F55\u3002\u8BF7\u5148\u8FD0\u884C `pdlab login`\u3002");
|
|
73
80
|
}
|
|
74
81
|
return token;
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
// src/api-client.ts
|
|
85
|
+
function classifyStatus(status) {
|
|
86
|
+
switch (status) {
|
|
87
|
+
case 400:
|
|
88
|
+
case 422:
|
|
89
|
+
return "validation";
|
|
90
|
+
case 401:
|
|
91
|
+
return "unauthenticated";
|
|
92
|
+
case 403:
|
|
93
|
+
return "forbidden";
|
|
94
|
+
case 404:
|
|
95
|
+
return "not_found";
|
|
96
|
+
case 409:
|
|
97
|
+
return "conflict";
|
|
98
|
+
case 0:
|
|
99
|
+
return "network";
|
|
100
|
+
default:
|
|
101
|
+
return "unknown";
|
|
102
|
+
}
|
|
103
|
+
}
|
|
78
104
|
var ApiRequestError = class extends Error {
|
|
79
105
|
constructor(message, status, details) {
|
|
80
106
|
super(message);
|
|
81
107
|
this.status = status;
|
|
82
108
|
this.details = details;
|
|
109
|
+
this.code = classifyStatus(status);
|
|
83
110
|
}
|
|
84
111
|
status;
|
|
85
112
|
details;
|
|
113
|
+
code;
|
|
86
114
|
};
|
|
87
115
|
async function apiRequest(path, options = {}) {
|
|
88
116
|
const apiUrl = resolveApiUrl(options.apiUrl);
|
|
89
117
|
const url = new URL(path.replace(/^\/+/, ""), apiUrl + "/");
|
|
90
118
|
if (options.query) {
|
|
91
119
|
for (const [key, value] of Object.entries(options.query)) {
|
|
92
|
-
if (value
|
|
120
|
+
if (value === void 0) continue;
|
|
121
|
+
if (Array.isArray(value)) {
|
|
122
|
+
for (const v of value) url.searchParams.append(key, v);
|
|
123
|
+
} else {
|
|
124
|
+
url.searchParams.set(key, value);
|
|
125
|
+
}
|
|
93
126
|
}
|
|
94
127
|
}
|
|
95
128
|
const headers = {};
|
|
@@ -142,7 +175,7 @@ async function pollCliAuth(code, apiUrl) {
|
|
|
142
175
|
|
|
143
176
|
// src/commands/login.ts
|
|
144
177
|
function registerLoginCommand(program2) {
|
|
145
|
-
program2.command("login").description("\u5728\u6D4F\u89C8\u5668\u91CC\u5B8C\u6210\u4E00\u6B21\u6027\u6388\u6743\uFF0C\u767B\u5F55 pdlab CLI\uFF08token \u957F\u671F\u6709\u6548\uFF0C\u76F4\u5230\u88AB\u64A4\u9500\uFF09").option("--api-url <url>", "API \u670D\u52A1\u5668\u5730\u5740\uFF0C\
|
|
178
|
+
program2.command("login").description("\u5728\u6D4F\u89C8\u5668\u91CC\u5B8C\u6210\u4E00\u6B21\u6027\u6388\u6743\uFF0C\u767B\u5F55 pdlab CLI\uFF08token \u957F\u671F\u6709\u6548\uFF0C\u76F4\u5230\u88AB\u64A4\u9500\uFF09").option("--api-url <url>", "API \u670D\u52A1\u5668\u5730\u5740\uFF0C\u9ED8\u8BA4\u662F\u5B98\u65B9\u90E8\u7F72\uFF0C\u81EA\u5EFA\u5B9E\u4F8B\u624D\u9700\u8981\u586B").action(async (opts) => {
|
|
146
179
|
const apiUrl = resolveApiUrl(opts.apiUrl);
|
|
147
180
|
const start = await apiRequest("/api/cli/auth/start", {
|
|
148
181
|
method: "POST",
|
|
@@ -174,7 +207,7 @@ function registerLoginCommand(program2) {
|
|
|
174
207
|
// src/commands/register.ts
|
|
175
208
|
var import_open2 = __toESM(require("open"));
|
|
176
209
|
function registerRegisterCommand(program2) {
|
|
177
|
-
program2.command("register").description("\u5728\u6D4F\u89C8\u5668\u91CC\u5B8C\u6210\u6CE8\u518C\u7533\u8BF7\uFF08\u6CE8\u518C\u540E\u9700\u7BA1\u7406\u5458\u5BA1\u6838\uFF0CCLI \u4E0D\u4F1A\u81EA\u52A8\u767B\u5F55\uFF09").option("--api-url <url>", "API \u670D\u52A1\u5668\u5730\u5740\uFF0C\
|
|
210
|
+
program2.command("register").description("\u5728\u6D4F\u89C8\u5668\u91CC\u5B8C\u6210\u6CE8\u518C\u7533\u8BF7\uFF08\u6CE8\u518C\u540E\u9700\u7BA1\u7406\u5458\u5BA1\u6838\uFF0CCLI \u4E0D\u4F1A\u81EA\u52A8\u767B\u5F55\uFF09").option("--api-url <url>", "API \u670D\u52A1\u5668\u5730\u5740\uFF0C\u9ED8\u8BA4\u662F\u5B98\u65B9\u90E8\u7F72\uFF0C\u81EA\u5EFA\u5B9E\u4F8B\u624D\u9700\u8981\u586B").action(async (opts) => {
|
|
178
211
|
const apiUrl = resolveApiUrl(opts.apiUrl);
|
|
179
212
|
const start = await apiRequest("/api/cli/auth/start", {
|
|
180
213
|
method: "POST",
|
|
@@ -227,8 +260,19 @@ function registerWhoamiCommand(program2) {
|
|
|
227
260
|
function registerConfigCommand(program2) {
|
|
228
261
|
const config = program2.command("config").description("\u67E5\u770B/\u4FEE\u6539\u672C\u5730\u914D\u7F6E\uFF08~/.pdlab/config.json\uFF09");
|
|
229
262
|
config.command("get").description("\u6253\u5370\u5F53\u524D\u914D\u7F6E").action(() => {
|
|
230
|
-
const { token,
|
|
231
|
-
console.log(
|
|
263
|
+
const { token, apiUrl } = readConfig();
|
|
264
|
+
console.log(
|
|
265
|
+
JSON.stringify(
|
|
266
|
+
{
|
|
267
|
+
apiUrl,
|
|
268
|
+
token: token ? "***" : void 0,
|
|
269
|
+
effectiveApiUrl: resolveApiUrl(),
|
|
270
|
+
defaultApiUrl: DEFAULT_API_URL
|
|
271
|
+
},
|
|
272
|
+
null,
|
|
273
|
+
2
|
|
274
|
+
)
|
|
275
|
+
);
|
|
232
276
|
});
|
|
233
277
|
config.command("set <key> <value>").description("\u8BBE\u7F6E\u4E00\u9879\u914D\u7F6E\uFF0C\u76EE\u524D\u652F\u6301\uFF1Aapi-url").action((key, value) => {
|
|
234
278
|
if (key !== "api-url") {
|
|
@@ -296,58 +340,134 @@ var postReviewSchema = import_zod3.z.object({
|
|
|
296
340
|
|
|
297
341
|
// src/errors.ts
|
|
298
342
|
var import_zod4 = require("zod");
|
|
299
|
-
|
|
300
|
-
|
|
343
|
+
var EXIT_CODES = {
|
|
344
|
+
ok: 0,
|
|
345
|
+
unhandled: 1,
|
|
346
|
+
validation: 2,
|
|
347
|
+
unauthenticated: 3,
|
|
348
|
+
forbidden: 4,
|
|
349
|
+
not_found: 5,
|
|
350
|
+
conflict: 6,
|
|
351
|
+
network: 7,
|
|
352
|
+
unknown: 1
|
|
353
|
+
};
|
|
354
|
+
function fieldsFromZod(error) {
|
|
355
|
+
const fields = {};
|
|
301
356
|
for (const issue of error.issues) {
|
|
302
357
|
const path = issue.path.length > 0 ? issue.path.join(".") : "(\u6839)";
|
|
303
|
-
|
|
358
|
+
(fields[path] ??= []).push(issue.message);
|
|
304
359
|
}
|
|
305
|
-
|
|
360
|
+
return fields;
|
|
306
361
|
}
|
|
307
|
-
function
|
|
308
|
-
if (
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
362
|
+
function fieldsFromApiDetails(details) {
|
|
363
|
+
if (!details || typeof details !== "object") return void 0;
|
|
364
|
+
const flat = details;
|
|
365
|
+
const fields = { ...flat.fieldErrors ?? {} };
|
|
366
|
+
if (flat.formErrors && flat.formErrors.length > 0) fields["(\u6839)"] = flat.formErrors;
|
|
367
|
+
return Object.keys(fields).length > 0 ? fields : void 0;
|
|
314
368
|
}
|
|
315
|
-
function
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
const flat = error.details;
|
|
319
|
-
for (const [field, messages] of Object.entries(flat.fieldErrors ?? {})) {
|
|
320
|
-
for (const message of messages) console.error(` - ${field}: ${message}`);
|
|
321
|
-
}
|
|
322
|
-
for (const message of flat.formErrors ?? []) console.error(` - ${message}`);
|
|
323
|
-
}
|
|
369
|
+
function exampleHint(examples) {
|
|
370
|
+
if (examples.length === 0) return void 0;
|
|
371
|
+
return examples.map((e) => e.command).join(" | ");
|
|
324
372
|
}
|
|
325
|
-
function handleCommandError(error, examples) {
|
|
373
|
+
function handleCommandError(error, examples = []) {
|
|
374
|
+
let structured;
|
|
326
375
|
if (error instanceof import_zod4.ZodError) {
|
|
327
|
-
|
|
376
|
+
structured = {
|
|
377
|
+
error: "\u53C2\u6570\u6821\u9A8C\u5931\u8D25",
|
|
378
|
+
code: "validation",
|
|
379
|
+
status: null,
|
|
380
|
+
fields: fieldsFromZod(error),
|
|
381
|
+
hint: exampleHint(examples)
|
|
382
|
+
};
|
|
328
383
|
} else if (error instanceof ApiRequestError) {
|
|
329
|
-
|
|
384
|
+
structured = {
|
|
385
|
+
error: error.message,
|
|
386
|
+
code: error.code,
|
|
387
|
+
status: error.status || null,
|
|
388
|
+
fields: fieldsFromApiDetails(error.details),
|
|
389
|
+
hint: exampleHint(examples)
|
|
390
|
+
};
|
|
391
|
+
} else if (error instanceof CliError) {
|
|
392
|
+
structured = { error: error.message, code: error.code, status: null, hint: "pdlab login" };
|
|
330
393
|
} else {
|
|
331
|
-
|
|
394
|
+
structured = {
|
|
395
|
+
error: error instanceof Error ? error.message : String(error),
|
|
396
|
+
code: "unhandled",
|
|
397
|
+
status: null
|
|
398
|
+
};
|
|
332
399
|
}
|
|
333
|
-
|
|
400
|
+
console.error(JSON.stringify(structured, null, 2));
|
|
401
|
+
process.exit(EXIT_CODES[structured.code] ?? 1);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// src/help-meta.ts
|
|
405
|
+
var META = /* @__PURE__ */ new WeakMap();
|
|
406
|
+
function attachMeta(command, meta) {
|
|
407
|
+
META.set(command, meta);
|
|
408
|
+
if (meta.examples && meta.examples.length > 0) {
|
|
409
|
+
command.addHelpText(
|
|
410
|
+
"after",
|
|
411
|
+
"\n\u793A\u4F8B\uFF1A\n" + meta.examples.map((e) => ` $ ${e.command}${e.note ? `
|
|
412
|
+
${e.note}` : ""}`).join("\n")
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
return command;
|
|
416
|
+
}
|
|
417
|
+
function getMeta(command) {
|
|
418
|
+
return META.get(command) ?? {};
|
|
334
419
|
}
|
|
335
420
|
|
|
336
421
|
// src/commands/options.ts
|
|
337
422
|
function withApiUrl(cmd) {
|
|
338
|
-
return cmd.option("--api-url <url>", "API \u670D\u52A1\u5668\u5730\u5740\uFF0C\u8986\u76D6 PDLAB_API_URL
|
|
423
|
+
return cmd.option("--api-url <url>", "API \u670D\u52A1\u5668\u5730\u5740\uFF0C\u8986\u76D6 PDLAB_API_URL\u3001\u914D\u7F6E\u6587\u4EF6\u4E0E\u9ED8\u8BA4\u5730\u5740");
|
|
339
424
|
}
|
|
340
425
|
|
|
341
426
|
// src/commands/project.ts
|
|
427
|
+
var STATUS_LIST = PROJECT_STATUS_VALUES.join(" | ");
|
|
342
428
|
var CREATE_EXAMPLES = [
|
|
343
429
|
{
|
|
344
430
|
command: 'pdlab project create --title "\u94A0\u7535\u56DE\u6536\u5DE5\u827A\u4F18\u5316" --description "..." --status planning --taxonomy-ids tax_1,tax_2',
|
|
345
|
-
note: "title \u5FC5\u586B\uFF0C\u5176\u4F59\u5B57\u6BB5\u53EF\u7701\u7565"
|
|
431
|
+
note: "title \u5FC5\u586B\uFF0C\u5176\u4F59\u5B57\u6BB5\u53EF\u7701\u7565\uFF1B\u9700\u8981\u300C1836\u53D1\u8D77\u4EBA\u300D\u89D2\u8272\uFF08project:create \u6743\u9650\uFF09"
|
|
346
432
|
}
|
|
347
433
|
];
|
|
348
434
|
var UPDATE_EXAMPLES = [
|
|
349
435
|
{ command: "pdlab project update proj_123 --progress 60 --status active", note: "\u53EA\u4F20\u8981\u6539\u7684\u5B57\u6BB5" }
|
|
350
436
|
];
|
|
437
|
+
var LIST_EXAMPLES = [
|
|
438
|
+
{ command: "pdlab project list --status active", note: "\u6309\u72B6\u6001\u7B5B\u9009" },
|
|
439
|
+
{ command: 'pdlab project list --q "\u94A0\u7535"', note: "\u6309\u6807\u9898\u5173\u952E\u8BCD\u641C\u7D22" },
|
|
440
|
+
{ command: "pdlab project list --taxonomy tax_1 --taxonomy tax_2", note: "\u53EF\u91CD\u590D\u4F20\uFF0C\u591A\u4E2A\u6807\u7B7E\u53D6\u4EA4\u96C6" },
|
|
441
|
+
{ command: "pdlab project list --limit 10 --cursor <\u4E0A\u4E00\u9875\u8FD4\u56DE\u7684 nextCursor>", note: "\u7FFB\u9875\uFF1BnextCursor \u4E3A null \u8868\u793A\u6CA1\u6709\u4E0B\u4E00\u9875\u4E86" }
|
|
442
|
+
];
|
|
443
|
+
var GET_EXAMPLES = [{ command: "pdlab project get proj_123" }];
|
|
444
|
+
var DELETE_EXAMPLES = [
|
|
445
|
+
{ command: "pdlab project delete proj_123", note: "\u9700\u8981\u662F\u9879\u76EE\u53D1\u8D77\u4EBA\uFF0C\u4E14\u9879\u76EE\u4E0B\u6CA1\u6709\u5185\u5BB9/\u79EF\u5206\u8BB0\u5F55" }
|
|
446
|
+
];
|
|
447
|
+
var JOIN_EXAMPLES = [
|
|
448
|
+
{ command: "pdlab project join proj_123", note: "\u62A5\u540D\u5171\u5EFA\uFF0C\u8FDB\u5165\u5F85\u5BA1\u6838\uFF1B\u91CD\u590D\u8C03\u7528\u662F\u5E42\u7B49\u7684" }
|
|
449
|
+
];
|
|
450
|
+
var LEAVE_EXAMPLES = [
|
|
451
|
+
{ command: "pdlab project leave proj_123", note: "\u64A4\u56DE\u62A5\u540D\u7533\u8BF7\uFF0C\u6216\u9000\u51FA\u5DF2\u901A\u8FC7\u5BA1\u6838\u7684\u5171\u5EFA" }
|
|
452
|
+
];
|
|
453
|
+
var MEMBER_REVIEW_EXAMPLES = [
|
|
454
|
+
{
|
|
455
|
+
command: "pdlab project member review proj_123 user_456 --status approved",
|
|
456
|
+
note: "\u5BA1\u6838\u4E00\u6761 pending \u7684\u62A5\u540D\u7533\u8BF7\uFF1B\u53EA\u6709\u9879\u76EE\u53D1\u8D77\u4EBA\u672C\u4EBA\u80FD\u8C03\u7528"
|
|
457
|
+
}
|
|
458
|
+
];
|
|
459
|
+
var MEMBER_SET_ROLE_EXAMPLES = [
|
|
460
|
+
{
|
|
461
|
+
command: "pdlab project member set-role proj_123 user_456 --role maintainer",
|
|
462
|
+
note: "\u4EC5\u5BF9\u5DF2\u901A\u8FC7\u5BA1\u6838\uFF08approved\uFF09\u7684\u53C2\u4E0E\u8005\u751F\u6548\uFF1B\u53EA\u6709\u9879\u76EE\u53D1\u8D77\u4EBA\u672C\u4EBA\u80FD\u8C03\u7528"
|
|
463
|
+
}
|
|
464
|
+
];
|
|
465
|
+
var MEMBER_REMOVE_EXAMPLES = [
|
|
466
|
+
{ command: "pdlab project member remove proj_123 user_456", note: "\u53EA\u6709\u9879\u76EE\u53D1\u8D77\u4EBA\u672C\u4EBA\u80FD\u8C03\u7528" }
|
|
467
|
+
];
|
|
468
|
+
var REVENUE_EXAMPLES = [
|
|
469
|
+
{ command: "pdlab project revenue proj_123", note: "\u53EA\u8BFB\uFF0C\u9700\u8981 data:view_stats \u6743\u9650" }
|
|
470
|
+
];
|
|
351
471
|
function toBody(opts) {
|
|
352
472
|
const body = {};
|
|
353
473
|
if (opts.title !== void 0) body.title = opts.title;
|
|
@@ -362,26 +482,43 @@ function toBody(opts) {
|
|
|
362
482
|
return body;
|
|
363
483
|
}
|
|
364
484
|
function withProjectFlags(cmd) {
|
|
365
|
-
return withApiUrl(cmd).option("--title <title>", "\u9879\u76EE\u6807\u9898").option("--description <description>", "\u9879\u76EE\u63CF\u8FF0").option("--cover-image <url>", "\u5C01\u9762\u56FE http/https \u94FE\u63A5").option("--commercial-type <type>", "\u5546\u4E1A\u5C5E\u6027").option("--status <status>",
|
|
485
|
+
return withApiUrl(cmd).option("--title <title>", "\u9879\u76EE\u6807\u9898\uFF08\u5FC5\u586B\uFF0C1-200 \u5B57\uFF09").option("--description <description>", "\u9879\u76EE\u63CF\u8FF0\uFF08\u9009\u586B\uFF0C\u6700\u591A 20000 \u5B57\uFF09").option("--cover-image <url>", "\u5C01\u9762\u56FE http/https \u94FE\u63A5\uFF08\u9009\u586B\uFF09").option("--commercial-type <type>", "\u5546\u4E1A\u5C5E\u6027\uFF08\u9009\u586B\uFF09").option("--status <status>", `\u9879\u76EE\u72B6\u6001\uFF1A${STATUS_LIST}\uFF08\u9009\u586B\uFF09`).option("--progress <percent>", "\u8FDB\u5EA6\uFF0C\u6574\u6570 0-100\uFF08\u9009\u586B\uFF09").option("--taxonomy-ids <ids>", "\u9017\u53F7\u5206\u9694\u7684\u5206\u7C7B\u6807\u7B7E id \u5217\u8868\uFF0C\u5168\u91CF\u66FF\u6362\uFF08\u9009\u586B\uFF09");
|
|
486
|
+
}
|
|
487
|
+
function collect(value, previous) {
|
|
488
|
+
return previous.concat([value]);
|
|
366
489
|
}
|
|
367
490
|
function registerProjectCommand(program2) {
|
|
368
|
-
const project = program2.command("project").description("\u9879\u76EE\u7684\u589E\u5220\u6539\u67E5");
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
491
|
+
const project = program2.command("project").description("\u9879\u76EE\u7684\u589E\u5220\u6539\u67E5\u3001\u62A5\u540D\u5171\u5EFA\u3001\u6210\u5458\u7BA1\u7406\u3001\u6536\u76CA\u67E5\u8BE2");
|
|
492
|
+
attachMeta(
|
|
493
|
+
withApiUrl(project.command("list").description("\u5217\u51FA\u9879\u76EE\uFF08\u516C\u5F00\u53EA\u8BFB\uFF0C\u4E0D\u767B\u5F55\u4E5F\u80FD\u7528\uFF09")).option("--status <status>", `\u6309\u72B6\u6001\u7B5B\u9009\uFF1A${STATUS_LIST}`).option("--q <keyword>", "\u6309\u6807\u9898\u5173\u952E\u8BCD\u641C\u7D22").option("--taxonomy <id>", "\u6309\u5206\u7C7B\u6807\u7B7E id \u7B5B\u9009\uFF0C\u53EF\u91CD\u590D\u4F20\uFF0C\u591A\u4E2A\u53D6\u4EA4\u96C6", collect, []).option("--limit <n>", "\u5355\u9875\u6570\u91CF\uFF0C\u9ED8\u8BA4 30\uFF0C\u4E0A\u9650 100").option("--cursor <token>", "\u7FFB\u9875\u6E38\u6807\uFF0C\u53D6\u4E0A\u4E00\u9875\u54CD\u5E94\u91CC\u7684 nextCursor").action(
|
|
494
|
+
async (opts) => {
|
|
495
|
+
const data = await apiRequest("/api/projects", {
|
|
496
|
+
query: {
|
|
497
|
+
status: opts.status,
|
|
498
|
+
q: opts.q,
|
|
499
|
+
taxonomy: opts.taxonomy.length > 0 ? opts.taxonomy : void 0,
|
|
500
|
+
limit: opts.limit,
|
|
501
|
+
cursor: opts.cursor
|
|
502
|
+
},
|
|
503
|
+
token: optionalToken(),
|
|
504
|
+
apiUrl: opts.apiUrl
|
|
505
|
+
});
|
|
506
|
+
console.log(JSON.stringify(data, null, 2));
|
|
507
|
+
}
|
|
508
|
+
),
|
|
509
|
+
{ examples: LIST_EXAMPLES }
|
|
382
510
|
);
|
|
383
|
-
|
|
384
|
-
|
|
511
|
+
attachMeta(
|
|
512
|
+
withApiUrl(project.command("get <id>").description("\u67E5\u770B\u9879\u76EE\u8BE6\u60C5\uFF08\u516C\u5F00\u53EA\u8BFB\uFF0C\u4E0D\u767B\u5F55\u4E5F\u80FD\u7528\uFF09")).action(
|
|
513
|
+
async (id, opts) => {
|
|
514
|
+
const data = await apiRequest(`/api/projects/${id}`, { token: optionalToken(), apiUrl: opts.apiUrl });
|
|
515
|
+
console.log(JSON.stringify(data, null, 2));
|
|
516
|
+
}
|
|
517
|
+
),
|
|
518
|
+
{ examples: GET_EXAMPLES }
|
|
519
|
+
);
|
|
520
|
+
attachMeta(
|
|
521
|
+
withProjectFlags(project.command("create").description("\u521B\u5EFA\u9879\u76EE")).action(async (opts) => {
|
|
385
522
|
const token = requireToken();
|
|
386
523
|
try {
|
|
387
524
|
const body = projectCreateSchema.parse(toBody(opts));
|
|
@@ -390,99 +527,275 @@ function registerProjectCommand(program2) {
|
|
|
390
527
|
} catch (error) {
|
|
391
528
|
handleCommandError(error, CREATE_EXAMPLES);
|
|
392
529
|
}
|
|
530
|
+
}),
|
|
531
|
+
{ permission: "project:create\uFF081836\u53D1\u8D77\u4EBA\u89D2\u8272\uFF09", examples: CREATE_EXAMPLES }
|
|
532
|
+
);
|
|
533
|
+
attachMeta(
|
|
534
|
+
withProjectFlags(project.command("update <id>").description("\u66F4\u65B0\u9879\u76EE")).action(
|
|
535
|
+
async (id, opts) => {
|
|
536
|
+
const token = requireToken();
|
|
537
|
+
try {
|
|
538
|
+
const body = projectUpdateSchema.parse(toBody(opts));
|
|
539
|
+
const data = await apiRequest(`/api/projects/${id}`, { method: "PATCH", body, token, apiUrl: opts.apiUrl });
|
|
540
|
+
console.log(JSON.stringify(data, null, 2));
|
|
541
|
+
} catch (error) {
|
|
542
|
+
handleCommandError(error, UPDATE_EXAMPLES);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
),
|
|
546
|
+
{
|
|
547
|
+
permission: "project:update_progress\uFF08\u53D1\u8D77\u4EBA\uFF09\u6216 project:join\uFF08\u534F\u4F5C\u8005\uFF0C\u4EC5\u80FD\u6539 progress/status/description\uFF09",
|
|
548
|
+
examples: UPDATE_EXAMPLES
|
|
393
549
|
}
|
|
394
550
|
);
|
|
395
|
-
|
|
396
|
-
|
|
551
|
+
attachMeta(
|
|
552
|
+
withApiUrl(
|
|
553
|
+
project.command("delete <id>").description("\u5220\u9664\u9879\u76EE\uFF08\u9700\u8981\u662F\u9879\u76EE\u53D1\u8D77\u4EBA\uFF0C\u4E14\u9879\u76EE\u4E0B\u6CA1\u6709\u5185\u5BB9/\u79EF\u5206\u8BB0\u5F55\uFF09")
|
|
554
|
+
).action(async (id, opts) => {
|
|
397
555
|
const token = requireToken();
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
556
|
+
const data = await apiRequest(`/api/projects/${id}`, { method: "DELETE", token, apiUrl: opts.apiUrl });
|
|
557
|
+
console.log(JSON.stringify(data, null, 2));
|
|
558
|
+
}),
|
|
559
|
+
{ permission: "project:create\uFF081836\u53D1\u8D77\u4EBA\u89D2\u8272\uFF09\uFF0C\u4E14\u5FC5\u987B\u662F\u8BE5\u9879\u76EE\u53D1\u8D77\u4EBA\u672C\u4EBA", examples: DELETE_EXAMPLES }
|
|
560
|
+
);
|
|
561
|
+
attachMeta(
|
|
562
|
+
withApiUrl(project.command("join <id>").description("\u62A5\u540D\u5171\u5EFA\u8BE5\u9879\u76EE\uFF0C\u8FDB\u5165\u5F85\u5BA1\u6838")).action(
|
|
563
|
+
async (id, opts) => {
|
|
564
|
+
const token = requireToken();
|
|
565
|
+
const data = await apiRequest(`/api/projects/${id}/join`, { method: "POST", token, apiUrl: opts.apiUrl });
|
|
401
566
|
console.log(JSON.stringify(data, null, 2));
|
|
402
|
-
} catch (error) {
|
|
403
|
-
handleCommandError(error, UPDATE_EXAMPLES);
|
|
404
567
|
}
|
|
405
|
-
|
|
568
|
+
),
|
|
569
|
+
{ permission: "project:join\uFF081836\u5171\u5EFA\u8005\u7B49\u89D2\u8272\uFF09", examples: JOIN_EXAMPLES }
|
|
570
|
+
);
|
|
571
|
+
attachMeta(
|
|
572
|
+
withApiUrl(project.command("leave <id>").description("\u64A4\u56DE\u62A5\u540D\u7533\u8BF7\uFF0C\u6216\u9000\u51FA\u5DF2\u901A\u8FC7\u5BA1\u6838\u7684\u5171\u5EFA")).action(
|
|
573
|
+
async (id, opts) => {
|
|
574
|
+
const token = requireToken();
|
|
575
|
+
const data = await apiRequest(`/api/projects/${id}/join`, { method: "DELETE", token, apiUrl: opts.apiUrl });
|
|
576
|
+
console.log(JSON.stringify(data, null, 2));
|
|
577
|
+
}
|
|
578
|
+
),
|
|
579
|
+
{ permission: "project:join\uFF081836\u5171\u5EFA\u8005\u7B49\u89D2\u8272\uFF09", examples: LEAVE_EXAMPLES }
|
|
580
|
+
);
|
|
581
|
+
const member = project.command("member").description("\u9879\u76EE\u53C2\u4E0E\u8005\u7684\u5BA1\u6838 / \u89D2\u8272 / \u79FB\u9664\uFF08\u4EC5\u9879\u76EE\u53D1\u8D77\u4EBA\u672C\u4EBA\u53EF\u7528\uFF09");
|
|
582
|
+
attachMeta(
|
|
583
|
+
withApiUrl(member.command("review <projectId> <userId>").description("\u5BA1\u6838\u4E00\u6761 pending \u7684\u62A5\u540D\u7533\u8BF7")).requiredOption("--status <status>", "approved | rejected").action(async (projectId, userId, opts) => {
|
|
584
|
+
const token = requireToken();
|
|
585
|
+
const data = await apiRequest(`/api/projects/${projectId}/members/${userId}`, {
|
|
586
|
+
method: "PATCH",
|
|
587
|
+
body: { status: opts.status },
|
|
588
|
+
token,
|
|
589
|
+
apiUrl: opts.apiUrl
|
|
590
|
+
});
|
|
591
|
+
console.log(JSON.stringify(data, null, 2));
|
|
592
|
+
}),
|
|
593
|
+
{ permission: "project:update_progress\uFF0C\u4E14\u5FC5\u987B\u662F\u8BE5\u9879\u76EE\u53D1\u8D77\u4EBA\u672C\u4EBA", examples: MEMBER_REVIEW_EXAMPLES }
|
|
594
|
+
);
|
|
595
|
+
attachMeta(
|
|
596
|
+
withApiUrl(member.command("set-role <projectId> <userId>").description("\u8BBE\u7F6E\u5DF2\u901A\u8FC7\u5BA1\u6838\u7684\u53C2\u4E0E\u8005\u7684\u9879\u76EE\u5185\u89D2\u8272")).requiredOption("--role <role>", "member | maintainer").action(async (projectId, userId, opts) => {
|
|
597
|
+
const token = requireToken();
|
|
598
|
+
const data = await apiRequest(`/api/projects/${projectId}/members/${userId}`, {
|
|
599
|
+
method: "PATCH",
|
|
600
|
+
body: { role: opts.role },
|
|
601
|
+
token,
|
|
602
|
+
apiUrl: opts.apiUrl
|
|
603
|
+
});
|
|
604
|
+
console.log(JSON.stringify(data, null, 2));
|
|
605
|
+
}),
|
|
606
|
+
{ permission: "project:update_progress\uFF0C\u4E14\u5FC5\u987B\u662F\u8BE5\u9879\u76EE\u53D1\u8D77\u4EBA\u672C\u4EBA", examples: MEMBER_SET_ROLE_EXAMPLES }
|
|
607
|
+
);
|
|
608
|
+
attachMeta(
|
|
609
|
+
withApiUrl(member.command("remove <projectId> <userId>").description("\u79FB\u9664\u4E00\u4E2A\u53C2\u4E0E\u8005")).action(
|
|
610
|
+
async (projectId, userId, opts) => {
|
|
611
|
+
const token = requireToken();
|
|
612
|
+
const data = await apiRequest(`/api/projects/${projectId}/members/${userId}`, {
|
|
613
|
+
method: "DELETE",
|
|
614
|
+
token,
|
|
615
|
+
apiUrl: opts.apiUrl
|
|
616
|
+
});
|
|
617
|
+
console.log(JSON.stringify(data, null, 2));
|
|
618
|
+
}
|
|
619
|
+
),
|
|
620
|
+
{ permission: "project:update_progress\uFF0C\u4E14\u5FC5\u987B\u662F\u8BE5\u9879\u76EE\u53D1\u8D77\u4EBA\u672C\u4EBA", examples: MEMBER_REMOVE_EXAMPLES }
|
|
621
|
+
);
|
|
622
|
+
attachMeta(
|
|
623
|
+
withApiUrl(project.command("revenue <id>").description("\u67E5\u770B\u9879\u76EE\u7684\u79EF\u5206\u5206\u6210\u660E\u7EC6\uFF08\u53EA\u8BFB\uFF09")).action(
|
|
624
|
+
async (id, opts) => {
|
|
625
|
+
const token = requireToken();
|
|
626
|
+
const data = await apiRequest(`/api/projects/${id}/revenue-breakdown`, { token, apiUrl: opts.apiUrl });
|
|
627
|
+
console.log(JSON.stringify(data, null, 2));
|
|
628
|
+
}
|
|
629
|
+
),
|
|
630
|
+
{ permission: "data:view_stats", examples: REVENUE_EXAMPLES }
|
|
406
631
|
);
|
|
407
|
-
withApiUrl(
|
|
408
|
-
project.command("delete <id>").description("\u5220\u9664\u9879\u76EE\uFF08\u9700\u8981\u662F\u9879\u76EE\u53D1\u8D77\u4EBA\uFF0C\u4E14\u9879\u76EE\u4E0B\u6CA1\u6709\u5185\u5BB9/\u79EF\u5206\u8BB0\u5F55\uFF09")
|
|
409
|
-
).action(async (id, opts) => {
|
|
410
|
-
const token = requireToken();
|
|
411
|
-
const data = await apiRequest(`/api/projects/${id}`, { method: "DELETE", token, apiUrl: opts.apiUrl });
|
|
412
|
-
console.log(JSON.stringify(data, null, 2));
|
|
413
|
-
});
|
|
414
632
|
}
|
|
415
633
|
|
|
416
634
|
// src/commands/post.ts
|
|
417
635
|
var CREATE_EXAMPLES2 = [
|
|
418
636
|
{
|
|
419
637
|
command: 'pdlab post create --title "\u7B2C\u4E00\u5468\u8FDB\u5C55" --body "..." --project-id proj_123 --media-links https://example.com/a.png',
|
|
420
|
-
note: "title / body / project-id \u5FC5\u586B"
|
|
638
|
+
note: "title / body / project-id \u5FC5\u586B\uFF1B\u9700\u8981\u662F\u9879\u76EE\u53D1\u8D77\u4EBA\u6216\u5DF2\u62A5\u540D\u5171\u5EFA\u8BE5\u9879\u76EE"
|
|
639
|
+
}
|
|
640
|
+
];
|
|
641
|
+
var UPDATE_EXAMPLES2 = [
|
|
642
|
+
{ command: 'pdlab post update post_123 --title "..." --body "..."', note: "title \u548C body \u90FD\u5FC5\u987B\u4F20" }
|
|
643
|
+
];
|
|
644
|
+
var LIST_EXAMPLES2 = [
|
|
645
|
+
{ command: "pdlab post list --project-id proj_123", note: "\u53EA\u770B\u67D0\u4E2A\u9879\u76EE\u4E0B\u7684\u5185\u5BB9" },
|
|
646
|
+
{ command: "pdlab post list --status pending", note: "\u67E5\u770B\u5F85\u5BA1\u6838\u5185\u5BB9\uFF0C\u9700\u8981 content:review \u6743\u9650\uFF0C\u5426\u5219 403" },
|
|
647
|
+
{ command: "pdlab post list --limit 10 --cursor <\u4E0A\u4E00\u9875\u8FD4\u56DE\u7684 nextCursor>", note: "\u7FFB\u9875\uFF1BnextCursor \u4E3A null \u8868\u793A\u6CA1\u6709\u4E0B\u4E00\u9875\u4E86" }
|
|
648
|
+
];
|
|
649
|
+
var GET_EXAMPLES2 = [{ command: "pdlab post get post_123" }];
|
|
650
|
+
var DELETE_EXAMPLES2 = [
|
|
651
|
+
{ command: "pdlab post delete post_123", note: "\u4F5C\u8005\u672C\u4EBA\uFF0C\u6216\u6709\u5220\u9664\u4EFB\u610F\u5185\u5BB9\u7684\u6743\u9650" }
|
|
652
|
+
];
|
|
653
|
+
var REVIEW_EXAMPLES = [
|
|
654
|
+
{
|
|
655
|
+
command: "pdlab post review post_123 --action approve",
|
|
656
|
+
note: "\u901A\u8FC7\u5BA1\u6838\uFF1B\u4F5C\u8005\u4E0D\u80FD\u5BA1\u81EA\u5DF1\u53D1\u5E03\u7684\u5185\u5BB9\uFF08403\uFF09\uFF0C\u53EA\u80FD\u5BA1 pending \u72B6\u6001\u7684\u5185\u5BB9\uFF08\u975E pending \u4F1A 409\uFF09"
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
command: 'pdlab post review post_123 --action reject --comment "\u7F3A\u5C11\u6570\u636E\u6765\u6E90\uFF0C\u8BF7\u8865\u5145\u5F15\u7528"',
|
|
660
|
+
note: "\u9A73\u56DE\u65F6\u5FC5\u987B\u586B\u5199 --comment\uFF0C\u5426\u5219 400"
|
|
421
661
|
}
|
|
422
662
|
];
|
|
423
|
-
var UPDATE_EXAMPLES2 = [{ command: 'pdlab post update post_123 --title "..." --body "..."', note: "title \u548C body \u90FD\u5FC5\u987B\u4F20" }];
|
|
424
663
|
function toMediaLinks(value) {
|
|
425
664
|
if (value === void 0) return void 0;
|
|
426
665
|
return value.split(",").map((url) => url.trim()).filter(Boolean);
|
|
427
666
|
}
|
|
428
667
|
function registerPostCommand(program2) {
|
|
429
|
-
const post = program2.command("post").description("\u5185\u5BB9\uFF08\u5E16\u5B50\uFF09\u7684\u589E\u5220\u6539\u67E5");
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
console.log(JSON.stringify(data, null, 2));
|
|
437
|
-
});
|
|
438
|
-
withApiUrl(post.command("get <id>").description("\u67E5\u770B\u5185\u5BB9\u8BE6\u60C5")).action(
|
|
439
|
-
async (id, opts) => {
|
|
440
|
-
const data = await apiRequest(`/api/posts/${id}`, { token: optionalToken(), apiUrl: opts.apiUrl });
|
|
441
|
-
console.log(JSON.stringify(data, null, 2));
|
|
442
|
-
}
|
|
443
|
-
);
|
|
444
|
-
withApiUrl(post.command("create").description("\u53D1\u5E03\u5185\u5BB9\uFF08\u9700\u8981\u5185\u5BB9\u521B\u5EFA\u6743\u9650\uFF0C\u4E14\u662F\u9879\u76EE\u53D1\u8D77\u4EBA\u6216\u5DF2\u62A5\u540D\u5171\u5EFA\uFF09")).option("--title <title>", "\u5185\u5BB9\u6807\u9898").option("--body <body>", "\u5185\u5BB9\u6B63\u6587").option("--project-id <id>", "\u6240\u5C5E\u9879\u76EE id").option("--media-links <urls>", "\u9017\u53F7\u5206\u9694\u7684\u5A92\u4F53\u94FE\u63A5").action(async (opts) => {
|
|
445
|
-
const token = requireToken();
|
|
446
|
-
try {
|
|
447
|
-
const body = postCreateSchema.parse({
|
|
448
|
-
title: opts.title,
|
|
449
|
-
body: opts.body,
|
|
450
|
-
projectId: opts.projectId,
|
|
451
|
-
mediaLinks: toMediaLinks(opts.mediaLinks)
|
|
668
|
+
const post = program2.command("post").description("\u5185\u5BB9\uFF08\u5E16\u5B50\uFF09\u7684\u589E\u5220\u6539\u67E5\u4E0E\u5BA1\u6838");
|
|
669
|
+
attachMeta(
|
|
670
|
+
withApiUrl(post.command("list").description("\u5217\u51FA\u5185\u5BB9\uFF08approved \u5185\u5BB9\u516C\u5F00\u53EA\u8BFB\uFF0C\u4E0D\u767B\u5F55\u4E5F\u80FD\u7528\uFF09")).option("--project-id <id>", "\u6309\u9879\u76EE\u7B5B\u9009").option("--status <status>", "pending | approved | rejected\uFF08\u67E5\u770B\u975E approved \u9700\u8981\u5BA1\u6838\u6743\u9650\uFF09").option("--limit <n>", "\u5355\u9875\u6570\u91CF\uFF0C\u9ED8\u8BA4 30\uFF0C\u4E0A\u9650 100").option("--cursor <token>", "\u7FFB\u9875\u6E38\u6807\uFF0C\u53D6\u4E0A\u4E00\u9875\u54CD\u5E94\u91CC\u7684 nextCursor").action(async (opts) => {
|
|
671
|
+
const data = await apiRequest("/api/posts", {
|
|
672
|
+
query: { projectId: opts.projectId, status: opts.status, limit: opts.limit, cursor: opts.cursor },
|
|
673
|
+
token: optionalToken(),
|
|
674
|
+
apiUrl: opts.apiUrl
|
|
452
675
|
});
|
|
453
|
-
const data = await apiRequest("/api/posts", { method: "POST", body, token, apiUrl: opts.apiUrl });
|
|
454
676
|
console.log(JSON.stringify(data, null, 2));
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
} catch (error) {
|
|
470
|
-
handleCommandError(error, UPDATE_EXAMPLES2);
|
|
471
|
-
}
|
|
472
|
-
});
|
|
473
|
-
withApiUrl(post.command("delete <id>").description("\u5220\u9664\u5185\u5BB9\uFF08\u4F5C\u8005\u672C\u4EBA\uFF0C\u6216\u6709\u5220\u9664\u4EFB\u610F\u5185\u5BB9\u7684\u6743\u9650\uFF09")).action(
|
|
474
|
-
async (id, opts) => {
|
|
677
|
+
}),
|
|
678
|
+
{ examples: LIST_EXAMPLES2 }
|
|
679
|
+
);
|
|
680
|
+
attachMeta(
|
|
681
|
+
withApiUrl(post.command("get <id>").description("\u67E5\u770B\u5185\u5BB9\u8BE6\u60C5")).action(
|
|
682
|
+
async (id, opts) => {
|
|
683
|
+
const data = await apiRequest(`/api/posts/${id}`, { token: optionalToken(), apiUrl: opts.apiUrl });
|
|
684
|
+
console.log(JSON.stringify(data, null, 2));
|
|
685
|
+
}
|
|
686
|
+
),
|
|
687
|
+
{ examples: GET_EXAMPLES2 }
|
|
688
|
+
);
|
|
689
|
+
attachMeta(
|
|
690
|
+
withApiUrl(post.command("create").description("\u53D1\u5E03\u5185\u5BB9")).option("--title <title>", "\u5185\u5BB9\u6807\u9898\uFF08\u5FC5\u586B\uFF09").option("--body <body>", "\u5185\u5BB9\u6B63\u6587\uFF08\u5FC5\u586B\uFF09").option("--project-id <id>", "\u6240\u5C5E\u9879\u76EE id\uFF08\u5FC5\u586B\uFF09").option("--media-links <urls>", "\u9017\u53F7\u5206\u9694\u7684\u5A92\u4F53\u94FE\u63A5\uFF08\u9009\u586B\uFF0C\u6700\u591A 20 \u6761\uFF0Chttp/https\uFF09").action(async (opts) => {
|
|
475
691
|
const token = requireToken();
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
692
|
+
try {
|
|
693
|
+
const body = postCreateSchema.parse({
|
|
694
|
+
title: opts.title,
|
|
695
|
+
body: opts.body,
|
|
696
|
+
projectId: opts.projectId,
|
|
697
|
+
mediaLinks: toMediaLinks(opts.mediaLinks)
|
|
698
|
+
});
|
|
699
|
+
const data = await apiRequest("/api/posts", { method: "POST", body, token, apiUrl: opts.apiUrl });
|
|
700
|
+
console.log(JSON.stringify(data, null, 2));
|
|
701
|
+
} catch (error) {
|
|
702
|
+
handleCommandError(error, CREATE_EXAMPLES2);
|
|
703
|
+
}
|
|
704
|
+
}),
|
|
705
|
+
{ permission: "content:create\uFF0C\u4E14\u662F\u9879\u76EE\u53D1\u8D77\u4EBA\u6216\u5DF2\u62A5\u540D\u5171\u5EFA\u8BE5\u9879\u76EE", examples: CREATE_EXAMPLES2 }
|
|
706
|
+
);
|
|
707
|
+
attachMeta(
|
|
708
|
+
withApiUrl(post.command("update <id>").description("\u7F16\u8F91\u5185\u5BB9\uFF08\u4F5C\u8005\u672C\u4EBA\uFF0C\u6216\u6709\u7F16\u8F91\u4EFB\u610F\u5185\u5BB9\u7684\u6743\u9650\uFF09")).option("--title <title>", "\u5185\u5BB9\u6807\u9898\uFF08\u5FC5\u586B\uFF09").option("--body <body>", "\u5185\u5BB9\u6B63\u6587\uFF08\u5FC5\u586B\uFF09").option("--media-links <urls>", "\u9017\u53F7\u5206\u9694\u7684\u5A92\u4F53\u94FE\u63A5\uFF08\u9009\u586B\uFF0C\u6700\u591A 20 \u6761\uFF0Chttp/https\uFF09").action(async (id, opts) => {
|
|
709
|
+
const token = requireToken();
|
|
710
|
+
try {
|
|
711
|
+
const body = postUpdateSchema.parse({
|
|
712
|
+
title: opts.title,
|
|
713
|
+
body: opts.body,
|
|
714
|
+
mediaLinks: toMediaLinks(opts.mediaLinks)
|
|
715
|
+
});
|
|
716
|
+
const data = await apiRequest(`/api/posts/${id}`, { method: "PATCH", body, token, apiUrl: opts.apiUrl });
|
|
717
|
+
console.log(JSON.stringify(data, null, 2));
|
|
718
|
+
} catch (error) {
|
|
719
|
+
handleCommandError(error, UPDATE_EXAMPLES2);
|
|
720
|
+
}
|
|
721
|
+
}),
|
|
722
|
+
{ examples: UPDATE_EXAMPLES2 }
|
|
723
|
+
);
|
|
724
|
+
attachMeta(
|
|
725
|
+
withApiUrl(post.command("delete <id>").description("\u5220\u9664\u5185\u5BB9\uFF08\u4F5C\u8005\u672C\u4EBA\uFF0C\u6216\u6709\u5220\u9664\u4EFB\u610F\u5185\u5BB9\u7684\u6743\u9650\uFF09")).action(
|
|
726
|
+
async (id, opts) => {
|
|
727
|
+
const token = requireToken();
|
|
728
|
+
const data = await apiRequest(`/api/posts/${id}`, { method: "DELETE", token, apiUrl: opts.apiUrl });
|
|
729
|
+
console.log(JSON.stringify(data, null, 2));
|
|
730
|
+
}
|
|
731
|
+
),
|
|
732
|
+
{ examples: DELETE_EXAMPLES2 }
|
|
733
|
+
);
|
|
734
|
+
attachMeta(
|
|
735
|
+
withApiUrl(post.command("review <id>").description("\u5BA1\u6838\u4E00\u6761\u5F85\u5BA1\u5185\u5BB9\uFF08approve / reject\uFF09")).requiredOption("--action <action>", "approve | reject").option("--comment <text>", "\u5BA1\u6838\u610F\u89C1\uFF0C\u6700\u591A 500 \u5B57\uFF08reject \u65F6\u5FC5\u586B\uFF09").action(async (id, opts) => {
|
|
736
|
+
const token = requireToken();
|
|
737
|
+
try {
|
|
738
|
+
const body = postReviewSchema.parse({ action: opts.action, reviewComment: opts.comment });
|
|
739
|
+
const data = await apiRequest(`/api/posts/${id}/review`, { method: "POST", body, token, apiUrl: opts.apiUrl });
|
|
740
|
+
console.log(JSON.stringify(data, null, 2));
|
|
741
|
+
} catch (error) {
|
|
742
|
+
handleCommandError(error, REVIEW_EXAMPLES);
|
|
743
|
+
}
|
|
744
|
+
}),
|
|
745
|
+
{ permission: "content:review\uFF0C\u4E14\u4E0D\u80FD\u5BA1\u6838\u81EA\u5DF1\u53D1\u5E03\u7684\u5185\u5BB9", examples: REVIEW_EXAMPLES }
|
|
479
746
|
);
|
|
480
747
|
}
|
|
481
748
|
|
|
749
|
+
// src/commands/schema.ts
|
|
750
|
+
var CODE_DESCRIPTION = {
|
|
751
|
+
ok: "\u6210\u529F",
|
|
752
|
+
unhandled: "\u672A\u5206\u7C7B\u9519\u8BEF",
|
|
753
|
+
validation: "\u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF08\u672C\u5730\u6216\u670D\u52A1\u7AEF\uFF09",
|
|
754
|
+
unauthenticated: "\u672A\u767B\u5F55\u6216 token \u5DF2\u5931\u6548\uFF0C\u9700\u8981 pdlab login",
|
|
755
|
+
forbidden: "\u65E0\u6743\u9650\uFF08\u670D\u52A1\u7AEF 403\uFF09",
|
|
756
|
+
not_found: "\u8D44\u6E90\u4E0D\u5B58\u5728\uFF08\u670D\u52A1\u7AEF 404\uFF09",
|
|
757
|
+
conflict: "\u72B6\u6001\u51B2\u7A81\uFF0C\u4F8B\u5982\u91CD\u590D\u5BA1\u6838\uFF08\u670D\u52A1\u7AEF 409\uFF09",
|
|
758
|
+
network: "\u8FDE\u4E0D\u4E0A API \u670D\u52A1\u5668",
|
|
759
|
+
unknown: "\u672A\u5206\u7C7B\u7684\u670D\u52A1\u7AEF\u9519\u8BEF"
|
|
760
|
+
};
|
|
761
|
+
function exitCodeTable() {
|
|
762
|
+
const table = {};
|
|
763
|
+
for (const [code, exitStatus] of Object.entries(EXIT_CODES)) {
|
|
764
|
+
if (table[exitStatus] === void 0) table[exitStatus] = CODE_DESCRIPTION[code];
|
|
765
|
+
}
|
|
766
|
+
return table;
|
|
767
|
+
}
|
|
768
|
+
function serialize(command) {
|
|
769
|
+
const meta = getMeta(command);
|
|
770
|
+
return {
|
|
771
|
+
name: command.name(),
|
|
772
|
+
description: command.description(),
|
|
773
|
+
permission: meta.permission,
|
|
774
|
+
arguments: command.registeredArguments.map((a) => ({ name: a.name(), required: a.required })),
|
|
775
|
+
options: command.options.map((o) => ({ flags: o.flags, description: o.description, required: o.mandatory })),
|
|
776
|
+
examples: meta.examples ?? [],
|
|
777
|
+
subcommands: command.commands.map(serialize)
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
function registerSchemaCommand(program2) {
|
|
781
|
+
program2.command("schema").description("\u4EE5 JSON \u8F93\u51FA\u5B8C\u6574\u547D\u4EE4\u6811\uFF08\u542B\u53C2\u6570\u3001\u6743\u9650\u8981\u6C42\u3001\u793A\u4F8B\uFF09\u548C\u9000\u51FA\u7801\u542B\u4E49\uFF0C\u4F9B agent/\u811A\u672C\u4E00\u6B21\u6027\u8BFB\u53D6").action(() => {
|
|
782
|
+
console.log(
|
|
783
|
+
JSON.stringify(
|
|
784
|
+
{
|
|
785
|
+
exitCodes: exitCodeTable(),
|
|
786
|
+
commands: program2.commands.map(serialize)
|
|
787
|
+
},
|
|
788
|
+
null,
|
|
789
|
+
2
|
|
790
|
+
)
|
|
791
|
+
);
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
|
|
482
795
|
// src/index.ts
|
|
483
796
|
var pkg = JSON.parse((0, import_fs2.readFileSync)((0, import_path2.join)(__dirname, "../package.json"), "utf8"));
|
|
484
797
|
var program = new import_commander.Command();
|
|
485
|
-
program.name("pdlab").description("1836 \u5F00\u6E90\u5171\u5EFA\u5E73\u53F0\u547D\u4EE4\u884C\u5DE5\u5177\u2014\u2014\u662F\u73B0\u6709 REST API \u7684\u8584\u5C01\u88C5").version(pkg.version);
|
|
798
|
+
program.name("pdlab").description("1836 \u5F00\u6E90\u5171\u5EFA\u5E73\u53F0\u547D\u4EE4\u884C\u5DE5\u5177\u2014\u2014\u662F\u73B0\u6709 REST API \u7684\u8584\u5C01\u88C5\u3002\u7ED9 agent/\u811A\u672C\u7528\uFF1Apdlab schema \u4E00\u6B21\u6027\u5217\u51FA\u5168\u90E8\u547D\u4EE4\u3001\u53C2\u6570\u4E0E\u9000\u51FA\u7801\u542B\u4E49\u3002").version(pkg.version);
|
|
486
799
|
registerLoginCommand(program);
|
|
487
800
|
registerRegisterCommand(program);
|
|
488
801
|
registerLogoutCommand(program);
|
|
@@ -490,11 +803,7 @@ registerWhoamiCommand(program);
|
|
|
490
803
|
registerConfigCommand(program);
|
|
491
804
|
registerProjectCommand(program);
|
|
492
805
|
registerPostCommand(program);
|
|
806
|
+
registerSchemaCommand(program);
|
|
493
807
|
program.parseAsync(process.argv).catch((error) => {
|
|
494
|
-
|
|
495
|
-
console.error(`\u9519\u8BEF\uFF1A${error.message}`);
|
|
496
|
-
} else {
|
|
497
|
-
console.error(error);
|
|
498
|
-
}
|
|
499
|
-
process.exit(1);
|
|
808
|
+
handleCommandError(error);
|
|
500
809
|
});
|