@chalksurf/cli 0.2.4 → 0.3.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.
@@ -7,20 +7,33 @@ import { hideBin } from "yargs/helpers";
7
7
  import yargs from "yargs/yargs";
8
8
 
9
9
  // src/lib/api-client.ts
10
+ var ApiClientError = class extends Error {
11
+ agentErrorCode;
12
+ constructor(message, options = {}) {
13
+ super(message);
14
+ this.name = "ApiClientError";
15
+ this.agentErrorCode = options.agentErrorCode;
16
+ }
17
+ };
10
18
  var normalizeBaseUrl = (baseUrl) => {
11
19
  return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
12
20
  };
13
21
  var getErrorMessage = (payload, status) => {
14
22
  return payload?.error?.message ?? `API request failed with status ${status}`;
15
23
  };
24
+ var getAgentErrorCode = (payload) => payload?.error?.data?.agentErrorCode;
16
25
  var getResponseData = async ({ response, batched }) => {
17
26
  const body = await response.json();
18
27
  const payload = batched ? body[0] : body;
19
28
  if (!response.ok) {
20
- throw new Error(getErrorMessage(payload, response.status));
29
+ throw new ApiClientError(getErrorMessage(payload, response.status), {
30
+ agentErrorCode: getAgentErrorCode(payload)
31
+ });
21
32
  }
22
33
  if (payload?.error) {
23
- throw new Error(payload.error.message);
34
+ throw new ApiClientError(payload.error.message, {
35
+ agentErrorCode: getAgentErrorCode(payload)
36
+ });
24
37
  }
25
38
  if (!payload?.result) {
26
39
  throw new Error("API response is missing a result payload");
@@ -101,30 +114,78 @@ var createApiClient = ({
101
114
  agentGetExerciseUsage: async (id) => {
102
115
  return await query("agentGetExerciseUsage", { id });
103
116
  },
117
+ agentListExerciseLabels: async () => {
118
+ return await query("agentListExerciseLabels", {});
119
+ },
104
120
  agentCopyExercise: async (id) => {
105
121
  return await mutation("agentCopyExercise", { id });
106
122
  },
123
+ agentDeleteExercise: async (input) => {
124
+ return await mutation("agentDeleteExercise", input);
125
+ },
126
+ agentCreateExercise: async (input) => {
127
+ return await mutation("agentCreateExercise", input);
128
+ },
107
129
  agentUpdateExercise: async (input) => {
108
130
  return await mutation("agentUpdateExercise", input);
109
131
  },
132
+ agentSetExerciseVisibility: async (input) => {
133
+ return await mutation("agentSetExerciseVisibility", input);
134
+ },
135
+ agentStartExerciseTranslationGeneration: async (input) => {
136
+ return await mutation(
137
+ "agentStartExerciseTranslationGeneration",
138
+ input
139
+ );
140
+ },
110
141
  agentGetSheet: async (id) => {
111
142
  return await query("agentGetSheet", { id });
112
143
  },
144
+ agentListSheetVersions: async (id) => {
145
+ return await query("agentListSheetVersions", { id });
146
+ },
147
+ agentGetSheetVersion: async (exerciseSheetId, versionId) => {
148
+ return await query("agentGetSheetVersion", { exerciseSheetId, versionId });
149
+ },
113
150
  agentGetSheetIssues: async (id) => {
114
151
  return await query("agentGetSheetIssues", { id });
115
152
  },
116
153
  agentCopySheet: async (input) => {
117
154
  return await mutation("agentCopySheet", input);
118
155
  },
156
+ agentDeleteSheet: async (input) => {
157
+ return await mutation("agentDeleteSheet", input);
158
+ },
159
+ agentCreateSheet: async (input) => {
160
+ return await mutation("agentCreateSheet", input);
161
+ },
119
162
  agentUpdateSheet: async (input) => {
120
163
  return await mutation("agentUpdateSheet", input);
121
164
  },
165
+ agentSetSheetVisibility: async (input) => {
166
+ return await mutation("agentSetSheetVisibility", input);
167
+ },
168
+ agentStartSheetTranslationGeneration: async (input) => {
169
+ return await mutation(
170
+ "agentStartSheetTranslationGeneration",
171
+ input
172
+ );
173
+ },
122
174
  agentAppendExercisesToSheet: async (input) => {
123
175
  return await mutation("agentAppendExercisesToSheet", input);
124
176
  },
125
177
  agentListFolders: async () => {
126
178
  return await query("agentListFolders", {});
127
179
  },
180
+ agentSendUserFeedback: async (input) => {
181
+ return await mutation("agentSendUserFeedback", input);
182
+ },
183
+ agentSendAgentFeedback: async (input) => {
184
+ return await mutation("agentSendAgentFeedback", input);
185
+ },
186
+ agentDeleteFolder: async (input) => {
187
+ return await mutation("agentDeleteFolder", input);
188
+ },
128
189
  agentCreateFolder: async (input) => {
129
190
  return await mutation("agentCreateFolder", input);
130
191
  },
@@ -157,14 +218,16 @@ var createSerializableCliError = ({
157
218
  code,
158
219
  exitCode,
159
220
  message,
160
- retryable
221
+ retryable,
222
+ agentErrorCode
161
223
  }) => {
162
224
  const resolvedCode = code ?? getCliErrorCode(exitCode);
163
225
  return {
164
226
  code: resolvedCode,
165
227
  exitCode,
166
228
  message,
167
- retryable: retryable ?? isRetryableCliErrorCode(resolvedCode)
229
+ retryable: retryable ?? isRetryableCliErrorCode(resolvedCode),
230
+ ...agentErrorCode ? { agentErrorCode } : {}
168
231
  };
169
232
  };
170
233
  var CliCommandError = class extends Error {
@@ -172,6 +235,7 @@ var CliCommandError = class extends Error {
172
235
  exitCode;
173
236
  retryable;
174
237
  shouldReport;
238
+ agentErrorCode;
175
239
  constructor(message, exitCode, shouldReport = true, options = {}) {
176
240
  super(message);
177
241
  this.name = "CliCommandError";
@@ -179,6 +243,7 @@ var CliCommandError = class extends Error {
179
243
  this.exitCode = exitCode;
180
244
  this.retryable = options.retryable ?? isRetryableCliErrorCode(this.code);
181
245
  this.shouldReport = shouldReport;
246
+ this.agentErrorCode = options.agentErrorCode;
182
247
  }
183
248
  };
184
249
  var serializeCliError = (error) => {
@@ -186,7 +251,8 @@ var serializeCliError = (error) => {
186
251
  code: error.code,
187
252
  exitCode: error.exitCode,
188
253
  message: error.message,
189
- retryable: error.retryable
254
+ retryable: error.retryable,
255
+ agentErrorCode: error.agentErrorCode
190
256
  });
191
257
  };
192
258
 
@@ -587,10 +653,15 @@ var normalizeOptionalString2 = (value) => {
587
653
  };
588
654
  var mapApiErrorToCliError = (error) => {
589
655
  const message = error instanceof Error ? error.message : "Unknown API error";
656
+ const agentErrorCode = error instanceof ApiClientError ? error.agentErrorCode : void 0;
590
657
  if (message.includes("UNAUTHORIZED")) {
591
- return new CliCommandError("Authentication failed. The CLI token is invalid or revoked.", 3);
658
+ return new CliCommandError("Authentication failed. The CLI token is invalid or revoked.", 3, true, {
659
+ agentErrorCode
660
+ });
592
661
  }
593
- return new CliCommandError(`API request failed: ${message}`, 5);
662
+ return new CliCommandError(`API request failed: ${message}`, 5, true, {
663
+ agentErrorCode
664
+ });
594
665
  };
595
666
  var requireResolvedBaseUrl = ({
596
667
  flagValue,
@@ -867,7 +938,461 @@ ${formatOrganizationSummary(result.organization)}`,
867
938
  };
868
939
 
869
940
  // src/commands/exercise.ts
870
- import { z as z8 } from "zod";
941
+ import { z as z11 } from "zod";
942
+
943
+ // ../shared/src/labels.json
944
+ var labels_default = [
945
+ {
946
+ id: "algebra",
947
+ name: "algebra",
948
+ children: [
949
+ {
950
+ id: "algebra.identities",
951
+ name: "identities"
952
+ },
953
+ {
954
+ id: "algebra.inequalities",
955
+ name: "inequalities"
956
+ },
957
+ {
958
+ id: "algebra.equations",
959
+ name: "equations",
960
+ children: [
961
+ {
962
+ id: "algebra.equations.linear_equation",
963
+ name: "linear equation"
964
+ },
965
+ {
966
+ id: "algebra.equations.quadratic_equation",
967
+ name: "quadratic equation"
968
+ },
969
+ {
970
+ id: "algebra.equations.higher_order_equation",
971
+ name: "higher order equation"
972
+ },
973
+ {
974
+ id: "algebra.equations.absolute_value_equation",
975
+ name: "absolute value equation"
976
+ },
977
+ {
978
+ id: "algebra.equations.diophantine_equation",
979
+ name: "Diophantine equation"
980
+ },
981
+ {
982
+ id: "algebra.equations.square_root_equation",
983
+ name: "square root equation"
984
+ },
985
+ {
986
+ id: "algebra.equations.exponential_logarithmic_equation",
987
+ name: "exponential, logarithmic equation"
988
+ },
989
+ {
990
+ id: "algebra.equations.trigonometric_equation",
991
+ name: "trigonometric equation"
992
+ },
993
+ {
994
+ id: "algebra.equations.parametric_equation",
995
+ name: "parametric equation"
996
+ },
997
+ {
998
+ id: "algebra.equations.equation_systems",
999
+ name: "equation systems"
1000
+ }
1001
+ ]
1002
+ },
1003
+ {
1004
+ id: "algebra.means",
1005
+ name: "means"
1006
+ }
1007
+ ]
1008
+ },
1009
+ {
1010
+ id: "arithmetic",
1011
+ name: "arithmetic",
1012
+ children: [
1013
+ {
1014
+ id: "arithmetic.counting",
1015
+ name: "counting"
1016
+ },
1017
+ {
1018
+ id: "arithmetic.fractions",
1019
+ name: "fractions"
1020
+ },
1021
+ {
1022
+ id: "arithmetic.proportionality",
1023
+ name: "proportionality"
1024
+ },
1025
+ {
1026
+ id: "arithmetic.digits",
1027
+ name: "digits"
1028
+ },
1029
+ {
1030
+ id: "arithmetic.powers",
1031
+ name: "powers"
1032
+ },
1033
+ {
1034
+ id: "arithmetic.percentage",
1035
+ name: "percentage"
1036
+ },
1037
+ {
1038
+ id: "arithmetic.square_roots",
1039
+ name: "(square) roots"
1040
+ },
1041
+ {
1042
+ id: "arithmetic.numeral_systems",
1043
+ name: "numeral systems"
1044
+ },
1045
+ {
1046
+ id: "arithmetic.units_of_measurement",
1047
+ name: "units of measurement"
1048
+ }
1049
+ ]
1050
+ },
1051
+ {
1052
+ id: "number_theory",
1053
+ name: "number theory",
1054
+ children: [
1055
+ {
1056
+ id: "number_theory.divisibility",
1057
+ name: "divisibility"
1058
+ },
1059
+ {
1060
+ id: "number_theory.prime_factorization",
1061
+ name: "prime factorization"
1062
+ },
1063
+ {
1064
+ id: "number_theory.primes_not_factorization",
1065
+ name: "primes (not factorization)"
1066
+ },
1067
+ {
1068
+ id: "number_theory.digits",
1069
+ name: "digits"
1070
+ },
1071
+ {
1072
+ id: "number_theory.modular_arithmetic",
1073
+ name: "modular arithmetic"
1074
+ }
1075
+ ]
1076
+ },
1077
+ {
1078
+ id: "analysis_functions",
1079
+ name: "analysis / functions",
1080
+ children: [
1081
+ {
1082
+ id: "analysis_functions.graph_of_a_function",
1083
+ name: "graph of a function"
1084
+ },
1085
+ {
1086
+ id: "analysis_functions.polynomials",
1087
+ name: "polynomials"
1088
+ },
1089
+ {
1090
+ id: "analysis_functions.monotonicity_of_function",
1091
+ name: "monotonicity of function"
1092
+ },
1093
+ {
1094
+ id: "analysis_functions.minimum_maximum_of_function",
1095
+ name: "minimum, maximum of function"
1096
+ },
1097
+ {
1098
+ id: "analysis_functions.zero_point_of_function",
1099
+ name: "zero point of function"
1100
+ },
1101
+ {
1102
+ id: "analysis_functions.derivatives",
1103
+ name: "derivatives"
1104
+ },
1105
+ {
1106
+ id: "analysis_functions.integration",
1107
+ name: "integration"
1108
+ },
1109
+ {
1110
+ id: "analysis_functions.limit_of_function",
1111
+ name: "limit of function"
1112
+ }
1113
+ ]
1114
+ },
1115
+ {
1116
+ id: "sequences",
1117
+ name: "sequences",
1118
+ children: [
1119
+ {
1120
+ id: "sequences.arithmetic_progression",
1121
+ name: "arithmetic progression"
1122
+ },
1123
+ {
1124
+ id: "sequences.geometric_progression",
1125
+ name: "geometric progression"
1126
+ },
1127
+ {
1128
+ id: "sequences.recursion",
1129
+ name: "recursion"
1130
+ },
1131
+ {
1132
+ id: "sequences.periodic",
1133
+ name: "periodic"
1134
+ },
1135
+ {
1136
+ id: "sequences.fibonacci",
1137
+ name: "Fibonacci"
1138
+ },
1139
+ {
1140
+ id: "sequences.monotonicity_boundedness",
1141
+ name: "monotonicity, boundedness"
1142
+ },
1143
+ {
1144
+ id: "sequences.limit",
1145
+ name: "limit"
1146
+ }
1147
+ ]
1148
+ },
1149
+ {
1150
+ id: "geometry",
1151
+ name: "geometry",
1152
+ children: [
1153
+ {
1154
+ id: "geometry.3d_geometry",
1155
+ name: "3D geometry",
1156
+ children: [
1157
+ {
1158
+ id: "geometry.3d_geometry.surface_area_volume",
1159
+ name: "surface area, volume"
1160
+ },
1161
+ {
1162
+ id: "geometry.3d_geometry.polyhedron_net",
1163
+ name: "polyhedron net"
1164
+ },
1165
+ {
1166
+ id: "geometry.3d_geometry.platonic_solids",
1167
+ name: "Platonic solids"
1168
+ },
1169
+ {
1170
+ id: "geometry.3d_geometry.cylinder",
1171
+ name: "cylinder"
1172
+ },
1173
+ {
1174
+ id: "geometry.3d_geometry.prism",
1175
+ name: "prism"
1176
+ },
1177
+ {
1178
+ id: "geometry.3d_geometry.pyramid",
1179
+ name: "pyramid"
1180
+ },
1181
+ {
1182
+ id: "geometry.3d_geometry.cone",
1183
+ name: "cone"
1184
+ },
1185
+ {
1186
+ id: "geometry.3d_geometry.3d_transformations",
1187
+ name: "3D transformations"
1188
+ }
1189
+ ]
1190
+ },
1191
+ {
1192
+ id: "geometry.vectors",
1193
+ name: "vectors"
1194
+ },
1195
+ {
1196
+ id: "geometry.coordinate_geometry",
1197
+ name: "coordinate geometry"
1198
+ },
1199
+ {
1200
+ id: "geometry.pythagorean_theorem",
1201
+ name: "Pythagorean theorem"
1202
+ },
1203
+ {
1204
+ id: "geometry.thales_theorem",
1205
+ name: "Thales theorem"
1206
+ },
1207
+ {
1208
+ id: "geometry.circumference_area",
1209
+ name: "circumference, area"
1210
+ },
1211
+ {
1212
+ id: "geometry.triangle",
1213
+ name: "triangle"
1214
+ },
1215
+ {
1216
+ id: "geometry.rectangle",
1217
+ name: "rectangle"
1218
+ },
1219
+ {
1220
+ id: "geometry.polygon",
1221
+ name: "polygon"
1222
+ },
1223
+ {
1224
+ id: "geometry.regular_polygon",
1225
+ name: "regular polygon"
1226
+ },
1227
+ {
1228
+ id: "geometry.circle",
1229
+ name: "circle"
1230
+ },
1231
+ {
1232
+ id: "geometry.conic_section",
1233
+ name: "conic section"
1234
+ },
1235
+ {
1236
+ id: "geometry.angles",
1237
+ name: "angles"
1238
+ },
1239
+ {
1240
+ id: "geometry.trigonometry",
1241
+ name: "trigonometry"
1242
+ },
1243
+ {
1244
+ id: "geometry.transformations",
1245
+ name: "transformations"
1246
+ },
1247
+ {
1248
+ id: "geometry.symmetry",
1249
+ name: "symmetry"
1250
+ },
1251
+ {
1252
+ id: "geometry.similarity",
1253
+ name: "similarity"
1254
+ }
1255
+ ]
1256
+ },
1257
+ {
1258
+ id: "probability_and_statistics",
1259
+ name: "probability and statistics",
1260
+ children: [
1261
+ {
1262
+ id: "probability_and_statistics.combinatorial_probability",
1263
+ name: "combinatorial probability"
1264
+ },
1265
+ {
1266
+ id: "probability_and_statistics.geometric_probability",
1267
+ name: "geometric probability"
1268
+ },
1269
+ {
1270
+ id: "probability_and_statistics.bayes_theorem",
1271
+ name: "Bayes theorem"
1272
+ },
1273
+ {
1274
+ id: "probability_and_statistics.independence",
1275
+ name: "independence"
1276
+ },
1277
+ {
1278
+ id: "probability_and_statistics.mean_variance",
1279
+ name: "mean, variance"
1280
+ },
1281
+ {
1282
+ id: "probability_and_statistics.statistics",
1283
+ name: "statistics"
1284
+ }
1285
+ ]
1286
+ },
1287
+ {
1288
+ id: "combinatorics",
1289
+ name: "combinatorics",
1290
+ children: [
1291
+ {
1292
+ id: "combinatorics.combination_variation",
1293
+ name: "combination, variation"
1294
+ },
1295
+ {
1296
+ id: "combinatorics.permutation",
1297
+ name: "permutation"
1298
+ },
1299
+ {
1300
+ id: "combinatorics.inclusion_exclusion",
1301
+ name: "inclusion exclusion"
1302
+ },
1303
+ {
1304
+ id: "combinatorics.geometric_combinatorics",
1305
+ name: "geometric combinatorics"
1306
+ }
1307
+ ]
1308
+ },
1309
+ {
1310
+ id: "graphs",
1311
+ name: "graphs",
1312
+ children: [
1313
+ {
1314
+ id: "graphs.plane_graphs",
1315
+ name: "plane graphs"
1316
+ },
1317
+ {
1318
+ id: "graphs.paths_walks",
1319
+ name: "paths, walks"
1320
+ },
1321
+ {
1322
+ id: "graphs.degrees",
1323
+ name: "degrees"
1324
+ },
1325
+ {
1326
+ id: "graphs.subgraph",
1327
+ name: "subgraph"
1328
+ },
1329
+ {
1330
+ id: "graphs.bipartite_graph",
1331
+ name: "bipartite graph"
1332
+ },
1333
+ {
1334
+ id: "graphs.oriented_graph",
1335
+ name: "oriented graph"
1336
+ }
1337
+ ]
1338
+ },
1339
+ {
1340
+ id: "set_theory",
1341
+ name: "set theory",
1342
+ children: [
1343
+ {
1344
+ id: "set_theory.set_arithmetics",
1345
+ name: "set arithmetics"
1346
+ },
1347
+ {
1348
+ id: "set_theory.inclusion_exclusion",
1349
+ name: "inclusion exclusion"
1350
+ },
1351
+ {
1352
+ id: "set_theory.de_morgan_identities",
1353
+ name: "de Morgan identities"
1354
+ },
1355
+ {
1356
+ id: "set_theory.intervals",
1357
+ name: "intervals"
1358
+ },
1359
+ {
1360
+ id: "set_theory.number_sets",
1361
+ name: "number sets"
1362
+ }
1363
+ ]
1364
+ },
1365
+ {
1366
+ id: "logic",
1367
+ name: "logic",
1368
+ children: [
1369
+ {
1370
+ id: "logic.logic_arithmetics",
1371
+ name: "logic arithmetics"
1372
+ },
1373
+ {
1374
+ id: "logic.true_false",
1375
+ name: "true false"
1376
+ },
1377
+ {
1378
+ id: "logic.recursive_logic",
1379
+ name: "recursive logic"
1380
+ },
1381
+ {
1382
+ id: "logic.winning_strategy",
1383
+ name: "winning strategy"
1384
+ },
1385
+ {
1386
+ id: "logic.tiling",
1387
+ name: "tiling"
1388
+ },
1389
+ {
1390
+ id: "logic.algorithm",
1391
+ name: "algorithm"
1392
+ }
1393
+ ]
1394
+ }
1395
+ ];
871
1396
 
872
1397
  // ../shared/src/agent-tools/index.ts
873
1398
  import { z } from "zod";
@@ -910,8 +1435,42 @@ var Constants = {
910
1435
  },
911
1436
  public: {
912
1437
  Enums: {
913
- event_type: ["feedback_sent", "feedback_abandoned", "error_report"],
1438
+ agent_audit_actor_kind: ["cli_token", "mcp_oauth"],
1439
+ agent_audit_operation: [
1440
+ "send_user_feedback",
1441
+ "send_agent_feedback",
1442
+ "copy_exercise",
1443
+ "copy_sheet",
1444
+ "update_exercise",
1445
+ "update_sheet",
1446
+ "append_exercises_to_sheet",
1447
+ "create_folder",
1448
+ "rename_folder",
1449
+ "delete_exercise",
1450
+ "delete_sheet",
1451
+ "delete_folder",
1452
+ "create_sheet",
1453
+ "create_exercise",
1454
+ "set_exercise_visibility",
1455
+ "set_sheet_visibility",
1456
+ "import_exercise_started",
1457
+ "import_exercise_completed",
1458
+ "import_exercise_solution_started",
1459
+ "import_exercise_solution_completed",
1460
+ "import_sheet_started",
1461
+ "import_sheet_completed",
1462
+ "import_sheet_solutions_started",
1463
+ "import_sheet_solutions_completed",
1464
+ "generate_exercise_translation_started",
1465
+ "generate_exercise_translation_completed",
1466
+ "generate_sheet_translation_started",
1467
+ "generate_sheet_translation_completed"
1468
+ ],
1469
+ agent_audit_outcome: ["started", "success", "failed", "denied"],
1470
+ agent_audit_resource_type: ["exercise", "sheet", "folder", "job", "event"],
1471
+ event_type: ["feedback_sent", "feedback_abandoned", "error_report", "user_feedback_sent", "agent_feedback_sent"],
914
1472
  exercise_sheet_translation_status: ["ready", "preparing", "failed"],
1473
+ exercise_sheet_version_type: ["backfill", "create", "manual_edit", "copy", "sheet_import", "revert"],
915
1474
  exercise_status: ["verified", "unverified", "invalid"],
916
1475
  exercise_subject: ["math", "physics", "chemistry", "informatics"],
917
1476
  exercise_version_type: [
@@ -966,12 +1525,23 @@ var latexValidationIssueCodes = [
966
1525
  // ../shared/src/types/types.ts
967
1526
  var exerciseStatusOptions = Constants.public.Enums.exercise_status;
968
1527
  var exerciseVersionTypes = Constants.public.Enums.exercise_version_type;
1528
+ var agentAuditActorKinds = Constants.public.Enums.agent_audit_actor_kind;
1529
+ var agentAuditOutcomes = Constants.public.Enums.agent_audit_outcome;
1530
+ var agentAuditOperations = Constants.public.Enums.agent_audit_operation;
1531
+ var agentAuditResourceTypes = Constants.public.Enums.agent_audit_resource_type;
969
1532
  var exerciseSheetTranslationStatuses = Constants.public.Enums.exercise_sheet_translation_status;
1533
+ var exerciseSheetVersionTypes = Constants.public.Enums.exercise_sheet_version_type;
970
1534
  var mcpOAuthGrantPermissions = ["read", "write"];
971
1535
  var jobTypes = Constants.public.Enums.job_type;
972
1536
  var userJobStatuses = Constants.public.Enums.user_job_status;
973
1537
  var eventTypes = Constants.public.Enums.event_type;
974
1538
  var exerciseSubjects = Constants.public.Enums.exercise_subject;
1539
+ var exportTemplateIds = [
1540
+ "exercises",
1541
+ "exercises-with-workspace",
1542
+ "exercises-with-solutions",
1543
+ "exercises-with-answers"
1544
+ ];
975
1545
  var organizationTypes = Constants.public.Enums.organization_type;
976
1546
  var organizationMemberRoles = Constants.public.Enums.organization_member_role;
977
1547
  var organizationInvitationStatuses = Constants.public.Enums.organization_invitation_status;
@@ -989,6 +1559,169 @@ var exerciseSheetTranslationFields = [
989
1559
  "description"
990
1560
  ];
991
1561
 
1562
+ // ../shared/src/agent-tools/operations.ts
1563
+ var agentWriteOperationRegistry = {
1564
+ send_user_feedback: {
1565
+ agentToolName: "send_user_feedback",
1566
+ receiptOperation: null,
1567
+ resourceType: "event",
1568
+ sync: true
1569
+ },
1570
+ send_agent_feedback: {
1571
+ agentToolName: "send_agent_feedback",
1572
+ receiptOperation: null,
1573
+ resourceType: "event",
1574
+ sync: true
1575
+ },
1576
+ copy_exercise: {
1577
+ agentToolName: "copy_exercise",
1578
+ receiptOperation: "copy_exercise",
1579
+ resourceType: "exercise",
1580
+ sync: true
1581
+ },
1582
+ copy_sheet: {
1583
+ agentToolName: "copy_sheet",
1584
+ receiptOperation: "copy_sheet",
1585
+ resourceType: "sheet",
1586
+ sync: true
1587
+ },
1588
+ update_exercise: {
1589
+ agentToolName: "update_exercise",
1590
+ receiptOperation: "update_exercise",
1591
+ resourceType: "exercise",
1592
+ sync: true
1593
+ },
1594
+ update_sheet: {
1595
+ agentToolName: "update_sheet",
1596
+ receiptOperation: "update_sheet",
1597
+ resourceType: "sheet",
1598
+ sync: true
1599
+ },
1600
+ append_exercises_to_sheet: {
1601
+ agentToolName: "append_exercises_to_sheet",
1602
+ receiptOperation: "append_exercises_to_sheet",
1603
+ resourceType: "sheet",
1604
+ sync: true
1605
+ },
1606
+ create_folder: {
1607
+ agentToolName: "create_folder",
1608
+ receiptOperation: "create_folder",
1609
+ resourceType: "folder",
1610
+ sync: true
1611
+ },
1612
+ rename_folder: {
1613
+ agentToolName: "rename_folder",
1614
+ receiptOperation: "rename_folder",
1615
+ resourceType: "folder",
1616
+ sync: true
1617
+ },
1618
+ delete_exercise: {
1619
+ agentToolName: "delete_exercise",
1620
+ receiptOperation: "delete_exercise",
1621
+ resourceType: "exercise",
1622
+ sync: true
1623
+ },
1624
+ delete_sheet: {
1625
+ agentToolName: "delete_sheet",
1626
+ receiptOperation: "delete_sheet",
1627
+ resourceType: "sheet",
1628
+ sync: true
1629
+ },
1630
+ delete_folder: {
1631
+ agentToolName: "delete_folder",
1632
+ receiptOperation: "delete_folder",
1633
+ resourceType: "folder",
1634
+ sync: true
1635
+ },
1636
+ create_sheet: {
1637
+ agentToolName: "create_sheet",
1638
+ receiptOperation: "create_sheet",
1639
+ resourceType: "sheet",
1640
+ sync: true
1641
+ },
1642
+ create_exercise: {
1643
+ agentToolName: "create_exercise",
1644
+ receiptOperation: "create_exercise",
1645
+ resourceType: "exercise",
1646
+ sync: true
1647
+ },
1648
+ set_exercise_visibility: {
1649
+ agentToolName: "set_exercise_visibility",
1650
+ receiptOperation: "set_exercise_visibility",
1651
+ resourceType: "exercise",
1652
+ sync: true
1653
+ },
1654
+ set_sheet_visibility: {
1655
+ agentToolName: "set_sheet_visibility",
1656
+ receiptOperation: "set_sheet_visibility",
1657
+ resourceType: "sheet",
1658
+ sync: true
1659
+ },
1660
+ import_exercise_started: {
1661
+ receiptOperation: null,
1662
+ resourceType: "job",
1663
+ sync: false
1664
+ },
1665
+ import_exercise_completed: {
1666
+ receiptOperation: null,
1667
+ resourceType: "exercise",
1668
+ sync: false
1669
+ },
1670
+ import_exercise_solution_started: {
1671
+ receiptOperation: null,
1672
+ resourceType: "job",
1673
+ sync: false
1674
+ },
1675
+ import_exercise_solution_completed: {
1676
+ receiptOperation: null,
1677
+ resourceType: "exercise",
1678
+ sync: false
1679
+ },
1680
+ import_sheet_started: {
1681
+ receiptOperation: null,
1682
+ resourceType: "job",
1683
+ sync: false
1684
+ },
1685
+ import_sheet_completed: {
1686
+ receiptOperation: null,
1687
+ resourceType: "sheet",
1688
+ sync: false
1689
+ },
1690
+ import_sheet_solutions_started: {
1691
+ receiptOperation: null,
1692
+ resourceType: "job",
1693
+ sync: false
1694
+ },
1695
+ import_sheet_solutions_completed: {
1696
+ receiptOperation: null,
1697
+ resourceType: "sheet",
1698
+ sync: false
1699
+ },
1700
+ generate_exercise_translation_started: {
1701
+ agentToolName: "start_exercise_translation_generation",
1702
+ receiptOperation: null,
1703
+ resourceType: "job",
1704
+ sync: false
1705
+ },
1706
+ generate_exercise_translation_completed: {
1707
+ receiptOperation: null,
1708
+ resourceType: "exercise",
1709
+ sync: false
1710
+ },
1711
+ generate_sheet_translation_started: {
1712
+ agentToolName: "start_sheet_translation_generation",
1713
+ receiptOperation: null,
1714
+ resourceType: "job",
1715
+ sync: false
1716
+ },
1717
+ generate_sheet_translation_completed: {
1718
+ receiptOperation: null,
1719
+ resourceType: "sheet",
1720
+ sync: false
1721
+ }
1722
+ };
1723
+ var agentWriteReceiptOperations = Object.values(agentWriteOperationRegistry).map((operation) => operation.receiptOperation).filter((operation) => Boolean(operation));
1724
+
992
1725
  // ../shared/src/agent-tools/index.ts
993
1726
  var strictObject = (shape) => z.object(shape).strict();
994
1727
  var uuidSchema = z.uuid();
@@ -998,6 +1731,21 @@ var optionalNullableStringSchema = z.string().trim().min(1).nullable().optional(
998
1731
  var metadataSchema = z.unknown().nullable();
999
1732
  var patchNullableStringSchema = z.string().nullable().optional();
1000
1733
  var expectedUpdatedAtSchema = z.string().trim().min(1);
1734
+ var feedbackContextSchema = z.record(z.string(), z.unknown()).optional();
1735
+ var feedbackMessageSchema = z.string().trim().min(1).max(5e3);
1736
+ var agentErrorCodes = [
1737
+ "precondition_failed",
1738
+ "confirmation_required",
1739
+ "resource_in_use",
1740
+ "feature_disabled",
1741
+ "invalid_label",
1742
+ "forbidden",
1743
+ "not_found",
1744
+ "validation_failed",
1745
+ "unauthorized"
1746
+ ];
1747
+ var agentErrorCodeSchema = z.enum(agentErrorCodes);
1748
+ var agentWriteReceiptOperationSchema = z.enum(agentWriteReceiptOperations);
1001
1749
  var exerciseTranslationFieldNames = [
1002
1750
  "exercise_text",
1003
1751
  "description",
@@ -1069,6 +1817,37 @@ var sheetTranslationSchema = strictObject({
1069
1817
  var sheetTranslationStatusSchema = strictObject({
1070
1818
  status: z.enum(exerciseSheetTranslationStatuses)
1071
1819
  });
1820
+ var sheetVersionTranslationSchema = strictObject({
1821
+ name: z.string(),
1822
+ title: z.string().nullable(),
1823
+ description: z.string().nullable()
1824
+ });
1825
+ var sheetVersionExerciseSchema = strictObject({
1826
+ exerciseId: uuidSchema,
1827
+ orderIndex: z.number().int().min(1),
1828
+ scorePoints: z.number().nullable()
1829
+ });
1830
+ var sheetVersionSnapshotSchema = strictObject({
1831
+ subject: z.enum(exerciseSubjects),
1832
+ private_notes: z.string().nullable(),
1833
+ scoring_enabled: z.boolean(),
1834
+ translations: z.record(z.string(), sheetVersionTranslationSchema),
1835
+ exercises: z.array(sheetVersionExerciseSchema)
1836
+ });
1837
+ var sheetVersionListItemSchema = strictObject({
1838
+ id: uuidSchema,
1839
+ exerciseSheetId: uuidSchema,
1840
+ versionNumber: z.number().int().positive(),
1841
+ createdAt: dateStringSchema,
1842
+ createdByUserId: uuidSchema.nullable(),
1843
+ createdByName: z.string().nullable(),
1844
+ type: z.enum(exerciseSheetVersionTypes),
1845
+ sourceVersionId: uuidSchema.nullable()
1846
+ });
1847
+ var sheetVersionDetailSchema = sheetVersionListItemSchema.extend({
1848
+ snapshot: sheetVersionSnapshotSchema,
1849
+ exercises: z.array(exerciseSummarySchema)
1850
+ });
1072
1851
  var sheetDetailsSchema = strictObject({
1073
1852
  id: uuidSchema,
1074
1853
  created_at: dateStringSchema,
@@ -1094,6 +1873,22 @@ var folderSchema = strictObject({
1094
1873
  parentId: uuidSchema.nullable(),
1095
1874
  updatedAt: dateStringSchema
1096
1875
  });
1876
+ var exerciseLabelSchema = strictObject({
1877
+ id: z.string().trim().min(1),
1878
+ name: z.string().trim().min(1),
1879
+ parentId: z.string().trim().min(1).nullable(),
1880
+ depth: z.number().int().min(0),
1881
+ pathIds: z.array(z.string().trim().min(1)),
1882
+ pathNames: z.array(z.string().trim().min(1)),
1883
+ displayPath: z.string().trim().min(1),
1884
+ childIds: z.array(z.string().trim().min(1))
1885
+ });
1886
+ var agentFeedbackEventTypeSchema = z.enum(["user_feedback_sent", "agent_feedback_sent"]);
1887
+ var feedbackReceiptSchema = strictObject({
1888
+ eventId: uuidSchema,
1889
+ eventType: agentFeedbackEventTypeSchema,
1890
+ submittedAt: dateStringSchema
1891
+ });
1097
1892
  var exerciseUsageSheetSchema = strictObject({
1098
1893
  id: uuidSchema,
1099
1894
  name: z.string(),
@@ -1103,6 +1898,19 @@ var exerciseUsageSchema = strictObject({
1103
1898
  sheets: z.array(exerciseUsageSheetSchema),
1104
1899
  otherOrganizationSheetCount: z.number().int().min(0)
1105
1900
  });
1901
+ var agentWriteReceiptVersionSchema = z.discriminatedUnion("created", [
1902
+ strictObject({
1903
+ resourceType: z.literal("sheet"),
1904
+ created: z.literal(true),
1905
+ versionId: uuidSchema,
1906
+ versionNumber: z.number().int().positive()
1907
+ }),
1908
+ strictObject({
1909
+ resourceType: z.literal("sheet"),
1910
+ created: z.literal(false),
1911
+ reason: z.string().trim().min(1)
1912
+ })
1913
+ ]);
1106
1914
  var latexValidationIssueSchema = strictObject({
1107
1915
  code: z.enum(latexValidationIssueCodes),
1108
1916
  message: z.string(),
@@ -1170,6 +1978,19 @@ var getSheetAgentInputSchema = strictObject({
1170
1978
  var getSheetAgentOutputSchema = strictObject({
1171
1979
  sheet: sheetDetailsSchema
1172
1980
  });
1981
+ var listSheetVersionsAgentInputSchema = strictObject({
1982
+ id: uuidSchema
1983
+ });
1984
+ var listSheetVersionsAgentOutputSchema = strictObject({
1985
+ versions: z.array(sheetVersionListItemSchema)
1986
+ });
1987
+ var getSheetVersionAgentInputSchema = strictObject({
1988
+ exerciseSheetId: uuidSchema,
1989
+ versionId: uuidSchema
1990
+ });
1991
+ var getSheetVersionAgentOutputSchema = strictObject({
1992
+ version: sheetVersionDetailSchema
1993
+ });
1173
1994
  var getSheetIssuesAgentInputSchema = strictObject({
1174
1995
  id: uuidSchema
1175
1996
  });
@@ -1181,6 +2002,10 @@ var listFoldersAgentInputSchema = strictObject({});
1181
2002
  var listFoldersAgentOutputSchema = strictObject({
1182
2003
  folders: z.array(folderSchema)
1183
2004
  });
2005
+ var listExerciseLabelsAgentInputSchema = strictObject({});
2006
+ var listExerciseLabelsAgentOutputSchema = strictObject({
2007
+ labels: z.array(exerciseLabelSchema)
2008
+ });
1184
2009
  var validateLatexSnippetsAgentInputSchema = strictObject({
1185
2010
  snippets: z.array(
1186
2011
  strictObject({
@@ -1192,6 +2017,56 @@ var validateLatexSnippetsAgentInputSchema = strictObject({
1192
2017
  var validateLatexSnippetsAgentOutputSchema = strictObject({
1193
2018
  results: z.array(latexValidationResultSchema)
1194
2019
  });
2020
+ var queuedExerciseTranslationJobSchema = strictObject({
2021
+ exerciseId: uuidSchema,
2022
+ jobId: uuidSchema,
2023
+ languages: z.array(z.enum(translationLanguages)).min(1),
2024
+ type: z.literal("exercise_translation_generation")
2025
+ });
2026
+ var queuedSheetTranslationJobSchema = strictObject({
2027
+ exerciseSheetId: uuidSchema,
2028
+ jobId: uuidSchema,
2029
+ language: z.enum(translationLanguages),
2030
+ type: z.literal("exercise_sheet_translation_generation")
2031
+ });
2032
+ var skippedSheetTranslationJobSchema = strictObject({
2033
+ jobId: z.null(),
2034
+ language: z.enum(translationLanguages),
2035
+ reason: z.literal("already_complete"),
2036
+ type: z.literal("exercise_sheet_translation_generation")
2037
+ });
2038
+ var targetTranslationLanguagesSchema = z.array(z.enum(translationLanguages)).min(1).refine((languages) => new Set(languages).size === languages.length, "Target languages must be unique");
2039
+ var startExerciseTranslationGenerationAgentInputSchema = strictObject({
2040
+ id: uuidSchema,
2041
+ targetLanguages: targetTranslationLanguagesSchema
2042
+ });
2043
+ var startExerciseTranslationGenerationAgentOutputSchema = strictObject({
2044
+ jobs: z.array(queuedExerciseTranslationJobSchema)
2045
+ });
2046
+ var startSheetTranslationGenerationAgentInputSchema = strictObject({
2047
+ id: uuidSchema,
2048
+ sourceLanguage: z.enum(translationLanguages).optional(),
2049
+ targetLanguages: targetTranslationLanguagesSchema
2050
+ });
2051
+ var startSheetTranslationGenerationAgentOutputSchema = strictObject({
2052
+ jobs: z.array(z.union([queuedSheetTranslationJobSchema, skippedSheetTranslationJobSchema]))
2053
+ });
2054
+ var sendUserFeedbackAgentInputSchema = strictObject({
2055
+ message: feedbackMessageSchema,
2056
+ userConsent: z.literal(true),
2057
+ category: z.enum(["bug_report", "feature_request", "frustration", "blocked_request", "other"]).optional(),
2058
+ context: feedbackContextSchema
2059
+ });
2060
+ var sendAgentFeedbackAgentInputSchema = strictObject({
2061
+ message: feedbackMessageSchema,
2062
+ category: z.enum(["api_inconsistency", "documentation_issue", "missing_capability", "unexpected_behavior", "other"]).optional(),
2063
+ context: feedbackContextSchema
2064
+ });
2065
+ var feedbackReceiptOutputSchema = strictObject({
2066
+ receipt: feedbackReceiptSchema
2067
+ });
2068
+ var sendUserFeedbackAgentOutputSchema = feedbackReceiptOutputSchema;
2069
+ var sendAgentFeedbackAgentOutputSchema = feedbackReceiptOutputSchema;
1195
2070
  var getExerciseUsageAgentInputSchema = strictObject({
1196
2071
  id: uuidSchema
1197
2072
  });
@@ -1203,7 +2078,7 @@ var agentWriteReceiptSchema = strictObject({
1203
2078
  type: z.enum(["exercise", "sheet", "folder"]),
1204
2079
  id: uuidSchema
1205
2080
  }),
1206
- operation: z.string(),
2081
+ operation: agentWriteReceiptOperationSchema,
1207
2082
  changedPaths: z.array(z.string()),
1208
2083
  precondition: strictObject({
1209
2084
  expectedUpdatedAt: optionalNullableStringSchema,
@@ -1217,6 +2092,7 @@ var agentWriteReceiptSchema = strictObject({
1217
2092
  details: z.unknown().optional()
1218
2093
  })
1219
2094
  ),
2095
+ version: agentWriteReceiptVersionSchema.optional(),
1220
2096
  details: z.unknown()
1221
2097
  });
1222
2098
  var agentWriteReceiptOutputSchema = strictObject({
@@ -1234,6 +2110,23 @@ var copySheetAgentInputSchema = strictObject({
1234
2110
  exerciseCopyMode: z.enum(exerciseSheetExerciseCopyModes).optional().default("keep_references")
1235
2111
  });
1236
2112
  var copySheetAgentOutputSchema = agentWriteReceiptOutputSchema;
2113
+ var deleteExerciseAgentInputSchema = strictObject({
2114
+ id: uuidSchema,
2115
+ expectedUpdatedAt: expectedUpdatedAtSchema,
2116
+ confirmResourceId: uuidSchema
2117
+ });
2118
+ var deleteExerciseAgentOutputSchema = agentWriteReceiptOutputSchema;
2119
+ var deleteSheetAgentInputSchema = strictObject({
2120
+ id: uuidSchema,
2121
+ expectedUpdatedAt: expectedUpdatedAtSchema,
2122
+ confirmResourceId: uuidSchema
2123
+ });
2124
+ var deleteSheetAgentOutputSchema = agentWriteReceiptOutputSchema;
2125
+ var deleteFolderAgentInputSchema = strictObject({
2126
+ id: uuidSchema,
2127
+ confirmResourceId: uuidSchema
2128
+ });
2129
+ var deleteFolderAgentOutputSchema = agentWriteReceiptOutputSchema;
1237
2130
  var createFolderAgentInputSchema = strictObject({
1238
2131
  name: z.string().trim().min(1),
1239
2132
  parentId: uuidSchema.nullable().optional()
@@ -1257,11 +2150,34 @@ var exercisePatchFigureSchema = strictObject({
1257
2150
  url: z.url(),
1258
2151
  widthInCm: z.number().positive().finite().nullable().optional()
1259
2152
  });
1260
- var exercisePatchMetadataSchema = strictObject({
2153
+ var exerciseCreateFigureSchema = strictObject({
2154
+ type: z.enum(exerciseFigureTypes),
2155
+ url: z.url(),
2156
+ widthInCm: z.number().positive().finite().optional()
2157
+ });
2158
+ var exercisePatchMetadataSchema = strictObject({
1261
2159
  sourceUrl: patchNullableStringSchema,
1262
2160
  solutionUrl: patchNullableStringSchema,
1263
2161
  figures: z.array(exercisePatchFigureSchema).optional()
1264
2162
  });
2163
+ var exerciseCreateMetadataSchema = strictObject({
2164
+ sourceUrl: z.url().optional(),
2165
+ solutionUrl: z.url().optional(),
2166
+ figures: z.array(exerciseCreateFigureSchema).optional()
2167
+ });
2168
+ var createExerciseAgentInputSchema = strictObject({
2169
+ difficulty: z.number().min(1).max(100).nullable().optional(),
2170
+ min_age: z.number().min(0).max(100).nullable().optional(),
2171
+ max_age: z.number().min(0).max(100).nullable().optional(),
2172
+ source: z.string().trim().min(1).optional(),
2173
+ metadata: exerciseCreateMetadataSchema.optional(),
2174
+ labels: z.array(z.string()).max(30).optional(),
2175
+ private_notes: z.string().optional(),
2176
+ translations: z.record(z.string(), exercisePatchTranslationSchema),
2177
+ exerciseSheetId: uuidSchema.optional(),
2178
+ confirmMakeExercisesPublic: z.boolean().optional().default(false)
2179
+ });
2180
+ var createExerciseAgentOutputSchema = agentWriteReceiptOutputSchema;
1265
2181
  var updateExerciseAgentInputSchema = strictObject({
1266
2182
  id: uuidSchema,
1267
2183
  expectedUpdatedAt: expectedUpdatedAtSchema,
@@ -1295,12 +2211,43 @@ var updateSheetAgentInputSchema = strictObject({
1295
2211
  })
1296
2212
  });
1297
2213
  var updateSheetAgentOutputSchema = agentWriteReceiptOutputSchema;
2214
+ var createSheetScoredExerciseSchema = strictObject({
2215
+ id: uuidSchema,
2216
+ scorePoints: z.number().min(0).max(99999.9).refine((value) => Number.isInteger(value * 10), "Score can have at most 1 decimal place").nullable()
2217
+ });
2218
+ var createSheetAgentInputSchema = strictObject({
2219
+ name: z.string().trim().min(1),
2220
+ title: z.string().trim().nullable().optional(),
2221
+ description: z.string().trim().optional(),
2222
+ language: z.enum(translationLanguages),
2223
+ exerciseIds: z.array(uuidSchema).max(200).optional(),
2224
+ exercises: z.array(createSheetScoredExerciseSchema).max(200).optional(),
2225
+ scoringEnabled: z.boolean().optional().default(false),
2226
+ private_notes: z.string().optional()
2227
+ }).refine((data) => data.exerciseIds === void 0 || data.exercises === void 0, {
2228
+ message: "Use exercises instead of exerciseIds when creating score values"
2229
+ });
2230
+ var createSheetAgentOutputSchema = agentWriteReceiptOutputSchema;
1298
2231
  var appendExercisesToSheetAgentInputSchema = strictObject({
1299
2232
  sheetId: uuidSchema,
1300
2233
  exerciseIds: z.array(uuidSchema).min(1),
1301
2234
  confirmMakeExercisesPublic: z.boolean().optional().default(false)
1302
2235
  });
1303
2236
  var appendExercisesToSheetAgentOutputSchema = agentWriteReceiptOutputSchema;
2237
+ var setExerciseVisibilityAgentInputSchema = strictObject({
2238
+ id: uuidSchema,
2239
+ expectedUpdatedAt: expectedUpdatedAtSchema,
2240
+ isPublic: z.boolean(),
2241
+ confirmMakePublicResourceId: uuidSchema.optional()
2242
+ });
2243
+ var setExerciseVisibilityAgentOutputSchema = agentWriteReceiptOutputSchema;
2244
+ var setSheetVisibilityAgentInputSchema = strictObject({
2245
+ id: uuidSchema,
2246
+ expectedUpdatedAt: expectedUpdatedAtSchema,
2247
+ isPublic: z.boolean(),
2248
+ confirmMakePublicResourceId: uuidSchema.optional()
2249
+ });
2250
+ var setSheetVisibilityAgentOutputSchema = agentWriteReceiptOutputSchema;
1304
2251
 
1305
2252
  // ../shared/src/agent-tools/mcp-tools.ts
1306
2253
  import { z as z3 } from "zod";
@@ -1516,14 +2463,34 @@ var getExerciseUsageInputSchema = getExerciseUsageAgentInputSchema.extend({
1516
2463
  organizationId: organizationIdSchema
1517
2464
  });
1518
2465
  var getExerciseUsageOutputSchema = getExerciseUsageAgentOutputSchema;
2466
+ var listExerciseLabelsInputSchema = listExerciseLabelsAgentInputSchema.extend({
2467
+ organizationId: organizationIdSchema
2468
+ });
2469
+ var listExerciseLabelsOutputSchema = listExerciseLabelsAgentOutputSchema;
1519
2470
  var copyExerciseInputSchema = copyExerciseAgentInputSchema.extend({
1520
2471
  organizationId: organizationIdSchema
1521
2472
  });
1522
2473
  var copyExerciseOutputSchema = copyExerciseAgentOutputSchema;
2474
+ var deleteExerciseInputSchema = deleteExerciseAgentInputSchema.extend({
2475
+ organizationId: organizationIdSchema
2476
+ });
2477
+ var deleteExerciseOutputSchema = deleteExerciseAgentOutputSchema;
2478
+ var createExerciseInputSchema = createExerciseAgentInputSchema.extend({
2479
+ organizationId: organizationIdSchema
2480
+ });
2481
+ var createExerciseOutputSchema = createExerciseAgentOutputSchema;
1523
2482
  var updateExerciseInputSchema = updateExerciseAgentInputSchema.extend({
1524
2483
  organizationId: organizationIdSchema
1525
2484
  });
1526
2485
  var updateExerciseOutputSchema = updateExerciseAgentOutputSchema;
2486
+ var setExerciseVisibilityInputSchema = setExerciseVisibilityAgentInputSchema.extend({
2487
+ organizationId: organizationIdSchema
2488
+ });
2489
+ var setExerciseVisibilityOutputSchema = setExerciseVisibilityAgentOutputSchema;
2490
+ var generateExerciseTranslationJobInputSchema = startExerciseTranslationGenerationAgentInputSchema.extend({
2491
+ organizationId: organizationIdSchema
2492
+ });
2493
+ var generateExerciseTranslationJobOutputSchema = startExerciseTranslationGenerationAgentOutputSchema;
1527
2494
  var importExerciseInputSchema = strictObject2({
1528
2495
  organizationId: organizationIdSchema,
1529
2496
  sources: importSourcesSchema,
@@ -1562,6 +2529,14 @@ var getSheetInputSchema = getSheetAgentInputSchema.extend({
1562
2529
  organizationId: organizationIdSchema
1563
2530
  });
1564
2531
  var getSheetOutputSchema = getSheetAgentOutputSchema;
2532
+ var listSheetVersionsInputSchema = listSheetVersionsAgentInputSchema.extend({
2533
+ organizationId: organizationIdSchema
2534
+ });
2535
+ var listSheetVersionsOutputSchema = listSheetVersionsAgentOutputSchema;
2536
+ var getSheetVersionInputSchema = getSheetVersionAgentInputSchema.extend({
2537
+ organizationId: organizationIdSchema
2538
+ });
2539
+ var getSheetVersionOutputSchema = getSheetVersionAgentOutputSchema;
1565
2540
  var getSheetIssuesInputSchema = getSheetIssuesAgentInputSchema.extend({
1566
2541
  organizationId: organizationIdSchema
1567
2542
  });
@@ -1570,10 +2545,26 @@ var copySheetInputSchema = copySheetAgentInputSchema.extend({
1570
2545
  organizationId: organizationIdSchema
1571
2546
  });
1572
2547
  var copySheetOutputSchema = copySheetAgentOutputSchema;
2548
+ var deleteSheetInputSchema = deleteSheetAgentInputSchema.extend({
2549
+ organizationId: organizationIdSchema
2550
+ });
2551
+ var deleteSheetOutputSchema = deleteSheetAgentOutputSchema;
2552
+ var createSheetInputSchema = createSheetAgentInputSchema.extend({
2553
+ organizationId: organizationIdSchema
2554
+ });
2555
+ var createSheetOutputSchema = createSheetAgentOutputSchema;
1573
2556
  var updateSheetInputSchema = updateSheetAgentInputSchema.extend({
1574
2557
  organizationId: organizationIdSchema
1575
2558
  });
1576
2559
  var updateSheetOutputSchema = updateSheetAgentOutputSchema;
2560
+ var setSheetVisibilityInputSchema = setSheetVisibilityAgentInputSchema.extend({
2561
+ organizationId: organizationIdSchema
2562
+ });
2563
+ var setSheetVisibilityOutputSchema = setSheetVisibilityAgentOutputSchema;
2564
+ var generateSheetTranslationJobInputSchema = startSheetTranslationGenerationAgentInputSchema.extend({
2565
+ organizationId: organizationIdSchema
2566
+ });
2567
+ var generateSheetTranslationJobOutputSchema = startSheetTranslationGenerationAgentOutputSchema;
1577
2568
  var appendExercisesToSheetInputSchema = appendExercisesToSheetAgentInputSchema.extend({
1578
2569
  organizationId: organizationIdSchema
1579
2570
  });
@@ -1582,6 +2573,18 @@ var listFoldersInputSchema = listFoldersAgentInputSchema.extend({
1582
2573
  organizationId: organizationIdSchema
1583
2574
  });
1584
2575
  var listFoldersOutputSchema = listFoldersAgentOutputSchema;
2576
+ var sendUserFeedbackInputSchema = sendUserFeedbackAgentInputSchema.extend({
2577
+ organizationId: organizationIdSchema
2578
+ });
2579
+ var sendUserFeedbackOutputSchema = sendUserFeedbackAgentOutputSchema;
2580
+ var sendAgentFeedbackInputSchema = sendAgentFeedbackAgentInputSchema.extend({
2581
+ organizationId: organizationIdSchema
2582
+ });
2583
+ var sendAgentFeedbackOutputSchema = sendAgentFeedbackAgentOutputSchema;
2584
+ var deleteFolderInputSchema = deleteFolderAgentInputSchema.extend({
2585
+ organizationId: organizationIdSchema
2586
+ });
2587
+ var deleteFolderOutputSchema = deleteFolderAgentOutputSchema;
1585
2588
  var createFolderInputSchema = createFolderAgentInputSchema.extend({
1586
2589
  organizationId: organizationIdSchema
1587
2590
  });
@@ -1693,6 +2696,16 @@ var chalksurfMcpToolCapabilities = {
1693
2696
  requiredPermission: "read",
1694
2697
  security: { type: "oauth2", scopes: [chalksurfMcpScopes.read] }
1695
2698
  },
2699
+ list_exercise_labels: {
2700
+ name: "list_exercise_labels",
2701
+ title: "List exercise labels",
2702
+ description: "Use this to discover canonical ChalkSurf exercise label IDs before creating or updating exercises.",
2703
+ inputSchema: listExerciseLabelsInputSchema,
2704
+ outputSchema: listExerciseLabelsOutputSchema,
2705
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
2706
+ requiredPermission: "read",
2707
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.read] }
2708
+ },
1696
2709
  copy_exercise: {
1697
2710
  name: "copy_exercise",
1698
2711
  title: "Copy exercise",
@@ -1703,6 +2716,26 @@ var chalksurfMcpToolCapabilities = {
1703
2716
  requiredPermission: "write",
1704
2717
  security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
1705
2718
  },
2719
+ delete_exercise: {
2720
+ name: "delete_exercise",
2721
+ title: "Delete exercise",
2722
+ description: "Use this to soft-delete one writable exercise after checking updated_at and exact destructive confirmation.",
2723
+ inputSchema: deleteExerciseInputSchema,
2724
+ outputSchema: deleteExerciseOutputSchema,
2725
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false },
2726
+ requiredPermission: "write",
2727
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
2728
+ },
2729
+ create_exercise: {
2730
+ name: "create_exercise",
2731
+ title: "Create exercise",
2732
+ description: "Use this to create one exercise in the selected ChalkSurf organization.",
2733
+ inputSchema: createExerciseInputSchema,
2734
+ outputSchema: createExerciseOutputSchema,
2735
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
2736
+ requiredPermission: "write",
2737
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
2738
+ },
1706
2739
  update_exercise: {
1707
2740
  name: "update_exercise",
1708
2741
  title: "Update exercise",
@@ -1713,6 +2746,26 @@ var chalksurfMcpToolCapabilities = {
1713
2746
  requiredPermission: "write",
1714
2747
  security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
1715
2748
  },
2749
+ set_exercise_visibility: {
2750
+ name: "set_exercise_visibility",
2751
+ title: "Set exercise visibility",
2752
+ description: "Use this to make one writable exercise public or private after checking updated_at and visibility policy.",
2753
+ inputSchema: setExerciseVisibilityInputSchema,
2754
+ outputSchema: setExerciseVisibilityOutputSchema,
2755
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
2756
+ requiredPermission: "write",
2757
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
2758
+ },
2759
+ generate_exercise_translation_job: {
2760
+ name: "generate_exercise_translation_job",
2761
+ title: "Generate exercise translation job",
2762
+ description: "Use this to queue translation generation for one writable ChalkSurf exercise.",
2763
+ inputSchema: generateExerciseTranslationJobInputSchema,
2764
+ outputSchema: generateExerciseTranslationJobOutputSchema,
2765
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
2766
+ requiredPermission: "write",
2767
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
2768
+ },
1716
2769
  import_exercise: {
1717
2770
  name: "import_exercise",
1718
2771
  title: "Import exercise",
@@ -1753,6 +2806,26 @@ var chalksurfMcpToolCapabilities = {
1753
2806
  requiredPermission: "read",
1754
2807
  security: { type: "oauth2", scopes: [chalksurfMcpScopes.read] }
1755
2808
  },
2809
+ list_sheet_versions: {
2810
+ name: "list_sheet_versions",
2811
+ title: "List sheet versions",
2812
+ description: "Use this to inspect the version history for one owned exercise sheet.",
2813
+ inputSchema: listSheetVersionsInputSchema,
2814
+ outputSchema: listSheetVersionsOutputSchema,
2815
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
2816
+ requiredPermission: "read",
2817
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.read] }
2818
+ },
2819
+ get_sheet_version: {
2820
+ name: "get_sheet_version",
2821
+ title: "Get sheet version",
2822
+ description: "Use this to fetch one owned exercise sheet version snapshot with its referenced exercise details.",
2823
+ inputSchema: getSheetVersionInputSchema,
2824
+ outputSchema: getSheetVersionOutputSchema,
2825
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
2826
+ requiredPermission: "read",
2827
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.read] }
2828
+ },
1756
2829
  get_sheet_issues: {
1757
2830
  name: "get_sheet_issues",
1758
2831
  title: "Get sheet issues",
@@ -1773,6 +2846,26 @@ var chalksurfMcpToolCapabilities = {
1773
2846
  requiredPermission: "write",
1774
2847
  security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
1775
2848
  },
2849
+ delete_sheet: {
2850
+ name: "delete_sheet",
2851
+ title: "Delete sheet",
2852
+ description: "Use this to soft-delete one writable exercise sheet after checking updated_at and exact destructive confirmation.",
2853
+ inputSchema: deleteSheetInputSchema,
2854
+ outputSchema: deleteSheetOutputSchema,
2855
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false },
2856
+ requiredPermission: "write",
2857
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
2858
+ },
2859
+ create_sheet: {
2860
+ name: "create_sheet",
2861
+ title: "Create sheet",
2862
+ description: "Use this to create one exercise sheet in the selected ChalkSurf organization.",
2863
+ inputSchema: createSheetInputSchema,
2864
+ outputSchema: createSheetOutputSchema,
2865
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
2866
+ requiredPermission: "write",
2867
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
2868
+ },
1776
2869
  update_sheet: {
1777
2870
  name: "update_sheet",
1778
2871
  title: "Update sheet",
@@ -1783,6 +2876,26 @@ var chalksurfMcpToolCapabilities = {
1783
2876
  requiredPermission: "write",
1784
2877
  security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
1785
2878
  },
2879
+ set_sheet_visibility: {
2880
+ name: "set_sheet_visibility",
2881
+ title: "Set sheet visibility",
2882
+ description: "Use this to make one writable exercise sheet public or private after checking updated_at and visibility policy.",
2883
+ inputSchema: setSheetVisibilityInputSchema,
2884
+ outputSchema: setSheetVisibilityOutputSchema,
2885
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
2886
+ requiredPermission: "write",
2887
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
2888
+ },
2889
+ generate_sheet_translation_job: {
2890
+ name: "generate_sheet_translation_job",
2891
+ title: "Generate sheet translation job",
2892
+ description: "Use this to queue translation generation for one writable ChalkSurf exercise sheet.",
2893
+ inputSchema: generateSheetTranslationJobInputSchema,
2894
+ outputSchema: generateSheetTranslationJobOutputSchema,
2895
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
2896
+ requiredPermission: "write",
2897
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
2898
+ },
1786
2899
  append_exercises_to_sheet: {
1787
2900
  name: "append_exercises_to_sheet",
1788
2901
  title: "Append exercises to sheet",
@@ -1803,6 +2916,36 @@ var chalksurfMcpToolCapabilities = {
1803
2916
  requiredPermission: "read",
1804
2917
  security: { type: "oauth2", scopes: [chalksurfMcpScopes.read] }
1805
2918
  },
2919
+ send_user_feedback: {
2920
+ name: "send_user_feedback",
2921
+ title: "Send user feedback",
2922
+ description: "Use this only after the user explicitly asks you to send feedback or agrees to send a bug report or feature request.",
2923
+ inputSchema: sendUserFeedbackInputSchema,
2924
+ outputSchema: sendUserFeedbackOutputSchema,
2925
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
2926
+ requiredPermission: "read",
2927
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.read] }
2928
+ },
2929
+ send_agent_feedback: {
2930
+ name: "send_agent_feedback",
2931
+ title: "Send agent feedback",
2932
+ description: "Use this when you observe a ChalkSurf CLI, MCP, API, or documentation inconsistency while using agent tools.",
2933
+ inputSchema: sendAgentFeedbackInputSchema,
2934
+ outputSchema: sendAgentFeedbackOutputSchema,
2935
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
2936
+ requiredPermission: "read",
2937
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.read] }
2938
+ },
2939
+ delete_folder: {
2940
+ name: "delete_folder",
2941
+ title: "Delete folder",
2942
+ description: "Use this to delete one empty exercise sheet folder after exact destructive confirmation.",
2943
+ inputSchema: deleteFolderInputSchema,
2944
+ outputSchema: deleteFolderOutputSchema,
2945
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false },
2946
+ requiredPermission: "write",
2947
+ security: { type: "oauth2", scopes: [chalksurfMcpScopes.write] }
2948
+ },
1806
2949
  create_folder: {
1807
2950
  name: "create_folder",
1808
2951
  title: "Create folder",
@@ -1885,12 +3028,580 @@ var chalksurfMcpToolCapabilities = {
1885
3028
  }
1886
3029
  };
1887
3030
 
1888
- // ../shared/src/helpers/latex/exercise-translation-latex.ts
1889
- var hintField = "hint";
1890
- var isLatexWholeField = (field) => {
1891
- return field !== hintField;
1892
- };
1893
- var exerciseTranslationLatexWholeFields = exerciseTranslationFields.filter(isLatexWholeField);
3031
+ // ../shared/src/export-layout/preview-layout-settings.ts
3032
+ import { z as z4 } from "zod";
3033
+ var worksheetPreviewLayoutSettingsVersion = 1;
3034
+ var worksheetWorkspaceFillModes = ["empty", "lines", "grid"];
3035
+ var worksheetPreviewLayoutSettingsLimits = {
3036
+ fontSizePt: {
3037
+ min: 8,
3038
+ max: 18,
3039
+ default: 12
3040
+ },
3041
+ figureWidthInCm: {
3042
+ min: 1,
3043
+ max: 16,
3044
+ default: 6
3045
+ },
3046
+ workspaceHeightInCm: {
3047
+ min: 1,
3048
+ max: 12,
3049
+ default: 4
3050
+ }
3051
+ };
3052
+ var defaultWorksheetPreviewLayoutSettings = {
3053
+ version: worksheetPreviewLayoutSettingsVersion,
3054
+ fontSizePt: worksheetPreviewLayoutSettingsLimits.fontSizePt.default,
3055
+ figureOverridesByBlockId: {},
3056
+ workspaceOverridesByExerciseId: {}
3057
+ };
3058
+ var finiteNumberSchema = z4.number().finite();
3059
+ var worksheetPreviewLayoutSettingsSchema = z4.object({
3060
+ version: z4.literal(worksheetPreviewLayoutSettingsVersion),
3061
+ fontSizePt: finiteNumberSchema.optional(),
3062
+ figureOverridesByBlockId: z4.record(
3063
+ z4.string().min(1),
3064
+ z4.object({
3065
+ widthInCm: finiteNumberSchema.optional(),
3066
+ placement: z4.unknown().optional()
3067
+ })
3068
+ ).optional(),
3069
+ workspaceOverridesByExerciseId: z4.record(
3070
+ z4.string().min(1),
3071
+ z4.object({
3072
+ heightInCm: finiteNumberSchema.optional(),
3073
+ fillMode: z4.unknown().optional()
3074
+ })
3075
+ ).optional()
3076
+ });
3077
+
3078
+ // ../shared/src/export-layout/types.ts
3079
+ import { z as z5 } from "zod";
3080
+ var worksheetLayoutVersion = 1;
3081
+ var defaultWorksheetPageSettings = {
3082
+ size: "A4",
3083
+ widthMm: 210,
3084
+ heightMm: 297,
3085
+ marginMm: {
3086
+ top: 16,
3087
+ right: 18,
3088
+ bottom: 16,
3089
+ left: 18
3090
+ }
3091
+ };
3092
+ var worksheetLayoutBlockTypes = [
3093
+ "sheet-title",
3094
+ "sheet-description",
3095
+ "exercise",
3096
+ "exercise-text",
3097
+ "figure",
3098
+ "workspace",
3099
+ "answer",
3100
+ "detailed-solution"
3101
+ ];
3102
+ var baseWorksheetLayoutBlockSchema = z5.object({
3103
+ id: z5.string().min(1),
3104
+ type: z5.enum(worksheetLayoutBlockTypes),
3105
+ exerciseId: z5.string().min(1).optional()
3106
+ });
3107
+ var worksheetLayoutBlockSchema = z5.lazy(
3108
+ () => z5.discriminatedUnion("type", [
3109
+ baseWorksheetLayoutBlockSchema.extend({
3110
+ type: z5.literal("sheet-title"),
3111
+ text: z5.string()
3112
+ }),
3113
+ baseWorksheetLayoutBlockSchema.extend({
3114
+ type: z5.literal("sheet-description"),
3115
+ text: z5.string()
3116
+ }),
3117
+ baseWorksheetLayoutBlockSchema.extend({
3118
+ type: z5.literal("exercise-text"),
3119
+ exerciseId: z5.string().min(1),
3120
+ text: z5.string()
3121
+ }),
3122
+ baseWorksheetLayoutBlockSchema.extend({
3123
+ type: z5.literal("answer"),
3124
+ exerciseId: z5.string().min(1),
3125
+ text: z5.string()
3126
+ }),
3127
+ baseWorksheetLayoutBlockSchema.extend({
3128
+ type: z5.literal("detailed-solution"),
3129
+ exerciseId: z5.string().min(1),
3130
+ text: z5.string()
3131
+ }),
3132
+ baseWorksheetLayoutBlockSchema.extend({
3133
+ type: z5.literal("exercise"),
3134
+ exerciseId: z5.string().min(1),
3135
+ exerciseNumber: z5.number().int().positive(),
3136
+ scorePoints: z5.number().nullable(),
3137
+ children: z5.array(worksheetLayoutBlockSchema)
3138
+ }),
3139
+ baseWorksheetLayoutBlockSchema.extend({
3140
+ type: z5.literal("figure"),
3141
+ exerciseId: z5.string().min(1),
3142
+ figure: z5.object({
3143
+ type: z5.enum(["text", "solution"]),
3144
+ url: z5.string(),
3145
+ widthInCm: z5.number().positive()
3146
+ }),
3147
+ figureNumber: z5.number().int().positive()
3148
+ }),
3149
+ baseWorksheetLayoutBlockSchema.extend({
3150
+ type: z5.literal("workspace"),
3151
+ exerciseId: z5.string().min(1),
3152
+ heightInCm: z5.number().nonnegative(),
3153
+ fillMode: z5.enum(worksheetWorkspaceFillModes)
3154
+ })
3155
+ ])
3156
+ );
3157
+ var worksheetLayoutDocumentSchema = z5.object({
3158
+ version: z5.literal(worksheetLayoutVersion),
3159
+ title: z5.string(),
3160
+ description: z5.string().nullable(),
3161
+ language: z5.enum(translationLanguages),
3162
+ blocks: z5.array(worksheetLayoutBlockSchema)
3163
+ });
3164
+ var worksheetRenderDiagnosticCodes = [
3165
+ "unclosed_latex_delimiter",
3166
+ "katex_render_error",
3167
+ "missing_katex_renderer",
3168
+ "image_load_error",
3169
+ "html_render_error",
3170
+ "layout_measurement_error",
3171
+ "page_overflow"
3172
+ ];
3173
+ var worksheetPageSegmentSchema = z5.discriminatedUnion("type", [
3174
+ z5.object({
3175
+ type: z5.literal("standalone"),
3176
+ unitId: z5.string().min(1),
3177
+ blockId: z5.string().min(1),
3178
+ heightPx: z5.number().finite().nonnegative()
3179
+ }),
3180
+ z5.object({
3181
+ type: z5.literal("exercise"),
3182
+ unitId: z5.string().min(1),
3183
+ blockId: z5.string().min(1),
3184
+ exerciseId: z5.string().min(1),
3185
+ includeHeading: z5.boolean(),
3186
+ childUnitIds: z5.array(z5.string().min(1)),
3187
+ heightPx: z5.number().finite().nonnegative(),
3188
+ isContinuation: z5.boolean(),
3189
+ overflow: z5.boolean()
3190
+ })
3191
+ ]);
3192
+ var worksheetPaginationPlanSchema = z5.object({
3193
+ pages: z5.array(
3194
+ z5.object({
3195
+ pageNumber: z5.number().int().positive(),
3196
+ segments: z5.array(worksheetPageSegmentSchema),
3197
+ usedHeightPx: z5.number().finite().nonnegative()
3198
+ })
3199
+ ),
3200
+ diagnostics: z5.array(
3201
+ z5.object({
3202
+ code: z5.enum(worksheetRenderDiagnosticCodes),
3203
+ severity: z5.enum(["error", "warning"]),
3204
+ message: z5.string(),
3205
+ blockId: z5.string().optional(),
3206
+ exerciseId: z5.string().optional(),
3207
+ snippet: z5.string().optional()
3208
+ })
3209
+ ),
3210
+ metrics: z5.object({
3211
+ pageCount: z5.number().int().positive(),
3212
+ measuredUnitCount: z5.number().int().nonnegative(),
3213
+ overflowCount: z5.number().int().nonnegative()
3214
+ })
3215
+ });
3216
+
3217
+ // ../shared/src/export-layout/document-css.ts
3218
+ var { heightMm, marginMm, widthMm } = defaultWorksheetPageSettings;
3219
+ var worksheetDocumentCss = `
3220
+ @page {
3221
+ size: ${widthMm}mm ${heightMm}mm;
3222
+ margin: 0;
3223
+ }
3224
+
3225
+ .cs-worksheet {
3226
+ box-sizing: border-box;
3227
+ color: #111;
3228
+ font-family: "STIX Two Text", "Latin Modern Roman", "Libertinus Serif", Cambria, Georgia, serif;
3229
+ font-size: 12pt;
3230
+ line-height: 1.45;
3231
+ }
3232
+
3233
+ .cs-worksheet *,
3234
+ .cs-worksheet *::before,
3235
+ .cs-worksheet *::after {
3236
+ box-sizing: border-box;
3237
+ }
3238
+
3239
+ .cs-worksheet .katex {
3240
+ padding: 0;
3241
+ }
3242
+
3243
+ .cs-worksheet--continuous {
3244
+ width: ${widthMm}mm;
3245
+ padding: ${marginMm.top}mm ${marginMm.right}mm ${marginMm.bottom}mm ${marginMm.left}mm;
3246
+ background: #fff;
3247
+ }
3248
+
3249
+ .cs-worksheet--paged {
3250
+ display: flex;
3251
+ flex-direction: column;
3252
+ gap: 16px;
3253
+ }
3254
+
3255
+ .cs-worksheet__page {
3256
+ width: ${widthMm}mm;
3257
+ min-height: ${heightMm}mm;
3258
+ margin-left: auto;
3259
+ margin-right: auto;
3260
+ padding: ${marginMm.top}mm ${marginMm.right}mm ${marginMm.bottom}mm ${marginMm.left}mm;
3261
+ background: #fff;
3262
+ box-shadow: 0 4px 18px rgba(0, 0, 0, 0.18);
3263
+ }
3264
+
3265
+ .cs-worksheet__title {
3266
+ margin: 0 0 40px;
3267
+ font-size: 20pt;
3268
+ font-weight: 700;
3269
+ line-height: 1.2;
3270
+ text-align: center;
3271
+ }
3272
+
3273
+ .cs-worksheet__exercise-list {
3274
+ margin: 0;
3275
+ padding: 0;
3276
+ list-style: none;
3277
+ }
3278
+
3279
+ .cs-worksheet__exercise {
3280
+ margin-bottom: 32px;
3281
+ break-inside: avoid;
3282
+ }
3283
+
3284
+ .cs-worksheet__exercise:last-child {
3285
+ margin-bottom: 0;
3286
+ }
3287
+
3288
+ .cs-worksheet__exercise-heading {
3289
+ display: flex;
3290
+ justify-content: space-between;
3291
+ align-items: baseline;
3292
+ gap: 16px;
3293
+ margin-bottom: 8px;
3294
+ }
3295
+
3296
+ .cs-worksheet__exercise-title {
3297
+ margin: 0;
3298
+ font-size: 13pt;
3299
+ font-weight: 700;
3300
+ line-height: 1.3;
3301
+ }
3302
+
3303
+ .cs-worksheet__exercise-score {
3304
+ font-size: 10pt;
3305
+ white-space: nowrap;
3306
+ }
3307
+
3308
+ .cs-worksheet__exercise-text,
3309
+ .cs-worksheet__subsection-content {
3310
+ overflow-wrap: anywhere;
3311
+ }
3312
+
3313
+ .cs-worksheet__exercise-text::after,
3314
+ .cs-worksheet__subsection-content::after {
3315
+ content: "";
3316
+ display: block;
3317
+ clear: both;
3318
+ }
3319
+
3320
+ .cs-worksheet__math--display {
3321
+ display: block;
3322
+ margin-top: 8px;
3323
+ margin-bottom: 8px;
3324
+ text-align: center;
3325
+ }
3326
+
3327
+ .cs-worksheet__figure {
3328
+ margin: 16px 0;
3329
+ text-align: center;
3330
+ break-inside: avoid;
3331
+ position: relative;
3332
+ outline-offset: 2px;
3333
+ }
3334
+
3335
+ .cs-worksheet__figure--left {
3336
+ text-align: left;
3337
+ }
3338
+
3339
+ .cs-worksheet__figure--center {
3340
+ text-align: center;
3341
+ }
3342
+
3343
+ .cs-worksheet__figure--right {
3344
+ text-align: right;
3345
+ }
3346
+
3347
+ .cs-worksheet__figure--float-left {
3348
+ float: left;
3349
+ max-width: 55%;
3350
+ margin: 0 12px 8px 0;
3351
+ text-align: left;
3352
+ }
3353
+
3354
+ .cs-worksheet__figure--float-right {
3355
+ float: right;
3356
+ max-width: 55%;
3357
+ margin: 0 0 8px 12px;
3358
+ text-align: right;
3359
+ }
3360
+
3361
+ .cs-worksheet__figure img {
3362
+ height: auto;
3363
+ }
3364
+
3365
+ .cs-worksheet__figure-row {
3366
+ display: flex;
3367
+ flex-wrap: nowrap;
3368
+ align-items: flex-start;
3369
+ margin-top: 16px;
3370
+ margin-bottom: 16px;
3371
+ break-inside: avoid;
3372
+ clear: both;
3373
+ width: 100%;
3374
+ }
3375
+
3376
+ .cs-worksheet__figure-row-spacer {
3377
+ flex: 1 1 auto;
3378
+ min-width: 0;
3379
+ }
3380
+
3381
+ .cs-worksheet__figure-row-slot {
3382
+ display: flex;
3383
+ flex: 0 0 auto;
3384
+ align-items: flex-start;
3385
+ gap: 8mm;
3386
+ min-width: 0;
3387
+ }
3388
+
3389
+ .cs-worksheet__figure-row-slot--left {
3390
+ justify-content: flex-start;
3391
+ }
3392
+
3393
+ .cs-worksheet__figure-row-slot--center {
3394
+ justify-content: center;
3395
+ }
3396
+
3397
+ .cs-worksheet__figure-row-slot--right {
3398
+ justify-content: flex-end;
3399
+ }
3400
+
3401
+ .cs-worksheet__figure-row .cs-worksheet__figure {
3402
+ margin-top: 0;
3403
+ margin-bottom: 0;
3404
+ flex: 0 1 auto;
3405
+ }
3406
+
3407
+ .cs-worksheet__workspace {
3408
+ margin-top: 12px;
3409
+ break-inside: avoid;
3410
+ background-color: #fff;
3411
+ -webkit-print-color-adjust: exact;
3412
+ print-color-adjust: exact;
3413
+ outline-offset: 2px;
3414
+ clear: both;
3415
+ }
3416
+
3417
+ .cs-worksheet__workspace--lines {
3418
+ background-image: linear-gradient(
3419
+ to bottom,
3420
+ #c9d4dc 0,
3421
+ #c9d4dc 0.2mm,
3422
+ transparent 0.2mm
3423
+ );
3424
+ background-size: 100% 7mm;
3425
+ background-repeat: repeat;
3426
+ }
3427
+
3428
+ .cs-worksheet__workspace--grid {
3429
+ background-image:
3430
+ linear-gradient(
3431
+ to right,
3432
+ #d3dce3 0,
3433
+ #d3dce3 0.2mm,
3434
+ transparent 0.2mm
3435
+ ),
3436
+ linear-gradient(
3437
+ to bottom,
3438
+ #d3dce3 0,
3439
+ #d3dce3 0.2mm,
3440
+ transparent 0.2mm
3441
+ );
3442
+ background-size: 5mm 5mm;
3443
+ background-repeat: repeat;
3444
+ }
3445
+
3446
+ .cs-worksheet__subsection {
3447
+ margin-top: 16px;
3448
+ break-inside: avoid;
3449
+ clear: both;
3450
+ }
3451
+
3452
+ .cs-worksheet__subsection-title {
3453
+ margin: 0 0 4px;
3454
+ font-size: 11pt;
3455
+ font-weight: 700;
3456
+ }
3457
+
3458
+ @media print {
3459
+ .cs-worksheet--paged {
3460
+ display: block;
3461
+ gap: 0;
3462
+ }
3463
+
3464
+ .cs-worksheet__page {
3465
+ margin: 0;
3466
+ box-shadow: none;
3467
+ break-after: page;
3468
+ page-break-after: always;
3469
+ }
3470
+
3471
+ .cs-worksheet__page:last-child {
3472
+ break-after: auto;
3473
+ page-break-after: auto;
3474
+ }
3475
+ }
3476
+ `.trim();
3477
+ var worksheetHtmlDocumentShellCss = `
3478
+ html,
3479
+ body {
3480
+ margin: 0;
3481
+ padding: 0;
3482
+ }
3483
+ `.trim();
3484
+
3485
+ // ../shared/src/export-layout/html-pdf-export.ts
3486
+ import { z as z6 } from "zod";
3487
+ var worksheetHtmlPdfExportPayloadVersion = 1;
3488
+ var worksheetHtmlPdfExportPayloadSchema = z6.object({
3489
+ version: z6.literal(worksheetHtmlPdfExportPayloadVersion),
3490
+ layoutSettings: worksheetPreviewLayoutSettingsSchema,
3491
+ paginationPlan: worksheetPaginationPlanSchema
3492
+ });
3493
+ var scorePointsSchema = z6.number().min(0, "Score must be greater than or equal to 0").max(99999.9, "Score must be less than or equal to 99999.9").refine((value) => Number.isInteger(value * 10), "Score can have at most 1 decimal place");
3494
+ var worksheetExportTemplateInputShape = {
3495
+ language: z6.enum(translationLanguages),
3496
+ templateId: z6.enum(exportTemplateIds).default("exercises"),
3497
+ parameters: z6.record(z6.string(), z6.unknown()).default({}),
3498
+ layoutSettings: worksheetPreviewLayoutSettingsSchema.optional()
3499
+ };
3500
+ var worksheetPersistedExportSourceInputSchema = z6.object({
3501
+ source: z6.enum(["saved-sheet", "public-sheet"]).default("saved-sheet"),
3502
+ id: z6.uuid(),
3503
+ ...worksheetExportTemplateInputShape
3504
+ });
3505
+ var worksheetLocalExportExerciseInputSchema = z6.object({
3506
+ id: z6.uuid("Invalid UUID"),
3507
+ scorePoints: scorePointsSchema.nullable()
3508
+ });
3509
+ var worksheetLocalExportSourceInputSchema = z6.object({
3510
+ source: z6.literal("local-sheet"),
3511
+ title: z6.string().trim().min(1, "Title is required"),
3512
+ scoringEnabled: z6.boolean().default(false),
3513
+ exercises: z6.array(worksheetLocalExportExerciseInputSchema).max(100).default([]),
3514
+ ...worksheetExportTemplateInputShape
3515
+ });
3516
+ var worksheetExportSourceInputSchema = z6.union([
3517
+ worksheetPersistedExportSourceInputSchema,
3518
+ worksheetLocalExportSourceInputSchema
3519
+ ]);
3520
+ var worksheetHtmlPdfExportInputSchema = z6.union([
3521
+ worksheetPersistedExportSourceInputSchema.extend({
3522
+ htmlExport: worksheetHtmlPdfExportPayloadSchema
3523
+ }),
3524
+ worksheetLocalExportSourceInputSchema.extend({
3525
+ htmlExport: worksheetHtmlPdfExportPayloadSchema
3526
+ })
3527
+ ]);
3528
+
3529
+ // ../../node_modules/entities/dist/esm/decode-codepoint.js
3530
+ var _a;
3531
+ var fromCodePoint = (
3532
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, n/no-unsupported-features/es-builtins
3533
+ (_a = String.fromCodePoint) !== null && _a !== void 0 ? _a : function(codePoint) {
3534
+ let output = "";
3535
+ if (codePoint > 65535) {
3536
+ codePoint -= 65536;
3537
+ output += String.fromCharCode(codePoint >>> 10 & 1023 | 55296);
3538
+ codePoint = 56320 | codePoint & 1023;
3539
+ }
3540
+ output += String.fromCharCode(codePoint);
3541
+ return output;
3542
+ }
3543
+ );
3544
+
3545
+ // ../../node_modules/entities/dist/esm/decode.js
3546
+ var CharCodes;
3547
+ (function(CharCodes2) {
3548
+ CharCodes2[CharCodes2["NUM"] = 35] = "NUM";
3549
+ CharCodes2[CharCodes2["SEMI"] = 59] = "SEMI";
3550
+ CharCodes2[CharCodes2["EQUALS"] = 61] = "EQUALS";
3551
+ CharCodes2[CharCodes2["ZERO"] = 48] = "ZERO";
3552
+ CharCodes2[CharCodes2["NINE"] = 57] = "NINE";
3553
+ CharCodes2[CharCodes2["LOWER_A"] = 97] = "LOWER_A";
3554
+ CharCodes2[CharCodes2["LOWER_F"] = 102] = "LOWER_F";
3555
+ CharCodes2[CharCodes2["LOWER_X"] = 120] = "LOWER_X";
3556
+ CharCodes2[CharCodes2["LOWER_Z"] = 122] = "LOWER_Z";
3557
+ CharCodes2[CharCodes2["UPPER_A"] = 65] = "UPPER_A";
3558
+ CharCodes2[CharCodes2["UPPER_F"] = 70] = "UPPER_F";
3559
+ CharCodes2[CharCodes2["UPPER_Z"] = 90] = "UPPER_Z";
3560
+ })(CharCodes || (CharCodes = {}));
3561
+ var BinTrieFlags;
3562
+ (function(BinTrieFlags2) {
3563
+ BinTrieFlags2[BinTrieFlags2["VALUE_LENGTH"] = 49152] = "VALUE_LENGTH";
3564
+ BinTrieFlags2[BinTrieFlags2["BRANCH_LENGTH"] = 16256] = "BRANCH_LENGTH";
3565
+ BinTrieFlags2[BinTrieFlags2["JUMP_TABLE"] = 127] = "JUMP_TABLE";
3566
+ })(BinTrieFlags || (BinTrieFlags = {}));
3567
+ var EntityDecoderState;
3568
+ (function(EntityDecoderState2) {
3569
+ EntityDecoderState2[EntityDecoderState2["EntityStart"] = 0] = "EntityStart";
3570
+ EntityDecoderState2[EntityDecoderState2["NumericStart"] = 1] = "NumericStart";
3571
+ EntityDecoderState2[EntityDecoderState2["NumericDecimal"] = 2] = "NumericDecimal";
3572
+ EntityDecoderState2[EntityDecoderState2["NumericHex"] = 3] = "NumericHex";
3573
+ EntityDecoderState2[EntityDecoderState2["NamedEntity"] = 4] = "NamedEntity";
3574
+ })(EntityDecoderState || (EntityDecoderState = {}));
3575
+ var DecodingMode;
3576
+ (function(DecodingMode2) {
3577
+ DecodingMode2[DecodingMode2["Legacy"] = 0] = "Legacy";
3578
+ DecodingMode2[DecodingMode2["Strict"] = 1] = "Strict";
3579
+ DecodingMode2[DecodingMode2["Attribute"] = 2] = "Attribute";
3580
+ })(DecodingMode || (DecodingMode = {}));
3581
+
3582
+ // ../../node_modules/entities/dist/esm/escape.js
3583
+ var getCodePoint = (
3584
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
3585
+ String.prototype.codePointAt == null ? (c, index) => (c.charCodeAt(index) & 64512) === 55296 ? (c.charCodeAt(index) - 55296) * 1024 + c.charCodeAt(index + 1) - 56320 + 65536 : c.charCodeAt(index) : (
3586
+ // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
3587
+ (input, index) => input.codePointAt(index)
3588
+ )
3589
+ );
3590
+
3591
+ // ../../node_modules/entities/dist/esm/index.js
3592
+ var EntityLevel;
3593
+ (function(EntityLevel2) {
3594
+ EntityLevel2[EntityLevel2["XML"] = 0] = "XML";
3595
+ EntityLevel2[EntityLevel2["HTML"] = 1] = "HTML";
3596
+ })(EntityLevel || (EntityLevel = {}));
3597
+ var EncodingMode;
3598
+ (function(EncodingMode2) {
3599
+ EncodingMode2[EncodingMode2["UTF8"] = 0] = "UTF8";
3600
+ EncodingMode2[EncodingMode2["ASCII"] = 1] = "ASCII";
3601
+ EncodingMode2[EncodingMode2["Extensive"] = 2] = "Extensive";
3602
+ EncodingMode2[EncodingMode2["Attribute"] = 3] = "Attribute";
3603
+ EncodingMode2[EncodingMode2["Text"] = 4] = "Text";
3604
+ })(EncodingMode || (EncodingMode = {}));
1894
3605
 
1895
3606
  // ../shared/src/helpers/latex/latex-helpers.ts
1896
3607
  var latexDelimiters = [
@@ -1903,185 +3614,241 @@ var sortedLatexDelimiters = [...latexDelimiters].sort((leftDelimiter, rightDelim
1903
3614
  return rightDelimiter.left.length - leftDelimiter.left.length;
1904
3615
  });
1905
3616
 
3617
+ // ../shared/src/export-layout/render-html.ts
3618
+ var worksheetContentWidthInCm = (defaultWorksheetPageSettings.widthMm - defaultWorksheetPageSettings.marginMm.left - defaultWorksheetPageSettings.marginMm.right) / 10;
3619
+
3620
+ // ../shared/src/helpers/exercise-labels.ts
3621
+ var exerciseLabels = labels_default;
3622
+ var flattenExerciseLabels = (labelNodes = exerciseLabels) => {
3623
+ const seenIds = /* @__PURE__ */ new Set();
3624
+ const flattenedLabels = [];
3625
+ const visit = ({
3626
+ depth,
3627
+ node,
3628
+ parentId,
3629
+ pathIds,
3630
+ pathNames
3631
+ }) => {
3632
+ if (seenIds.has(node.id)) {
3633
+ throw new Error(`Duplicate exercise label id: ${node.id}`);
3634
+ }
3635
+ seenIds.add(node.id);
3636
+ const childIds = node.children?.map((child) => child.id) ?? [];
3637
+ const nextPathIds = [...pathIds, node.id];
3638
+ const nextPathNames = [...pathNames, node.name];
3639
+ flattenedLabels.push({
3640
+ id: node.id,
3641
+ name: node.name,
3642
+ parentId,
3643
+ depth,
3644
+ pathIds: nextPathIds,
3645
+ pathNames: nextPathNames,
3646
+ displayPath: nextPathNames.join(" / "),
3647
+ childIds
3648
+ });
3649
+ node.children?.forEach((child) => {
3650
+ visit({
3651
+ depth: depth + 1,
3652
+ node: child,
3653
+ parentId: node.id,
3654
+ pathIds: nextPathIds,
3655
+ pathNames: nextPathNames
3656
+ });
3657
+ });
3658
+ };
3659
+ labelNodes.forEach((node) => {
3660
+ visit({ depth: 0, node, parentId: null, pathIds: [], pathNames: [] });
3661
+ });
3662
+ return flattenedLabels;
3663
+ };
3664
+ var canonicalExerciseLabelIds = new Set(flattenExerciseLabels().map((label) => label.id));
3665
+
3666
+ // ../shared/src/helpers/latex/exercise-translation-latex.ts
3667
+ var hintField = "hint";
3668
+ var isLatexWholeField = (field) => {
3669
+ return field !== hintField;
3670
+ };
3671
+ var exerciseTranslationLatexWholeFields = exerciseTranslationFields.filter(isLatexWholeField);
3672
+
1906
3673
  // ../shared/src/schemas/model-output-schemas.ts
1907
- import z4 from "zod";
1908
- var importFigureCandidateIdsSchema = z4.array(z4.string()).optional();
1909
- var exerciseTranslationOutputSchema = z4.object({
1910
- translations: z4.object({
1911
- exercise_text: z4.string().trim().min(1).nullable(),
1912
- description: z4.string().trim().min(1).nullable(),
1913
- hint: z4.string().trim().min(1).nullable(),
1914
- answer: z4.string().trim().min(1).nullable(),
1915
- scaffold: z4.string().trim().min(1).nullable(),
1916
- detailed_solution: z4.string().trim().min(1).nullable()
3674
+ import z7 from "zod";
3675
+ var importFigureCandidateIdsSchema = z7.array(z7.string()).optional();
3676
+ var exerciseTranslationOutputSchema = z7.object({
3677
+ translations: z7.object({
3678
+ exercise_text: z7.string().trim().min(1).nullable(),
3679
+ description: z7.string().trim().min(1).nullable(),
3680
+ hint: z7.string().trim().min(1).nullable(),
3681
+ answer: z7.string().trim().min(1).nullable(),
3682
+ scaffold: z7.string().trim().min(1).nullable(),
3683
+ detailed_solution: z7.string().trim().min(1).nullable()
1917
3684
  })
1918
3685
  });
1919
- var sheetTranslationFieldSchema = z4.string().trim().min(1);
1920
- var exerciseSheetTranslationOutputSchema = z4.object({
1921
- translations: z4.object(
3686
+ var sheetTranslationFieldSchema = z7.string().trim().min(1);
3687
+ var exerciseSheetTranslationOutputSchema = z7.object({
3688
+ translations: z7.object(
1922
3689
  Object.fromEntries(
1923
3690
  exerciseSheetTranslationFields.map((field) => [field, sheetTranslationFieldSchema.nullable()])
1924
3691
  )
1925
3692
  ).strict()
1926
3693
  });
1927
- var generatedTranslationFieldSchema = z4.string().trim().min(1);
1928
- var generatedTranslationFieldsSchema = z4.object(
3694
+ var generatedTranslationFieldSchema = z7.string().trim().min(1);
3695
+ var generatedTranslationFieldsSchema = z7.object(
1929
3696
  Object.fromEntries(
1930
3697
  exerciseTranslationFields.map((field) => [field, generatedTranslationFieldSchema.nullable()])
1931
3698
  )
1932
3699
  ).strict();
1933
- var exerciseSolutionImportOutputSchema = z4.object({
1934
- language: z4.enum(translationLanguages),
1935
- hints: z4.array(z4.string()).nullable(),
1936
- answer: z4.string().nullable(),
1937
- scaffold: z4.string().nullable(),
1938
- detailedSolution: z4.string().nullable(),
1939
- notes: z4.string().nullable(),
3700
+ var exerciseSolutionImportOutputSchema = z7.object({
3701
+ language: z7.enum(translationLanguages),
3702
+ hints: z7.array(z7.string()).nullable(),
3703
+ answer: z7.string().nullable(),
3704
+ scaffold: z7.string().nullable(),
3705
+ detailedSolution: z7.string().nullable(),
3706
+ notes: z7.string().nullable(),
1940
3707
  solutionFigureCandidateIds: importFigureCandidateIdsSchema
1941
3708
  });
1942
- var generatedSolutionFieldsSchema = z4.object({
1943
- hints: z4.array(z4.string().trim().min(1)).min(1).nullable(),
1944
- answer: z4.string().trim().min(1).nullable(),
1945
- scaffold: z4.string().trim().min(1).nullable(),
1946
- detailedSolution: z4.string().trim().min(1).nullable()
3709
+ var generatedSolutionFieldsSchema = z7.object({
3710
+ hints: z7.array(z7.string().trim().min(1)).min(1).nullable(),
3711
+ answer: z7.string().trim().min(1).nullable(),
3712
+ scaffold: z7.string().trim().min(1).nullable(),
3713
+ detailedSolution: z7.string().trim().min(1).nullable()
1947
3714
  }).strict();
1948
- var sheetImportExerciseOutputSchema = z4.object({
1949
- text: z4.string(),
1950
- detailedSolution: z4.string().nullable(),
1951
- hints: z4.array(z4.string()).nullable(),
1952
- scaffold: z4.string().nullable(),
1953
- answer: z4.string().nullable(),
1954
- source: z4.string().nullable(),
1955
- notes: z4.string().nullable(),
3715
+ var sheetImportExerciseOutputSchema = z7.object({
3716
+ text: z7.string(),
3717
+ detailedSolution: z7.string().nullable(),
3718
+ hints: z7.array(z7.string()).nullable(),
3719
+ scaffold: z7.string().nullable(),
3720
+ answer: z7.string().nullable(),
3721
+ source: z7.string().nullable(),
3722
+ notes: z7.string().nullable(),
1956
3723
  textFigureCandidateIds: importFigureCandidateIdsSchema,
1957
3724
  solutionFigureCandidateIds: importFigureCandidateIdsSchema
1958
3725
  }).strict();
1959
- var sheetImportOutputSchema = z4.object({
1960
- isExerciseSheet: z4.boolean(),
1961
- title: z4.string(),
1962
- description: z4.string().nullable(),
1963
- language: z4.enum(translationLanguages),
1964
- exercises: z4.array(sheetImportExerciseOutputSchema)
3726
+ var sheetImportOutputSchema = z7.object({
3727
+ isExerciseSheet: z7.boolean(),
3728
+ title: z7.string(),
3729
+ description: z7.string().nullable(),
3730
+ language: z7.enum(translationLanguages),
3731
+ exercises: z7.array(sheetImportExerciseOutputSchema)
1965
3732
  }).strict();
1966
- var exerciseImportOutputSchema = z4.object({
1967
- exercises: z4.array(
1968
- z4.object({
1969
- language: z4.enum(translationLanguages),
1970
- text: z4.string(),
1971
- detailedSolution: z4.string().nullable(),
1972
- hints: z4.array(z4.string()).nullable(),
1973
- scaffold: z4.string().nullable(),
1974
- answer: z4.string().nullable(),
1975
- source: z4.string().nullable(),
1976
- notes: z4.string().nullable(),
3733
+ var exerciseImportOutputSchema = z7.object({
3734
+ exercises: z7.array(
3735
+ z7.object({
3736
+ language: z7.enum(translationLanguages),
3737
+ text: z7.string(),
3738
+ detailedSolution: z7.string().nullable(),
3739
+ hints: z7.array(z7.string()).nullable(),
3740
+ scaffold: z7.string().nullable(),
3741
+ answer: z7.string().nullable(),
3742
+ source: z7.string().nullable(),
3743
+ notes: z7.string().nullable(),
1977
3744
  textFigureCandidateIds: importFigureCandidateIdsSchema,
1978
3745
  solutionFigureCandidateIds: importFigureCandidateIdsSchema
1979
3746
  })
1980
3747
  )
1981
3748
  });
1982
- var komalPdfExerciseOutputSchema = z4.object({
1983
- exercise_text_latex: z4.string().describe("The parsed exercise text with LaTeX formulas delimited by $ signs"),
1984
- language: z4.enum(translationLanguages).describe("The language of the exercise"),
1985
- subject: z4.enum(exerciseSubjects).describe("The subject of the exercise")
3749
+ var komalPdfExerciseOutputSchema = z7.object({
3750
+ exercise_text_latex: z7.string().describe("The parsed exercise text with LaTeX formulas delimited by $ signs"),
3751
+ language: z7.enum(translationLanguages).describe("The language of the exercise"),
3752
+ subject: z7.enum(exerciseSubjects).describe("The subject of the exercise")
1986
3753
  });
1987
3754
 
1988
3755
  // ../shared/src/schemas/pgmq.ts
1989
- import { z as z5 } from "zod";
1990
- var importFileSchema = z5.object({
1991
- fileName: z5.string(),
1992
- fileType: z5.string(),
1993
- storageFilePath: z5.string()
3756
+ import { z as z8 } from "zod";
3757
+ var importFileSchema = z8.object({
3758
+ fileName: z8.string(),
3759
+ fileType: z8.string(),
3760
+ storageFilePath: z8.string()
1994
3761
  });
1995
- var declaredSheetImportComponentSchema = z5.object({
3762
+ var declaredSheetImportComponentSchema = z8.object({
1996
3763
  componentId: sheetImportComponentIdSchema,
1997
- description: z5.string().trim().min(1),
1998
- folderId: z5.string().nullable(),
1999
- titleOverride: z5.string().trim().min(1).nullable().optional(),
3764
+ description: z8.string().trim().min(1),
3765
+ folderId: z8.string().nullable(),
3766
+ titleOverride: z8.string().trim().min(1).nullable().optional(),
2000
3767
  translateToLanguages: sheetImportTranslationLanguageListSchema.optional()
2001
3768
  }).strict();
2002
- var exerciseSheetImportQueueMessageSchema = z5.object({
2003
- userId: z5.string(),
2004
- organizationId: z5.uuid(),
2005
- files: z5.array(importFileSchema),
2006
- jobId: z5.string(),
2007
- folderId: z5.string().nullable(),
2008
- docxGotenbergConversionEnabled: z5.boolean().optional(),
2009
- titleOverride: z5.string().nullable().optional(),
2010
- translateToLanguages: z5.array(z5.enum(translationLanguages)).refine((languages) => new Set(languages).size === languages.length, {
3769
+ var exerciseSheetImportQueueMessageSchema = z8.object({
3770
+ userId: z8.string(),
3771
+ organizationId: z8.uuid(),
3772
+ files: z8.array(importFileSchema),
3773
+ jobId: z8.string(),
3774
+ folderId: z8.string().nullable(),
3775
+ docxGotenbergConversionEnabled: z8.boolean().optional(),
3776
+ titleOverride: z8.string().nullable().optional(),
3777
+ translateToLanguages: z8.array(z8.enum(translationLanguages)).refine((languages) => new Set(languages).size === languages.length, {
2011
3778
  message: "translateToLanguages must be unique"
2012
3779
  }).optional(),
2013
- declaredComponents: z5.array(declaredSheetImportComponentSchema).min(1).optional()
2014
- });
2015
- var exerciseSolutionImportQueueMessageSchema = z5.object({
2016
- userId: z5.string(),
2017
- organizationId: z5.uuid(),
2018
- exerciseId: z5.uuid(),
2019
- files: z5.array(importFileSchema),
2020
- jobId: z5.string(),
2021
- docxGotenbergConversionEnabled: z5.boolean().optional()
2022
- });
2023
- var exerciseSheetSolutionImportQueueMessageSchema = z5.object({
2024
- userId: z5.string(),
2025
- organizationId: z5.uuid(),
2026
- exerciseSheetId: z5.uuid(),
2027
- files: z5.array(importFileSchema),
2028
- jobId: z5.string(),
2029
- docxGotenbergConversionEnabled: z5.boolean().optional()
2030
- });
2031
- var exerciseSolutionGenerationQueueMessageSchema = z5.object({
2032
- userId: z5.uuid(),
2033
- organizationId: z5.uuid(),
2034
- exerciseId: z5.uuid(),
2035
- exerciseSheetId: z5.uuid().optional(),
2036
- batchId: z5.uuid().optional(),
2037
- jobId: z5.uuid()
2038
- });
2039
- var exerciseTranslationGenerationQueueMessageSchema = z5.object({
2040
- userId: z5.uuid(),
2041
- organizationId: z5.uuid(),
2042
- exerciseId: z5.uuid(),
2043
- jobId: z5.uuid(),
2044
- languages: z5.array(z5.enum(translationLanguages)).min(1)
3780
+ declaredComponents: z8.array(declaredSheetImportComponentSchema).min(1).optional()
3781
+ });
3782
+ var exerciseSolutionImportQueueMessageSchema = z8.object({
3783
+ userId: z8.string(),
3784
+ organizationId: z8.uuid(),
3785
+ exerciseId: z8.uuid(),
3786
+ files: z8.array(importFileSchema),
3787
+ jobId: z8.string(),
3788
+ docxGotenbergConversionEnabled: z8.boolean().optional()
3789
+ });
3790
+ var exerciseSheetSolutionImportQueueMessageSchema = z8.object({
3791
+ userId: z8.string(),
3792
+ organizationId: z8.uuid(),
3793
+ exerciseSheetId: z8.uuid(),
3794
+ files: z8.array(importFileSchema),
3795
+ jobId: z8.string(),
3796
+ docxGotenbergConversionEnabled: z8.boolean().optional()
3797
+ });
3798
+ var exerciseSolutionGenerationQueueMessageSchema = z8.object({
3799
+ userId: z8.uuid(),
3800
+ organizationId: z8.uuid(),
3801
+ exerciseId: z8.uuid(),
3802
+ exerciseSheetId: z8.uuid().optional(),
3803
+ batchId: z8.uuid().optional(),
3804
+ jobId: z8.uuid()
3805
+ });
3806
+ var exerciseTranslationGenerationQueueMessageSchema = z8.object({
3807
+ userId: z8.uuid(),
3808
+ organizationId: z8.uuid(),
3809
+ exerciseId: z8.uuid(),
3810
+ jobId: z8.uuid(),
3811
+ languages: z8.array(z8.enum(translationLanguages)).min(1)
2045
3812
  }).refine((value) => new Set(value.languages).size === value.languages.length, {
2046
3813
  message: "languages must be unique"
2047
3814
  });
2048
- var exerciseSheetTranslationGenerationQueueMessageSchema = z5.object({
2049
- userId: z5.uuid(),
2050
- organizationId: z5.uuid(),
2051
- exerciseSheetId: z5.uuid(),
2052
- jobId: z5.uuid(),
2053
- language: z5.enum(translationLanguages),
2054
- sourceLanguage: z5.enum(translationLanguages).optional()
2055
- });
2056
- var exerciseImportQueueMessageSchema = z5.object({
2057
- source: z5.literal("ui"),
2058
- userId: z5.uuid(),
2059
- organizationId: z5.uuid(),
2060
- files: z5.array(importFileSchema),
2061
- exerciseSheetId: z5.uuid().nullable().optional(),
2062
- jobId: z5.string(),
2063
- docxGotenbergConversionEnabled: z5.boolean().optional(),
2064
- translateToLanguages: z5.array(z5.enum(translationLanguages)).refine((languages) => new Set(languages).size === languages.length, {
3815
+ var exerciseSheetTranslationGenerationQueueMessageSchema = z8.object({
3816
+ userId: z8.uuid(),
3817
+ organizationId: z8.uuid(),
3818
+ exerciseSheetId: z8.uuid(),
3819
+ jobId: z8.uuid(),
3820
+ language: z8.enum(translationLanguages),
3821
+ sourceLanguage: z8.enum(translationLanguages).optional()
3822
+ });
3823
+ var exerciseImportQueueMessageSchema = z8.object({
3824
+ source: z8.literal("ui"),
3825
+ userId: z8.uuid(),
3826
+ organizationId: z8.uuid(),
3827
+ files: z8.array(importFileSchema),
3828
+ exerciseSheetId: z8.uuid().nullable().optional(),
3829
+ jobId: z8.string(),
3830
+ docxGotenbergConversionEnabled: z8.boolean().optional(),
3831
+ translateToLanguages: z8.array(z8.enum(translationLanguages)).refine((languages) => new Set(languages).size === languages.length, {
2065
3832
  message: "translateToLanguages must be unique"
2066
3833
  }).optional()
2067
3834
  });
2068
- var exerciseEmbeddingRecalculationQueueMessageSchema = z5.object({
2069
- exerciseId: z5.uuid(),
2070
- force: z5.boolean().optional()
3835
+ var exerciseEmbeddingRecalculationQueueMessageSchema = z8.object({
3836
+ exerciseId: z8.uuid(),
3837
+ force: z8.boolean().optional()
2071
3838
  });
2072
- var externalNotificationQueueMessageSchema = z5.discriminatedUnion("type", [
2073
- z5.object({
2074
- type: z5.literal("new_user_signup"),
2075
- userId: z5.uuid(),
2076
- email: z5.email().nullable(),
2077
- occurredAt: z5.iso.datetime({ offset: true })
3839
+ var externalNotificationQueueMessageSchema = z8.discriminatedUnion("type", [
3840
+ z8.object({
3841
+ type: z8.literal("new_user_signup"),
3842
+ userId: z8.uuid(),
3843
+ email: z8.email().nullable(),
3844
+ occurredAt: z8.iso.datetime({ offset: true })
2078
3845
  })
2079
3846
  ]);
2080
3847
 
2081
3848
  // ../shared/src/templates/export-template-definitions.ts
2082
- import { z as z6 } from "zod";
3849
+ import { z as z9 } from "zod";
2083
3850
  var showScoresParameterSchema = {
2084
- showScores: z6.boolean().default(true)
3851
+ showScores: z9.boolean().default(true)
2085
3852
  };
2086
3853
  var showScoresParameterUi = {
2087
3854
  showScores: {
@@ -2089,11 +3856,11 @@ var showScoresParameterUi = {
2089
3856
  shouldDisplay: ({ scoringEnabled }) => scoringEnabled
2090
3857
  }
2091
3858
  };
2092
- var baseExportTemplateParametersSchema = z6.object(showScoresParameterSchema).strict();
3859
+ var baseExportTemplateParametersSchema = z9.object(showScoresParameterSchema).strict();
2093
3860
  var workspaceHeightParameterConfig = {
2094
- defaultValue: 4,
2095
- min: 0,
2096
- max: 12,
3861
+ defaultValue: worksheetPreviewLayoutSettingsLimits.workspaceHeightInCm.default,
3862
+ min: worksheetPreviewLayoutSettingsLimits.workspaceHeightInCm.min,
3863
+ max: worksheetPreviewLayoutSettingsLimits.workspaceHeightInCm.max,
2097
3864
  step: 0.5
2098
3865
  };
2099
3866
  var exportTemplateDefinitions = {
@@ -2104,9 +3871,10 @@ var exportTemplateDefinitions = {
2104
3871
  },
2105
3872
  "exercises-with-workspace": {
2106
3873
  id: "exercises-with-workspace",
2107
- parametersSchema: z6.object({
3874
+ parametersSchema: z9.object({
2108
3875
  ...showScoresParameterSchema,
2109
- workspaceHeightInCm: z6.number().min(workspaceHeightParameterConfig.min).max(workspaceHeightParameterConfig.max).default(workspaceHeightParameterConfig.defaultValue)
3876
+ workspaceHeightInCm: z9.number().min(workspaceHeightParameterConfig.min).max(workspaceHeightParameterConfig.max).default(workspaceHeightParameterConfig.defaultValue),
3877
+ workspaceFillMode: z9.enum(worksheetWorkspaceFillModes).default("grid")
2110
3878
  }).strict(),
2111
3879
  parameterUi: {
2112
3880
  ...showScoresParameterUi,
@@ -2116,6 +3884,11 @@ var exportTemplateDefinitions = {
2116
3884
  max: workspaceHeightParameterConfig.max,
2117
3885
  step: workspaceHeightParameterConfig.step,
2118
3886
  unit: "cm"
3887
+ },
3888
+ workspaceFillMode: {
3889
+ control: "select",
3890
+ options: [...worksheetWorkspaceFillModes],
3891
+ shouldDisplay: ({ previewRendererMode }) => previewRendererMode === "html"
2119
3892
  }
2120
3893
  }
2121
3894
  },
@@ -2157,6 +3930,20 @@ var parseUpdateExerciseAgentInput = (input) => {
2157
3930
  }
2158
3931
  return parsedInput.data;
2159
3932
  };
3933
+ var parseCreateExerciseAgentInput = (input) => {
3934
+ const parsedInput = createExerciseAgentInputSchema.safeParse(input);
3935
+ if (!parsedInput.success) {
3936
+ throw new CliCommandError(`Invalid exercise create input: ${formatZodIssues(parsedInput.error.issues)}`, 2);
3937
+ }
3938
+ return parsedInput.data;
3939
+ };
3940
+ var parseCreateSheetAgentInput = (input) => {
3941
+ const parsedInput = createSheetAgentInputSchema.safeParse(input);
3942
+ if (!parsedInput.success) {
3943
+ throw new CliCommandError(`Invalid sheet create input: ${formatZodIssues(parsedInput.error.issues)}`, 2);
3944
+ }
3945
+ return parsedInput.data;
3946
+ };
2160
3947
  var parseUpdateSheetAgentInput = (input) => {
2161
3948
  const parsedInput = updateSheetAgentInputSchema.safeParse(input);
2162
3949
  if (!parsedInput.success) {
@@ -2459,7 +4246,7 @@ var formatCliImportTranslationJobs = (translationJobs) => {
2459
4246
  // src/lib/manifest.ts
2460
4247
  import { readFile as readFile2, stat as stat2 } from "node:fs/promises";
2461
4248
  import { resolve as resolve2 } from "node:path";
2462
- import { z as z7 } from "zod";
4249
+ import { z as z10 } from "zod";
2463
4250
 
2464
4251
  // src/lib/translation-languages.ts
2465
4252
  var translationLanguages2 = ["english", "hungarian", "german", "french", "spanish", "italian"];
@@ -2489,7 +4276,7 @@ var normalizeOptionalString4 = (value) => {
2489
4276
  const normalizedValue = value.trim();
2490
4277
  return normalizedValue.length > 0 ? normalizedValue : void 0;
2491
4278
  };
2492
- var translationLanguageListSchema = z7.array(z7.enum(translationLanguages2)).min(1, { message: "translateTo must include at least one language." }).refine((languages) => new Set(languages).size === languages.length, {
4279
+ var translationLanguageListSchema = z10.array(z10.enum(translationLanguages2)).min(1, { message: "translateTo must include at least one language." }).refine((languages) => new Set(languages).size === languages.length, {
2493
4280
  message: "translateTo languages must be unique."
2494
4281
  });
2495
4282
  var sheetImportComponentIdPattern2 = /^[a-zA-Z0-9_-]{1,80}$/;
@@ -3272,6 +5059,46 @@ var throwSilentExitCode = (exitCode) => {
3272
5059
  throw new CliCommandError("", exitCode, false);
3273
5060
  };
3274
5061
 
5062
+ // src/commands/exercise-labels.ts
5063
+ var formatExerciseLabelsOutput = ({ labels }) => {
5064
+ if (labels.length === 0) {
5065
+ return "No exercise labels returned.";
5066
+ }
5067
+ return [
5068
+ `${labels.length} exercise label${labels.length === 1 ? "" : "s"} returned.`,
5069
+ ...labels.map((label) => `${" ".repeat(label.depth)}${label.id} ${label.displayPath}`)
5070
+ ].join("\n");
5071
+ };
5072
+ var createExerciseLabelsCommand = (context) => ({
5073
+ command: "labels",
5074
+ describe: "List canonical exercise labels supported by ChalkSurf",
5075
+ builder: (labelsYargs) => labelsYargs.example("chalksurf exercise labels --json", "List valid exercise labels for agent workflows"),
5076
+ handler: async (argv) => {
5077
+ const { apiClient, organizationId } = await createResolvedApiClient({
5078
+ context,
5079
+ baseUrlFlagValue: argv.baseUrl,
5080
+ organizationFlagValue: argv.organization,
5081
+ profileName: argv.profile
5082
+ });
5083
+ let result;
5084
+ try {
5085
+ result = await apiClient.agentListExerciseLabels();
5086
+ } catch (error) {
5087
+ throw mapApiErrorToCliError(error);
5088
+ }
5089
+ context.output.print(
5090
+ {
5091
+ organizationId: organizationId ?? null,
5092
+ labels: result.labels
5093
+ },
5094
+ (output) => formatExerciseLabelsOutput({ labels: output.labels }),
5095
+ {
5096
+ command: "exercise labels"
5097
+ }
5098
+ );
5099
+ }
5100
+ });
5101
+
3275
5102
  // src/commands/exercise.ts
3276
5103
  var exerciseStatusOptions2 = ["verified", "unverified", "invalid"];
3277
5104
  var noSearchableTermsWarningMessage = "Search terms were too common and were ignored.";
@@ -3314,9 +5141,34 @@ var formatExerciseDetailsOutput = ({ exercise }) => {
3314
5141
  var formatCopyExerciseOutput = ({ receipt }) => {
3315
5142
  return formatAgentWriteReceiptOutput({ receipt });
3316
5143
  };
5144
+ var formatCreateExerciseOutput = ({ receipt }) => {
5145
+ return formatAgentWriteReceiptOutput({ receipt });
5146
+ };
5147
+ var formatDeleteExerciseOutput = ({ receipt }) => {
5148
+ return formatAgentWriteReceiptOutput({ receipt });
5149
+ };
3317
5150
  var formatUpdateExerciseOutput = ({ receipt }) => {
3318
5151
  return formatAgentWriteReceiptOutput({ receipt });
3319
5152
  };
5153
+ var formatSetExerciseVisibilityOutput = ({ receipt }) => {
5154
+ return formatAgentWriteReceiptOutput({ receipt });
5155
+ };
5156
+ var getExerciseTranslationJobIds = ({ jobs }) => jobs.map((job) => job.jobId);
5157
+ var formatExerciseTranslationOutput = ({ jobs }) => {
5158
+ if (jobs.length === 0) {
5159
+ return "No exercise translation jobs queued.";
5160
+ }
5161
+ return jobs.map((job) => `${job.jobId} exercise ${job.exerciseId} ${job.languages.join(", ")}`).join("\n");
5162
+ };
5163
+ var resolveVisibilityFlag = ({ privateFlag, publicFlag }) => {
5164
+ if (publicFlag && privateFlag) {
5165
+ throw new CliCommandError("--public and --private cannot be used together.", 2);
5166
+ }
5167
+ if (!publicFlag && !privateFlag) {
5168
+ throw new CliCommandError("Either --public or --private is required.", 2);
5169
+ }
5170
+ return Boolean(publicFlag);
5171
+ };
3320
5172
  var formatExerciseUsageOutput = ({ usage }) => {
3321
5173
  const sheetCount = usage.sheets.length;
3322
5174
  const otherSheetCount = usage.otherOrganizationSheetCount;
@@ -3386,7 +5238,7 @@ var resolveRequestedUuid = ({
3386
5238
  }
3387
5239
  return void 0;
3388
5240
  }
3389
- const parsedValue = z8.uuid().safeParse(resolvedValue);
5241
+ const parsedValue = z11.uuid().safeParse(resolvedValue);
3390
5242
  if (!parsedValue.success) {
3391
5243
  throw new CliCommandError(`${label} must be a valid UUID.`, 2);
3392
5244
  }
@@ -3470,7 +5322,7 @@ var formatWaitedImportOutput = (job) => {
3470
5322
  return `${job.jobId} ${job.status ?? "pending"}`;
3471
5323
  };
3472
5324
  var registerExerciseCommands = (exerciseYargs, context) => {
3473
- return exerciseYargs.command(
5325
+ return exerciseYargs.command(createExerciseLabelsCommand(context)).command(
3474
5326
  "search",
3475
5327
  "Search exercises visible to the selected organization",
3476
5328
  (searchYargs) => searchYargs.option("text", {
@@ -3519,7 +5371,7 @@ var registerExerciseCommands = (exerciseYargs, context) => {
3519
5371
  'chalksurf exercise search --text "binomial theorem" --language english --ownership own --json',
3520
5372
  "Verify imported exercises in the selected organization"
3521
5373
  ).example(
3522
- "chalksurf --profile prod-codex exercise search --label geometry.triangles --status unverified --json",
5374
+ "chalksurf --profile prod-codex exercise search --label geometry.triangle --status unverified --json",
3523
5375
  "Find agent-created exercises that still need review"
3524
5376
  ),
3525
5377
  async (argv) => {
@@ -3687,21 +5539,246 @@ var registerExerciseCommands = (exerciseYargs, context) => {
3687
5539
  },
3688
5540
  usage: result.usage
3689
5541
  },
3690
- (output) => formatExerciseUsageOutput({ usage: output.usage }),
5542
+ (output) => formatExerciseUsageOutput({ usage: output.usage }),
5543
+ {
5544
+ command: "exercise usage"
5545
+ }
5546
+ );
5547
+ }
5548
+ ).command(
5549
+ "copy [exerciseId]",
5550
+ "Copy a visible exercise into the selected organization",
5551
+ (copyYargs) => copyYargs.positional("exerciseId", {
5552
+ type: "string",
5553
+ describe: "Exercise ID to copy"
5554
+ }).example(
5555
+ "chalksurf exercise copy 00000000-0000-4000-8000-000000000001 --json",
5556
+ "Copy a public or owned exercise for an agent workflow"
5557
+ ),
5558
+ async (argv) => {
5559
+ const id = resolveRequestedUuid({
5560
+ fallbackValue: argv.exerciseId,
5561
+ label: "exerciseId",
5562
+ required: true
5563
+ });
5564
+ const { apiClient, organizationId } = await createResolvedApiClient({
5565
+ context,
5566
+ baseUrlFlagValue: argv.baseUrl,
5567
+ organizationFlagValue: argv.organization,
5568
+ profileName: argv.profile
5569
+ });
5570
+ let result;
5571
+ try {
5572
+ result = await apiClient.agentCopyExercise(id);
5573
+ } catch (error) {
5574
+ throw mapApiErrorToCliError(error);
5575
+ }
5576
+ context.output.print(
5577
+ {
5578
+ request: {
5579
+ id,
5580
+ organizationId: organizationId ?? null
5581
+ },
5582
+ receipt: result.receipt
5583
+ },
5584
+ (output) => formatCopyExerciseOutput({ receipt: output.receipt }),
5585
+ {
5586
+ command: "exercise copy"
5587
+ }
5588
+ );
5589
+ }
5590
+ ).command(
5591
+ "create",
5592
+ "Create an exercise from an agent JSON payload",
5593
+ (createYargs) => createYargs.option("input-json", {
5594
+ type: "string",
5595
+ demandOption: true,
5596
+ describe: "JSON object matching the agent exercise create contract"
5597
+ }).example(
5598
+ `chalksurf exercise create --input-json '{"translations":{"english":{"exercise_text":"Find $x$."}},"labels":["algebra.equations"]}' --json`,
5599
+ "Create an exercise for an agent workflow"
5600
+ ),
5601
+ async (argv) => {
5602
+ const input = parseCreateExerciseAgentInput(
5603
+ parseJsonObjectFlag({ label: "--input-json", value: argv.inputJson })
5604
+ );
5605
+ const { apiClient, organizationId } = await createResolvedApiClient({
5606
+ context,
5607
+ baseUrlFlagValue: argv.baseUrl,
5608
+ organizationFlagValue: argv.organization,
5609
+ profileName: argv.profile
5610
+ });
5611
+ let result;
5612
+ try {
5613
+ result = await apiClient.agentCreateExercise(input);
5614
+ } catch (error) {
5615
+ throw mapApiErrorToCliError(error);
5616
+ }
5617
+ context.output.print(
5618
+ {
5619
+ request: {
5620
+ ...input,
5621
+ organizationId: organizationId ?? null
5622
+ },
5623
+ receipt: result.receipt
5624
+ },
5625
+ (output) => formatCreateExerciseOutput({ receipt: output.receipt }),
5626
+ {
5627
+ command: "exercise create"
5628
+ }
5629
+ );
5630
+ }
5631
+ ).command(
5632
+ "delete [exerciseId]",
5633
+ "Delete an unused exercise after confirmation",
5634
+ (deleteYargs) => deleteYargs.positional("exerciseId", {
5635
+ type: "string",
5636
+ describe: "Exercise ID to delete"
5637
+ }).option("expected-updated-at", {
5638
+ type: "string",
5639
+ demandOption: true,
5640
+ describe: "Expected current exercise updated_at ISO timestamp"
5641
+ }).option("confirm-resource-id", {
5642
+ type: "string",
5643
+ demandOption: true,
5644
+ describe: "Must exactly match the exercise ID being deleted"
5645
+ }).example(
5646
+ "chalksurf exercise delete 00000000-0000-4000-8000-000000000001 --expected-updated-at 2026-01-01T00:00:00.000Z --confirm-resource-id 00000000-0000-4000-8000-000000000001 --json",
5647
+ "Delete an unused exercise with destructive confirmation"
5648
+ ),
5649
+ async (argv) => {
5650
+ const id = resolveRequestedUuid({
5651
+ fallbackValue: argv.exerciseId,
5652
+ label: "exerciseId",
5653
+ required: true
5654
+ });
5655
+ const confirmResourceId = resolveRequestedUuid({
5656
+ flagValue: argv.confirmResourceId,
5657
+ label: "--confirm-resource-id",
5658
+ required: true
5659
+ });
5660
+ const input = {
5661
+ id,
5662
+ expectedUpdatedAt: argv.expectedUpdatedAt,
5663
+ confirmResourceId
5664
+ };
5665
+ const { apiClient, organizationId } = await createResolvedApiClient({
5666
+ context,
5667
+ baseUrlFlagValue: argv.baseUrl,
5668
+ organizationFlagValue: argv.organization,
5669
+ profileName: argv.profile
5670
+ });
5671
+ let result;
5672
+ try {
5673
+ result = await apiClient.agentDeleteExercise(input);
5674
+ } catch (error) {
5675
+ throw mapApiErrorToCliError(error);
5676
+ }
5677
+ context.output.print(
5678
+ {
5679
+ request: {
5680
+ ...input,
5681
+ organizationId: organizationId ?? null
5682
+ },
5683
+ receipt: result.receipt
5684
+ },
5685
+ (output) => formatDeleteExerciseOutput({ receipt: output.receipt }),
5686
+ {
5687
+ command: "exercise delete"
5688
+ }
5689
+ );
5690
+ }
5691
+ ).command(
5692
+ "update [exerciseId]",
5693
+ "Apply a field-level patch to an exercise",
5694
+ (updateYargs) => updateYargs.positional("exerciseId", {
5695
+ type: "string",
5696
+ describe: "Exercise ID to update"
5697
+ }).option("expected-updated-at", {
5698
+ type: "string",
5699
+ demandOption: true,
5700
+ describe: "Expected current exercise updated_at ISO timestamp"
5701
+ }).option("patch-json", {
5702
+ type: "string",
5703
+ demandOption: true,
5704
+ describe: "JSON object matching the agent exercise patch contract"
5705
+ }).option("target-sheet-id", {
5706
+ type: "string",
5707
+ describe: "Sheet ID whose variant workflow this update targets"
5708
+ }).option("allow-shared-exercise-update", {
5709
+ type: "boolean",
5710
+ default: false,
5711
+ describe: "Acknowledge updating an exercise used outside --target-sheet-id"
5712
+ }).example(
5713
+ `chalksurf exercise update 00000000-0000-4000-8000-000000000001 --expected-updated-at 2026-01-01T00:00:00.000Z --patch-json '{"translations":{"english":{"exercise_text":"Find $x$."}}}' --json`,
5714
+ "Patch exercise content with an optimistic updated_at precondition"
5715
+ ),
5716
+ async (argv) => {
5717
+ const id = resolveRequestedUuid({
5718
+ fallbackValue: argv.exerciseId,
5719
+ label: "exerciseId",
5720
+ required: true
5721
+ });
5722
+ const targetSheetId = resolveRequestedUuid({
5723
+ flagValue: argv.targetSheetId,
5724
+ label: "--target-sheet-id"
5725
+ });
5726
+ const patch = parseJsonObjectFlag({ label: "--patch-json", value: argv.patchJson });
5727
+ const input = parseUpdateExerciseAgentInput({
5728
+ id,
5729
+ expectedUpdatedAt: argv.expectedUpdatedAt,
5730
+ patch,
5731
+ ...targetSheetId === void 0 ? {} : { targetSheetId },
5732
+ allowSharedExerciseUpdate: argv.allowSharedExerciseUpdate ?? false
5733
+ });
5734
+ const { apiClient, organizationId } = await createResolvedApiClient({
5735
+ context,
5736
+ baseUrlFlagValue: argv.baseUrl,
5737
+ organizationFlagValue: argv.organization,
5738
+ profileName: argv.profile
5739
+ });
5740
+ let result;
5741
+ try {
5742
+ result = await apiClient.agentUpdateExercise(input);
5743
+ } catch (error) {
5744
+ throw mapApiErrorToCliError(error);
5745
+ }
5746
+ context.output.print(
5747
+ {
5748
+ request: {
5749
+ ...input,
5750
+ organizationId: organizationId ?? null
5751
+ },
5752
+ receipt: result.receipt
5753
+ },
5754
+ (output) => formatUpdateExerciseOutput({ receipt: output.receipt }),
3691
5755
  {
3692
- command: "exercise usage"
5756
+ command: "exercise update"
3693
5757
  }
3694
5758
  );
3695
5759
  }
3696
5760
  ).command(
3697
- "copy [exerciseId]",
3698
- "Copy a visible exercise into the selected organization",
3699
- (copyYargs) => copyYargs.positional("exerciseId", {
5761
+ "set-visibility [exerciseId]",
5762
+ "Set exercise visibility after checking the current updated_at value",
5763
+ (visibilityYargs) => visibilityYargs.positional("exerciseId", {
3700
5764
  type: "string",
3701
- describe: "Exercise ID to copy"
5765
+ describe: "Exercise ID to update"
5766
+ }).option("expected-updated-at", {
5767
+ type: "string",
5768
+ demandOption: true,
5769
+ describe: "Expected current exercise updated_at ISO timestamp"
5770
+ }).option("public", {
5771
+ type: "boolean",
5772
+ describe: "Make the exercise public"
5773
+ }).option("private", {
5774
+ type: "boolean",
5775
+ describe: "Make the exercise private"
5776
+ }).option("confirm-make-public-resource-id", {
5777
+ type: "string",
5778
+ describe: "Required when using --public; must exactly match the exercise ID"
3702
5779
  }).example(
3703
- "chalksurf exercise copy 00000000-0000-4000-8000-000000000001 --json",
3704
- "Copy a public or owned exercise for an agent workflow"
5780
+ "chalksurf exercise set-visibility 00000000-0000-4000-8000-000000000001 --public --expected-updated-at 2026-01-01T00:00:00.000Z --confirm-make-public-resource-id 00000000-0000-4000-8000-000000000001 --json",
5781
+ "Make an exercise public with confirmation"
3705
5782
  ),
3706
5783
  async (argv) => {
3707
5784
  const id = resolveRequestedUuid({
@@ -3709,6 +5786,20 @@ var registerExerciseCommands = (exerciseYargs, context) => {
3709
5786
  label: "exerciseId",
3710
5787
  required: true
3711
5788
  });
5789
+ const isPublic = resolveVisibilityFlag({
5790
+ privateFlag: argv.private,
5791
+ publicFlag: argv.public
5792
+ });
5793
+ const confirmMakePublicResourceId = resolveRequestedUuid({
5794
+ flagValue: argv.confirmMakePublicResourceId,
5795
+ label: "--confirm-make-public-resource-id"
5796
+ });
5797
+ const input = {
5798
+ id,
5799
+ expectedUpdatedAt: argv.expectedUpdatedAt,
5800
+ isPublic,
5801
+ ...confirmMakePublicResourceId === void 0 ? {} : { confirmMakePublicResourceId }
5802
+ };
3712
5803
  const { apiClient, organizationId } = await createResolvedApiClient({
3713
5804
  context,
3714
5805
  baseUrlFlagValue: argv.baseUrl,
@@ -3717,48 +5808,45 @@ var registerExerciseCommands = (exerciseYargs, context) => {
3717
5808
  });
3718
5809
  let result;
3719
5810
  try {
3720
- result = await apiClient.agentCopyExercise(id);
5811
+ result = await apiClient.agentSetExerciseVisibility(input);
3721
5812
  } catch (error) {
3722
5813
  throw mapApiErrorToCliError(error);
3723
5814
  }
3724
5815
  context.output.print(
3725
5816
  {
3726
5817
  request: {
3727
- id,
5818
+ ...input,
3728
5819
  organizationId: organizationId ?? null
3729
5820
  },
3730
5821
  receipt: result.receipt
3731
5822
  },
3732
- (output) => formatCopyExerciseOutput({ receipt: output.receipt }),
5823
+ (output) => formatSetExerciseVisibilityOutput({ receipt: output.receipt }),
3733
5824
  {
3734
- command: "exercise copy"
5825
+ command: "exercise set-visibility"
3735
5826
  }
3736
5827
  );
3737
5828
  }
3738
5829
  ).command(
3739
- "update [exerciseId]",
3740
- "Apply a field-level patch to an exercise",
3741
- (updateYargs) => updateYargs.positional("exerciseId", {
5830
+ "translate [exerciseId]",
5831
+ "Queue translation generation for an existing exercise",
5832
+ (translateYargs) => translateYargs.positional("exerciseId", {
3742
5833
  type: "string",
3743
- describe: "Exercise ID to update"
3744
- }).option("expected-updated-at", {
3745
- type: "string",
3746
- demandOption: true,
3747
- describe: "Expected current exercise updated_at ISO timestamp"
3748
- }).option("patch-json", {
3749
- type: "string",
3750
- demandOption: true,
3751
- describe: "JSON object matching the agent exercise patch contract"
3752
- }).option("target-sheet-id", {
5834
+ describe: "Exercise ID to translate"
5835
+ }).option("translate-to", {
5836
+ array: true,
3753
5837
  type: "string",
3754
- describe: "Sheet ID whose variant workflow this update targets"
3755
- }).option("allow-shared-exercise-update", {
5838
+ describe: `Generate translated exercise content for these languages (${translationLanguages2.join(", ")})`
5839
+ }).option("timeout-ms", {
5840
+ type: "number",
5841
+ default: 3e5,
5842
+ describe: "Maximum time to wait before timing out"
5843
+ }).option("wait", {
3756
5844
  type: "boolean",
3757
5845
  default: false,
3758
- describe: "Acknowledge updating an exercise used outside --target-sheet-id"
5846
+ describe: "Wait for the queued translation job to finish"
3759
5847
  }).example(
3760
- `chalksurf exercise update 00000000-0000-4000-8000-000000000001 --expected-updated-at 2026-01-01T00:00:00.000Z --patch-json '{"translations":{"english":{"exercise_text":"Find $x$."}}}' --json`,
3761
- "Patch exercise content with an optimistic updated_at precondition"
5848
+ "chalksurf exercise translate 00000000-0000-4000-8000-000000000001 --translate-to english --json",
5849
+ "Queue exercise translation generation"
3762
5850
  ),
3763
5851
  async (argv) => {
3764
5852
  const id = resolveRequestedUuid({
@@ -3766,18 +5854,11 @@ var registerExerciseCommands = (exerciseYargs, context) => {
3766
5854
  label: "exerciseId",
3767
5855
  required: true
3768
5856
  });
3769
- const targetSheetId = resolveRequestedUuid({
3770
- flagValue: argv.targetSheetId,
3771
- label: "--target-sheet-id"
3772
- });
3773
- const patch = parseJsonObjectFlag({ label: "--patch-json", value: argv.patchJson });
3774
- const input = parseUpdateExerciseAgentInput({
3775
- id,
3776
- expectedUpdatedAt: argv.expectedUpdatedAt,
3777
- patch,
3778
- ...targetSheetId === void 0 ? {} : { targetSheetId },
3779
- allowSharedExerciseUpdate: argv.allowSharedExerciseUpdate ?? false
3780
- });
5857
+ const targetLanguages = resolveRequestedTranslateToLanguages(argv.translateTo);
5858
+ if (!targetLanguages || targetLanguages.length === 0) {
5859
+ throw new CliCommandError("--translate-to is required at least once.", 2);
5860
+ }
5861
+ const input = { id, targetLanguages };
3781
5862
  const { apiClient, organizationId } = await createResolvedApiClient({
3782
5863
  context,
3783
5864
  baseUrlFlagValue: argv.baseUrl,
@@ -3786,23 +5867,56 @@ var registerExerciseCommands = (exerciseYargs, context) => {
3786
5867
  });
3787
5868
  let result;
3788
5869
  try {
3789
- result = await apiClient.agentUpdateExercise(input);
5870
+ result = await apiClient.agentStartExerciseTranslationGeneration(input);
3790
5871
  } catch (error) {
3791
5872
  throw mapApiErrorToCliError(error);
3792
5873
  }
5874
+ if (argv.wait !== true) {
5875
+ context.output.print(
5876
+ {
5877
+ request: {
5878
+ ...input,
5879
+ organizationId: organizationId ?? null,
5880
+ wait: false,
5881
+ timeoutMs: null
5882
+ },
5883
+ jobs: result.jobs
5884
+ },
5885
+ (output) => formatExerciseTranslationOutput({ jobs: output.jobs }),
5886
+ {
5887
+ command: "exercise translate"
5888
+ }
5889
+ );
5890
+ return;
5891
+ }
5892
+ const timeoutMs = normalizeWaitTimeoutMs(argv.timeoutMs);
5893
+ const waitResult = await waitForCliJobs({
5894
+ getUserJob: async (jobId) => await apiClient.getUserJob(jobId),
5895
+ jobIds: getExerciseTranslationJobIds(result),
5896
+ now: context.now,
5897
+ sleep: context.sleep,
5898
+ timeoutMs
5899
+ });
5900
+ const waitError = getWaitError(waitResult);
3793
5901
  context.output.print(
3794
5902
  {
3795
5903
  request: {
3796
5904
  ...input,
3797
- organizationId: organizationId ?? null
5905
+ organizationId: organizationId ?? null,
5906
+ wait: true,
5907
+ timeoutMs
3798
5908
  },
3799
- receipt: result.receipt
5909
+ jobs: result.jobs,
5910
+ wait: waitResult
3800
5911
  },
3801
- (output) => formatUpdateExerciseOutput({ receipt: output.receipt }),
5912
+ (output) => output.wait.jobs.map((job) => formatCliJobSummary(job)).join("\n"),
3802
5913
  {
3803
- command: "exercise update"
5914
+ command: "exercise translate",
5915
+ ok: waitError == null,
5916
+ error: waitError
3804
5917
  }
3805
5918
  );
5919
+ throwSilentExitCode(getWaitExitCode(waitResult));
3806
5920
  }
3807
5921
  ).command(
3808
5922
  "validate-latex",
@@ -4211,6 +6325,120 @@ var registerExerciseCommands = (exerciseYargs, context) => {
4211
6325
  ).demandCommand(1).strict();
4212
6326
  };
4213
6327
 
6328
+ // src/commands/feedback.ts
6329
+ var parseOptionalContextJson = (value) => {
6330
+ return value === void 0 ? void 0 : parseJsonObjectFlag({ label: "--context-json", value });
6331
+ };
6332
+ var requireMessage = (value) => {
6333
+ const message = value?.trim();
6334
+ if (!message) {
6335
+ throw new CliCommandError("--message is required.", 2);
6336
+ }
6337
+ return message;
6338
+ };
6339
+ var formatFeedbackOutput = ({ receipt }) => `Submitted ${receipt.eventType} feedback event ${receipt.eventId}.`;
6340
+ var registerFeedbackCommands = (feedbackYargs, context) => {
6341
+ return feedbackYargs.command(
6342
+ "user",
6343
+ "Send user-consented feedback to ChalkSurf",
6344
+ (userYargs) => userYargs.option("message", {
6345
+ type: "string",
6346
+ demandOption: true,
6347
+ describe: "Feedback text the user agreed to send"
6348
+ }).option("user-consent", {
6349
+ type: "boolean",
6350
+ default: false,
6351
+ describe: "Confirm the user explicitly consented to sending this feedback"
6352
+ }).option("category", {
6353
+ type: "string",
6354
+ choices: ["bug_report", "feature_request", "frustration", "blocked_request", "other"],
6355
+ describe: "Feedback category"
6356
+ }).option("context-json", {
6357
+ type: "string",
6358
+ describe: "Optional JSON object with reproduction details or request context"
6359
+ }).example(
6360
+ 'chalksurf feedback user --message "Import failed for my sheet" --user-consent --json',
6361
+ "Send user-consented feedback"
6362
+ ),
6363
+ async (argv) => {
6364
+ if (!argv.userConsent) {
6365
+ throw new CliCommandError("--user-consent is required before sending user feedback.", 2);
6366
+ }
6367
+ const input = {
6368
+ message: requireMessage(argv.message),
6369
+ userConsent: true,
6370
+ ...argv.category ? { category: argv.category } : {},
6371
+ ...argv.contextJson === void 0 ? {} : { context: parseOptionalContextJson(argv.contextJson) }
6372
+ };
6373
+ const { apiClient, organizationId } = await createResolvedApiClient({
6374
+ context,
6375
+ baseUrlFlagValue: argv.baseUrl,
6376
+ organizationFlagValue: argv.organization,
6377
+ profileName: argv.profile
6378
+ });
6379
+ let result;
6380
+ try {
6381
+ result = await apiClient.agentSendUserFeedback(input);
6382
+ } catch (error) {
6383
+ throw mapApiErrorToCliError(error);
6384
+ }
6385
+ context.output.print(
6386
+ {
6387
+ organizationId: organizationId ?? null,
6388
+ receipt: result.receipt
6389
+ },
6390
+ (output) => formatFeedbackOutput({ receipt: output.receipt }),
6391
+ { command: "feedback user" }
6392
+ );
6393
+ }
6394
+ ).command(
6395
+ "agent",
6396
+ "Send agent-observed CLI, MCP, API, or documentation feedback to ChalkSurf",
6397
+ (agentYargs) => agentYargs.option("message", {
6398
+ type: "string",
6399
+ demandOption: true,
6400
+ describe: "Feedback text describing the agent-observed issue"
6401
+ }).option("category", {
6402
+ type: "string",
6403
+ choices: ["api_inconsistency", "documentation_issue", "missing_capability", "unexpected_behavior", "other"],
6404
+ describe: "Feedback category"
6405
+ }).option("context-json", {
6406
+ type: "string",
6407
+ describe: "Optional JSON object with command, tool, or documentation context"
6408
+ }).example(
6409
+ 'chalksurf feedback agent --message "MCP tool output differed from docs" --category documentation_issue --json',
6410
+ "Send agent-observed feedback"
6411
+ ),
6412
+ async (argv) => {
6413
+ const input = {
6414
+ message: requireMessage(argv.message),
6415
+ ...argv.category ? { category: argv.category } : {},
6416
+ ...argv.contextJson === void 0 ? {} : { context: parseOptionalContextJson(argv.contextJson) }
6417
+ };
6418
+ const { apiClient, organizationId } = await createResolvedApiClient({
6419
+ context,
6420
+ baseUrlFlagValue: argv.baseUrl,
6421
+ organizationFlagValue: argv.organization,
6422
+ profileName: argv.profile
6423
+ });
6424
+ let result;
6425
+ try {
6426
+ result = await apiClient.agentSendAgentFeedback(input);
6427
+ } catch (error) {
6428
+ throw mapApiErrorToCliError(error);
6429
+ }
6430
+ context.output.print(
6431
+ {
6432
+ organizationId: organizationId ?? null,
6433
+ receipt: result.receipt
6434
+ },
6435
+ (output) => formatFeedbackOutput({ receipt: output.receipt }),
6436
+ { command: "feedback agent" }
6437
+ );
6438
+ }
6439
+ ).demandCommand(1);
6440
+ };
6441
+
4214
6442
  // src/commands/job.ts
4215
6443
  var jobStatusOptions = ["pending", "in_progress", "completed", "failed"];
4216
6444
  var jobTypeOptions = [
@@ -4631,7 +6859,7 @@ var registerProfileCommands = (profileYargs, context) => {
4631
6859
  };
4632
6860
 
4633
6861
  // src/commands/sheet.ts
4634
- import { z as z9 } from "zod";
6862
+ import { z as z12 } from "zod";
4635
6863
  var readinessIssueTypeLabels = {
4636
6864
  missing_translation: "missing translations",
4637
6865
  missing_solution: "missing solutions",
@@ -4755,7 +6983,7 @@ var resolveRequestedUuid2 = ({
4755
6983
  }
4756
6984
  return void 0;
4757
6985
  }
4758
- const parsedValue = z9.uuid().safeParse(resolvedValue);
6986
+ const parsedValue = z12.uuid().safeParse(resolvedValue);
4759
6987
  if (!parsedValue.success) {
4760
6988
  throw new CliCommandError(`${label} must be a valid UUID.`, 2);
4761
6989
  }
@@ -4766,7 +6994,7 @@ var resolveRequestedUuidList = ({ label, values }) => {
4766
6994
  throw new CliCommandError(`${label} is required at least once.`, 2);
4767
6995
  }
4768
6996
  return values.map((value, index) => {
4769
- const parsedValue = z9.uuid().safeParse(value.trim());
6997
+ const parsedValue = z12.uuid().safeParse(value.trim());
4770
6998
  if (!parsedValue.success) {
4771
6999
  throw new CliCommandError(`${label}[${index}] must be a valid UUID.`, 2);
4772
7000
  }
@@ -5102,6 +7330,33 @@ var formatSheetDetailsOutput = ({ sheet }) => {
5102
7330
  `readiness: ${formatSheetReadinessSummary(sheet.readinessSummary)}`
5103
7331
  ].join("\n");
5104
7332
  };
7333
+ var formatSheetVersionListOutput = ({ versions }) => {
7334
+ if (versions.length === 0) {
7335
+ return "No sheet versions found.";
7336
+ }
7337
+ return [
7338
+ `${versions.length} sheet version${versions.length === 1 ? "" : "s"} returned.`,
7339
+ ...versions.map(
7340
+ (version) => [
7341
+ version.id,
7342
+ `v${version.versionNumber}`,
7343
+ version.type,
7344
+ version.createdAt,
7345
+ version.createdByName ? `by ${version.createdByName}` : null,
7346
+ version.sourceVersionId ? `source: ${version.sourceVersionId}` : null
7347
+ ].filter(Boolean).join(" ")
7348
+ )
7349
+ ].join("\n");
7350
+ };
7351
+ var formatSheetVersionDetailsOutput = ({ version }) => {
7352
+ return [
7353
+ `Sheet version ${version.id}`,
7354
+ `sheet: ${version.exerciseSheetId}`,
7355
+ `version: ${version.versionNumber}`,
7356
+ `type: ${version.type}`,
7357
+ `exercises: ${version.exercises.length}`
7358
+ ].join("\n");
7359
+ };
5105
7360
  var formatSheetIssuesOutput = ({ issues, readinessSummary }) => {
5106
7361
  if (issues.length === 0) {
5107
7362
  return `No sheet issues found. ${formatSheetReadinessSummary(readinessSummary)}`;
@@ -5126,9 +7381,27 @@ var formatSheetIssuesOutput = ({ issues, readinessSummary }) => {
5126
7381
  var formatCopySheetOutput = ({ receipt }) => {
5127
7382
  return formatAgentWriteReceiptOutput({ receipt });
5128
7383
  };
7384
+ var formatCreateSheetOutput = ({ receipt }) => {
7385
+ return formatAgentWriteReceiptOutput({ receipt });
7386
+ };
7387
+ var formatDeleteSheetOutput = ({ receipt }) => {
7388
+ return formatAgentWriteReceiptOutput({ receipt });
7389
+ };
5129
7390
  var formatUpdateSheetOutput = ({ receipt }) => {
5130
7391
  return formatAgentWriteReceiptOutput({ receipt });
5131
7392
  };
7393
+ var formatSetSheetVisibilityOutput = ({ receipt }) => {
7394
+ return formatAgentWriteReceiptOutput({ receipt });
7395
+ };
7396
+ var getSheetTranslationJobIds = ({ jobs }) => jobs.flatMap((job) => job.jobId ? [job.jobId] : []);
7397
+ var formatSheetTranslationOutput = ({ jobs }) => {
7398
+ if (jobs.length === 0 || jobs.every((job) => job.jobId === null)) {
7399
+ return "No sheet translation jobs queued.";
7400
+ }
7401
+ return jobs.map(
7402
+ (job) => job.jobId ? `${job.jobId} sheet ${job.exerciseSheetId} ${job.language}` : `already complete ${job.language}`
7403
+ ).join("\n");
7404
+ };
5132
7405
  var formatAppendExercisesToSheetOutput = ({ receipt }) => {
5133
7406
  return formatAgentWriteReceiptOutput({ receipt });
5134
7407
  };
@@ -5144,9 +7417,21 @@ var formatFolderListOutput = ({ folders }) => {
5144
7417
  var formatCreateFolderOutput = ({ receipt }) => {
5145
7418
  return formatAgentWriteReceiptOutput({ receipt });
5146
7419
  };
7420
+ var formatDeleteFolderOutput = ({ receipt }) => {
7421
+ return formatAgentWriteReceiptOutput({ receipt });
7422
+ };
5147
7423
  var formatRenameFolderOutput = ({ receipt }) => {
5148
7424
  return formatAgentWriteReceiptOutput({ receipt });
5149
7425
  };
7426
+ var resolveVisibilityFlag2 = ({ privateFlag, publicFlag }) => {
7427
+ if (publicFlag && privateFlag) {
7428
+ throw new CliCommandError("--public and --private cannot be used together.", 2);
7429
+ }
7430
+ if (!publicFlag && !privateFlag) {
7431
+ throw new CliCommandError("Either --public or --private is required.", 2);
7432
+ }
7433
+ return Boolean(publicFlag);
7434
+ };
5150
7435
  var registerSheetCommands = (sheetYargs, context) => {
5151
7436
  return sheetYargs.command(
5152
7437
  "search",
@@ -5217,42 +7502,134 @@ var registerSheetCommands = (sheetYargs, context) => {
5217
7502
  context.output.print(
5218
7503
  {
5219
7504
  request: {
5220
- text,
5221
- ownership,
5222
- hasIssues: readinessFilters.hasIssues,
5223
- issueTypes: readinessFilters.issueTypes,
5224
- limit,
5225
- offset,
7505
+ text,
7506
+ ownership,
7507
+ hasIssues: readinessFilters.hasIssues,
7508
+ issueTypes: readinessFilters.issueTypes,
7509
+ limit,
7510
+ offset,
7511
+ organizationId: organizationId ?? null
7512
+ },
7513
+ exerciseSheets: searchResult.exerciseSheets,
7514
+ totalCount: searchResult.totalCount
7515
+ },
7516
+ (result) => formatSheetSearchOutput({
7517
+ exerciseSheets: result.exerciseSheets,
7518
+ totalCount: result.totalCount
7519
+ }),
7520
+ {
7521
+ command: "sheet search"
7522
+ }
7523
+ );
7524
+ }
7525
+ ).command(
7526
+ "get [exerciseSheetId]",
7527
+ "Get full exercise sheet details visible to the selected organization",
7528
+ (getYargs) => getYargs.positional("exerciseSheetId", {
7529
+ type: "string",
7530
+ describe: "Exercise sheet ID to fetch"
7531
+ }).example(
7532
+ "chalksurf sheet get 00000000-0000-4000-8000-000000000001 --json",
7533
+ "Fetch sheet details for an agent workflow"
7534
+ ),
7535
+ async (argv) => {
7536
+ const id = resolveRequestedUuid2({
7537
+ fallbackValue: argv.exerciseSheetId,
7538
+ label: "exerciseSheetId",
7539
+ required: true
7540
+ });
7541
+ const { apiClient, organizationId } = await createResolvedApiClient({
7542
+ context,
7543
+ baseUrlFlagValue: argv.baseUrl,
7544
+ organizationFlagValue: argv.organization,
7545
+ profileName: argv.profile
7546
+ });
7547
+ let result;
7548
+ try {
7549
+ result = await apiClient.agentGetSheet(id);
7550
+ } catch (error) {
7551
+ throw mapApiErrorToCliError(error);
7552
+ }
7553
+ context.output.print(
7554
+ {
7555
+ request: {
7556
+ id,
7557
+ organizationId: organizationId ?? null
7558
+ },
7559
+ sheet: result.sheet
7560
+ },
7561
+ (output) => formatSheetDetailsOutput({ sheet: output.sheet }),
7562
+ {
7563
+ command: "sheet get"
7564
+ }
7565
+ );
7566
+ }
7567
+ ).command(
7568
+ "versions [exerciseSheetId]",
7569
+ "List version history for an exercise sheet owned by the selected organization",
7570
+ (versionsYargs) => versionsYargs.positional("exerciseSheetId", {
7571
+ type: "string",
7572
+ describe: "Exercise sheet ID to inspect"
7573
+ }).example(
7574
+ "chalksurf sheet versions 00000000-0000-4000-8000-000000000001 --json",
7575
+ "List restorable sheet versions for an agent audit"
7576
+ ),
7577
+ async (argv) => {
7578
+ const id = resolveRequestedUuid2({
7579
+ fallbackValue: argv.exerciseSheetId,
7580
+ label: "exerciseSheetId",
7581
+ required: true
7582
+ });
7583
+ const { apiClient, organizationId } = await createResolvedApiClient({
7584
+ context,
7585
+ baseUrlFlagValue: argv.baseUrl,
7586
+ organizationFlagValue: argv.organization,
7587
+ profileName: argv.profile
7588
+ });
7589
+ let result;
7590
+ try {
7591
+ result = await apiClient.agentListSheetVersions(id);
7592
+ } catch (error) {
7593
+ throw mapApiErrorToCliError(error);
7594
+ }
7595
+ context.output.print(
7596
+ {
7597
+ request: {
7598
+ id,
5226
7599
  organizationId: organizationId ?? null
5227
7600
  },
5228
- exerciseSheets: searchResult.exerciseSheets,
5229
- totalCount: searchResult.totalCount
7601
+ versions: result.versions
5230
7602
  },
5231
- (result) => formatSheetSearchOutput({
5232
- exerciseSheets: result.exerciseSheets,
5233
- totalCount: result.totalCount
5234
- }),
7603
+ (output) => formatSheetVersionListOutput({ versions: output.versions }),
5235
7604
  {
5236
- command: "sheet search"
7605
+ command: "sheet versions"
5237
7606
  }
5238
7607
  );
5239
7608
  }
5240
7609
  ).command(
5241
- "get [exerciseSheetId]",
5242
- "Get full exercise sheet details visible to the selected organization",
5243
- (getYargs) => getYargs.positional("exerciseSheetId", {
7610
+ "version [exerciseSheetId] [versionId]",
7611
+ "Get one exercise sheet version snapshot",
7612
+ (versionYargs) => versionYargs.positional("exerciseSheetId", {
5244
7613
  type: "string",
5245
- describe: "Exercise sheet ID to fetch"
7614
+ describe: "Exercise sheet ID to inspect"
7615
+ }).positional("versionId", {
7616
+ type: "string",
7617
+ describe: "Sheet version ID to fetch"
5246
7618
  }).example(
5247
- "chalksurf sheet get 00000000-0000-4000-8000-000000000001 --json",
5248
- "Fetch sheet details for an agent workflow"
7619
+ "chalksurf sheet version 00000000-0000-4000-8000-000000000001 00000000-0000-4000-8000-000000000002 --json",
7620
+ "Fetch one sheet version snapshot for an agent audit"
5249
7621
  ),
5250
7622
  async (argv) => {
5251
- const id = resolveRequestedUuid2({
7623
+ const exerciseSheetId = resolveRequestedUuid2({
5252
7624
  fallbackValue: argv.exerciseSheetId,
5253
7625
  label: "exerciseSheetId",
5254
7626
  required: true
5255
7627
  });
7628
+ const versionId = resolveRequestedUuid2({
7629
+ fallbackValue: argv.versionId,
7630
+ label: "versionId",
7631
+ required: true
7632
+ });
5256
7633
  const { apiClient, organizationId } = await createResolvedApiClient({
5257
7634
  context,
5258
7635
  baseUrlFlagValue: argv.baseUrl,
@@ -5261,21 +7638,22 @@ var registerSheetCommands = (sheetYargs, context) => {
5261
7638
  });
5262
7639
  let result;
5263
7640
  try {
5264
- result = await apiClient.agentGetSheet(id);
7641
+ result = await apiClient.agentGetSheetVersion(exerciseSheetId, versionId);
5265
7642
  } catch (error) {
5266
7643
  throw mapApiErrorToCliError(error);
5267
7644
  }
5268
7645
  context.output.print(
5269
7646
  {
5270
7647
  request: {
5271
- id,
7648
+ exerciseSheetId,
7649
+ versionId,
5272
7650
  organizationId: organizationId ?? null
5273
7651
  },
5274
- sheet: result.sheet
7652
+ version: result.version
5275
7653
  },
5276
- (output) => formatSheetDetailsOutput({ sheet: output.sheet }),
7654
+ (output) => formatSheetVersionDetailsOutput({ version: output.version }),
5277
7655
  {
5278
- command: "sheet get"
7656
+ command: "sheet version"
5279
7657
  }
5280
7658
  );
5281
7659
  }
@@ -5404,6 +7782,58 @@ var registerSheetCommands = (sheetYargs, context) => {
5404
7782
  }
5405
7783
  );
5406
7784
  }
7785
+ ).command(
7786
+ "delete [folderId]",
7787
+ "Delete an empty folder after confirmation",
7788
+ (deleteYargs) => deleteYargs.positional("folderId", {
7789
+ type: "string",
7790
+ describe: "Folder ID to delete"
7791
+ }).option("confirm-resource-id", {
7792
+ type: "string",
7793
+ demandOption: true,
7794
+ describe: "Must exactly match the folder ID being deleted"
7795
+ }).example(
7796
+ "chalksurf sheet folder delete 00000000-0000-4000-8000-000000000001 --confirm-resource-id 00000000-0000-4000-8000-000000000001 --json",
7797
+ "Delete an empty folder with destructive confirmation"
7798
+ ),
7799
+ async (argv) => {
7800
+ const id = resolveRequestedUuid2({
7801
+ fallbackValue: argv.folderId,
7802
+ label: "folderId",
7803
+ required: true
7804
+ });
7805
+ const confirmResourceId = resolveRequestedUuid2({
7806
+ flagValue: argv.confirmResourceId,
7807
+ label: "--confirm-resource-id",
7808
+ required: true
7809
+ });
7810
+ const input = { id, confirmResourceId };
7811
+ const { apiClient, organizationId } = await createResolvedApiClient({
7812
+ context,
7813
+ baseUrlFlagValue: argv.baseUrl,
7814
+ organizationFlagValue: argv.organization,
7815
+ profileName: argv.profile
7816
+ });
7817
+ let result;
7818
+ try {
7819
+ result = await apiClient.agentDeleteFolder(input);
7820
+ } catch (error) {
7821
+ throw mapApiErrorToCliError(error);
7822
+ }
7823
+ context.output.print(
7824
+ {
7825
+ request: {
7826
+ ...input,
7827
+ organizationId: organizationId ?? null
7828
+ },
7829
+ receipt: result.receipt
7830
+ },
7831
+ (output) => formatDeleteFolderOutput({ receipt: output.receipt }),
7832
+ {
7833
+ command: "sheet folder delete"
7834
+ }
7835
+ );
7836
+ }
5407
7837
  ).command(
5408
7838
  "rename [folderId] [name]",
5409
7839
  "Rename a folder in the selected organization",
@@ -5454,6 +7884,176 @@ var registerSheetCommands = (sheetYargs, context) => {
5454
7884
  ).demandCommand(1),
5455
7885
  () => {
5456
7886
  }
7887
+ ).command(
7888
+ "create",
7889
+ "Create an exercise sheet from an agent JSON payload",
7890
+ (createYargs) => createYargs.option("input-json", {
7891
+ type: "string",
7892
+ demandOption: true,
7893
+ describe: "JSON object matching the agent sheet create contract"
7894
+ }).example(
7895
+ `chalksurf sheet create --input-json '{"name":"Practice","language":"english","exerciseIds":["00000000-0000-4000-8000-000000000001"]}' --json`,
7896
+ "Create a sheet for an agent workflow"
7897
+ ),
7898
+ async (argv) => {
7899
+ const input = parseCreateSheetAgentInput(
7900
+ parseJsonObjectFlag({ label: "--input-json", value: argv.inputJson })
7901
+ );
7902
+ const { apiClient, organizationId } = await createResolvedApiClient({
7903
+ context,
7904
+ baseUrlFlagValue: argv.baseUrl,
7905
+ organizationFlagValue: argv.organization,
7906
+ profileName: argv.profile
7907
+ });
7908
+ let result;
7909
+ try {
7910
+ result = await apiClient.agentCreateSheet(input);
7911
+ } catch (error) {
7912
+ throw mapApiErrorToCliError(error);
7913
+ }
7914
+ context.output.print(
7915
+ {
7916
+ request: {
7917
+ ...input,
7918
+ organizationId: organizationId ?? null
7919
+ },
7920
+ receipt: result.receipt
7921
+ },
7922
+ (output) => formatCreateSheetOutput({ receipt: output.receipt }),
7923
+ {
7924
+ command: "sheet create"
7925
+ }
7926
+ );
7927
+ }
7928
+ ).command(
7929
+ "delete [exerciseSheetId]",
7930
+ "Delete an exercise sheet after confirmation",
7931
+ (deleteYargs) => deleteYargs.positional("exerciseSheetId", {
7932
+ type: "string",
7933
+ describe: "Exercise sheet ID to delete"
7934
+ }).option("expected-updated-at", {
7935
+ type: "string",
7936
+ demandOption: true,
7937
+ describe: "Expected current sheet updated_at ISO timestamp"
7938
+ }).option("confirm-resource-id", {
7939
+ type: "string",
7940
+ demandOption: true,
7941
+ describe: "Must exactly match the sheet ID being deleted"
7942
+ }).example(
7943
+ "chalksurf sheet delete 00000000-0000-4000-8000-000000000001 --expected-updated-at 2026-01-01T00:00:00.000Z --confirm-resource-id 00000000-0000-4000-8000-000000000001 --json",
7944
+ "Delete a sheet with destructive confirmation"
7945
+ ),
7946
+ async (argv) => {
7947
+ const id = resolveRequestedUuid2({
7948
+ fallbackValue: argv.exerciseSheetId,
7949
+ label: "exerciseSheetId",
7950
+ required: true
7951
+ });
7952
+ const confirmResourceId = resolveRequestedUuid2({
7953
+ flagValue: argv.confirmResourceId,
7954
+ label: "--confirm-resource-id",
7955
+ required: true
7956
+ });
7957
+ const input = {
7958
+ id,
7959
+ expectedUpdatedAt: argv.expectedUpdatedAt,
7960
+ confirmResourceId
7961
+ };
7962
+ const { apiClient, organizationId } = await createResolvedApiClient({
7963
+ context,
7964
+ baseUrlFlagValue: argv.baseUrl,
7965
+ organizationFlagValue: argv.organization,
7966
+ profileName: argv.profile
7967
+ });
7968
+ let result;
7969
+ try {
7970
+ result = await apiClient.agentDeleteSheet(input);
7971
+ } catch (error) {
7972
+ throw mapApiErrorToCliError(error);
7973
+ }
7974
+ context.output.print(
7975
+ {
7976
+ request: {
7977
+ ...input,
7978
+ organizationId: organizationId ?? null
7979
+ },
7980
+ receipt: result.receipt
7981
+ },
7982
+ (output) => formatDeleteSheetOutput({ receipt: output.receipt }),
7983
+ {
7984
+ command: "sheet delete"
7985
+ }
7986
+ );
7987
+ }
7988
+ ).command(
7989
+ "set-visibility [exerciseSheetId]",
7990
+ "Set sheet visibility after checking the current updated_at value",
7991
+ (visibilityYargs) => visibilityYargs.positional("exerciseSheetId", {
7992
+ type: "string",
7993
+ describe: "Exercise sheet ID to update"
7994
+ }).option("expected-updated-at", {
7995
+ type: "string",
7996
+ demandOption: true,
7997
+ describe: "Expected current sheet updated_at ISO timestamp"
7998
+ }).option("public", {
7999
+ type: "boolean",
8000
+ describe: "Make the sheet public"
8001
+ }).option("private", {
8002
+ type: "boolean",
8003
+ describe: "Make the sheet private"
8004
+ }).option("confirm-make-public-resource-id", {
8005
+ type: "string",
8006
+ describe: "Required when using --public; must exactly match the sheet ID"
8007
+ }).example(
8008
+ "chalksurf sheet set-visibility 00000000-0000-4000-8000-000000000001 --public --expected-updated-at 2026-01-01T00:00:00.000Z --confirm-make-public-resource-id 00000000-0000-4000-8000-000000000001 --json",
8009
+ "Make a sheet public with confirmation"
8010
+ ),
8011
+ async (argv) => {
8012
+ const id = resolveRequestedUuid2({
8013
+ fallbackValue: argv.exerciseSheetId,
8014
+ label: "exerciseSheetId",
8015
+ required: true
8016
+ });
8017
+ const isPublic = resolveVisibilityFlag2({
8018
+ privateFlag: argv.private,
8019
+ publicFlag: argv.public
8020
+ });
8021
+ const confirmMakePublicResourceId = resolveRequestedUuid2({
8022
+ flagValue: argv.confirmMakePublicResourceId,
8023
+ label: "--confirm-make-public-resource-id"
8024
+ });
8025
+ const input = {
8026
+ id,
8027
+ expectedUpdatedAt: argv.expectedUpdatedAt,
8028
+ isPublic,
8029
+ ...confirmMakePublicResourceId === void 0 ? {} : { confirmMakePublicResourceId }
8030
+ };
8031
+ const { apiClient, organizationId } = await createResolvedApiClient({
8032
+ context,
8033
+ baseUrlFlagValue: argv.baseUrl,
8034
+ organizationFlagValue: argv.organization,
8035
+ profileName: argv.profile
8036
+ });
8037
+ let result;
8038
+ try {
8039
+ result = await apiClient.agentSetSheetVisibility(input);
8040
+ } catch (error) {
8041
+ throw mapApiErrorToCliError(error);
8042
+ }
8043
+ context.output.print(
8044
+ {
8045
+ request: {
8046
+ ...input,
8047
+ organizationId: organizationId ?? null
8048
+ },
8049
+ receipt: result.receipt
8050
+ },
8051
+ (output) => formatSetSheetVisibilityOutput({ receipt: output.receipt }),
8052
+ {
8053
+ command: "sheet set-visibility"
8054
+ }
8055
+ );
8056
+ }
5457
8057
  ).command(
5458
8058
  "copy [exerciseSheetId] [name]",
5459
8059
  "Copy a visible exercise sheet into the selected organization",
@@ -5591,6 +8191,111 @@ var registerSheetCommands = (sheetYargs, context) => {
5591
8191
  }
5592
8192
  );
5593
8193
  }
8194
+ ).command(
8195
+ "translate [exerciseSheetId]",
8196
+ "Queue translation generation for an existing exercise sheet",
8197
+ (translateYargs) => translateYargs.positional("exerciseSheetId", {
8198
+ type: "string",
8199
+ describe: "Exercise sheet ID to translate"
8200
+ }).option("translate-to", {
8201
+ array: true,
8202
+ type: "string",
8203
+ describe: `Generate translated sheet content for these languages (${translationLanguages2.join(", ")})`
8204
+ }).option("source-language", {
8205
+ type: "string",
8206
+ describe: "Preferred source language for sheet metadata translation"
8207
+ }).option("timeout-ms", {
8208
+ type: "number",
8209
+ default: 3e5,
8210
+ describe: "Maximum time to wait before timing out"
8211
+ }).option("wait", {
8212
+ type: "boolean",
8213
+ default: false,
8214
+ describe: "Wait for queued translation jobs to finish"
8215
+ }).example(
8216
+ "chalksurf sheet translate 00000000-0000-4000-8000-000000000001 --translate-to english --json",
8217
+ "Queue sheet translation generation"
8218
+ ),
8219
+ async (argv) => {
8220
+ const id = resolveRequestedUuid2({
8221
+ fallbackValue: argv.exerciseSheetId,
8222
+ label: "exerciseSheetId",
8223
+ required: true
8224
+ });
8225
+ const targetLanguages = resolveRequestedTranslateToLanguages(argv.translateTo);
8226
+ if (!targetLanguages || targetLanguages.length === 0) {
8227
+ throw new CliCommandError("--translate-to is required at least once.", 2);
8228
+ }
8229
+ const sourceLanguage = normalizeChoiceValues({
8230
+ allowedValues: translationLanguages2,
8231
+ label: "--source-language",
8232
+ values: argv.sourceLanguage ? [argv.sourceLanguage] : void 0
8233
+ })?.[0];
8234
+ const input = {
8235
+ id,
8236
+ targetLanguages,
8237
+ ...sourceLanguage === void 0 ? {} : { sourceLanguage }
8238
+ };
8239
+ const { apiClient, organizationId } = await createResolvedApiClient({
8240
+ context,
8241
+ baseUrlFlagValue: argv.baseUrl,
8242
+ organizationFlagValue: argv.organization,
8243
+ profileName: argv.profile
8244
+ });
8245
+ let result;
8246
+ try {
8247
+ result = await apiClient.agentStartSheetTranslationGeneration(input);
8248
+ } catch (error) {
8249
+ throw mapApiErrorToCliError(error);
8250
+ }
8251
+ if (argv.wait !== true) {
8252
+ context.output.print(
8253
+ {
8254
+ request: {
8255
+ ...input,
8256
+ organizationId: organizationId ?? null,
8257
+ wait: false,
8258
+ timeoutMs: null
8259
+ },
8260
+ jobs: result.jobs
8261
+ },
8262
+ (output) => formatSheetTranslationOutput({ jobs: output.jobs }),
8263
+ {
8264
+ command: "sheet translate"
8265
+ }
8266
+ );
8267
+ return;
8268
+ }
8269
+ const timeoutMs = normalizeWaitTimeoutMs(argv.timeoutMs);
8270
+ const jobIds = getSheetTranslationJobIds(result);
8271
+ const waitResult = jobIds.length === 0 ? { jobs: [], timedOut: false } : await waitForCliJobs({
8272
+ getUserJob: async (jobId) => await apiClient.getUserJob(jobId),
8273
+ jobIds,
8274
+ now: context.now,
8275
+ sleep: context.sleep,
8276
+ timeoutMs
8277
+ });
8278
+ const waitError = getWaitError(waitResult);
8279
+ context.output.print(
8280
+ {
8281
+ request: {
8282
+ ...input,
8283
+ organizationId: organizationId ?? null,
8284
+ wait: true,
8285
+ timeoutMs
8286
+ },
8287
+ jobs: result.jobs,
8288
+ wait: waitResult
8289
+ },
8290
+ (output) => output.wait.jobs.length > 0 ? output.wait.jobs.map((job) => formatCliJobSummary(job)).join("\n") : formatSheetTranslationOutput({ jobs: output.jobs }),
8291
+ {
8292
+ command: "sheet translate",
8293
+ ok: waitError == null,
8294
+ error: waitError
8295
+ }
8296
+ );
8297
+ throwSilentExitCode(getWaitExitCode(waitResult));
8298
+ }
5594
8299
  ).command(
5595
8300
  "update [exerciseSheetId]",
5596
8301
  "Apply a field-level patch to an exercise sheet",
@@ -6215,6 +8920,12 @@ var createCli = ({
6215
8920
  (exerciseYargs) => registerExerciseCommands(exerciseYargs, commandContext),
6216
8921
  () => {
6217
8922
  }
8923
+ ).command(
8924
+ "feedback <subcommand>",
8925
+ "Feedback commands",
8926
+ (feedbackYargs) => registerFeedbackCommands(feedbackYargs, commandContext),
8927
+ () => {
8928
+ }
6218
8929
  ).command(
6219
8930
  "sheet <subcommand>",
6220
8931
  "Exercise sheet commands",
@@ -6250,7 +8961,7 @@ var parseCliWithCapturedOutput = async ({
6250
8961
  var hasFlag = (argv, flags) => {
6251
8962
  return argv.some((argument) => flags.includes(argument));
6252
8963
  };
6253
- var topLevelCommands = /* @__PURE__ */ new Set(["auth", "org", "profile", "exercise", "sheet", "job"]);
8964
+ var topLevelCommands = /* @__PURE__ */ new Set(["auth", "org", "profile", "exercise", "feedback", "sheet", "job"]);
6254
8965
  var hasTopLevelCommand = (argv) => {
6255
8966
  return argv.some((argument) => topLevelCommands.has(argument));
6256
8967
  };