@robbeverhelst/do 1.308.0 → 1.308.1

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 +484 -104
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -31255,6 +31255,27 @@ var commentOperations = defineOperations({
31255
31255
  }
31256
31256
  });
31257
31257
 
31258
+ // ../../packages/schema/src/operations/contacts.ts
31259
+ var contactOperations = defineOperations({
31260
+ ...crudOperations({
31261
+ segment: "contacts",
31262
+ tag: "Contacts",
31263
+ noun: "contact",
31264
+ read: "contacts:read",
31265
+ write: "contacts:write",
31266
+ create: createContactInputSchema,
31267
+ update: updateContactInputSchema,
31268
+ listQuery: [
31269
+ { name: "kind", description: "Only `person` or only `organization` contacts." },
31270
+ {
31271
+ name: "role",
31272
+ description: "Only contacts with this role (`insurer`, `telecom`, `gp`, `vet`, \u2026)."
31273
+ }
31274
+ ],
31275
+ listQuerySchema: contactsQuerySchema
31276
+ })
31277
+ });
31278
+
31258
31279
  // ../../packages/schema/src/operations/days.ts
31259
31280
  var pathParams = {
31260
31281
  date: {
@@ -32329,6 +32350,357 @@ var inviteOperations = defineOperations({
32329
32350
  }
32330
32351
  });
32331
32352
 
32353
+ // ../../packages/schema/src/operations/journal.ts
32354
+ var journalOperations = defineOperations({
32355
+ range: {
32356
+ method: "get",
32357
+ path: "/journal/days",
32358
+ scopes: ["journal:read"],
32359
+ tag: "Journal",
32360
+ summary: "Journal days in a range",
32361
+ description: "Journal home's read: every day in `[from, to]` (at most 366 days, the key's member's civil days) that has a Journal day or a Metric value, newest first. Each carries the Journal day's title, status, highlights, tags and a plain excerpt of its summary when there is one, and that day's Metric values by key (`rating`, `mood`, `sleep`, \u2026), with how many photos and entries it holds and the first nodes it links to. The Journal is owner-only: a key reads only its own member's days.",
32362
+ afterScopes: "`*` does not cover it.",
32363
+ query: [
32364
+ { name: "from", description: "The first day, `YYYY-MM-DD`.", format: "date" },
32365
+ { name: "to", description: "The last day, `YYYY-MM-DD`.", format: "date" }
32366
+ ],
32367
+ querySchema: journalRangeQuerySchema,
32368
+ status: 200,
32369
+ response: { description: "The days.", view: "JournalDayList" },
32370
+ errors: { 400: true },
32371
+ operationId: "list_journal_days"
32372
+ },
32373
+ search: {
32374
+ method: "get",
32375
+ path: "/journal/search",
32376
+ scopes: ["journal:read"],
32377
+ tag: "Journal",
32378
+ summary: "Search Journal days",
32379
+ description: "The key's member's days that answer `q` (at least 2 characters), best match first, at most 30, each shaped like a day of `GET /journal/days`. Keyword and date, no model: the words left after small words (each with a few that mean the same, English and Dutch) scored where they're found (one-liner and tags, then highlights, then the summary and entries); a date phrase (`in March`, `last week`, `14 October`, `2026-02`, `yesterday`) narrows to its window, or alone reads it; a question leaning on a heavy or a bright day (`rough`, `tired`, `a great day`) adds the days rated 4 or less / 8 or more (within the window, else the last year). `understood` says how it was read. Owner-only: another member's days never match.",
32380
+ afterScopes: "`*` does not cover it.",
32381
+ query: [{ name: "q", description: "What to look for." }],
32382
+ querySchema: journalSearchQuerySchema,
32383
+ status: 200,
32384
+ response: { description: "The matching days.", view: "JournalSearch" },
32385
+ errors: { 400: true }
32386
+ },
32387
+ day: {
32388
+ method: "get",
32389
+ path: "/journal/days/{date}",
32390
+ scopes: ["journal:read"],
32391
+ tag: "Journal",
32392
+ summary: "A Journal day",
32393
+ description: "One civil day of the key's member: the Journal day (its summary, entries, highlights and tags; null when none was written yet) and what happened that day, read live: the Metric values, what landed (tasks and time blocks, by the member or an agent), the habits due and whether they happened, the calendar events, and the nodes the day links to.",
32394
+ afterScopes: "`*` does not cover it.",
32395
+ pathParams: {
32396
+ date: { description: "The day, `YYYY-MM-DD`.", format: "date" }
32397
+ },
32398
+ pathParamSchemas: { date: journalDateSchema },
32399
+ status: 200,
32400
+ response: { description: "The day.", view: "JournalSnapshot" },
32401
+ errors: { 400: true },
32402
+ operationId: "get_journal_day"
32403
+ },
32404
+ like: {
32405
+ method: "get",
32406
+ path: "/journal/days/{date}/like",
32407
+ scopes: ["journal:read"],
32408
+ tag: "Journal",
32409
+ summary: "Days like this one",
32410
+ description: "\"When did I feel like this before?\" (`journal_like`): the key's member's other days most like this one, by Postgres full text over each day's one-liner, highlights, tags, summary and entries, queried with this day's distinctive words (each widened by a few that mean the same, English and Dutch), then ranked by the words and tags they share and how close the rating is. Each day is shaped like the range's, with `shared` (this day's words the other has) and `sharedTags`; `words` is how this day was read. Words, not meanings: there are no embeddings. A day hidden from memories is never offered. A day with nothing written is a 404.",
32411
+ afterScopes: "`*` does not cover it.",
32412
+ pathParams: {
32413
+ date: { description: "The day, `YYYY-MM-DD`.", format: "date" }
32414
+ },
32415
+ pathParamSchemas: { date: journalDateSchema },
32416
+ query: [{ name: "limit", description: "At most this many days (1\u201310, 5 by default)." }],
32417
+ querySchema: journalLikeQuerySchema,
32418
+ status: 200,
32419
+ response: { description: "The days most like it.", view: "JournalLike" },
32420
+ errors: { 400: true, 404: true }
32421
+ },
32422
+ export: {
32423
+ method: "get",
32424
+ path: "/journal/export",
32425
+ scopes: ["journal:export"],
32426
+ tag: "Journal",
32427
+ summary: "Export the Journal as markdown",
32428
+ description: "Every Journal day of the key's member changed at or after `since` (all without it) as a markdown file: `path` (`YYYY/YYYY-MM-DD.md`), front matter (date, title, status, Metric values, tags, `do_id`), the summary, highlights, entries and links as `do://node/<id>`. Links into other sensitive domains stay out. Store `nextSince` and pass it next time. The agent's runtime pulls this nightly into its memory; do is the record and the files are read-only copies.",
32429
+ query: [
32430
+ {
32431
+ name: "since",
32432
+ description: "Only days changed at or after this instant (ISO).",
32433
+ format: "date-time"
32434
+ }
32435
+ ],
32436
+ querySchema: journalExportQuerySchema,
32437
+ status: 200,
32438
+ response: { description: "The files.", view: "JournalExport" },
32439
+ errors: { 400: true },
32440
+ operationId: "export_journal"
32441
+ },
32442
+ write: {
32443
+ method: "post",
32444
+ path: "/journal/days/{date}",
32445
+ scopes: ["journal:write"],
32446
+ tag: "Journal",
32447
+ summary: "Write a Journal day",
32448
+ description: "The agent's evening write (`journal_write_day`) or the member's: creates the day when missing and sets what's given. `summary` (markdown) replaces the summary entry, `highlights` (at most 3) replace the day's, `tags` and `links` (`{ kind, nodeId }`, e.g. `saw` a contact, `about` an event) are added, `metrics` (`{ rating: 7, mood: 4 }`) are logged on each Metric's line for that day. A future date, an unknown Metric or a value out of range is a 400. Returns the day's snapshot, the receipt; an agent's write shows in the change list with Undo.",
32449
+ pathParams: {
32450
+ date: { description: "The day, `YYYY-MM-DD`.", format: "date" }
32451
+ },
32452
+ pathParamSchemas: { date: journalDateSchema },
32453
+ body: journalWriteDayInputSchema,
32454
+ status: 200,
32455
+ response: { description: "The day.", view: "JournalSnapshot" },
32456
+ errors: { 400: true },
32457
+ operationId: "journal_write_day"
32458
+ },
32459
+ addEntry: {
32460
+ method: "post",
32461
+ path: "/journal/days/{date}/entries",
32462
+ scopes: ["journal:write"],
32463
+ tag: "Journal",
32464
+ summary: "Add a Journal entry",
32465
+ description: "Add an entry to the day (`journal_add_entry`): a markdown body and an optional title. The day is made when missing. Returns the snapshot.",
32466
+ pathParams: {
32467
+ date: { description: "The day, `YYYY-MM-DD`.", format: "date" }
32468
+ },
32469
+ pathParamSchemas: { date: journalDateSchema },
32470
+ body: journalAddEntryInputSchema,
32471
+ status: 200,
32472
+ response: { description: "The day.", view: "JournalSnapshot" },
32473
+ errors: { 400: true },
32474
+ operationId: "journal_add_entry"
32475
+ },
32476
+ correct: {
32477
+ method: "patch",
32478
+ path: "/journal/days/{date}",
32479
+ scopes: ["journal:write"],
32480
+ tag: "Journal",
32481
+ summary: "Correct a Journal day",
32482
+ description: "Fix the day (`journal_correct`): `title`, `summary` (null clears it), `highlights` and `tags` replace what's there, `removeLinks` unlinks nodes, `metrics` log a corrected value for the day, `status` and `hiddenFromMemories` set those. The member's own correction marks the day reviewed. 404 when the date has no Journal day. Returns the snapshot.",
32483
+ pathParams: {
32484
+ date: { description: "The day, `YYYY-MM-DD`.", format: "date" }
32485
+ },
32486
+ pathParamSchemas: { date: journalDateSchema },
32487
+ body: journalCorrectInputSchema,
32488
+ status: 200,
32489
+ response: { description: "The day.", view: "JournalSnapshot" },
32490
+ errors: { 400: true, 404: "No Journal day on that date." },
32491
+ operationId: "journal_correct"
32492
+ },
32493
+ stageImport: {
32494
+ method: "post",
32495
+ path: "/journal/imports",
32496
+ scopes: ["journal:write"],
32497
+ tag: "Journal",
32498
+ summary: "Stage daily notes for the backfill",
32499
+ description: "Stage parsed daily notes (`do journal import push <dir>`): one item per day (at most 400 a request) with its source file and hash, what becomes its entry (`summary`, `retro` or `log`), a one-liner, the summary's text (health lines left out), a clear `rating` or a `ratingQuestion` (\"~5/10\"), a highlight, whether it may be a milestone or had health lines, and the links counted. Nothing is written into the Journal: the member reviews and approves each month in the app, and a key can't approve. A day still waiting is replaced; one already imported is left alone (`alreadyImported`). Staged days stand behind the Journal's wall.",
32500
+ body: journalImportUploadInputSchema,
32501
+ status: 200,
32502
+ response: { description: "How the upload went.", view: "JournalImportUpload" },
32503
+ errors: { 400: true }
32504
+ },
32505
+ importOverview: {
32506
+ method: "get",
32507
+ path: "/journal/imports",
32508
+ scopes: ["journal:read"],
32509
+ tag: "Journal",
32510
+ summary: "What the backfill has staged",
32511
+ description: "The key's member's staged days: the source folder, how many files over which dates, what the parser found (summaries, ratings and the unclear ones, milestone candidates, days with health lines, links), each month's batch (days, ready, needing the member, imported), and one batch's days (`?batch=YYYY-MM`, else the newest still waiting), each with its `state`: `ready`, `needs_you`, `today` (never imported), `imported` or `skipped`.",
32512
+ afterScopes: "`*` does not cover it.",
32513
+ query: [{ name: "batch", description: "A month, `YYYY-MM`." }],
32514
+ querySchema: journalImportQuerySchema,
32515
+ status: 200,
32516
+ response: { description: "The overview.", view: "JournalImportOverview" },
32517
+ errors: { 400: true }
32518
+ },
32519
+ milestones: {
32520
+ method: "get",
32521
+ path: "/journal/milestones",
32522
+ scopes: ["journal:read"],
32523
+ tag: "Journal",
32524
+ summary: "The life timeline",
32525
+ description: "The key's member's milestones and the Space's shared ones, oldest first: title, kind, when (`happenedOn` at its `precision`: year, month or day), `planned` (still ahead), `status` (`suggested` by an agent and not kept yet, or `kept`), `visibility` (`owner` = Only me, the default; `space` = shared), the nodes it is about (each with its title, type and, for a Project, its `status`), the Journal day it happened on (rating, photos) when the date is a day, and whether it reminds yearly.",
32526
+ afterScopes: "`*` does not cover it.",
32527
+ status: 200,
32528
+ response: { description: "The timeline.", view: "JournalMilestoneList" }
32529
+ },
32530
+ createMilestone: {
32531
+ method: "post",
32532
+ path: "/journal/milestones",
32533
+ scopes: ["journal:write"],
32534
+ tag: "Journal",
32535
+ summary: "Mark a milestone",
32536
+ description: "Mark a milestone (`journal_mark_milestone`): a title, a kind, when and how exactly, planned or not, a line about it, Only me (default) or shared, the nodes it is about (`links`: a Journal day, a paper, a project, a person) and `remindYearly` (a yearly `anniversary` Key date; needs a day). An agent's mark is `suggested` unless it sends `status: kept`; the member keeps or removes it.",
32537
+ body: journalCreateMilestoneInputSchema,
32538
+ status: 201,
32539
+ response: { description: "The milestone.", view: "JournalMilestone" },
32540
+ errors: { 400: true }
32541
+ },
32542
+ updateMilestone: {
32543
+ method: "patch",
32544
+ path: "/journal/milestones/{id}",
32545
+ scopes: ["journal:write"],
32546
+ tag: "Journal",
32547
+ summary: "Change a milestone",
32548
+ description: "Change what's given; `status: kept` keeps a suggestion; `addLinks` / `removeLinks` link or unlink; `remindYearly` turns the yearly Key date on or off (it moves with the date). 404 for someone else's Only me milestone.",
32549
+ pathParams: {
32550
+ id: "The milestone's id."
32551
+ },
32552
+ pathParamSchemas: { id: ulidSchema },
32553
+ body: journalUpdateMilestoneInputSchema,
32554
+ status: 200,
32555
+ response: { description: "The milestone.", view: "JournalMilestone" },
32556
+ errors: { 400: true, 404: "No such milestone." }
32557
+ },
32558
+ removeMilestone: {
32559
+ method: "delete",
32560
+ path: "/journal/milestones/{id}",
32561
+ scopes: ["journal:write"],
32562
+ tag: "Journal",
32563
+ summary: "Remove a milestone",
32564
+ description: "Remove a milestone (to the trash) and its yearly reminder.",
32565
+ pathParams: {
32566
+ id: "The milestone's id."
32567
+ },
32568
+ pathParamSchemas: { id: ulidSchema },
32569
+ status: 204,
32570
+ response: { description: "Removed." },
32571
+ errors: { 404: "No such milestone." }
32572
+ },
32573
+ week: {
32574
+ method: "get",
32575
+ path: "/journal/weeks/{week}",
32576
+ scopes: ["journal:read"],
32577
+ tag: "Journal",
32578
+ summary: "A Journal week",
32579
+ description: "One ISO week of the key's member: the week's recap (the prose, up to 3 best moments, one pattern line; null until written), the week's days with a Journal day or a Metric value (as `GET /journal/days`), `usual` (the mean day rating over the eight weeks before) and the numbers from Progress and the Metrics: what landed (and how much of it was the member's own), each habit's done and due days, the average sleep and the nights to bed after midnight.",
32580
+ afterScopes: "`*` does not cover it.",
32581
+ pathParams: {
32582
+ week: "The ISO week, `YYYY-Www` (e.g. `2026-W42`)."
32583
+ },
32584
+ pathParamSchemas: { week: journalWeekKeySchema },
32585
+ status: 200,
32586
+ response: { description: "The week.", view: "JournalWeek" },
32587
+ errors: { 400: true }
32588
+ },
32589
+ writeRecap: {
32590
+ method: "put",
32591
+ path: "/journal/weeks/{week}/recap",
32592
+ scopes: ["journal:write"],
32593
+ tag: "Journal",
32594
+ summary: "Write a week's recap",
32595
+ description: "The agent's Sunday recap (`journal_write_recap`) or the member's: `body` (markdown) replaces the prose; `moments` (at most 3, `{ text, date?, nodeId? }`) and `pattern` replace theirs when given (`pattern: null` clears it). The recap is owner-only like the days. A week that hasn't started is a 400. Returns the week.",
32596
+ pathParams: {
32597
+ week: "The ISO week, `YYYY-Www` (e.g. `2026-W42`)."
32598
+ },
32599
+ pathParamSchemas: { week: journalWeekKeySchema },
32600
+ body: journalWriteRecapInputSchema,
32601
+ status: 200,
32602
+ response: { description: "The week.", view: "JournalWeek" },
32603
+ errors: { 400: true }
32604
+ },
32605
+ recall: {
32606
+ method: "get",
32607
+ path: "/journal/recall",
32608
+ scopes: ["journal:read"],
32609
+ tag: "Journal",
32610
+ summary: "Recall the Journal",
32611
+ description: "The agent's recall (`journal_recall`): \"what did I do / how was I around <date or topic>\" over the key's member's own days only (another member's days never answer). `q` (2+ characters) finds the days that mention it; `around` (a day) reads 3 days either side; `from`/`to` read a window (at most 366 days); words and a window combine; with neither, the last 7 days. Returns the days newest first (as `GET /journal/days`, at most `limit`, 30 by default), how many were rated and their mean, the member's kept milestones within a week of the window, and the window's last day in up to 3 earlier years (a day hidden from memories left out), so an answer can cite dates.",
32612
+ afterScopes: "`*` does not cover it.",
32613
+ query: [
32614
+ { name: "q", description: "Words to look for (2+ characters)." },
32615
+ { name: "around", description: "A day, YYYY-MM-DD: 3 days either side." },
32616
+ { name: "from", description: "The window's first day, YYYY-MM-DD." },
32617
+ { name: "to", description: "The window's last day, YYYY-MM-DD." },
32618
+ { name: "limit", description: "At most this many days (1\u201330)." }
32619
+ ],
32620
+ querySchema: journalRecallQuerySchema,
32621
+ status: 200,
32622
+ response: { description: "The days that answer.", view: "JournalRecall" },
32623
+ errors: { 400: true },
32624
+ operationId: "journal_recall"
32625
+ },
32626
+ digest: {
32627
+ method: "get",
32628
+ path: "/journal/digest",
32629
+ scopes: ["journal:read"],
32630
+ tag: "Journal",
32631
+ summary: "The Journal digest",
32632
+ description: "The last 7 days of the key's member's Journal, for the agent's private session context: each day's one line and rating (oldest first), the member's kept milestones a week either side, and `text`, the same as a few plain lines (a few hundred tokens).",
32633
+ afterScopes: "`*` does not cover it.",
32634
+ status: 200,
32635
+ response: { description: "The digest.", view: "JournalDigest" },
32636
+ operationId: "journal_digest"
32637
+ },
32638
+ month: {
32639
+ method: "get",
32640
+ path: "/journal/months/{month}",
32641
+ scopes: ["journal:read"],
32642
+ tag: "Journal",
32643
+ summary: "A Journal month",
32644
+ description: "One month of the key's member: the month's recap (the prose, up to 3 best moments, one pattern line; null until written), the month's days with a Journal day or a Metric value (as `GET /journal/days`), `usual` (the mean day rating over the three months before), the numbers from Progress and the Metrics (what landed and how much was the member's own, each habit's done and due days, the average sleep and the nights to bed after midnight) and the member's own kept milestones that happened in it.",
32645
+ afterScopes: "`*` does not cover it.",
32646
+ pathParams: {
32647
+ month: "The month, `YYYY-MM` (e.g. `2026-10`)."
32648
+ },
32649
+ pathParamSchemas: { month: journalMonthKeySchema },
32650
+ status: 200,
32651
+ response: { description: "The month.", view: "JournalMonth" },
32652
+ errors: { 400: true }
32653
+ },
32654
+ writeMonthRecap: {
32655
+ method: "put",
32656
+ path: "/journal/months/{month}/recap",
32657
+ scopes: ["journal:write"],
32658
+ tag: "Journal",
32659
+ summary: "Write a month's recap",
32660
+ description: "The agent's recap on the 1st or the member's: `body` (markdown) replaces the prose; `moments` (at most 3, `{ text, date?, nodeId? }`) and `pattern` replace theirs when given (`pattern: null` clears it). Owner-only like the days. A month that hasn't started is a 400. Returns the month.",
32661
+ pathParams: {
32662
+ month: "The month, `YYYY-MM` (e.g. `2026-10`)."
32663
+ },
32664
+ pathParamSchemas: { month: journalMonthKeySchema },
32665
+ body: journalWriteRecapInputSchema,
32666
+ status: 200,
32667
+ response: { description: "The month.", view: "JournalMonth" },
32668
+ errors: { 400: true }
32669
+ },
32670
+ year: {
32671
+ method: "get",
32672
+ path: "/journal/years/{year}",
32673
+ scopes: ["journal:read"],
32674
+ tag: "Journal",
32675
+ summary: "A Journal year",
32676
+ description: "One year of the key's member: the year's recap (null until written), the year's days (its rating pixels), each begun month's average rating, rated and kept days and best day, `usual` (the mean day rating of the year before), the numbers from Progress and the Metrics, and the member's own kept milestones of the year.",
32677
+ afterScopes: "`*` does not cover it.",
32678
+ pathParams: {
32679
+ year: "The year, `YYYY` (e.g. `2026`)."
32680
+ },
32681
+ pathParamSchemas: { year: journalYearKeySchema },
32682
+ status: 200,
32683
+ response: { description: "The year.", view: "JournalYear" },
32684
+ errors: { 400: true }
32685
+ },
32686
+ writeYearRecap: {
32687
+ method: "put",
32688
+ path: "/journal/years/{year}/recap",
32689
+ scopes: ["journal:write"],
32690
+ tag: "Journal",
32691
+ summary: "Write a year's recap",
32692
+ description: "The agent's recap on 1 January or the member's, the same input as a week's: `body` replaces the prose; `moments` and `pattern` replace theirs when given. Owner-only like the days. A year that hasn't started is a 400. Returns the year.",
32693
+ pathParams: {
32694
+ year: "The year, `YYYY` (e.g. `2026`)."
32695
+ },
32696
+ pathParamSchemas: { year: journalYearKeySchema },
32697
+ body: journalWriteRecapInputSchema,
32698
+ status: 200,
32699
+ response: { description: "The year.", view: "JournalYear" },
32700
+ errors: { 400: true }
32701
+ }
32702
+ });
32703
+
32332
32704
  // ../../packages/schema/src/operations/keys.ts
32333
32705
  var keyOperations = defineOperations({
32334
32706
  list: {
@@ -34884,7 +35256,7 @@ function parseCapture2(input, now) {
34884
35256
 
34885
35257
  // src/meta.ts
34886
35258
  var CLI_NAME = "do";
34887
- var VERSION = "1.308.0";
35259
+ var VERSION = "1.308.1";
34888
35260
  var API_PREFIX = "/api/v1";
34889
35261
  var DEFAULT_API_URL = "http://localhost:3001";
34890
35262
 
@@ -35113,7 +35485,6 @@ function resolveConfig(io, flags) {
35113
35485
  }
35114
35486
 
35115
35487
  // src/contacts-commands.ts
35116
- var WRITE6 = ["contacts:write"];
35117
35488
  var FIELD_FLAGS = [
35118
35489
  { name: "name", type: "string", description: "The display name (or pass it as the argument)." },
35119
35490
  { name: "kind", type: "string", description: "person (the default) or organization." },
@@ -35156,7 +35527,7 @@ var CONTACT_COMMAND_SPECS = [
35156
35527
  summary: "Add a contact: a person or an organisation, with their details.",
35157
35528
  args: [{ name: "name", required: false, description: "The display name." }],
35158
35529
  flags: FIELD_FLAGS,
35159
- scopes: WRITE6,
35530
+ scopes: [...contactOperations.create.scopes],
35160
35531
  returns: "ContactView",
35161
35532
  notes: 'Flags build a CreateContactInput; --data adds any other field (a flag wins). The id is minted when omitted. e.g. `do contacts create "Sam Peters" --email sam@example.com --birthday 1990-04-12 --circles <id>`.'
35162
35533
  },
@@ -35165,7 +35536,7 @@ var CONTACT_COMMAND_SPECS = [
35165
35536
  summary: "Change a contact's details.",
35166
35537
  args: [{ name: "id", required: true, description: "The contact's id." }],
35167
35538
  flags: FIELD_FLAGS,
35168
- scopes: WRITE6,
35539
+ scopes: [...contactOperations.update.scopes],
35169
35540
  returns: "ContactView",
35170
35541
  notes: "Only the flags you pass change. `none` clears a field (--email none, --birthday none). --birthday keeps the contact's other dates; --roles, --circles and --tags replace the list (a role it already has keeps its details)."
35171
35542
  }
@@ -35428,12 +35799,9 @@ var ENTITIES = [
35428
35799
  createInput: "CreateNoteInput",
35429
35800
  updateInput: "UpdateNoteInput"
35430
35801
  }),
35431
- {
35802
+ entityFromOperations(contactOperations, {
35432
35803
  name: "contacts",
35433
- path: "/contacts",
35434
- readScopes: ["contacts:read"],
35435
35804
  returns: "Contact",
35436
- canGet: true,
35437
35805
  listFlags: [
35438
35806
  { name: "kind", description: "only person or only organization contacts", query: "kind" },
35439
35807
  {
@@ -35448,15 +35816,9 @@ var ENTITIES = [
35448
35816
  sends: "true"
35449
35817
  }
35450
35818
  ],
35451
- write: {
35452
- scopes: ["contacts:write"],
35453
- createSchema: createContactInputSchema,
35454
- createInput: "CreateContactInput",
35455
- updateSchema: updateContactInputSchema,
35456
- updateInput: "UpdateContactInput",
35457
- canDelete: true
35458
- }
35459
- },
35819
+ createInput: "CreateContactInput",
35820
+ updateInput: "UpdateContactInput"
35821
+ }),
35460
35822
  {
35461
35823
  name: "contact-moments",
35462
35824
  path: "/contact-moments",
@@ -35826,7 +36188,7 @@ function entityOperations(e) {
35826
36188
 
35827
36189
  // src/health-commands.ts
35828
36190
  var READ6 = ["health:read"];
35829
- var WRITE7 = ["health:write"];
36191
+ var WRITE6 = ["health:write"];
35830
36192
  var DATA_FLAG = {
35831
36193
  name: "data",
35832
36194
  type: "string",
@@ -35856,7 +36218,7 @@ function recordSpecs(plural, singular, noun, returns, createInput, updateInput,
35856
36218
  summary: `Add a health ${noun} (--data '${createInput}').`,
35857
36219
  args: [],
35858
36220
  flags: [DATA_FLAG, ...addFlags],
35859
- scopes: WRITE7,
36221
+ scopes: WRITE6,
35860
36222
  returns,
35861
36223
  notes: `Body: ${createInput}. Always private to you; subjectNodeId names who it is about (absent = you).`
35862
36224
  },
@@ -35865,7 +36227,7 @@ function recordSpecs(plural, singular, noun, returns, createInput, updateInput,
35865
36227
  summary: `Change a health ${noun} (--data '${updateInput}').`,
35866
36228
  args: [id],
35867
36229
  flags: [DATA_FLAG],
35868
- scopes: WRITE7,
36230
+ scopes: WRITE6,
35869
36231
  returns,
35870
36232
  notes: `Body: ${updateInput}. null clears a field.`
35871
36233
  },
@@ -35874,7 +36236,7 @@ function recordSpecs(plural, singular, noun, returns, createInput, updateInput,
35874
36236
  summary: `Delete a health ${noun}.`,
35875
36237
  args: [id],
35876
36238
  flags: [],
35877
- scopes: WRITE7,
36239
+ scopes: WRITE6,
35878
36240
  returns: "Deleted",
35879
36241
  notes: "Destructive: needs --allow-destructive. An Agent's delete waits on your confirmation."
35880
36242
  }
@@ -35924,7 +36286,7 @@ var HEALTH_COMMAND_SPECS = [
35924
36286
  description: `Sex, in your words, for the doctor's page ("female"); "" clears it.`
35925
36287
  }
35926
36288
  ],
35927
- scopes: WRITE7,
36289
+ scopes: WRITE6,
35928
36290
  returns: "HealthProfile",
35929
36291
  notes: "Body: UpdateHealthProfileInput. An absent key keeps a field; null clears it. Lifestyle is `alcohol`, `smoking`, `exercise`, and `notes` anything else: the member's own words. Notes go on For the doctor's background; `sex` on its patient line."
35930
36292
  },
@@ -35933,7 +36295,7 @@ var HEALTH_COMMAND_SPECS = [
35933
36295
  summary: "Log one health message: find or start the Episode, add a symptom and/or a dose.",
35934
36296
  args: [],
35935
36297
  flags: [DATA_FLAG],
35936
- scopes: WRITE7,
36298
+ scopes: WRITE6,
35937
36299
  returns: "HealthReceipt",
35938
36300
  notes: 'Body: LogHealthInput, e.g. {"episode":{"title":"Sprained ankle","bodyRegion":"ankle_l"},"symptom":{"symptom":"worse on the stairs","severity":6,"severityGuessed":true},"dose":{"medication":"Ibuprofen"}}. The receipt lists each part with a line, what was guessed, and its undo. With "thread":{"slug":"<agent>"} (only an agent key that converses) the receipt card is posted there too, and postId names it.'
35939
36301
  },
@@ -35942,7 +36304,7 @@ var HEALTH_COMMAND_SPECS = [
35942
36304
  summary: `Correct a symptom entry and get a receipt (--data '{"bodyRegion":"ankle_l"}').`,
35943
36305
  args: [{ name: "entry", required: true, description: "The entry's id (its latest version)." }],
35944
36306
  flags: [DATA_FLAG],
35945
- scopes: WRITE7,
36307
+ scopes: WRITE6,
35946
36308
  returns: "HealthReceipt"
35947
36309
  },
35948
36310
  {
@@ -35953,7 +36315,7 @@ var HEALTH_COMMAND_SPECS = [
35953
36315
  { name: "trend", required: true, description: "better|same|worse, against yesterday." }
35954
36316
  ],
35955
36317
  flags: [],
35956
- scopes: WRITE7,
36318
+ scopes: WRITE6,
35957
36319
  returns: "HealthReceipt",
35958
36320
  notes: "One a day: a second check-in the same day corrects the first. The receipt carries its undo."
35959
36321
  },
@@ -35970,7 +36332,7 @@ var HEALTH_COMMAND_SPECS = [
35970
36332
  description: "Post the confirmation card in this thread (by slug); the agent's key only."
35971
36333
  }
35972
36334
  ],
35973
- scopes: WRITE7,
36335
+ scopes: WRITE6,
35974
36336
  returns: "HealthRedFlagsResult",
35975
36337
  notes: "Flags: fever, vomiting, black_stools, blood, weight_loss, night_pain, chest_pain, short_of_breath. Answers merge into those asked before; the Episode is marked checked today, and For the doctor shows it."
35976
36338
  },
@@ -35982,7 +36344,7 @@ var HEALTH_COMMAND_SPECS = [
35982
36344
  { name: "id", required: true, description: "The id from the receipt's undo." }
35983
36345
  ],
35984
36346
  flags: [],
35985
- scopes: WRITE7,
36347
+ scopes: WRITE6,
35986
36348
  returns: "HealthUndoResult",
35987
36349
  notes: "A POST, so an Agent's undo never waits on a confirmation."
35988
36350
  },
@@ -35991,7 +36353,7 @@ var HEALTH_COMMAND_SPECS = [
35991
36353
  summary: "Find the open Episode a complaint belongs to, or start one (--data UpsertHealthEpisodeInput).",
35992
36354
  args: [],
35993
36355
  flags: [DATA_FLAG],
35994
- scopes: WRITE7,
36356
+ scopes: WRITE6,
35995
36357
  returns: "HealthEpisodeUpsert"
35996
36358
  },
35997
36359
  {
@@ -36033,7 +36395,7 @@ var HEALTH_COMMAND_SPECS = [
36033
36395
  summary: "Take a For-the-doctor link back: it stops opening.",
36034
36396
  args: [{ name: "id", required: true, description: "The share's id." }],
36035
36397
  flags: [],
36036
- scopes: WRITE7,
36398
+ scopes: WRITE6,
36037
36399
  returns: "HealthShare"
36038
36400
  },
36039
36401
  ...recordSpecs("conditions", "condition", "condition", "HealthConditionView", "CreateHealthConditionInput", "UpdateHealthConditionInput"),
@@ -36051,7 +36413,7 @@ var HEALTH_COMMAND_SPECS = [
36051
36413
  description: 'Their role on it, in your words ("dermatologist").'
36052
36414
  }
36053
36415
  ],
36054
- scopes: WRITE7,
36416
+ scopes: WRITE6,
36055
36417
  returns: "HealthConditionView",
36056
36418
  notes: "A cared_by link (condition \u2192 contact). Adding one already on it sets the role. The condition's page, the Health home's Care team and For the doctor list them."
36057
36419
  },
@@ -36063,7 +36425,7 @@ var HEALTH_COMMAND_SPECS = [
36063
36425
  { name: "contact", required: true, description: "The Contact's id." }
36064
36426
  ],
36065
36427
  flags: [],
36066
- scopes: WRITE7,
36428
+ scopes: WRITE6,
36067
36429
  returns: "HealthConditionView",
36068
36430
  notes: "An Agent's removal waits on your confirmation, like a delete."
36069
36431
  },
@@ -36100,7 +36462,7 @@ var HEALTH_COMMAND_SPECS = [
36100
36462
  { name: "at", type: "string", description: "When it happened (ISO); defaults to now." },
36101
36463
  { name: "note", type: "string", description: "A free-text note." }
36102
36464
  ],
36103
- scopes: WRITE7,
36465
+ scopes: WRITE6,
36104
36466
  returns: "HealthSymptomEntry",
36105
36467
  notes: "An Agent's entry is source chat. For qualifiers, send --data with LogHealthSymptomInput."
36106
36468
  },
@@ -36116,7 +36478,7 @@ var HEALTH_COMMAND_SPECS = [
36116
36478
  }
36117
36479
  ],
