@robbeverhelst/do 1.403.0 → 1.405.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 +220 -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.403.0";
14423
+ var VERSION = "1.405.0";
14424
14424
  var API_PREFIX = "/api/v1";
14425
14425
  var DEFAULT_API_URL = "http://localhost:3001";
14426
14426
 
@@ -17926,7 +17926,8 @@ var habitEntrySource = pgEnum("habit_entry_source", [
17926
17926
  "ingest",
17927
17927
  "agent"
17928
17928
  ]);
17929
- var habitEntryKind = pgEnum("habit_entry_kind", ["check_in", "skip"]);
17929
+ var habitEntryKind = pgEnum("habit_entry_kind", ["check_in", "skip", "not_needed"]);
17930
+ var habitAnswerType = pgEnum("habit_answer_type", ["yn", "count", "amount", "dur"]);
17930
17931
  var habitSource = pgEnum("habit_source", ["manual", "google_fit", "strava", "github"]);
17931
17932
  var recurrenceMode = pgEnum("recurrence_mode", ["rigid", "flexible"]);
17932
17933
  var recurrenceFreq = pgEnum("recurrence_freq", ["daily", "weekly", "monthly", "yearly"]);
@@ -18011,6 +18012,15 @@ var tasks = pgTable("tasks", {
18011
18012
  index("tasks_tenant_ready_idx").on(t.tenantId, t.readyAt).where(sql`${t.readyAt} IS NOT NULL`),
18012
18013
  check2("tasks_area_xor_project_chk", sql`${t.projectId} IS NULL OR ${t.areaId} IS NULL`)
18013
18014
  ]);
