@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/README.md CHANGED
@@ -1,3 +1,74 @@
1
1
  # @wcs-edu-os/cli
2
2
 
3
- WCS-Edu 管理员 CLI,支持 R0 查询与受 dry-run、确认令牌、幂等键保护的 R1 创建/编辑命令。详细文档随源码仓库提供,二进制名称为 `wcs-edu`。
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.0";
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-Edu base URL", ExitCode.VALIDATION, false, { profile: name }, [
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.0";
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-Edu \u7BA1\u7406\u5458\u547D\u4EE4\u884C\u5DE5\u5177").addHelpText("after", `
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);