36118
36480
  flags: [DATA_FLAG],
36119
- scopes: WRITE7,
36481
+ scopes: WRITE6,
36120
36482
  returns: "HealthSymptomEntry",
36121
36483
  notes: "Body: CorrectHealthSymptomInput; fields not named are copied. The history stays."
36122
36484
  },
@@ -36128,7 +36490,7 @@ var HEALTH_COMMAND_SPECS = [
36128
36490
  { name: "entry", required: true, description: "The entry's id." }
36129
36491
  ],
36130
36492
  flags: [],
36131
- scopes: WRITE7,
36493
+ scopes: WRITE6,
36132
36494
  returns: "Deleted"
36133
36495
  },
36134
36496
  ...recordSpecs("visits", "visit", "visit", "HealthEncounterView", "CreateHealthEncounterInput", "UpdateHealthEncounterInput"),
@@ -36152,7 +36514,7 @@ var HEALTH_COMMAND_SPECS = [
36152
36514
  { name: "at", type: "string", description: "When (ISO); defaults to now." },
36153
36515
  { name: "note", type: "string", description: "A free-text note." }
36154
36516
  ],
36155
- scopes: WRITE7,
36517
+ scopes: WRITE6,
36156
36518
  returns: "HealthMedicationDose"
36157
36519
  },
