@wspc/cli 0.0.11 → 0.0.13

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.
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { Command as Command59 } from "commander";
4
+ import { Command as Command62 } from "commander";
5
5
 
6
6
  // src/generated/cli/invite/accept.ts
7
7
  import { Command } from "commander";
@@ -1078,6 +1078,15 @@ var recurrenceRuleList = (options) => (options.client ?? client).get({
1078
1078
  url: "/todo/recurrence-rules",
1079
1079
  ...options
1080
1080
  });
1081
+ var recurrenceRuleCreate = (options) => (options?.client ?? client).post({
1082
+ security: [{ scheme: "bearer", type: "http" }],
1083
+ url: "/todo/recurrence-rules",
1084
+ ...options,
1085
+ headers: {
1086
+ "Content-Type": "application/json",
1087
+ ...options?.headers
1088
+ }
1089
+ });
1081
1090
  var todoList = (options) => (options.client ?? client).get({
1082
1091
  security: [{ scheme: "bearer", type: "http" }],
1083
1092
  url: "/todo/items",
@@ -1111,6 +1120,20 @@ var todoCommentUpdate = (options) => (options.client ?? client).patch({
1111
1120
  ...options.headers
1112
1121
  }
1113
1122
  });
1123
+ var recurrenceRuleDelete = (options) => (options.client ?? client).delete({
1124
+ security: [{ scheme: "bearer", type: "http" }],
1125
+ url: "/todo/recurrence-rules/{id}",
1126
+ ...options,
1127
+ headers: {
1128
+ "Content-Type": "application/json",
1129
+ ...options.headers
1130
+ }
1131
+ });
1132
+ var recurrenceRuleGet = (options) => (options.client ?? client).get({
1133
+ security: [{ scheme: "bearer", type: "http" }],
1134
+ url: "/todo/recurrence-rules/{id}",
1135
+ ...options
1136
+ });
1114
1137
  var todoDelete = (options) => (options.client ?? client).delete({
1115
1138
  security: [{ scheme: "bearer", type: "http" }],
1116
1139
  url: "/todo/items/{id}",
@@ -1230,9 +1253,9 @@ var ConfigStore = class {
1230
1253
  };
1231
1254
 
1232
1255
  // src/version.ts
1233
- var VERSION = "0.0.11";
1234
- var SPEC_SHA = "5ae5d422";
1235
- var SPEC_FETCHED_AT = "2026-06-09T04:35:08.355Z";
1256
+ var VERSION = "0.0.13";
1257
+ var SPEC_SHA = "7842b7a9";
1258
+ var SPEC_FETCHED_AT = "2026-06-09T08:10:52.164Z";
1236
1259
  var API_BASE = "https://api.wspc.ai";
1237
1260
 
1238
1261
  // src/index.ts
@@ -1599,9 +1622,24 @@ function render(ctx, data) {
1599
1622
  const specific = SPECIFIC_RENDERERS[ctx.kind];
1600
1623
  if (specific) {
1601
1624
  specific(target, ctx.display);
1602
- return;
1625
+ } else {
1626
+ renderGeneric(target, ctx.display);
1627
+ }
1628
+ renderPaginationFooter(data);
1629
+ }
1630
+ function renderPaginationFooter(data) {
1631
+ if (data === null || typeof data !== "object") return;
1632
+ const d = data;
1633
+ if (typeof d.next_cursor === "string" && d.next_cursor.length > 0) {
1634
+ process.stdout.write(dim(` \u2026 more results \u2014 re-run with --cursor ${d.next_cursor}`) + "\n");
1635
+ }
1636
+ const id = typeof d.id === "string" ? d.id : "<id>";
1637
+ if (typeof d.children_next_cursor === "string" && d.children_next_cursor.length > 0) {
1638
+ process.stdout.write(dim(` \u2026 more children \u2014 wspc todo ls --parent ${id}`) + "\n");
1639
+ }
1640
+ if (typeof d.comments_next_cursor === "string" && d.comments_next_cursor.length > 0) {
1641
+ process.stdout.write(dim(` \u2026 more comments \u2014 wspc todo comment ls ${id}`) + "\n");
1603
1642
  }
1604
- renderGeneric(target, ctx.display);
1605
1643
  }
1606
1644
  function drillDataPath(data, dataPath) {
1607
1645
  if (!dataPath) return data;
@@ -1874,7 +1912,7 @@ var inviteAcceptCommand = new Command("accept").description("Accept an invite an
1874
1912
 
1875
1913
  // src/generated/cli/keys/create.ts
1876
1914
  import { Command as Command2 } from "commander";
1877
- var keyCreateCommand = new Command2("create").description("Create a new API key (full value returned once)").option("--label <value>", "label").action(async (opts) => {
1915
+ var keyCreateCommand = new Command2("create").description("Create a new API key (full value returned once)").option("--label <value>", "Human-readable label for the new key (1\u201360 chars after trimming). Pick something that identifies where the key will live \u2014 agent name, machine, or environment \u2014 so you can recognise it later in `wspc keys list`.").action(async (opts) => {
1878
1916
  const client2 = await loadSdkClient();
1879
1917
  const result = await keyCreate({
1880
1918
  client: client2._rawClient,
@@ -1913,7 +1951,7 @@ var keyListCommand = new Command3("ls").description("List active API keys").acti
1913
1951
 
1914
1952
  // src/generated/cli/org/invite.ts
1915
1953
  import { Command as Command4 } from "commander";
1916
- var orgInviteCreateCommand = new Command4("invite").description("Invite an email to join the caller's organization").option("--email <value>", "email").action(async (opts) => {
1954
+ var orgInviteCreateCommand = new Command4("invite").description("Invite an email to join the caller's organization").option("--email <value>", "Email address to invite into the caller's organization.").action(async (opts) => {
1917
1955
  const client2 = await loadSdkClient();
1918
1956
  const result = await orgInviteCreate({
1919
1957
  client: client2._rawClient,
@@ -1970,7 +2008,7 @@ var orgGetCommand = new Command6("show").description("Get the authenticated user
1970
2008
 
1971
2009
  // src/generated/cli/org/rename.ts
1972
2010
  import { Command as Command7 } from "commander";
1973
- var orgUpdateCommand = new Command7("rename").description("Update the authenticated user's organization").option("--name <value>", "name").action(async (opts) => {
2011
+ var orgUpdateCommand = new Command7("rename").description("Update the authenticated user's organization").option("--name <value>", "The new name for the organization. Cannot be empty or purely whitespace.").action(async (opts) => {
1974
2012
  const client2 = await loadSdkClient();
1975
2013
  const result = await orgUpdate({
1976
2014
  client: client2._rawClient,
@@ -2048,7 +2086,7 @@ var invitesListCommand = new Command10("invites").description("List invites addr
2048
2086
 
2049
2087
  // src/generated/cli/org/members.ts
2050
2088
  import { Command as Command11 } from "commander";
2051
- var orgMembersListCommand = new Command11("members").description("List members of the authenticated user's organization").option("--cursor <value>", "cursor").option("--limit <value>", "limit").action(async (opts) => {
2089
+ var orgMembersListCommand = new Command11("members").description("List members of the authenticated user's organization").option("--cursor <value>", "Opaque pagination cursor. Pass the `next_cursor` returned by the previous page to fetch the next slice. Omit on the first call.").option("--limit <value>", "Maximum members to return. Clamped to [1, 100]. Defaults to 50.").action(async (opts) => {
2052
2090
  const client2 = await loadSdkClient();
2053
2091
  const result = await orgMembersList({
2054
2092
  client: client2._rawClient,
@@ -2112,7 +2150,7 @@ var keyRevokeCommand = new Command13("rm").description("Soft-revoke an API key")
2112
2150
 
2113
2151
  // src/generated/cli/keys/edit.ts
2114
2152
  import { Command as Command14 } from "commander";
2115
- var keyUpdateCommand = new Command14("edit").description("Update an active API key's label").argument("<id>", "id").option("--label <value>", "label").action(async (id, opts) => {
2153
+ var keyUpdateCommand = new Command14("edit").description("Update an active API key's label").argument("<id>", "id").option("--label <value>", "Human-readable label for the key (1\u201360 chars after trimming).").action(async (id, opts) => {
2116
2154
  const client2 = await loadSdkClient();
2117
2155
  const result = await keyUpdate({
2118
2156
  client: client2._rawClient,
@@ -2242,7 +2280,7 @@ function parseAttendee(input) {
2242
2280
  }
2243
2281
 
2244
2282
  // src/generated/cli/event/add.ts
2245
- var eventCreateCommand = new Command16("add").description("Schedule a calendar event").argument("<title>", "title").option("--description <value>", "description").option("--start <value>", "start").option("--end <value>", "end").option("-l, --location <value>", "location").option("-u, --url <value>", "url").option("--status <value>", "status").option("--attendee <value>", "attendee", (val, memo) => {
2283
+ var eventCreateCommand = new Command16("add").description("Schedule a calendar event").argument("<title>", "title").option("--description <value>", "Free-form notes about the event (agenda, dial-in instructions, etc.). Markdown formatted (CommonMark + GFM tables, strikethrough, task lists); stored verbatim. Invitation emails include the raw source \u2014 most email clients display it as plain text.").option("--start <value>", "Accepts ISO 8601 datetime with offset (e.g. `2026-06-01T12:30:00+08:00`) for timed events, or ISO date-only (e.g. `2026-06-01`) for all-day. The `wspc` CLI additionally accepts natural-language phrases (`tomorrow 12:30pm`, `next Monday 9am`) and resolves them to ISO before sending; the server itself only accepts ISO. All-day uses RFC 5545 exclusive end: a one-day event on 6/1 is `start=2026-06-01, end=2026-06-02`; both endpoints must be the same type.").option("--end <value>", "Accepts ISO 8601 datetime with offset (e.g. `2026-06-01T12:30:00+08:00`) for timed events, or ISO date-only (e.g. `2026-06-01`) for all-day. The `wspc` CLI additionally accepts natural-language phrases (`tomorrow 12:30pm`, `next Monday 9am`) and resolves them to ISO before sending; the server itself only accepts ISO. All-day uses RFC 5545 exclusive end: a one-day event on 6/1 is `start=2026-06-01, end=2026-06-02`; both endpoints must be the same type.").option("-l, --location <value>", "Free-text location \u2014 physical address, room, or short note. Separate from `url` (meeting link).").option("-u, --url <value>", "Optional meeting link (Zoom / Meet / etc.). Kept separate from `location` so calendar clients can render it as a join action.").option("--status <value>", "Lifecycle status. `confirmed`: the event will happen (default). `tentative`: organizer has not finalized; still visible in lists. `cancelled`: the event was called off but the record is kept so attendees can be notified and history audited; distinct from soft-delete (DELETE `/calendar/events/{id}`) which hides the event from default list responses.").option("--attendee <value>", "Up to 50 unique attendees (deduped case-insensitively by email). If non-empty, each attendee receives an invitation email with an `.ics` REQUEST attachment as a side effect of creation.", (val, memo) => {
2246
2284
  memo.push(val);
2247
2285
  return memo;
2248
2286
  }, []).option("--all-day", "all_day").option("--tz <zone>", "IANA timezone for relative time parsing").action(async (title, opts) => {
@@ -2292,7 +2330,7 @@ var eventCreateCommand = new Command16("add").description("Schedule a calendar e
2292
2330
 
2293
2331
  // src/generated/cli/event/ls.ts
2294
2332
  import { Command as Command17 } from "commander";
2295
- var eventListCommand = new Command17("ls").description("List calendar events").option("--q <value>", "q").option("--from <value>", "from").option("--to <value>", "to").option("--end-from <value>", "end_from").option("--end-to <value>", "end_to").option("--cursor <value>", "cursor").option("--limit <value>", "limit").option("--include-deleted <value>", "include_deleted").option("--include-past <value>", "include_past").option("--tz <zone>", "IANA timezone for relative time parsing").action(async (opts) => {
2333
+ var eventListCommand = new Command17("ls").description("List calendar events").option("--q <value>", "Optional full-text search across title, description, and location (case-insensitive substring).").option("--from <value>", "Inclusive lower bound on the event `start` (ISO datetime with offset, or ISO date-only). When ANY of `start_from`/`start_to`/`end_from`/`end_to` is provided, the implicit past filter is disabled.").option("--to <value>", "Inclusive upper bound on the event `start`.").option("--end-from <value>", "Inclusive lower bound on the event `end`.").option("--end-to <value>", "Inclusive upper bound on the event `end`.").option("--cursor <value>", "Opaque pagination cursor returned in `next_cursor` of a previous response.").option("--limit <value>", "Maximum number of events to return. Clamped to `[1, 200]`. Default is server-defined.").option("--include-deleted <value>", "When `true`, include soft-deleted events. Default `false`.").option("--include-past <value>", "When omitted or `false`, events whose `end` is before now are hidden. Pass `true` to include them. Ignored when any of `start_from`/`start_to`/`end_from`/`end_to` is provided \u2014 explicit time bounds always win.").option("--tz <zone>", "IANA timezone for relative time parsing").action(async (opts) => {
2296
2334
  const zone = resolveTimezone(opts.tz);
2297
2335
  let fromValue;
2298
2336
  if (opts.from !== void 0) {
@@ -2330,7 +2368,7 @@ var eventListCommand = new Command17("ls").description("List calendar events").o
2330
2368
 
2331
2369
  // src/generated/cli/event/rm.ts
2332
2370
  import { Command as Command18 } from "commander";
2333
- var eventDeleteCommand = new Command18("rm").description("Soft-delete a calendar event").argument("<id>", "id").option("--expected-version <value>", "expected_version").action(async (id, opts) => {
2371
+ var eventDeleteCommand = new Command18("rm").description("Soft-delete a calendar event").argument("<id>", "id").option("--expected-version <value>", "Optional optimistic lock. Omit to let the server use the current version; pass only to fail with 409 `VERSION_CONFLICT` if someone else has mutated the event since you last read.").action(async (id, opts) => {
2334
2372
  const client2 = await loadSdkClient();
2335
2373
  const result = await eventDelete({
2336
2374
  client: client2._rawClient,
@@ -2354,7 +2392,7 @@ var eventDeleteCommand = new Command18("rm").description("Soft-delete a calendar
2354
2392
 
2355
2393
  // src/generated/cli/event/show.ts
2356
2394
  import { Command as Command19 } from "commander";
2357
- var eventGetCommand = new Command19("show").description("Get a calendar event by id").argument("<id>", "id").option("--include-deleted <value>", "include_deleted").action(async (id, opts) => {
2395
+ var eventGetCommand = new Command19("show").description("Get a calendar event by id").argument("<id>", "id").option("--include-deleted <value>", "When `true`, return the row even if soft-deleted. Default `false` (returns 404).").action(async (id, opts) => {
2358
2396
  const client2 = await loadSdkClient();
2359
2397
  const result = await eventGet({
2360
2398
  client: client2._rawClient,
@@ -2378,7 +2416,7 @@ var eventGetCommand = new Command19("show").description("Get a calendar event by
2378
2416
 
2379
2417
  // src/generated/cli/event/set.ts
2380
2418
  import { Command as Command20 } from "commander";
2381
- var eventUpdateCommand = new Command20("set").description("Update a calendar event").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--title <value>", "title").option("--description <value>", "description").option("--start <value>", "start").option("--end <value>", "end").option("-l, --location <value>", "location").option("-u, --url <value>", "url").option("--status <value>", "status").option("--attendee <value>", "attendee", (val, memo) => {
2419
+ var eventUpdateCommand = new Command20("set").description("Update a calendar event").argument("<id>", "id").option("--expected-version <value>", "Optional optimistic lock. Omit to let the server use the current version; pass only to fail the call if someone else has mutated the event since you last read. On mismatch the server returns 409 `VERSION_CONFLICT` with `extra.expected_version` and `extra.actual_version`.").option("--title <value>", "New event title. Omit to leave unchanged.").option("--description <value>", "New description. Markdown formatted (CommonMark + GFM tables, strikethrough, task lists). Pass an empty string to clear; omit to leave unchanged.").option("--start <value>", "Accepts ISO 8601 datetime with offset (e.g. `2026-06-01T12:30:00+08:00`) for timed events, or ISO date-only (e.g. `2026-06-01`) for all-day. The `wspc` CLI additionally accepts natural-language phrases (`tomorrow 12:30pm`, `next Monday 9am`) and resolves them to ISO before sending; the server itself only accepts ISO. All-day uses RFC 5545 exclusive end: a one-day event on 6/1 is `start=2026-06-01, end=2026-06-02`; both endpoints must be the same type.").option("--end <value>", "Accepts ISO 8601 datetime with offset (e.g. `2026-06-01T12:30:00+08:00`) for timed events, or ISO date-only (e.g. `2026-06-01`) for all-day. The `wspc` CLI additionally accepts natural-language phrases (`tomorrow 12:30pm`, `next Monday 9am`) and resolves them to ISO before sending; the server itself only accepts ISO. All-day uses RFC 5545 exclusive end: a one-day event on 6/1 is `start=2026-06-01, end=2026-06-02`; both endpoints must be the same type.").option("-l, --location <value>", "New location. Pass an empty string to clear; omit to leave unchanged.").option("-u, --url <value>", "New meeting link. Pass an empty string to clear; omit to leave unchanged.").option("--status <value>", "Lifecycle status. `confirmed`: the event will happen (default). `tentative`: organizer has not finalized; still visible in lists. `cancelled`: the event was called off but the record is kept so attendees can be notified and history audited; distinct from soft-delete (DELETE `/calendar/events/{id}`) which hides the event from default list responses.").option("--attendee <value>", "If provided, REPLACES the attendee list (after case-insensitive email dedupe, up to 50). Added attendees receive a fresh invitation, kept attendees receive an update email, removed attendees receive a cancellation.", (val, memo) => {
2382
2420
  memo.push(val);
2383
2421
  return memo;
2384
2422
  }, []).option("--all-day", "all_day").option("--tz <zone>", "IANA timezone for relative time parsing").action(async (id, opts) => {
@@ -2474,7 +2512,7 @@ var emailAliasCreateCommand = new Command22("add").description("Create a receivi
2474
2512
 
2475
2513
  // src/generated/cli/alias/ls.ts
2476
2514
  import { Command as Command23 } from "commander";
2477
- var emailAliasListCommand = new Command23("ls").description("List the caller's aliases").option("--include-deleted <value>", "include_deleted").action(async (opts) => {
2515
+ var emailAliasListCommand = new Command23("ls").description("List the caller's aliases").option("--include-deleted <value>", "When `true`, include soft-deleted aliases (with `deleted_at` set) alongside active ones. Defaults to `false`.").action(async (opts) => {
2478
2516
  const client2 = await loadSdkClient();
2479
2517
  const result = await emailAliasList({
2480
2518
  client: client2._rawClient,
@@ -2599,7 +2637,7 @@ var emailDomainGetCommand = new Command28("show").description("Get one cached cu
2599
2637
 
2600
2638
  // src/generated/cli/email/show.ts
2601
2639
  import { Command as Command29 } from "commander";
2602
- var emailGetCommand = new Command29("show").description("Get an inbound email by id").argument("<id>", "id").option("--include-html <value>", "include_html").option("--include-deleted <value>", "include_deleted").action(async (id, opts) => {
2640
+ var emailGetCommand = new Command29("show").description("Get an inbound email by id").argument("<id>", "id").option("--include-html <value>", "When `true`, fetch the HTML body from R2 and include it as `html_body` in the response. Costs an extra R2 read; omit if you only need text.").option("--include-deleted <value>", "When `true`, allow fetching a soft-deleted email. Defaults to `false` (returns 404 for soft-deleted rows).").action(async (id, opts) => {
2603
2641
  const client2 = await loadSdkClient();
2604
2642
  const result = await emailGet({
2605
2643
  client: client2._rawClient,
@@ -2624,7 +2662,7 @@ var emailGetCommand = new Command29("show").description("Get an inbound email by
2624
2662
 
2625
2663
  // src/generated/cli/email/ls.ts
2626
2664
  import { Command as Command30 } from "commander";
2627
- var emailListCommand = new Command30("ls").description("List inbound emails").option("--limit <value>", "limit").option("--alias-email <value>", "alias_email").option("--unread-only <value>", "unread_only").option("--since <value>", "since").option("--cursor <value>", "cursor").option("--include-deleted <value>", "include_deleted").action(async (opts) => {
2665
+ var emailListCommand = new Command30("ls").description("List inbound emails").option("--limit <value>", "Max items to return (clamped to 1-100). Defaults to 20 server-side.").option("--alias-email <value>", "If set, only return emails received on this full alias email address.").option("--unread-only <value>", "When `true`, only return emails with `is_read=false`.").option("--since <value>", "Unix epoch milliseconds \u2014 only return emails with `received_at >= since`. Useful for incremental sync.").option("--cursor <value>", "Opaque pagination cursor returned in `next_cursor` of a previous response.").option("--include-deleted <value>", "When `true`, also return soft-deleted emails. Defaults to `false`.").action(async (opts) => {
2628
2666
  const client2 = await loadSdkClient();
2629
2667
  const result = await emailList({
2630
2668
  client: client2._rawClient,
@@ -2738,7 +2776,7 @@ var pushConfigDeleteCommand = new Command34("rm").description("Remove a push tra
2738
2776
 
2739
2777
  // src/generated/cli/push/config/set.ts
2740
2778
  import { Command as Command35 } from "commander";
2741
- var pushConfigSetCommand = new Command35("set").description("Register or update a push transport").option("--transport <value>", "transport").option("--target-bot-username <value>", "target_bot_username").action(async (opts) => {
2779
+ var pushConfigSetCommand = new Command35("set").description("Register or update a push transport").option("--transport <value>", "Transport discriminator. `telegram` is the only supported value today \u2014 push delivers via a Telegram bot DM. Future transports (web push, iOS/Android, generic webhook) will be added as additional discriminator values.").option("--target-bot-username <value>", "Telegram bot username (with leading `@`, 5\u201332 alphanumeric/underscore characters). This is the bot the user has already started a chat with \u2014 wspc DMs notifications to it via the Telegram Bot API.").action(async (opts) => {
2742
2780
  const client2 = await loadSdkClient();
2743
2781
  const result = await pushConfigSet({
2744
2782
  client: client2._rawClient,
@@ -2780,7 +2818,7 @@ var pushConfigGetCommand = new Command36("show").description("List the caller's
2780
2818
 
2781
2819
  // src/generated/cli/push/test.ts
2782
2820
  import { Command as Command37 } from "commander";
2783
- var pushTestCommand = new Command37("test").description("Send a test push notification").option("--transport <value>", "transport").action(async (opts) => {
2821
+ var pushTestCommand = new Command37("test").description("Send a test push notification").option("--transport <value>", "Which transport to send the test message through. Must match a transport the caller has already registered via `POST /push/config`; today only `telegram` is supported.").action(async (opts) => {
2784
2822
  const client2 = await loadSdkClient();
2785
2823
  const result = await pushTest({
2786
2824
  client: client2._rawClient,
@@ -2828,7 +2866,7 @@ var todoCommentCreateCommand = new Command38("add").description("Add a comment t
2828
2866
 
2829
2867
  // src/generated/cli/todo/comment/ls.ts
2830
2868
  import { Command as Command39 } from "commander";
2831
- var todoCommentListCommand = new Command39("ls").description("List comments on a todo").argument("<id>", "id").option("--order <value>", "order").option("--include-deleted <value>", "include_deleted").option("--limit <value>", "limit").option("--cursor <value>", "cursor").action(async (id, opts) => {
2869
+ var todoCommentListCommand = new Command39("ls").description("List comments on a todo").argument("<id>", "id").option("--order <value>", "order").option("--include-deleted <value>", "include_deleted").option("--limit <value>", "Max comments to return. Clamped to [1, 200]. Default 50 server-side.").option("--cursor <value>", "Opaque pagination cursor returned in `next_cursor` of a previous response.").action(async (id, opts) => {
2832
2870
  const client2 = await loadSdkClient();
2833
2871
  const result = await todoCommentList({
2834
2872
  client: client2._rawClient,
@@ -2877,7 +2915,7 @@ var projectCreateCommand = new Command40("add").description("Create a project").
2877
2915
 
2878
2916
  // src/generated/cli/todo/project/ls.ts
2879
2917
  import { Command as Command41 } from "commander";
2880
- var projectListCommand = new Command41("ls").description("List projects").option("--include-deleted <value>", "include_deleted").action(async (opts) => {
2918
+ var projectListCommand = new Command41("ls").description("List projects").option("--include-deleted <value>", "Set to `true` to include soft-deleted projects in the response.").action(async (opts) => {
2881
2919
  const client2 = await loadSdkClient();
2882
2920
  const result = await projectList({
2883
2921
  client: client2._rawClient,
@@ -2896,9 +2934,36 @@ var projectListCommand = new Command41("ls").description("List projects").option
2896
2934
  render({ kind: "project_list", display: { "shape": "list", "columns": ["id", "name", "default_todo_type_id"], "format": { "id": "id-short", "name": "truncate", "default_todo_type_id": "id-short" }, "emptyMessage": "no projects" } }, result.data);
2897
2935
  });
2898
2936
 
2899
- // src/generated/cli/todo/rule/ls.ts
2937
+ // src/generated/cli/todo/rule/add.ts
2900
2938
  import { Command as Command42 } from "commander";
2901
- var recurrenceRuleListCommand = new Command42("ls").description("List recurring todo rules").option("--project-id <value>", "project_id").option("--user-id <value>", "user_id").action(async (opts) => {
2939
+ var recurrenceRuleCreateCommand = new Command42("add").description("Create a recurring todo rule").argument("<title>", "title").option("--rrule <value>", "rrule").option("--dtstart <value>", "dtstart").option("--description <value>", "description").option("--parent-id <value>", "parent_id").option("-p, --project <value>", "Project for the recurrence rule, its template todo, and all materialized instances. Must be an active project in the caller's organization.").option("-t, --type <value>", "type_id").action(async (title, opts) => {
2940
+ const client2 = await loadSdkClient();
2941
+ const result = await recurrenceRuleCreate({
2942
+ client: client2._rawClient,
2943
+ body: {
2944
+ title,
2945
+ rrule: opts.rrule,
2946
+ dtstart: opts.dtstart,
2947
+ description: opts.description,
2948
+ parent_id: opts.parentId,
2949
+ project_id: opts.project,
2950
+ type_id: opts.type
2951
+ }
2952
+ });
2953
+ if (result.error || !result.response?.ok) {
2954
+ process.stderr.write(
2955
+ `HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
2956
+ `
2957
+ );
2958
+ process.exitCode = 1;
2959
+ return;
2960
+ }
2961
+ render({ kind: "recurrence_rule_create", display: void 0 }, result.data);
2962
+ });
2963
+
2964
+ // src/generated/cli/todo/rule/ls.ts
2965
+ import { Command as Command43 } from "commander";
2966
+ var recurrenceRuleListCommand = new Command43("ls").description("List recurring todo rules").option("--project-id <value>", "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.").option("--user-id <value>", "user_id").action(async (opts) => {
2902
2967
  const client2 = await loadSdkClient();
2903
2968
  const result = await recurrenceRuleList({
2904
2969
  client: client2._rawClient,
@@ -2915,12 +2980,26 @@ var recurrenceRuleListCommand = new Command42("ls").description("List recurring
2915
2980
  process.exitCode = 1;
2916
2981
  return;
2917
2982
  }
2918
- render({ kind: "recurrence_rule_list", display: { "shape": "list", "columns": ["id", "rrule", "dtstart"], "format": { "id": "id-short", "rrule": "truncate" }, "emptyMessage": "no recurrence rules" } }, result.data);
2983
+ render({ kind: "recurrence_rule_list", display: { "shape": "list", "columns": ["id", "rrule", "dtstart", "type_id"], "format": { "id": "id-short", "rrule": "truncate", "type_id": "id-short" }, "emptyMessage": "no recurrence rules" } }, result.data);
2919
2984
  });
2920
2985
 
2921
2986
  // src/generated/cli/todo/add.ts
2922
- import { Command as Command43 } from "commander";
2923
- var todoCreateCommand = new Command43("add").description("Create a todo").argument("<title>", "title").option("-p, --project <value>", "project_id").option("--description <value>", "description").option("--parent-id <value>", "parent_id").option("--status <value>", "status").option("--due-at <value>", "due_at").option("--type-id <value>", "type_id").option("--custom-fields <value>", "custom_fields").action(async (title, opts) => {
2987
+ import { Command as Command44 } from "commander";
2988
+
2989
+ // src/handwritten/utils/parse-json-field.ts
2990
+ function parseJsonField(raw, flag) {
2991
+ if (raw === void 0) return void 0;
2992
+ try {
2993
+ return JSON.parse(raw);
2994
+ } catch {
2995
+ process.stderr.write(`Invalid JSON for --${flag}: ${raw}
2996
+ `);
2997
+ process.exit(1);
2998
+ }
2999
+ }
3000
+
3001
+ // src/generated/cli/todo/add.ts
3002
+ var todoCreateCommand = new Command44("add").description("Create a todo").argument("<title>", "title").option("-p, --project <value>", "Project id to assign this todo to. It must be an active project in the caller's organization.").option("--description <value>", "Free-form details about the todo. Fully supports GFM Markdown (tables, strikethrough, task lists). Stored verbatim; client applications are responsible for rendering. Optional. Passing `null` is strictly rejected.").option("--parent-id <value>", "Parent todo ID (`tod_<ULID>`) to attach this todo as a child under another todo. Omit or pass `null` to create a root-level todo. Nesting is limited to one level; attempting to set a child todo as a parent will trigger `PARENT_IS_CHILD`. To make a subtask appear on every occurrence of a recurring rule, set this to that rule's template todo id (the template id returned when the rule is created); the server re-materializes future occurrences so each carries the subtask.").option("--status <value>", "Initial status of the todo. Omit to default to `open`. Allowed values: `open`, `in_progress`, `done`, `cancelled`.").option("--due-at <value>", 'Optional calendar due date in ISO date-only format (`YYYY-MM-DD`). Stored without timezone offsets to represent the same local calendar day globally. Pass `""` or omit the field to skip setting a due date. Passing `null` is strictly rejected.').option("--type-id <value>", "Type id this todo belongs to. Omit to use the project's default type. When project_id is also supplied, the type must belong to the same project. New server-generated type ids use typ_<ULID>; legacy ids remain accepted.").option("--custom-fields <value>", "Custom field values keyed by the field's immutable `key` (not the human `label`). Each value must match the declared field type: string fields require string values, and string_array fields require string arrays. Providing a key that is not declared on the resolved todo type is strictly rejected with `UNDECLARED_FIELD`. Missing required fields that lack a default value are rejected with `FIELD_REQUIRED`. Defaults declared on the type are auto-applied at create time.").action(async (title, opts) => {
2924
3003
  const client2 = await loadSdkClient();
2925
3004
  const result = await todoCreate({
2926
3005
  client: client2._rawClient,
@@ -2932,7 +3011,7 @@ var todoCreateCommand = new Command43("add").description("Create a todo").argume
2932
3011
  status: opts.status,
2933
3012
  due_at: opts.dueAt,
2934
3013
  type_id: opts.typeId,
2935
- custom_fields: opts.customFields
3014
+ custom_fields: parseJsonField(opts.customFields, "custom-fields")
2936
3015
  }
2937
3016
  });
2938
3017
  if (result.error || !result.response?.ok) {
@@ -2947,8 +3026,8 @@ var todoCreateCommand = new Command43("add").description("Create a todo").argume
2947
3026
  });
2948
3027
 
2949
3028
  // src/generated/cli/todo/ls.ts
2950
- import { Command as Command44 } from "commander";
2951
- var todoListCommand = new Command44("ls").description("List todos with filters").option("-p, --project <value>", "project_id").option("--user-id <value>", "user_id").option("--parent-id <value>", "parent_id").option("-s, --status <value>", "status").option("--include-deleted <value>", "include_deleted").option("--include-templates <value>", "include_templates").option("--due-after <value>", "due_after").option("--due-before <value>", "due_before").option("--type-id <value>", "type_id").option("--sort-by <value>", "sort_by").option("--order <value>", "order").option("--include-orphan-fields <value>", "include_orphan_fields").option("--limit <value>", "limit").option("--cursor <value>", "cursor").action(async (opts) => {
3029
+ import { Command as Command45 } from "commander";
3030
+ var todoListCommand = new Command45("ls").description("List todos with filters").option("-p, --project <value>", "Filter by project. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.").option("--user-id <value>", "user_id").option("--parent-id <value>", "parent_id").option("-s, --status <value>", "status").option("--include-deleted <value>", "include_deleted").option("--include-templates <value>", "include_templates").option("--due-after <value>", "due_after").option("--due-before <value>", "due_before").option("--type-id <value>", "type_id").option("--sort-by <value>", "sort_by").option("--order <value>", "order").option("--include-orphan-fields <value>", "include_orphan_fields").option("--limit <value>", "Max todos to return. Clamped to [1, 200]. Default 50 server-side.").option("--cursor <value>", "Opaque pagination cursor returned in `next_cursor` of a previous response.").action(async (opts) => {
2952
3031
  const client2 = await loadSdkClient();
2953
3032
  const result = await todoList({
2954
3033
  client: client2._rawClient,
@@ -2981,8 +3060,8 @@ var todoListCommand = new Command44("ls").description("List todos with filters")
2981
3060
  });
2982
3061
 
2983
3062
  // src/generated/cli/todo/type/ls.ts
2984
- import { Command as Command45 } from "commander";
2985
- var todoTypeListCommand = new Command45("ls").description("List todo types").option("--project-id <value>", "project_id").option("--user-id <value>", "user_id").option("--include-deleted <value>", "include_deleted").action(async (opts) => {
3063
+ import { Command as Command46 } from "commander";
3064
+ var todoTypeListCommand = new Command46("ls").description("List todo types").option("--project-id <value>", "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.").option("--user-id <value>", "user_id").option("--include-deleted <value>", "include_deleted").action(async (opts) => {
2986
3065
  const client2 = await loadSdkClient();
2987
3066
  const result = await todoTypeList({
2988
3067
  client: client2._rawClient,
@@ -3004,8 +3083,8 @@ var todoTypeListCommand = new Command45("ls").description("List todo types").opt
3004
3083
  });
3005
3084
 
3006
3085
  // src/generated/cli/todo/comment/rm.ts
3007
- import { Command as Command46 } from "commander";
3008
- var todoCommentDeleteCommand = new Command46("rm").description("Soft-delete a comment").argument("<id>", "id").action(async (id, opts) => {
3086
+ import { Command as Command47 } from "commander";
3087
+ var todoCommentDeleteCommand = new Command47("rm").description("Soft-delete a comment").argument("<id>", "id").action(async (id, opts) => {
3009
3088
  const client2 = await loadSdkClient();
3010
3089
  const result = await todoCommentDelete({
3011
3090
  client: client2._rawClient,
@@ -3025,8 +3104,8 @@ var todoCommentDeleteCommand = new Command46("rm").description("Soft-delete a co
3025
3104
  });
3026
3105
 
3027
3106
  // src/generated/cli/todo/comment/edit.ts
3028
- import { Command as Command47 } from "commander";
3029
- var todoCommentUpdateCommand = new Command47("edit").description("Edit a comment").argument("<id>", "id").argument("<content>", "content").action(async (id, content, opts) => {
3107
+ import { Command as Command48 } from "commander";
3108
+ var todoCommentUpdateCommand = new Command48("edit").description("Edit a comment").argument("<id>", "id").argument("<content>", "content").action(async (id, content, opts) => {
3030
3109
  const client2 = await loadSdkClient();
3031
3110
  const result = await todoCommentUpdate({
3032
3111
  client: client2._rawClient,
@@ -3048,9 +3127,54 @@ var todoCommentUpdateCommand = new Command47("edit").description("Edit a comment
3048
3127
  render({ kind: "todo_comment_update", display: { "shape": "object", "format": { "id": "id-short", "todo_id": "id-short", "user_id": "id-short", "created_at": "relative-time", "updated_at": "relative-time", "deleted_at": "relative-time" } } }, result.data);
3049
3128
  });
3050
3129
 
3130
+ // src/generated/cli/todo/rule/rm.ts
3131
+ import { Command as Command49 } from "commander";
3132
+ var recurrenceRuleDeleteCommand = new Command49("rm").description("Delete a recurring todo rule").argument("<id>", "id").option("--expected-version <value>", "expected_version").action(async (id, opts) => {
3133
+ const client2 = await loadSdkClient();
3134
+ const result = await recurrenceRuleDelete({
3135
+ client: client2._rawClient,
3136
+ path: {
3137
+ id
3138
+ },
3139
+ body: {
3140
+ expected_version: opts.expectedVersion
3141
+ }
3142
+ });
3143
+ if (result.error || !result.response?.ok) {
3144
+ process.stderr.write(
3145
+ `HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
3146
+ `
3147
+ );
3148
+ process.exitCode = 1;
3149
+ return;
3150
+ }
3151
+ render({ kind: "recurrence_rule_delete", display: void 0 }, result.data);
3152
+ });
3153
+
3154
+ // src/generated/cli/todo/rule/show.ts
3155
+ import { Command as Command50 } from "commander";
3156
+ var recurrenceRuleGetCommand = new Command50("show").description("Get a recurring todo rule").argument("<id>", "id").action(async (id, opts) => {
3157
+ const client2 = await loadSdkClient();
3158
+ const result = await recurrenceRuleGet({
3159
+ client: client2._rawClient,
3160
+ path: {
3161
+ id
3162
+ }
3163
+ });
3164
+ if (result.error || !result.response?.ok) {
3165
+ process.stderr.write(
3166
+ `HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
3167
+ `
3168
+ );
3169
+ process.exitCode = 1;
3170
+ return;
3171
+ }
3172
+ render({ kind: "recurrence_rule_get", display: { "shape": "object", "format": { "id": "id-short", "type_id": "id-short" } } }, result.data);
3173
+ });
3174
+
3051
3175
  // src/generated/cli/todo/rm.ts
3052
- import { Command as Command48 } from "commander";
3053
- var todoDeleteCommand = new Command48("rm").description("Soft-delete a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--cascade <value>", "cascade").action(async (id, opts) => {
3176
+ import { Command as Command51 } from "commander";
3177
+ var todoDeleteCommand = new Command51("rm").description("Soft-delete a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--cascade <value>", "cascade").action(async (id, opts) => {
3054
3178
  const client2 = await loadSdkClient();
3055
3179
  const result = await todoDelete({
3056
3180
  client: client2._rawClient,
@@ -3074,8 +3198,8 @@ var todoDeleteCommand = new Command48("rm").description("Soft-delete a todo").ar
3074
3198
  });
3075
3199
 
3076
3200
  // src/generated/cli/todo/show.ts
3077
- import { Command as Command49 } from "commander";
3078
- var todoGetCommand = new Command49("show").description("Get a todo by id").argument("<id>", "id").option("--include-deleted <value>", "include_deleted").option("--include-orphan-fields <value>", "include_orphan_fields").action(async (id, opts) => {
3201
+ import { Command as Command52 } from "commander";
3202
+ var todoGetCommand = new Command52("show").description("Get a todo by id").argument("<id>", "id").option("--include-deleted <value>", "include_deleted").option("--include-orphan-fields <value>", "include_orphan_fields").action(async (id, opts) => {
3079
3203
  const client2 = await loadSdkClient();
3080
3204
  const result = await todoGet({
3081
3205
  client: client2._rawClient,
@@ -3100,8 +3224,8 @@ var todoGetCommand = new Command49("show").description("Get a todo by id").argum
3100
3224
  });
3101
3225
 
3102
3226
  // src/generated/cli/todo/update.ts
3103
- import { Command as Command50 } from "commander";
3104
- var todoUpdateCommand = new Command50("update").description("Update a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--title <value>", "title").option("--description <value>", "description").option("--parent-id <value>", "parent_id").option("--status <value>", "status").option("--due-at <value>", "due_at").option("--type-id <value>", "type_id").option("--custom-fields <value>", "custom_fields").option("--user-id <value>", "user_id").action(async (id, opts) => {
3227
+ import { Command as Command53 } from "commander";
3228
+ var todoUpdateCommand = new Command53("update").description("Update a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--title <value>", "New title. Omit to leave the existing title unchanged. Must be non-empty when supplied.").option("--description <value>", 'New description. Markdown formatted (CommonMark + GFM tables, strikethrough, task lists). Pass empty string `""` explicitly to clear an existing description, or omit to leave unchanged. Passing `null` is strictly rejected.').option("--parent-id <value>", "Re-parent the todo. Pass a valid parent ID to attach under another todo, pass `null` to move it back to the root level, or omit to leave unchanged. Nesting is limited to one level; attempting to set a child todo as a parent will trigger `PARENT_IS_CHILD`.").option("--status <value>", "New status of the todo. Allowed transitions: `open` \u2794 `in_progress` \u2794 `done`. `cancelled` represents a terminal state. Transitioning to `done` automatically emits a `captureTodoCompleted` analytics event. Omit to leave the existing status unchanged.").option("--due-at <value>", 'Update calendar due date in ISO date-only format (`YYYY-MM-DD`). Pass `""` explicitly to clear an existing due date, or omit to leave it unchanged. Passing `null` is strictly rejected.').option("--type-id <value>", "Re-assign this todo to a different active type. The new type must belong to the todo's same project; otherwise the request fails with TYPE_PROJECT_MISMATCH. New server-generated type ids use typ_<ULID>; legacy ids remain accepted.").option("--custom-fields <value>", "PATCH semantics: only the keys present in this map change. Pass `null` for a key (e.g. `custom_fields: { priority: null }`) to explicitly delete that custom field value. Array values are replaced wholesale with no element-level diff. Providing a key that is not declared on the effective todo type is rejected with `UNDECLARED_FIELD`.").option("--user-id <value>", "Reassign the owner (assignee) user ID of this todo. Target user must belong to the same organization.").action(async (id, opts) => {
3105
3229
  const client2 = await loadSdkClient();
3106
3230
  const result = await todoUpdate({
3107
3231
  client: client2._rawClient,
@@ -3116,7 +3240,7 @@ var todoUpdateCommand = new Command50("update").description("Update a todo").arg
3116
3240
  status: opts.status,
3117
3241
  due_at: opts.dueAt,
3118
3242
  type_id: opts.typeId,
3119
- custom_fields: opts.customFields,
3243
+ custom_fields: parseJsonField(opts.customFields, "custom-fields"),
3120
3244
  user_id: opts.userId
3121
3245
  }
3122
3246
  });
@@ -3191,7 +3315,10 @@ function registerGeneratedCommands(root) {
3191
3315
  root_todo_project.addCommand(projectCreateCommand);
3192
3316
  root_todo_project.addCommand(projectListCommand);
3193
3317
  const root_todo_rule = root_todo.command("rule").description("rule commands");
3318
+ root_todo_rule.addCommand(recurrenceRuleCreateCommand);
3194
3319
  root_todo_rule.addCommand(recurrenceRuleListCommand);
3320
+ root_todo_rule.addCommand(recurrenceRuleDeleteCommand);
3321
+ root_todo_rule.addCommand(recurrenceRuleGetCommand);
3195
3322
  root_todo.addCommand(todoCreateCommand);
3196
3323
  root_todo.addCommand(todoListCommand);
3197
3324
  const root_todo_type = root_todo.command("type").description("type commands");
@@ -3202,7 +3329,7 @@ function registerGeneratedCommands(root) {
3202
3329
  }
3203
3330
 
3204
3331
  // src/handwritten/commands/login.ts
3205
- import { Command as Command51 } from "commander";
3332
+ import { Command as Command54 } from "commander";
3206
3333
 
3207
3334
  // src/handwritten/auth/device-flow.ts
3208
3335
  var DEFAULT_SLEEP = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -3381,7 +3508,7 @@ async function runLogin(opts) {
3381
3508
  }
3382
3509
 
3383
3510
  // src/handwritten/commands/login.ts
3384
- var loginCommand = new Command51("login").description("Log in via OAuth device flow (default) or API key").option("--api-key <key>", "Log in with a wspc API key (escape hatch)").option("--json", "Emit machine-readable events to stdout").action(async (opts) => {
3511
+ var loginCommand = new Command54("login").description("Log in via OAuth device flow (default) or API key").option("--api-key <key>", "Log in with a wspc API key (escape hatch)").option("--json", "Emit machine-readable events to stdout").action(async (opts) => {
3385
3512
  const store = new ConfigStore();
3386
3513
  const output = opts.json ? { write: () => {
3387
3514
  }, writeJson: (e) => process.stdout.write(JSON.stringify(e) + "\n") } : {
@@ -3398,7 +3525,7 @@ var loginCommand = new Command51("login").description("Log in via OAuth device f
3398
3525
  });
3399
3526
 
3400
3527
  // src/handwritten/commands/logout.ts
3401
- import { Command as Command52 } from "commander";
3528
+ import { Command as Command55 } from "commander";
3402
3529
 
3403
3530
  // src/handwritten/auth/logout.ts
3404
3531
  async function runLogout(opts) {
@@ -3426,7 +3553,7 @@ async function runLogout(opts) {
3426
3553
  }
3427
3554
 
3428
3555
  // src/handwritten/commands/logout.ts
3429
- var logoutCommand = new Command52("logout").description("Log out an account (default: the active account in the current env)").argument("[email]", "Email of the account to log out").option("--all", "Log out every account in the current env").action(async (email, opts) => {
3556
+ var logoutCommand = new Command55("logout").description("Log out an account (default: the active account in the current env)").argument("[email]", "Email of the account to log out").option("--all", "Log out every account in the current env").action(async (email, opts) => {
3430
3557
  const res = await runLogout({ store: new ConfigStore(), email, all: opts.all });
3431
3558
  if (res.removed.length === 0) {
3432
3559
  process.stdout.write("nothing to log out\n");
@@ -3439,7 +3566,7 @@ var logoutCommand = new Command52("logout").description("Log out an account (def
3439
3566
  });
3440
3567
 
3441
3568
  // src/handwritten/commands/whoami.ts
3442
- import { Command as Command53 } from "commander";
3569
+ import { Command as Command56 } from "commander";
3443
3570
  var ENV_DISPLAY = {
3444
3571
  shape: "object",
3445
3572
  fields: ["name", "api_base", "account", "actor", "agent_label"]
@@ -3471,7 +3598,7 @@ async function backfillActiveEmail(store, envName, email, userId) {
3471
3598
  await store.write(cfg);
3472
3599
  }
3473
3600
  }
3474
- var whoamiCommand = new Command53("whoami").description("Show the active env, signed-in account, and organization").action(async () => {
3601
+ var whoamiCommand = new Command56("whoami").description("Show the active env, signed-in account, and organization").action(async () => {
3475
3602
  const store = new ConfigStore();
3476
3603
  const config = await store.read();
3477
3604
  let resolved;
@@ -3524,8 +3651,8 @@ function printLoggedOut() {
3524
3651
  }
3525
3652
 
3526
3653
  // src/handwritten/commands/config.ts
3527
- import { Command as Command54 } from "commander";
3528
- var configCommand = new Command54("config").description("Manage wspc local config");
3654
+ import { Command as Command57 } from "commander";
3655
+ var configCommand = new Command57("config").description("Manage wspc local config");
3529
3656
  registerRenderer("config_show", (data) => {
3530
3657
  const d = data;
3531
3658
  if (d.envs.length === 0) {
@@ -3596,7 +3723,7 @@ configCommand.command("use <env>").description("Switch current_env").action(asyn
3596
3723
  });
3597
3724
 
3598
3725
  // src/handwritten/commands/account.ts
3599
- import { Command as Command55 } from "commander";
3726
+ import { Command as Command58 } from "commander";
3600
3727
  async function listAccounts(store) {
3601
3728
  const c = await store.read();
3602
3729
  const envName = c.current_env;
@@ -3637,7 +3764,7 @@ registerRenderer("account_ls", (data) => {
3637
3764
  ]);
3638
3765
  process.stdout.write(table(headers, body));
3639
3766
  });
3640
- var accountCommand = new Command55("account").description("Manage logged-in accounts");
3767
+ var accountCommand = new Command58("account").description("Manage logged-in accounts");
3641
3768
  accountCommand.command("ls").description("List accounts in the current env (active marked with \u2713)").action(async () => {
3642
3769
  const accounts = await listAccounts(new ConfigStore());
3643
3770
  render({ kind: "account_ls" }, { accounts });
@@ -3649,7 +3776,7 @@ accountCommand.command("switch <email>").description("Set the active account for
3649
3776
  });
3650
3777
 
3651
3778
  // src/handwritten/commands/todo-done.ts
3652
- import { Command as Command56 } from "commander";
3779
+ import { Command as Command59 } from "commander";
3653
3780
  var TODO_UPDATE_DISPLAY = {
3654
3781
  shape: "object",
3655
3782
  format: {
@@ -3667,7 +3794,7 @@ var TODO_UPDATE_DISPLAY = {
3667
3794
  deleted_at: "relative-time"
3668
3795
  }
3669
3796
  };
3670
- var todoDoneCommand = new Command56("done").description("Mark a todo done (sugar for `update <id> --status done`)").argument("<id>", "Todo id").action(async (id) => {
3797
+ var todoDoneCommand = new Command59("done").description("Mark a todo done (sugar for `update <id> --status done`)").argument("<id>", "Todo id").action(async (id) => {
3671
3798
  const client2 = await loadSdkClient();
3672
3799
  const result = await todoUpdate({
3673
3800
  client: client2._rawClient,
@@ -3686,7 +3813,7 @@ var todoDoneCommand = new Command56("done").description("Mark a todo done (sugar
3686
3813
  });
3687
3814
 
3688
3815
  // src/handwritten/commands/email/send.ts
3689
- import { Command as Command57 } from "commander";
3816
+ import { Command as Command60 } from "commander";
3690
3817
  import { readFile, stat } from "fs/promises";
3691
3818
  import { basename } from "path";
3692
3819
 
@@ -3744,7 +3871,7 @@ async function resolveAttachment(input) {
3744
3871
  `--attach ${input}: neither a readable file nor a valid <prefix>_<ulid>:<idx> reference.`
3745
3872
  );
3746
3873
  }
3747
- var sendCommand = new Command57("send").description("Send an outbound email").requiredOption("--from <alias-email>", "alias email to send from").option("--to <addr...>", "recipient address (repeatable)", []).option("--subject <text>", "subject").option("--text <body>", "plain-text body").option("--text-file <path>", "read text body from file").option("--reply <id>", "inbound email id to reply to").option("--attach <path-or-ref...>", "attachment (file path or eml_xxx:idx)", []).requiredOption("--idempotency-key <key>", "idempotency key").action(async (opts) => {
3874
+ var sendCommand = new Command60("send").description("Send an outbound email").requiredOption("--from <alias-email>", "alias email to send from").option("--to <addr...>", "recipient address (repeatable)", []).option("--subject <text>", "subject").option("--text <body>", "plain-text body").option("--text-file <path>", "read text body from file").option("--reply <id>", "inbound email id to reply to").option("--attach <path-or-ref...>", "attachment (file path or eml_xxx:idx)", []).requiredOption("--idempotency-key <key>", "idempotency key").action(async (opts) => {
3748
3875
  const isReply = Boolean(opts.reply);
3749
3876
  const to = opts.to;
3750
3877
  const attachInputs = opts.attach;
@@ -3831,7 +3958,7 @@ var sendCommand = new Command57("send").description("Send an outbound email").re
3831
3958
  });
3832
3959
 
3833
3960
  // src/handwritten/commands/email/attachment.ts
3834
- import { Command as Command58 } from "commander";
3961
+ import { Command as Command61 } from "commander";
3835
3962
  import { createWriteStream } from "fs";
3836
3963
  import { Readable } from "stream";
3837
3964
  import { pipeline } from "stream/promises";
@@ -3848,7 +3975,7 @@ function parseContentDispositionFilename(header) {
3848
3975
  }
3849
3976
 
3850
3977
  // src/handwritten/commands/email/attachment.ts
3851
- var attachmentCommand = new Command58("attachment").description("Download an inbound email attachment by index").argument("<email-id>").argument("<idx>").option("--output <path>", "output file path").option("--include-deleted", "allow downloads from soft-deleted parent emails").action(async (emailId, idxArg, opts) => {
3978
+ var attachmentCommand = new Command61("attachment").description("Download an inbound email attachment by index").argument("<email-id>").argument("<idx>").option("--output <path>", "output file path").option("--include-deleted", "allow downloads from soft-deleted parent emails").action(async (emailId, idxArg, opts) => {
3852
3979
  const idx = Number(idxArg);
3853
3980
  if (!Number.isInteger(idx) || idx < 0) {
3854
3981
  process.stderr.write(`<idx> must be a non-negative integer (got "${idxArg}")
@@ -3881,7 +4008,7 @@ var attachmentCommand = new Command58("attachment").description("Download an inb
3881
4008
 
3882
4009
  // src/cli.ts
3883
4010
  function buildProgram() {
3884
- const program = new Command59().name("wspc").description("Official CLI for wspc.ai").version(`wspc ${VERSION} (spec ${SPEC_SHA}, fetched ${SPEC_FETCHED_AT})`).option("--json", "Output raw JSON (machine-readable)").option("--account <email>", "Run as a specific account (overrides the active account)").hook("preAction", (_thisCommand, actionCommand) => {
4011
+ const program = new Command62().name("wspc").description("Official CLI for wspc.ai").version(`wspc ${VERSION} (spec ${SPEC_SHA}, fetched ${SPEC_FETCHED_AT})`).option("--json", "Output raw JSON (machine-readable)").option("--account <email>", "Run as a specific account (overrides the active account)").hook("preAction", (_thisCommand, actionCommand) => {
3885
4012
  const globals = actionCommand.optsWithGlobals();
3886
4013
  if (globals.json) process.env.WSPC_OUTPUT = "json";
3887
4014
  if (globals.account) process.env.WSPC_ACCOUNT = String(globals.account);