@wspc/cli 0.0.7 → 0.0.9

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 Command51 } from "commander";
4
+ import { Command as Command55 } from "commander";
5
5
 
6
6
  // src/generated/cli/invite/accept.ts
7
7
  import { Command } from "commander";
@@ -1021,6 +1021,20 @@ var pushTest = (options) => (options.client ?? client).post({
1021
1021
  ...options.headers
1022
1022
  }
1023
1023
  });
1024
+ var todoCommentList = (options) => (options.client ?? client).get({
1025
+ security: [{ scheme: "bearer", type: "http" }],
1026
+ url: "/todo/items/{id}/comments",
1027
+ ...options
1028
+ });
1029
+ var todoCommentCreate = (options) => (options.client ?? client).post({
1030
+ security: [{ scheme: "bearer", type: "http" }],
1031
+ url: "/todo/items/{id}/comments",
1032
+ ...options,
1033
+ headers: {
1034
+ "Content-Type": "application/json",
1035
+ ...options.headers
1036
+ }
1037
+ });
1024
1038
  var projectList = (options) => (options?.client ?? client).get({
1025
1039
  security: [{ scheme: "bearer", type: "http" }],
1026
1040
  url: "/todo/projects",
@@ -1059,6 +1073,20 @@ var todoTypeList = (options) => (options.client ?? client).get({
1059
1073
  url: "/todo/types",
1060
1074
  ...options
1061
1075
  });
1076
+ var todoCommentDelete = (options) => (options.client ?? client).delete({
1077
+ security: [{ scheme: "bearer", type: "http" }],
1078
+ url: "/todo/comments/{id}",
1079
+ ...options
1080
+ });
1081
+ var todoCommentUpdate = (options) => (options.client ?? client).patch({
1082
+ security: [{ scheme: "bearer", type: "http" }],
1083
+ url: "/todo/comments/{id}",
1084
+ ...options,
1085
+ headers: {
1086
+ "Content-Type": "application/json",
1087
+ ...options.headers
1088
+ }
1089
+ });
1062
1090
  var todoDelete = (options) => (options.client ?? client).delete({
1063
1091
  security: [{ scheme: "bearer", type: "http" }],
1064
1092
  url: "/todo/items/{id}",
@@ -1178,9 +1206,9 @@ var ConfigStore = class {
1178
1206
  };
1179
1207
 
1180
1208
  // src/version.ts
1181
- var VERSION = "0.0.7";
1182
- var SPEC_SHA = "c579a55a";
1183
- var SPEC_FETCHED_AT = "2026-06-03T06:34:38.606Z";
1209
+ var VERSION = "0.0.9";
1210
+ var SPEC_SHA = "15a30e63";
1211
+ var SPEC_FETCHED_AT = "2026-06-08T09:36:22.810Z";
1184
1212
  var API_BASE = "https://api.wspc.ai";
1185
1213
 
1186
1214
  // src/index.ts
@@ -1468,6 +1496,42 @@ function relativeTime(value, now = Date.now()) {
1468
1496
  }
1469
1497
  return future ? `in ${amount}${unit}` : `${amount}${unit} ago`;
1470
1498
  }
1499
+ function wrapToWidth(text, width) {
1500
+ const limit = width > 0 ? width : 80;
1501
+ const out = [];
1502
+ for (const line of text.split("\n")) {
1503
+ if (line.length === 0) {
1504
+ out.push("");
1505
+ continue;
1506
+ }
1507
+ let cur = "";
1508
+ for (let word of line.split(" ")) {
1509
+ while (visibleWidth(word) > limit) {
1510
+ let head = "";
1511
+ for (const ch of word) {
1512
+ if (head && visibleWidth(head + ch) > limit) break;
1513
+ head += ch;
1514
+ if (visibleWidth(head) >= limit) break;
1515
+ }
1516
+ if (cur) {
1517
+ out.push(cur);
1518
+ cur = "";
1519
+ }
1520
+ out.push(head);
1521
+ word = word.slice(head.length);
1522
+ }
1523
+ const sep = cur ? " " : "";
1524
+ if (cur && visibleWidth(cur + sep + word) > limit) {
1525
+ out.push(cur);
1526
+ cur = word;
1527
+ } else {
1528
+ cur = cur + sep + word;
1529
+ }
1530
+ }
1531
+ if (cur) out.push(cur);
1532
+ }
1533
+ return out;
1534
+ }
1471
1535
  function table(headers, rows) {
1472
1536
  if (rows.length === 0) {
1473
1537
  return "";
@@ -1529,6 +1593,10 @@ function shouldOutputJson() {
1529
1593
  }
1530
1594
  return false;
1531
1595
  }
1596
+ function termWidth() {
1597
+ const c = process.stdout.columns;
1598
+ return typeof c === "number" && c > 0 ? c : 80;
1599
+ }
1532
1600
  function renderGeneric(data, hints) {
1533
1601
  const shape = hints?.shape ?? detectShape(data);
1534
1602
  if (shape === "list") {
@@ -1610,18 +1678,45 @@ function renderObject(data, hints) {
1610
1678
  const arrayFields = hints?.fields ? [] : Object.keys(obj).filter(
1611
1679
  (k) => Array.isArray(obj[k]) && obj[k].length > 0
1612
1680
  );
1681
+ const formatted = fields.map((f) => [
1682
+ f,
1683
+ formatCell(obj[f], format[f], hints?.enumColorMap?.[f], { noTruncate: true })
1684
+ ]);
1613
1685
  const labelWidth = Math.max(
1614
- ...fields.map((f) => f.length),
1615
- ...arrayFields.map((f) => f.length)
1686
+ ...formatted.map(([f]) => f.length),
1687
+ ...arrayFields.map((f) => f.length),
1688
+ 0
1616
1689
  );
1617
- for (const f of fields) {
1618
- const value = formatCell(obj[f], format[f], hints?.enumColorMap?.[f]);
1690
+ const tw = termWidth();
1691
+ const avail = tw - (2 + labelWidth + 2);
1692
+ const inlineFinal = [];
1693
+ const blocks = [];
1694
+ for (const [f, value] of formatted) {
1695
+ if (value.includes("\n") || visibleWidth(value) > avail) {
1696
+ blocks.push([f, value]);
1697
+ } else {
1698
+ inlineFinal.push([f, value]);
1699
+ }
1700
+ }
1701
+ for (const [f, value] of inlineFinal) {
1619
1702
  process.stdout.write(` ${dim(f.padEnd(labelWidth))} ${value}
1620
1703
  `);
1621
1704
  }
1622
1705
  for (const f of arrayFields) {
1623
- renderArrayField(f, obj[f], labelWidth);
1624
- }
1706
+ const uncapped = f === "children" || f === "comments";
1707
+ const max = uncapped ? Number.POSITIVE_INFINITY : ARRAY_FIELD_MAX_ITEMS;
1708
+ renderArrayField(f, obj[f], labelWidth, max);
1709
+ }
1710
+ const hadAbove = inlineFinal.length > 0 || arrayFields.length > 0;
1711
+ blocks.forEach(([f, value], i) => {
1712
+ if (hadAbove || i > 0) process.stdout.write("\n");
1713
+ process.stdout.write(` ${dim(f)}
1714
+ `);
1715
+ for (const line of wrapToWidth(value, tw - 4)) {
1716
+ process.stdout.write(` ${line}
1717
+ `);
1718
+ }
1719
+ });
1625
1720
  if (hints?.secretField) {
1626
1721
  const value = obj[hints.secretField];
1627
1722
  if (value !== void 0) {
@@ -1635,12 +1730,12 @@ function renderObject(data, hints) {
1635
1730
  }
1636
1731
  }
1637
1732
  var ARRAY_FIELD_MAX_ITEMS = 10;
1638
- function renderArrayField(name, items, labelWidth) {
1733
+ function renderArrayField(name, items, labelWidth, max = ARRAY_FIELD_MAX_ITEMS) {
1639
1734
  const count = items.length;
1640
1735
  const header = `${count} ${count === 1 ? "item" : "items"}`;
1641
1736
  process.stdout.write(` ${dim(name.padEnd(labelWidth))} ${header}
1642
1737
  `);
1643
- const shown = items.slice(0, ARRAY_FIELD_MAX_ITEMS);
1738
+ const shown = items.slice(0, max);
1644
1739
  shown.forEach((item, i) => {
1645
1740
  process.stdout.write(` ${dim(`${i + 1}.`)} ${formatArrayItem(item)}
1646
1741
  `);
@@ -1653,10 +1748,31 @@ function renderArrayField(name, items, labelWidth) {
1653
1748
  function formatArrayItem(item) {
1654
1749
  if (item === null) return dim("null");
1655
1750
  if (typeof item !== "object") return String(item);
1751
+ const todo = formatTodoLike(item);
1752
+ if (todo !== null) return todo;
1753
+ const comment = formatCommentLike(item);
1754
+ if (comment !== null) return comment;
1656
1755
  const attendee = formatAttendeeLike(item);
1657
1756
  if (attendee !== null) return attendee;
1658
1757
  return JSON.stringify(item);
1659
1758
  }
1759
+ function formatTodoLike(item) {
1760
+ if (!item || typeof item !== "object" || Array.isArray(item)) return null;
1761
+ const rec = item;
1762
+ if (typeof rec.id !== "string" || typeof rec.title !== "string") return null;
1763
+ const id = idShort(rec.id);
1764
+ const status = typeof rec.status === "string" ? statusBadge(rec.status) : "";
1765
+ return status ? `${id} ${status} ${rec.title}` : `${id} ${rec.title}`;
1766
+ }
1767
+ function formatCommentLike(item) {
1768
+ if (!item || typeof item !== "object" || Array.isArray(item)) return null;
1769
+ const rec = item;
1770
+ if (typeof rec.id !== "string" || typeof rec.content !== "string") return null;
1771
+ const id = idShort(rec.id);
1772
+ const when = rec.created_at !== void 0 ? `${relativeTime(rec.created_at)} ` : "";
1773
+ const snippet = truncate(rec.content, 60);
1774
+ return `${id} ${when}${snippet}`;
1775
+ }
1660
1776
  function formatAttendeeLike(item) {
1661
1777
  if (!item || typeof item !== "object" || Array.isArray(item)) return null;
1662
1778
  const rec = item;
@@ -1683,7 +1799,7 @@ function renderScalar(data) {
1683
1799
  function isScalar(v) {
1684
1800
  return v === null || typeof v !== "object" && typeof v !== "function";
1685
1801
  }
1686
- function formatCell(value, fmt, colorMap) {
1802
+ function formatCell(value, fmt, colorMap, opts) {
1687
1803
  if (fmt !== "enum-badge" && (value === void 0 || value === null)) return dim("\u2014");
1688
1804
  switch (fmt) {
1689
1805
  case "id-short":
@@ -1693,7 +1809,7 @@ function formatCell(value, fmt, colorMap) {
1693
1809
  case "relative-time":
1694
1810
  return relativeTime(value);
1695
1811
  case "truncate":
1696
- return truncate(String(value), 50);
1812
+ return opts?.noTruncate ? String(value) : truncate(String(value), 50);
1697
1813
  case "bool-badge":
1698
1814
  return boolBadge(value);
1699
1815
  case "enum-badge": {
@@ -2581,9 +2697,58 @@ var pushTestCommand = new Command33("test").description("Send a test push notifi
2581
2697
  }
2582
2698
  });
2583
2699
 
2584
- // src/generated/cli/todo/project/add.ts
2700
+ // src/generated/cli/todo/comment/add.ts
2585
2701
  import { Command as Command34 } from "commander";
2586
- var projectCreateCommand = new Command34("add").description("Create a project").argument("<name>", "name").option("--default-todo-type-id <value>", "default_todo_type_id").action(async (name, opts) => {
2702
+ var todoCommentCreateCommand = new Command34("add").description("Add a comment to a todo").argument("<id>", "id").argument("<content>", "content").action(async (id, content, opts) => {
2703
+ const client2 = await loadSdkClient();
2704
+ const result = await todoCommentCreate({
2705
+ client: client2._rawClient,
2706
+ path: {
2707
+ id
2708
+ },
2709
+ body: {
2710
+ content
2711
+ }
2712
+ });
2713
+ if (result.error || !result.response?.ok) {
2714
+ process.stderr.write(
2715
+ `HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
2716
+ `
2717
+ );
2718
+ process.exitCode = 1;
2719
+ return;
2720
+ }
2721
+ render({ kind: "todo_comment_create", 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);
2722
+ });
2723
+
2724
+ // src/generated/cli/todo/comment/ls.ts
2725
+ import { Command as Command35 } from "commander";
2726
+ var todoCommentListCommand = new Command35("ls").description("List comments on a todo").argument("<id>", "id").option("--order <value>", "order").option("--include-deleted <value>", "include_deleted").action(async (id, opts) => {
2727
+ const client2 = await loadSdkClient();
2728
+ const result = await todoCommentList({
2729
+ client: client2._rawClient,
2730
+ path: {
2731
+ id
2732
+ },
2733
+ query: {
2734
+ order: opts.order,
2735
+ include_deleted: opts.includeDeleted
2736
+ }
2737
+ });
2738
+ if (result.error || !result.response?.ok) {
2739
+ process.stderr.write(
2740
+ `HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
2741
+ `
2742
+ );
2743
+ process.exitCode = 1;
2744
+ return;
2745
+ }
2746
+ render({ kind: "todo_comment_list", display: { "shape": "list", "columns": ["id", "content", "created_at"], "format": { "id": "id-short", "content": "truncate", "created_at": "relative-time" }, "emptyMessage": "no comments" } }, result.data);
2747
+ });
2748
+
2749
+ // src/generated/cli/todo/project/add.ts
2750
+ import { Command as Command36 } from "commander";
2751
+ var projectCreateCommand = new Command36("add").description("Create a project").argument("<name>", "name").option("--default-todo-type-id <value>", "default_todo_type_id").action(async (name, opts) => {
2587
2752
  const client2 = await loadSdkClient();
2588
2753
  const result = await projectCreate({
2589
2754
  client: client2._rawClient,
@@ -2604,8 +2769,8 @@ var projectCreateCommand = new Command34("add").description("Create a project").
2604
2769
  });
2605
2770
 
2606
2771
  // src/generated/cli/todo/project/ls.ts
2607
- import { Command as Command35 } from "commander";
2608
- var projectListCommand = new Command35("ls").description("List projects").option("--include-deleted <value>", "include_deleted").action(async (opts) => {
2772
+ import { Command as Command37 } from "commander";
2773
+ var projectListCommand = new Command37("ls").description("List projects").option("--include-deleted <value>", "include_deleted").action(async (opts) => {
2609
2774
  const client2 = await loadSdkClient();
2610
2775
  const result = await projectList({
2611
2776
  client: client2._rawClient,
@@ -2625,8 +2790,8 @@ var projectListCommand = new Command35("ls").description("List projects").option
2625
2790
  });
2626
2791
 
2627
2792
  // src/generated/cli/todo/rule/ls.ts
2628
- import { Command as Command36 } from "commander";
2629
- var recurrenceRuleListCommand = new Command36("ls").description("List recurring todo rules").option("--project-id <value>", "project_id").option("--user-id <value>", "user_id").action(async (opts) => {
2793
+ import { Command as Command38 } from "commander";
2794
+ var recurrenceRuleListCommand = new Command38("ls").description("List recurring todo rules").option("--project-id <value>", "project_id").option("--user-id <value>", "user_id").action(async (opts) => {
2630
2795
  const client2 = await loadSdkClient();
2631
2796
  const result = await recurrenceRuleList({
2632
2797
  client: client2._rawClient,
@@ -2647,8 +2812,8 @@ var recurrenceRuleListCommand = new Command36("ls").description("List recurring
2647
2812
  });
2648
2813
 
2649
2814
  // src/generated/cli/todo/add.ts
2650
- import { Command as Command37 } from "commander";
2651
- var todoCreateCommand = new Command37("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) => {
2815
+ import { Command as Command39 } from "commander";
2816
+ var todoCreateCommand = new Command39("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) => {
2652
2817
  const client2 = await loadSdkClient();
2653
2818
  const result = await todoCreate({
2654
2819
  client: client2._rawClient,
@@ -2671,12 +2836,12 @@ var todoCreateCommand = new Command37("add").description("Create a todo").argume
2671
2836
  process.exitCode = 1;
2672
2837
  return;
2673
2838
  }
2674
- render({ kind: "todo_create", display: { "shape": "object", "format": { "id": "id-short", "user_id": "id-short", "project_id": "id-short", "parent_id": "id-short", "type_id": "id-short", "title": "truncate", "description": "truncate", "status": "status-badge", "due_at": "relative-time", "created_at": "relative-time", "updated_at": "relative-time", "deleted_at": "relative-time" } } }, result.data);
2839
+ render({ kind: "todo_create", display: { "shape": "object", "format": { "id": "id-short", "user_id": "id-short", "project_id": "id-short", "parent_id": "id-short", "type_id": "id-short", "status": "status-badge", "due_at": "relative-time", "created_at": "relative-time", "updated_at": "relative-time", "deleted_at": "relative-time" } } }, result.data);
2675
2840
  });
2676
2841
 
2677
2842
  // src/generated/cli/todo/ls.ts
2678
- import { Command as Command38 } from "commander";
2679
- var todoListCommand = new Command38("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").action(async (opts) => {
2843
+ import { Command as Command40 } from "commander";
2844
+ var todoListCommand = new Command40("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").action(async (opts) => {
2680
2845
  const client2 = await loadSdkClient();
2681
2846
  const result = await todoList({
2682
2847
  client: client2._rawClient,
@@ -2707,8 +2872,8 @@ var todoListCommand = new Command38("ls").description("List todos with filters")
2707
2872
  });
2708
2873
 
2709
2874
  // src/generated/cli/todo/type/ls.ts
2710
- import { Command as Command39 } from "commander";
2711
- var todoTypeListCommand = new Command39("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) => {
2875
+ import { Command as Command41 } from "commander";
2876
+ var todoTypeListCommand = new Command41("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) => {
2712
2877
  const client2 = await loadSdkClient();
2713
2878
  const result = await todoTypeList({
2714
2879
  client: client2._rawClient,
@@ -2729,9 +2894,54 @@ var todoTypeListCommand = new Command39("ls").description("List todo types").opt
2729
2894
  render({ kind: "todo_type_list", display: { "shape": "list", "columns": ["id", "label"], "format": { "id": "id-short", "label": "truncate" }, "emptyMessage": "no todo types" } }, result.data);
2730
2895
  });
2731
2896
 
2897
+ // src/generated/cli/todo/comment/rm.ts
2898
+ import { Command as Command42 } from "commander";
2899
+ var todoCommentDeleteCommand = new Command42("rm").description("Soft-delete a comment").argument("<id>", "id").action(async (id, opts) => {
2900
+ const client2 = await loadSdkClient();
2901
+ const result = await todoCommentDelete({
2902
+ client: client2._rawClient,
2903
+ path: {
2904
+ id
2905
+ }
2906
+ });
2907
+ if (result.error || !result.response?.ok) {
2908
+ process.stderr.write(
2909
+ `HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
2910
+ `
2911
+ );
2912
+ process.exitCode = 1;
2913
+ return;
2914
+ }
2915
+ render({ kind: "todo_comment_delete", 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);
2916
+ });
2917
+
2918
+ // src/generated/cli/todo/comment/edit.ts
2919
+ import { Command as Command43 } from "commander";
2920
+ var todoCommentUpdateCommand = new Command43("edit").description("Edit a comment").argument("<id>", "id").argument("<content>", "content").action(async (id, content, opts) => {
2921
+ const client2 = await loadSdkClient();
2922
+ const result = await todoCommentUpdate({
2923
+ client: client2._rawClient,
2924
+ path: {
2925
+ id
2926
+ },
2927
+ body: {
2928
+ content
2929
+ }
2930
+ });
2931
+ if (result.error || !result.response?.ok) {
2932
+ process.stderr.write(
2933
+ `HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
2934
+ `
2935
+ );
2936
+ process.exitCode = 1;
2937
+ return;
2938
+ }
2939
+ 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);
2940
+ });
2941
+
2732
2942
  // src/generated/cli/todo/rm.ts
2733
- import { Command as Command40 } from "commander";
2734
- var todoDeleteCommand = new Command40("rm").description("Soft-delete a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--cascade <value>", "cascade").action(async (id, opts) => {
2943
+ import { Command as Command44 } from "commander";
2944
+ var todoDeleteCommand = new Command44("rm").description("Soft-delete a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--cascade <value>", "cascade").action(async (id, opts) => {
2735
2945
  const client2 = await loadSdkClient();
2736
2946
  const result = await todoDelete({
2737
2947
  client: client2._rawClient,
@@ -2751,12 +2961,12 @@ var todoDeleteCommand = new Command40("rm").description("Soft-delete a todo").ar
2751
2961
  process.exitCode = 1;
2752
2962
  return;
2753
2963
  }
2754
- render({ kind: "todo_delete", display: { "shape": "object", "format": { "id": "id-short", "user_id": "id-short", "project_id": "id-short", "parent_id": "id-short", "type_id": "id-short", "title": "truncate", "description": "truncate", "status": "status-badge", "due_at": "relative-time", "created_at": "relative-time", "updated_at": "relative-time", "deleted_at": "relative-time" } } }, result.data);
2964
+ render({ kind: "todo_delete", display: { "shape": "object", "format": { "id": "id-short", "user_id": "id-short", "project_id": "id-short", "parent_id": "id-short", "type_id": "id-short", "status": "status-badge", "due_at": "relative-time", "created_at": "relative-time", "updated_at": "relative-time", "deleted_at": "relative-time" } } }, result.data);
2755
2965
  });
2756
2966
 
2757
2967
  // src/generated/cli/todo/show.ts
2758
- import { Command as Command41 } from "commander";
2759
- var todoGetCommand = new Command41("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) => {
2968
+ import { Command as Command45 } from "commander";
2969
+ var todoGetCommand = new Command45("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) => {
2760
2970
  const client2 = await loadSdkClient();
2761
2971
  const result = await todoGet({
2762
2972
  client: client2._rawClient,
@@ -2765,7 +2975,8 @@ var todoGetCommand = new Command41("show").description("Get a todo by id").argum
2765
2975
  },
2766
2976
  query: {
2767
2977
  include_deleted: opts.includeDeleted,
2768
- include_orphan_fields: opts.includeOrphanFields
2978
+ include_orphan_fields: opts.includeOrphanFields,
2979
+ include: "children,comments"
2769
2980
  }
2770
2981
  });
2771
2982
  if (result.error || !result.response?.ok) {
@@ -2776,12 +2987,12 @@ var todoGetCommand = new Command41("show").description("Get a todo by id").argum
2776
2987
  process.exitCode = 1;
2777
2988
  return;
2778
2989
  }
2779
- render({ kind: "todo_get", display: { "shape": "object", "format": { "id": "id-short", "user_id": "id-short", "project_id": "id-short", "parent_id": "id-short", "type_id": "id-short", "title": "truncate", "description": "truncate", "status": "status-badge", "due_at": "relative-time", "created_at": "relative-time", "updated_at": "relative-time", "deleted_at": "relative-time" } } }, result.data);
2990
+ render({ kind: "todo_get", display: { "shape": "object", "format": { "id": "id-short", "user_id": "id-short", "project_id": "id-short", "parent_id": "id-short", "type_id": "id-short", "status": "status-badge", "due_at": "relative-time", "created_at": "relative-time", "updated_at": "relative-time", "deleted_at": "relative-time" } } }, result.data);
2780
2991
  });
2781
2992
 
2782
2993
  // src/generated/cli/todo/update.ts
2783
- import { Command as Command42 } from "commander";
2784
- var todoUpdateCommand = new Command42("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) => {
2994
+ import { Command as Command46 } from "commander";
2995
+ var todoUpdateCommand = new Command46("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) => {
2785
2996
  const client2 = await loadSdkClient();
2786
2997
  const result = await todoUpdate({
2787
2998
  client: client2._rawClient,
@@ -2808,7 +3019,7 @@ var todoUpdateCommand = new Command42("update").description("Update a todo").arg
2808
3019
  process.exitCode = 1;
2809
3020
  return;
2810
3021
  }
2811
- render({ kind: "todo_update", display: { "shape": "object", "format": { "id": "id-short", "user_id": "id-short", "project_id": "id-short", "parent_id": "id-short", "type_id": "id-short", "title": "truncate", "description": "truncate", "status": "status-badge", "due_at": "relative-time", "created_at": "relative-time", "updated_at": "relative-time", "deleted_at": "relative-time" } } }, result.data);
3022
+ render({ kind: "todo_update", display: { "shape": "object", "format": { "id": "id-short", "user_id": "id-short", "project_id": "id-short", "parent_id": "id-short", "type_id": "id-short", "status": "status-badge", "due_at": "relative-time", "created_at": "relative-time", "updated_at": "relative-time", "deleted_at": "relative-time" } } }, result.data);
2812
3023
  });
2813
3024
 
2814
3025
  // src/generated/cli/index.ts
@@ -2857,6 +3068,11 @@ function registerGeneratedCommands(root) {
2857
3068
  root_push_config.addCommand(pushConfigGetCommand);
2858
3069
  root_push.addCommand(pushTestCommand);
2859
3070
  const root_todo = root.command("todo").description("todo commands");
3071
+ const root_todo_comment = root_todo.command("comment").description("comment commands");
3072
+ root_todo_comment.addCommand(todoCommentCreateCommand);
3073
+ root_todo_comment.addCommand(todoCommentListCommand);
3074
+ root_todo_comment.addCommand(todoCommentDeleteCommand);
3075
+ root_todo_comment.addCommand(todoCommentUpdateCommand);
2860
3076
  const root_todo_project = root_todo.command("project").description("project commands");
2861
3077
  root_todo_project.addCommand(projectCreateCommand);
2862
3078
  root_todo_project.addCommand(projectListCommand);
@@ -2872,7 +3088,7 @@ function registerGeneratedCommands(root) {
2872
3088
  }
2873
3089
 
2874
3090
  // src/handwritten/commands/login.ts
2875
- import { Command as Command43 } from "commander";
3091
+ import { Command as Command47 } from "commander";
2876
3092
 
2877
3093
  // src/handwritten/auth/device-flow.ts
2878
3094
  var DEFAULT_SLEEP = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -3051,7 +3267,7 @@ async function runLogin(opts) {
3051
3267
  }
3052
3268
 
3053
3269
  // src/handwritten/commands/login.ts
3054
- var loginCommand = new Command43("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) => {
3270
+ var loginCommand = new Command47("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) => {
3055
3271
  const store = new ConfigStore();
3056
3272
  const output = opts.json ? { write: () => {
3057
3273
  }, writeJson: (e) => process.stdout.write(JSON.stringify(e) + "\n") } : {
@@ -3068,7 +3284,7 @@ var loginCommand = new Command43("login").description("Log in via OAuth device f
3068
3284
  });
3069
3285
 
3070
3286
  // src/handwritten/commands/logout.ts
3071
- import { Command as Command44 } from "commander";
3287
+ import { Command as Command48 } from "commander";
3072
3288
 
3073
3289
  // src/handwritten/auth/logout.ts
3074
3290
  async function runLogout(opts) {
@@ -3096,7 +3312,7 @@ async function runLogout(opts) {
3096
3312
  }
3097
3313
 
3098
3314
  // src/handwritten/commands/logout.ts
3099
- var logoutCommand = new Command44("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) => {
3315
+ var logoutCommand = new Command48("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) => {
3100
3316
  const res = await runLogout({ store: new ConfigStore(), email, all: opts.all });
3101
3317
  if (res.removed.length === 0) {
3102
3318
  process.stdout.write("nothing to log out\n");
@@ -3109,7 +3325,7 @@ var logoutCommand = new Command44("logout").description("Log out an account (def
3109
3325
  });
3110
3326
 
3111
3327
  // src/handwritten/commands/whoami.ts
3112
- import { Command as Command45 } from "commander";
3328
+ import { Command as Command49 } from "commander";
3113
3329
  var ENV_DISPLAY = {
3114
3330
  shape: "object",
3115
3331
  fields: ["name", "api_base", "account", "actor", "agent_label"]
@@ -3141,7 +3357,7 @@ async function backfillActiveEmail(store, envName, email, userId) {
3141
3357
  await store.write(cfg);
3142
3358
  }
3143
3359
  }
3144
- var whoamiCommand = new Command45("whoami").description("Show the active env, signed-in account, and organization").action(async () => {
3360
+ var whoamiCommand = new Command49("whoami").description("Show the active env, signed-in account, and organization").action(async () => {
3145
3361
  const store = new ConfigStore();
3146
3362
  const config = await store.read();
3147
3363
  let resolved;
@@ -3194,8 +3410,8 @@ function printLoggedOut() {
3194
3410
  }
3195
3411
 
3196
3412
  // src/handwritten/commands/config.ts
3197
- import { Command as Command46 } from "commander";
3198
- var configCommand = new Command46("config").description("Manage wspc local config");
3413
+ import { Command as Command50 } from "commander";
3414
+ var configCommand = new Command50("config").description("Manage wspc local config");
3199
3415
  registerRenderer("config_show", (data) => {
3200
3416
  const d = data;
3201
3417
  if (d.envs.length === 0) {
@@ -3266,7 +3482,7 @@ configCommand.command("use <env>").description("Switch current_env").action(asyn
3266
3482
  });
3267
3483
 
3268
3484
  // src/handwritten/commands/account.ts
3269
- import { Command as Command47 } from "commander";
3485
+ import { Command as Command51 } from "commander";
3270
3486
  async function listAccounts(store) {
3271
3487
  const c = await store.read();
3272
3488
  const envName = c.current_env;
@@ -3307,7 +3523,7 @@ registerRenderer("account_ls", (data) => {
3307
3523
  ]);
3308
3524
  process.stdout.write(table(headers, body));
3309
3525
  });
3310
- var accountCommand = new Command47("account").description("Manage logged-in accounts");
3526
+ var accountCommand = new Command51("account").description("Manage logged-in accounts");
3311
3527
  accountCommand.command("ls").description("List accounts in the current env (active marked with \u2713)").action(async () => {
3312
3528
  const accounts = await listAccounts(new ConfigStore());
3313
3529
  render({ kind: "account_ls" }, { accounts });
@@ -3319,7 +3535,7 @@ accountCommand.command("switch <email>").description("Set the active account for
3319
3535
  });
3320
3536
 
3321
3537
  // src/handwritten/commands/todo-done.ts
3322
- import { Command as Command48 } from "commander";
3538
+ import { Command as Command52 } from "commander";
3323
3539
  var TODO_UPDATE_DISPLAY = {
3324
3540
  shape: "object",
3325
3541
  format: {
@@ -3337,7 +3553,7 @@ var TODO_UPDATE_DISPLAY = {
3337
3553
  deleted_at: "relative-time"
3338
3554
  }
3339
3555
  };
3340
- var todoDoneCommand = new Command48("done").description("Mark a todo done (sugar for `update <id> --status done`)").argument("<id>", "Todo id").action(async (id) => {
3556
+ var todoDoneCommand = new Command52("done").description("Mark a todo done (sugar for `update <id> --status done`)").argument("<id>", "Todo id").action(async (id) => {
3341
3557
  const client2 = await loadSdkClient();
3342
3558
  const result = await todoUpdate({
3343
3559
  client: client2._rawClient,
@@ -3356,7 +3572,7 @@ var todoDoneCommand = new Command48("done").description("Mark a todo done (sugar
3356
3572
  });
3357
3573
 
3358
3574
  // src/handwritten/commands/email/send.ts
3359
- import { Command as Command49 } from "commander";
3575
+ import { Command as Command53 } from "commander";
3360
3576
  import { readFile, stat } from "fs/promises";
3361
3577
  import { basename } from "path";
3362
3578
 
@@ -3414,7 +3630,7 @@ async function resolveAttachment(input) {
3414
3630
  `--attach ${input}: neither a readable file nor a valid <prefix>_<ulid>:<idx> reference.`
3415
3631
  );
3416
3632
  }
3417
- var sendCommand = new Command49("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) => {
3633
+ var sendCommand = new Command53("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) => {
3418
3634
  const isReply = Boolean(opts.reply);
3419
3635
  const to = opts.to;
3420
3636
  const attachInputs = opts.attach;
@@ -3501,7 +3717,7 @@ var sendCommand = new Command49("send").description("Send an outbound email").re
3501
3717
  });
3502
3718
 
3503
3719
  // src/handwritten/commands/email/attachment.ts
3504
- import { Command as Command50 } from "commander";
3720
+ import { Command as Command54 } from "commander";
3505
3721
  import { createWriteStream } from "fs";
3506
3722
  import { Readable } from "stream";
3507
3723
  import { pipeline } from "stream/promises";
@@ -3518,7 +3734,7 @@ function parseContentDispositionFilename(header) {
3518
3734
  }
3519
3735
 
3520
3736
  // src/handwritten/commands/email/attachment.ts
3521
- var attachmentCommand = new Command50("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) => {
3737
+ var attachmentCommand = new Command54("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) => {
3522
3738
  const idx = Number(idxArg);
3523
3739
  if (!Number.isInteger(idx) || idx < 0) {
3524
3740
  process.stderr.write(`<idx> must be a non-negative integer (got "${idxArg}")
@@ -3551,7 +3767,7 @@ var attachmentCommand = new Command50("attachment").description("Download an inb
3551
3767
 
3552
3768
  // src/cli.ts
3553
3769
  function buildProgram() {
3554
- const program = new Command51().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) => {
3770
+ const program = new Command55().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) => {
3555
3771
  const globals = actionCommand.optsWithGlobals();
3556
3772
  if (globals.json) process.env.WSPC_OUTPUT = "json";
3557
3773
  if (globals.account) process.env.WSPC_ACCOUNT = String(globals.account);