@pmate/cli 0.20.1 → 0.20.2

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/dist/index.d.ts CHANGED
@@ -121,12 +121,31 @@ type SummaryCommandArgs = {
121
121
  };
122
122
  type QuizCommandArgs = {
123
123
  type: Command.Quiz;
124
- action: "publish";
124
+ action: "create-draft";
125
+ paperId: string;
126
+ apiBaseUrl?: string;
127
+ linkBaseUrl?: string;
128
+ } | {
129
+ type: Command.Quiz;
130
+ action: "update-meta";
131
+ paperId: string;
125
132
  filePath: string;
133
+ apiBaseUrl?: string;
134
+ linkBaseUrl?: string;
135
+ } | {
136
+ type: Command.Quiz;
137
+ action: "append-step";
126
138
  paperId: string;
139
+ filePath: string;
140
+ apiBaseUrl?: string;
141
+ linkBaseUrl?: string;
142
+ } | {
143
+ type: Command.Quiz;
144
+ action: "reorder";
145
+ paperId: string;
146
+ stepIds: string[];
127
147
  apiBaseUrl?: string;
128
148
  linkBaseUrl?: string;
129
- activate: boolean;
130
149
  } | {
131
150
  type: Command.Quiz;
132
151
  action: "activate";
package/dist/index.js CHANGED
@@ -13271,7 +13271,14 @@ var LoginCommandHandler = class {
13271
13271
  if (!token) {
13272
13272
  response.statusCode = 400;
13273
13273
  response.setHeader("Content-Type", "text/html; charset=utf-8");
13274
- response.end(this.renderHtml("Login failed", "Missing sessionId in redirect URL."));
13274
+ response.end(
13275
+ this.renderHtml({
13276
+ state: "error",
13277
+ title: "Login failed",
13278
+ message: "Missing sessionId in redirect URL.",
13279
+ hint: "Please retry from your terminal with `pmate login`."
13280
+ })
13281
+ );
13275
13282
  rejectToken(new Error("Login callback did not include sessionId."));
13276
13283
  return;
13277
13284
  }
@@ -13280,30 +13287,106 @@ var LoginCommandHandler = class {
13280
13287
  response.setHeader("Connection", "close");
13281
13288
  response.end(
13282
13289
  this.renderHtml(
13283
- "Login complete",
13284
- "You can close this tab and return to the terminal."
13290
+ {
13291
+ state: "success",
13292
+ title: "Login complete",
13293
+ message: "You can close this tab and return to the terminal.",
13294
+ hint: "This window is only used to hand the session back to PMate CLI."
13295
+ }
13285
13296
  ),
13286
13297
  () => resolveToken(token)
13287
13298
  );
13288
13299
  }
13289
- renderHtml(title, message) {
13300
+ renderHtml(input) {
13301
+ const badgeBg = input.state === "success" ? "#ecfdf3" : "#fff1f2";
13302
+ const badgeText = input.state === "success" ? "#027a48" : "#be123c";
13303
+ const dotColor = input.state === "success" ? "#10b981" : "#f43f5e";
13304
+ const stateText = input.state === "success" ? "Ready" : "Action required";
13305
+ const hint = input.hint?.trim();
13290
13306
  return `<!doctype html>
13291
13307
  <html lang="en">
13292
13308
  <head>
13293
13309
  <meta charset="utf-8" />
13294
13310
  <meta name="viewport" content="width=device-width, initial-scale=1" />
13295
- <title>${title}</title>
13311
+ <title>${input.title}</title>
13296
13312
  <style>
13297
- body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; padding: 32px; color: #111; }
13298
- main { max-width: 560px; margin: 10vh auto; }
13299
- h1 { font-size: 28px; margin-bottom: 12px; }
13300
- p { font-size: 16px; line-height: 1.5; }
13313
+ :root {
13314
+ color-scheme: light;
13315
+ }
13316
+ * {
13317
+ box-sizing: border-box;
13318
+ }
13319
+ body {
13320
+ margin: 0;
13321
+ min-height: 100vh;
13322
+ font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
13323
+ color: #0f172a;
13324
+ background:
13325
+ radial-gradient(circle at 18% 18%, #e0f2fe 0, transparent 36%),
13326
+ radial-gradient(circle at 82% 14%, #e0e7ff 0, transparent 34%),
13327
+ linear-gradient(180deg, #f8fafc 0%, #eef2ff 100%);
13328
+ display: grid;
13329
+ place-items: center;
13330
+ padding: 24px;
13331
+ }
13332
+ main {
13333
+ width: min(560px, 100%);
13334
+ border-radius: 28px;
13335
+ border: 1px solid rgba(15, 23, 42, 0.08);
13336
+ background: rgba(255, 255, 255, 0.9);
13337
+ box-shadow:
13338
+ 0 22px 56px rgba(15, 23, 42, 0.14),
13339
+ inset 0 1px 0 rgba(255, 255, 255, 0.75);
13340
+ backdrop-filter: blur(8px);
13341
+ padding: 28px;
13342
+ }
13343
+ .badge {
13344
+ display: inline-flex;
13345
+ align-items: center;
13346
+ gap: 8px;
13347
+ border-radius: 999px;
13348
+ padding: 8px 12px;
13349
+ font-size: 14px;
13350
+ font-weight: 600;
13351
+ background: ${badgeBg};
13352
+ color: ${badgeText};
13353
+ }
13354
+ .dot {
13355
+ width: 10px;
13356
+ height: 10px;
13357
+ border-radius: 999px;
13358
+ background: ${dotColor};
13359
+ }
13360
+ h1 {
13361
+ margin: 16px 0 8px;
13362
+ font-size: 32px;
13363
+ line-height: 1.18;
13364
+ letter-spacing: -0.03em;
13365
+ }
13366
+ p {
13367
+ margin: 0;
13368
+ font-size: 16px;
13369
+ line-height: 1.6;
13370
+ color: #334155;
13371
+ }
13372
+ .hint {
13373
+ margin-top: 16px;
13374
+ border-radius: 14px;
13375
+ background: rgba(148, 163, 184, 0.14);
13376
+ padding: 12px 14px;
13377
+ font-size: 14px;
13378
+ }
13301
13379
  </style>
13302
13380
  </head>
13303
13381
  <body>
13304
13382
  <main>
13305
- <h1>${title}</h1>
13306
- <p>${message}</p>
13383
+ <div class="badge">
13384
+ <span class="dot"></span>
13385
+ <span>${stateText}</span>
13386
+ </div>
13387
+ <h1>${input.title}</h1>
13388
+ <p>${input.message}</p>
13389
+ ${hint ? `<p class="hint">${hint}</p>` : ""}
13307
13390
  </main>
13308
13391
  </body>
13309
13392
  </html>`;
@@ -17966,22 +18049,22 @@ init_sessionStore();
17966
18049
  var INTRO_STEP_COUNT = 2;
17967
18050
  var QUIZ_APP_ID = "quiz";
17968
18051
  var DEFAULT_MIN_LENGTHS = Object.freeze({
17969
- knowledgeSummary: 36,
18052
+ teachingArticle: 36,
17970
18053
  explanation: 60
17971
18054
  });
17972
18055
  var INTRO_MIN_LENGTHS = Object.freeze({
17973
- knowledgeSummary: 90,
17974
- knowledgeNote: 36,
18056
+ teachingArticle: 90,
18057
+ teachingTip: 36,
17975
18058
  explanation: 90
17976
18059
  });
17977
18060
  var FIELD_RULES = Object.freeze({
17978
- knowledgeSummary: Object.freeze({
17979
- label: "knowledgeSummary\uFF08\u77E5\u8BC6\u8BB2\u89E3\uFF09",
18061
+ teachingArticle: Object.freeze({
18062
+ label: "teachingArticle\uFF08\u6559\u5B66\u77ED\u6587\uFF09",
17980
18063
  defaultHint: "\u77E5\u8BC6\u8BB2\u89E3\u81F3\u5C11\u8981\u5148\u628A\u9898\u76EE\u524D\u63D0\u8BF4\u6E05\u695A\uFF0C\u518D\u8BA9\u7528\u6237\u53BB\u9009\u7B54\u6848\u3002",
17981
18064
  introHint: "\u5F00\u573A\u9898\u81F3\u5C11\u8981\u8BB2\u6E05\u5B83\u662F\u4EC0\u4E48\u3001\u89E3\u51B3\u4EC0\u4E48\u95EE\u9898\uFF0C\u4EE5\u53CA\u8BFB\u8005\u63A5\u4E0B\u6765\u8BE5\u5E26\u7740\u4EC0\u4E48\u7406\u89E3\u8DEF\u5F84\u7EE7\u7EED\u5F80\u4E0B\u770B\u3002"
17982
18065
  }),
17983
- knowledgeNote: Object.freeze({
17984
- label: "knowledgeNote\uFF08\u8865\u5145\u8BF4\u660E\uFF09",
18066
+ teachingTip: Object.freeze({
18067
+ label: "teachingTip\uFF08\u8865\u5145\u8BF4\u660E\uFF09",
17985
18068
  introHint: "\u5F00\u573A\u9898\u8981\u8865\u5145\u4E3A\u4EC0\u4E48\u5BB9\u6613\u8BEF\u89E3\uFF0C\u6216\u8005\u7B2C\u4E00\u6B21\u8BFB\u8FD9\u5757\u5185\u5BB9\u65F6\u5E94\u8BE5\u5148\u770B\u54EA\u91CC\u3002"
17986
18069
  }),
17987
18070
  explanation: Object.freeze({
@@ -18021,9 +18104,9 @@ function validateQuizPaperPayload(payload) {
18021
18104
  assertMinLength(
18022
18105
  step,
18023
18106
  index,
18024
- "knowledgeSummary",
18025
- DEFAULT_MIN_LENGTHS.knowledgeSummary,
18026
- FIELD_RULES.knowledgeSummary.defaultHint
18107
+ "teachingArticle",
18108
+ DEFAULT_MIN_LENGTHS.teachingArticle,
18109
+ FIELD_RULES.teachingArticle.defaultHint
18027
18110
  );
18028
18111
  assertMinLength(
18029
18112
  step,
@@ -18038,16 +18121,16 @@ function validateQuizPaperPayload(payload) {
18038
18121
  assertMinLength(
18039
18122
  step,
18040
18123
  index,
18041
- "knowledgeSummary",
18042
- INTRO_MIN_LENGTHS.knowledgeSummary,
18043
- FIELD_RULES.knowledgeSummary.introHint
18124
+ "teachingArticle",
18125
+ INTRO_MIN_LENGTHS.teachingArticle,
18126
+ FIELD_RULES.teachingArticle.introHint
18044
18127
  );
18045
18128
  assertMinLength(
18046
18129
  step,
18047
18130
  index,
18048
- "knowledgeNote",
18049
- INTRO_MIN_LENGTHS.knowledgeNote,
18050
- FIELD_RULES.knowledgeNote.introHint
18131
+ "teachingTip",
18132
+ INTRO_MIN_LENGTHS.teachingTip,
18133
+ FIELD_RULES.teachingTip.introHint
18051
18134
  );
18052
18135
  assertMinLength(
18053
18136
  step,
@@ -18195,6 +18278,131 @@ async function activateQuizPaper({
18195
18278
  data: activated
18196
18279
  };
18197
18280
  }
18281
+ async function createQuizDraft({
18282
+ fetchImpl = fetch,
18283
+ apiBaseUrl,
18284
+ linkBaseUrl,
18285
+ paperId,
18286
+ token
18287
+ }) {
18288
+ const trimmedApiBaseUrl = apiBaseUrl.replace(/\/+$/, "");
18289
+ const trimmedLinkBaseUrl = linkBaseUrl.replace(/\/+$/, "");
18290
+ const previewLink = `${trimmedLinkBaseUrl}/?paper=${encodeURIComponent(paperId)}`;
18291
+ const data = await requestJson(
18292
+ fetchImpl,
18293
+ `${trimmedApiBaseUrl}/api/quiz/papers`,
18294
+ {
18295
+ method: "POST",
18296
+ headers: {
18297
+ Authorization: `Bearer ${token}`,
18298
+ "Content-Type": "application/json"
18299
+ },
18300
+ body: JSON.stringify({ paperId })
18301
+ },
18302
+ "\u521B\u5EFA\u8349\u7A3F"
18303
+ );
18304
+ return {
18305
+ apiBaseUrl: trimmedApiBaseUrl,
18306
+ paperId,
18307
+ previewLink,
18308
+ data
18309
+ };
18310
+ }
18311
+ async function updateQuizPaperMetadata({
18312
+ fetchImpl = fetch,
18313
+ apiBaseUrl,
18314
+ linkBaseUrl,
18315
+ paperId,
18316
+ metadata,
18317
+ token
18318
+ }) {
18319
+ const trimmedApiBaseUrl = apiBaseUrl.replace(/\/+$/, "");
18320
+ const trimmedLinkBaseUrl = linkBaseUrl.replace(/\/+$/, "");
18321
+ const previewLink = `${trimmedLinkBaseUrl}/?paper=${encodeURIComponent(paperId)}`;
18322
+ const data = await requestJson(
18323
+ fetchImpl,
18324
+ `${trimmedApiBaseUrl}/api/quiz/papers/${encodeURIComponent(paperId)}`,
18325
+ {
18326
+ method: "PATCH",
18327
+ headers: {
18328
+ Authorization: `Bearer ${token}`,
18329
+ "Content-Type": "application/json"
18330
+ },
18331
+ body: JSON.stringify(metadata)
18332
+ },
18333
+ "\u66F4\u65B0\u8BD5\u5377\u5143\u4FE1\u606F"
18334
+ );
18335
+ return {
18336
+ apiBaseUrl: trimmedApiBaseUrl,
18337
+ paperId,
18338
+ previewLink,
18339
+ data
18340
+ };
18341
+ }
18342
+ async function appendQuizPaperStep({
18343
+ fetchImpl = fetch,
18344
+ apiBaseUrl,
18345
+ linkBaseUrl,
18346
+ paperId,
18347
+ step,
18348
+ token
18349
+ }) {
18350
+ const trimmedApiBaseUrl = apiBaseUrl.replace(/\/+$/, "");
18351
+ const trimmedLinkBaseUrl = linkBaseUrl.replace(/\/+$/, "");
18352
+ const previewLink = `${trimmedLinkBaseUrl}/?paper=${encodeURIComponent(paperId)}`;
18353
+ const data = await requestJson(
18354
+ fetchImpl,
18355
+ `${trimmedApiBaseUrl}/api/quiz/papers/${encodeURIComponent(paperId)}/steps`,
18356
+ {
18357
+ method: "POST",
18358
+ headers: {
18359
+ Authorization: `Bearer ${token}`,
18360
+ "Content-Type": "application/json"
18361
+ },
18362
+ body: JSON.stringify(step)
18363
+ },
18364
+ `\u8FFD\u52A0\u9898\u76EE\uFF08${String(step?.stepId ?? "unknown-step")}\uFF09`
18365
+ );
18366
+ return {
18367
+ apiBaseUrl: trimmedApiBaseUrl,
18368
+ paperId,
18369
+ previewLink,
18370
+ data
18371
+ };
18372
+ }
18373
+ async function reorderQuizPaperSteps({
18374
+ fetchImpl = fetch,
18375
+ apiBaseUrl,
18376
+ linkBaseUrl,
18377
+ paperId,
18378
+ stepIds,
18379
+ token
18380
+ }) {
18381
+ const trimmedApiBaseUrl = apiBaseUrl.replace(/\/+$/, "");
18382
+ const trimmedLinkBaseUrl = linkBaseUrl.replace(/\/+$/, "");
18383
+ const previewLink = `${trimmedLinkBaseUrl}/?paper=${encodeURIComponent(paperId)}`;
18384
+ const data = await requestJson(
18385
+ fetchImpl,
18386
+ `${trimmedApiBaseUrl}/api/quiz/papers/${encodeURIComponent(paperId)}/steps/reorder`,
18387
+ {
18388
+ method: "POST",
18389
+ headers: {
18390
+ Authorization: `Bearer ${token}`,
18391
+ "Content-Type": "application/json"
18392
+ },
18393
+ body: JSON.stringify({
18394
+ stepIds
18395
+ })
18396
+ },
18397
+ "\u91CD\u6392\u9898\u76EE\u987A\u5E8F"
18398
+ );
18399
+ return {
18400
+ apiBaseUrl: trimmedApiBaseUrl,
18401
+ paperId,
18402
+ previewLink,
18403
+ data
18404
+ };
18405
+ }
18198
18406
  async function viewQuizPaper({
18199
18407
  fetchImpl = fetch,
18200
18408
  apiBaseUrl,
@@ -18257,26 +18465,76 @@ var QuizCommandHandler = class {
18257
18465
  const apiBaseUrl = args.apiBaseUrl || DEFAULT_QUIZ_API_BASE_URL;
18258
18466
  const linkBaseUrl = args.linkBaseUrl || DEFAULT_QUIZ_LINK_BASE_URL;
18259
18467
  if (args.action === "activate") {
18260
- const result2 = await activateQuizPaper({
18468
+ const result = await activateQuizPaper({
18469
+ apiBaseUrl,
18470
+ linkBaseUrl,
18471
+ paperId: args.paperId,
18472
+ token: session.token
18473
+ });
18474
+ ui.success("Quiz \u5DF2\u6FC0\u6D3B\u53D1\u5E03", result.link);
18475
+ return;
18476
+ }
18477
+ if (args.action === "create-draft") {
18478
+ const result = await createQuizDraft({
18261
18479
  apiBaseUrl,
18262
18480
  linkBaseUrl,
18263
18481
  paperId: args.paperId,
18264
18482
  token: session.token
18265
18483
  });
18266
- ui.success("Quiz \u5DF2\u6FC0\u6D3B\u53D1\u5E03", result2.link);
18484
+ ui.success("Quiz \u8349\u7A3F\u5DF2\u521B\u5EFA", result.previewLink);
18485
+ ui.info("\u72B6\u6001", "draft");
18486
+ return;
18487
+ }
18488
+ if (args.action === "update-meta") {
18489
+ const resolvedFilePath = import_node_path14.default.resolve(process.cwd(), args.filePath);
18490
+ const metadata = JSON.parse((0, import_node_fs9.readFileSync)(resolvedFilePath, "utf8"));
18491
+ const result = await updateQuizPaperMetadata({
18492
+ apiBaseUrl,
18493
+ linkBaseUrl,
18494
+ paperId: args.paperId,
18495
+ metadata,
18496
+ token: session.token
18497
+ });
18498
+ ui.success("Quiz \u5143\u4FE1\u606F\u5DF2\u66F4\u65B0", result.previewLink);
18499
+ return;
18500
+ }
18501
+ if (args.action === "append-step") {
18502
+ const resolvedFilePath = import_node_path14.default.resolve(process.cwd(), args.filePath);
18503
+ const step = JSON.parse((0, import_node_fs9.readFileSync)(resolvedFilePath, "utf8"));
18504
+ const result = await appendQuizPaperStep({
18505
+ apiBaseUrl,
18506
+ linkBaseUrl,
18507
+ paperId: args.paperId,
18508
+ step,
18509
+ token: session.token
18510
+ });
18511
+ ui.success("Quiz \u9898\u76EE\u5DF2\u8FFD\u52A0", result.previewLink);
18512
+ ui.info("stepId", String(step.stepId));
18513
+ return;
18514
+ }
18515
+ if (args.action === "reorder") {
18516
+ const result = await reorderQuizPaperSteps({
18517
+ apiBaseUrl,
18518
+ linkBaseUrl,
18519
+ paperId: args.paperId,
18520
+ stepIds: args.stepIds,
18521
+ token: session.token
18522
+ });
18523
+ ui.success("Quiz \u9898\u76EE\u987A\u5E8F\u5DF2\u66F4\u65B0", result.previewLink);
18524
+ ui.info("\u6570\u91CF", String(args.stepIds.length));
18267
18525
  return;
18268
18526
  }
18269
18527
  if (args.action === "view") {
18270
- const result2 = await viewQuizPaper({
18528
+ const result = await viewQuizPaper({
18271
18529
  apiBaseUrl,
18272
18530
  linkBaseUrl,
18273
18531
  paperId: args.paperId,
18274
18532
  token: session.token
18275
18533
  });
18276
- ui.success("Quiz \u8BD5\u5377\u5DF2\u627E\u5230", result2.previewLink);
18277
- ui.info("\u72B6\u6001", result2.paperStatus);
18278
- if (typeof result2.stepCount === "number") {
18279
- ui.info("\u9898\u76EE\u6570", String(result2.stepCount));
18534
+ ui.success("Quiz \u8BD5\u5377\u5DF2\u627E\u5230", result.previewLink);
18535
+ ui.info("\u72B6\u6001", result.paperStatus);
18536
+ if (typeof result.stepCount === "number") {
18537
+ ui.info("\u9898\u76EE\u6570", String(result.stepCount));
18280
18538
  }
18281
18539
  return;
18282
18540
  }
@@ -18291,13 +18549,13 @@ var QuizCommandHandler = class {
18291
18549
  if (targetIndex < 0) {
18292
18550
  throw new Error(`\u672A\u627E\u5230 stepId=${args.stepId}\uFF0C\u65E0\u6CD5\u66F4\u65B0\u8BE5\u9898\u76EE\u3002`);
18293
18551
  }
18294
- const resolvedFilePath2 = import_node_path14.default.resolve(process.cwd(), args.filePath);
18295
- const nextStep = JSON.parse((0, import_node_fs9.readFileSync)(resolvedFilePath2, "utf8"));
18552
+ const resolvedFilePath = import_node_path14.default.resolve(process.cwd(), args.filePath);
18553
+ const nextStep = JSON.parse((0, import_node_fs9.readFileSync)(resolvedFilePath, "utf8"));
18296
18554
  nextStep.stepId = args.stepId;
18297
18555
  const nextSteps = [...basePaper.steps];
18298
18556
  nextSteps[targetIndex] = nextStep;
18299
18557
  const nextPaperId = args.newPaperId || `${args.paperId}-rev-${this.timestampTag()}`;
18300
- const result2 = await publishQuizPaper({
18558
+ const result = await publishQuizPaper({
18301
18559
  apiBaseUrl,
18302
18560
  linkBaseUrl,
18303
18561
  paperId: nextPaperId,
@@ -18311,37 +18569,20 @@ var QuizCommandHandler = class {
18311
18569
  token: session.token,
18312
18570
  activate: args.activate
18313
18571
  });
18314
- if (result2.status === "draft") {
18315
- ui.success("Quiz \u5355\u9898\u4FEE\u8BA2\u7A3F\u5DF2\u521B\u5EFA", result2.previewLink);
18572
+ if (result.status === "draft") {
18573
+ ui.success("Quiz \u5355\u9898\u4FEE\u8BA2\u7A3F\u5DF2\u521B\u5EFA", result.previewLink);
18316
18574
  ui.info("\u6765\u6E90\u8BD5\u5377", args.paperId);
18317
18575
  ui.info("\u4FEE\u8BA2\u9898\u76EE", args.stepId);
18318
18576
  ui.info("\u65B0\u8BD5\u5377", nextPaperId);
18319
18577
  ui.info("\u4E0B\u4E00\u6B65", `pmate quiz activate --paper-id ${nextPaperId}`);
18320
18578
  return;
18321
18579
  }
18322
- ui.success("Quiz \u5355\u9898\u4FEE\u8BA2\u7A3F\u5DF2\u53D1\u5E03", result2.link);
18580
+ ui.success("Quiz \u5355\u9898\u4FEE\u8BA2\u7A3F\u5DF2\u53D1\u5E03", result.link);
18323
18581
  ui.info("\u6765\u6E90\u8BD5\u5377", args.paperId);
18324
18582
  ui.info("\u4FEE\u8BA2\u9898\u76EE", args.stepId);
18325
18583
  ui.info("\u65B0\u8BD5\u5377", nextPaperId);
18326
18584
  return;
18327
18585
  }
18328
- const resolvedFilePath = import_node_path14.default.resolve(process.cwd(), args.filePath);
18329
- const payload = JSON.parse((0, import_node_fs9.readFileSync)(resolvedFilePath, "utf8"));
18330
- const result = await publishQuizPaper({
18331
- apiBaseUrl,
18332
- linkBaseUrl,
18333
- paperId: args.paperId,
18334
- payload,
18335
- token: session.token,
18336
- activate: args.activate
18337
- });
18338
- if (result.status === "draft") {
18339
- ui.success("Quiz \u8349\u7A3F\u5DF2\u521B\u5EFA", result.previewLink);
18340
- ui.info("\u72B6\u6001", "draft");
18341
- ui.info("\u4E0B\u4E00\u6B65", `pmate quiz activate --paper-id ${args.paperId}`);
18342
- return;
18343
- }
18344
- ui.success("Quiz \u5DF2\u53D1\u5E03", result.link);
18345
18586
  }
18346
18587
  timestampTag() {
18347
18588
  const now = /* @__PURE__ */ new Date();
@@ -21992,7 +22233,10 @@ var HELP_TEXT = [
21992
22233
  ` ${import_chalk3.default.cyan("summary")} Summarize a GitHub PR with AI`,
21993
22234
  ` ${import_chalk3.default.gray(" --pr <id> [--cwd <dir>]")}`,
21994
22235
  ` ${import_chalk3.default.cyan("quiz")} Manage quiz papers on quiz-api`,
21995
- ` ${import_chalk3.default.gray(" publish --file <json> --paper-id <id> [--activate]")}`,
22236
+ ` ${import_chalk3.default.gray(" create-draft --paper-id <id>")}`,
22237
+ ` ${import_chalk3.default.gray(" update-meta --paper-id <id> --file <metadata.json>")}`,
22238
+ ` ${import_chalk3.default.gray(" append-step --paper-id <id> --file <step.json>")}`,
22239
+ ` ${import_chalk3.default.gray(" reorder --paper-id <id> --step-ids <id1,id2,...>")}`,
21996
22240
  ` ${import_chalk3.default.gray(" activate --paper-id <id>")}`,
21997
22241
  ` ${import_chalk3.default.gray(" view --paper-id <id>")}`,
21998
22242
  ` ${import_chalk3.default.gray(" edit-step --paper-id <id> --step-id <step-id> --file <step.json> [--new-paper-id <id>] [--activate]")}`,
@@ -22592,50 +22836,158 @@ function parseQuizArgs(tokens) {
22592
22836
  const rest = [...tokens];
22593
22837
  const action = rest.shift();
22594
22838
  if (!action) {
22595
- throw new Error("Missing quiz action. Usage: quiz publish|activate|view");
22839
+ throw new Error("Missing quiz action. Usage: quiz create-draft|update-meta|append-step|reorder|activate|view|edit-step");
22596
22840
  }
22597
- if (action === "publish") {
22598
- let filePath;
22841
+ if (action === "create-draft") {
22599
22842
  let paperId;
22600
22843
  let apiBaseUrl;
22601
22844
  let linkBaseUrl;
22602
- let activate = false;
22603
22845
  while (rest.length > 0) {
22604
22846
  const token = rest.shift();
22605
22847
  switch (token) {
22848
+ case "--paper-id":
22849
+ paperId = requireValue8(rest, token);
22850
+ break;
22851
+ case "--base-url":
22852
+ apiBaseUrl = requireValue8(rest, token);
22853
+ break;
22854
+ case "--link-base":
22855
+ linkBaseUrl = requireValue8(rest, token);
22856
+ break;
22857
+ default:
22858
+ throw new Error(`Unknown quiz create-draft option: ${token}`);
22859
+ }
22860
+ }
22861
+ if (!paperId) {
22862
+ throw new Error("Missing --paper-id. Usage: quiz create-draft --paper-id <id>.");
22863
+ }
22864
+ return {
22865
+ type: "quiz" /* Quiz */,
22866
+ action: "create-draft",
22867
+ paperId,
22868
+ apiBaseUrl,
22869
+ linkBaseUrl
22870
+ };
22871
+ }
22872
+ if (action === "update-meta") {
22873
+ let paperId;
22874
+ let filePath;
22875
+ let apiBaseUrl;
22876
+ let linkBaseUrl;
22877
+ while (rest.length > 0) {
22878
+ const token = rest.shift();
22879
+ switch (token) {
22880
+ case "--paper-id":
22881
+ paperId = requireValue8(rest, token);
22882
+ break;
22606
22883
  case "--file":
22607
22884
  filePath = requireValue8(rest, token);
22608
22885
  break;
22886
+ case "--base-url":
22887
+ apiBaseUrl = requireValue8(rest, token);
22888
+ break;
22889
+ case "--link-base":
22890
+ linkBaseUrl = requireValue8(rest, token);
22891
+ break;
22892
+ default:
22893
+ throw new Error(`Unknown quiz update-meta option: ${token}`);
22894
+ }
22895
+ }
22896
+ if (!paperId) {
22897
+ throw new Error("Missing --paper-id. Usage: quiz update-meta --paper-id <id> --file <metadata.json>.");
22898
+ }
22899
+ if (!filePath) {
22900
+ throw new Error("Missing --file. Usage: quiz update-meta --paper-id <id> --file <metadata.json>.");
22901
+ }
22902
+ return {
22903
+ type: "quiz" /* Quiz */,
22904
+ action: "update-meta",
22905
+ paperId,
22906
+ filePath,
22907
+ apiBaseUrl,
22908
+ linkBaseUrl
22909
+ };
22910
+ }
22911
+ if (action === "append-step") {
22912
+ let paperId;
22913
+ let filePath;
22914
+ let apiBaseUrl;
22915
+ let linkBaseUrl;
22916
+ while (rest.length > 0) {
22917
+ const token = rest.shift();
22918
+ switch (token) {
22609
22919
  case "--paper-id":
22610
22920
  paperId = requireValue8(rest, token);
22611
22921
  break;
22922
+ case "--file":
22923
+ filePath = requireValue8(rest, token);
22924
+ break;
22612
22925
  case "--base-url":
22613
22926
  apiBaseUrl = requireValue8(rest, token);
22614
22927
  break;
22615
22928
  case "--link-base":
22616
22929
  linkBaseUrl = requireValue8(rest, token);
22617
22930
  break;
22618
- case "--activate":
22619
- activate = true;
22620
- break;
22621
22931
  default:
22622
- throw new Error(`Unknown quiz publish option: ${token}`);
22932
+ throw new Error(`Unknown quiz append-step option: ${token}`);
22623
22933
  }
22624
22934
  }
22935
+ if (!paperId) {
22936
+ throw new Error("Missing --paper-id. Usage: quiz append-step --paper-id <id> --file <step.json>.");
22937
+ }
22625
22938
  if (!filePath) {
22626
- throw new Error("Missing --file. Usage: quiz publish --file <json> --paper-id <id>.");
22939
+ throw new Error("Missing --file. Usage: quiz append-step --paper-id <id> --file <step.json>.");
22940
+ }
22941
+ return {
22942
+ type: "quiz" /* Quiz */,
22943
+ action: "append-step",
22944
+ paperId,
22945
+ filePath,
22946
+ apiBaseUrl,
22947
+ linkBaseUrl
22948
+ };
22949
+ }
22950
+ if (action === "reorder") {
22951
+ let paperId;
22952
+ let stepIdsRaw;
22953
+ let apiBaseUrl;
22954
+ let linkBaseUrl;
22955
+ while (rest.length > 0) {
22956
+ const token = rest.shift();
22957
+ switch (token) {
22958
+ case "--paper-id":
22959
+ paperId = requireValue8(rest, token);
22960
+ break;
22961
+ case "--step-ids":
22962
+ stepIdsRaw = requireValue8(rest, token);
22963
+ break;
22964
+ case "--base-url":
22965
+ apiBaseUrl = requireValue8(rest, token);
22966
+ break;
22967
+ case "--link-base":
22968
+ linkBaseUrl = requireValue8(rest, token);
22969
+ break;
22970
+ default:
22971
+ throw new Error(`Unknown quiz reorder option: ${token}`);
22972
+ }
22627
22973
  }
22628
22974
  if (!paperId) {
22629
- throw new Error("Missing --paper-id. Usage: quiz publish --file <json> --paper-id <id>.");
22975
+ throw new Error("Missing --paper-id. Usage: quiz reorder --paper-id <id> --step-ids <id1,id2,...>.");
22976
+ }
22977
+ if (!stepIdsRaw) {
22978
+ throw new Error("Missing --step-ids. Usage: quiz reorder --paper-id <id> --step-ids <id1,id2,...>.");
22979
+ }
22980
+ const stepIds = stepIdsRaw.split(",").map((item) => item.trim()).filter(Boolean);
22981
+ if (stepIds.length === 0) {
22982
+ throw new Error("Invalid --step-ids. At least one step id is required.");
22630
22983
  }
22631
22984
  return {
22632
22985
  type: "quiz" /* Quiz */,
22633
- action: "publish",
22634
- filePath,
22986
+ action: "reorder",
22635
22987
  paperId,
22988
+ stepIds,
22636
22989
  apiBaseUrl,
22637
- linkBaseUrl,
22638
- activate
22990
+ linkBaseUrl
22639
22991
  };
22640
22992
  }
22641
22993
  if (action === "activate") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pmate/cli",
3
- "version": "0.20.1",
3
+ "version": "0.20.2",
4
4
  "description": "CLI utilities for the pMate project",
5
5
  "license": "MIT",
6
6
  "bin": {