36158
36520
  {
@@ -36163,7 +36525,7 @@ var HEALTH_COMMAND_SPECS = [
36163
36525
  { name: "dose", required: true, description: "The dose's id." }
36164
36526
  ],
36165
36527
  flags: [DATA_FLAG],
36166
- scopes: WRITE7,
36528
+ scopes: WRITE6,
36167
36529
  returns: "HealthMedicationDose",
36168
36530
  notes: "Body: UpdateHealthDoseInput."
36169
36531
  },
@@ -36175,7 +36537,7 @@ var HEALTH_COMMAND_SPECS = [
36175
36537
  { name: "dose", required: true, description: "The dose's id." }
36176
36538
  ],
36177
36539
  flags: [],
36178
- scopes: WRITE7,
36540
+ scopes: WRITE6,
36179
36541
  returns: "Deleted"
36180
36542
  },
36181
36543
  ...recordSpecs("labs", "lab", "lab draw", "HealthLabPanelView", "CreateHealthLabPanelInput", "UpdateHealthLabPanelInput"),
@@ -36197,7 +36559,7 @@ var HEALTH_COMMAND_SPECS = [
36197
36559
  description: "The file's media type, when its name doesn't say."
36198
36560
  }
36199
36561
  ],
36200
- scopes: WRITE7,
36562
+ scopes: WRITE6,
36201
36563
  returns: "HealthLabImportResult",
