@robbeverhelst/do 1.43.0 → 1.45.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 +384 -2
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -4545,6 +4545,36 @@ var inventoryItems = pgTable("inventory_items", {
4545
4545
  }, (t) => [
4546
4546
  index("inventory_items_tenant_idx").on(t.tenantId)
4547
4547
  ]);
4548
+ // ../../packages/schema/src/db/collection.ts
4549
+ var collectionItems = pgTable("collection_items", {
4550
+ id: text("id").primaryKey().references(() => nodes.id),
4551
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
4552
+ type: text("type").$type().notNull(),
4553
+ status: text("status").$type().notNull().default("want"),
4554
+ quantity: doublePrecision("quantity"),
4555
+ facet: jsonb("facet").$type(),
4556
+ areaId: text("area_id").references(() => areas.id),
4557
+ tags: text("tags").array().notNull().default([]),
4558
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
4559
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
4560
+ }, (t) => [
4561
+ index("collection_items_tenant_type_idx").on(t.tenantId, t.type),
4562
+ index("collection_items_tenant_idx").on(t.tenantId),
4563
+ index("collection_items_area_idx").on(t.areaId),
4564
+ index("collection_items_tags_idx").using("gin", t.tags)
4565
+ ]);
4566
+ var collectionEntries = pgTable("collection_entries", {
4567
+ id: text("id").primaryKey(),
4568
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
4569
+ itemId: text("item_id").notNull().references(() => collectionItems.id),
4570
+ occurredOn: date("occurred_on").notNull(),
4571
+ rating: integer("rating"),
4572
+ note: text("note"),
4573
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
4574
+ }, (t) => [
4575
+ index("collection_entries_item_occurred_idx").on(t.itemId, t.occurredOn),
4576
+ index("collection_entries_tenant_idx").on(t.tenantId)
4577
+ ]);
4548
4578
  // ../../packages/schema/src/db/recipes.ts
4549
4579
  var mealType = pgEnum("meal_type", ["breakfast", "lunch", "dinner", "snack"]);
