@robbeverhelst/do 1.295.0 → 1.296.0

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 (2) hide show
  1. package/dist/do.js +405 -5
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -5221,6 +5221,46 @@ var mailDeliveries = pgTable("mail_deliveries", {
5221
5221
  uniqueIndex("mail_deliveries_campaign_email_uniq").on(t.campaignId, t.toEmail)
5222
5222
  ]);
5223
5223
 
5224
+ // ../../packages/schema/src/db/rsvp-questions.ts
5225
+ var rsvpQuestionKind = pgEnum("rsvp_question_kind", [
5226
+ "choice",
5227
+ "multi",
5228
+ "text",
5229
+ "number",
5230
+ "yes_no"
5231
+ ]);
5232
+ var rsvpQuestionScope = pgEnum("rsvp_question_scope", ["household", "guest"]);
5233
+ var rsvpQuestions = pgTable("rsvp_questions", {
5234
+ id: text("id").primaryKey(),
5235
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
5236
+ guestListId: text("guest_list_id").notNull().references(() => guestLists.id, { onDelete: "cascade" }),
5237
+ kind: rsvpQuestionKind("kind").notNull(),
5238
+ label: jsonb("label").$type().notNull(),
5239
+ options: jsonb("options").$type().notNull().default([]),
5240
+ scope: rsvpQuestionScope("scope").notNull().default("household"),
5241
+ eventKey: text("event_key"),
5242
+ required: boolean("required").notNull().default(false),
5243
+ sort: integer("sort").notNull().default(0),
5244
+ showIf: jsonb("show_if").$type().notNull().default([]),
5245
+ preset: text("preset"),
5246
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5247
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5248
+ }, (t) => [index("rsvp_questions_list_idx").on(t.guestListId)]);
5249
+ var rsvpAnswers = pgTable("rsvp_answers", {
5250
+ id: text("id").primaryKey(),
5251
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
5252
+ guestListId: text("guest_list_id").notNull().references(() => guestLists.id, { onDelete: "cascade" }),
5253
+ questionId: text("question_id").notNull().references(() => rsvpQuestions.id, { onDelete: "cascade" }),
5254
+ householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
5255
+ guestId: text("guest_id").references(() => guests.id, { onDelete: "cascade" }),
5256
+ value: jsonb("value").$type().notNull(),
5257
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5258
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5259
+ }, (t) => [
5260
+ unique("rsvp_answers_uniq").on(t.questionId, t.householdId, t.guestId).nullsNotDistinct(),
5261
+ index("rsvp_answers_list_idx").on(t.guestListId)
5262
+ ]);
5263
+
5224
5264
  // ../../packages/schema/src/db/calendar.ts
5225
5265
  var calendarLinkPurpose = pgEnum("calendar_link_purpose", ["block", "deadline"]);