36202
36564
  notes: "The draw stays a draft (status draft, source import) until the member checks it; the report is kept as its original. A report with no lab value in it is a 422."
36203
36565
  },
@@ -36282,7 +36644,7 @@ var HEALTH_COMMAND_SPECS = [
36282
36644
  summary: `Keep a target band or the supplement for an analyte (--data '{"targetLow":40,"targetHigh":60}').`,
36283
36645
  args: [{ name: "analyte", required: true, description: "The analyte key (vitamin_d)." }],
36284
36646
  flags: [DATA_FLAG],
36285
- scopes: WRITE7,
36647
+ scopes: WRITE6,
36286
36648
  returns: "HealthLabAnalyteView",
36287
36649
  notes: "Body: SetHealthLabAnalyteInput. An absent key keeps a field; null clears it."
36288
36650
  }
@@ -36626,9 +36988,9 @@ var COMMAND_SPECS = [
36626
36988
  summary: "One Journal day: the summary, entries and highlights, and what happened (Metrics, landed, habits, events, links).",
36627
36989
  args: [{ name: "date", required: true, description: "The day, YYYY-MM-DD." }],
36628
36990
  flags: [],
36629
- scopes: ["journal:read"],
36991
+ scopes: [...journalOperations.day.scopes],
36630
36992
  returns: "JournalSnapshot",
36631
- notes: "GET /api/v1/journal/days/{date} \u2014 your own days only. journal:read is a sensitive scope: a full-access (*) key doesn't hold it. `day` is null until a Journal day was written."
36993
+ notes: `${routeOf(journalOperations.day)} \u2014 your own days only. journal:read is a sensitive scope: a full-access (*) key doesn't hold it. \`day\` is null until a Journal day was written.`
36632
36994
  },
36633
36995
  {
36634
36996
  path: ["journal", "days"],
@@ -36642,18 +37004,18 @@ var COMMAND_SPECS = [
36642
37004
  description: "The last day, YYYY-MM-DD (at most 366 days on)."
36643
37005
  }
36644
37006
  ],
36645
- scopes: ["journal:read"],
37007
+ scopes: [...journalOperations.range.scopes],
36646
37008
  returns: "JournalDayList",
36647
- notes: "GET /api/v1/journal/days \u2014 lists only days with a Journal day or a Metric value. journal:read is a sensitive scope."
37009
+ notes: `${routeOf(journalOperations.range)} \u2014 lists only days with a Journal day or a Metric value. journal:read is a sensitive scope.`
36648
37010
  },
36649
37011
  {
36650
37012
  path: ["journal", "search"],
36651
37013
  summary: "Your Journal days that mention some words, newest first.",
36652
37014
  args: [{ name: "words", required: true, description: "What to look for (2+ characters)." }],
36653
37015
  flags: [],
36654
- scopes: ["journal:read"],
37016
+ scopes: [...journalOperations.search.scopes],
36655
37017
  returns: "JournalSearch",
36656
- notes: "GET /api/v1/journal/search?q= \u2014 your own days only, best match first (at most 30): the words (and a few that mean the same, English and Dutch) in the one-liner, tags, highlights, summary and entries; a date phrase (in March, last week, 14 October, 2026-02) narrows to its window; a heavy or bright question (rough, tired, a great day) adds the days rated 4 or less / 8 or more. `understood` says how it was read. journal:read is a sensitive scope."
37018
+ notes: `${routeOf(journalOperations.search)}?q= \u2014 your own days only, best match first (at most 30): the words (and a few that mean the same, English and Dutch) in the one-liner, tags, highlights, summary and entries; a date phrase (in March, last week, 14 October, 2026-02) narrows to its window; a heavy or bright question (rough, tired, a great day) adds the days rated 4 or less / 8 or more. \`understood\` says how it was read. journal:read is a sensitive scope.`
36657
37019
  },
36658
37020
  {
36659
37021
  path: ["journal", "recall"],
@@ -36669,9 +37031,9 @@ var COMMAND_SPECS = [
36669
37031
  { name: "to", type: "string", description: "The window's last day, YYYY-MM-DD." },
36670
37032
  { name: "limit", type: "string", description: "At most this many days (1\u201330)." }
36671
37033
  ],
36672
- scopes: ["journal:read"],
37034
+ scopes: [...journalOperations.recall.scopes],
36673
37035
  returns: "JournalRecall",
36674
- notes: "GET /api/v1/journal/recall (journal_recall) \u2014 your own days only, dated so an answer can cite them; another member's days never answer. --around can't be combined with --from/--to. journal:read is a sensitive scope."
37036
+ notes: `${routeOf(journalOperations.recall)} (journal_recall) \u2014 your own days only, dated so an answer can cite them; another member's days never answer. --around can't be combined with --from/--to. journal:read is a sensitive scope.`
36675
37037
  },
36676
37038
  {
36677
37039
  path: ["journal", "like"],
@@ -36684,45 +37046,45 @@ var COMMAND_SPECS = [
36684
37046
  description: "At most this many days (1\u201310, 5 by default)."
36685
37047
  }
36686
37048
  ],
36687
- scopes: ["journal:read"],
37049
+ scopes: [...journalOperations.like.scopes],
36688
37050
  returns: "JournalLike",
36689
- notes: "GET /api/v1/journal/days/{date}/like (journal_like) \u2014 your own days only, by Postgres full text over the one-liner, highlights, tags, summary and entries (the day's own words, with a few that mean the same), then shared tags and a close rating. Words, not meanings: no embeddings. A day hidden from memories is never offered. journal:read is a sensitive scope."
37051
+ notes: `${routeOf(journalOperations.like)} (journal_like) \u2014 your own days only, by Postgres full text over the one-liner, highlights, tags, summary and entries (the day's own words, with a few that mean the same), then shared tags and a close rating. Words, not meanings: no embeddings. A day hidden from memories is never offered. journal:read is a sensitive scope.`
36690
37052
  },