18015
+ var habitGroups = pgTable("habit_groups", {
18016
+ id: text("id").primaryKey(),
18017
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
18018
+ name: text("name").notNull(),
18019
+ icon: text("icon"),
18020
+ position: integer2("position").notNull().default(0),
18021
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
18022
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
18023
+ }, (t) => [index("habit_groups_tenant_idx").on(t.tenantId, t.position)]);
18014
18024
  var habits = pgTable("habits", {
18015
18025
  ...leafColumns(),
18016
18026
  measurementType: habitMeasurementType("measurement_type").notNull(),
@@ -18034,10 +18044,22 @@ var habits = pgTable("habits", {
18034
18044
  eventOffset: text("event_offset"),
18035
18045
  durationMinutes: integer2("duration_minutes"),
18036
18046
  activeMonths: integer2("active_months").array(),
18037
- checklist: boolean4("checklist").notNull().default(false)
18047
+ checklist: boolean4("checklist").notNull().default(false),
18048
+ groupId: text("group_id").references(() => habitGroups.id, { onDelete: "set null" }),
18049
+ answerType: habitAnswerType("answer_type"),
18050
+ unitOne: text("unit_one"),
18051
+ step: doublePrecision("step"),
18052
+ decimals: integer2("decimals"),
18053
+ quickPicks: doublePrecision("quick_picks").array().notNull().default(sql`'{}'::double precision[]`),
18054
+ notNeededReasons: text("not_needed_reasons").array().notNull().default(sql`'{}'::text[]`),
18055
+ skipReasons: text("skip_reasons").array().notNull().default(sql`'{}'::text[]`),
18056
+ notNeededKeepsStreak: boolean4("not_needed_keeps_streak").notNull().default(true)
18038
18057
  }, (t) => [
18039
18058
  index("habits_tenant_idx").on(t.tenantId),
18040
18059
  index("habits_tenant_area_idx").on(t.tenantId, t.areaId),
18060
+ index("habits_tenant_group_idx").on(t.tenantId, t.groupId),
18061
+ check2("habits_decimals_chk", sql`${t.decimals} IS NULL OR ${t.decimals} BETWEEN 0 AND 3`),
18062
+ check2("habits_step_chk", sql`${t.step} IS NULL OR ${t.step} > 0`),
18041
18063
  check2("habits_time_of_day_chk", sql`${t.timeOfDay} IS NULL OR ${t.timeOfDay} IN ('morning', 'midday', 'evening') OR ${t.timeOfDay} ~ '^([01][0-9]|2[0-3]):[0-5][0-9]$'`),
18042
18064
  check2("habits_duration_minutes_chk", sql`${t.durationMinutes} IS NULL OR ${t.durationMinutes} BETWEEN 1 AND 600`)
18043
18065
  ]);
@@ -18054,7 +18076,8 @@ var habitEntries = pgTable("habit_entries", {
18054
18076
  agentId: text("agent_id"),
18055
18077
  userId: text("user_id"),
18056
18078
  note: text("note"),
18057
- matchedName: text("matched_name")
18079
+ matchedName: text("matched_name"),
18080
+ reason: text("reason")
18058
18081
  }, (t) => [
18059
18082
  index("habit_entries_habit_occurred_idx").on(t.habitId, t.occurredAt),
18060
18083
  uniqueIndex("habit_entries_habit_external_uniq").on(t.habitId, t.externalId).where(sql`${t.externalId} IS NOT NULL`)
@@ -19110,6 +19133,7 @@ var habitMeasurementTypeSchema = _enum2(habitMeasurementType.enumValues);
19110
19133
  var habitPeriodSchema = _enum2(habitPeriod.enumValues);
19111
19134
  var habitEntrySourceSchema = _enum2(habitEntrySource.enumValues);
19112
19135
  var habitEntryKindSchema = _enum2(habitEntryKind.enumValues);
19136
+ var habitAnswerTypeSchema = _enum2(habitAnswerType.enumValues);
19113
19137
  var recurrenceModeSchema = _enum2(recurrenceMode.enumValues);
19114
19138
  var recurrenceFreqSchema = _enum2(recurrenceFreq.enumValues);
19115
19139
  var recurrenceUnitSchema = _enum2(recurrenceUnit.enumValues);
@@ -22479,7 +22503,16 @@ var habitSchema = createSelectSchema(habits, {
22479
22503
  eventOffset: string2().nullable().default(null),
22480
22504
  durationMinutes: number2().int().nullable().default(null),
22481
22505
  activeMonths: array(number2().int()).nullable().default(null),
22482
- checklist: boolean2().default(false)
22506
+ checklist: boolean2().default(false),
22507
+ groupId: string2().nullable().default(null),
22508
+ answerType: habitAnswerTypeSchema.nullable().default(null),
22509
+ unitOne: string2().nullable().default(null),
22510
+ step: number2().nullable().default(null),
22511
+ decimals: number2().int().nullable().default(null),
22512
+ quickPicks: array(number2()).default([]),
22513
+ notNeededReasons: array(string2()).default([]),
22514
+ skipReasons: array(string2()).default([]),
22515
+ notNeededKeepsStreak: boolean2().default(true)
22483
22516
  });
22484
22517
  var habitEntrySchema = createSelectSchema(habitEntries, {
22485
22518
  occurredAt: exports_coerce.date(),
@@ -22489,7 +22522,8 @@ var habitEntrySchema = createSelectSchema(habitEntries, {
22489
22522
  kind: habitEntryKindSchema.default("check_in"),
22490
22523
  agentId: string2().nullish(),
22491
22524
  note: string2().nullish(),
22492
- matchedName: string2().nullish()
22525
+ matchedName: string2().nullish(),
22526
+ reason: string2().nullish()
22493
22527
  }).extend({
22494
22528
  by: string2().nullish()
22495
22529
  });
@@ -22532,6 +22566,23 @@ var habitScheduleSchema = discriminatedUnion("kind", [
22532
22566
  })
22533
22567
  ]);
22534
22568
  var eventColumns = { eventSourceId: true, eventMatch: true, eventOffset: true };
22569
+ var HABIT_REASON_MAX = 40;
22570
+ var HABIT_CHOICES_MAX = 8;
22571
+ var habitReasonSchema = string2().trim().max(HABIT_REASON_MAX).transform((reason) => reason === "" ? null : reason);
22572
+ var habitReasonsSchema = array(string2().trim().min(1).max(HABIT_REASON_MAX)).max(HABIT_CHOICES_MAX).refine((list) => new Set(list.map((x) => x.toLowerCase())).size === list.length, {
22573
+ message: "each reason once"
22574
+ });
22575
+ var habitAnswerFields = {
22576
+ groupId: ulidSchema.nullish(),
22577
+ answerType: habitAnswerTypeSchema.nullish(),
22578
+ unitOne: string2().trim().min(1).max(30).nullish(),
22579
+ step: number2().positive().max(1000).nullish(),
22580
+ decimals: number2().int().min(0).max(3).nullish(),
22581
+ quickPicks: array(number2().nonnegative()).max(HABIT_CHOICES_MAX).optional(),
22582
+ notNeededReasons: habitReasonsSchema.optional(),
22583
+ skipReasons: habitReasonsSchema.optional(),
22584
+ notNeededKeepsStreak: boolean2().optional()
22585
+ };
22535
22586
  var createHabitInputSchema = createInsertSchema(habits, {
22536
22587
  id: ulidSchema,
22537
22588
  source: habitSourceSchema.optional(),
@@ -22548,7 +22599,8 @@ var createHabitInputSchema = createInsertSchema(habits, {
22548
22599
  remind: boolean2().optional(),
22549
22600
  durationMinutes: habitDurationMinutesSchema.nullish(),
22550
22601
  activeMonths: habitActiveMonthsSchema.optional(),
22551
- checklist: boolean2().optional()
22602
+ checklist: boolean2().optional(),
22603
+ ...habitAnswerFields
22552
22604
  }).omit({ tenantId: true, recurrenceRuleId: true, retiredAt: true, ...eventColumns }).extend({
22553
22605
  title: string2().min(1),
22554
22606
  schedule: habitScheduleSchema.optional(),
@@ -22568,7 +22620,8 @@ var updateHabitInputSchema = createUpdateSchema(habits, {
22568
22620
  dayTimes: weekdayTimesSchema.nullish(),
22569
22621
  remind: boolean2().optional(),
22570
22622
  durationMinutes: habitDurationMinutesSchema.nullish(),
22571
- activeMonths: habitActiveMonthsSchema.optional()
22623
+ activeMonths: habitActiveMonthsSchema.optional(),
22624
+ ...habitAnswerFields
22572
22625
  }).omit({
22573
22626
  id: true,
22574
22627
  tenantId: true,
@@ -22613,6 +22666,7 @@ var habitStreakSchema = object({
22613
22666
  graceBudget: number2().int().nonnegative(),
22614
22667
  graceRemaining: number2().int().nonnegative(),
22615
22668
  skippedToday: boolean2().default(false),
22669
+ notNeededToday: boolean2().default(false),
22616
22670
  runSince: exports_iso.date().nullable().default(null)
22617
22671
  });
22618
22672
  var habitRoutineRefSchema = object({
@@ -22658,6 +22712,7 @@ var habitHeatmapCellSchema = object({
22658
22712
  value: number2(),
22659
22713
  satisfied: boolean2(),
22660
22714
  rest: boolean2().default(false),
22715
+ notNeeded: boolean2().default(false),
22661
22716
  notes: array(string2()).optional()
22662
22717
  });
22663
22718
  var habitDetailSchema = habitSummarySchema.extend({
@@ -22749,6 +22804,12 @@ var habitCheckInByTitleResultSchema = habitSummarySchema.extend({
22749
22804
  var habitAliasInputSchema = object({ alias: habitAliasSchema }).strict();
22750
22805
  var habitSkipInputSchema = object({
22751
22806
  date: exports_iso.date().optional(),
22807
+ note: habitEntryNoteSchema.nullish(),
22808
+ reason: habitReasonSchema.nullish()
22809
+ }).strict();
22810
+ var habitNotNeededInputSchema = object({
22811
+ date: exports_iso.date().optional(),
22812
+ reason: habitReasonSchema.nullish(),
22752
22813
  note: habitEntryNoteSchema.nullish()
22753
22814
  }).strict();
22754
22815
  var habitPauseInputSchema = object({ until: exports_iso.date().nullish() }).strict();
@@ -30633,13 +30694,19 @@ var foodDayIntakeSchema = object({
30633
30694
  amount: string2().nullable(),
30634
30695
  note: string2().nullable()
30635
30696
  });
30697
+ var foodDayRefSchema = object({
30698
+ id: string2(),
30699
+ brand: string2().nullable(),
30700
+ portions: record(string2(), number2())
30701
+ });
30636
30702
  var foodDayViewSchema = object({
30637
30703
  date: civilDate2,
30638
30704
  logs: array(mealLogViewSchema),
30639
30705
  total: foodDaySchema.nullable(),
30640
30706
  planned: array(plannedMealSchema),
30641
30707
  notes: array(foodDayMealNoteSchema),
30642
- intakes: array(foodDayIntakeSchema)
30708
+ intakes: array(foodDayIntakeSchema),
30709
+ refs: array(foodDayRefSchema).optional()
30643
30710
  });
30644
30711
  var MEAL_PLAN_STATUS_VALUES = ["as_planned", "swapped", "unplanned"];
30645
30712
  var MEAL_AFTER_KIND_VALUES = ["symptom", "episode", "dose", "sleep", "rating"];
@@ -32018,6 +32085,56 @@ var guestOperations = defineOperations({
32018
32085
  }
32019
32086
  });
32020
32087
 
32088
+ // ../../packages/schema/src/contracts/habit-groups.ts
32089
+ var HABIT_GROUP_NAME_MAX = 40;
32090
+ var habitGroupSchema = createSelectSchema(habitGroups, {
32091
+ createdAt: exports_coerce.date(),
32092
+ updatedAt: exports_coerce.date()
32093
+ });
32094
+ var name3 = string2().trim().min(1).max(HABIT_GROUP_NAME_MAX);
32095
+ var icon = string2().trim().regex(/^[a-z0-9-]{1,40}$/, "an icon name: lower-case letters, digits and dashes");
32096
+ var createHabitGroupInputSchema = object({
32097
+ id: ulidSchema,
32098
+ name: name3,
32099
+ icon: icon.nullish(),
32100
+ position: number2().int().nonnegative().optional()
32101
+ }).strict();
32102
+ var updateHabitGroupInputSchema = object({
32103
+ name: name3.optional(),
32104
+ icon: icon.nullable().optional(),
32105
+ position: number2().int().nonnegative().optional()
32106
+ }).strict().refine((x) => Object.keys(x).length > 0, { message: "nothing to change" });
32107
+
32108
+ // ../../packages/schema/src/operations/habit-groups.ts
32109
+ var crud3 = crudOperations({
32110
+ segment: "habit-groups",
32111
+ tag: "Habits",
32112
+ noun: "habit group",
32113
+ read: "habits:read",
32114
+ write: "habits:write",
32115
+ create: createHabitGroupInputSchema,
32116
+ update: updateHabitGroupInputSchema,
32117
+ listQuery: []
32118
+ });
32119
+ var habitGroupOperations = defineOperations({
32120
+ ...crud3,
32121
+ list: {
32122
+ ...crud3.list,
32123
+ description: "The Space's habit groups in their order (`position`, then oldest first): each `{ id, name, icon, position }`. A habit's `groupId` names its group."
32124
+ },
32125
+ create: {
32126
+ ...crud3.create,
32127
+ description: "A new group, `{ id, name, icon?, position? }`: the client mints the ULID; `icon` is an icon name (`sunrise`, `paw`); without a `position` it goes after the last group. A taken id is a 409.",
32128
+ webhook: undefined
32129
+ },
32130
+ update: { ...crud3.update, webhook: undefined },
32131
+ remove: {
32132
+ ...crud3.remove,
32133
+ description: "Delete a group. Its habits stay, ungrouped (their `groupId` becomes null).",
32134
+ webhook: undefined
32135
+ }
32136
+ });
32137
+
32021
32138
  // ../../packages/schema/src/operations/habits.ts
32022
32139
  var item = { itemId: "The item's ULID." };
32023
32140
  var notChecklist = "A habit that isn't a checklist answers 409.";
@@ -32240,7 +32357,7 @@ var habitOperations = defineOperations({
32240
32357
  scopes: ["habits:write"],
32241
32358
  tag: "Habits",
32242
32359
  summary: "Skip a habit",
32243
- description: '"Skip gym today": a neutral rest day (a `skip` entry, value 0), never a miss. The streak treats the period as neutral and spends no grace. `date` (YYYY-MM-DD) defaults to today; an optional `note` says why ("Dentist"). Skipping a skipped day changes nothing but its note. Undo by deleting the skip entry like a check-in. Returns the refreshed habit; fires `habit.updated`.',
32360
+ description: '"Skip gym today": a neutral rest day (a `skip` entry, value 0), never a miss. The streak treats the period as neutral and spends no grace. `date` (YYYY-MM-DD) defaults to today; an optional `reason` is its one-tap reason (one of the habit\'s `skipReasons`, "Away") and `note` says more ("Dentist"). It replaces a Not needed on that day; skipping a skipped day changes nothing but its reason and note. Undo by deleting the skip entry like a check-in. Returns the refreshed habit; fires `habit.updated`.',
32244
32361
  body: habitSkipInputSchema,
32245
32362
  status: 201,
32246
32363
  response: { description: "The refreshed habit." },
@@ -32250,6 +32367,23 @@ var habitOperations = defineOperations({
32250
32367
  },
32251
32368
  webhook: "habit.updated"
32252
32369
  },
32370
+ notNeeded: {
32371
+ method: "post",
32372
+ path: "/habits/{id}/not-needed",
32373
+ scopes: ["habits:write"],
32374
+ tag: "Habits",
32375
+ summary: "Answer a habit Not needed",
32376
+ description: '"The scraps bucket was empty": checked, nothing to do (a `not_needed` entry, value 0). It adds a day to the streak while the habit\'s `notNeededKeepsStreak` is on (the default), and rests like a skip when it\'s off; `streak.notNeededToday` says so. `date` (YYYY-MM-DD) defaults to today; an optional `reason` is its one-tap reason (one of the habit\'s `notNeededReasons`, "Bucket empty") and `note` says more. It replaces a skip on that day; answering a day already not needed changes nothing but its reason and note. Undo by deleting the entry like a check-in. Returns the refreshed habit; fires `habit.updated`.',
32377
+ body: habitNotNeededInputSchema,
32378
+ status: 201,
32379
+ response: { description: "The refreshed habit." },
32380
+ errors: {
32381
+ 400: true,
32382
+ 404: true
32383
+ },
32384
+ webhook: "habit.updated",
32385
+ operationId: "not_needed_habit"
32386
+ },
32253
32387
  pause: {
32254
32388
  method: "post",
32255
32389
  path: "/habits/{id}/pause",
@@ -40830,18 +40964,18 @@ var runPlayStatusValues = [
40830
40964
  "dropped"
40831
40965
  ];
40832
40966
  var runPlayStatusSchema = _enum2(runPlayStatusValues);
40833
- var name3 = string2().trim().min(1).max(200);
40967
+ var name4 = string2().trim().min(1).max(200);
40834
40968
  var text5 = string2().trim().max(2000);
40835
40969
  var shortText2 = string2().trim().max(300);
40836
40970
  var isoDate = string2().regex(/^\d{4}-\d{2}-\d{2}$/, "must be an ISO date (YYYY-MM-DD)");
40837
40971
  var ref = string2().trim().min(1).max(200);
40838
40972
  var runCharacterSchema = object({
40839
- name: name3,
40973
+ name: name4,
40840
40974
  pronoun: _enum2(["he", "she", "they"]).nullish(),
40841
40975
  subtitle: shortText2.nullish(),
40842
40976
  level: number2().int().min(0).max(1e4).nullish(),
40843
40977
  build: shortText2.nullish(),
40844
- stats: array(object({ k: name3, v: union([number2(), shortText2]) }).strict()).max(40).optional(),
40978
+ stats: array(object({ k: name4, v: union([number2(), shortText2]) }).strict()).max(40).optional(),
40845
40979
  traits: array(shortText2).max(20).optional(),
40846
40980
  backstory: text5.nullish(),
40847
40981
  rules: array(shortText2).max(30).optional(),
@@ -40850,12 +40984,12 @@ var runCharacterSchema = object({
40850
40984
  var runArcSchema = object({
40851
40985
  title: shortText2.nullish(),
40852
40986
  chapters: array(object({
40853
- key: name3,
40854
- name: name3,
40987
+ key: name4,
40988
+ name: name4,
40855
40989
  range: shortText2.nullish(),
40856
40990
  moral: text5.nullish()
40857
40991
  }).strict()).max(40),
40858
- current: name3.nullish()
40992
+ current: name4.nullish()
40859
40993
  }).strict();
40860
40994
  var runStepStatusValues = ["done", "now", "todo", "skipped"];
40861
40995
  var runStepStatusSchema = _enum2(runStepStatusValues);
@@ -40868,7 +41002,7 @@ var runQuestStatusValues = ["active", "paused", "planned", "done", "failed"];
40868
41002
  var runQuestStatusSchema = _enum2(runQuestStatusValues);
40869
41003
  var runQuestSchema = object({
40870
41004
  ref: ref.nullish(),
40871
- name: name3,
41005
+ name: name4,
40872
41006
  line: shortText2.nullish(),
40873
41007
  status: runQuestStatusSchema.default("active"),
40874
41008
  objective: text5.nullish(),
@@ -40883,7 +41017,7 @@ var runQuestSchema = object({
40883
41017
  }).strict()).max(40).optional(),
40884
41018
  pausedAt: shortText2.nullish(),
40885
41019
  why: text5.nullish(),
40886
- revisitAt: name3.nullish()
41020
+ revisitAt: name4.nullish()
40887
41021
  }).strict();
40888
41022
  var runNextStepsSchema = object({
40889
41023
  items: array(shortText2.pipe(string2().min(1))).max(3),
@@ -40892,50 +41026,50 @@ var runNextStepsSchema = object({
40892
41026
  }).strict();
40893
41027
  var runChoiceSchema = object({
40894
41028
  ref: ref.nullish(),
40895
- title: name3,
41029
+ title: name4,
40896
41030
  place: shortText2.nullish(),
40897
41031
  status: _enum2(["made", "planned"]).default("made"),
40898
41032
  options: array(shortText2).max(6).optional(),
40899
41033
  why: text5.nullish(),
40900
41034
  consequence: text5.nullish(),
40901
- revisitAt: name3.nullish(),
40902
- chapter: name3.nullish(),
41035
+ revisitAt: name4.nullish(),
41036
+ chapter: name4.nullish(),
40903
41037
  tone: _enum2(["good", "grey", "dark"]).nullish(),
40904
41038
  on: isoDate.nullish()
40905
41039
  }).strict();
40906
41040
  var runHomeSchema = object({
40907
41041
  ref: ref.nullish(),
40908
- name: name3,
41042
+ name: name4,
40909
41043
  role: _enum2(["home", "collector", "storage", "planned", "later"]).default("home"),
40910
41044
  place: shortText2.nullish(),
40911
- upgrades: array(object({ name: name3, done: boolean2().default(false) }).strict()).max(40).optional(),
41045
+ upgrades: array(object({ name: name4, done: boolean2().default(false) }).strict()).max(40).optional(),
40912
41046
  steward: shortText2.nullish(),
40913
41047
  note: text5.nullish()
40914
41048
  }).strict();
40915
41049
  var runPersonSchema = object({
40916
41050
  ref: ref.nullish(),
40917
- name: name3,
41051
+ name: name4,
40918
41052
  role: _enum2(["child", "spouse", "steward", "follower", "pet", "rival", "other"]),
40919
41053
  status: _enum2(["with", "planned", "lost"]).default("with"),
40920
41054
  home: shortText2.nullish(),
40921
41055
  note: text5.nullish()
40922
41056
  }).strict();
40923
41057
  var runMountSchema = object({
40924
- name: name3,
41058
+ name: name4,
40925
41059
  status: _enum2(["with", "planned", "lost"]).default("with"),
40926
41060
  note: text5.nullish()
40927
41061
  }).strict();
40928
41062
  var runUniqueSchema = object({
40929
41063
  ref: ref.nullish(),
40930
- name: name3,
41064
+ name: name4,
40931
41065
  status: _enum2(["have", "now", "want"]).default("have"),
40932
41066
  source: shortText2.nullish(),
40933
41067
  displayAt: shortText2.nullish(),
40934
- set: name3.nullish()
41068
+ set: name4.nullish()
40935
41069
  }).strict();
40936
41070
  var runChecklistSchema = object({
40937
41071
  key: string2().trim().min(1).max(60).regex(/^[a-z0-9][a-z0-9_-]*$/, "must be a lowercase slug"),
40938
- label: name3,
41072
+ label: name4,
40939
41073
  total: number2().int().min(0).max(5000).nullish(),
40940
41074
  items: array(object({ id: ref, label: shortText2.nullish() }).strict()).max(5000).optional(),
40941
41075
  done: array(ref).max(5000),
@@ -40944,7 +41078,7 @@ var runChecklistSchema = object({
40944
41078
  legend: shortText2.nullish()
40945
41079
  }).strict();
40946
41080
  var runTeamMemberSchema = object({
40947
- species: name3,
41081
+ species: name4,
40948
41082
  nick: shortText2.nullish(),
40949
41083
  level: number2().int().min(1).max(100).nullish(),
40950
41084
  nature: shortText2.nullish(),
@@ -40958,8 +41092,8 @@ var runAchievementsSchema = object({
40958
41092
  source: _enum2(["steam", "xbox", "psn", "manual"]).default("manual"),
40959
41093
  total: number2().int().min(0).max(5000).nullish(),
40960
41094
  enabled: boolean2().default(true),
40961
- unlocked: array(object({ name: name3, on: isoDate.nullish(), hint: shortText2.nullish(), key: ref.nullish() }).strict()).max(5000),
40962
- locked: array(object({ name: name3, hint: shortText2.nullish(), key: ref.nullish() }).strict()).max(5000).optional(),
41095
+ unlocked: array(object({ name: name4, on: isoDate.nullish(), hint: shortText2.nullish(), key: ref.nullish() }).strict()).max(5000),
41096
+ locked: array(object({ name: name4, hint: shortText2.nullish(), key: ref.nullish() }).strict()).max(5000).optional(),
40963
41097
  syncedAt: string2().datetime({ offset: true }).nullish()
40964
41098
  }).strict();
40965
41099
  var runRareFindsSchema = object({
@@ -40969,7 +41103,7 @@ var runRareFindsSchema = object({
40969
41103
  }).strict();
40970
41104
  var runInstallSchema = object({
40971
41105
  edition: shortText2.nullish(),
40972
- mods: array(object({ name: name3, url: string2().url().max(2000).nullish() }).strict()).max(200).default([]),
41106
+ mods: array(object({ name: name4, url: string2().url().max(2000).nullish() }).strict()).max(200).default([]),
40973
41107
  savePath: string2().trim().max(500).nullish(),
40974
41108
  lastBackup: isoDate.nullish(),
40975
41109
  notes: text5.nullish()
@@ -40979,7 +41113,7 @@ var runSaveFields = {
40979
41113
  game: _enum2(["skyrim"]).default("skyrim"),
40980
41114
  fileName: shortText2.nullish(),
40981
41115
  saveNumber: number2().int().min(0).max(1e9),
40982
- playerName: name3,
41116
+ playerName: name4,
40983
41117
  level: number2().int().min(0).max(1e4),
40984
41118
  location: shortText2,
40985
41119
  race: shortText2.nullish(),
@@ -41025,7 +41159,7 @@ var runFacetSchema = object({
41025
41159
  install: runInstallSchema.nullish(),
41026
41160
  save: runSaveSchema.nullish(),
41027
41161
  money: object({ goal: shortText2.nullish(), purpose: shortText2.nullish() }).strict().nullish(),
41028
- links: array(object({ label: name3, url: string2().url().max(2000) }).strict()).max(50).optional()
41162
+ links: array(object({ label: name4, url: string2().url().max(2000) }).strict()).max(50).optional()
41029
41163
  }).strict();
41030
41164
  var runListSectionValues = [
41031
41165
  "orderOfPlay",
@@ -41179,12 +41313,12 @@ var runSaveHeaderResultSchema = object({
41179
41313
  var createRunInputSchema = object({
41180
41314
  id: ulidSchema,
41181
41315
  gameId: ulidSchema,
41182
- title: name3,
41316
+ title: name4,
41183
41317
  status: runPlayStatusSchema.optional(),
41184
41318
  facet: runFacetSchema.optional()
41185
41319
  }).strict();
41186
41320
  var updateRunInputSchema = object({
41187
- title: name3.optional(),
41321
+ title: name4.optional(),
41188
41322
  status: runPlayStatusSchema.optional(),
41189
41323
  facet: runFacetSchema.optional()
41190
41324
  }).strict();
@@ -46032,6 +46166,13 @@ var ENTITIES = [
46032
46166
  createInput: "CreateBlockTemplateInput",
46033
46167
  updateInput: "UpdateBlockTemplateInput"
46034
46168
  }),
46169
+ entityFromOperations(habitGroupOperations, {
46170
+ name: "habit-groups",
46171
+ returns: "HabitGroup",
46172
+ listFlags: [],
46173
+ createInput: "CreateHabitGroupInput",
46174
+ updateInput: "UpdateHabitGroupInput"
46175
+ }),
46035
46176
  entityFromOperations({ list: webhookOperations.list, get: webhookOperations.get }, { name: "webhooks", returns: "WebhookSubscription", listFlags: [] })
46036
46177
  ];
46037
46178
  var entityByName = (name) => ENTITIES.find((e) => e.name === name);
@@ -51847,19 +51988,26 @@ var commands22 = [
51847
51988
  name: "note",
51848
51989
  type: "string",
51849
51990
  description: 'Why, if you like ("Dentist"); shows in the log.'
51991
+ },
51992
+ {
51993
+ name: "reason",
51994
+ type: "string",
51995
+ description: `Its one-tap reason, usually one of the habit's skipReasons ("Away").`
51850
51996
  }
51851
51997
  ],
51852
51998
  scopes: [...habitOperations.skip.scopes],
51853
51999
  returns: "HabitSummary",
51854
- notes: `${routeOf(habitOperations.skip)}. The streak treats the period as neutral and spends no grace; the habit leaves Now for the day. Skipping a skipped day changes nothing. Undo: delete the skip entry (\`do habit check-ins <id>\` lists it with kind \`skip\`).`
52000
+ notes: `${routeOf(habitOperations.skip)}. The streak treats the period as neutral and spends no grace; the habit leaves Now for the day. It replaces a Not needed on that day; skipping a skipped day changes nothing but its reason and note. Undo: delete the skip entry (\`do habit check-ins <id>\` lists it with kind \`skip\`).`
51855
52001
  },
51856
52002
  run: async ({ args, flags, requireClient }) => {
51857
52003
  const id = requireArg(args, 0, "habit id");
51858
52004
  const date = flagString(flags, "date");
51859
52005
  const note = flagString(flags, "note");
52006
+ const reason = flagString(flags, "reason");
51860
52007
  const input = parseInput(habitSkipInputSchema, {
51861
52008
  ...date ? { date } : {},
51862
- ...note !== undefined ? { note } : {}
52009
+ ...note !== undefined ? { note } : {},
52010
+ ...reason !== undefined ? { reason } : {}
51863
52011
  });
51864
52012
  return {
51865
52013
  data: await requireClient().post(pathOf(habitOperations.skip, { id }), input),
@@ -51867,6 +52015,40 @@ var commands22 = [
51867
52015
  };
51868
52016
  }
51869
52017
  },
52018
+ {
52019
+ spec: {
52020
+ path: ["habit", "not-needed"],
52021
+ summary: 'Not needed: checked, nothing to do ("the scraps bucket was empty").',
52022
+ args: [{ name: "id", required: true, description: "Habit ULID." }],
52023
+ flags: [
52024
+ { name: "date", type: "string", description: "The day (YYYY-MM-DD); defaults to today." },
52025
+ {
52026
+ name: "reason",
52027
+ type: "string",
52028
+ description: `Its one-tap reason, usually one of the habit's notNeededReasons ("Bucket empty").`
52029
+ },
52030
+ { name: "note", type: "string", description: "More, if you like; shows in the log." }
52031
+ ],
52032
+ scopes: [...habitOperations.notNeeded.scopes],
52033
+ returns: "HabitSummary",
52034
+ notes: `${routeOf(habitOperations.notNeeded)}. It adds a day to the streak while the habit's notNeededKeepsStreak is on (the default) and rests like a skip when it's off. It replaces a skip on that day; answering again changes nothing but its reason and note. Undo: delete the entry (\`do habit check-ins <id>\` lists it with kind \`not_needed\`).`
52035
+ },
52036
+ run: async ({ args, flags, requireClient }) => {
52037
+ const id = requireArg(args, 0, "habit id");
52038
+ const date = flagString(flags, "date");
52039
+ const note = flagString(flags, "note");
52040
+ const reason = flagString(flags, "reason");
52041
+ const input = parseInput(habitNotNeededInputSchema, {
52042
+ ...date ? { date } : {},
52043
+ ...note !== undefined ? { note } : {},
52044
+ ...reason !== undefined ? { reason } : {}
52045
+ });
52046
+ return {
52047
+ data: await requireClient().post(pathOf(habitOperations.notNeeded, { id }), input),
52048
+ render: renderHabit
52049
+ };
52050
+ }
52051
+ },
51870
52052
  {
51871
52053
  spec: {
51872
52054
  path: ["routine", "done"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.403.0",
3
+ "version": "1.405.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",