recess-cli 1.9.0 → 1.9.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.
Files changed (3) hide show
  1. package/README.md +4 -1
  2. package/dist/cli.js +59 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -197,13 +197,16 @@ recess --json students schedule --student <kid-id> --days 30
197
197
  recess --json students xp-history --student <kid-id> --range month
198
198
  recess --json goals list --student <kid-id>
199
199
  recess --json todos create --student <kid-id> --title "Read chapter 4"
200
+ recess --json todos generate-applet <todo-id> --student <kid-id> [--due-date YYYY-MM-DD]
200
201
  recess --json memories context --student <kid-id>
201
202
  recess --json memories log --student <kid-id> --date 2026-08-12
202
203
  recess --json rocky get --student <kid-id>
203
204
  ```
204
205
 
205
206
  All family writes still preview first. Goal/todo/Rocky edits also carry the current server version
206
- into the confirmed request. A guardian cannot target another family, inspect frozen/deleted
207
+ into the confirmed request. Applet generation is staff-only: it resolves the todo's latest learning
208
+ analysis, defaults the generated todo to tomorrow in the student's timezone, and lets the server
209
+ select v1 or v2 for that student. A guardian cannot target another family, inspect frozen/deleted
207
210
  template history, choose todo rewards/completion/internal fields, or use the ADMIN-only
208
211
  device-authorization flow. `memories context` and `memories log` read only the tutor repository's
209
212
  spine, rules, reminders, and session logs; private guide remarks are never returned. The CLI does
package/dist/cli.js CHANGED
@@ -180,6 +180,8 @@ Usage:
180
180
  [--due-date YYYY-MM-DD] [--estimated-minutes N] [--url URL] [--confirm]
181
181
  recess [--json] todos edit <todo-id> --patch-file <path/patch.json>
182
182
  [--confirm --approval-token TOKEN]
183
+ recess [--json] todos generate-applet <todo-id> --student <kid-id>
184
+ [--due-date YYYY-MM-DD] [--confirm --approval-token TOKEN]
183
185
  recess [--json] memories context --student <kid-id>
184
186
  recess [--json] memories log --student <kid-id> --date YYYY-MM-DD
185
187
  recess [--json] rocky get --student <kid-id>
@@ -1175,6 +1177,20 @@ function flagItemDateMs(parsed) {
1175
1177
  }
1176
1178
  return ms;
1177
1179
  }
1180
+ function flagDateOnly(parsed, name) {
1181
+ const raw = flagString(parsed, name);
1182
+ if (raw === undefined)
1183
+ return undefined;
1184
+ const parsedDate = /^\d{4}-\d{2}-\d{2}$/.test(raw)
1185
+ ? new Date(`${raw}T00:00:00.000Z`)
1186
+ : null;
1187
+ if (!parsedDate ||
1188
+ Number.isNaN(parsedDate.getTime()) ||
1189
+ parsedDate.toISOString().slice(0, 10) !== raw) {
1190
+ throw new CliError("invalid_arguments", `--${name} must be a valid YYYY-MM-DD date.`);
1191
+ }
1192
+ return raw;
1193
+ }
1178
1194
  const DAY_MS = 24 * 60 * 60 * 1000;
1179
1195
  // The cohort event routes take zoneless local wall-clock datetimes
1180
1196
  // (interpreted in the cohort's timezone server-side).
@@ -3423,7 +3439,49 @@ export async function runCommand(argv) {
3423
3439
  body,
3424
3440
  }));
3425
3441
  }
3426
- throw new CliError("invalid_arguments", "Use todos create|edit.");
3442
+ if (verb === "generate-applet") {
3443
+ const todoId = positional(parsed, 2, "todo ID");
3444
+ const studentId = flagString(parsed, "student", { required: true });
3445
+ const targetDueDateISO = flagDateOnly(parsed, "due-date");
3446
+ const [todo, learningAnalysis] = await Promise.all([
3447
+ api.client.GET("/tutor/browser/todos/{id}/", {
3448
+ params: { path: { id: todoId } },
3449
+ }),
3450
+ api.client.GET("/tutor/students/{studentId}/todos/{todoId}/learning-analysis", {
3451
+ params: { path: { studentId, todoId } },
3452
+ }),
3453
+ ]);
3454
+ const currentTodo = unwrap(todo);
3455
+ if (currentTodo.userId !== studentId) {
3456
+ throw new CliError("not_found", "The todo does not belong to the requested student.");
3457
+ }
3458
+ const analysis = unwrap(learningAnalysis).analysis;
3459
+ if (!analysis) {
3460
+ throw new CliError("not_found", "This todo does not have a learning analysis to generate an applet from.");
3461
+ }
3462
+ const preview = {
3463
+ action: "generate an applet from a student's todo analysis",
3464
+ target: {
3465
+ studentUserId: studentId,
3466
+ todoId,
3467
+ todoTitle: currentTodo.title,
3468
+ analysisId: analysis.id,
3469
+ },
3470
+ request: {
3471
+ targetDueDateISO: targetDueDateISO ?? null,
3472
+ },
3473
+ details: {
3474
+ dueDate: targetDueDateISO ?? "tomorrow in the student's timezone",
3475
+ versionRouting: "The server evaluates applet-gen-v2 for this student and uses v1 when the flag is off or its evaluation fails.",
3476
+ },
3477
+ };
3478
+ requirePreviewBoundConfirmation(parsed, preview);
3479
+ return unwrap(await api.client.POST("/admin/learning-pipeline/{analysisId}/generate-applet/", {
3480
+ params: { path: { analysisId: analysis.id } },
3481
+ body: targetDueDateISO ? { targetDueDateISO } : {},
3482
+ }));
3483
+ }
3484
+ throw new CliError("invalid_arguments", "Use todos create|edit|generate-applet.");
3427
3485
  }
3428
3486
  if (noun === "memories") {
3429
3487
  const studentId = flagString(parsed, "student", { required: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recess-cli",
3
- "version": "1.9.0",
3
+ "version": "1.9.1",
4
4
  "description": "Safe Recess administration and family AI tools from the command line.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {