@robbeverhelst/do 1.47.0 → 1.49.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 +164 -1
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -21617,6 +21617,29 @@ var COLLECTION_TYPES = {
21617
21617
  wine: stubType("wine", "Wines", "bottle")
21618
21618
  };
21619
21619
  var COLLECTION_TYPE_LIST = collectionTypeValues.map((k) => COLLECTION_TYPES[k]);
21620
+ var collectionTypeSummarySchema = exports_external.object({
21621
+ key: collectionTypeSchema,
21622
+ label: exports_external.string(),
21623
+ itemNoun: exports_external.string(),
21624
+ statuses: exports_external.array(collectionStatusSchema),
21625
+ statusLabels: exports_external.record(exports_external.string(), exports_external.string()),
21626
+ view: collectionViewSchema,
21627
+ lookupId: exports_external.string().nullable(),
21628
+ stub: exports_external.boolean()
21629
+ });
21630
+ function toCollectionTypeSummary(config2) {
21631
+ return {
21632
+ key: config2.key,
21633
+ label: config2.label,
21634
+ itemNoun: config2.itemNoun,
21635
+ statuses: [...config2.statuses],
21636
+ statusLabels: { ...config2.statusLabels },
21637
+ view: config2.view,
21638
+ lookupId: config2.lookupId ?? null,
21639
+ stub: config2.stub ?? false
21640
+ };
21641
+ }
21642
+ var COLLECTION_TYPE_SUMMARIES = COLLECTION_TYPE_LIST.map(toCollectionTypeSummary);
21620
21643
  // ../../packages/schema/src/presets/recipe.ts
