@wcs-edu-os/cli 0.1.0 → 0.1.1
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/LICENSE +661 -0
- package/README.md +72 -1
- package/dist/index.js +32 -32
- package/dist/index.js.map +1 -1
- package/package.json +45 -25
package/README.md
CHANGED
|
@@ -1,3 +1,74 @@
|
|
|
1
1
|
# @wcs-edu-os/cli
|
|
2
2
|
|
|
3
|
-
WCS
|
|
3
|
+
WCS EDU OS 开源管理员 CLI,命令入口为 `wcs-edu-os`。它通过网关 API 查询和管理课程、用户、题库及考试资源,适合管理员、自动化脚本和 AI Agent 使用。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @wcs-edu-os/cli
|
|
9
|
+
wcs-edu-os version --output json
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
也可以使用 npx:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx --yes @wcs-edu-os/cli doctor --output json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
要求 Node.js 22 或更高版本。
|
|
19
|
+
|
|
20
|
+
## 配置认证
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
export WCS_EDU_BASE_URL=https://edu.example.com
|
|
24
|
+
export WCS_EDU_APP_KEY=your-app-key
|
|
25
|
+
export WCS_EDU_APP_SECRET=your-app-secret
|
|
26
|
+
wcs-edu-os doctor --output table
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
不希望把 secret 放入环境变量时,可以通过标准输入传入:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
printf '%s' "$WCS_EDU_APP_SECRET" | wcs-edu-os --secret-stdin auth test --output json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 常用命令
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
wcs-edu-os guide getting-started
|
|
39
|
+
wcs-edu-os capabilities --output json
|
|
40
|
+
wcs-edu-os category list --output table
|
|
41
|
+
wcs-edu-os lecturer list --output table
|
|
42
|
+
wcs-edu-os course list --output json
|
|
43
|
+
wcs-edu-os course get <courseId> --output json
|
|
44
|
+
wcs-edu-os question list --output json
|
|
45
|
+
wcs-edu-os paper list --output json
|
|
46
|
+
wcs-edu-os exam list --output json
|
|
47
|
+
wcs-edu-os user list --page 1 --size 20 --output json
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
非交互环境默认输出 JSON;终端环境可使用 `--output table`。分页列表支持 `--page`、`--size`、`--max-items` 和重复的 `--filter key=value`。
|
|
51
|
+
|
|
52
|
+
## 安全写操作
|
|
53
|
+
|
|
54
|
+
创建和编辑命令必须先使用 `--dry-run` 生成确认令牌,再使用确认令牌和幂等键执行。CLI 不会自动重试写请求,也不会在命令行参数中接收密码。
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
wcs-edu-os course create --input course.json --dry-run --output json
|
|
58
|
+
wcs-edu-os course create --input course.json \
|
|
59
|
+
--confirm-token "$WCS_CONFIRM_TOKEN" \
|
|
60
|
+
--idempotency-key "course-create-20261102-001" \
|
|
61
|
+
--output json
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 输出协议
|
|
65
|
+
|
|
66
|
+
JSON 结果使用固定信封字段:`schemaVersion`、`ok`、`command`、`requestId`、`data`、`page`、`warnings`、`meta` 和 `error`。诊断信息写入 stderr,并自动脱敏。
|
|
67
|
+
|
|
68
|
+
## 相关链接
|
|
69
|
+
|
|
70
|
+
- [项目源码](https://codeup.aliyun.com/qixin/base/opens/wcs-edu)
|
|
71
|
+
|
|
72
|
+
完整命令和参数可通过 wcs-edu-os --help 及 wcs-edu-os guide all 查看。
|
|
73
|
+
|
|
74
|
+
许可证:AGPL-3.0-only,与 wcs-edu 开源项目一致。
|
package/dist/index.js
CHANGED
|
@@ -411,7 +411,7 @@ function maskIdentifier(value2) {
|
|
|
411
411
|
}
|
|
412
412
|
|
|
413
413
|
// ../core/src/http.ts
|
|
414
|
-
var USER_AGENT = "@wcs-edu-os/cli/0.1.
|
|
414
|
+
var USER_AGENT = "@wcs-edu-os/cli/0.1.1";
|
|
415
415
|
var HttpClient = class {
|
|
416
416
|
constructor(baseUrl) {
|
|
417
417
|
this.baseUrl = baseUrl;
|
|
@@ -660,9 +660,9 @@ import { homedir } from "os";
|
|
|
660
660
|
import { join } from "path";
|
|
661
661
|
function getCacheDir(env = process.env) {
|
|
662
662
|
if (env.WCS_EDU_CACHE_DIR) return env.WCS_EDU_CACHE_DIR;
|
|
663
|
-
if (process.platform === "win32") return join(env.LOCALAPPDATA ?? join(homedir(), "AppData", "Local"), "wcs-edu-cli");
|
|
664
|
-
if (process.platform === "darwin") return join(homedir(), "Library", "Caches", "wcs-edu-cli");
|
|
665
|
-
return join(env.XDG_CACHE_HOME ?? join(homedir(), ".cache"), "wcs-edu-cli");
|
|
663
|
+
if (process.platform === "win32") return join(env.LOCALAPPDATA ?? join(homedir(), "AppData", "Local"), "wcs-edu-os-cli");
|
|
664
|
+
if (process.platform === "darwin") return join(homedir(), "Library", "Caches", "wcs-edu-os-cli");
|
|
665
|
+
return join(env.XDG_CACHE_HOME ?? join(homedir(), ".cache"), "wcs-edu-os-cli");
|
|
666
666
|
}
|
|
667
667
|
function credentialFingerprint(baseUrl, appKey) {
|
|
668
668
|
return createHash("sha256").update(`${baseUrl}\0${appKey}`).digest("hex").slice(0, 16);
|
|
@@ -918,9 +918,9 @@ import YAML from "yaml";
|
|
|
918
918
|
var EMPTY_PROFILES = { profiles: {} };
|
|
919
919
|
function getConfigDir(env = process.env) {
|
|
920
920
|
if (env.WCS_EDU_CONFIG_DIR) return env.WCS_EDU_CONFIG_DIR;
|
|
921
|
-
if (process.platform === "win32") return join3(env.APPDATA ?? join3(homedir2(), "AppData", "Roaming"), "wcs-edu-cli");
|
|
922
|
-
if (process.platform === "darwin") return join3(homedir2(), "Library", "Application Support", "wcs-edu-cli");
|
|
923
|
-
return join3(env.XDG_CONFIG_HOME ?? join3(homedir2(), ".config"), "wcs-edu-cli");
|
|
921
|
+
if (process.platform === "win32") return join3(env.APPDATA ?? join3(homedir2(), "AppData", "Roaming"), "wcs-edu-os-cli");
|
|
922
|
+
if (process.platform === "darwin") return join3(homedir2(), "Library", "Application Support", "wcs-edu-os-cli");
|
|
923
|
+
return join3(env.XDG_CONFIG_HOME ?? join3(homedir2(), ".config"), "wcs-edu-os-cli");
|
|
924
924
|
}
|
|
925
925
|
function getProfilePath(env = process.env) {
|
|
926
926
|
return join3(getConfigDir(env), "profiles.yml");
|
|
@@ -961,7 +961,7 @@ async function resolveProfile(explicitName, env = process.env) {
|
|
|
961
961
|
const source = explicitName ? "argument" : env.WCS_EDU_PROFILE ? "environment" : config.currentProfile ? "current" : "default";
|
|
962
962
|
const baseUrl = env.WCS_EDU_BASE_URL ?? config.profiles[name]?.baseUrl;
|
|
963
963
|
if (!baseUrl) {
|
|
964
|
-
throw new CliError("BASE_URL_MISSING", "\u672A\u914D\u7F6E WCS
|
|
964
|
+
throw new CliError("BASE_URL_MISSING", "\u672A\u914D\u7F6E WCS EDU OS base URL", ExitCode.VALIDATION, false, { profile: name }, [
|
|
965
965
|
"\u8BBE\u7F6E WCS_EDU_BASE_URL",
|
|
966
966
|
`\u6216\u6267\u884C profile use ${name} --base-url <url>`
|
|
967
967
|
]);
|
|
@@ -988,7 +988,7 @@ function isNotFound(error) {
|
|
|
988
988
|
import { createHash as createHash3 } from "crypto";
|
|
989
989
|
import { z as z3 } from "zod";
|
|
990
990
|
import Table from "cli-table3";
|
|
991
|
-
var VERSION = "0.1.
|
|
991
|
+
var VERSION = "0.1.1";
|
|
992
992
|
async function runCommand(spec2, rawInput, globals, io) {
|
|
993
993
|
const id = requestId(globals.requestId);
|
|
994
994
|
const started = Date.now();
|
|
@@ -1270,24 +1270,24 @@ function buildGuide(topic) {
|
|
|
1270
1270
|
summary: "\u5B89\u88C5 CLI\u3001\u914D\u7F6E\u7F51\u5173\u548C\u51ED\u636E\uFF0C\u7136\u540E\u7528 doctor \u9A8C\u8BC1\u8FDE\u63A5\u3002",
|
|
1271
1271
|
commands: [
|
|
1272
1272
|
"npm install -g @wcs-edu-os/cli",
|
|
1273
|
-
"wcs-edu version",
|
|
1274
|
-
"wcs-edu profile use test --base-url https://edu.example.com",
|
|
1275
|
-
"wcs-edu doctor --output table",
|
|
1276
|
-
"wcs-edu auth test --non-interactive --output json"
|
|
1273
|
+
"wcs-edu-os version",
|
|
1274
|
+
"wcs-edu-os profile use test --base-url https://edu.example.com",
|
|
1275
|
+
"wcs-edu-os doctor --output table",
|
|
1276
|
+
"wcs-edu-os auth test --non-interactive --output json"
|
|
1277
1277
|
],
|
|
1278
1278
|
environment: ["WCS_EDU_BASE_URL", "WCS_EDU_APP_KEY", "WCS_EDU_APP_SECRET \u6216 --secret-stdin"],
|
|
1279
|
-
prompt: "\u8BF7\u5148\u8FD0\u884C wcs-edu doctor\uFF1B\u5982\u679C\u901A\u8FC7\uFF0C\u5E2E\u6211\u67E5\u770B\u5F53\u524D\u7BA1\u7406\u5458\u8EAB\u4EFD\u548C\u53EF\u7528\u6743\u9650\u3002"
|
|
1279
|
+
prompt: "\u8BF7\u5148\u8FD0\u884C wcs-edu-os doctor\uFF1B\u5982\u679C\u901A\u8FC7\uFF0C\u5E2E\u6211\u67E5\u770B\u5F53\u524D\u7BA1\u7406\u5458\u8EAB\u4EFD\u548C\u53EF\u7528\u6743\u9650\u3002"
|
|
1280
1280
|
},
|
|
1281
1281
|
course: {
|
|
1282
1282
|
title: "\u8BFE\u7A0B\u7BA1\u7406\u6D41\u7A0B",
|
|
1283
1283
|
summary: "\u5148\u67E5\u5206\u7C7B\u548C\u8BB2\u5E08\uFF0C\u518D\u67E5\u8BE2\u8BFE\u7A0B\u3001\u7AE0\u8282\uFF1B\u521B\u5EFA\u6216\u66F4\u65B0\u5FC5\u987B\u5148 dry-run\u3002",
|
|
1284
1284
|
commands: [
|
|
1285
|
-
"wcs-edu category list --output table",
|
|
1286
|
-
"wcs-edu lecturer list --output table",
|
|
1287
|
-
"wcs-edu course list --keyword \u5173\u952E\u8BCD --output table",
|
|
1288
|
-
"wcs-edu course get <courseId> --output json",
|
|
1289
|
-
"wcs-edu course chapter list <courseId> --output json",
|
|
1290
|
-
"wcs-edu course create --input course.json --dry-run --output json"
|
|
1285
|
+
"wcs-edu-os category list --output table",
|
|
1286
|
+
"wcs-edu-os lecturer list --output table",
|
|
1287
|
+
"wcs-edu-os course list --keyword \u5173\u952E\u8BCD --output table",
|
|
1288
|
+
"wcs-edu-os course get <courseId> --output json",
|
|
1289
|
+
"wcs-edu-os course chapter list <courseId> --output json",
|
|
1290
|
+
"wcs-edu-os course create --input course.json --dry-run --output json"
|
|
1291
1291
|
],
|
|
1292
1292
|
prompt: "\u8BF7\u5148\u5217\u51FA\u8BFE\u7A0B\u5206\u7C7B\u3001\u8BB2\u5E08\u548C\u8BFE\u7A0B\uFF0C\u627E\u5230\u76EE\u6807\u8BFE\u7A0B\u540E\u5C55\u793A\u8BE6\u60C5\u4E0E\u7AE0\u8282\uFF1B\u4EFB\u4F55\u5199\u64CD\u4F5C\u5148\u7ED9\u51FA dry-run \u8BA1\u5212\uFF0C\u4E0D\u8981\u76F4\u63A5\u63D0\u4EA4\u3002"
|
|
1293
1293
|
},
|
|
@@ -1295,10 +1295,10 @@ function buildGuide(topic) {
|
|
|
1295
1295
|
title: "\u9898\u5E93\u4E0E\u8003\u8BD5\u67E5\u8BE2",
|
|
1296
1296
|
summary: "\u6309\u8BD5\u9898\u3001\u8BD5\u5377\u3001\u8003\u8BD5\u4E09\u5C42\u67E5\u8BE2\uFF0C\u5148\u5217\u51FA\u8D44\u6E90\u518D\u67E5\u770B\u8BE6\u60C5\u3002",
|
|
1297
1297
|
commands: [
|
|
1298
|
-
"wcs-edu question list --output table",
|
|
1299
|
-
"wcs-edu paper list --output table",
|
|
1300
|
-
"wcs-edu exam list --output table",
|
|
1301
|
-
"wcs-edu exam get <examId> --output json"
|
|
1298
|
+
"wcs-edu-os question list --output table",
|
|
1299
|
+
"wcs-edu-os paper list --output table",
|
|
1300
|
+
"wcs-edu-os exam list --output table",
|
|
1301
|
+
"wcs-edu-os exam get <examId> --output json"
|
|
1302
1302
|
],
|
|
1303
1303
|
prompt: "\u8BF7\u5148\u5217\u51FA\u53EF\u7528\u8BD5\u5377\u548C\u8003\u8BD5\uFF0C\u6309\u540D\u79F0\u6216\u72B6\u6001\u7B5B\u9009\uFF1B\u627E\u5230\u76EE\u6807\u540E\u67E5\u8BE2\u8BE6\u60C5\uFF0C\u5E76\u8BF4\u660E\u5F53\u524D CLI \u4E0D\u652F\u6301\u53D1\u5E03\u3001\u5220\u9664\u548C\u6279\u91CF\u6307\u6D3E\u3002"
|
|
1304
1304
|
},
|
|
@@ -1306,13 +1306,13 @@ function buildGuide(topic) {
|
|
|
1306
1306
|
title: "\u5B89\u5168\u5199\u64CD\u4F5C",
|
|
1307
1307
|
summary: "\u521B\u5EFA\u548C\u66F4\u65B0\u53EA\u63A5\u53D7 JSON \u8F93\u5165\uFF0C\u5FC5\u987B\u7ECF\u8FC7 dry-run\u3001\u786E\u8BA4\u4EE4\u724C\u548C\u5E42\u7B49\u952E\u3002",
|
|
1308
1308
|
commands: [
|
|
1309
|
-
"wcs-edu course update --input course.json --dry-run --output json",
|
|
1310
|
-
"wcs-edu course update --input course.json --confirm-token <token> --idempotency-key <unique-key> --output json"
|
|
1309
|
+
"wcs-edu-os course update --input course.json --dry-run --output json",
|
|
1310
|
+
"wcs-edu-os course update --input course.json --confirm-token <token> --idempotency-key <unique-key> --output json"
|
|
1311
1311
|
],
|
|
1312
1312
|
prompt: "\u8BF7\u68C0\u67E5\u8FD9\u4EFD JSON \u7684\u5B57\u6BB5\u548C\u76EE\u6807\u73AF\u5883\uFF0C\u5148\u6267\u884C dry-run\uFF0C\u89E3\u91CA\u526F\u4F5C\u7528\u3001\u56DE\u6EDA\u65B9\u5F0F\u548C\u786E\u8BA4\u7801\u6709\u6548\u671F\uFF0C\u7B49\u5F85\u6211\u786E\u8BA4\u540E\u518D\u63D0\u4EA4\u3002"
|
|
1313
1313
|
}
|
|
1314
1314
|
};
|
|
1315
|
-
if (topic === "all") return { topics: Object.values(guides), hint: "\u4F7F\u7528 wcs-edu guide <topic> \u67E5\u770B\u5355\u4E2A\u4E3B\u9898\u3002" };
|
|
1315
|
+
if (topic === "all") return { topics: Object.values(guides), hint: "\u4F7F\u7528 wcs-edu-os guide <topic> \u67E5\u770B\u5355\u4E2A\u4E3B\u9898\u3002" };
|
|
1316
1316
|
return guides[topic] ?? guides["getting-started"];
|
|
1317
1317
|
}
|
|
1318
1318
|
function chooseOutput(explicit, isTTY) {
|
|
@@ -1362,13 +1362,13 @@ function isRecord4(value2) {
|
|
|
1362
1362
|
// src/program.ts
|
|
1363
1363
|
function createProgram(io) {
|
|
1364
1364
|
const program = new Command();
|
|
1365
|
-
program.name("wcs-edu").description("WCS
|
|
1365
|
+
program.name("wcs-edu-os").description("WCS EDU OS \u5F00\u6E90\u7BA1\u7406\u5458\u547D\u4EE4\u884C\u5DE5\u5177").addHelpText("after", `
|
|
1366
1366
|
\u9996\u6B21\u4F7F\u7528\uFF1A
|
|
1367
1367
|
npm install -g @wcs-edu-os/cli
|
|
1368
|
-
wcs-edu guide getting-started
|
|
1369
|
-
wcs-edu doctor
|
|
1368
|
+
wcs-edu-os guide getting-started
|
|
1369
|
+
wcs-edu-os doctor
|
|
1370
1370
|
|
|
1371
|
-
\u5E38\u7528\u4E3B\u9898\uFF1Awcs-edu guide course | wcs-edu guide exam | wcs-edu guide write
|
|
1371
|
+
\u5E38\u7528\u4E3B\u9898\uFF1Awcs-edu-os guide course | wcs-edu-os guide exam | wcs-edu-os guide write
|
|
1372
1372
|
`).showHelpAfterError().exitOverride().option("--profile <name>", "\u9009\u62E9 Profile").option("--output <format>", "\u8F93\u51FA\u683C\u5F0F: json|jsonl|table").option("--non-interactive", "\u7981\u7528\u4EA4\u4E92\u63D0\u793A").option("--secret-stdin", "\u4ECE\u6807\u51C6\u8F93\u5165\u8BFB\u53D6 appSecret").option("--request-id <id>", "\u8BF7\u6C42\u94FE\u8DEF\u6807\u8BC6").option("--timeout <ms>", "\u8BF7\u6C42\u8D85\u65F6\u6BEB\u79D2\u6570", "10000").option("--no-color", "\u7981\u7528 ANSI \u989C\u8272").option("--debug", "\u8F93\u51FA\u8131\u654F\u8BCA\u65AD\u4FE1\u606F\u5230 stderr");
|
|
1373
1373
|
program.option("--dry-run", "\u4EC5\u6821\u9A8C\u5199\u8BA1\u5212\u5E76\u751F\u6210\u786E\u8BA4\u4EE4\u724C").option("--confirm-token <token>", "\u6267\u884C dry-run \u751F\u6210\u7684\u786E\u8BA4\u4EE4\u724C").option("--idempotency-key <key>", "\u5199\u8BF7\u6C42\u5E42\u7B49\u952E");
|
|
1374
1374
|
for (const spec2 of commandRegistry) registerSpec(program, spec2, io);
|
|
@@ -1402,7 +1402,7 @@ function registerSpec(program, spec2, io) {
|
|
|
1402
1402
|
}
|
|
1403
1403
|
const leaf = new Command(spec2.segments.at(-1)).description(spec2.description).exitOverride();
|
|
1404
1404
|
leaf.addHelpText("after", `
|
|
1405
|
-
\u793A\u4F8B\uFF1Awcs-edu ${spec2.segments.join(" ")} --output json
|
|
1405
|
+
\u793A\u4F8B\uFF1Awcs-edu-os ${spec2.segments.join(" ")} --output json
|
|
1406
1406
|
`);
|
|
1407
1407
|
for (const argument of spec2.arguments) {
|
|
1408
1408
|
leaf.argument(argument.required ? `<${argument.name}>` : `[${argument.name}]`, argument.description);
|