36691
37053
  {
36692
37054
  path: ["journal", "digest"],
36693
37055
  summary: "The last 7 days of your Journal as a short digest: each day's line and rating, and the milestones a week either side.",
36694
37056
  args: [],
36695
37057
  flags: [],
36696
- scopes: ["journal:read"],
37058
+ scopes: [...journalOperations.digest.scopes],
36697
37059
  returns: "JournalDigest",
36698
- notes: "GET /api/v1/journal/digest \u2014 `text` is the few plain lines an agent keeps in its private session. journal:read is a sensitive scope."
37060
+ notes: `${routeOf(journalOperations.digest)} \u2014 \`text\` is the few plain lines an agent keeps in its private session. journal:read is a sensitive scope.`
36699
37061
  },
36700
37062
  {
36701
37063
  path: ["journal", "week"],
36702
37064
  summary: "One week of the Journal: its recap (prose, best moments, a pattern), its days, the usual rating and the numbers from Progress.",
36703
37065
  args: [{ name: "week", required: true, description: "The ISO week, e.g. 2026-W42." }],
36704
37066
  flags: [],
36705
- scopes: ["journal:read"],
37067
+ scopes: [...journalOperations.week.scopes],
36706
37068
  returns: "JournalWeek",
36707
- notes: "GET /api/v1/journal/weeks/{week} \u2014 your own week only. `recap` is null until one was written. journal:read is a sensitive scope."
37069
+ notes: `${routeOf(journalOperations.week)} \u2014 your own week only. \`recap\` is null until one was written. journal:read is a sensitive scope.`
36708
37070
  },
36709
37071
  {
36710
37072
  path: ["journal", "month"],
36711
37073
  summary: "One month of the Journal: its recap, its days, the usual rating, the numbers from Progress and the milestones that happened in it.",
36712
37074
  args: [{ name: "month", required: true, description: "The month, e.g. 2026-10." }],
36713
37075
  flags: [],
36714
- scopes: ["journal:read"],
37076
+ scopes: [...journalOperations.month.scopes],
36715
37077
  returns: "JournalMonth",
36716
- notes: "GET /api/v1/journal/months/{month} \u2014 your own month only. `recap` is null until one was written; `usual` is the mean rating over the three months before. journal:read is a sensitive scope."
37078
+ notes: `${routeOf(journalOperations.month)} \u2014 your own month only. \`recap\` is null until one was written; \`usual\` is the mean rating over the three months before. journal:read is a sensitive scope.`
36717
37079
  },
36718
37080
  {
36719
37081
  path: ["journal", "year"],
36720
37082
  summary: "One year of the Journal: its recap, its days (the rating pixels), each month's average and best day, the usual, the numbers and the year's milestones.",
36721
37083
  args: [{ name: "year", required: true, description: "The year, e.g. 2026." }],
36722
37084
  flags: [],
36723
- scopes: ["journal:read"],
37085
+ scopes: [...journalOperations.year.scopes],
36724
37086
  returns: "JournalYear",
36725
- notes: "GET /api/v1/journal/years/{year} \u2014 your own year only. `recap` is null until one was written; `usual` is the mean rating of the year before. journal:read is a sensitive scope."
37087
+ notes: `${routeOf(journalOperations.year)} \u2014 your own year only. \`recap\` is null until one was written; \`usual\` is the mean rating of the year before. journal:read is a sensitive scope.`
36726
37088
  },
36727
37089
  {
36728
37090
  path: ["journal", "recap"],
@@ -36742,9 +37104,9 @@ var COMMAND_SPECS = [
36742
37104
  description: 'The JournalWriteRecapInput as JSON, merged under --body: {"body":"\u2026","moments":[{"text":"\u2026","date":"2026-10-14","nodeId":"\u2026"}],"pattern":"\u2026"}.'
36743
37105
  }
36744
37106
  ],
36745
- scopes: ["journal:write"],
37107
+ scopes: [...journalOperations.writeRecap.scopes],
36746
37108
  returns: "JournalWeek",
36747
- notes: "PUT /api/v1/journal/weeks/{week}/recap (journal_write_recap), /api/v1/journal/months/{month}/recap or /api/v1/journal/years/{year}/recap, by the period's shape. The body replaces the prose; moments and pattern replace theirs when given (pattern null clears it). Returns the period (a JournalWeek, JournalMonth or JournalYear)."
37109
+ notes: `${routeOf(journalOperations.writeRecap)} (journal_write_recap), /api/v1/journal/months/{month}/recap or /api/v1/journal/years/{year}/recap, by the period's shape. The body replaces the prose; moments and pattern replace theirs when given (pattern null clears it). Returns the period (a JournalWeek, JournalMonth or JournalYear).`
36748
37110
  },
36749
37111
  {
36750
37112
  path: ["journal", "write"],
@@ -36760,9 +37122,9 @@ var COMMAND_SPECS = [
36760
37122
  description: 'The JournalWriteDayInput as JSON, merged under the flags: {"summary":"\u2026","highlights":[{"text":"\u2026","nodeId":"\u2026"}],"tags":["Home"],"links":[{"kind":"saw","nodeId":"\u2026"}],"metrics":{"rating":7,"mood":4}}.'
36761
37123
  }
36762
37124
  ],
36763
- scopes: ["journal:write"],
37125
+ scopes: [...journalOperations.write.scopes],
36764
37126
  returns: "JournalSnapshot",
36765
- notes: "POST /api/v1/journal/days/{date} (journal_write_day). Makes the day when missing. Highlights replace; tags and links add. An agent's write shows in the member's change list with Undo."
37127
+ notes: `${routeOf(journalOperations.write)} (journal_write_day). Makes the day when missing. Highlights replace; tags and links add. An agent's write shows in the member's change list with Undo.`
36766
37128
  },
36767
37129
  {
36768
37130
  path: ["journal", "add"],
@@ -36772,9 +37134,9 @@ var COMMAND_SPECS = [
36772
37134
  { name: "text", required: true, description: "The entry, markdown; the rest of the line." }
36773
37135
  ],
36774
37136
  flags: [{ name: "title", type: "string", description: "The entry's title." }],
36775
- scopes: ["journal:write"],
37137
+ scopes: [...journalOperations.addEntry.scopes],
36776
37138
  returns: "JournalSnapshot",
36777
- notes: "POST /api/v1/journal/days/{date}/entries (journal_add_entry)."
37139
+ notes: `${routeOf(journalOperations.addEntry)} (journal_add_entry).`
36778
37140
  },
36779
37141
  {
36780
37142
  path: ["journal", "correct"],
@@ -36787,9 +37149,9 @@ var COMMAND_SPECS = [
36787
37149
  description: 'The JournalCorrectInput as JSON: {"title":"\u2026","summary":null,"highlights":[\u2026],"tags":[\u2026],"removeLinks":["\u2026"],"metrics":{"rating":6},"status":"reviewed","hiddenFromMemories":true}.'
36788
37150
  }
36789
37151
  ],
36790
- scopes: ["journal:write"],
37152
+ scopes: [...journalOperations.correct.scopes],
36791
37153
  returns: "JournalSnapshot",
36792
- notes: "PATCH /api/v1/journal/days/{date} (journal_correct). 404 when the date has no Journal day."
37154
+ notes: `${routeOf(journalOperations.correct)} (journal_correct). 404 when the date has no Journal day.`
36793
37155
  },
36794
37156
  {
36795
37157
  path: ["journal", "import", "push"],
@@ -36809,27 +37171,27 @@ var COMMAND_SPECS = [
36809
37171
  description: "How the days name their folder (default memory/daily)."
36810
37172
  }
36811
37173
  ],
36812
- scopes: ["journal:write"],
37174
+ scopes: [...journalOperations.stageImport.scopes],
36813
37175
  returns: "JournalImportUpload",
36814
- notes: "POST /api/v1/journal/imports, 400 days a request. The day's '## Day summary' becomes its entry; a clear 'n/10' rating is kept, '~5/10' or '3-4/10' becomes a question; health and automation lines never reach the text. Nothing is written into the Journal until the member approves the month (the app only; a key can't approve). Re-running replaces what's still waiting."
37176
+ notes: `${routeOf(journalOperations.stageImport)}, 400 days a request. The day's '## Day summary' becomes its entry; a clear 'n/10' rating is kept, '~5/10' or '3-4/10' becomes a question; health and automation lines never reach the text. Nothing is written into the Journal until the member approves the month (the app only; a key can't approve). Re-running replaces what's still waiting.`
36815
37177
  },