5226
5266
  var calendarEventLinks = pgTable("calendar_event_links", {
@@ -20590,7 +20630,13 @@ var METRICS = {
20590
20630
  bedtime: { label: "Bedtime", unit: "clock", min: 0, max: 720, step: 5 }
20591
20631
  };
20592
20632
  var metricKeySchema = _enum2(["weight", "sleep", "mood", "rating", "energy", "bedtime"]);
20593
- var metricSourceSchema = _enum2(["manual", "device", "agent", "google_fit"]);
20633
+ var metricSourceSchema = _enum2([
20634
+ "manual",
20635
+ "device",
20636
+ "agent",
20637
+ "google_fit",
20638
+ "google_health"
20639
+ ]);
20594
20640
  var loggedMetricSourceSchema = _enum2(["manual", "device", "agent"]);
20595
20641
  var metricPointSchema = object({
20596
20642
  day: string2(),
@@ -20614,7 +20660,7 @@ var sessionSchema = object({
20614
20660
  sport: string2(),
20615
20661
  name: string2().nullable(),
20616
20662
  minutes: number2().nullable(),
20617
- source: _enum2(["google_fit", "strava"])
20663
+ source: _enum2(["google_fit", "google_health", "strava"])
20618
20664
  });
20619
20665
  var sessionsQuerySchema = object({
20620
20666
  days: exports_coerce.number().int().min(1).max(365).default(14)
@@ -22801,6 +22847,65 @@ var journalMilestoneListSchema = object({
22801
22847
  milestones: array(journalMilestoneSchema)
22802
22848
  });
22803
22849
 
22850
+ // ../../packages/schema/src/contracts/journal-recall.ts
22851
+ var JOURNAL_RECALL_LIMIT = 30;
22852
+ var JOURNAL_RECALL_MAX_DAYS = 366;
22853
+ var daysBetween = (from, to) => (Date.parse(`${to}T00:00:00Z`) - Date.parse(`${from}T00:00:00Z`)) / 86400000;
22854
+ var journalRecallQuerySchema = object({
22855
+ q: string2().trim().min(2, "search for at least 2 characters").max(100).optional(),
22856
+ around: journalDateSchema.optional(),
22857
+ from: journalDateSchema.optional(),
22858
+ to: journalDateSchema.optional(),
22859
+ limit: exports_coerce.number().int().min(1).max(JOURNAL_RECALL_LIMIT).optional()
22860
+ }).strict().refine((q) => !(q.around && (q.from || q.to)), {
22861
+ message: "give around, or from and to, not both",
22862
+ path: ["around"]
22863
+ }).refine((q) => !q.from || !q.to || q.from <= q.to, {
22864
+ message: "from must be on or before to",
22865
+ path: ["to"]
22866
+ }).refine((q) => !q.from || !q.to || daysBetween(q.from, q.to) < JOURNAL_RECALL_MAX_DAYS, {
22867
+ message: `a recall covers at most ${JOURNAL_RECALL_MAX_DAYS} days`,
22868
+ path: ["to"]
22869
+ });
22870
+ var journalRecallMilestoneSchema = object({
22871
+ id: string2(),
22872
+ title: string2(),
22873
+ kind: journalMilestoneKindSchema,
22874
+ happenedOn: journalDateSchema,
22875
+ precision: journalMilestonePrecisionSchema,
22876
+ planned: boolean3()
22877
+ });
22878
+ var journalRecallEarlierSchema = object({
22879
+ date: journalDateSchema,
22880
+ yearsAgo: number2().int().positive(),
22881
+ title: string2().nullable(),
22882
+ rating: number2().nullable()
22883
+ });
22884
+ var journalRecallSchema = object({
22885
+ q: string2().nullable(),
22886
+ from: journalDateSchema.nullable(),
22887
+ to: journalDateSchema.nullable(),
22888
+ timezone: string2().min(1),
22889
+ days: array(journalDayListItemSchema).max(JOURNAL_RECALL_LIMIT),
22890
+ rated: number2().int().nonnegative(),
22891
+ average: number2().nullable(),
22892
+ milestones: array(journalRecallMilestoneSchema),
22893
+ earlier: array(journalRecallEarlierSchema)
22894
+ });
22895
+ var journalDigestDaySchema = object({
22896
+ date: journalDateSchema,
22897
+ title: string2().nullable(),
22898
+ rating: number2().nullable()
22899
+ });
22900
+ var journalDigestSchema = object({
22901
+ from: journalDateSchema,
22902
+ to: journalDateSchema,
22903
+ timezone: string2().min(1),
22904
+ days: array(journalDigestDaySchema),
22905
+ milestones: array(journalRecallMilestoneSchema),
22906
+ text: string2()
22907
+ });
22908
+
22804
22909
  // ../../packages/schema/src/contracts/journal-recap.ts
22805
22910
  var journalWeekKeySchema = string2().regex(/^\d{4}-W(0[1-9]|[1-4]\d|5[0-3])$/, "must be an ISO week (YYYY-Www)");
22806
22911
  var JOURNAL_MOMENTS_MAX = 3;
@@ -27235,6 +27340,10 @@ var mailFooterSchema = object({
27235
27340
  deleteBy: keyDateDaySchema.optional(),
27236
27341
  contact: email2().max(320).optional()
27237
27342
  }).strict();
27343
+ var mailLookShape = {
27344
+ couple: string2().trim().min(1).max(120).optional(),
27345
+ imagesUrl: url({ protocol: /^https$/ }).max(500).optional()
27346
+ };
27238
27347
  var lineSchema = string2().trim().min(1).max(2000);
27239
27348
  var mailMessageCopySchema = object({
27240
27349
  subject: string2().trim().min(1).max(200),
@@ -27245,6 +27354,7 @@ var mailMessageCopySchema = object({
27245
27354
  var mailMessageDataSchema = object({
27246
27355
  nl: mailMessageCopySchema,
27247
27356
  pt: mailMessageCopySchema.optional(),
27357
+ ...mailLookShape,
27248
27358
  footer: mailFooterSchema.optional()
27249
27359
  }).strict();
27250
27360
  var mailDaySchema = object({
@@ -27266,9 +27376,37 @@ var mailSaveTheDateDataSchema = object({
27266
27376
  pt: mailSaveTheDateCopySchema.optional(),
27267
27377
  days: array(mailDaySchema).min(1).max(5),
27268
27378
  calendarTitle: string2().trim().min(1).max(120).optional(),
27379
+ ...mailLookShape,
27269
27380
  footer: mailFooterSchema.optional()
27270
27381
  }).strict();
27271
27382
  var mailSaveTheDateDeliverySchema = object({ link: url().optional() }).strict();
27383
+ var mailProgrammeItemSchema = object({
27384
+ date: keyDateDaySchema.optional(),
27385
+ time: string2().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "time is HH:MM"),
27386
+ label: mailDaySchema.shape.label,
27387
+ place: string2().trim().min(1).max(200).optional()
27388
+ }).strict();
27389
+ var laterMailShape = {
27390
+ nl: mailSaveTheDateCopySchema,
27391
+ pt: mailSaveTheDateCopySchema.optional(),
27392
+ days: array(mailDaySchema).min(1).max(5),
27393
+ ...mailLookShape,
27394
+ footer: mailFooterSchema.optional()
27395
+ };
27396
+ var mailInvitationDataSchema = object({
27397
+ ...laterMailShape,
27398
+ programme: array(mailProgrammeItemSchema).max(12).optional(),
27399
+ rsvpBy: keyDateDaySchema.optional(),
27400
+ calendarTitle: string2().trim().min(1).max(120).optional()
27401
+ }).strict();
27402
+ var mailReminderDataSchema = object({ ...laterMailShape, rsvpBy: keyDateDaySchema }).strict();
27403
+ var mailFinalInfoDataSchema = object({ ...laterMailShape, programme: array(mailProgrammeItemSchema).max(12).optional() }).strict();
27404
+ var mailHouseholdDeliverySchema = object({
27405
+ link: url().optional(),
27406
+ household: string2().trim().min(1).max(200).optional(),
27407
+ programme: array(mailProgrammeItemSchema).max(12).optional(),
27408
+ table: string2().trim().min(1).max(120).optional()
27409
+ }).strict();
27272
27410
  var mailProviderEventSchema = looseObject({
27273
27411
  type: string2().min(1),
27274
27412
  created_at: string2().optional(),
@@ -27283,11 +27421,20 @@ var mailProviderEventSchema = looseObject({
27283
27421
  });
27284
27422
  var MAIL_CAMPAIGN_KINDS = ["message", "save_the_date", "invitation"];
27285
27423
  var mailCampaignKindSchema = _enum2(MAIL_CAMPAIGN_KINDS);
27286
- var MAIL_TEMPLATES = ["message", "save_the_date"];
27424
+ var MAIL_TEMPLATES = [
27425
+ "message",
27426
+ "save_the_date",
27427
+ "invitation",
27428
+ "reminder",
27429
+ "final_info"
27430
+ ];
27287
27431
  var mailTemplateSchema = _enum2(MAIL_TEMPLATES);
27288
27432
  var mailTemplateDataSchemas = {
27289
27433
  message: mailMessageDataSchema,
27290
- save_the_date: mailSaveTheDateDataSchema
27434
+ save_the_date: mailSaveTheDateDataSchema,
27435
+ invitation: mailInvitationDataSchema,
27436
+ reminder: mailReminderDataSchema,
27437
+ final_info: mailFinalInfoDataSchema
27291
27438
  };
27292
27439
  function mailTemplateDataError(template, data) {
27293
27440
  const parsed = mailTemplateDataSchemas[template].safeParse(data);
@@ -27343,6 +27490,100 @@ var mailCampaignViewSchema = mailCampaignSchema.extend({
27343
27490
  readyToSend: boolean3()
27344
27491
  });
27345
27492
 
27493
+ // ../../packages/schema/src/contracts/rsvp-questions.ts
27494
+ var RSVP_QUESTION_KINDS = ["choice", "multi", "text", "number", "yes_no"];
27495
+ var rsvpQuestionKindSchema = _enum2(RSVP_QUESTION_KINDS);
27496
+ var rsvpQuestionScopeSchema = _enum2(["household", "guest"]);
27497
+ var RSVP_QUESTION_PRESETS = ["diet", "message"];
27498
+ var rsvpQuestionPresetSchema = _enum2(RSVP_QUESTION_PRESETS);
27499
+ var RSVP_SHOW_IF_MAX = 5;
27500
+ var rsvpTextSchema = (max) => object({
27501
+ nl: string2().trim().min(1).max(max).optional(),
27502
+ pt: string2().trim().min(1).max(max).optional()
27503
+ }).strict().refine((t) => t.nl !== undefined || t.pt !== undefined, "give it in NL or PT");
27504
+ var keySchema = string2().regex(/^[a-z][a-z0-9_]{0,31}$/, "expected a short lower-case word (vegan, civil)");
27505
+ var rsvpQuestionOptionSchema = object({ key: keySchema, label: rsvpTextSchema(120) }).strict();
27506
+ var rsvpShowIfConditionSchema = union([
27507
+ object({
27508
+ questionId: ulidSchema,
27509
+ equals: union([string2().max(200), number2(), boolean3()])
27510
+ }).strict(),
27511
+ object({ eventKey: keySchema.optional(), rsvp: literal("yes") }).strict()
27512
+ ]);
27513
+ var rsvpAnswerValueSchema = union([
27514
+ string2().max(2000),
27515
+ array(string2().max(32)).max(20),
27516
+ number2(),
27517
+ boolean3()
27518
+ ]);
27519
+ var rsvpQuestionSchema = createSelectSchema(rsvpQuestions, {
27520
+ label: object({ nl: string2().optional(), pt: string2().optional() }),
27521
+ options: array(object({
27522
+ key: string2(),
27523
+ label: object({ nl: string2().optional(), pt: string2().optional() })
27524
+ })),
27525
+ showIf: array(rsvpShowIfConditionSchema),
27526
+ preset: rsvpQuestionPresetSchema.nullable(),
27527
+ createdAt: exports_coerce.date(),
27528
+ updatedAt: exports_coerce.date()
27529
+ });
27530
+ var rsvpAnswerSchema = createSelectSchema(rsvpAnswers, {
27531
+ value: rsvpAnswerValueSchema,
27532
+ createdAt: exports_coerce.date(),
27533
+ updatedAt: exports_coerce.date()
27534
+ });
27535
+ function rsvpOptionsProblem(kind, options) {
27536
+ if (kind === "choice" || kind === "multi") {
27537
+ if (options.length < 2)
27538
+ return `a ${kind} question needs two options or more`;
27539
+ if (new Set(options.map((o) => o.key)).size !== options.length)
27540
+ return "each option needs its own key";
27541
+ return null;
27542
+ }
27543
+ return options.length > 0 ? `a ${kind} question has no options` : null;
27544
+ }
27545
+ var questionFields = {
27546
+ label: rsvpTextSchema(300),
27547
+ options: array(rsvpQuestionOptionSchema).max(30).optional(),
27548
+ scope: rsvpQuestionScopeSchema.optional(),
27549
+ eventKey: keySchema.nullish(),
27550
+ required: boolean3().optional(),
27551
+ sort: number2().int().min(0).max(1e4).optional(),
27552
+ showIf: array(rsvpShowIfConditionSchema).max(RSVP_SHOW_IF_MAX).optional()
27553
+ };
27554
+ var createRsvpQuestionInputSchema = object({
27555
+ id: ulidSchema,
27556
+ guestListId: ulidSchema,
27557
+ kind: rsvpQuestionKindSchema,
27558
+ ...questionFields
27559
+ }).strict().superRefine((q, ctx) => {
27560
+ const problem = rsvpOptionsProblem(q.kind, q.options ?? []);
27561
+ if (problem)
27562
+ ctx.addIssue({ code: "custom", message: problem, path: ["options"] });
27563
+ if (q.showIf?.some((c) => ("questionId" in c) && c.questionId === q.id))
27564
+ ctx.addIssue({
27565
+ code: "custom",
27566
+ message: "a question can't depend on itself",
27567
+ path: ["showIf"]
27568
+ });
27569
+ });
27570
+ var updateRsvpQuestionInputSchema = object(questionFields).partial().strict();
27571
+ var rsvpQuestionsQuerySchema = object({ guestListId: ulidSchema });
27572
+ var rsvpAnswerInputSchema = object({
27573
+ questionId: ulidSchema,
27574
+ guestId: ulidSchema.nullish(),
27575
+ value: rsvpAnswerValueSchema.nullable()
27576
+ }).strict();
27577
+ var setRsvpAnswersInputSchema = object({
27578
+ guestListId: ulidSchema,
27579
+ householdId: ulidSchema,
27580
+ answers: array(rsvpAnswerInputSchema).min(1).max(200)
27581
+ }).strict();
27582
+ var rsvpAnswersQuerySchema = object({
27583
+ guestListId: ulidSchema,
27584
+ householdId: ulidSchema.optional()
27585
+ });
27586
+
27346
27587
  // ../../packages/schema/src/contracts/calendar.ts
27347
27588
  var calendarEventLinkSchema = createSelectSchema(calendarEventLinks, {
27348
27589
  createdAt: exports_coerce.date(),
@@ -28935,7 +29176,7 @@ function parseCapture2(input, now) {
28935
29176
 
28936
29177
  // src/meta.ts
28937
29178
  var CLI_NAME = "do";
28938
- var VERSION = "1.295.0";
29179
+ var VERSION = "1.296.0";
28939
29180
  var API_PREFIX = "/api/v1";
28940
29181
  var DEFAULT_API_URL = "http://localhost:3001";
28941
29182
 
@@ -29686,6 +29927,24 @@ var ENTITIES = [
29686
29927
  canDelete: true
29687
29928
  }
29688
29929
  },
29930
+ {
29931
+ name: "rsvp-questions",
29932
+ path: "/rsvp-questions",
29933
+ readScope: "contacts:read",
29934
+ returns: "RsvpQuestion",
29935
+ canGet: true,
29936
+ listFlags: [
29937
+ { name: "list", description: "the guest list's id (required)", query: "guestListId" }
29938
+ ],
29939
+ write: {
29940
+ scope: "contacts:write",
29941
+ createSchema: createRsvpQuestionInputSchema,
29942
+ createInput: "CreateRsvpQuestionInput",
29943
+ updateSchema: updateRsvpQuestionInputSchema,
29944
+ updateInput: "UpdateRsvpQuestionInput",
29945
+ canDelete: true
29946
+ }
29947
+ },
29689
29948
  {
29690
29949
  name: "guests",
29691
29950
  path: "/guests",
@@ -30401,6 +30660,24 @@ var HEALTH_COMMAND_SPECS = [
30401
30660
  scopes: READ,
30402
30661
  returns: "HealthLabOverview"
30403
30662
  },
30663
+ {
30664
+ path: ["health", "google", "status"],
30665
+ summary: "Whether your Google Health is connected, the last sync, and what stops it.",
30666
+ args: [],
30667
+ flags: [],
30668
+ scopes: READ,
30669
+ returns: "GoogleHealthStatus",
30670
+ notes: "GET /api/v1/health/google-health. Connecting needs Google's consent in a browser: Settings \u2192 Health in do. `failure` (reauth, not_linked, unavailable, other) says what stops the sync, with a title and a hint."
30671
+ },
30672
+ {
30673
+ path: ["health", "google", "sync"],
30674
+ summary: "Sync your Google Health now (sleep, resting heart rate, HRV, steps, workouts), as the morning sync does.",
30675
+ args: [],
30676
+ flags: [],
30677
+ scopes: WRITE2,
30678
+ returns: "GoogleHealthSyncResult",
30679
+ notes: "POST /api/v1/health/google-health/sync. Written and skipped per resource, and the status after it; a sync that stops answers 200 with `status.failure`. 409 before Google Health is connected, 403 while the server has it switched off."
30680
+ },
30404
30681
  {
30405
30682
  path: ["health", "analyte"],
30406
30683
  summary: "One analyte's trend across draws (do health analyte vitamin_d).",
@@ -30787,6 +31064,33 @@ var COMMAND_SPECS = [
30787
31064
  returns: "JournalSearch",
30788
31065
  notes: "GET /api/v1/journal/search?q= \u2014 matches the one-liner, highlights, the summary and entries of your own days (at most 30). journal:read is a sensitive scope."
30789
31066
  },
31067
+ {
31068
+ path: ["journal", "recall"],
31069
+ summary: "Recall your Journal: the days that answer some words or a window (or the last 7 days), the milestones near them and the same date in earlier years.",
31070
+ args: [{ name: "words", required: false, description: "A topic to look for (2+ characters)." }],
31071
+ flags: [
31072
+ {
31073
+ name: "around",
31074
+ type: "string",
31075
+ description: "A day, YYYY-MM-DD: reads 3 days either side."
31076
+ },
31077
+ { name: "from", type: "string", description: "The window's first day, YYYY-MM-DD." },
31078
+ { name: "to", type: "string", description: "The window's last day, YYYY-MM-DD." },
31079
+ { name: "limit", type: "string", description: "At most this many days (1\u201330)." }
31080
+ ],
31081
+ scopes: ["journal:read"],
31082
+ returns: "JournalRecall",
31083
+ notes: "GET /api/v1/journal/recall (journal_recall) \u2014 your own days only, dated so an answer can cite them; another member's days never answer. --around can't be combined with --from/--to. journal:read is a sensitive scope."
31084
+ },
31085
+ {
31086
+ path: ["journal", "digest"],
31087
+ summary: "The last 7 days of your Journal as a short digest: each day's line and rating, and the milestones a week either side.",
31088
+ args: [],
31089
+ flags: [],
31090
+ scopes: ["journal:read"],
31091
+ returns: "JournalDigest",
31092
+ notes: "GET /api/v1/journal/digest \u2014 `text` is the few plain lines an agent keeps in its private session. journal:read is a sensitive scope."
31093
+ },
30790
31094
  {
30791
31095
  path: ["journal", "week"],
30792
31096
  summary: "One week of the Journal: its recap (prose, best moments, a pattern), its days, the usual rating and the numbers from Progress.",
@@ -34420,6 +34724,31 @@ var COMMAND_SPECS = [
34420
34724
  scopes: ["contacts:write"],
34421
34725
  returns: "GuestView"
34422
34726
  },
34727
+ {
34728
+ path: ["rsvp-answers", "list"],
34729
+ summary: "A guest list's answers to its RSVP questions, or one household's.",
34730
+ args: [],
34731
+ flags: [
34732
+ { name: "list", type: "string", description: "The guest list's id (required)." },
34733
+ { name: "household", type: "string", description: "Only this household's answers." }
34734
+ ],
34735
+ scopes: ["contacts:read"],
34736
+ returns: "RsvpAnswer"
34737
+ },
34738
+ {
34739
+ path: ["rsvp-answers", "set"],
34740
+ summary: "Set a household's RSVP answers (null clears one); an answer to a hidden question is dropped.",
34741
+ args: [],
34742
+ flags: [
34743
+ {
34744
+ name: "data",
34745
+ type: "string",
34746
+ description: 'JSON SetRsvpAnswersInput, e.g. {"guestListId":"01\u2026","householdId":"01\u2026","answers":[{"questionId":"01\u2026","value":true},{"questionId":"01\u2026","guestId":"01\u2026","value":["vegan"]}]}'
34747
+ }
34748
+ ],
34749
+ scopes: ["contacts:write"],
34750
+ returns: "RsvpAnswer"
34751
+ },
34423
34752
  {
34424
34753
  path: ["seating-proposals", "list"],
34425
34754
  summary: "A guest list's proposed seating plans, newest first.",
@@ -36042,6 +36371,33 @@ function renderJournalSearch(data, mode) {
36042
36371
  return paint(mode, "dim", "(no journal days mention that)");
36043
36372
  return renderJournalDays({ days: d.days }, mode);
36044
36373
  }
36374
+ function renderJournalRecall(data, mode) {
36375
+ const d = data;
36376
+ const head = [
36377
+ d.q ? `\u201C${d.q}\u201D` : null,
36378
+ d.from && d.to ? `${d.from} \u2013 ${d.to}` : null,
36379
+ d.average != null ? `avg ${d.average} over ${d.rated} rated` : null
36380
+ ].filter(Boolean).join(" \xB7 ");
36381
+ const out = head ? [paint(mode, "dim", head)] : [];
36382
+ out.push((d.days ?? []).length === 0 ? paint(mode, "dim", "(no journal day answers that)") : renderJournalDays({ days: d.days }, mode));
36383
+ if ((d.milestones ?? []).length > 0) {
36384
+ out.push("", paint(mode, "dim", "Milestones near"));
36385
+ for (const m of d.milestones ?? [])
36386
+ out.push(` \u25C6 ${m.title}${paint(mode, "dim", ` \xB7 ${m.happenedOn}${m.planned ? " (planned)" : ""}`)}`);
36387
+ }
36388
+ if ((d.earlier ?? []).length > 0) {
36389
+ out.push("", paint(mode, "dim", "On this day"));
36390
+ for (const e of d.earlier ?? []) {
36391
+ const rating = e.rating == null ? "" : paint(mode, "dim", ` ${e.rating}/10`);
36392
+ out.push(` ${e.date} ${e.title ?? paint(mode, "dim", "(no entry)")}${rating}`);
36393
+ }
36394
+ }
36395
+ return out.join(`
36396
+ `);
36397
+ }
36398
+ function renderJournalDigest(data) {
36399
+ return data.text ?? "";
36400
+ }
36045
36401
  function renderJournalImportScan(data, mode) {
36046
36402
  const d = data;
36047
36403
  const items = d.items;
@@ -37170,6 +37526,27 @@ var HANDLERS = {
37170
37526
  render: renderJournalSearch
37171
37527
  };
37172
37528
  },
37529
+ "journal recall": async ({ args, flags, requireClient }) => {
37530
+ const q = args.join(" ").trim() || undefined;
37531
+ if (q !== undefined && q.length < 2)
37532
+ throw usageError("journal recall needs 2+ characters");
37533
+ const query = {
37534
+ q,
37535
+ around: flagString(flags, "around"),
37536
+ from: flagString(flags, "from"),
37537
+ to: flagString(flags, "to"),
37538
+ limit: flagString(flags, "limit")
37539
+ };
37540
+ parseInput(journalRecallQuerySchema, Object.fromEntries(Object.entries(query).filter(([, v]) => v !== undefined)));
37541
+ return {
37542
+ data: await requireClient().get("/journal/recall", { query }),
37543
+ render: renderJournalRecall
37544
+ };
37545
+ },
37546
+ "journal digest": async ({ requireClient }) => ({
37547
+ data: await requireClient().get("/journal/digest"),
37548
+ render: renderJournalDigest
37549
+ }),
37173
37550
  "journal week": async ({ args, requireClient }) => {
37174
37551
  const week = journalWeekArg(args, "week");
37175
37552
  return {
@@ -39407,6 +39784,14 @@ var HANDLERS = {
39407
39784
  data: await requireClient().delete(`/health/shares/${requireArg(args, 0, "id")}`),
39408
39785
  render: renderRecord
39409
39786
  }),
39787
+ "health google status": async ({ requireClient }) => ({
39788
+ data: await requireClient().get("/health/google-health"),
39789
+ render: renderRecord
39790
+ }),
39791
+ "health google sync": async ({ requireClient }) => ({
39792
+ data: await requireClient().post("/health/google-health/sync", {}),
39793
+ render: renderRecord
39794
+ }),
39410
39795
  "health consent": async ({ requireClient }) => ({
39411
39796
  data: await requireClient().get("/health/consent"),
39412
39797
  render: renderRecord
@@ -39746,6 +40131,21 @@ var HANDLERS = {
39746
40131
  const body = parseInput(markGuestsSentInputSchema, readDataFlag(flags));
39747
40132
  return { data: await requireClient().post("/guests/sent", body), render: renderRecord };
39748
40133
  },
40134
+ "rsvp-answers list": async ({ flags, requireClient }) => {
40135
+ const list = flagString(flags, "list");
40136
+ if (!list)
40137
+ throw usageError("rsvp-answers list needs --list <guest list id>");
40138
+ const household = flagString(flags, "household");
40139
+ const query = parseInput(rsvpAnswersQuerySchema, {
40140
+ guestListId: list,
40141
+ ...household ? { householdId: household } : {}
40142
+ });
40143
+ return { data: await requireClient().get("/rsvp-answers", { query }), render: renderRecord };
40144
+ },
40145
+ "rsvp-answers set": async ({ flags, requireClient }) => {
40146
+ const body = parseInput(setRsvpAnswersInputSchema, readDataFlag(flags));
40147
+ return { data: await requireClient().put("/rsvp-answers", body), render: renderRecord };
40148
+ },
39749
40149
  "seating-proposals list": async ({ flags, requireClient }) => {
39750
40150
  const list = flagString(flags, "list");
39751
40151
  if (!list)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.295.0",
3
+ "version": "1.296.0",
4
4
  "private": false,
5
5
  "description": "do — the agent-drivable CLI over the public /api/v1 surface",
6
6
  "homepage": "https://github.com/robbeverhelst/do/tree/main/apps/cli",