@robbeverhelst/do 1.300.0 → 1.301.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 +267 -172
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -4438,6 +4438,20 @@ var documents = pgTable("documents", {
4438
4438
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
4439
4439
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
4440
4440
  }, (t) => [index("documents_tenant_kind_idx").on(t.tenantId, t.kind)]);
4441
+ var paperShares = pgTable("paper_shares", {
4442
+ id: text("id").primaryKey(),
4443
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
4444
+ userId: text("user_id").notNull().references(() => users.id),
4445
+ label: text("label").notNull(),
4446
+ nodeIds: text("node_ids").array().notNull().default(sql`'{}'::text[]`),
4447
+ snapshot: jsonb("snapshot").notNull(),
4448
+ tokenHash: text("token_hash").notNull().unique(),
4449
+ expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
4450
+ revokedAt: timestamp("revoked_at", { withTimezone: true }),
4451
+ opens: integer("opens").notNull().default(0),
4452
+ lastOpenedAt: timestamp("last_opened_at", { withTimezone: true }),
4453
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
4454
+ }, (t) => [index("paper_shares_user_idx").on(t.tenantId, t.userId, t.createdAt)]);
4441
4455
 
4442
4456
  // ../../packages/schema/src/db/incidents.ts
4443
4457
  var incidentKind = pgEnum("incident_kind", [
@@ -22455,6 +22469,28 @@ var houseUpkeepYearSchema = object({
22455
22469
  });
22456
22470
  var houseUpkeepYearQuerySchema = object({ year: exports_coerce.number().int().min(2000).max(2100).optional() }).strict();
22457
22471
 
22472
+ // ../../packages/schema/src/receipt-kinds.ts
22473
+ var MONEY_RECEIPT_NODE_TYPE = "money_transaction";
22474
+ var RECEIPT_KINDS = {
22475
+ document: { about: [] },
22476
+ health_episode: { about: ["red_flags"] },
22477
+ journal_day: { about: ["saved"] },
22478
+ time_block: { about: [] },
22479
+ meal_log: { about: [] },
22480
+ collection_item: { about: [] },
22481
+ person_note: { about: [] },
22482
+ health_encounter: { about: [] },
22483
+ animal: { about: ["vet_visit"] },
22484
+ [MONEY_RECEIPT_NODE_TYPE]: { about: ["ask", "bill"] },
22485
+ planning_rule: { about: [] }
22486
+ };
22487
+ var NODE_RECEIPT_ABOUT_VALUES = [
22488
+ ...RECEIPT_KINDS.health_episode.about,
22489
+ ...RECEIPT_KINDS.journal_day.about,
22490
+ ...RECEIPT_KINDS.animal.about
22491
+ ];
22492
+ var MONEY_RECEIPT_ABOUT_VALUES = RECEIPT_KINDS[MONEY_RECEIPT_NODE_TYPE].about;
22493
+
22458
22494
  // ../../packages/schema/src/contracts/agent-chat.ts
22459
22495
  var agentConnectionSourceSchema = _enum2(["space", "env"]);
22460
22496
  var agentGatewayStatusSchema = _enum2(["connected", "offline", "not_connected"]);
@@ -22691,7 +22727,7 @@ var postRunSchema = object({
22691
22727
  status: runStatusSchema,
22692
22728
  steps: array(runStepSchema).max(12).optional()
22693
22729
  });
22694
- var POST_RECEIPT_ABOUT_VALUES = ["red_flags", "saved", "vet_visit"];
22730
+ var POST_RECEIPT_ABOUT_VALUES = NODE_RECEIPT_ABOUT_VALUES;
22695
22731
  var POST_RECEIPT_SOURCE_MAX = 80;
22696
22732
  var postNodeReceiptInputSchema = object({
22697
22733
  nodeId: ulidSchema,
@@ -22700,7 +22736,7 @@ var postNodeReceiptInputSchema = object({
22700
22736
  source: string2().trim().min(1).max(POST_RECEIPT_SOURCE_MAX).optional(),
22701
22737
  personNotes: array(ulidSchema).min(1).max(10).optional()
22702
22738
  }).strict();
22703
- var POST_MONEY_RECEIPT_ABOUT_VALUES = ["ask", "bill"];
22739
+ var POST_MONEY_RECEIPT_ABOUT_VALUES = MONEY_RECEIPT_ABOUT_VALUES;
22704
22740
  var webUrlSchema = string2().url().max(2000).refine((url) => /^https?:\/\//i.test(url), "must be an http(s) link");
22705
22741
  var postMoneyReceiptInputSchema = object({
22706
22742
  transactionId: ulidSchema,
@@ -23615,6 +23651,20 @@ var journalSearchSchema = object({
23615
23651
  days: array(journalDayListItemSchema).max(JOURNAL_SEARCH_LIMIT),
23616
23652
  understood: journalSearchUnderstoodSchema.nullable().default(null)
23617
23653
  });
23654
+ var JOURNAL_LIKE_LIMIT = 10;
23655
+ var journalLikeQuerySchema = object({
23656
+ limit: exports_coerce.number().int().min(1).max(JOURNAL_LIKE_LIMIT).default(5)
23657
+ });
23658
+ var journalLikeDaySchema = journalDayListItemSchema.extend({
23659
+ shared: array(string2()),
23660
+ sharedTags: array(string2())
23661
+ });
23662
+ var journalLikeSchema = object({
23663
+ date: journalDateSchema,
23664
+ timezone: string2().min(1),
23665
+ words: array(string2()),
23666
+ days: array(journalLikeDaySchema).max(JOURNAL_LIKE_LIMIT)
23667
+ });
23618
23668
  var journalLinkInputSchema = object({
23619
23669
  kind: string2().trim().regex(/^[a-z][a-z_]{0,31}$/, "a link kind is a short lowercase word"),
23620
23670
  nodeId: ulidSchema
@@ -27486,6 +27536,104 @@ var familyTreeMatchDecisionResultSchema = object({
27486
27536
  matches: array(familyTreeMatchViewSchema)
27487
27537
  });
27488
27538
 
27539
+ // ../../packages/schema/src/contracts/rsvp-questions.ts
27540
+ var RSVP_QUESTION_KINDS = ["choice", "multi", "text", "number", "yes_no"];
27541
+ var rsvpQuestionKindSchema = _enum2(RSVP_QUESTION_KINDS);
27542
+ var rsvpQuestionScopeSchema = _enum2(["household", "guest"]);
27543
+ var RSVP_QUESTION_PRESETS = ["diet", "diet_other", "message"];
27544
+ var rsvpQuestionPresetSchema = _enum2(RSVP_QUESTION_PRESETS);
27545
+ var RSVP_SHOW_IF_MAX = 5;
27546
+ var rsvpTextSchema = (max) => object({
27547
+ nl: string2().trim().min(1).max(max).optional(),
27548
+ pt: string2().trim().min(1).max(max).optional()
27549
+ }).strict().refine((t) => t.nl !== undefined || t.pt !== undefined, "give it in NL or PT");
27550
+ var keySchema = string2().regex(/^[a-z][a-z0-9_]{0,31}$/, "expected a short lower-case word (vegan, civil)");
27551
+ var rsvpQuestionOptionSchema = object({ key: keySchema, label: rsvpTextSchema(120) }).strict();
27552
+ var rsvpShowIfConditionSchema = union([
27553
+ object({
27554
+ questionId: ulidSchema,
27555
+ equals: union([string2().max(200), number2(), boolean3()])
27556
+ }).strict(),
27557
+ object({ eventKey: keySchema.optional(), rsvp: literal("yes") }).strict()
27558
+ ]);
27559
+ var rsvpAnswerValueSchema = union([
27560
+ string2().max(2000),
27561
+ array(string2().max(32)).max(20),
27562
+ number2(),
27563
+ boolean3()
27564
+ ]);
27565
+ var rsvpQuestionSchema = createSelectSchema(rsvpQuestions, {
27566
+ label: object({ nl: string2().optional(), pt: string2().optional() }),
27567
+ options: array(object({
27568
+ key: string2(),
27569
+ label: object({ nl: string2().optional(), pt: string2().optional() })
27570
+ })),
27571
+ showIf: array(rsvpShowIfConditionSchema),
27572
+ preset: rsvpQuestionPresetSchema.nullable(),
27573
+ createdAt: exports_coerce.date(),
27574
+ updatedAt: exports_coerce.date()
27575
+ });
27576
+ var rsvpAnswerSchema = createSelectSchema(rsvpAnswers, {
27577
+ value: rsvpAnswerValueSchema,
27578
+ createdAt: exports_coerce.date(),
27579
+ updatedAt: exports_coerce.date()
27580
+ });
27581
+ function rsvpOptionsProblem(kind, options) {
27582
+ if (kind === "choice" || kind === "multi") {
27583
+ if (options.length < 2)
27584
+ return `a ${kind} question needs two options or more`;
27585
+ if (new Set(options.map((o) => o.key)).size !== options.length)
27586
+ return "each option needs its own key";
27587
+ return null;
27588
+ }
27589
+ return options.length > 0 ? `a ${kind} question has no options` : null;
27590
+ }
27591
+ var questionFields = {
27592
+ label: rsvpTextSchema(300),
27593
+ options: array(rsvpQuestionOptionSchema).max(30).optional(),
27594
+ scope: rsvpQuestionScopeSchema.optional(),
27595
+ eventKey: keySchema.nullish(),
27596
+ required: boolean3().optional(),
27597
+ sort: number2().int().min(0).max(1e4).optional(),
27598
+ showIf: array(rsvpShowIfConditionSchema).max(RSVP_SHOW_IF_MAX).optional()
27599
+ };
27600
+ var createRsvpQuestionInputSchema = object({
27601
+ id: ulidSchema,
27602
+ guestListId: ulidSchema,
27603
+ kind: rsvpQuestionKindSchema,
27604
+ ...questionFields
27605
+ }).strict().superRefine((q, ctx) => {
27606
+ const problem = rsvpOptionsProblem(q.kind, q.options ?? []);
27607
+ if (problem)
27608
+ ctx.addIssue({ code: "custom", message: problem, path: ["options"] });
27609
+ if (q.showIf?.some((c) => ("questionId" in c) && c.questionId === q.id))
27610
+ ctx.addIssue({
27611
+ code: "custom",
27612
+ message: "a question can't depend on itself",
27613
+ path: ["showIf"]
27614
+ });
27615
+ });
27616
+ var updateRsvpQuestionInputSchema = object(questionFields).partial().strict();
27617
+ var rsvpQuestionsQuerySchema = object({ guestListId: ulidSchema });
27618
+ var rsvpAnswerInputSchema = object({
27619
+ questionId: ulidSchema,
27620
+ guestId: ulidSchema.nullish(),
27621
+ value: rsvpAnswerValueSchema.nullable()
27622
+ }).strict();
27623
+ var setRsvpAnswersInputSchema = object({
27624
+ guestListId: ulidSchema,
27625
+ householdId: ulidSchema,
27626
+ answers: array(rsvpAnswerInputSchema).min(1).max(200)
27627
+ }).strict();
27628
+ var rsvpAnswersQuerySchema = object({
27629
+ guestListId: ulidSchema,
27630
+ householdId: ulidSchema.optional()
27631
+ });
27632
+ var addRsvpPresetsInputSchema = object({
27633
+ guestListId: ulidSchema,
27634
+ presets: array(_enum2(["diet", "message"])).min(1).max(2)
27635
+ }).strict();
27636
+
27489
27637
  // ../../packages/schema/src/contracts/guests.ts
27490
27638
  var guestAnswerSchema = _enum2(["yes", "no", "maybe"]);
27491
27639
  var guestStateSchema = _enum2(["yes", "no", "maybe", "waiting"]);
@@ -27711,10 +27859,10 @@ var submitRsvpInputSchema = object({
27711
27859
  email: string2().trim().email().max(254).nullish()
27712
27860
  }).strict()).max(30).default([]),
27713
27861
  address: householdAddressSchema.nullish(),
27714
- language: rsvpLanguageSchema.optional()
27715
- }).strict().refine((i) => i.guests.length > 0 || !!i.address || !!i.language, {
27716
- message: "nothing to send: answers, an address or a language"
27717
- });
27862
+ language: rsvpLanguageSchema.optional(),
27863
+ answers: array(rsvpAnswerInputSchema).max(200).optional(),
27864
+ dietConsent: boolean3().optional()
27865
+ }).strict().refine((i) => i.guests.length > 0 || (i.answers?.length ?? 0) > 0 || !!i.address || !!i.language, { message: "nothing to send: answers, an address or a language" });
27718
27866
  var eventTextSchema = (max) => object({
27719
27867
  nl: string2().trim().min(1).max(max).optional(),
27720
27868
  pt: string2().trim().min(1).max(max).optional()
@@ -27983,104 +28131,6 @@ var mailCampaignViewSchema = mailCampaignSchema.extend({
27983
28131
  readyToSend: boolean3()
27984
28132
  });
27985
28133
 
27986
- // ../../packages/schema/src/contracts/rsvp-questions.ts
27987
- var RSVP_QUESTION_KINDS = ["choice", "multi", "text", "number", "yes_no"];
27988
- var rsvpQuestionKindSchema = _enum2(RSVP_QUESTION_KINDS);
27989
- var rsvpQuestionScopeSchema = _enum2(["household", "guest"]);
27990
- var RSVP_QUESTION_PRESETS = ["diet", "diet_other", "message"];
27991
- var rsvpQuestionPresetSchema = _enum2(RSVP_QUESTION_PRESETS);
27992
- var RSVP_SHOW_IF_MAX = 5;
27993
- var rsvpTextSchema = (max) => object({
27994
- nl: string2().trim().min(1).max(max).optional(),
27995
- pt: string2().trim().min(1).max(max).optional()
27996
- }).strict().refine((t) => t.nl !== undefined || t.pt !== undefined, "give it in NL or PT");
27997
- var keySchema = string2().regex(/^[a-z][a-z0-9_]{0,31}$/, "expected a short lower-case word (vegan, civil)");
27998
- var rsvpQuestionOptionSchema = object({ key: keySchema, label: rsvpTextSchema(120) }).strict();
27999
- var rsvpShowIfConditionSchema = union([
28000
- object({
28001
- questionId: ulidSchema,
28002
- equals: union([string2().max(200), number2(), boolean3()])
28003
- }).strict(),
28004
- object({ eventKey: keySchema.optional(), rsvp: literal("yes") }).strict()
28005
- ]);
28006
- var rsvpAnswerValueSchema = union([
28007
- string2().max(2000),
28008
- array(string2().max(32)).max(20),
28009
- number2(),
28010
- boolean3()
28011
- ]);
28012
- var rsvpQuestionSchema = createSelectSchema(rsvpQuestions, {
28013
- label: object({ nl: string2().optional(), pt: string2().optional() }),
28014
- options: array(object({
28015
- key: string2(),
28016
- label: object({ nl: string2().optional(), pt: string2().optional() })
28017
- })),
28018
- showIf: array(rsvpShowIfConditionSchema),
28019
- preset: rsvpQuestionPresetSchema.nullable(),
28020
- createdAt: exports_coerce.date(),
28021
- updatedAt: exports_coerce.date()
28022
- });
28023
- var rsvpAnswerSchema = createSelectSchema(rsvpAnswers, {
28024
- value: rsvpAnswerValueSchema,
28025
- createdAt: exports_coerce.date(),
28026
- updatedAt: exports_coerce.date()
28027
- });
28028
- function rsvpOptionsProblem(kind, options) {
28029
- if (kind === "choice" || kind === "multi") {
28030
- if (options.length < 2)
28031
- return `a ${kind} question needs two options or more`;
28032
- if (new Set(options.map((o) => o.key)).size !== options.length)
28033
- return "each option needs its own key";
28034
- return null;
28035
- }
28036
- return options.length > 0 ? `a ${kind} question has no options` : null;
28037
- }
28038
- var questionFields = {
28039
- label: rsvpTextSchema(300),
28040
- options: array(rsvpQuestionOptionSchema).max(30).optional(),
28041
- scope: rsvpQuestionScopeSchema.optional(),
28042
- eventKey: keySchema.nullish(),
28043
- required: boolean3().optional(),
28044
- sort: number2().int().min(0).max(1e4).optional(),
28045
- showIf: array(rsvpShowIfConditionSchema).max(RSVP_SHOW_IF_MAX).optional()
28046
- };
28047
- var createRsvpQuestionInputSchema = object({
28048
- id: ulidSchema,
28049
- guestListId: ulidSchema,
28050
- kind: rsvpQuestionKindSchema,
28051
- ...questionFields
28052
- }).strict().superRefine((q, ctx) => {
28053
- const problem = rsvpOptionsProblem(q.kind, q.options ?? []);
28054
- if (problem)
28055
- ctx.addIssue({ code: "custom", message: problem, path: ["options"] });
28056
- if (q.showIf?.some((c) => ("questionId" in c) && c.questionId === q.id))
28057
- ctx.addIssue({
28058
- code: "custom",
28059
- message: "a question can't depend on itself",
28060
- path: ["showIf"]
28061
- });
28062
- });
28063
- var updateRsvpQuestionInputSchema = object(questionFields).partial().strict();
28064
- var rsvpQuestionsQuerySchema = object({ guestListId: ulidSchema });
28065
- var rsvpAnswerInputSchema = object({
28066
- questionId: ulidSchema,
28067
- guestId: ulidSchema.nullish(),
28068
- value: rsvpAnswerValueSchema.nullable()
28069
- }).strict();
28070
- var setRsvpAnswersInputSchema = object({
28071
- guestListId: ulidSchema,
28072
- householdId: ulidSchema,
28073
- answers: array(rsvpAnswerInputSchema).min(1).max(200)
28074
- }).strict();
28075
- var rsvpAnswersQuerySchema = object({
28076
- guestListId: ulidSchema,
28077
- householdId: ulidSchema.optional()
28078
- });
28079
- var addRsvpPresetsInputSchema = object({
28080
- guestListId: ulidSchema,
28081
- presets: array(_enum2(["diet", "message"])).min(1).max(2)
28082
- }).strict();
28083
-
28084
28134
  // ../../packages/schema/src/contracts/google-contacts.ts
28085
28135
  var googleContactsModeSchema = _enum2(["off", "fake", "live"]);
28086
28136
  var googleContactsStatusSchema = object({
@@ -29766,7 +29816,7 @@ function parseCapture2(input, now) {
29766
29816
 
29767
29817
  // src/meta.ts
29768
29818
  var CLI_NAME = "do";
29769
- var VERSION = "1.300.0";
29819
+ var VERSION = "1.301.0";
29770
29820
  var API_PREFIX = "/api/v1";
29771
29821
  var DEFAULT_API_URL = "http://localhost:3001";
29772
29822
 
@@ -30156,7 +30206,7 @@ var ENTITIES = [
30156
30206
  {
30157
30207
  name: "tasks",
30158
30208
  path: "/tasks",
30159
- readScope: "tasks:read",
30209
+ readScopes: ["tasks:read"],
30160
30210
  returns: "Task",
30161
30211
  canGet: true,
30162
30212
  listFlags: [
@@ -30201,7 +30251,7 @@ var ENTITIES = [
30201
30251
  }
30202
30252
  ],
30203
30253
  write: {
30204
- scope: "tasks:write",
30254
+ scopes: ["tasks:write"],
30205
30255
  createSchema: createTaskInputSchema,
30206
30256
  createInput: "CreateTaskInput",
30207
30257
  updateSchema: updateTaskInputSchema,
@@ -30212,7 +30262,7 @@ var ENTITIES = [
30212
30262
  {
30213
30263
  name: "habits",
30214
30264
  path: "/habits",
30215
- readScope: "habits:read",
30265
+ readScopes: ["habits:read"],
30216
30266
  returns: "HabitSummary",
30217
30267
  canGet: true,
30218
30268
  listFlags: [
@@ -30224,7 +30274,7 @@ var ENTITIES = [
30224
30274
  }
30225
30275
  ],
30226
30276
  write: {
30227
- scope: "habits:write",
30277
+ scopes: ["habits:write"],
30228
30278
  createSchema: createHabitInputSchema,
30229
30279
  createInput: "CreateHabitInput",
30230
30280
  updateSchema: updateHabitInputSchema,
@@ -30235,7 +30285,7 @@ var ENTITIES = [
30235
30285
  {
30236
30286
  name: "projects",
30237
30287
  path: "/projects",
30238
- readScope: "projects:read",
30288
+ readScopes: ["projects:read"],
30239
30289
  returns: "ProjectView",
30240
30290
  canGet: true,
30241
30291
  listFlags: [
@@ -30248,7 +30298,7 @@ var ENTITIES = [
30248
30298
  DUE_BEFORE_FLAG
30249
30299
  ],
30250
30300
  write: {
30251
- scope: "projects:write",
30301
+ scopes: ["projects:write"],
30252
30302
  createSchema: createProjectInputSchema,
30253
30303
  createInput: "CreateProjectInput",
30254
30304
  updateSchema: updateProjectInputSchema,
@@ -30259,7 +30309,7 @@ var ENTITIES = [
30259
30309
  {
30260
30310
  name: "areas",
30261
30311
  path: "/areas",
30262
- readScope: "areas:read",
30312
+ readScopes: ["areas:read"],
30263
30313
  returns: "AreaView",
30264
30314
  canGet: true,
30265
30315
  listFlags: [
@@ -30272,7 +30322,7 @@ var ENTITIES = [
30272
30322
  { name: "archived", description: "only archived areas", query: "archived", sends: "true" }
30273
30323
  ],
30274
30324
  write: {
30275
- scope: "areas:write",
30325
+ scopes: ["areas:write"],
30276
30326
  createSchema: createAreaInputSchema,
30277
30327
  createInput: "CreateAreaInput",
30278
30328
  updateSchema: updateAreaInputSchema,
@@ -30283,12 +30333,12 @@ var ENTITIES = [
30283
30333
  {
30284
30334
  name: "places",
30285
30335
  path: "/places",
30286
- readScope: "places:read",
30336
+ readScopes: ["places:read"],
30287
30337
  returns: "PlaceView",
30288
30338
  canGet: true,
30289
30339
  listFlags: [],
30290
30340
  write: {
30291
- scope: "places:write",
30341
+ scopes: ["places:write"],
30292
30342
  createSchema: createPlaceInputSchema,
30293
30343
  createInput: "CreatePlaceInput",
30294
30344
  updateSchema: updatePlaceInputSchema,
@@ -30299,12 +30349,12 @@ var ENTITIES = [
30299
30349
  {
30300
30350
  name: "routines",
30301
30351
  path: "/routines",
30302
- readScope: "routines:read",
30352
+ readScopes: ["routines:read"],
30303
30353
  returns: "RoutineView",
30304
30354
  canGet: true,
30305
30355
  listFlags: [],
30306
30356
  write: {
30307
- scope: "routines:write",
30357
+ scopes: ["routines:write"],
30308
30358
  createSchema: createRoutineInputSchema,
30309
30359
  createInput: "CreateRoutineInput",
30310
30360
  updateSchema: updateRoutineInputSchema,
@@ -30315,7 +30365,7 @@ var ENTITIES = [
30315
30365
  {
30316
30366
  name: "notes",
30317
30367
  path: "/notes",
30318
- readScope: "notes:read",
30368
+ readScopes: ["notes:read"],
30319
30369
  returns: "Note",
30320
30370
  canGet: true,
30321
30371
  listFlags: [
@@ -30324,7 +30374,7 @@ var ENTITIES = [
30324
30374
  { name: "tag", description: "filter to notes carrying this tag", query: "tag" }
30325
30375
  ],
30326
30376
  write: {
30327
- scope: "notes:write",
30377
+ scopes: ["notes:write"],
30328
30378
  createSchema: createNoteInputSchema,
30329
30379
  createInput: "CreateNoteInput",
30330
30380
  updateSchema: updateNoteInputSchema,
@@ -30335,7 +30385,7 @@ var ENTITIES = [
30335
30385
  {
30336
30386
  name: "contacts",
30337
30387
  path: "/contacts",
30338
- readScope: "contacts:read",
30388
+ readScopes: ["contacts:read"],
30339
30389
  returns: "Contact",
30340
30390
  canGet: true,
30341
30391
  listFlags: [
@@ -30353,7 +30403,7 @@ var ENTITIES = [
30353
30403
  }
30354
30404
  ],
30355
30405
  write: {
30356
- scope: "contacts:write",
30406
+ scopes: ["contacts:write"],
30357
30407
  createSchema: createContactInputSchema,
30358
30408
  createInput: "CreateContactInput",
30359
30409
  updateSchema: updateContactInputSchema,
@@ -30364,7 +30414,7 @@ var ENTITIES = [
30364
30414
  {
30365
30415
  name: "contact-moments",
30366
30416
  path: "/contact-moments",
30367
- readScope: "contacts:read",
30417
+ readScopes: ["contacts:read"],
30368
30418
  returns: "ContactMomentView",
30369
30419
  canGet: true,
30370
30420
  listFlags: [
@@ -30375,7 +30425,7 @@ var ENTITIES = [
30375
30425
  { name: "limit", description: "at most this many, newest first", query: "limit" }
30376
30426
  ],
30377
30427
  write: {
30378
- scope: "contacts:write",
30428
+ scopes: ["contacts:write"],
30379
30429
  createSchema: createContactMomentInputSchema,
30380
30430
  createInput: "CreateContactMomentInput",
30381
30431
  updateSchema: updateContactMomentInputSchema,
@@ -30386,7 +30436,7 @@ var ENTITIES = [
30386
30436
  {
30387
30437
  name: "gift-ideas",
30388
30438
  path: "/gift-ideas",
30389
- readScope: "contacts:read",
30439
+ readScopes: ["contacts:read"],
30390
30440
  returns: "GiftIdeaView",
30391
30441
  canGet: true,
30392
30442
  listFlags: [
@@ -30403,7 +30453,7 @@ var ENTITIES = [
30403
30453
  }
30404
30454
  ],
30405
30455
  write: {
30406
- scope: "contacts:write",
30456
+ scopes: ["contacts:write"],
30407
30457
  createSchema: createGiftIdeaInputSchema,
30408
30458
  createInput: "CreateGiftIdeaInput",
30409
30459
  updateSchema: updateGiftIdeaInputSchema,
@@ -30414,12 +30464,12 @@ var ENTITIES = [
30414
30464
  {
30415
30465
  name: "circles",
30416
30466
  path: "/circles",
30417
- readScope: "contacts:read",
30467
+ readScopes: ["contacts:read"],
30418
30468
  returns: "CircleView",
30419
30469
  canGet: true,
30420
30470
  listFlags: [],
30421
30471
  write: {
30422
- scope: "contacts:write",
30472
+ scopes: ["contacts:write"],
30423
30473
  createSchema: createCircleInputSchema,
30424
30474
  createInput: "CreateCircleInput",
30425
30475
  updateSchema: updateCircleInputSchema,
@@ -30430,12 +30480,12 @@ var ENTITIES = [
30430
30480
  {
30431
30481
  name: "contact-relations",
30432
30482
  path: "/contact-relations",
30433
- readScope: "contacts:read",
30483
+ readScopes: ["contacts:read"],
30434
30484
  returns: "ContactRelation",
30435
30485
  canGet: true,
30436
30486
  listFlags: [{ name: "contact", description: "only this contact id", query: "contactId" }],
30437
30487
  write: {
30438
- scope: "contacts:write",
30488
+ scopes: ["contacts:write"],
30439
30489
  createSchema: createContactRelationInputSchema,
30440
30490
  createInput: "CreateContactRelationInput",
30441
30491
  updateSchema: updateContactRelationInputSchema,
@@ -30446,7 +30496,7 @@ var ENTITIES = [
30446
30496
  {
30447
30497
  name: "households",
30448
30498
  path: "/households",
30449
- readScope: "contacts:read",
30499
+ readScopes: ["contacts:read"],
30450
30500
  returns: "HouseholdView",
30451
30501
  canGet: true,
30452
30502
  listFlags: [
@@ -30457,7 +30507,7 @@ var ENTITIES = [
30457
30507
  }
30458
30508
  ],
30459
30509
  write: {
30460
- scope: "contacts:write",
30510
+ scopes: ["contacts:write"],
30461
30511
  createSchema: createHouseholdInputSchema,
30462
30512
  createInput: "CreateHouseholdInput",
30463
30513
  updateSchema: updateHouseholdInputSchema,
@@ -30468,12 +30518,12 @@ var ENTITIES = [
30468
30518
  {
30469
30519
  name: "guest-lists",
30470
30520
  path: "/guest-lists",
30471
- readScope: "contacts:read",
30521
+ readScopes: ["contacts:read"],
30472
30522
  returns: "GuestListView",
30473
30523
  canGet: true,
30474
30524
  listFlags: [{ name: "project", description: "only this project's list", query: "projectId" }],
30475
30525
  write: {
30476
- scope: "contacts:write",
30526
+ scopes: ["contacts:write"],
30477
30527
  createSchema: createGuestListInputSchema,
30478
30528
  createInput: "CreateGuestListInput",
30479
30529
  updateSchema: updateGuestListInputSchema,
@@ -30484,14 +30534,14 @@ var ENTITIES = [
30484
30534
  {
30485
30535
  name: "guest-list-events",
30486
30536
  path: "/guest-list-events",
30487
- readScope: "contacts:read",
30537
+ readScopes: ["contacts:read"],
30488
30538
  returns: "GuestListEvent",
30489
30539
  canGet: true,
30490
30540
  listFlags: [
30491
30541
  { name: "list", description: "the guest list's id (required)", query: "guestListId" }
30492
30542
  ],
30493
30543
  write: {
30494
- scope: "contacts:write",
30544
+ scopes: ["contacts:write"],
30495
30545
  createSchema: createGuestListEventInputSchema,
30496
30546
  createInput: "CreateGuestListEventInput",
30497
30547
  updateSchema: updateGuestListEventInputSchema,
@@ -30502,14 +30552,14 @@ var ENTITIES = [
30502
30552
  {
30503
30553
  name: "guest-tables",
30504
30554
  path: "/guest-tables",
30505
- readScope: "contacts:read",
30555
+ readScopes: ["contacts:read"],
30506
30556
  returns: "GuestTableView",
30507
30557
  canGet: true,
30508
30558
  listFlags: [
30509
30559
  { name: "list", description: "the guest list's id (required)", query: "guestListId" }
30510
30560
  ],
30511
30561
  write: {
30512
- scope: "contacts:write",
30562
+ scopes: ["contacts:write"],
30513
30563
  createSchema: createGuestTableInputSchema,
30514
30564
  createInput: "CreateGuestTableInput",
30515
30565
  updateSchema: updateGuestTableInputSchema,
@@ -30520,14 +30570,14 @@ var ENTITIES = [
30520
30570
  {
30521
30571
  name: "rsvp-questions",
30522
30572
  path: "/rsvp-questions",
30523
- readScope: "contacts:read",
30573
+ readScopes: ["contacts:read"],
30524
30574
  returns: "RsvpQuestion",
30525
30575
  canGet: true,
30526
30576
  listFlags: [
30527
30577
  { name: "list", description: "the guest list's id (required)", query: "guestListId" }
30528
30578
  ],
30529
30579
  write: {
30530
- scope: "contacts:write",
30580
+ scopes: ["contacts:write"],
30531
30581
  createSchema: createRsvpQuestionInputSchema,
30532
30582
  createInput: "CreateRsvpQuestionInput",
30533
30583
  updateSchema: updateRsvpQuestionInputSchema,
@@ -30538,7 +30588,7 @@ var ENTITIES = [
30538
30588
  {
30539
30589
  name: "guests",
30540
30590
  path: "/guests",
30541
- readScope: "contacts:read",
30591
+ readScopes: ["contacts:read"],
30542
30592
  returns: "GuestView",
30543
30593
  canGet: true,
30544
30594
  listFlags: [
@@ -30547,7 +30597,7 @@ var ENTITIES = [
30547
30597
  { name: "state", description: "yes, no, maybe or waiting (overall)", query: "state" }
30548
30598
  ],
30549
30599
  write: {
30550
- scope: "contacts:write",
30600
+ scopes: ["contacts:write"],
30551
30601
  createSchema: createGuestInputSchema,
30552
30602
  createInput: "CreateGuestInput",
30553
30603
  updateSchema: updateGuestInputSchema,
@@ -30558,7 +30608,7 @@ var ENTITIES = [
30558
30608
  {
30559
30609
  name: "key-dates",
30560
30610
  path: "/key-dates",
30561
- readScope: "key-dates:read",
30611
+ readScopes: ["key-dates:read"],
30562
30612
  returns: "KeyDateView",
30563
30613
  canGet: true,
30564
30614
  listFlags: [
@@ -30580,7 +30630,7 @@ var ENTITIES = [
30580
30630
  }
30581
30631
  ],
30582
30632
  write: {
30583
- scope: "key-dates:write",
30633
+ scopes: ["key-dates:write"],
30584
30634
  createSchema: createKeyDateInputSchema,
30585
30635
  createInput: "CreateKeyDateInput",
30586
30636
  updateSchema: updateKeyDateInputSchema,
@@ -30591,7 +30641,7 @@ var ENTITIES = [
30591
30641
  {
30592
30642
  name: "documents",
30593
30643
  path: "/documents",
30594
- readScope: "documents:read",
30644
+ readScopes: ["documents:read"],
30595
30645
  returns: "DocumentView",
30596
30646
  canGet: true,
30597
30647
  listFlags: [
@@ -30612,7 +30662,7 @@ var ENTITIES = [
30612
30662
  }
30613
30663
  ],
30614
30664
  write: {
30615
- scope: "documents:write",
30665
+ scopes: ["documents:write"],
30616
30666
  createSchema: createDocumentInputSchema,
30617
30667
  createInput: "CreateDocumentInput",
30618
30668
  updateSchema: updateDocumentInputSchema,
@@ -30623,7 +30673,7 @@ var ENTITIES = [
30623
30673
  {
30624
30674
  name: "incidents",
30625
30675
  path: "/incidents",
30626
- readScope: "documents:read",
30676
+ readScopes: ["documents:read"],
30627
30677
  returns: "IncidentView",
30628
30678
  canGet: true,
30629
30679
  listFlags: [
@@ -30635,7 +30685,7 @@ var ENTITIES = [
30635
30685
  }
30636
30686
  ],
30637
30687
  write: {
30638
- scope: "documents:write",
30688
+ scopes: ["documents:write"],
30639
30689
  createSchema: createIncidentInputSchema,
30640
30690
  createInput: "CreateIncidentInput",
30641
30691
  updateSchema: updateIncidentInputSchema,
@@ -30646,7 +30696,7 @@ var ENTITIES = [
30646
30696
  {
30647
30697
  name: "periods",
30648
30698
  path: "/periods",
30649
- readScope: "periods:read",
30699
+ readScopes: ["periods:read"],
30650
30700
  returns: "PeriodView",
30651
30701
  canGet: true,
30652
30702
  listFlags: [
@@ -30663,7 +30713,7 @@ var ENTITIES = [
30663
30713
  }
30664
30714
  ],
30665
30715
  write: {
30666
- scope: "periods:write",
30716
+ scopes: ["periods:write"],
30667
30717
  createSchema: createPeriodInputSchema,
30668
30718
  createInput: "CreatePeriodInput",
30669
30719
  updateSchema: updatePeriodInputSchema,
@@ -30674,12 +30724,12 @@ var ENTITIES = [
30674
30724
  {
30675
30725
  name: "tap-tags",
30676
30726
  path: "/tap-tags",
30677
- readScope: "habits:read",
30727
+ readScopes: ["habits:read", "routines:read"],
30678
30728
  returns: "TapTagView",
30679
30729
  canGet: true,
30680
30730
  listFlags: [],
30681
30731
  write: {
30682
- scope: "habits:write",
30732
+ scopes: ["habits:write", "routines:write"],
30683
30733
  createSchema: createTapTagInputSchema,
30684
30734
  createInput: "CreateTapTagInput",
30685
30735
  updateSchema: updateTapTagInputSchema,
@@ -30690,7 +30740,7 @@ var ENTITIES = [
30690
30740
  {
30691
30741
  name: "animals",
30692
30742
  path: "/animals",
30693
- readScope: "animals:read",
30743
+ readScopes: ["animals:read"],
30694
30744
  returns: "AnimalView",
30695
30745
  canGet: true,
30696
30746
  listFlags: [
@@ -30709,7 +30759,7 @@ var ENTITIES = [
30709
30759
  }
30710
30760
  ],
30711
30761
  write: {
30712
- scope: "animals:write",
30762
+ scopes: ["animals:write"],
30713
30763
  createSchema: createAnimalInputSchema,
30714
30764
  createInput: "CreateAnimalInput",
30715
30765
  updateSchema: updateAnimalInputSchema,
@@ -30720,7 +30770,7 @@ var ENTITIES = [
30720
30770
  {
30721
30771
  name: "runs",
30722
30772
  path: "/runs",
30723
- readScope: "collections:read",
30773
+ readScopes: ["collections:read"],
30724
30774
  returns: "RunView",
30725
30775
  canGet: true,
30726
30776
  listFlags: [
@@ -30733,7 +30783,7 @@ var ENTITIES = [
30733
30783
  { name: "theme", description: "only this theme pack (skyrim, pokemon, \u2026)", query: "theme" }
30734
30784
  ],
30735
30785
  write: {
30736
- scope: "collections:write",
30786
+ scopes: ["collections:write"],
30737
30787
  createSchema: createRunInputSchema,
30738
30788
  createInput: "CreateRunInput",
30739
30789
  updateSchema: updateRunInputSchema,
@@ -30744,12 +30794,12 @@ var ENTITIES = [
30744
30794
  {
30745
30795
  name: "shopping-lists",
30746
30796
  path: "/shopping-lists",
30747
- readScope: "shopping:read",
30797
+ readScopes: ["shopping:read"],
30748
30798
  returns: "ShoppingList",
30749
30799
  canGet: true,
30750
30800
  listFlags: [],
30751
30801
  write: {
30752
- scope: "shopping:write",
30802
+ scopes: ["shopping:write"],
30753
30803
  createSchema: createShoppingListInputSchema,
30754
30804
  createInput: "CreateShoppingListInput",
30755
30805
  updateSchema: updateShoppingListInputSchema,
@@ -30760,12 +30810,12 @@ var ENTITIES = [
30760
30810
  {
30761
30811
  name: "inventory-items",
30762
30812
  path: "/inventory-items",
30763
- readScope: "inventory:read",
30813
+ readScopes: ["inventory:read"],
30764
30814
  returns: "InventoryItem",
30765
30815
  canGet: true,
30766
30816
  listFlags: [],
30767
30817
  write: {
30768
- scope: "inventory:write",
30818
+ scopes: ["inventory:write"],
30769
30819
  createSchema: createInventoryItemInputSchema,
30770
30820
  createInput: "CreateInventoryItemInput",
30771
30821
  updateSchema: updateInventoryItemInputSchema,
@@ -30776,12 +30826,12 @@ var ENTITIES = [
30776
30826
  {
30777
30827
  name: "recipes",
30778
30828
  path: "/recipes",
30779
- readScope: "meals:read",
30829
+ readScopes: ["meals:read"],
30780
30830
  returns: "Recipe",
30781
30831
  canGet: true,
30782
30832
  listFlags: [],
30783
30833
  write: {
30784
- scope: "meals:write",
30834
+ scopes: ["meals:write"],
30785
30835
  createSchema: createRecipeInputSchema,
30786
30836
  createInput: "CreateRecipeInput",
30787
30837
  updateSchema: updateRecipeInputSchema,
@@ -30792,12 +30842,12 @@ var ENTITIES = [
30792
30842
  {
30793
30843
  name: "meal-plans",
30794
30844
  path: "/meal-plans",
30795
- readScope: "meals:read",
30845
+ readScopes: ["meals:read"],
30796
30846
  returns: "MealPlan",
30797
30847
  canGet: true,
30798
30848
  listFlags: [],
30799
30849
  write: {
30800
- scope: "meals:write",
30850
+ scopes: ["meals:write"],
30801
30851
  createSchema: createMealPlanInputSchema,
30802
30852
  createInput: "CreateMealPlanInput",
30803
30853
  updateSchema: updateMealPlanInputSchema,
@@ -30808,7 +30858,7 @@ var ENTITIES = [
30808
30858
  {
30809
30859
  name: "occurrences",
30810
30860
  path: "/occurrences",
30811
- readScope: "occurrences:read",
30861
+ readScopes: ["occurrences:read"],
30812
30862
  returns: "Occurrence",
30813
30863
  canGet: false,
30814
30864
  listFlags: [
@@ -30823,7 +30873,7 @@ var ENTITIES = [
30823
30873
  {
30824
30874
  name: "time-blocks",
30825
30875
  path: "/time-blocks",
30826
- readScope: "calendar:read",
30876
+ readScopes: ["calendar:read"],
30827
30877
  returns: "TimeBlockView",
30828
30878
  canGet: true,
30829
30879
  listFlags: [
@@ -30835,7 +30885,7 @@ var ENTITIES = [
30835
30885
  { name: "kind", description: "only blocks of this kind: task, focus or life" }
30836
30886
  ],
30837
30887
  write: {
30838
- scope: "calendar:write",
30888
+ scopes: ["calendar:write"],
30839
30889
  createSchema: createTimeBlockInputSchema,
30840
30890
  createInput: "CreateTimeBlockInput",
30841
30891
  updateSchema: updateTimeBlockInputSchema,
@@ -30846,12 +30896,12 @@ var ENTITIES = [
30846
30896
  {
30847
30897
  name: "block-templates",
30848
30898
  path: "/block-templates",
30849
- readScope: "calendar:read",
30899
+ readScopes: ["calendar:read"],
30850
30900
  returns: "BlockTemplateView",
30851
30901
  canGet: true,
30852
30902
  listFlags: [],
30853
30903
  write: {
30854
- scope: "calendar:write",
30904
+ scopes: ["calendar:write"],
30855
30905
  createSchema: createBlockTemplateInputSchema,
30856
30906
  createInput: "CreateBlockTemplateInput",
30857
30907
  updateSchema: updateBlockTemplateInputSchema,
@@ -30862,7 +30912,7 @@ var ENTITIES = [
30862
30912
  {
30863
30913
  name: "webhooks",
30864
30914
  path: "/webhooks",
30865
- readScope: "webhooks:read",
30915
+ readScopes: ["webhooks:read"],
30866
30916
  returns: "WebhookSubscription",
30867
30917
  canGet: true,
30868
30918
  listFlags: []
@@ -31298,7 +31348,7 @@ var HEALTH_COMMAND_SPECS = [
31298
31348
  flags: [],
31299
31349
  scopes: READ,
31300
31350
  returns: "GoogleHealthStatus",
31301
- 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."
31351
+ 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. `nutrition` says whether your food is written back to Google Health (turned on in do; each settled day once, one entry per meal type) and the last day written."
31302
31352
  },
31303
31353
  {
31304
31354
  path: ["health", "google", "sync"],
@@ -31713,6 +31763,21 @@ var COMMAND_SPECS = [
31713
31763
  returns: "JournalRecall",
31714
31764
  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."
31715
31765
  },
31766
+ {
31767
+ path: ["journal", "like"],
31768
+ summary: 'Days like this one: your other days that share the most with a day (its words, tags and rating), for "when did I feel like this before?".',
31769
+ args: [{ name: "date", required: true, description: "The day, YYYY-MM-DD." }],
31770
+ flags: [
31771
+ {
31772
+ name: "limit",
31773
+ type: "string",
31774
+ description: "At most this many days (1\u201310, 5 by default)."
31775
+ }
31776
+ ],
31777
+ scopes: ["journal:read"],
31778
+ returns: "JournalLike",
31779
+ notes: "GET /api/v1/journal/days/{date}/like (journal_like) \u2014 your own days only, by Postgres full text over the one-liner, highlights, tags, summary and entries (the day's own words, with a few that mean the same), then shared tags and a close rating. Words, not meanings: no embeddings. A day hidden from memories is never offered. journal:read is a sensitive scope."
31780
+ },
31716
31781
  {
31717
31782
  path: ["journal", "digest"],
31718
31783
  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.",
@@ -36249,8 +36314,8 @@ function buildManifest() {
36249
36314
  name: e.name,
36250
36315
  operations: entityOperations(e),
36251
36316
  path: `${API_PREFIX}${e.path}`,
36252
- readScope: e.readScope,
36253
- ...e.write ? { writeScope: e.write.scope } : {},
36317
+ readScopes: e.readScopes,
36318
+ ...e.write ? { writeScopes: e.write.scopes } : {},
36254
36319
  ...e.write?.createInput || e.write?.updateInput ? {
36255
36320
  inputs: {
36256
36321
  ...e.write.createInput ? { create: e.write.createInput } : {},
@@ -37388,6 +37453,24 @@ function renderJournalRecall(data, mode) {
37388
37453
  return out.join(`
37389
37454
  `);
37390
37455
  }
37456
+ function renderJournalLike(data, mode) {
37457
+ const d = data;
37458
+ const out = [paint(mode, "dim", `Like ${d.date ?? "this day"}: ${(d.words ?? []).join(" \xB7 ")}`)];
37459
+ const days = d.days ?? [];
37460
+ if (days.length === 0) {
37461
+ out.push(paint(mode, "dim", "(no other day shares enough with it)"));
37462
+ return out.join(`
37463
+ `);
37464
+ }
37465
+ for (const day of days) {
37466
+ const rating = day.metrics?.rating;
37467
+ const meta = rating === undefined ? "" : paint(mode, "dim", ` ${rating}/10`);
37468
+ const shared = [...day.shared ?? [], ...(day.sharedTags ?? []).map((t) => `#${t}`)];
37469
+ out.push(`${day.date} ${day.title ?? paint(mode, "dim", "(no entry)")}${meta}${shared.length ? paint(mode, "dim", ` \xB7 ${shared.join(", ")}`) : ""}`);
37470
+ }
37471
+ return out.join(`
37472
+ `);
37473
+ }
37391
37474
  function renderJournalDigest(data) {
37392
37475
  return data.text ?? "";
37393
37476
  }
@@ -38569,6 +38652,18 @@ var HANDLERS = {
38569
38652
  render: renderJournalRecall
38570
38653
  };
38571
38654
  },
38655
+ "journal like": async ({ args, flags, requireClient }) => {
38656
+ const [date] = args;
38657
+ if (!date)
38658
+ throw usageError("journal like needs the day, YYYY-MM-DD");
38659
+ parseInput(journalDateSchema, date);
38660
+ const limit = flagString(flags, "limit");
38661
+ parseInput(journalLikeQuerySchema, limit === undefined ? {} : { limit });
38662
+ return {
38663
+ data: await requireClient().get(`/journal/days/${date}/like`, { query: { limit } }),
38664
+ render: renderJournalLike
38665
+ };
38666
+ },
38572
38667
  "journal digest": async ({ requireClient }) => ({
38573
38668
  data: await requireClient().get("/journal/digest"),
38574
38669
  render: renderJournalDigest
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.300.0",
3
+ "version": "1.301.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",