21621
21644
  var presetEntitySchema = exports_external.enum([
21622
21645
  "habit",
@@ -23635,7 +23658,7 @@ function parseCapture2(input) {
23635
23658
 
23636
23659
  // src/meta.ts
23637
23660
  var CLI_NAME = "do";
23638
- var VERSION = "1.47.0";
23661
+ var VERSION = "1.49.0";
23639
23662
  var API_PREFIX = "/api/v1";
23640
23663
  var DEFAULT_API_URL = "http://localhost:3001";
23641
23664
 
@@ -24262,6 +24285,81 @@ var COMMAND_SPECS = [
24262
24285
  returns: "PresetInstallResult",
24263
24286
  notes: "Authors content as the caller, so it needs a key minted while logged in."
24264
24287
  },
24288
+ {
24289
+ path: ["collection", "types"],
24290
+ summary: "List the catalog Types (key \xB7 label \xB7 status subset).",
24291
+ args: [],
24292
+ flags: [],
24293
+ scopes: ["collections:read"],
24294
+ returns: "CollectionTypeSummary",
24295
+ notes: "The Type registry is code-defined (ADR 0017); served from GET /api/v1/collection/types."
24296
+ },
24297
+ {
24298
+ path: ["collection", "list"],
24299
+ summary: "List Collection Items, optionally sliced by Type / Status / tag.",
24300
+ args: [],
24301
+ flags: [
24302
+ { name: "type", type: "string", description: "Filter to one Type (book|film|game|\u2026)." },
24303
+ {
24304
+ name: "status",
24305
+ type: "string",
24306
+ description: "Filter to one Status (want|have|doing|done|dropped)."
24307
+ },
24308
+ { name: "tag", type: "string", description: "Filter to Items carrying this tag." }
24309
+ ],
24310
+ scopes: ["collections:read"],
24311
+ returns: "CollectionItemView"
24312
+ },
24313
+ {
24314
+ path: ["collection", "add"],
24315
+ summary: "Add a Collection Item (the title may embed #tag).",
24316
+ args: [{ name: "title", required: true, description: "Item title; may embed #tag." }],
24317
+ flags: [
24318
+ { name: "type", type: "string", description: "Type (book|film|game|music|place|wine)." },
24319
+ {
24320
+ name: "status",
24321
+ type: "string",
24322
+ description: "Initial status; defaults to the Type's first."
24323
+ }
24324
+ ],
24325
+ scopes: ["collections:write"],
24326
+ returns: "CollectionItemView",
24327
+ grammar: {
24328
+ "#tag": "Adds a tag. Repeatable: '#scifi #2024'."
24329
+ },
24330
+ notes: "--type is required; the per-Type facet rides --data (validated server-side against the Type)."
24331
+ },
24332
+ {
24333
+ path: ["collection", "set-status"],
24334
+ summary: "Set a Collection Item's status (browse/filter spine).",
24335
+ args: [
24336
+ { name: "id", required: true, description: "Item ULID." },
24337
+ {
24338
+ name: "status",
24339
+ required: true,
24340
+ description: "want|have|doing|done|dropped (per-Type subset)."
24341
+ }
24342
+ ],
24343
+ flags: [],
24344
+ scopes: ["collections:write"],
24345
+ returns: "CollectionItemView"
24346
+ },
24347
+ {
24348
+ path: ["collection", "add-entry"],
24349
+ summary: "Log a dated Entry against an Item (recomputes its headline rating).",
24350
+ args: [{ name: "id", required: true, description: "Item ULID." }],
24351
+ flags: [
24352
+ { name: "rating", type: "string", description: "Rating 1\u20135 for this Entry." },
24353
+ { name: "note", type: "string", description: "Free-text note for this Entry." },
24354
+ {
24355
+ name: "on",
24356
+ type: "string",
24357
+ description: "Day it occurred (YYYY-MM-DD); defaults to today."
24358
+ }
24359
+ ],
24360
+ scopes: ["collections:write"],
24361
+ returns: "CollectionItemDetail"
24362
+ },
24265
24363
  {
24266
24364
  path: ["invite", "create"],
24267
24365
  summary: "Create a Space invite (email/link/guest).",
@@ -25018,6 +25116,55 @@ var HANDLERS = {
25018
25116
  const result = presetInstallResultSchema.parse(await requireClient().post(`/presets/${encodeURIComponent(key)}/install`, undefined));
25019
25117
  return { data: result, render: renderPresetInstall };
25020
25118
  },
25119
+ "collection types": async ({ requireClient }) => {
25120
+ const types2 = collectionTypeSummarySchema.array().parse(await requireClient().get("/collection/types"));
25121
+ return { data: types2, render: renderList };
25122
+ },
25123
+ "collection list": async ({ flags, requireClient }) => {
25124
+ const query = {
25125
+ type: flagString(flags, "type"),
25126
+ status: flagString(flags, "status"),
25127
+ tag: flagString(flags, "tag")
25128
+ };
25129
+ return { data: await requireClient().get("/collection", { query }), render: renderList };
25130
+ },
25131
+ "collection add": async ({ args, flags, requireClient }) => {
25132
+ const { title, tags } = parseTitleTags(args);
25133
+ if (title.length === 0)
25134
+ throw usageError('collection add needs a title, e.g. `do collection add "Dune" --type book`');
25135
+ const type = requireFlag(flags, "type", "collection add needs --type <book|film|game|music|place|wine>");
25136
+ const body = parseInput(createCollectionItemInputSchema, {
25137
+ id: ulid3(),
25138
+ type,
25139
+ title,
25140
+ ...tags.length > 0 ? { tags } : {},
25141
+ ...flagString(flags, "status") ? { status: flagString(flags, "status") } : {}
25142
+ });
25143
+ return { data: await requireClient().post("/collection", body), render: renderRecord };
25144
+ },
25145
+ "collection set-status": async ({ args, requireClient }) => {
25146
+ const id = requireArg(args, 0, "item id");
25147
+ const status = requireArg(args, 1, "status");
25148
+ const body = parseInput(updateCollectionItemInputSchema, { status });
25149
+ return { data: await requireClient().patch(`/collection/${id}`, body), render: renderRecord };
25150
+ },
25151
+ "collection add-entry": async ({ args, flags, io, requireClient }) => {
25152
+ const id = requireArg(args, 0, "item id");
25153
+ const rating = flagString(flags, "rating");
25154
+ if (rating !== undefined && Number.isNaN(Number(rating))) {
25155
+ throw usageError("--rating must be a number (1\u20135)");
25156
+ }
25157
+ const body = parseInput(createCollectionEntryInputSchema, {
25158
+ id: ulid3(),
25159
+ occurredOn: flagString(flags, "on") ?? isoDay(io.now()),
25160
+ ...rating !== undefined ? { rating: Number(rating) } : {},
25161
+ ...flagString(flags, "note") ? { note: flagString(flags, "note") } : {}
25162
+ });
25163
+ return {
25164
+ data: await requireClient().post(`/collection/${id}/entries`, body),
25165
+ render: renderRecord
25166
+ };
25167
+ },
25021
25168
  "invite create": async ({ flags, requireClient }) => {
25022
25169
  const body = parseInput(createInviteInputSchema, { id: ulid3(), ...readDataFlag(flags) });
25023
25170
  return { data: await requireClient().post("/invites", body), render: renderRecord };
@@ -25203,6 +25350,22 @@ async function setModuleVisibility(args, requireClient, on) {
25203
25350
  const body = parseInput(updateUserSettingsInputSchema, { enabledModules });
25204
25351
  return { data: await client.patch("/settings", body), render: renderRecord };
25205
25352
  }
25353
+ function parseTitleTags(args) {
25354
+ const titleWords = [];
25355
+ const tags = [];
25356
+ for (const token of args.join(" ").split(/\s+/).filter(Boolean)) {
25357
+ if (token.length > 1 && token.startsWith("#"))
25358
+ tags.push(token.slice(1));
25359
+ else
25360
+ titleWords.push(token);
25361
+ }
25362
+ return { title: titleWords.join(" ").trim(), tags };
25363
+ }
25364
+ function isoDay(date6) {
25365
+ const month = String(date6.getMonth() + 1).padStart(2, "0");
25366
+ const day = String(date6.getDate()).padStart(2, "0");
25367
+ return `${date6.getFullYear()}-${month}-${day}`;
25368
+ }
25206
25369
  function requireArg(args, index2, name) {
25207
25370
  const value = args[index2];
25208
25371
  if (value === undefined || value.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.47.0",
3
+ "version": "1.49.0",
4
4
  "private": false,
5
5
  "description": "do — the agent-drivable CLI over the public /api/v1 surface",
6
6
  "type": "module",