@robbeverhelst/do 1.384.0 → 1.386.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 +173 -38
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -14420,7 +14420,7 @@ var configError = (message) => new CliError("config", message, EXIT.CONFIG);
14420
14420
 
14421
14421
  // src/meta.ts
14422
14422
  var CLI_NAME = "do";
14423
- var VERSION = "1.384.0";
14423
+ var VERSION = "1.386.0";
14424
14424
  var API_PREFIX = "/api/v1";
14425
14425
  var DEFAULT_API_URL = "http://localhost:3001";
14426
14426
 
@@ -19020,7 +19020,9 @@ var recipes = pgTable("recipes", {
19020
19020
  favorite: boolean4("favorite").notNull().default(false),
19021
19021
  kind: recipeKind("kind").notNull().default("recipe"),
19022
19022
  cookedWeightG: doublePrecision("cooked_weight_g"),
19023
- nutritionCache: jsonb("nutrition_cache").$type()
19023
+ nutritionCache: jsonb("nutrition_cache").$type(),
19024
+ photoUrl: text("photo_url"),
19025
+ photoCredit: text("photo_credit")
19024
19026
  }, (t) => [
19025
19027
  index("recipes_tenant_idx").on(t.tenantId)
19026
19028
  ]);
@@ -19052,7 +19054,9 @@ var mealPlans = pgTable("meal_plans", {
19052
19054
  company: text("company"),
19053
19055
  leftoverPortions: integer2("leftover_portions"),
19054
19056
  leftoverEatBy: date5("leftover_eat_by", { mode: "string" }),
19055
- leftoverFrozen: boolean4("leftover_frozen").notNull().default(false)
19057
+ leftoverFrozen: boolean4("leftover_frozen").notNull().default(false),
19058
+ eaterUserIds: text("eater_user_ids").array().notNull().default([]),
19059
+ guests: integer2("guests").notNull().default(0)
19056
19060
  }, (t) => [
19057
19061
  index("meal_plans_tenant_planned_idx").on(t.tenantId, t.plannedFor),
19058
19062
  check2("meal_plans_state_check", sql`${t.state} IN ('planned', 'cooked', 'out', 'unsure', 'draft')`)
@@ -25088,7 +25092,10 @@ var blockTemplateInstanceSchema = object({
25088
25092
  routineId: string2().nullable()
25089
25093
  });
25090
25094
  var PLAN_VS_RECORD_RANGES = [7, 30, 90];
25095
+ var PLAN_VS_RECORD_MONTH_RANGES = ["month", "six", "year", "all"];
25096
+ var planVsRecordMonthRangeSchema = _enum2(PLAN_VS_RECORD_MONTH_RANGES);
25091
25097
  var planVsRecordQuerySchema = object({
25098
+ range: planVsRecordMonthRangeSchema.optional(),
25092
25099
  days: exports_coerce.number().refine((d) => PLAN_VS_RECORD_RANGES.includes(d), {
25093
25100
  message: "days must be 7, 30 or 90"
25094
25101
  }).default(30)
@@ -25142,6 +25149,7 @@ var planVsRecordSuggestionSchema = object({
25142
25149
  });
25143
25150
  var planVsRecordSchema = object({
25144
25151
  days: number2().int(),
25152
+ range: planVsRecordMonthRangeSchema.nullable().default(null),
25145
25153
  since: string2().nullable(),
25146
25154
  recordedDays: number2().int(),
25147
25155
  week: array(planVsRecordDaySchema),
@@ -35262,7 +35270,9 @@ var weekMenuFields = {
35262
35270
  company: string2().max(120).nullish(),
35263
35271
  leftoverPortions: number2().int().positive().nullish(),
35264
35272
  leftoverEatBy: civilDate2.nullish(),
35265
- leftoverFrozen: boolean2().optional()
35273
+ leftoverFrozen: boolean2().optional(),
35274
+ eaterUserIds: array(ulidSchema).max(50).optional(),
35275
+ guests: number2().int().min(0).max(99).optional()
35266
35276
  };
35267
35277
  var mealPlanSchema = createSelectSchema(mealPlans, {
35268
35278
  plannedFor: exports_coerce.date(),
@@ -35271,7 +35281,9 @@ var mealPlanSchema = createSelectSchema(mealPlans, {
35271
35281
  company: string2().nullable().default(null),
35272
35282
  leftoverPortions: number2().int().nullable().default(null),
35273
35283
  leftoverEatBy: string2().nullable().default(null),
35274
- leftoverFrozen: boolean2().default(false)
35284
+ leftoverFrozen: boolean2().default(false),
35285
+ eaterUserIds: array(string2()).default([]),
35286
+ guests: number2().int().default(0)
35275
35287
  });
35276
35288
  var createMealPlanInputSchema = createInsertSchema(mealPlans, {
35277
35289
  id: ulidSchema,
@@ -35338,6 +35350,8 @@ var mealWeekSlotSchema = object({
35338
35350
  cook: mealWeekCookSchema.nullable(),
35339
35351
  company: string2().nullable(),
35340
35352
  notes: string2().nullable(),
35353
+ eaters: array(mealWeekCookSchema).default([]),
35354
+ guests: number2().int().min(0).default(0),
35341
35355
  time: string2().nullable()
35342
35356
  });
35343
35357
  var mealWeekDaySchema = object({
@@ -35370,7 +35384,8 @@ var mealWeekSchema = object({
35370
35384
  out: number2().int().min(0)
35371
35385
  }),
35372
35386
  leftovers: array(mealWeekLeftoverSchema),
35373
- draft: array(mealWeekDraftDaySchema).length(7)
35387
+ draft: array(mealWeekDraftDaySchema).length(7),
35388
+ openDrafts: array(mealWeekDraftDaySchema).default([])
35374
35389
  });
35375
35390
 
35376
35391
  // ../../packages/schema/src/operations/meal-plans.ts
@@ -35570,8 +35585,60 @@ var moneyOdooUndoResultSchema = object({
35570
35585
  line: string2()
35571
35586
  });
35572
35587
 
35573
- // ../../packages/schema/src/contracts/money-net-worth.ts
35588
+ // ../../packages/schema/src/contracts/money-flow.ts
35574
35589
  var amount5 = string2();
35590
+ var MONEY_FLOW_START = "start";
35591
+ var moneyFlowQuerySchema = object({
35592
+ from: union([moneyMonthSchema, literal(MONEY_FLOW_START)]).optional(),
35593
+ to: moneyMonthSchema.optional(),
35594
+ scope: moneyBudgetScopeSchema.optional()
35595
+ }).refine((q) => !q.from || q.from === MONEY_FLOW_START || !q.to || q.from <= q.to, {
35596
+ message: "from must not be after to",
35597
+ path: ["from"]
35598
+ });
35599
+ var moneyFlowSourceSchema = object({
35600
+ kind: _enum2(["income", "moved_in"]),
35601
+ categoryId: ulidSchema.nullable(),
35602
+ name: string2(),
35603
+ amount: amount5
35604
+ });
35605
+ var MONEY_FLOW_OUTS = [
35606
+ "fixed",
35607
+ "flexible",
35608
+ "moved_out",
35609
+ "goals",
35610
+ "invested",
35611
+ "kept"
35612
+ ];
35613
+ var moneyFlowOutKindSchema = _enum2(MONEY_FLOW_OUTS);
35614
+ var moneyFlowOutSchema = object({
35615
+ kind: moneyFlowOutKindSchema,
35616
+ name: string2(),
35617
+ amount: amount5
35618
+ });
35619
+ var moneyFlowCategorySchema = object({
35620
+ categoryId: ulidSchema.nullable(),
35621
+ name: string2(),
35622
+ amount: amount5
35623
+ });
35624
+ var moneyFlowSchema = object({
35625
+ scope: moneyBudgetScopeSchema,
35626
+ from: moneyMonthSchema,
35627
+ to: moneyMonthSchema,
35628
+ through: moneyMonthSchema,
35629
+ firstMonth: moneyMonthSchema.nullable(),
35630
+ in: amount5,
35631
+ sources: array(moneyFlowSourceSchema),
35632
+ fromSavings: amount5,
35633
+ outs: array(moneyFlowOutSchema),
35634
+ fixed: array(moneyFlowCategorySchema),
35635
+ flexible: array(moneyFlowCategorySchema),
35636
+ unsorted: amount5,
35637
+ saved: amount5
35638
+ });
35639
+
35640
+ // ../../packages/schema/src/contracts/money-net-worth.ts
35641
+ var amount6 = string2();
35575
35642
  var moneySnapshotSourceSchema = _enum2(moneySnapshotSource.enumValues);
35576
35643
  var moneyNetWorthQuerySchema = object({
35577
35644
  scope: moneyBudgetScopeSchema.optional(),
@@ -35579,9 +35646,9 @@ var moneyNetWorthQuerySchema = object({
35579
35646
  });
35580
35647
  var moneyNetWorthPointSchema = object({
35581
35648
  month: moneyMonthSchema,
35582
- total: amount5.nullable(),
35583
- have: amount5.nullable(),
35584
- owe: amount5.nullable()
35649
+ total: amount6.nullable(),
35650
+ have: amount6.nullable(),
35651
+ owe: amount6.nullable()
35585
35652
  });
35586
35653
  var moneyNetWorthAccountSchema = object({
35587
35654
  accountId: ulidSchema,
@@ -35589,7 +35656,7 @@ var moneyNetWorthAccountSchema = object({
35589
35656
  kind: moneyAccountKindSchema,
35590
35657
  visibility: _enum2(NODE_VISIBILITY_VALUES),
35591
35658
  currency: string2(),
35592
- value: amount5,
35659
+ value: amount6,
35593
35660
  source: moneySnapshotSourceSchema,
35594
35661
  month: moneyMonthSchema,
35595
35662
  pensionSubtype: moneyPensionSubtypeSchema.nullable(),
@@ -35606,11 +35673,11 @@ var moneyNetWorthUnknownSchema = moneyNetWorthAccountSchema.pick({
35606
35673
  var moneyNetWorthSchema = object({
35607
35674
  scope: moneyBudgetScopeSchema,
35608
35675
  month: moneyMonthSchema,
35609
- total: amount5,
35610
- have: amount5,
35611
- owe: amount5,
35612
- liquid: amount5,
35613
- locked: amount5,
35676
+ total: amount6,
35677
+ have: amount6,
35678
+ owe: amount6,
35679
+ liquid: amount6,
35680
+ locked: amount6,
35614
35681
  points: array(moneyNetWorthPointSchema),
35615
35682
  accounts: array(moneyNetWorthAccountSchema),
35616
35683
  complete: boolean2(),
@@ -35625,7 +35692,7 @@ var moneySnapshotSchema = object({
35625
35692
  id: ulidSchema,
35626
35693
  accountId: ulidSchema,
35627
35694
  month: moneyMonthSchema,
35628
- value: amount5,
35695
+ value: amount6,
35629
35696
  source: moneySnapshotSourceSchema
35630
35697
  });
35631
35698
 
@@ -35715,22 +35782,22 @@ var moneySettlementViewSchema = object({
35715
35782
  });
35716
35783
 
35717
35784
  // ../../packages/schema/src/contracts/money-year.ts
35718
- var amount6 = string2();
35785
+ var amount7 = string2();
35719
35786
  var moneyYearQuerySchema = object({
35720
35787
  year: exports_coerce.number().int().min(2000).max(2100).optional(),
35721
35788
  scope: moneyBudgetScopeSchema.optional()
35722
35789
  });
35723
35790
  var moneyYearMonthSchema = object({
35724
35791
  month: moneyMonthSchema,
35725
- income: amount6,
35726
- spent: amount6
35792
+ income: amount7,
35793
+ spent: amount7
35727
35794
  });
35728
35795
  var moneyYearCategorySchema = object({
35729
35796
  categoryId: ulidSchema.nullable(),
35730
35797
  name: string2(),
35731
35798
  group: _enum2(["fixed", "flexible", "income"]).nullable(),
35732
- amount: amount6,
35733
- lastYear: amount6
35799
+ amount: amount7,
35800
+ lastYear: amount7
35734
35801
  });
35735
35802
  var MONEY_YEAR_STREAM_CHANGES = ["new", "stopped", "up", "down", "same"];
35736
35803
  var moneyYearStreamChangeSchema = _enum2(MONEY_YEAR_STREAM_CHANGES);
@@ -35739,8 +35806,8 @@ var moneyYearStreamSchema = object({
35739
35806
  title: string2(),
35740
35807
  cadence: moneyCadenceSchema,
35741
35808
  visibility: _enum2(NODE_VISIBILITY_VALUES),
35742
- thisYear: amount6,
35743
- lastYear: amount6,
35809
+ thisYear: amount7,
35810
+ lastYear: amount7,
35744
35811
  change: moneyYearStreamChangeSchema
35745
35812
  });
35746
35813
  var moneyYearGoalSchema = object({
@@ -35749,14 +35816,14 @@ var moneyYearGoalSchema = object({
35749
35816
  visibility: _enum2(NODE_VISIBILITY_VALUES),
35750
35817
  status: moneyGoalStatusSchema,
35751
35818
  projectTitle: string2().nullable(),
35752
- thisYear: amount6,
35753
- saved: amount6,
35754
- target: amount6
35819
+ thisYear: amount7,
35820
+ saved: amount7,
35821
+ target: amount7
35755
35822
  });
35756
35823
  var moneyYearTotalsSchema = object({
35757
- income: amount6,
35758
- spent: amount6,
35759
- saved: amount6
35824
+ income: amount7,
35825
+ spent: amount7,
35826
+ saved: amount7
35760
35827
  });
35761
35828
  var moneyYearSchema = object({
35762
35829
  year: number2().int(),
@@ -36410,6 +36477,23 @@ var moneyOperations = defineOperations({
36410
36477
  response: { description: "The year." },
36411
36478
  errors: { 400: true }
36412
36479
  },
36480
+ flow: {
36481
+ method: "get",
36482
+ path: "/money/flow",
36483
+ scopes: ["finance:read"],
36484
+ tag: "Money",
36485
+ summary: "Get where the money went",
36486
+ description: "What came in over a span of months and where it went, as the flow chart draws it: `sources` (each income category, null `categoryId` for income not sorted yet, and with a `scope` narrower than `all` `moved_in`, money moved in from the other budget accounts; biggest first) adding up to `in`; `outs` in the chart's order, only what's above zero: `fixed` and `flexible` spending (refunds netted, plain transfers left out; what isn't sorted yet sits under flexible), `moved_out` (to the other budget accounts, with a narrower scope), `goals` (a deposit linked to a goal, or spending toward it from the budget), `invested` (transfers into an investment or a pension account) and `kept` (what's left); `fromSavings` when more went out than came in. `fixed` and `flexible` by category, biggest first, with `unsorted`, and `saved` (goals, invested and kept). Read over the accounts counted in the budget; another member's Only me account or goal never adds to it. `from` and `to` are months (`YYYY-MM`; `to` this month and `from` `to` by default, `from=start` the ledger's first month, `firstMonth`); a span under way counts to this month (`through`). `scope`: `all` (default), `space` or `owner`.",
36487
+ query: [
36488
+ { name: "from", description: "The first month, YYYY-MM, or start (default: to)." },
36489
+ { name: "to", description: "The last month, YYYY-MM (default this one)." },
36490
+ { name: "scope", description: "all, space or owner." }
36491
+ ],
36492
+ querySchema: moneyFlowQuerySchema,
36493
+ status: 200,
36494
+ response: { description: "The flow." },
36495
+ errors: { 400: true }
36496
+ },
36413
36497
  netWorthRead: {
36414
36498
  method: "get",
36415
36499
  path: "/money/net-worth",
@@ -38979,8 +39063,12 @@ var readOperations = defineOperations({
38979
39063
  var recipeSchema = createSelectSchema(recipes, {
38980
39064
  kind: (s) => s.default("recipe"),
38981
39065
  cookedWeightG: number2().positive().nullable().default(null),
38982
- nutritionCache: recipeNutritionCacheSchema.nullable().default(null)
39066
+ nutritionCache: recipeNutritionCacheSchema.nullable().default(null),
39067
+ photoUrl: string2().nullable().default(null),
39068
+ photoCredit: string2().nullable().default(null)
38983
39069
  });
39070
+ var photoUrlSchema = string2().trim().url().max(2048).refine((u) => /^https?:\/\//i.test(u), "an http(s) URL");
39071
+ var photoCreditSchema = string2().trim().max(200);
38984
39072
  var recipeIngredientSchema = createSelectSchema(recipeIngredients, {
38985
39073
  createdAt: exports_coerce.date()
38986
39074
  });
@@ -38998,7 +39086,9 @@ var createRecipeInputSchema = createInsertSchema(recipes, {
38998
39086
  prepMinutes: number2().int().min(0).nullish(),
38999
39087
  cookMinutes: number2().int().min(0).nullish(),
39000
39088
  tags: array(string2()).optional(),
39001
- cookedWeightG: number2().positive().nullish()
39089
+ cookedWeightG: number2().positive().nullish(),
39090
+ photoUrl: photoUrlSchema.nullish(),
39091
+ photoCredit: photoCreditSchema.nullish()
39002
39092
  }).omit({ tenantId: true, nutritionCache: true }).extend({
39003
39093
  title: string2().min(1),
39004
39094
  parentId: ulidSchema.nullish(),
@@ -39010,7 +39100,9 @@ var updateRecipeInputSchema = createUpdateSchema(recipes, {
39010
39100
  prepMinutes: number2().int().min(0).nullish(),
39011
39101
  cookMinutes: number2().int().min(0).nullish(),
39012
39102
  tags: array(string2()).optional(),
39013
- cookedWeightG: number2().positive().nullish()
39103
+ cookedWeightG: number2().positive().nullish(),
39104
+ photoUrl: photoUrlSchema.nullish(),
39105
+ photoCredit: photoCreditSchema.nullish()
39014
39106
  }).omit({ id: true, tenantId: true, nutritionCache: true }).extend({
39015
39107
  title: string2().min(1).optional(),
39016
39108
  parentId: ulidSchema.nullish(),
@@ -41441,9 +41533,14 @@ var timeBlockOperations = defineOperations({
41441
41533
  scopes: ["calendar:read"],
41442
41534
  tag: "Calendar",
41443
41535
  summary: "Plan vs what happened",
41444
- description: 'How the key\'s member\'s life blocks went against their plan over the last `days` (7, 30 or 90; default 30): `week`, last week (Monday to Sunday) as strips (each block\'s planned and recorded minutes into the day, and the day in words, "Held mostly", "Evening went elsewhere"); `hours`, where that week\'s time went per group of kinds, recorded against planned; `moves`, which blocks move over the range\'s weekdays and how, in words ("Lunch \xB7 60\u201375 min \xB7 Runs about twice the 30 planned \xB7 17 of 22"), counting a record once it\'s confirmed or 48 h old, each with `latestId` (its latest block); `evening`, the weekday evenings\' tasks (Tasks planned from 17:00) held, in words with the days work ran past 17:30, and a confidence word, or null; and `suggestion`, one template length to change ("plan it like it is", apply with `PATCH /api/v1/block-templates/{id}` `{ minutes }`) or null. Moving is information, not a miss: no score, no streak.',
41536
+ description: "How the key's member's life blocks went against their plan over the last `days` (7, 30 or 90; default 30), or a month `range` in its place (Review's Range menu: `month`, this month so far; `six`, from the first of the month five back; `year`, this year so far; `all`, since the first recorded block; the response says its `days` and `range`): `week`, last week (Monday to Sunday) as strips (each block's planned and recorded minutes into the day, and the day in words, \"Held mostly\", \"Evening went elsewhere\"); `hours`, where that week's time went per group of kinds, recorded against planned; `moves`, which blocks move over the range's weekdays and how, in words (\"Lunch \xB7 60\u201375 min \xB7 Runs about twice the 30 planned \xB7 17 of 22\"), counting a record once it's confirmed or 48 h old, each with `latestId` (its latest block); `evening`, the weekday evenings' tasks (Tasks planned from 17:00) held, in words with the days work ran past 17:30, and a confidence word, or null; and `suggestion`, one template length to change (\"plan it like it is\", apply with `PATCH /api/v1/block-templates/{id}` `{ minutes }`) or null. Moving is information, not a miss: no score, no streak.",
41445
41537
  query: [
41446
- { name: "days", description: "7, 30 (default) or 90.", type: "integer", enum: [7, 30, 90] }
41538
+ { name: "days", description: "7, 30 (default) or 90.", type: "integer", enum: [7, 30, 90] },
41539
+ {
41540
+ name: "range",
41541
+ description: "month, six, year or all, in place of days.",
41542
+ enum: ["month", "six", "year", "all"]
41543
+ }
41447
41544
  ],
41448
41545
  querySchema: planVsRecordQuerySchema,
41449
41546
  status: 200,
@@ -54361,6 +54458,33 @@ var commands34 = [
54361
54458
  render: renderRecord
54362
54459
  })
54363
54460
  }),
54461
+ defineCommand({
54462
+ operation: moneyOperations.flow,
54463
+ path: ["money", "flow"],
54464
+ summary: "Where the money went over a span of months: in by source, out to fixed, flexible, goals, invested and kept.",
54465
+ args: [],
54466
+ flags: [
54467
+ {
54468
+ name: "from",
54469
+ type: "string",
54470
+ description: "The first month, YYYY-MM, or start (default: --to)."
54471
+ },
54472
+ { name: "to", type: "string", description: "The last month, YYYY-MM (default this one)." },
54473
+ { name: "scope", type: "string", description: "all (default) | space | owner." }
54474
+ ],
54475
+ returns: "MoneyFlow",
54476
+ notes: ". sources (income by category, moved_in with a narrower scope) adding up to in; outs in the chart's order (fixed \xB7 flexible \xB7 moved_out \xB7 goals \xB7 invested \xB7 kept), only what's above zero; fromSavings when more went out than came in; fixed and flexible by category, with unsorted (what isn't sorted sits under flexible) and saved. `do money flow --from 2026-05 --to 2026-10`; `--from start` reads since the ledger begins.",
54477
+ run: async ({ flags, requireClient }) => ({
54478
+ data: await requireClient().get(pathOf(moneyOperations.flow), {
54479
+ query: {
54480
+ from: flagString(flags, "from"),
54481
+ to: flagString(flags, "to"),
54482
+ scope: flagString(flags, "scope")
54483
+ }
54484
+ }),
54485
+ render: renderRecord
54486
+ })
54487
+ }),
54364
54488
  defineCommand({
54365
54489
  operation: moneyOperations.netWorthRead,
54366
54490
  path: ["money", "net-worth"],
@@ -59413,16 +59537,27 @@ var commands58 = [
59413
59537
  path: ["time-blocks", "plan-vs-record"],
59414
59538
  summary: "How the life blocks went against their plan: last week day by day, where the time went, which blocks move (in words), and one template change worth making.",
59415
59539
  args: [],
59416
- flags: [{ name: "days", type: "string", description: "7, 30 (default) or 90." }],
59540
+ flags: [
59541
+ { name: "days", type: "string", description: "7, 30 (default) or 90." },
59542
+ {
59543
+ name: "range",
59544
+ type: "string",
59545
+ description: "month | six | year | all (Review's months), in place of --days."
59546
+ }
59547
+ ],
59417
59548
  scopes: [...timeBlockOperations.planVsRecord.scopes],
59418
59549
  returns: "PlanVsRecord",
59419
- notes: `${routeOf(timeBlockOperations.planVsRecord)}?days= (plan vs record). No score, no streak.`
59550
+ notes: `${routeOf(timeBlockOperations.planVsRecord)}?days= or ?range= (plan vs record). No score, no streak.`
59420
59551
  },
59421
59552
  run: async ({ flags, requireClient }) => {
59422
59553
  const days = flagString(flags, "days");
59554
+ const range = flagString(flags, "range");
59423
59555
  return {
59424
59556
  data: await requireClient().get(pathOf(timeBlockOperations.planVsRecord), {
59425
- query: days === undefined ? {} : { days }
59557
+ query: {
59558
+ ...days === undefined ? {} : { days },
59559
+ ...range === undefined ? {} : { range }
59560
+ }
59426
59561
  }),
59427
59562
  render: renderRecord
59428
59563
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.384.0",
3
+ "version": "1.386.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",