@robbeverhelst/do 1.28.0 → 1.30.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 +908 -27
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -4517,6 +4517,7 @@ var shoppingItems = pgTable("shopping_items", {
4517
4517
  isChecked: boolean("is_checked").notNull().default(false),
4518
4518
  sortOrder: integer("sort_order").notNull().default(0),
4519
4519
  notes: text("notes"),
4520
+ facet: jsonb("facet").$type(),
4520
4521
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
4521
4522
  }, (t) => [
4522
4523
  index("shopping_items_list_order_idx").on(t.listId, t.sortOrder),
@@ -19580,6 +19581,14 @@ var linkGoogleInputSchema = exports_external.object({
19580
19581
  code: exports_external.string().min(1),
19581
19582
  state: exports_external.string().min(1)
19582
19583
  });
19584
+ // ../../packages/schema/src/contracts/books.ts
19585
+ var bookCoverQuerySchema = exports_external.object({
19586
+ title: exports_external.string().min(1).max(300)
19587
+ });
19588
+ var bookCoverResultSchema = exports_external.object({
19589
+ coverUrl: exports_external.string().url().nullable(),
19590
+ author: exports_external.string().nullable()
19591
+ });
19583
19592
  // ../../packages/schema/src/contracts/tasks.ts
19584
19593
  var taskSchema = createSelectSchema(tasks, {
19585
19594
  scheduledAt: exports_external.coerce.date().nullable(),
@@ -20013,8 +20022,10 @@ var reviewDayStatSchema = exports_external.object({
20013
20022
  var reviewStatsSchema = exports_external.array(reviewDayStatSchema);
20014
20023
  // ../../packages/schema/src/contracts/shopping.ts
20015
20024
  var shoppingListSchema = createSelectSchema(shoppingLists);
20025
+ var itemFacetSchema = exports_external.record(exports_external.string(), exports_external.unknown());
20016
20026
  var shoppingItemSchema = createSelectSchema(shoppingItems, {
20017
- createdAt: exports_external.coerce.date()
20027
+ createdAt: exports_external.coerce.date(),
20028
+ facet: itemFacetSchema.nullable()
20018
20029
  });
20019
20030
  var shoppingItemInputSchema = exports_external.object({
20020
20031
  id: ulidSchema,
@@ -20023,13 +20034,15 @@ var shoppingItemInputSchema = exports_external.object({
20023
20034
  unit: exports_external.string().nullish(),
20024
20035
  isChecked: exports_external.boolean().optional(),
20025
20036
  sortOrder: exports_external.number().int().min(0).optional(),
20026
- notes: exports_external.string().nullish()
20037
+ notes: exports_external.string().nullish(),
20038
+ facet: itemFacetSchema.nullish()
20027
20039
  });
20028
20040
  var createShoppingListInputSchema = exports_external.object({
20029
20041
  id: ulidSchema,
20030
20042
  title: exports_external.string().min(1),
20031
20043
  parentId: ulidSchema.nullish(),
20032
20044
  notes: exports_external.string().nullish(),
20045
+ displayKind: exports_external.string().min(1).optional(),
20033
20046
  items: exports_external.array(shoppingItemInputSchema).optional()
20034
20047
  });
20035
20048
  var updateShoppingListInputSchema = exports_external.object({
@@ -20041,6 +20054,7 @@ var updateShoppingListInputSchema = exports_external.object({
20041
20054
  var shoppingListViewSchema = shoppingListSchema.extend({
20042
20055
  title: exports_external.string(),
20043
20056
  parentId: ulidSchema.nullable(),
20057
+ displayKind: exports_external.string(),
20044
20058
  createdAt: exports_external.coerce.date(),
20045
20059
  updatedAt: exports_external.coerce.date(),
20046
20060
  deletedAt: exports_external.coerce.date().nullable(),
@@ -21062,8 +21076,33 @@ function parseCapture(input) {
21062
21076
  const title = input.replace(TAG_RE, " ").replace(PRIORITY_RE, " ").replace(AREA_RE, " ").replace(/\s+/g, " ").trim();
21063
21077
  return { title, tags, ...priority ? { priority } : {}, ...area ? { area } : {} };
21064
21078
  }
21079
+ // ../../packages/schema/src/presets/facets.ts
21080
+ var MEDIA_SHELF_DISPLAY_KIND = "media-shelf";
21081
+ var bookStatusValues = ["to-read", "reading", "read"];
21082
+ var bookStatusSchema = exports_external.enum(bookStatusValues);
21083
+ var mediaShelfFacetSchema = exports_external.object({
21084
+ author: exports_external.string().min(1).max(200).nullish(),
21085
+ coverUrl: exports_external.string().url().max(2048).nullish(),
21086
+ status: bookStatusSchema.default("to-read"),
21087
+ rating: exports_external.number().int().min(1).max(5).nullish()
21088
+ }).strict();
21089
+ var facetSchemasByDisplayKind = {
21090
+ [MEDIA_SHELF_DISPLAY_KIND]: mediaShelfFacetSchema
21091
+ };
21065
21092
  // ../../packages/schema/src/presets/recipe.ts
21066
- var presetEntitySchema = exports_external.enum(["habit", "list", "inventory"]);
21093
+ var presetEntitySchema = exports_external.enum([
21094
+ "habit",
21095
+ "list",
21096
+ "inventory",
21097
+ "library",
21098
+ "routine",
21099
+ "area",
21100
+ "project",
21101
+ "recipe",
21102
+ "contact",
21103
+ "challenge",
21104
+ "automation"
21105
+ ]);
21067
21106
  var recipeNodeBase = {
21068
21107
  ref: exports_external.string().min(1),
21069
21108
  parentRef: exports_external.string().min(1).nullish()
@@ -21082,13 +21121,15 @@ var recipeShoppingItemSchema = exports_external.object({
21082
21121
  title: exports_external.string().min(1),
21083
21122
  quantity: exports_external.number().positive().nullish(),
21084
21123
  unit: exports_external.string().min(1).nullish(),
21085
- notes: exports_external.string().min(1).nullish()
21124
+ notes: exports_external.string().min(1).nullish(),
21125
+ facet: itemFacetSchema.nullish()
21086
21126
  });
21087
21127
  var recipeShoppingListNodeSchema = exports_external.object({
21088
21128
  ...recipeNodeBase,
21089
21129
  kind: exports_external.literal("shopping_list"),
21090
21130
  title: exports_external.string().min(1),
21091
21131
  notes: exports_external.string().min(1).nullish(),
21132
+ displayKind: exports_external.string().min(1).optional(),
21092
21133
  items: exports_external.array(recipeShoppingItemSchema).optional()
21093
21134
  });
21094
21135
  var recipeInventoryNodeSchema = exports_external.object({
@@ -21101,10 +21142,89 @@ var recipeInventoryNodeSchema = exports_external.object({
21101
21142
  location: exports_external.string().min(1).nullish(),
21102
21143
  lowStockThreshold: exports_external.number().min(0).nullish()
21103
21144
  });
21145
+ var recipeRoutineStepSchema = exports_external.object({
21146
+ title: exports_external.string().min(1),
21147
+ durationMinutes: exports_external.number().int().positive().nullish(),
21148
+ notes: exports_external.string().min(1).nullish()
21149
+ });
21150
+ var recipeRoutineNodeSchema = exports_external.object({
21151
+ ...recipeNodeBase,
21152
+ kind: exports_external.literal("routine"),
21153
+ title: exports_external.string().min(1),
21154
+ routineKind: routineKindSchema.optional(),
21155
+ notes: exports_external.string().min(1).nullish(),
21156
+ steps: exports_external.array(recipeRoutineStepSchema).optional()
21157
+ });
21158
+ var recipeAreaNodeSchema = exports_external.object({
21159
+ ...recipeNodeBase,
21160
+ kind: exports_external.literal("area"),
21161
+ title: exports_external.string().min(1),
21162
+ color: areaColorSchema.optional(),
21163
+ icon: exports_external.string().min(1).nullish(),
21164
+ reviewCadence: reviewCadenceSchema.nullish()
21165
+ });
21166
+ var recipeProjectNodeSchema = exports_external.object({
21167
+ ...recipeNodeBase,
21168
+ kind: exports_external.literal("project"),
21169
+ title: exports_external.string().min(1),
21170
+ status: projectStatusSchema.optional(),
21171
+ notes: exports_external.string().min(1).nullish(),
21172
+ milestones: exports_external.array(exports_external.object({ title: exports_external.string().min(1) })).optional()
21173
+ });
21174
+ var recipeIngredientItemSchema = exports_external.object({
21175
+ name: exports_external.string().min(1),
21176
+ quantity: exports_external.number().positive().nullish(),
21177
+ unit: exports_external.string().min(1).nullish()
21178
+ });
21179
+ var recipeRecipeNodeSchema = exports_external.object({
21180
+ ...recipeNodeBase,
21181
+ kind: exports_external.literal("recipe"),
21182
+ title: exports_external.string().min(1),
21183
+ description: exports_external.string().min(1).nullish(),
21184
+ instructions: exports_external.string().min(1).nullish(),
21185
+ servings: exports_external.number().int().positive().nullish(),
21186
+ prepMinutes: exports_external.number().int().min(0).nullish(),
21187
+ cookMinutes: exports_external.number().int().min(0).nullish(),
21188
+ tags: exports_external.array(exports_external.string().min(1)).optional(),
21189
+ ingredients: exports_external.array(recipeIngredientItemSchema).optional()
21190
+ });
21191
+ var recipeContactNodeSchema = exports_external.object({
21192
+ ...recipeNodeBase,
21193
+ kind: exports_external.literal("contact"),
21194
+ title: exports_external.string().min(1),
21195
+ company: exports_external.string().min(1).nullish(),
21196
+ notes: exports_external.string().min(1).nullish(),
21197
+ tags: exports_external.array(exports_external.string().min(1)).optional()
21198
+ });
21199
+ var recipeChallengeNodeSchema = exports_external.object({
21200
+ ...recipeNodeBase,
21201
+ kind: exports_external.literal("challenge"),
21202
+ title: exports_external.string().min(1),
21203
+ description: exports_external.string().min(1).nullish(),
21204
+ metric: exports_external.string().min(1),
21205
+ target: exports_external.number().int().positive(),
21206
+ durationDays: exports_external.number().int().positive()
21207
+ });
21208
+ var recipeAutomationNodeSchema = exports_external.object({
21209
+ ...recipeNodeBase,
21210
+ kind: exports_external.literal("automation"),
21211
+ name: exports_external.string().min(1),
21212
+ enabled: exports_external.boolean().optional(),
21213
+ trigger: automationTriggerSchema,
21214
+ condition: automationConditionSchema.nullish(),
21215
+ action: automationActionSchema
21216
+ });
21104
21217
  var recipeNodeSchema = exports_external.discriminatedUnion("kind", [
21105
21218
  recipeHabitNodeSchema,
21106
21219
  recipeShoppingListNodeSchema,
21107
- recipeInventoryNodeSchema
21220
+ recipeInventoryNodeSchema,
21221
+ recipeRoutineNodeSchema,
21222
+ recipeAreaNodeSchema,
21223
+ recipeProjectNodeSchema,
21224
+ recipeRecipeNodeSchema,
21225
+ recipeContactNodeSchema,
21226
+ recipeChallengeNodeSchema,
21227
+ recipeAutomationNodeSchema
21108
21228
  ]);
21109
21229
  var presetRecipeSchema = exports_external.object({
21110
21230
  nodes: exports_external.array(recipeNodeSchema).min(1)
@@ -21118,6 +21238,7 @@ var presetSchema = exports_external.object({
21118
21238
  color: exports_external.string().regex(/^#[0-9a-fA-F]{6}$/),
21119
21239
  category: exports_external.string().min(1),
21120
21240
  displayKind: exports_external.string().min(1).optional(),
21241
+ featured: exports_external.boolean().optional(),
21121
21242
  recipe: presetRecipeSchema
21122
21243
  });
21123
21244
  var presetInstallResultSchema = exports_external.object({
@@ -21126,6 +21247,7 @@ var presetInstallResultSchema = exports_external.object({
21126
21247
  nodeIds: exports_external.array(exports_external.string()),
21127
21248
  nodeCount: exports_external.number().int().nonnegative()
21128
21249
  });
21250
+ var MS_PER_DAY = 24 * 60 * 60 * 1000;
21129
21251
  // ../../packages/schema/src/presets/catalog.ts
21130
21252
  var habitPresets = [
21131
21253
  {
@@ -21137,6 +21259,7 @@ var habitPresets = [
21137
21259
  color: "#38bdf8",
21138
21260
  category: "Health",
21139
21261
  displayKind: "water-cup",
21262
+ featured: true,
21140
21263
  recipe: {
21141
21264
  nodes: [
21142
21265
  {
@@ -21431,16 +21554,6 @@ var habitPresets = [
21431
21554
  ];
21432
21555
  var shoppingItems2 = (...titles) => titles.map((title) => ({ title }));
21433
21556
  var listPresetDefs = [
21434
- {
21435
- key: "books-to-read",
21436
- name: "Books to Read",
21437
- description: "Your reading queue.",
21438
- icon: "\uD83D\uDCDA",
21439
- color: "#f59e0b",
21440
- category: "Reading",
21441
- title: "Books to Read",
21442
- items: ["Atomic Habits", "Deep Work", "The Pragmatic Programmer"]
21443
- },
21444
21557
  {
21445
21558
  key: "watchlist",
21446
21559
  name: "Watchlist",
@@ -21522,20 +21635,58 @@ var listPresetDefs = [
21522
21635
  items: ["Change HVAC filter", "Clean gutters", "Test smoke alarms", "Descale kettle"]
21523
21636
  }
21524
21637
  ];
21525
- var shoppingListPresets = listPresetDefs.map((def) => ({
21526
- key: def.key,
21527
- entity: "list",
21528
- name: def.name,
21529
- description: def.description,
21530
- icon: def.icon,
21531
- color: def.color,
21532
- category: def.category,
21638
+ var booksToRead = [
21639
+ { title: "Atomic Habits", author: "James Clear" },
21640
+ { title: "Deep Work", author: "Cal Newport" },
21641
+ { title: "The Pragmatic Programmer", author: "Andrew Hunt" }
21642
+ ];
21643
+ var booksToReadPreset = {
21644
+ key: "books-to-read",
21645
+ entity: "library",
21646
+ name: "Books to Read",
21647
+ description: "Your reading queue \u2014 covers, status and ratings.",
21648
+ icon: "\uD83D\uDCDA",
21649
+ color: "#f59e0b",
21650
+ category: "Reading",
21651
+ displayKind: MEDIA_SHELF_DISPLAY_KIND,
21533
21652
  recipe: {
21534
21653
  nodes: [
21535
- { ref: "list", kind: "shopping_list", title: def.title, items: shoppingItems2(...def.items) }
21654
+ {
21655
+ ref: "list",
21656
+ kind: "shopping_list",
21657
+ title: "Books to Read",
21658
+ displayKind: MEDIA_SHELF_DISPLAY_KIND,
21659
+ items: booksToRead.map((book) => ({
21660
+ title: book.title,
21661
+ facet: { author: book.author, status: "to-read" }
21662
+ }))
21663
+ }
21536
21664
  ]
21537
21665
  }
21538
- }));
21666
+ };
21667
+ var shoppingListPresets = [
21668
+ booksToReadPreset,
21669
+ ...listPresetDefs.map((def) => ({
21670
+ key: def.key,
21671
+ entity: "list",
21672
+ name: def.name,
21673
+ description: def.description,
21674
+ icon: def.icon,
21675
+ color: def.color,
21676
+ category: def.category,
21677
+ featured: def.key === "groceries",
21678
+ recipe: {
21679
+ nodes: [
21680
+ {
21681
+ ref: "list",
21682
+ kind: "shopping_list",
21683
+ title: def.title,
21684
+ items: shoppingItems2(...def.items)
21685
+ }
21686
+ ]
21687
+ }
21688
+ }))
21689
+ ];
21539
21690
  var pantryStaples = [
21540
21691
  { title: "Rice", category: "Grains", unit: "kg", threshold: 1 },
21541
21692
  { title: "Pasta", category: "Grains", unit: "boxes", threshold: 2 },
@@ -21570,10 +21721,740 @@ var inventoryPresets = [
21570
21721
  }
21571
21722
  }
21572
21723
  ];
21724
+ var routinePresetDefs = [
21725
+ {
21726
+ key: "morning-routine",
21727
+ name: "Morning Routine",
21728
+ description: "Start the day with intention.",
21729
+ icon: "\uD83C\uDF05",
21730
+ color: "#f59e0b",
21731
+ category: "Daily",
21732
+ displayKind: "routine-checklist",
21733
+ steps: ["Make the bed", "Drink a glass of water", "Stretch", "Plan the day"]
21734
+ },
21735
+ {
21736
+ key: "evening-wind-down",
21737
+ name: "Evening Wind-Down",
21738
+ description: "Ease into a restful night.",
21739
+ icon: "\uD83C\uDF19",
21740
+ color: "#818cf8",
21741
+ category: "Daily",
21742
+ steps: ["Dim the lights", "Tidy up", "Read a few pages", "Lights out"]
21743
+ },
21744
+ {
21745
+ key: "deep-work-block",
21746
+ name: "Deep Work Block",
21747
+ description: "Set up for focused, distraction-free work.",
21748
+ icon: "\uD83C\uDFAF",
21749
+ color: "#a78bfa",
21750
+ category: "Work",
21751
+ steps: ["Silence notifications", "Pick one task", "Start a 50-min timer", "Take a break"]
21752
+ },
21753
+ {
21754
+ key: "gym-session",
21755
+ name: "Gym Session",
21756
+ description: "A repeatable workout flow.",
21757
+ icon: "\uD83C\uDFCB\uFE0F",
21758
+ color: "#fb7185",
21759
+ category: "Fitness",
21760
+ steps: ["Warm up", "Main lifts", "Accessory work", "Cool down & stretch"]
21761
+ },
21762
+ {
21763
+ key: "weekly-review",
21764
+ name: "Weekly Review",
21765
+ description: "Close the week and set up the next.",
21766
+ icon: "\uD83D\uDDD3\uFE0F",
21767
+ color: "#34d399",
21768
+ category: "Work",
21769
+ steps: ["Clear the inbox", "Review last week", "Check goals", "Plan next week"]
21770
+ },
21771
+ {
21772
+ key: "leaving-the-house",
21773
+ name: "Leaving the House",
21774
+ description: "Never forget the essentials.",
21775
+ icon: "\uD83D\uDEAA",
21776
+ color: "#38bdf8",
21777
+ category: "Daily",
21778
+ steps: ["Keys", "Wallet", "Phone", "Lock the door"]
21779
+ },
21780
+ {
21781
+ key: "skincare-routine",
21782
+ name: "Skincare AM/PM",
21783
+ description: "A simple morning and night skincare flow.",
21784
+ icon: "\uD83E\uDDF4",
21785
+ color: "#f472b6",
21786
+ category: "Self-care",
21787
+ steps: ["Cleanse", "Treat", "Moisturise", "SPF (AM only)"]
21788
+ },
21789
+ {
21790
+ key: "shutdown-ritual",
21791
+ name: "Shutdown Ritual",
21792
+ description: "End the workday cleanly.",
21793
+ icon: "\uD83D\uDD0C",
21794
+ color: "#a78bfa",
21795
+ category: "Work",
21796
+ steps: ["Review what got done", "Note tomorrow's top task", "Close all tabs", "Step away"]
21797
+ }
21798
+ ];
21799
+ var routinePresets = routinePresetDefs.map((def) => ({
21800
+ key: def.key,
21801
+ entity: "routine",
21802
+ name: def.name,
21803
+ description: def.description,
21804
+ icon: def.icon,
21805
+ color: def.color,
21806
+ category: def.category,
21807
+ ...def.displayKind ? { displayKind: def.displayKind } : {},
21808
+ featured: def.key === "morning-routine",
21809
+ recipe: {
21810
+ nodes: [
21811
+ {
21812
+ ref: "routine",
21813
+ kind: "routine",
21814
+ title: def.name,
21815
+ steps: def.steps.map((title) => ({ title }))
21816
+ }
21817
+ ]
21818
+ }
21819
+ }));
21820
+ var areaBundleDefs = [
21821
+ {
21822
+ key: "life-setup",
21823
+ name: "Life Setup",
21824
+ description: "Nine areas of responsibility to organise your whole life.",
21825
+ icon: "\uD83C\uDF31",
21826
+ color: "#34d399",
21827
+ areas: [
21828
+ { title: "Health", color: "green", icon: "heart-pulse" },
21829
+ { title: "Finances", color: "amber", icon: "wallet" },
21830
+ { title: "Career", color: "blue", icon: "briefcase" },
21831
+ { title: "Relationships", color: "rose", icon: "users" },
21832
+ { title: "Home", color: "teal", icon: "house" },
21833
+ { title: "Personal Growth", color: "purple", icon: "sprout" },
21834
+ { title: "Recreation", color: "amber", icon: "gamepad-2" },
21835
+ { title: "Admin", color: "slate", icon: "file-text" },
21836
+ { title: "Community", color: "red", icon: "hand-heart" }
21837
+ ]
21838
+ },
21839
+ {
21840
+ key: "student-life",
21841
+ name: "Student Life",
21842
+ description: "Keep coursework, exams and the rest of life in balance.",
21843
+ icon: "\uD83C\uDF93",
21844
+ color: "#38bdf8",
21845
+ areas: [
21846
+ { title: "Coursework", color: "blue", icon: "book-open" },
21847
+ { title: "Exams", color: "red", icon: "graduation-cap" },
21848
+ { title: "Finances", color: "amber", icon: "wallet" },
21849
+ { title: "Social", color: "rose", icon: "users" },
21850
+ { title: "Health", color: "green", icon: "heart-pulse" },
21851
+ { title: "Career Prep", color: "purple", icon: "briefcase" }
21852
+ ]
21853
+ },
21854
+ {
21855
+ key: "founder",
21856
+ name: "Founder",
21857
+ description: "The hats a founder wears, as areas to steward.",
21858
+ icon: "\uD83D\uDE80",
21859
+ color: "#a78bfa",
21860
+ areas: [
21861
+ { title: "Product", color: "purple", icon: "box" },
21862
+ { title: "Sales", color: "green", icon: "trending-up" },
21863
+ { title: "Fundraising", color: "amber", icon: "banknote" },
21864
+ { title: "Team", color: "blue", icon: "users" },
21865
+ { title: "Finances", color: "slate", icon: "wallet" },
21866
+ { title: "Personal", color: "rose", icon: "heart" }
21867
+ ]
21868
+ },
21869
+ {
21870
+ key: "new-parent",
21871
+ name: "New Parent",
21872
+ description: "Stay on top of life with a newborn.",
21873
+ icon: "\uD83C\uDF7C",
21874
+ color: "#f472b6",
21875
+ areas: [
21876
+ { title: "Baby Care", color: "rose", icon: "baby" },
21877
+ { title: "Health", color: "green", icon: "heart-pulse" },
21878
+ { title: "Home", color: "teal", icon: "house" },
21879
+ { title: "Finances", color: "amber", icon: "wallet" },
21880
+ { title: "Relationship", color: "purple", icon: "heart" },
21881
+ { title: "Self-care", color: "blue", icon: "sparkles" }
21882
+ ]
21883
+ }
21884
+ ];
21885
+ var areaPresets = areaBundleDefs.map((def) => ({
21886
+ key: def.key,
21887
+ entity: "area",
21888
+ name: def.name,
21889
+ description: def.description,
21890
+ icon: def.icon,
21891
+ color: def.color,
21892
+ category: "Life Setup",
21893
+ featured: def.key === "life-setup",
21894
+ recipe: {
21895
+ nodes: def.areas.map((area, index2) => ({
21896
+ ref: `area-${index2}`,
21897
+ kind: "area",
21898
+ title: area.title,
21899
+ color: area.color,
21900
+ icon: area.icon
21901
+ }))
21902
+ }
21903
+ }));
21904
+ var projectPresetDefs = [
21905
+ {
21906
+ key: "plan-a-trip",
21907
+ name: "Plan a Trip",
21908
+ description: "From idea to itinerary.",
21909
+ icon: "\uD83E\uDDF3",
21910
+ color: "#38bdf8",
21911
+ category: "Personal",
21912
+ milestones: ["Pick dates & destination", "Book flights", "Book stay", "Plan itinerary", "Pack"]
21913
+ },
21914
+ {
21915
+ key: "job-search",
21916
+ name: "Job Search",
21917
+ description: "Run a focused job hunt.",
21918
+ icon: "\uD83D\uDCBC",
21919
+ color: "#a78bfa",
21920
+ category: "Career",
21921
+ milestones: ["Update CV", "Build a target list", "Apply", "Interview prep", "Negotiate offer"]
21922
+ },
21923
+ {
21924
+ key: "move-house",
21925
+ name: "Move House",
21926
+ description: "Keep a move from overwhelming you.",
21927
+ icon: "\uD83D\uDCE6",
21928
+ color: "#f59e0b",
21929
+ category: "Home",
21930
+ milestones: ["Declutter", "Book movers", "Pack room by room", "Change address", "Unpack"]
21931
+ },
21932
+ {
21933
+ key: "side-project",
21934
+ name: "Launch a Side Project",
21935
+ description: "Ship something on the side.",
21936
+ icon: "\uD83D\uDEE0\uFE0F",
21937
+ color: "#34d399",
21938
+ category: "Career",
21939
+ milestones: ["Define the MVP", "Build it", "Test with users", "Launch", "Gather feedback"]
21940
+ },
21941
+ {
21942
+ key: "plan-an-event",
21943
+ name: "Plan an Event",
21944
+ description: "Pull off a gathering without the stress.",
21945
+ icon: "\uD83C\uDF89",
21946
+ color: "#fb7185",
21947
+ category: "Personal",
21948
+ milestones: [
21949
+ "Set date & budget",
21950
+ "Invite guests",
21951
+ "Book venue",
21952
+ "Order food",
21953
+ "Day-of run sheet"
21954
+ ]
21955
+ },
21956
+ {
21957
+ key: "learn-a-skill",
21958
+ name: "Learn a Skill",
21959
+ description: "Go from beginner to capable.",
21960
+ icon: "\uD83D\uDCDA",
21961
+ color: "#f59e0b",
21962
+ category: "Growth",
21963
+ milestones: [
21964
+ "Pick a resource",
21965
+ "Daily practice",
21966
+ "Build a project",
21967
+ "Get feedback",
21968
+ "Teach someone"
21969
+ ]
21970
+ }
21971
+ ];
21972
+ var projectPresets = projectPresetDefs.map((def) => ({
21973
+ key: def.key,
21974
+ entity: "project",
21975
+ name: def.name,
21976
+ description: def.description,
21977
+ icon: def.icon,
21978
+ color: def.color,
21979
+ category: def.category,
21980
+ featured: def.key === "plan-a-trip",
21981
+ recipe: {
21982
+ nodes: [
21983
+ {
21984
+ ref: "project",
21985
+ kind: "project",
21986
+ title: def.name,
21987
+ milestones: def.milestones.map((title) => ({ title }))
21988
+ }
21989
+ ]
21990
+ }
21991
+ }));
21992
+ var recipeNode = (def) => ({
21993
+ ref: def.ref,
21994
+ kind: "recipe",
21995
+ title: def.title,
21996
+ ...def.servings ? { servings: def.servings } : {},
21997
+ ...def.tags ? { tags: def.tags } : {},
21998
+ ingredients: def.ingredients.map((name) => ({ name }))
21999
+ });
22000
+ var mealPresets = [
22001
+ {
22002
+ key: "weeknight-dinners",
22003
+ entity: "recipe",
22004
+ name: "Weeknight Dinners",
22005
+ description: "Three fast, no-fuss dinners.",
22006
+ icon: "\uD83C\uDF5D",
22007
+ color: "#fb7185",
22008
+ category: "Recipes",
22009
+ featured: true,
22010
+ recipe: {
22011
+ nodes: [
22012
+ recipeNode({
22013
+ ref: "r1",
22014
+ title: "One-Pan Pasta",
22015
+ servings: 2,
22016
+ ingredients: ["Pasta", "Cherry tomatoes", "Garlic", "Olive oil", "Basil"],
22017
+ tags: ["quick"]
22018
+ }),
22019
+ recipeNode({
22020
+ ref: "r2",
22021
+ title: "Sheet-Pan Chicken & Veg",
22022
+ servings: 4,
22023
+ ingredients: ["Chicken thighs", "Broccoli", "Potatoes", "Olive oil", "Paprika"],
22024
+ tags: ["quick"]
22025
+ }),
22026
+ recipeNode({
22027
+ ref: "r3",
22028
+ title: "Black Bean Tacos",
22029
+ servings: 3,
22030
+ ingredients: ["Tortillas", "Black beans", "Avocado", "Lime", "Cilantro"],
22031
+ tags: ["quick", "vegetarian"]
22032
+ })
22033
+ ]
22034
+ }
22035
+ },
22036
+ {
22037
+ key: "meal-prep-sunday",
22038
+ entity: "recipe",
22039
+ name: "Meal Prep Sunday",
22040
+ description: "Two batch recipes plus the grocery list to shop for them.",
22041
+ icon: "\uD83E\uDD61",
22042
+ color: "#34d399",
22043
+ category: "Recipes",
22044
+ recipe: {
22045
+ nodes: [
22046
+ recipeNode({
22047
+ ref: "r1",
22048
+ title: "Big-Batch Chili",
22049
+ servings: 6,
22050
+ ingredients: ["Ground beef", "Kidney beans", "Canned tomatoes", "Onion", "Chili powder"],
22051
+ tags: ["meal-prep"]
22052
+ }),
22053
+ recipeNode({
22054
+ ref: "r2",
22055
+ title: "Roasted Veg & Grains",
22056
+ servings: 6,
22057
+ ingredients: ["Quinoa", "Sweet potato", "Chickpeas", "Bell pepper", "Tahini"],
22058
+ tags: ["meal-prep", "vegetarian"]
22059
+ }),
22060
+ {
22061
+ ref: "groceries",
22062
+ kind: "shopping_list",
22063
+ title: "Meal Prep Groceries",
22064
+ items: [
22065
+ { title: "Ground beef" },
22066
+ { title: "Kidney beans" },
22067
+ { title: "Canned tomatoes" },
22068
+ { title: "Quinoa" },
22069
+ { title: "Sweet potato" },
22070
+ { title: "Chickpeas" }
22071
+ ]
22072
+ }
22073
+ ]
22074
+ }
22075
+ },
22076
+ {
22077
+ key: "smoothies",
22078
+ entity: "recipe",
22079
+ name: "Smoothies",
22080
+ description: "Three blend-and-go smoothies.",
22081
+ icon: "\uD83E\uDD64",
22082
+ color: "#f472b6",
22083
+ category: "Recipes",
22084
+ recipe: {
22085
+ nodes: [
22086
+ recipeNode({
22087
+ ref: "r1",
22088
+ title: "Green Smoothie",
22089
+ servings: 1,
22090
+ ingredients: ["Spinach", "Banana", "Almond milk", "Peanut butter"]
22091
+ }),
22092
+ recipeNode({
22093
+ ref: "r2",
22094
+ title: "Berry Blast",
22095
+ servings: 1,
22096
+ ingredients: ["Mixed berries", "Greek yogurt", "Honey", "Oats"]
22097
+ }),
22098
+ recipeNode({
22099
+ ref: "r3",
22100
+ title: "Tropical Smoothie",
22101
+ servings: 1,
22102
+ ingredients: ["Mango", "Pineapple", "Coconut water", "Lime"]
22103
+ })
22104
+ ]
22105
+ }
22106
+ },
22107
+ {
22108
+ key: "high-protein-pack",
22109
+ entity: "recipe",
22110
+ name: "High-Protein Pack",
22111
+ description: "Protein-forward meals to fuel training.",
22112
+ icon: "\uD83D\uDCAA",
22113
+ color: "#fb7185",
22114
+ category: "Recipes",
22115
+ recipe: {
22116
+ nodes: [
22117
+ recipeNode({
22118
+ ref: "r1",
22119
+ title: "Chicken & Rice Bowl",
22120
+ servings: 2,
22121
+ ingredients: ["Chicken breast", "Rice", "Broccoli", "Soy sauce"],
22122
+ tags: ["high-protein"]
22123
+ }),
22124
+ recipeNode({
22125
+ ref: "r2",
22126
+ title: "Egg & Oats Breakfast",
22127
+ servings: 1,
22128
+ ingredients: ["Eggs", "Oats", "Cottage cheese", "Berries"],
22129
+ tags: ["high-protein"]
22130
+ })
22131
+ ]
22132
+ }
22133
+ },
22134
+ {
22135
+ key: "vegetarian-pack",
22136
+ entity: "recipe",
22137
+ name: "Vegetarian Pack",
22138
+ description: "Meat-free meals that satisfy.",
22139
+ icon: "\uD83E\uDD57",
22140
+ color: "#34d399",
22141
+ category: "Recipes",
22142
+ recipe: {
22143
+ nodes: [
22144
+ recipeNode({
22145
+ ref: "r1",
22146
+ title: "Lentil Curry",
22147
+ servings: 4,
22148
+ ingredients: ["Red lentils", "Coconut milk", "Spinach", "Curry powder", "Onion"],
22149
+ tags: ["vegetarian"]
22150
+ }),
22151
+ recipeNode({
22152
+ ref: "r2",
22153
+ title: "Halloumi Salad",
22154
+ servings: 2,
22155
+ ingredients: ["Halloumi", "Mixed greens", "Cherry tomatoes", "Cucumber", "Olive oil"],
22156
+ tags: ["vegetarian"]
22157
+ })
22158
+ ]
22159
+ }
22160
+ },
22161
+ {
22162
+ key: "budget-pack",
22163
+ entity: "recipe",
22164
+ name: "Budget Pack",
22165
+ description: "Cheap, filling meals that stretch the grocery bill.",
22166
+ icon: "\uD83D\uDCB0",
22167
+ color: "#f59e0b",
22168
+ category: "Recipes",
22169
+ recipe: {
22170
+ nodes: [
22171
+ recipeNode({
22172
+ ref: "r1",
22173
+ title: "Rice & Beans",
22174
+ servings: 4,
22175
+ ingredients: ["Rice", "Black beans", "Onion", "Cumin", "Garlic"],
22176
+ tags: ["budget"]
22177
+ }),
22178
+ recipeNode({
22179
+ ref: "r2",
22180
+ title: "Pasta Aglio e Olio",
22181
+ servings: 2,
22182
+ ingredients: ["Pasta", "Garlic", "Olive oil", "Chili flakes", "Parsley"],
22183
+ tags: ["budget"]
22184
+ })
22185
+ ]
22186
+ }
22187
+ }
22188
+ ];
22189
+ var contactCircleDefs = [
22190
+ {
22191
+ key: "inner-circle",
22192
+ name: "Inner Circle",
22193
+ description: "The people you check in with weekly.",
22194
+ cadence: "every week",
22195
+ tag: "1w"
22196
+ },
22197
+ {
22198
+ key: "close-friends",
22199
+ name: "Close Friends",
22200
+ description: "Friends worth a message every couple of weeks.",
22201
+ cadence: "every 2 weeks",
22202
+ tag: "2w"
22203
+ },
22204
+ {
22205
+ key: "keep-warm",
22206
+ name: "Keep Warm",
22207
+ description: "People to keep warm with a monthly hello.",
22208
+ cadence: "every month",
22209
+ tag: "1m"
22210
+ },
22211
+ {
22212
+ key: "network",
22213
+ name: "Network",
22214
+ description: "Professional contacts to touch base with quarterly.",
22215
+ cadence: "every 3 months",
22216
+ tag: "3m"
22217
+ },
22218
+ {
22219
+ key: "birthday-only",
22220
+ name: "Birthday Only",
22221
+ description: "People you reach out to on their birthday.",
22222
+ cadence: "on their birthday",
22223
+ tag: "birthday"
22224
+ }
22225
+ ];
22226
+ var contactPresets = contactCircleDefs.map((def) => ({
22227
+ key: def.key,
22228
+ entity: "contact",
22229
+ name: def.name,
22230
+ description: def.description,
22231
+ icon: "\uD83D\uDC65",
22232
+ color: "#38bdf8",
22233
+ category: "Keep in Touch",
22234
+ featured: def.key === "inner-circle",
22235
+ recipe: {
22236
+ nodes: [
22237
+ {
22238
+ ref: "contact",
22239
+ kind: "contact",
22240
+ title: def.name,
22241
+ notes: `Keep-in-touch circle \u2014 reach out ${def.cadence}. Rename to a person and set their cadence.`,
22242
+ tags: ["keep-in-touch", def.tag]
22243
+ }
22244
+ ]
22245
+ }
22246
+ }));
22247
+ var challengePresetDefs = [
22248
+ {
22249
+ key: "challenge-75-hard",
22250
+ name: "75 Hard",
22251
+ description: "75 days of two workouts, water, reading and a clean diet.",
22252
+ icon: "\uD83D\uDD25",
22253
+ color: "#fb7185",
22254
+ metric: "habits.checked_in",
22255
+ target: 75,
22256
+ durationDays: 75
22257
+ },
22258
+ {
22259
+ key: "challenge-no-sugar",
22260
+ name: "30-Day No Sugar",
22261
+ description: "Cut added sugar for 30 days.",
22262
+ icon: "\uD83C\uDF6D",
22263
+ color: "#f472b6",
22264
+ metric: "habits.checked_in",
22265
+ target: 30,
22266
+ durationDays: 30
22267
+ },
22268
+ {
22269
+ key: "challenge-couch-to-5k",
22270
+ name: "Couch-to-5K",
22271
+ description: "Run your first 5K in nine weeks.",
22272
+ icon: "\uD83C\uDFC3",
22273
+ color: "#34d399",
22274
+ metric: "habits.checked_in",
22275
+ target: 27,
22276
+ durationDays: 63
22277
+ },
22278
+ {
22279
+ key: "challenge-dry-january",
22280
+ name: "Dry January",
22281
+ description: "An alcohol-free month to reset.",
22282
+ icon: "\uD83D\uDEAB",
22283
+ color: "#38bdf8",
22284
+ metric: "habits.checked_in",
22285
+ target: 31,
22286
+ durationDays: 31
22287
+ },
22288
+ {
22289
+ key: "challenge-meditation",
22290
+ name: "31-Day Meditation",
22291
+ description: "Sit every day for a month.",
22292
+ icon: "\uD83E\uDDD8",
22293
+ color: "#a78bfa",
22294
+ metric: "habits.checked_in",
22295
+ target: 31,
22296
+ durationDays: 31
22297
+ },
22298
+ {
22299
+ key: "challenge-no-spend",
22300
+ name: "No-Spend Month",
22301
+ description: "Thirty days of buying only the essentials.",
22302
+ icon: "\uD83D\uDCB8",
22303
+ color: "#f59e0b",
22304
+ metric: "habits.checked_in",
22305
+ target: 30,
22306
+ durationDays: 30
22307
+ }
22308
+ ];
22309
+ var challengePresets = challengePresetDefs.map((def) => ({
22310
+ key: def.key,
22311
+ entity: "challenge",
22312
+ name: def.name,
22313
+ description: def.description,
22314
+ icon: def.icon,
22315
+ color: def.color,
22316
+ category: "Challenges",
22317
+ featured: def.key === "challenge-couch-to-5k",
22318
+ recipe: {
22319
+ nodes: [
22320
+ {
22321
+ ref: "challenge",
22322
+ kind: "challenge",
22323
+ title: def.name,
22324
+ description: def.description,
22325
+ metric: def.metric,
22326
+ target: def.target,
22327
+ durationDays: def.durationDays
22328
+ }
22329
+ ]
22330
+ }
22331
+ }));
22332
+ var automationPresets = [
22333
+ {
22334
+ key: "auto-low-stock-groceries",
22335
+ entity: "automation",
22336
+ name: "Low stock \u2192 add to groceries",
22337
+ description: "When an inventory item runs low, make a task to restock it.",
22338
+ icon: "\uD83E\uDD6B",
22339
+ color: "#34d399",
22340
+ category: "Automations",
22341
+ recipe: {
22342
+ nodes: [
22343
+ {
22344
+ ref: "automation",
22345
+ kind: "automation",
22346
+ name: "Low stock \u2192 add to groceries",
22347
+ trigger: { entity: "inventory", action: "updated" },
22348
+ condition: { path: "value.lowStock", op: "eq", value: true },
22349
+ action: { type: "create_task", title: "Restock low groceries", priority: "medium" }
22350
+ }
22351
+ ]
22352
+ }
22353
+ },
22354
+ {
22355
+ key: "auto-habit-missed-nudge",
22356
+ entity: "automation",
22357
+ name: "Habit missed 3\xD7 \u2192 nudge",
22358
+ description: "Get a gentle nudge when you miss a habit three times.",
22359
+ icon: "\uD83D\uDD14",
22360
+ color: "#fb7185",
22361
+ category: "Automations",
22362
+ recipe: {
22363
+ nodes: [
22364
+ {
22365
+ ref: "automation",
22366
+ kind: "automation",
22367
+ name: "Habit missed 3\xD7 \u2192 nudge",
22368
+ trigger: { entity: "habits", action: "updated" },
22369
+ condition: { path: "value.missedStreak", op: "eq", value: 3 },
22370
+ action: {
22371
+ type: "notify",
22372
+ title: "Don't break the chain",
22373
+ body: "You've missed this habit three times \u2014 jump back in today."
22374
+ }
22375
+ }
22376
+ ]
22377
+ }
22378
+ },
22379
+ {
22380
+ key: "auto-task-overdue-bump",
22381
+ entity: "automation",
22382
+ name: "Task overdue \u2192 bump priority",
22383
+ description: "When a task goes overdue, raise a high-priority follow-up.",
22384
+ icon: "\u23F0",
22385
+ color: "#f59e0b",
22386
+ category: "Automations",
22387
+ recipe: {
22388
+ nodes: [
22389
+ {
22390
+ ref: "automation",
22391
+ kind: "automation",
22392
+ name: "Task overdue \u2192 bump priority",
22393
+ trigger: { entity: "tasks", action: "updated" },
22394
+ condition: { path: "value.overdue", op: "eq", value: true },
22395
+ action: { type: "create_task", title: "Reprioritise overdue task", priority: "high" }
22396
+ }
22397
+ ]
22398
+ }
22399
+ },
22400
+ {
22401
+ key: "auto-weekly-review",
22402
+ entity: "automation",
22403
+ name: "Weekly review reminder",
22404
+ description: "Reschedule your weekly review a week out each time you finish it.",
22405
+ icon: "\uD83D\uDDD3\uFE0F",
22406
+ color: "#34d399",
22407
+ category: "Automations",
22408
+ recipe: {
22409
+ nodes: [
22410
+ {
22411
+ ref: "automation",
22412
+ kind: "automation",
22413
+ name: "Weekly review reminder",
22414
+ trigger: { entity: "tasks", action: "updated" },
22415
+ condition: { path: "value.title", op: "contains", value: "Weekly Review" },
22416
+ action: { type: "schedule_task", offsetMinutes: 10080 }
22417
+ }
22418
+ ]
22419
+ }
22420
+ },
22421
+ {
22422
+ key: "auto-finished-book-rate",
22423
+ entity: "automation",
22424
+ name: "Finished book \u2192 rate it",
22425
+ description: "When you finish a book, make a task to rate it.",
22426
+ icon: "\uD83D\uDCDA",
22427
+ color: "#f59e0b",
22428
+ category: "Automations",
22429
+ recipe: {
22430
+ nodes: [
22431
+ {
22432
+ ref: "automation",
22433
+ kind: "automation",
22434
+ name: "Finished book \u2192 rate it",
22435
+ trigger: { entity: "books", action: "updated" },
22436
+ condition: { path: "value.status", op: "eq", value: "finished" },
22437
+ action: {
22438
+ type: "create_task",
22439
+ title: "Rate the book you just finished",
22440
+ priority: "low"
22441
+ }
22442
+ }
22443
+ ]
22444
+ }
22445
+ }
22446
+ ];
21573
22447
  var presetCatalog = [
21574
22448
  ...habitPresets,
21575
22449
  ...shoppingListPresets,
21576
- ...inventoryPresets
22450
+ ...inventoryPresets,
22451
+ ...routinePresets,
22452
+ ...areaPresets,
22453
+ ...projectPresets,
22454
+ ...mealPresets,
22455
+ ...contactPresets,
22456
+ ...challengePresets,
22457
+ ...automationPresets
21577
22458
  ];
21578
22459
  var presetsByKey = new Map(presetCatalog.map((preset) => [preset.key, preset]));
21579
22460
  // ../../node_modules/.bun/ulidx@2.4.1/node_modules/ulidx/dist/node/index.js
@@ -21828,7 +22709,7 @@ function parseCapture2(input) {
21828
22709
 
21829
22710
  // src/meta.ts
21830
22711
  var CLI_NAME = "do";
21831
- var VERSION = "1.28.0";
22712
+ var VERSION = "1.30.0";
21832
22713
  var API_PREFIX = "/api/v1";
21833
22714
  var DEFAULT_API_URL = "http://localhost:3001";
21834
22715
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.28.0",
3
+ "version": "1.30.0",
4
4
  "private": false,
5
5
  "description": "do — the agent-drivable CLI over the public /api/v1 surface",
6
6
  "type": "module",