@dotta/xc 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/README.md +348 -0
  2. package/dist/__tests__/bookmarks.test.d.ts +4 -0
  3. package/dist/__tests__/bookmarks.test.js +104 -0
  4. package/dist/__tests__/bookmarks.test.js.map +1 -0
  5. package/dist/__tests__/budget.test.d.ts +6 -0
  6. package/dist/__tests__/budget.test.js +105 -0
  7. package/dist/__tests__/budget.test.js.map +1 -0
  8. package/dist/__tests__/dm.test.d.ts +4 -0
  9. package/dist/__tests__/dm.test.js +115 -0
  10. package/dist/__tests__/dm.test.js.map +1 -0
  11. package/dist/__tests__/followers.test.d.ts +4 -0
  12. package/dist/__tests__/followers.test.js +129 -0
  13. package/dist/__tests__/followers.test.js.map +1 -0
  14. package/dist/__tests__/lib/api.test.d.ts +5 -0
  15. package/dist/__tests__/lib/api.test.js +202 -0
  16. package/dist/__tests__/lib/api.test.js.map +1 -0
  17. package/dist/__tests__/lib/budget.test.d.ts +5 -0
  18. package/dist/__tests__/lib/budget.test.js +194 -0
  19. package/dist/__tests__/lib/budget.test.js.map +1 -0
  20. package/dist/__tests__/lib/config.test.d.ts +6 -0
  21. package/dist/__tests__/lib/config.test.js +228 -0
  22. package/dist/__tests__/lib/config.test.js.map +1 -0
  23. package/dist/__tests__/lib/cost.test.d.ts +6 -0
  24. package/dist/__tests__/lib/cost.test.js +177 -0
  25. package/dist/__tests__/lib/cost.test.js.map +1 -0
  26. package/dist/__tests__/lib/format.test.d.ts +4 -0
  27. package/dist/__tests__/lib/format.test.js +139 -0
  28. package/dist/__tests__/lib/format.test.js.map +1 -0
  29. package/dist/__tests__/lib/oauth.test.d.ts +5 -0
  30. package/dist/__tests__/lib/oauth.test.js +123 -0
  31. package/dist/__tests__/lib/oauth.test.js.map +1 -0
  32. package/dist/__tests__/lib/resolve.test.d.ts +4 -0
  33. package/dist/__tests__/lib/resolve.test.js +154 -0
  34. package/dist/__tests__/lib/resolve.test.js.map +1 -0
  35. package/dist/__tests__/lists.test.d.ts +4 -0
  36. package/dist/__tests__/lists.test.js +96 -0
  37. package/dist/__tests__/lists.test.js.map +1 -0
  38. package/dist/__tests__/media.test.d.ts +4 -0
  39. package/dist/__tests__/media.test.js +132 -0
  40. package/dist/__tests__/media.test.js.map +1 -0
  41. package/dist/cli.d.ts +2 -0
  42. package/dist/cli.js +93 -0
  43. package/dist/cli.js.map +1 -0
  44. package/dist/commands/auth.d.ts +2 -0
  45. package/dist/commands/auth.js +191 -0
  46. package/dist/commands/auth.js.map +1 -0
  47. package/dist/commands/block.d.ts +15 -0
  48. package/dist/commands/block.js +117 -0
  49. package/dist/commands/block.js.map +1 -0
  50. package/dist/commands/bookmarks.d.ts +12 -0
  51. package/dist/commands/bookmarks.js +100 -0
  52. package/dist/commands/bookmarks.js.map +1 -0
  53. package/dist/commands/budget.d.ts +9 -0
  54. package/dist/commands/budget.js +124 -0
  55. package/dist/commands/budget.js.map +1 -0
  56. package/dist/commands/cost.d.ts +5 -0
  57. package/dist/commands/cost.js +75 -0
  58. package/dist/commands/cost.js.map +1 -0
  59. package/dist/commands/delete.d.ts +8 -0
  60. package/dist/commands/delete.js +31 -0
  61. package/dist/commands/delete.js.map +1 -0
  62. package/dist/commands/dm.d.ts +10 -0
  63. package/dist/commands/dm.js +179 -0
  64. package/dist/commands/dm.js.map +1 -0
  65. package/dist/commands/engagement.d.ts +14 -0
  66. package/dist/commands/engagement.js +167 -0
  67. package/dist/commands/engagement.js.map +1 -0
  68. package/dist/commands/followers.d.ts +14 -0
  69. package/dist/commands/followers.js +138 -0
  70. package/dist/commands/followers.js.map +1 -0
  71. package/dist/commands/get.d.ts +2 -0
  72. package/dist/commands/get.js +63 -0
  73. package/dist/commands/get.js.map +1 -0
  74. package/dist/commands/hide.d.ts +10 -0
  75. package/dist/commands/hide.js +58 -0
  76. package/dist/commands/hide.js.map +1 -0
  77. package/dist/commands/like.d.ts +3 -0
  78. package/dist/commands/like.js +52 -0
  79. package/dist/commands/like.js.map +1 -0
  80. package/dist/commands/lists.d.ts +20 -0
  81. package/dist/commands/lists.js +384 -0
  82. package/dist/commands/lists.js.map +1 -0
  83. package/dist/commands/media.d.ts +19 -0
  84. package/dist/commands/media.js +205 -0
  85. package/dist/commands/media.js.map +1 -0
  86. package/dist/commands/mentions.d.ts +8 -0
  87. package/dist/commands/mentions.js +59 -0
  88. package/dist/commands/mentions.js.map +1 -0
  89. package/dist/commands/mute.d.ts +12 -0
  90. package/dist/commands/mute.js +99 -0
  91. package/dist/commands/mute.js.map +1 -0
  92. package/dist/commands/post.d.ts +11 -0
  93. package/dist/commands/post.js +87 -0
  94. package/dist/commands/post.js.map +1 -0
  95. package/dist/commands/repost.d.ts +10 -0
  96. package/dist/commands/repost.js +59 -0
  97. package/dist/commands/repost.js.map +1 -0
  98. package/dist/commands/search.d.ts +2 -0
  99. package/dist/commands/search.js +49 -0
  100. package/dist/commands/search.js.map +1 -0
  101. package/dist/commands/stream.d.ts +13 -0
  102. package/dist/commands/stream.js +251 -0
  103. package/dist/commands/stream.js.map +1 -0
  104. package/dist/commands/timeline.d.ts +2 -0
  105. package/dist/commands/timeline.js +61 -0
  106. package/dist/commands/timeline.js.map +1 -0
  107. package/dist/commands/trends.d.ts +10 -0
  108. package/dist/commands/trends.js +59 -0
  109. package/dist/commands/trends.js.map +1 -0
  110. package/dist/commands/usage.d.ts +2 -0
  111. package/dist/commands/usage.js +52 -0
  112. package/dist/commands/usage.js.map +1 -0
  113. package/dist/commands/user.d.ts +2 -0
  114. package/dist/commands/user.js +43 -0
  115. package/dist/commands/user.js.map +1 -0
  116. package/dist/commands/usersearch.d.ts +8 -0
  117. package/dist/commands/usersearch.js +48 -0
  118. package/dist/commands/usersearch.js.map +1 -0
  119. package/dist/commands/whoami.d.ts +2 -0
  120. package/dist/commands/whoami.js +54 -0
  121. package/dist/commands/whoami.js.map +1 -0
  122. package/dist/lib/api.d.ts +12 -0
  123. package/dist/lib/api.js +91 -0
  124. package/dist/lib/api.js.map +1 -0
  125. package/dist/lib/budget.d.ts +44 -0
  126. package/dist/lib/budget.js +119 -0
  127. package/dist/lib/budget.js.map +1 -0
  128. package/dist/lib/config.d.ts +39 -0
  129. package/dist/lib/config.js +63 -0
  130. package/dist/lib/config.js.map +1 -0
  131. package/dist/lib/cost.d.ts +43 -0
  132. package/dist/lib/cost.js +224 -0
  133. package/dist/lib/cost.js.map +1 -0
  134. package/dist/lib/format.d.ts +24 -0
  135. package/dist/lib/format.js +72 -0
  136. package/dist/lib/format.js.map +1 -0
  137. package/dist/lib/oauth.d.ts +32 -0
  138. package/dist/lib/oauth.js +132 -0
  139. package/dist/lib/oauth.js.map +1 -0
  140. package/dist/lib/resolve.d.ts +12 -0
  141. package/dist/lib/resolve.js +48 -0
  142. package/dist/lib/resolve.js.map +1 -0
  143. package/package.json +46 -0
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Stream commands: manage filtered stream rules and connect to the stream.
3
+ *
4
+ * Subcommands:
5
+ * xc stream add <query> [--tag <name>] โ€” add a filtered stream rule
6
+ * xc stream rules โ€” list current rules
7
+ * xc stream remove <rule-id> โ€” remove a rule by ID
8
+ * xc stream clear โ€” remove all rules
9
+ * xc stream connect [--json] [--quiet] โ€” connect and output matching posts
10
+ */
11
+ import { getClient } from "../lib/api.js";
12
+ import { outputJson } from "../lib/cost.js";
13
+ /** Register the `stream` command group with its subcommands. */
14
+ export function registerStreamCommand(program) {
15
+ const stream = program
16
+ .command("stream")
17
+ .description("Manage filtered stream rules and connect");
18
+ // --- stream add <query> ---
19
+ stream
20
+ .command("add <query>")
21
+ .description("Add a filtered stream rule")
22
+ .option("--tag <name>", "Label for this rule")
23
+ .option("--account <name>", "Account to use")
24
+ .option("--json", "Output raw JSON")
25
+ .action(async (query, opts) => {
26
+ try {
27
+ const client = await getClient(opts.account);
28
+ // Build the add-rules request body
29
+ const rule = { value: query };
30
+ if (opts.tag)
31
+ rule.tag = opts.tag;
32
+ const result = await client.stream.updateRules({ add: [rule] });
33
+ if (opts.json) {
34
+ outputJson(result);
35
+ return;
36
+ }
37
+ const rules = result.data ?? [];
38
+ if (rules.length > 0) {
39
+ for (const r of rules) {
40
+ console.log(`Added rule ${r.id}: ${r.value}${r.tag ? ` [${r.tag}]` : ""}`);
41
+ }
42
+ }
43
+ else {
44
+ console.log("No rules added.");
45
+ // Show errors if present
46
+ if (result.errors) {
47
+ for (const e of result.errors) {
48
+ console.error(` Error: ${JSON.stringify(e)}`);
49
+ }
50
+ }
51
+ }
52
+ }
53
+ catch (err) {
54
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
55
+ process.exit(1);
56
+ }
57
+ });
58
+ // --- stream rules ---
59
+ stream
60
+ .command("rules")
61
+ .description("List current filtered stream rules")
62
+ .option("--account <name>", "Account to use")
63
+ .option("--json", "Output raw JSON")
64
+ .action(async (opts) => {
65
+ try {
66
+ const client = await getClient(opts.account);
67
+ const result = await client.stream.getRules();
68
+ if (opts.json) {
69
+ outputJson(result);
70
+ return;
71
+ }
72
+ const rules = result.data ?? [];
73
+ if (rules.length === 0) {
74
+ console.log("No rules configured.");
75
+ return;
76
+ }
77
+ for (const r of rules) {
78
+ const tag = r.tag ? ` [${r.tag}]` : "";
79
+ console.log(` ${r.id} ${r.value}${tag}`);
80
+ }
81
+ console.log(`\n${rules.length} rule${rules.length !== 1 ? "s" : ""}`);
82
+ }
83
+ catch (err) {
84
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
85
+ process.exit(1);
86
+ }
87
+ });
88
+ // --- stream remove <rule-id> ---
89
+ stream
90
+ .command("remove <ruleId>")
91
+ .description("Remove a filtered stream rule by ID")
92
+ .option("--account <name>", "Account to use")
93
+ .option("--json", "Output raw JSON")
94
+ .action(async (ruleId, opts) => {
95
+ try {
96
+ const client = await getClient(opts.account);
97
+ const result = await client.stream.updateRules({
98
+ delete: { ids: [ruleId] },
99
+ });
100
+ if (opts.json) {
101
+ outputJson(result);
102
+ return;
103
+ }
104
+ const summary = result.meta?.summary;
105
+ const deleted = summary?.deleted ?? 0;
106
+ if (deleted > 0) {
107
+ console.log(`Removed rule ${ruleId}`);
108
+ }
109
+ else {
110
+ console.log(`Rule ${ruleId} not found or already removed.`);
111
+ if (result.errors) {
112
+ for (const e of result.errors) {
113
+ console.error(` Error: ${JSON.stringify(e)}`);
114
+ }
115
+ }
116
+ }
117
+ }
118
+ catch (err) {
119
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
120
+ process.exit(1);
121
+ }
122
+ });
123
+ // --- stream clear ---
124
+ stream
125
+ .command("clear")
126
+ .description("Remove all filtered stream rules")
127
+ .option("--account <name>", "Account to use")
128
+ .option("--json", "Output raw JSON")
129
+ .action(async (opts) => {
130
+ try {
131
+ const client = await getClient(opts.account);
132
+ // First get all current rule IDs
133
+ const current = await client.stream.getRules();
134
+ const rules = current.data ?? [];
135
+ if (rules.length === 0) {
136
+ console.log("No rules to remove.");
137
+ return;
138
+ }
139
+ const ids = rules
140
+ .map((r) => r.id)
141
+ .filter((id) => !!id);
142
+ const result = await client.stream.updateRules({
143
+ delete: { ids },
144
+ });
145
+ if (opts.json) {
146
+ outputJson(result);
147
+ return;
148
+ }
149
+ const summary = result.meta?.summary;
150
+ const deleted = summary?.deleted ?? ids.length;
151
+ console.log(`Cleared ${deleted} rule${deleted !== 1 ? "s" : ""}.`);
152
+ }
153
+ catch (err) {
154
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
155
+ process.exit(1);
156
+ }
157
+ });
158
+ // --- stream connect ---
159
+ stream
160
+ .command("connect")
161
+ .description("Connect to filtered stream and output posts as they arrive")
162
+ .option("--json", "Output raw JSON lines")
163
+ .option("--quiet", "Output only post IDs")
164
+ .option("--account <name>", "Account to use")
165
+ .action(async (opts) => {
166
+ try {
167
+ const client = await getClient(opts.account);
168
+ // Connect to the filtered stream with tweet fields for human-readable output
169
+ const streamOpts = {};
170
+ if (!opts.quiet) {
171
+ streamOpts.tweetFields = ["created_at", "author_id", "text"];
172
+ streamOpts.expansions = ["author_id"];
173
+ streamOpts.userFields = ["name", "username"];
174
+ }
175
+ console.error("Connecting to filtered stream...");
176
+ const eventStream = await client.stream.posts(streamOpts);
177
+ // Handle graceful shutdown on Ctrl+C
178
+ const cleanup = () => {
179
+ console.error("\nDisconnecting...");
180
+ eventStream.close();
181
+ process.exit(0);
182
+ };
183
+ process.on("SIGINT", cleanup);
184
+ process.on("SIGTERM", cleanup);
185
+ console.error("Connected. Waiting for posts... (Ctrl+C to stop)\n");
186
+ // Listen for data events using the async iterator
187
+ for await (const event of eventStream) {
188
+ if (opts.json) {
189
+ // Raw JSON lines mode
190
+ console.log(JSON.stringify(event));
191
+ }
192
+ else if (opts.quiet) {
193
+ // Just post IDs
194
+ const id = event.data?.id;
195
+ if (id)
196
+ console.log(id);
197
+ }
198
+ else {
199
+ // Human-readable output
200
+ formatStreamEvent(event);
201
+ }
202
+ }
203
+ console.error("Stream ended.");
204
+ }
205
+ catch (err) {
206
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
207
+ process.exit(1);
208
+ }
209
+ });
210
+ }
211
+ /** Print a single streamed tweet event in human-readable format. */
212
+ function formatStreamEvent(event) {
213
+ const tweet = event.data;
214
+ if (!tweet)
215
+ return;
216
+ const lines = [];
217
+ // Try to find author from includes
218
+ const authorId = tweet.author_id;
219
+ const users = event.includes?.users ?? [];
220
+ const author = authorId
221
+ ? users.find((u) => u.id === authorId)
222
+ : undefined;
223
+ if (author) {
224
+ lines.push(`@${author.username} (${author.name})`);
225
+ }
226
+ // Tweet text
227
+ const text = tweet.text ?? "";
228
+ lines.push(` ${text.replace(/\n/g, "\n ")}`);
229
+ // Matched rules
230
+ const rules = event.matching_rules ?? [];
231
+ if (rules.length > 0) {
232
+ const ruleLabels = rules
233
+ .map((r) => r.tag ?? r.id ?? "unknown")
234
+ .join(", ");
235
+ lines.push(` rules: ${ruleLabels}`);
236
+ }
237
+ // ID and timestamp
238
+ const meta = [];
239
+ if (tweet.created_at) {
240
+ meta.push(new Date(tweet.created_at).toLocaleString());
241
+ }
242
+ if (tweet.id) {
243
+ meta.push(`id:${tweet.id}`);
244
+ }
245
+ if (meta.length > 0) {
246
+ lines.push(` ${meta.join(" ยท ")}`);
247
+ }
248
+ console.log(lines.join("\n"));
249
+ console.log(); // blank line between tweets
250
+ }
251
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/commands/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,gEAAgE;AAChE,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,MAAM,MAAM,GAAG,OAAO;SACnB,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,0CAA0C,CAAC,CAAC;IAE3D,6BAA6B;IAC7B,MAAM;SACH,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,4BAA4B,CAAC;SACzC,MAAM,CAAC,cAAc,EAAE,qBAAqB,CAAC;SAC7C,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,IAAI,EAAE,EAAE;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE7C,mCAAmC;YACnC,MAAM,IAAI,GAAoC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;YAC/D,IAAI,IAAI,CAAC,GAAG;gBAAE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;YAElC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEhE,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YAChC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;oBACtB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7E,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;gBAC/B,yBAAyB;gBACzB,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;wBAC9B,OAAO,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBACjD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,uBAAuB;IACvB,MAAM;SACH,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,oCAAoC,CAAC;SACjD,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YAE9C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YAChC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;gBACpC,OAAO;YACT,CAAC;YAED,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;gBACtB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,GAAG,GAAG,EAAE,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM,QAAQ,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACxE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,kCAAkC;IAClC,MAAM;SACH,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,qCAAqC,CAAC;SAClD,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,IAAI,EAAE,EAAE;QACrC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC;gBAC7C,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE;aAC1B,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,OAEhB,CAAC;YACd,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,CAAC,CAAC;YAEtC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;gBAChB,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,QAAQ,MAAM,gCAAgC,CAAC,CAAC;gBAC5D,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;wBAC9B,OAAO,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBACjD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,uBAAuB;IACvB,MAAM;SACH,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE7C,iCAAiC;YACjC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;YAEjC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;gBACnC,OAAO;YACT,CAAC;YAED,MAAM,GAAG,GAAG,KAAK;iBACd,GAAG,CAAC,CAAC,CAAkB,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACjC,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAEtC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC;gBAC7C,MAAM,EAAE,EAAE,GAAG,EAAE;aAChB,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,OAEhB,CAAC;YACd,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,QAAQ,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACrE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,yBAAyB;IACzB,MAAM;SACH,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,4DAA4D,CAAC;SACzE,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;SACzC,MAAM,CAAC,SAAS,EAAE,sBAAsB,CAAC;SACzC,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE7C,6EAA6E;YAC7E,MAAM,UAAU,GAA4B,EAAE,CAAC;YAC/C,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAChB,UAAU,CAAC,WAAW,GAAG,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;gBAC7D,UAAU,CAAC,UAAU,GAAG,CAAC,WAAW,CAAC,CAAC;gBACtC,UAAU,CAAC,UAAU,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YAC/C,CAAC;YAED,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;YAClD,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAE1D,qCAAqC;YACrC,MAAM,OAAO,GAAG,GAAG,EAAE;gBACnB,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;gBACpC,WAAW,CAAC,KAAK,EAAE,CAAC;gBACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC,CAAC;YACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC9B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAE/B,OAAO,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;YAEpE,kDAAkD;YAClD,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;gBACtC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACd,sBAAsB;oBACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;gBACrC,CAAC;qBAAM,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBACtB,gBAAgB;oBAChB,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;oBAC1B,IAAI,EAAE;wBAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC1B,CAAC;qBAAM,CAAC;oBACN,wBAAwB;oBACxB,iBAAiB,CAAC,KAAK,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;YAED,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,oEAAoE;AACpE,SAAS,iBAAiB,CAAC,KAI1B;IACC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;IACzB,IAAI,CAAC,KAAK;QAAE,OAAO;IAEnB,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,mCAAmC;IACnC,MAAM,QAAQ,GAAG,KAAK,CAAC,SAA+B,CAAC;IACvD,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,QAAQ;QACrB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC;QACtC,CAAC,CAAC,SAAS,CAAC;IAEd,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;IACrD,CAAC;IAED,aAAa;IACb,MAAM,IAAI,GAAI,KAAK,CAAC,IAAe,IAAI,EAAE,CAAC;IAC1C,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAE/C,gBAAgB;IAChB,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,IAAI,EAAE,CAAC;IACzC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,UAAU,GAAG,KAAK;aACrB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,IAAI,SAAS,CAAC;aACtC,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,YAAY,UAAU,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,mBAAmB;IACnB,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,UAAoB,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;QACb,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9B,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,4BAA4B;AAC7C,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerTimelineCommand(program: Command): void;
@@ -0,0 +1,61 @@
1
+ import { getClient } from "../lib/api.js";
2
+ import { outputJson } from "../lib/cost.js";
3
+ import { buildUserMap, formatTweetList } from "../lib/format.js";
4
+ import { resolveAuthenticatedUserId, resolveUserId } from "../lib/resolve.js";
5
+ const TWEET_FIELDS = ["created_at", "public_metrics", "author_id"];
6
+ const EXPANSIONS = ["author_id"];
7
+ const USER_FIELDS = ["name", "username"];
8
+ export function registerTimelineCommand(program) {
9
+ program
10
+ .command("timeline [username]")
11
+ .description("View home timeline, or a user's posts with @username argument")
12
+ .option("-n, --limit <n>", "Max results (1-100)", "20")
13
+ .option("--json", "Output raw JSON")
14
+ .option("--account <name>", "Account to use")
15
+ .action(async (username, opts) => {
16
+ try {
17
+ const client = await getClient(opts.account);
18
+ const fieldOpts = {
19
+ tweetFields: TWEET_FIELDS,
20
+ expansions: EXPANSIONS,
21
+ userFields: USER_FIELDS,
22
+ maxResults: parseInt(opts.limit, 10),
23
+ };
24
+ let result;
25
+ if (username) {
26
+ // User timeline: fetch their posts
27
+ const userId = await resolveUserId(username, opts.account);
28
+ result = await client.users.getPosts(userId, fieldOpts);
29
+ }
30
+ else {
31
+ // Home timeline: reverse-chronological feed
32
+ const myId = await resolveAuthenticatedUserId(opts.account);
33
+ result = await client.users.getTimeline(myId, fieldOpts);
34
+ }
35
+ if (opts.json) {
36
+ outputJson(result);
37
+ return;
38
+ }
39
+ const tweets = result.data ?? [];
40
+ if (tweets.length === 0) {
41
+ console.log("No posts found.");
42
+ return;
43
+ }
44
+ const usersById = buildUserMap(result.includes?.users);
45
+ // Header
46
+ if (username) {
47
+ const clean = username.replace(/^@/, "");
48
+ console.log(`Posts from @${clean}:\n`);
49
+ }
50
+ else {
51
+ console.log("Home timeline:\n");
52
+ }
53
+ console.log(formatTweetList(tweets, usersById));
54
+ }
55
+ catch (err) {
56
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
57
+ process.exit(1);
58
+ }
59
+ });
60
+ }
61
+ //# sourceMappingURL=timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../src/commands/timeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Trends commands: view trending topics.
3
+ *
4
+ * Usage:
5
+ * xc trends โ€” personalized trends
6
+ * xc trends <woeid> โ€” trends by location (WOEID)
7
+ * xc trends --global โ€” worldwide trends (WOEID 1)
8
+ */
9
+ import { Command } from "commander";
10
+ export declare function registerTrendsCommand(program: Command): void;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Trends commands: view trending topics.
3
+ *
4
+ * Usage:
5
+ * xc trends โ€” personalized trends
6
+ * xc trends <woeid> โ€” trends by location (WOEID)
7
+ * xc trends --global โ€” worldwide trends (WOEID 1)
8
+ */
9
+ import { getClient } from "../lib/api.js";
10
+ import { outputJson } from "../lib/cost.js";
11
+ export function registerTrendsCommand(program) {
12
+ program
13
+ .command("trends [woeid]")
14
+ .description("View trending topics (personalized, by WOEID, or --global)")
15
+ .option("--global", "Show worldwide trends (WOEID 1)")
16
+ .option("--json", "Output raw JSON")
17
+ .option("--account <name>", "Account to use")
18
+ .action(async (woeid, opts) => {
19
+ try {
20
+ const client = await getClient(opts.account);
21
+ let result;
22
+ const locationId = opts.global ? 1 : woeid ? parseInt(woeid, 10) : undefined;
23
+ if (locationId !== undefined) {
24
+ result = await client.trends.getByWoeid(locationId);
25
+ }
26
+ else {
27
+ result = await client.trends.getPersonalized();
28
+ }
29
+ if (opts.json) {
30
+ outputJson(result);
31
+ return;
32
+ }
33
+ const trends = (result.data ?? []);
34
+ if (trends.length === 0) {
35
+ console.log("No trends found.");
36
+ return;
37
+ }
38
+ const label = locationId !== undefined
39
+ ? locationId === 1
40
+ ? "Worldwide"
41
+ : `WOEID ${locationId}`
42
+ : "Personalized";
43
+ console.log(`${label} trends:\n`);
44
+ for (let i = 0; i < trends.length; i++) {
45
+ const trend = trends[i];
46
+ const name = trend.trendName ?? trend.name ?? "Unknown";
47
+ const countStr = trend.tweetCount
48
+ ? ` (${trend.tweetCount.toLocaleString()} posts)`
49
+ : "";
50
+ console.log(` ${i + 1}. ${name}${countStr}`);
51
+ }
52
+ }
53
+ catch (err) {
54
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
55
+ process.exit(1);
56
+ }
57
+ });
58
+ }
59
+ //# sourceMappingURL=trends.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trends.js","sourceRoot":"","sources":["../../src/commands/trends.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAU5C,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,4DAA4D,CAAC;SACzE,MAAM,CAAC,UAAU,EAAE,iCAAiC,CAAC;SACrD,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,KAAyB,EAAE,IAAI,EAAE,EAAE;QAChD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE7C,IAAI,MAAM,CAAC;YACX,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAE7E,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC7B,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;YACtD,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YACjD,CAAC;YAED,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAY,CAAC;YAC9C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;gBAChC,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,UAAU,KAAK,SAAS;gBACpC,CAAC,CAAC,UAAU,KAAK,CAAC;oBAChB,CAAC,CAAC,WAAW;oBACb,CAAC,CAAC,SAAS,UAAU,EAAE;gBACzB,CAAC,CAAC,cAAc,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,YAAY,CAAC,CAAC;YAElC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACvC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;gBACxB,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,IAAI,SAAS,CAAC;gBACxD,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU;oBAC/B,CAAC,CAAC,KAAK,KAAK,CAAC,UAAU,CAAC,cAAc,EAAE,SAAS;oBACjD,CAAC,CAAC,EAAE,CAAC;gBACP,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,QAAQ,EAAE,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerUsageCommand(program: Command): void;
@@ -0,0 +1,52 @@
1
+ import { getClient } from "../lib/api.js";
2
+ import { outputJson } from "../lib/cost.js";
3
+ export function registerUsageCommand(program) {
4
+ program
5
+ .command("usage")
6
+ .description("Show API usage stats")
7
+ .option("--json", "Output raw JSON")
8
+ .option("--account <name>", "Account to use")
9
+ .action(async (opts) => {
10
+ try {
11
+ const client = await getClient(opts.account);
12
+ const result = await client.usage.get();
13
+ if (opts.json) {
14
+ outputJson(result);
15
+ return;
16
+ }
17
+ const data = result.data;
18
+ if (!data) {
19
+ console.log("No usage data available.");
20
+ return;
21
+ }
22
+ // Show cap reset day if present
23
+ if (data.capResetDay) {
24
+ console.log(`Cap resets on day ${data.capResetDay} of each month\n`);
25
+ }
26
+ // Summarize recent daily usage
27
+ const days = (data.dailyProjectUsage ?? []);
28
+ if (days.length === 0) {
29
+ console.log("No daily usage data available.");
30
+ return;
31
+ }
32
+ console.log("Daily tweet usage:\n");
33
+ for (const day of days) {
34
+ const date = new Date(day.date).toLocaleDateString();
35
+ const total = day.usage.reduce((sum, u) => sum + u.tweets, 0);
36
+ console.log(` ${date}: ${total.toLocaleString()} tweets`);
37
+ // Per-app breakdown if multiple apps
38
+ if (day.usage.length > 1) {
39
+ for (const u of day.usage) {
40
+ const appName = u.app?.appName ?? "unknown";
41
+ console.log(` ${appName}: ${u.tweets.toLocaleString()}`);
42
+ }
43
+ }
44
+ }
45
+ }
46
+ catch (err) {
47
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
48
+ process.exit(1);
49
+ }
50
+ });
51
+ }
52
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/commands/usage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAU5C,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,sBAAsB,CAAC;SACnC,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YAExC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAA2C,CAAC;YAChE,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;gBACxC,OAAO;YACT,CAAC;YAED,gCAAgC;YAChC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,CAAC,WAAW,kBAAkB,CAAC,CAAC;YACvE,CAAC;YAED,+BAA+B;YAC/B,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAsB,CAAC;YACjE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;gBAC9C,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACpC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,kBAAkB,EAAE,CAAC;gBACrD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBAC9D,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,KAAK,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;gBAE3D,qCAAqC;gBACrC,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACzB,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;wBAC1B,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,IAAI,SAAS,CAAC;wBAC5C,OAAO,CAAC,GAAG,CAAC,OAAO,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;oBAC9D,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerUserCommand(program: Command): void;
@@ -0,0 +1,43 @@
1
+ import { getClient } from "../lib/api.js";
2
+ import { outputJson } from "../lib/cost.js";
3
+ const USER_FIELDS = ["created_at", "description", "public_metrics"];
4
+ export function registerUserCommand(program) {
5
+ program
6
+ .command("user <username>")
7
+ .description("Look up a user by @username")
8
+ .option("--json", "Output raw JSON")
9
+ .option("--account <name>", "Account to use")
10
+ .action(async (username, opts) => {
11
+ try {
12
+ const clean = username.replace(/^@/, "");
13
+ const client = await getClient(opts.account);
14
+ const result = await client.users.getByUsername(clean, {
15
+ userFields: USER_FIELDS,
16
+ });
17
+ if (opts.json) {
18
+ outputJson(result);
19
+ return;
20
+ }
21
+ const data = result.data;
22
+ if (!data) {
23
+ console.error(`User @${clean} not found.`);
24
+ process.exit(1);
25
+ }
26
+ const m = data.publicMetrics;
27
+ console.log(`@${data.username} (${data.name})`);
28
+ if (data.description)
29
+ console.log(` ${data.description}`);
30
+ if (m) {
31
+ console.log(` ${(m.followersCount ?? 0).toLocaleString()} followers ยท ${(m.followingCount ?? 0).toLocaleString()} following ยท ${(m.tweetCount ?? 0).toLocaleString()} posts`);
32
+ }
33
+ if (data.createdAt) {
34
+ console.log(` Joined ${new Date(data.createdAt).toLocaleDateString()}`);
35
+ }
36
+ }
37
+ catch (err) {
38
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
39
+ process.exit(1);
40
+ }
41
+ });
42
+ }
43
+ //# sourceMappingURL=user.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.js","sourceRoot":"","sources":["../../src/commands/user.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,WAAW,GAAG,CAAC,YAAY,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;AAEpE,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAI,EAAE,EAAE;QACvC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACzC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,EAAE;gBACrD,UAAU,EAAE,WAAW;aACxB,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACzB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,CAAC,KAAK,CAAC,SAAS,KAAK,aAAa,CAAC,CAAC;gBAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,MAAM,CAAC,GAAG,IAAI,CAAC,aAAmD,CAAC;YAEnE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;YAChD,IAAI,IAAI,CAAC,WAAW;gBAAE,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YAC3D,IAAI,CAAC,EAAE,CAAC;gBACN,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,cAAc,EAAE,QAAQ,CAClK,CAAC;YACJ,CAAC;YACD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnB,OAAO,CAAC,GAAG,CACT,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,kBAAkB,EAAE,EAAE,CAC5D,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * User search command.
3
+ *
4
+ * Usage:
5
+ * xc usersearch <query> โ€” search for users by keyword
6
+ */
7
+ import { Command } from "commander";
8
+ export declare function registerUserSearchCommand(program: Command): void;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * User search command.
3
+ *
4
+ * Usage:
5
+ * xc usersearch <query> โ€” search for users by keyword
6
+ */
7
+ import { getClient } from "../lib/api.js";
8
+ import { outputJson } from "../lib/cost.js";
9
+ import { formatUserLine } from "../lib/format.js";
10
+ export function registerUserSearchCommand(program) {
11
+ program
12
+ .command("usersearch <query>")
13
+ .description("Search for users by keyword")
14
+ .option("-n, --limit <n>", "Max results (1-100)", "20")
15
+ .option("--json", "Output raw JSON")
16
+ .option("--account <name>", "Account to use")
17
+ .action(async (query, opts) => {
18
+ try {
19
+ const client = await getClient(opts.account);
20
+ const result = await client.users.search(query, {
21
+ userFields: ["username", "name", "public_metrics", "description"],
22
+ maxResults: parseInt(opts.limit, 10),
23
+ });
24
+ if (opts.json) {
25
+ outputJson(result);
26
+ return;
27
+ }
28
+ const users = (result.data ?? []);
29
+ if (users.length === 0) {
30
+ console.log(`No users found for "${query}".`);
31
+ return;
32
+ }
33
+ console.log(`Users matching "${query}":\n`);
34
+ for (const user of users) {
35
+ console.log(formatUserLine(user));
36
+ if (user.description) {
37
+ console.log(` ${user.description.replace(/\n/g, " ").slice(0, 100)}`);
38
+ }
39
+ }
40
+ console.log(`\nโ€” ${users.length} shown`);
41
+ }
42
+ catch (err) {
43
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
44
+ process.exit(1);
45
+ }
46
+ });
47
+ }
48
+ //# sourceMappingURL=usersearch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usersearch.js","sourceRoot":"","sources":["../../src/commands/usersearch.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAmB,MAAM,kBAAkB,CAAC;AAEnE,MAAM,UAAU,yBAAyB,CAAC,OAAgB;IACxD,OAAO;SACJ,OAAO,CAAC,oBAAoB,CAAC;SAC7B,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,iBAAiB,EAAE,qBAAqB,EAAE,IAAI,CAAC;SACtD,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,IAAI,EAAE,EAAE;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE;gBAC9C,UAAU,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,CAAC;gBACjE,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;aACrC,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAiB,CAAC;YAClD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,IAAI,CAAC,CAAC;gBAC9C,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,MAAM,CAAC,CAAC;YAC5C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;gBAClC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oBACrB,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC3E,CAAC;YACH,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerWhoamiCommand(program: Command): void;
@@ -0,0 +1,54 @@
1
+ import { getClient } from "../lib/api.js";
2
+ import { outputJson } from "../lib/cost.js";
3
+ const USER_FIELDS = [
4
+ "created_at",
5
+ "description",
6
+ "public_metrics",
7
+ "verified",
8
+ "location",
9
+ "url",
10
+ "profile_image_url",
11
+ ];
12
+ export function registerWhoamiCommand(program) {
13
+ program
14
+ .command("whoami")
15
+ .description("Show the authenticated user")
16
+ .option("--account <name>", "Account to check")
17
+ .option("--json", "Output raw JSON")
18
+ .action(async (opts) => {
19
+ try {
20
+ const client = await getClient(opts.account);
21
+ const result = await client.users.getMe({ userFields: USER_FIELDS });
22
+ if (opts.json) {
23
+ outputJson(result);
24
+ return;
25
+ }
26
+ const data = result.data;
27
+ if (!data) {
28
+ console.error("Could not fetch user info.");
29
+ process.exit(1);
30
+ }
31
+ const m = data.publicMetrics;
32
+ console.log(`@${data.username} (${data.name})`);
33
+ if (data.description)
34
+ console.log(` ${data.description}`);
35
+ if (data.location)
36
+ console.log(` ๐Ÿ“ ${data.location}`);
37
+ if (data.url)
38
+ console.log(` ๐Ÿ”— ${data.url}`);
39
+ if (data.verified)
40
+ console.log(` โœ“ Verified`);
41
+ if (m) {
42
+ console.log(` ${(m.followersCount ?? 0).toLocaleString()} followers ยท ${(m.followingCount ?? 0).toLocaleString()} following ยท ${(m.tweetCount ?? 0).toLocaleString()} posts`);
43
+ }
44
+ if (data.createdAt) {
45
+ console.log(` Joined ${new Date(data.createdAt).toLocaleDateString()}`);
46
+ }
47
+ }
48
+ catch (err) {
49
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
50
+ process.exit(1);
51
+ }
52
+ });
53
+ }
54
+ //# sourceMappingURL=whoami.js.map