36816
37178
  {
36817
37179
  path: ["journal", "import", "status"],
36818
37180
  summary: "What the backfill has staged: the files, what the parser found, each month's batch.",
36819
37181
  args: [],
36820
37182
  flags: [{ name: "batch", type: "string", description: "Show this month's days (YYYY-MM)." }],
36821
- scopes: ["journal:read"],
37183
+ scopes: [...journalOperations.importOverview.scopes],
36822
37184
  returns: "JournalImportOverview",
36823
- notes: "GET /api/v1/journal/imports. journal:read is a sensitive scope."
37185
+ notes: `${routeOf(journalOperations.importOverview)}. journal:read is a sensitive scope.`
36824
37186
  },
36825
37187
  {
36826
37188
  path: ["journal", "milestones"],
36827
37189
  summary: "Your life timeline: your milestones and the Space's shared ones, oldest first, with the suggestions.",
36828
37190
  args: [],
36829
37191
  flags: [],
36830
- scopes: ["journal:read"],
37192
+ scopes: [...journalOperations.milestones.scopes],
36831
37193
  returns: "JournalMilestoneList",
36832
- notes: "GET /api/v1/journal/milestones. A milestone is Only me unless shared; `status: suggested` is an agent's mark you haven't kept yet. journal:read is a sensitive scope."
37194
+ notes: `${routeOf(journalOperations.milestones)}. A milestone is Only me unless shared; \`status: suggested\` is an agent's mark you haven't kept yet. journal:read is a sensitive scope.`
36833
37195
  },
36834
37196
  {
36835
37197
  path: ["journal", "milestone", "add"],
@@ -36856,9 +37218,9 @@ var COMMAND_SPECS = [
36856
37218
  description: 'The JournalCreateMilestoneInput as JSON, merged under the flags: {"description":"\u2026","visibility":"space","links":["<node id>"],"remindYearly":true,"status":"kept"}.'
36857
37219
  }
36858
37220
  ],
36859
- scopes: ["journal:write"],
37221
+ scopes: [...journalOperations.createMilestone.scopes],
36860
37222
  returns: "JournalMilestone",
36861
- notes: "POST /api/v1/journal/milestones (journal_mark_milestone). Only me unless visibility is space. links point it at what it's about (a Journal day, a paper, a project, a person); remindYearly adds a yearly Key date."
37223
+ notes: `${routeOf(journalOperations.createMilestone)} (journal_mark_milestone). Only me unless visibility is space. links point it at what it's about (a Journal day, a paper, a project, a person); remindYearly adds a yearly Key date.`
36862
37224
  },
36863
37225
  {
36864
37226
  path: ["journal", "milestone", "edit"],
@@ -36872,9 +37234,9 @@ var COMMAND_SPECS = [
36872
37234
  description: 'The JournalUpdateMilestoneInput as JSON: {"title":"\u2026","happenedOn":"2026-10-14","planned":false,"addLinks":["<id>"],"removeLinks":["<id>"],"remindYearly":true}.'
36873
37235
  }
36874
37236
  ],
36875
- scopes: ["journal:write"],
37237
+ scopes: [...journalOperations.updateMilestone.scopes],
36876
37238
  returns: "JournalMilestone",
36877
- notes: "PATCH /api/v1/journal/milestones/{id}."
37239
+ notes: `${routeOf(journalOperations.updateMilestone)}.`
36878
37240
  },
36879
37241
  {
36880
37242
  path: ["journal", "milestone", "remove"],
@@ -36887,9 +37249,9 @@ var COMMAND_SPECS = [
36887
37249
  description: "Required to actually remove it."
36888
37250
  }
36889
37251
  ],
36890
- scopes: ["journal:write"],
37252
+ scopes: [...journalOperations.removeMilestone.scopes],
36891
37253
  returns: "None",
36892
- notes: "DELETE /api/v1/journal/milestones/{id}. Goes to the trash like any node."
37254
+ notes: `${routeOf(journalOperations.removeMilestone)}. Goes to the trash like any node.`
36893
37255
  },
36894
37256
  {
36895
37257
  path: ["journal", "export"],
@@ -36907,9 +37269,9 @@ var COMMAND_SPECS = [
36907
37269
  description: "Write the files under this directory instead of printing them."
36908
37270
  }
36909
37271
  ],
36910
- scopes: ["journal:export"],
37272
+ scopes: [...journalOperations.export.scopes],
36911
37273
  returns: "JournalExport",
36912
- notes: "GET /api/v1/journal/export. Prints `nextSince`; pass it as --since next time. do is the record: the files are read-only copies and are overwritten."
37274
+ notes: `${routeOf(journalOperations.export)}. Prints \`nextSince\`; pass it as --since next time. do is the record: the files are read-only copies and are overwritten.`
36913
37275
  },
36914
37276
  {
36915
37277
  path: ["progress", "commits"],
@@ -43348,6 +43710,11 @@ async function dispatchEntity(entity, rest, flags, requireClient) {
43348
43710
  }
43349
43711
  throw usageError(`unknown operation for ${entity.name}: \`${op ?? ""}\` (use ${entityOperations(entity).join(", ")})`);
43350
43712
  }
43713
+ var RECAP_OPERATION = {
43714
+ week: journalOperations.writeRecap,
43715
+ month: journalOperations.writeMonthRecap,
43716
+ year: journalOperations.writeYearRecap
43717
+ };
43351
43718
  function runFixed(spec, ctx) {
43352
43719
  const key = spec.path.join(" ");
43353
43720
  const handler = HANDLERS[key];
@@ -43566,7 +43933,7 @@ var HANDLERS = {
43566
43933
  throw usageError("journal day needs a date as YYYY-MM-DD, e.g. `do journal day 2026-10-15`");
43567
43934
  }
43568
43935
  return {
43569
- data: await requireClient().get(`/journal/days/${date}`),
43936
+ data: await requireClient().get(pathOf(journalOperations.day, { date })),
43570
43937
  render: renderJournalDay
43571
43938
  };
43572
43939
  },
@@ -43577,7 +43944,7 @@ var HANDLERS = {
43577
43944
  throw usageError("journal days needs --from and --to as YYYY-MM-DD");
43578
43945
  }
43579
43946
  return {
43580
- data: await requireClient().get("/journal/days", { query: { from, to } }),
43947
+ data: await requireClient().get(pathOf(journalOperations.range), { query: { from, to } }),
43581
43948
  render: renderJournalDays
43582
43949
  };
43583
43950
  },
@@ -43586,7 +43953,7 @@ var HANDLERS = {
43586
43953
  if (q.length < 2)
43587
43954
  throw usageError("journal search needs the words to look for");
43588
43955
  return {
43589
- data: await requireClient().get("/journal/search", { query: { q } }),
43956
+ data: await requireClient().get(pathOf(journalOperations.search), { query: { q } }),
43590
43957
  render: renderJournalSearch
43591
43958
  };
43592
43959
  },
@@ -43603,7 +43970,7 @@ var HANDLERS = {
43603
43970
  };
43604
43971
  parseInput(journalRecallQuerySchema, Object.fromEntries(Object.entries(query).filter(([, v]) => v !== undefined)));
43605
43972
  return {
43606
- data: await requireClient().get("/journal/recall", { query }),
43973
+ data: await requireClient().get(pathOf(journalOperations.recall), { query }),
43607
43974
  render: renderJournalRecall
43608
43975
  };
43609
43976
  },
@@ -43615,18 +43982,20 @@ var HANDLERS = {
43615
43982
  const limit = flagString(flags, "limit");
43616
43983
  parseInput(journalLikeQuerySchema, limit === undefined ? {} : { limit });
43617
43984
  return {
43618
- data: await requireClient().get(`/journal/days/${date}/like`, { query: { limit } }),
43985
+ data: await requireClient().get(pathOf(journalOperations.like, { date }), {
43986
+ query: { limit }
43987
+ }),
43619
43988
  render: renderJournalLike
43620
43989
  };
43621
43990
  },
43622
43991
  "journal digest": async ({ requireClient }) => ({
43623
- data: await requireClient().get("/journal/digest"),
43992
+ data: await requireClient().get(pathOf(journalOperations.digest)),
43624
43993
  render: renderJournalDigest
43625
43994
  }),
43626
43995
  "journal week": async ({ args, requireClient }) => {
43627
43996
  const week = journalWeekArg(args, "week");
43628
43997
  return {
43629
- data: await requireClient().get(`/journal/weeks/${week}`),
43998
+ data: await requireClient().get(pathOf(journalOperations.week, { week })),
43630
43999
  render: renderJournalPeriod
43631
44000
  };
43632
44001
  },
@@ -43636,7 +44005,7 @@ var HANDLERS = {
43636
44005
  throw usageError("journal month needs a month as YYYY-MM, e.g. `do journal month 2026-10`");
43637
44006
  }