4550
4580
  var recipes = pgTable("recipes", {
@@ -20012,6 +20042,200 @@ var areaDetailSchema = areaViewSchema.extend({
20012
20042
  routines: exports_external.array(routineViewSchema),
20013
20043
  tasks: exports_external.array(taskViewSchema)
20014
20044
  });
20045
+ // ../../packages/schema/src/contracts/modules.ts
20046
+ var MODULE_KEYS = [
20047
+ "tasks",
20048
+ "habits",
20049
+ "routines",
20050
+ "challenges",
20051
+ "projects",
20052
+ "areas",
20053
+ "notes",
20054
+ "shopping",
20055
+ "inventory",
20056
+ "meals",
20057
+ "library",
20058
+ "watchlist",
20059
+ "games",
20060
+ "cellar",
20061
+ "places",
20062
+ "music",
20063
+ "contacts",
20064
+ "automations"
20065
+ ];
20066
+ var moduleKeySchema = exports_external.enum(MODULE_KEYS);
20067
+ var FEATURE_MODULES = [
20068
+ {
20069
+ key: "today",
20070
+ label: "Today",
20071
+ description: "Your daily dashboard \u2014 always on.",
20072
+ group: "System",
20073
+ defaultEnabled: true,
20074
+ system: true
20075
+ },
20076
+ {
20077
+ key: "inbox",
20078
+ label: "Inbox",
20079
+ description: "Quick capture and triage \u2014 always on.",
20080
+ group: "System",
20081
+ defaultEnabled: true,
20082
+ system: true
20083
+ },
20084
+ {
20085
+ key: "settings",
20086
+ label: "Settings",
20087
+ description: "This screen \u2014 always on.",
20088
+ group: "System",
20089
+ defaultEnabled: true,
20090
+ system: true
20091
+ },
20092
+ {
20093
+ key: "tasks",
20094
+ label: "Tasks",
20095
+ description: "To-dos, due dates, and priorities.",
20096
+ group: "Track",
20097
+ defaultEnabled: true
20098
+ },
20099
+ {
20100
+ key: "habits",
20101
+ label: "Habits",
20102
+ description: "Daily routines and streaks.",
20103
+ group: "Track",
20104
+ defaultEnabled: true
20105
+ },
20106
+ {
20107
+ key: "routines",
20108
+ label: "Routines",
20109
+ description: "Repeatable checklists you run.",
20110
+ group: "Track",
20111
+ defaultEnabled: true
20112
+ },
20113
+ {
20114
+ key: "challenges",
20115
+ label: "Challenges",
20116
+ description: "Time-boxed goals and competitions.",
20117
+ group: "Track",
20118
+ defaultEnabled: true
20119
+ },
20120
+ {
20121
+ key: "projects",
20122
+ label: "Projects",
20123
+ description: "Multi-step work with milestones.",
20124
+ group: "Organize",
20125
+ defaultEnabled: true
20126
+ },
20127
+ {
20128
+ key: "areas",
20129
+ label: "Areas",
20130
+ description: "Ongoing life domains (PARA areas).",
20131
+ group: "Organize",
20132
+ defaultEnabled: true
20133
+ },
20134
+ {
20135
+ key: "notes",
20136
+ label: "Notes",
20137
+ description: "Quick notes and documents.",
20138
+ group: "Organize",
20139
+ defaultEnabled: true
20140
+ },
20141
+ {
20142
+ key: "shopping",
20143
+ label: "Shopping",
20144
+ description: "Lists and groceries.",
20145
+ group: "Household",
20146
+ defaultEnabled: true
20147
+ },
20148
+ {
20149
+ key: "inventory",
20150
+ label: "Inventory",
20151
+ description: "Things you own and stock.",
20152
+ group: "Household",
20153
+ defaultEnabled: true
20154
+ },
20155
+ {
20156
+ key: "meals",
20157
+ label: "Meals",
20158
+ description: "Recipes and meal plans.",
20159
+ group: "Household",
20160
+ defaultEnabled: true
20161
+ },
20162
+ {
20163
+ key: "library",
20164
+ label: "Library",
20165
+ description: "Books and things you catalog.",
20166
+ group: "Collections",
20167
+ defaultEnabled: true
20168
+ },
20169
+ {
20170
+ key: "watchlist",
20171
+ label: "Watchlist",
20172
+ description: "Films and shows to watch.",
20173
+ group: "Collections",
20174
+ defaultEnabled: true
20175
+ },
20176
+ {
20177
+ key: "games",
20178
+ label: "Games",
20179
+ description: "Games to play and backlog.",
20180
+ group: "Collections",
20181
+ defaultEnabled: true
20182
+ },
20183
+ {
20184
+ key: "cellar",
20185
+ label: "Cellar",
20186
+ description: "Wines and bottles you keep.",
20187
+ group: "Collections",
20188
+ defaultEnabled: true
20189
+ },
20190
+ {
20191
+ key: "places",
20192
+ label: "Places",
20193
+ description: "Spots to visit and remember.",
20194
+ group: "Collections",
20195
+ defaultEnabled: true
20196
+ },
20197
+ {
20198
+ key: "music",
20199
+ label: "Music",
20200
+ description: "Albums and records to hear.",
20201
+ group: "Collections",
20202
+ defaultEnabled: true
20203
+ },
20204
+ {
20205
+ key: "contacts",
20206
+ label: "Contacts",
20207
+ description: "People and relationships.",
20208
+ group: "People",
20209
+ defaultEnabled: true
20210
+ },
20211
+ {
20212
+ key: "automations",
20213
+ label: "Automations",
20214
+ description: "Trigger \u2192 condition \u2192 action rules.",
20215
+ group: "Manage",
20216
+ defaultEnabled: true
20217
+ }
20218
+ ];
20219
+ var TOGGLEABLE_MODULES = FEATURE_MODULES.filter((m) => !m.system);
20220
+ function isModuleKey(value) {
20221
+ return MODULE_KEYS.includes(value);
20222
+ }
20223
+ function normalizeEnabledModules(keys) {
20224
+ const present = new Set(keys.filter(isModuleKey));
20225
+ return MODULE_KEYS.filter((key) => present.has(key));
20226
+ }
20227
+ function effectiveEnabledModules(enabled) {
20228
+ const known = normalizeEnabledModules(enabled ?? []);
20229
+ return known.length > 0 ? known : [...MODULE_KEYS];
20230
+ }
20231
+ function setModuleEnabled(enabled, key, on) {
20232
+ const next = new Set(effectiveEnabledModules(enabled));
20233
+ if (on)
20234
+ next.add(key);
20235
+ else
20236
+ next.delete(key);
20237
+ return MODULE_KEYS.filter((candidate) => next.has(candidate));
20238
+ }
20015
20239
  // ../../packages/schema/src/contracts/settings.ts
20016
20240
  var settingsThemeSchema = exports_external.enum(settingsTheme.enumValues);
20017
20241
  var settingsDensitySchema = exports_external.enum(settingsDensity.enumValues);
@@ -20028,7 +20252,7 @@ var updateUserSettingsInputSchema = exports_external.object({
20028
20252
  theme: settingsThemeSchema.optional(),
20029
20253
  density: settingsDensitySchema.optional(),
20030
20254
  accent: settingsAccentSchema.optional(),
20031
- enabledModules: exports_external.array(exports_external.string().trim().min(1)).optional()
20255
+ enabledModules: exports_external.array(exports_external.string().trim().min(1)).transform(normalizeEnabledModules).optional()
20032
20256
  }).strict();
20033
20257
  // ../../packages/schema/src/contracts/notifications.ts
20034
20258
  var notificationTypeSchema = exports_external.enum(["task_due", "occurrence_due"]);
@@ -20286,6 +20510,60 @@ var restockInputSchema = exports_external.object({
20286
20510
  listId: ulidSchema.optional(),
20287
20511
  itemIds: exports_external.array(ulidSchema).optional()
20288
20512
  }).strict();
20513
+ // ../../packages/schema/src/contracts/collection.ts
20514
+ var collectionStatusValues = ["want", "have", "doing", "done", "dropped"];
20515
+ var collectionStatusSchema = exports_external.enum(collectionStatusValues);
20516
+ var collectionTypeValues = ["book", "film", "game", "music", "place", "wine"];
20517
+ var collectionTypeSchema = exports_external.enum(collectionTypeValues);
20518
+ var collectionViewValues = ["grid", "shelf", "map"];
20519
+ var collectionViewSchema = exports_external.enum(collectionViewValues);
20520
+ var collectionFacetSchema = exports_external.record(exports_external.string(), exports_external.unknown());
20521
+ var collectionItemSchema = createSelectSchema(collectionItems, {
20522
+ facet: collectionFacetSchema.nullable(),
20523
+ tags: exports_external.array(exports_external.string()),
20524
+ createdAt: exports_external.coerce.date(),
20525
+ updatedAt: exports_external.coerce.date()
20526
+ });
20527
+ var createCollectionItemInputSchema = exports_external.object({
20528
+ id: ulidSchema,
20529
+ type: collectionTypeSchema,
20530
+ title: exports_external.string().min(1),
20531
+ status: collectionStatusSchema.optional(),
20532
+ quantity: exports_external.number().min(0).nullish(),
20533
+ parentId: ulidSchema.nullish(),
20534
+ areaId: ulidSchema.nullish(),
20535
+ tags: exports_external.array(exports_external.string().min(1)).optional(),
20536
+ facet: collectionFacetSchema.nullish()
20537
+ });
20538
+ var updateCollectionItemInputSchema = exports_external.object({
20539
+ title: exports_external.string().min(1).optional(),
20540
+ status: collectionStatusSchema.optional(),
20541
+ quantity: exports_external.number().min(0).nullish(),
20542
+ parentId: ulidSchema.nullish(),
20543
+ areaId: ulidSchema.nullish(),
20544
+ tags: exports_external.array(exports_external.string().min(1)).optional(),
20545
+ facet: collectionFacetSchema.nullish()
20546
+ }).strict();
20547
+ var collectionEntrySchema = createSelectSchema(collectionEntries, {
20548
+ createdAt: exports_external.coerce.date()
20549
+ });
20550
+ var createCollectionEntryInputSchema = exports_external.object({
20551
+ id: ulidSchema,
20552
+ occurredOn: exports_external.string().regex(/^\d{4}-\d{2}-\d{2}$/, "must be an ISO date (YYYY-MM-DD)"),
20553
+ rating: exports_external.number().int().min(1).max(5).nullish(),
20554
+ note: exports_external.string().max(2000).nullish()
20555
+ });
20556
+ var collectionItemViewSchema = collectionItemSchema.extend({
20557
+ title: exports_external.string(),
20558
+ parentId: ulidSchema.nullable(),
20559
+ type: exports_external.string(),
20560
+ status: exports_external.string(),
20561
+ rating: exports_external.number().int().min(1).max(5).nullable(),
20562
+ deletedAt: exports_external.coerce.date().nullable()
20563
+ });
20564
+ var collectionItemDetailSchema = collectionItemViewSchema.extend({
20565
+ entries: exports_external.array(collectionEntrySchema)
20566
+ });
20289
20567
  // ../../packages/schema/src/contracts/recipes.ts
20290
20568
  var recipeSchema = createSelectSchema(recipes);
20291
20569
  var recipeIngredientSchema = createSelectSchema(recipeIngredients, {
@@ -21288,6 +21566,57 @@ function parseCapture(input) {
21288
21566
  const title = input.replace(TAG_RE, " ").replace(PRIORITY_RE, " ").replace(AREA_RE, " ").replace(/\s+/g, " ").trim();
21289
21567
  return { title, tags, ...priority ? { priority } : {}, ...area ? { area } : {} };
21290
21568
  }
21569
+ // ../../packages/schema/src/presets/collection-types.ts
21570
+ var bookFacetSchema = exports_external.object({
21571
+ author: exports_external.string().min(1).max(200).nullish(),
21572
+ coverUrl: exports_external.string().url().max(2048).nullish(),
21573
+ pageCount: exports_external.number().int().min(1).max(1e5).nullish()
21574
+ }).strict();
21575
+ var stubFacetSchema = exports_external.object({}).strict();
21576
+ var ALL_STATUSES = collectionStatusValues;
21577
+ var DEFAULT_STATUS_LABELS = {
21578
+ want: "Want",
21579
+ have: "Have",
21580
+ doing: "Doing",
21581
+ done: "Done",
21582
+ dropped: "Dropped"
21583
+ };
21584
+ function stubType(key, label, itemNoun) {
21585
+ return {
21586
+ key,
21587
+ label,
21588
+ itemNoun,
21589
+ statuses: ALL_STATUSES,
21590
+ statusLabels: DEFAULT_STATUS_LABELS,
21591
+ facetSchema: stubFacetSchema,
21592
+ view: "grid",
21593
+ stub: true
21594
+ };
21595
+ }
21596
+ var COLLECTION_TYPES = {
21597
+ book: {
21598
+ key: "book",
21599
+ label: "Books",
21600
+ itemNoun: "book",
21601
+ statuses: ["want", "have", "doing", "done", "dropped"],
21602
+ statusLabels: {
21603
+ want: "Want to read",
21604
+ have: "Owned",
21605
+ doing: "Reading",
21606
+ done: "Read",
21607
+ dropped: "Abandoned"
21608
+ },
21609
+ facetSchema: bookFacetSchema,
21610
+ view: "shelf",
21611
+ lookupId: "open-library"
21612
+ },
21613
+ film: stubType("film", "Films & TV", "title"),
21614
+ game: stubType("game", "Games", "game"),
21615
+ music: stubType("music", "Music", "album"),
21616
+ place: stubType("place", "Places", "place"),
21617
+ wine: stubType("wine", "Wines", "bottle")
21618
+ };
21619
+ var COLLECTION_TYPE_LIST = collectionTypeValues.map((k) => COLLECTION_TYPES[k]);
21291
21620
  // ../../packages/schema/src/presets/recipe.ts
21292
21621
  var presetEntitySchema = exports_external.enum([
21293
21622
  "habit",
@@ -23306,7 +23635,7 @@ function parseCapture2(input) {
23306
23635
 
23307
23636
  // src/meta.ts
23308
23637
  var CLI_NAME = "do";
23309
- var VERSION = "1.43.0";
23638
+ var VERSION = "1.45.0";
23310
23639
  var API_PREFIX = "/api/v1";
23311
23640
  var DEFAULT_API_URL = "http://localhost:3001";
23312
23641
 
@@ -23882,6 +24211,33 @@ var COMMAND_SPECS = [
23882
24211
  scopes: ["settings:write"],
23883
24212
  returns: "UserSettings"
23884
24213
  },
24214
+ {
24215
+ path: ["modules", "list"],
24216
+ summary: "List feature-modules and whether each is enabled for the caller.",
24217
+ args: [],
24218
+ flags: [],
24219
+ scopes: ["settings:read"],
24220
+ returns: "ModuleStatus",
24221
+ notes: "Reads enabledModules from GET /api/v1/settings; an empty set means every module is on."
24222
+ },
24223
+ {
24224
+ path: ["modules", "enable"],
24225
+ summary: "Enable a feature-module (surfaces it in nav / quick-add / \u2318K).",
24226
+ args: [{ name: "key", required: true, description: "Module key (see `do modules list`)." }],
24227
+ flags: [],
24228
+ scopes: ["settings:read", "settings:write"],
24229
+ returns: "UserSettings",
24230
+ notes: "Reads then patches settings; only the module visibility list changes."
24231
+ },
24232
+ {
24233
+ path: ["modules", "disable"],
24234
+ summary: "Disable a feature-module (hides its surfaces \u2014 nothing is deleted).",
24235
+ args: [{ name: "key", required: true, description: "Module key (see `do modules list`)." }],
24236
+ flags: [],
24237
+ scopes: ["settings:read", "settings:write"],
24238
+ returns: "UserSettings",
24239
+ notes: "Reads then patches settings; only the module visibility list changes."
24240
+ },
23885
24241
  {
23886
24242
  path: ["presets", "list"],
23887
24243
  summary: "List the preset gallery (key \xB7 name \xB7 entity).",
@@ -24633,6 +24989,21 @@ var HANDLERS = {
24633
24989
  const body = parseInput(updateUserSettingsInputSchema, readDataFlag(flags));
24634
24990
  return { data: await requireClient().patch("/settings", body), render: renderRecord };
24635
24991
  },
24992
+ "modules list": async ({ requireClient }) => {
24993
+ const settings2 = await requireClient().get("/settings");
24994
+ const enabled = new Set(effectiveEnabledModules(settings2.enabledModules));
24995
+ const rows = FEATURE_MODULES.map((module) => ({
24996
+ key: module.key,
24997
+ label: module.label,
24998
+ group: module.group,
24999
+ enabled: module.system ? true : enabled.has(module.key),
25000
+ system: Boolean(module.system),
25001
+ default: module.defaultEnabled
25002
+ }));
25003
+ return { data: rows, render: renderList };
25004
+ },
25005
+ "modules enable": async ({ args, requireClient }) => setModuleVisibility(args, requireClient, true),
25006
+ "modules disable": async ({ args, requireClient }) => setModuleVisibility(args, requireClient, false),
24636
25007
  "presets list": async ({ flags, requireClient }) => {
24637
25008
  const entity = flagString(flags, "entity");
24638
25009
  if (entity !== undefined && !presetEntitySchema.safeParse(entity).success) {
@@ -24821,6 +25192,17 @@ var HANDLERS = {
24821
25192
  render: () => `${CLI_NAME} ${VERSION}`
24822
25193
  })
24823
25194
  };
25195
+ async function setModuleVisibility(args, requireClient, on) {
25196
+ const key = requireArg(args, 0, "module key");
25197
+ if (!isModuleKey(key)) {
25198
+ throw usageError(`unknown module \`${key}\` \u2014 valid keys: ${MODULE_KEYS.join(", ")}`);
25199
+ }
25200
+ const client = requireClient();
25201
+ const settings2 = await client.get("/settings");
25202
+ const enabledModules = setModuleEnabled(settings2.enabledModules, key, on);
25203
+ const body = parseInput(updateUserSettingsInputSchema, { enabledModules });
25204
+ return { data: await client.patch("/settings", body), render: renderRecord };
25205
+ }
24824
25206
  function requireArg(args, index2, name) {
24825
25207
  const value = args[index2];
24826
25208
  if (value === undefined || value.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.43.0",
3
+ "version": "1.45.0",
4
4
  "private": false,
5
5
  "description": "do — the agent-drivable CLI over the public /api/v1 surface",
6
6
  "type": "module",