@robbeverhelst/do 1.292.0 → 1.294.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 +150 -15
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -3976,7 +3976,9 @@ var notificationType = pgEnum("notification_type", [
3976
3976
  "bank_link",
3977
3977
  "import_failed",
3978
3978
  "animal_ask",
3979
- "life_block"
3979
+ "life_block",
3980
+ "animal_alert",
3981
+ "health_checkin"
3980
3982
  ]);
3981
3983
  var notificationDomain = pgEnum("notification_domain", [
3982
3984
  "task",
@@ -4094,6 +4096,37 @@ var notificationReceipts = pgTable("notification_receipts", {
4094
4096
  undoneAt: timestamp("undone_at", { withTimezone: true }),
4095
4097
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
4096
4098
  }, (t) => [unique("notification_receipts_action_uniq").on(t.notificationId, t.actionIndex)]);
4099
+ var telegramLinks = pgTable("telegram_links", {
4100
+ id: text("id").primaryKey(),
4101
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
4102
+ userId: text("user_id").notNull().references(() => users.id),
4103
+ code: text("code"),
4104
+ codeExpiresAt: timestamp("code_expires_at", { withTimezone: true }),
4105
+ chatId: text("chat_id"),
4106
+ threadId: integer("thread_id"),
4107
+ chatTitle: text("chat_title"),
4108
+ telegramUserId: text("telegram_user_id"),
4109
+ linkedAt: timestamp("linked_at", { withTimezone: true }),
4110
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
4111
+ }, (t) => [
4112
+ unique("telegram_links_member_uniq").on(t.tenantId, t.userId),
4113
+ unique("telegram_links_code_uniq").on(t.code)
4114
+ ]);
4115
+ var telegramMessages = pgTable("telegram_messages", {
4116
+ id: text("id").primaryKey(),
4117
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
4118
+ userId: text("user_id").notNull().references(() => users.id),
4119
+ notificationId: text("notification_id").notNull().references(() => notifications.id, { onDelete: "cascade" }),
4120
+ kind: text("kind").$type().notNull(),
4121
+ chatId: text("chat_id").notNull(),
4122
+ messageId: bigint("message_id", { mode: "number" }),
4123
+ buttons: jsonb("buttons").$type().notNull().default([]),
4124
+ receiptId: text("receipt_id"),
4125
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
4126
+ editedAt: timestamp("edited_at", { withTimezone: true })
4127
+ }, (t) => [
4128
+ uniqueIndex("telegram_messages_notification_uniq").on(t.notificationId).where(sql`${t.kind} <> 'receipt'`)
4129
+ ]);
4097
4130
 
4098
4131
  // ../../packages/schema/src/db/foods.ts
4099
4132
  var foodSource = pgEnum("food_source", ["nevo", "usda", "off", "nubel"]);
@@ -4717,6 +4750,7 @@ var moneyTransactions = pgTable("money_transactions", {
4717
4750
  onDelete: "set null"
4718
4751
  }),
4719
4752
  note: text("note"),
4753
+ orderItem: text("order_item"),
4720
4754
  businessShare: smallint("business_share").notNull().default(0),
4721
4755
  businessStatus: moneyBusinessStatus("business_status").notNull().default("none"),
4722
4756
  businessNote: text("business_note"),
@@ -21291,7 +21325,11 @@ var houseAssetLinkSchema = object({
21291
21325
  title: string2(),
21292
21326
  type: string2(),
21293
21327
  kind: string2(),
21294
- direction: _enum2(["in", "out"])
21328
+ direction: _enum2(["in", "out"]),
21329
+ label: string2().nullable().default(null),
21330
+ context: string2().nullable().default(null),
21331
+ at: exports_coerce.date().nullable().default(null),
21332
+ timed: boolean3().default(false)
21295
21333
  });
21296
21334
  var houseAssetSchema = object({
21297
21335
  item: collectionItemDetailSchema,
@@ -21624,13 +21662,30 @@ var postRunSchema = object({
21624
21662
  });
21625
21663
  var POST_RECEIPT_ABOUT_VALUES = ["red_flags", "saved", "vet_visit"];
21626
21664
  var POST_RECEIPT_SOURCE_MAX = 80;
21627
- var postReceiptInputSchema = object({
21665
+ var postNodeReceiptInputSchema = object({
21628
21666
  nodeId: ulidSchema,
21629
21667
  parts: array(ulidSchema).min(1).max(10).optional(),
21630
21668
  about: _enum2(POST_RECEIPT_ABOUT_VALUES).optional(),
21631
21669
  source: string2().trim().min(1).max(POST_RECEIPT_SOURCE_MAX).optional(),
21632
21670
  personNotes: array(ulidSchema).min(1).max(10).optional()
21633
21671
  }).strict();
21672
+ var POST_MONEY_RECEIPT_ABOUT_VALUES = ["ask", "bill"];
21673
+ var webUrlSchema = string2().url().max(2000).refine((url) => /^https?:\/\//i.test(url), "must be an http(s) link");
21674
+ var postMoneyReceiptInputSchema = object({
21675
+ transactionId: ulidSchema,
21676
+ about: _enum2(POST_MONEY_RECEIPT_ABOUT_VALUES),
21677
+ odoo: object({
21678
+ openUrl: webUrlSchema,
21679
+ account: string2().trim().min(1).max(120).nullish()
21680
+ }).strict().optional(),
21681
+ undo: object({
21682
+ items: array(object({ id: ulidSchema }).passthrough()).min(1).max(200)
21683
+ }).optional()
21684
+ }).strict();
21685
+ var postReceiptInputSchema = union([
21686
+ postNodeReceiptInputSchema,
21687
+ postMoneyReceiptInputSchema
21688
+ ]);
21634
21689
  var postReceiptPartSchema = object({
21635
21690
  id: string2(),
21636
21691
  type: string2(),
@@ -21641,8 +21696,10 @@ var postReceiptSchema = object({
21641
21696
  nodeType: string2(),
21642
21697
  parts: array(string2()).optional(),
21643
21698
  partNodes: array(postReceiptPartSchema).optional(),
21644
- about: _enum2(POST_RECEIPT_ABOUT_VALUES).optional(),
21645
- source: string2().optional()
21699
+ about: _enum2([...POST_RECEIPT_ABOUT_VALUES, ...POST_MONEY_RECEIPT_ABOUT_VALUES]).optional(),
21700
+ source: string2().optional(),
21701
+ odoo: object({ openUrl: string2(), account: string2().nullish() }).optional(),
21702
+ undo: object({ items: array(object({ id: string2() }).passthrough()) }).optional()
21646
21703
  });
21647
21704
  var POST_TITLE_MAX = 200;
21648
21705
  var postTitleSchema = string2().trim().min(1).max(POST_TITLE_MAX);
@@ -23608,6 +23665,7 @@ var createMealLogInputSchema = object({
23608
23665
  photoFileId: ulidSchema.nullish(),
23609
23666
  items: array(mealLogItemInputSchema).min(1).max(40)
23610
23667
  }).strict();
23668
+ var logUsualMealInputSchema = object({ mealType: mealLogTypeSchema }).strict();
23611
23669
  var correctMealLogInputSchema = object({
23612
23670
  title: string2().trim().min(1).max(200).optional(),
23613
23671
  eatenAt: exports_coerce.date().optional(),
@@ -23813,7 +23871,10 @@ var FOOD_PATTERN_QUESTION_VALUES = [
23813
23871
  "flagged_meal_symptom",
23814
23872
  "coffee_sleep",
23815
23873
  "kcal_rating",
23816
- "weekly_kcal_weight"
23874
+ "weekly_kcal_weight",
23875
+ "fried_next_day",
23876
+ "skipped_breakfast_lunch",
23877
+ "big_dinner_sleep"
23817
23878
  ];
23818
23879
  var foodPatternQuestionSchema = _enum2(FOOD_PATTERN_QUESTION_VALUES);
23819
23880
  var foodPatternSideSchema = object({
@@ -23828,6 +23889,12 @@ var foodPatternWeekSchema = object({
23828
23889
  averageKcal: number2().nullable(),
23829
23890
  weightChange: number2().nullable()
23830
23891
  });
23892
+ var foodPatternDaySchema = object({
23893
+ day: civilDate,
23894
+ with: boolean3(),
23895
+ hit: boolean3().nullable(),
23896
+ value: number2().nullable()
23897
+ });
23831
23898
  var foodPatternAnswerSchema = object({
23832
23899
  question: foodPatternQuestionSchema,
23833
23900
  title: string2(),
@@ -23841,7 +23908,9 @@ var foodPatternAnswerSchema = object({
23841
23908
  neededDays: number2().int().nonnegative(),
23842
23909
  progress: object({ have: number2().int(), need: number2().int() }),
23843
23910
  examples: array(string2()),
23844
- weeks: array(foodPatternWeekSchema)
23911
+ weeks: array(foodPatternWeekSchema),
23912
+ unit: _enum2(["days", "nights", "weeks"]),
23913
+ behind: array(foodPatternDaySchema)
23845
23914
  });
23846
23915
  var FOOD_TRIAL_NOTE_MAX = 1000;
23847
23916
  var proposeFoodTrialInputSchema = object({
@@ -24661,7 +24730,8 @@ var sortMoneyTransactionInputSchema = object({
24661
24730
  businessShare: moneyBusinessShareSchema.optional(),
24662
24731
  businessStatus: moneySortBusinessStatusSchema.optional(),
24663
24732
  businessNote: moneyBusinessNoteSchema.nullish(),
24664
- taxTag: moneyTaxTagSchema.nullish()
24733
+ taxTag: moneyTaxTagSchema.nullish(),
24734
+ orderItem: string2().trim().min(1).max(200).nullish()
24665
24735
  }).strict();
24666
24736
  var createMoneyRuleInputSchema = object({
24667
24737
  id: ulidSchema,
@@ -25691,8 +25761,9 @@ var runAchievementsSchema = object({
25691
25761
  source: _enum2(["steam", "xbox", "psn", "manual"]).default("manual"),
25692
25762
  total: number2().int().min(0).max(5000).nullish(),
25693
25763
  enabled: boolean3().default(true),
25694
- unlocked: array(object({ name, on: isoDate.nullish(), hint: shortText.nullish() }).strict()).max(5000),
25695
- locked: array(object({ name, hint: shortText.nullish() }).strict()).max(5000).optional()
25764
+ unlocked: array(object({ name, on: isoDate.nullish(), hint: shortText.nullish(), key: ref.nullish() }).strict()).max(5000),
25765
+ locked: array(object({ name, hint: shortText.nullish(), key: ref.nullish() }).strict()).max(5000).optional(),
25766
+ syncedAt: string2().datetime({ offset: true }).nullish()
25696
25767
  }).strict();
25697
25768
  var runRareFindsSchema = object({
25698
25769
  place: shortText.nullish(),
@@ -25911,6 +25982,39 @@ var runsQuerySchema = object({
25911
25982
  theme: runThemeSchema.optional()
25912
25983
  }).strict();
25913
25984
 
25985
+ // ../../packages/schema/src/contracts/runs-steam.ts
25986
+ var steamIdSchema = string2().trim().regex(/^7656119\d{10}$/, "must be a SteamID64 (17 digits, starting 7656119)");
25987
+ var steamApiKeySchema = string2().trim().regex(/^[0-9A-Fa-f]{32}$/, "must be a Steam Web API key (32 letters and digits)");
25988
+ var steamAccountInputSchema = object({ steamId: steamIdSchema, apiKey: steamApiKeySchema }).strict();
25989
+ var steamAccountStatusSchema = object({
25990
+ connected: boolean3(),
25991
+ games: number2().int().nonnegative(),
25992
+ lastSyncedAt: string2().nullable()
25993
+ });
25994
+ var steamSyncInputSchema = object({ gameId: string2().trim().min(1).max(64).optional() }).strict();
25995
+ var steamSyncErrorValues = [
25996
+ "unauthorized",
25997
+ "private",
25998
+ "no_stats",
25999
+ "unavailable",
26000
+ "bad_response"
26001
+ ];
26002
+ var steamSyncErrorSchema = _enum2(steamSyncErrorValues);
26003
+ var steamGameSyncSchema = object({
26004
+ gameId: string2(),
26005
+ gameTitle: string2(),
26006
+ appId: number2().int(),
26007
+ outcome: _enum2(["ok", "failed"]),
26008
+ runs: number2().int().nonnegative(),
26009
+ unlocked: number2().int().nonnegative(),
26010
+ total: number2().int().nonnegative(),
26011
+ error: steamSyncErrorSchema.nullable()
26012
+ });
26013
+ var steamSyncResultSchema = object({
26014
+ syncedAt: string2(),
26015
+ games: array(steamGameSyncSchema)
26016
+ });
26017
+
25914
26018
  // ../../packages/schema/src/contracts/animals.ts
25915
26019
  var animalFormSchema = _enum2(animalForm.enumValues);
25916
26020
  var animalStatusSchema = _enum2(animalStatus.enumValues);
@@ -26403,7 +26507,7 @@ var animalsOverviewSchema = object({
26403
26507
  supplies: array(animalSupplySchema),
26404
26508
  habits: array(animalHabitSchema)
26405
26509
  }),
26406
- comingUp: array(keyDateViewSchema),
26510
+ comingUp: array(keyDateViewSchema.extend({ vet: string2().nullable() })),
26407
26511
  periods: array(periodViewSchema)
26408
26512
  });
26409
26513
  var animalHolidayModeSchema = object({
@@ -26584,7 +26688,8 @@ var moneyTaxEvidenceSchema = object({
26584
26688
  }))
26585
26689
  });
26586
26690
  var moneyOdooPushInputSchema = object({
26587
- note: string2().trim().min(1).max(500).optional()
26691
+ note: string2().trim().min(1).max(500).optional(),
26692
+ account: string2().trim().min(1).max(120).optional()
26588
26693
  }).strict();
26589
26694
  var moneyOdooReceiptSchema = object({
26590
26695
  transactionId: ulidSchema,
@@ -26594,7 +26699,8 @@ var moneyOdooReceiptSchema = object({
26594
26699
  amount: string2(),
26595
26700
  share: moneyBusinessShareSchema,
26596
26701
  attachments: number2().int().nonnegative(),
26597
- alreadyThere: boolean3()
26702
+ alreadyThere: boolean3(),
26703
+ account: string2().nullable().default(null)
26598
26704
  });
26599
26705
  var moneyOdooUndoResultSchema = object({
26600
26706
  transactionId: ulidSchema,
@@ -28299,7 +28405,8 @@ var gameFacetSchema = object({
28299
28405
  platform: string2().min(1).max(120).nullish(),
28300
28406
  coverUrl,
28301
28407
  coverSources: coverSourcesSchema.nullish(),
28302
- completion: number2().int().min(0).max(100).nullish()
28408
+ completion: number2().int().min(0).max(100).nullish(),
28409
+ steamAppId: number2().int().positive().max(99999999).nullish()
28303
28410
  }).strict();
28304
28411
  var musicFacetSchema = object({
28305
28412
  artist: string2().min(1).max(200).nullish(),
@@ -28774,7 +28881,7 @@ function parseCapture2(input, now) {
28774
28881
 
28775
28882
  // src/meta.ts
28776
28883
  var CLI_NAME = "do";
28777
- var VERSION = "1.292.0";
28884
+ var VERSION = "1.294.0";
28778
28885
  var API_PREFIX = "/api/v1";
28779
28886
  var DEFAULT_API_URL = "http://localhost:3001";
28780
28887
 
@@ -33944,6 +34051,24 @@ var COMMAND_SPECS = [
33944
34051
  returns: "RunChangesResult",
33945
34052
  notes: "POST /api/v1/runs/{id}/checklists/{key}/tick. `do runs dex tick <run> 495 496 497`, `do runs dex tick <run> --bulk caught.txt` (up to 5000 ids). A dex the run doesn't have yet is made from the Pok\xE9mon pack's national dex."
33946
34053
  },
34054
+ {
34055
+ path: ["runs", "steam", "status"],
34056
+ summary: "Whether you've linked Steam, how many games have a Steam app id, and the last sync.",
34057
+ args: [],
34058
+ flags: [],
34059
+ scopes: ["collections:read"],
34060
+ returns: "SteamAccountStatus",
34061
+ notes: "GET /api/v1/runs/steam. Steam is linked in the app's Settings; the Steam ID and Web API key are never returned. A game takes part once its `steamAppId` is set."
34062
+ },
34063
+ {
34064
+ path: ["runs", "steam", "sync"],
34065
+ summary: "Sync your Steam achievements into your runs now, as the daily sync does.",
34066
+ args: [],
34067
+ flags: [{ name: "game", type: "string", description: "Only this game item ULID." }],
34068
+ scopes: ["collections:write"],
34069
+ returns: "SteamSyncResult",
34070
+ notes: "POST /api/v1/runs/steam/sync. Writes into each run whose achievements come from Steam or aren't kept yet; runs kept by hand are left alone. Per game: outcome, runs, unlocked, total and the error (unauthorized, private, no_stats, unavailable, bad_response). 409 before Steam is linked."
34071
+ },
33947
34072
  {
33948
34073
  path: ["runs", "sessions", "list"],
33949
34074
  summary: "A run's sessions, newest first, with recaps and change batches.",
@@ -39040,6 +39165,16 @@ var HANDLERS = {
39040
39165
  render: renderRecord
39041
39166
  };
39042
39167
  },
39168
+ "runs steam status": async ({ requireClient }) => ({
39169
+ data: await requireClient().get("/runs/steam"),
39170
+ render: renderRecord
39171
+ }),
39172
+ "runs steam sync": async ({ flags, requireClient }) => {
39173
+ const body = parseInput(steamSyncInputSchema, {
39174
+ ...typeof flags.game === "string" ? { gameId: flags.game } : {}
39175
+ });
39176
+ return { data: await requireClient().post("/runs/steam/sync", body), render: renderRecord };
39177
+ },
39043
39178
  "runs sessions list": async ({ args, requireClient }) => {
39044
39179
  const id = requireArg(args, 0, "run id");
39045
39180
  return { data: await requireClient().get(`/runs/${id}/sessions`), render: renderList };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.292.0",
3
+ "version": "1.294.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",