43638
44007
  return {
43639
- data: await requireClient().get(`/journal/months/${month}`),
44008
+ data: await requireClient().get(pathOf(journalOperations.month, { month })),
43640
44009
  render: renderJournalPeriod
43641
44010
  };
43642
44011
  },
@@ -43646,7 +44015,7 @@ var HANDLERS = {
43646
44015
  throw usageError("journal year needs a year as YYYY, e.g. `do journal year 2026`");
43647
44016
  }
43648
44017
  return {
43649
- data: await requireClient().get(`/journal/years/${year}`),
44018
+ data: await requireClient().get(pathOf(journalOperations.year, { year })),
43650
44019
  render: renderJournalPeriod
43651
44020
  };
43652
44021
  },
@@ -43662,7 +44031,7 @@ var HANDLERS = {
43662
44031
  body.body = text;
43663
44032
  const input = parseInput(journalWriteRecapInputSchema, body);
43664
44033
  return {
43665
- data: await requireClient().put(`/journal/${kind}s/${period}/recap`, input),
44034
+ data: await requireClient().put(pathOf(RECAP_OPERATION[kind], { [kind]: period }), input),
43666
44035
  render: renderJournalPeriod
43667
44036
  };
43668
44037
  },
@@ -43687,7 +44056,7 @@ var HANDLERS = {
43687
44056
  }
43688
44057
  const input = parseInput(journalWriteDayInputSchema, body);
43689
44058
  return {
43690
- data: await requireClient().post(`/journal/days/${date}`, input),
44059
+ data: await requireClient().post(pathOf(journalOperations.write, { date }), input),
43691
44060
  render: renderJournalDay
43692
44061
  };
43693
44062
  },
@@ -43702,7 +44071,7 @@ var HANDLERS = {
43702
44071
  ...title !== undefined ? { title } : {}
43703
44072
  });
43704
44073
  return {
43705
- data: await requireClient().post(`/journal/days/${date}/entries`, input),
44074
+ data: await requireClient().post(pathOf(journalOperations.addEntry, { date }), input),
43706
44075
  render: renderJournalDay
43707
44076
  };
43708
44077
  },
@@ -43712,7 +44081,7 @@ var HANDLERS = {
43712
44081
  throw usageError("journal correct needs --data");
43713
44082
  const input = parseInput(journalCorrectInputSchema, readDataFlag(flags));
43714
44083
  return {
43715
- data: await requireClient().patch(`/journal/days/${date}`, input),
44084
+ data: await requireClient().patch(pathOf(journalOperations.correct, { date }), input),
43716
44085
  render: renderJournalDay
43717
44086
  };
43718
44087
  },
@@ -43730,7 +44099,7 @@ var HANDLERS = {
43730
44099
  const input = parseInput(journalImportUploadInputSchema, {
43731
44100
  items: items.slice(i, i + JOURNAL_IMPORT_MAX_ITEMS)
43732
44101
  });
43733
- const res = await requireClient().post("/journal/imports", input);
44102
+ const res = await requireClient().post(pathOf(journalOperations.stageImport), input);
43734
44103
  staged += res.staged;
43735
44104
  alreadyImported += res.alreadyImported;
43736
44105
  }
@@ -43742,12 +44111,14 @@ var HANDLERS = {
43742
44111
  "journal import status": async ({ flags, requireClient }) => {
43743
44112
  const batch = flagString(flags, "batch");
43744
44113
  return {
43745
- data: await requireClient().get("/journal/imports", { query: batch ? { batch } : {} }),
44114
+ data: await requireClient().get(pathOf(journalOperations.importOverview), {
44115
+ query: batch ? { batch } : {}
44116
+ }),
43746
44117
  render: renderJournalImportStatus
43747
44118
  };
43748
44119
  },
43749
44120
  "journal milestones": async ({ requireClient }) => ({
43750
- data: await requireClient().get("/journal/milestones"),
44121
+ data: await requireClient().get(pathOf(journalOperations.milestones)),
43751
44122
  render: renderJournalMilestones
43752
44123
  }),
43753
44124
  "journal milestone add": async ({ args, flags, requireClient }) => {
@@ -43768,7 +44139,7 @@ var HANDLERS = {
43768
44139
  body.planned = true;
43769
44140
  const input = parseInput(journalCreateMilestoneInputSchema, body);
43770
44141
  return {
43771
- data: await requireClient().post("/journal/milestones", input),
44142
+ data: await requireClient().post(pathOf(journalOperations.createMilestone), input),
43772
44143
  render: renderJournalMilestone
43773
44144
  };
43774
44145
  },
@@ -43779,20 +44150,20 @@ var HANDLERS = {
43779
44150
  body.status = "kept";
43780
44151
  const input = parseInput(journalUpdateMilestoneInputSchema, body);
43781
44152
  return {
43782
- data: await requireClient().patch(`/journal/milestones/${id}`, input),
44153
+ data: await requireClient().patch(pathOf(journalOperations.updateMilestone, { id }), input),
43783
44154
  render: renderJournalMilestone
43784
44155
  };
43785
44156
  },
43786
44157
  "journal milestone remove": async ({ args, flags, requireClient }) => {
43787
44158
  const id = requireArg(args, 0, "milestone id");
43788
44159
  assertDestructiveAllowed(flags, `remove milestone ${id}`);
43789
- await requireClient().delete(`/journal/milestones/${id}`);
44160
+ await requireClient().delete(pathOf(journalOperations.removeMilestone, { id }));
43790
44161
  return { data: { ok: true, removed: id }, render: renderRecord };
43791
44162
  },
43792
44163
  "journal export": async ({ flags, requireClient }) => {
43793
44164
  const since = flagString(flags, "since");
43794
44165
  const out = flagString(flags, "out");
43795
- const data = await requireClient().get("/journal/export", {
44166
+ const data = await requireClient().get(pathOf(journalOperations.export), {
43796
44167
  query: { since }
43797
44168
  });
43798
44169
  if (out !== undefined) {
@@ -43861,13 +44232,16 @@ var HANDLERS = {
43861
44232
  }
43862
44233
  const client = requireClient();
43863
44234
  if (flagBool(flags, "dry-run")) {
43864
- const before = await client.get(`/notes/${id}`);
44235
+ const before = await client.get(pathOf(noteOperations.get, { id }));
43865
44236
  return {
43866
44237
  data: { dryRun: true, op: "update", entity: "notes", id, before, changes: body },
43867
44238
  render: renderRecord
43868
44239
  };
43869
44240
  }
43870
- return { data: await client.patch(`/notes/${id}`, body), render: renderRecord };
44241
+ return {
44242
+ data: await client.patch(pathOf(noteOperations.update, { id }), body),
44243
+ render: renderRecord
44244
+ };
43871
44245
  },
43872
44246
  "notes detach": async ({ args, flags, requireClient }) => {
43873
44247
  const node = requireArg(args, 0, "node id");
@@ -46494,13 +46868,16 @@ var HANDLERS = {
46494
46868
  render: renderRecord
46495
46869
  };
46496
46870
  }
46497
- return { data: await requireClient().post("/contacts", body), render: renderRecord };
46871
+ return {
46872
+ data: await requireClient().post(pathOf(contactOperations.create), body),
46873
+ render: renderRecord
46874
+ };
46498
46875
  },
46499
46876
  "contacts update": async ({ args, flags, requireClient }) => {
46500
46877
  const id = requireArg(args, 0, "contact id");
46501
46878
  const client = requireClient();
46502
46879
  const dryRun = flagBool(flags, "dry-run");
46503
- const before = dryRun || MERGING_FLAGS.some((f) => flags[f] !== undefined) ? await client.get(`/contacts/${id}`) : undefined;
46880
+ const before = dryRun || MERGING_FLAGS.some((f) => flags[f] !== undefined) ? await client.get(pathOf(contactOperations.get, { id })) : undefined;
46504
46881
  const body = parseInput(updateContactInputSchema, contactBodyFromFlags(flags, readDataFlag(flags), "update", before));
46505
46882
  if (Object.keys(body).length === 0)
46506
46883
  throw usageError("nothing to change \u2014 pass a flag such as --email, or --data");
@@ -46518,7 +46895,10 @@ var HANDLERS = {
46518
46895
  render: renderRecord
46519
46896
  };
46520
46897
  }
46521
- return { data: await client.patch(`/contacts/${id}`, body), render: renderRecord };
46898
+ return {
46899
+ data: await client.patch(pathOf(contactOperations.update, { id }), body),
46900
+ render: renderRecord
46901
+ };
46522
46902
  },
46523
46903
  "people tree": async ({ flags, requireClient }) => {
46524
46904
  const side = flagString(flags, "side");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.308.0",
3
+ "version": "1.308.1",
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",