@curviate/cli 0.22.0 → 0.23.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.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,71 @@ a new command or flag is a minor; a breaking command/flag/exit-code change is a
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.23.0] - 2026-08-10
12
+
13
+ A security and correctness release. Upgrade promptly if `--account` is ever
14
+ set from anything other than a literal you typed yourself (an environment
15
+ variable, a config profile, or agent- or model-generated text): every
16
+ published version through 0.22.0 interpolated it into the request path with
17
+ no validation at all, so a value carrying a slash, `..`, a question mark, a
18
+ hash, or a percent sign could redirect a request, including a write, to a
19
+ different endpoint on the API host. This release also lets `--account` take a
20
+ connected account's name, not just its id.
21
+
22
+ ### Fixed
23
+
24
+ - **`--account` could redirect a request to a different endpoint.**
25
+ `inbox mark-read` on `--account 'x/../../../v1/accounts'` built
26
+ `PATCH /v1/accounts/chats/chat_1` instead of touching the account the caller
27
+ named. `--account 'a?x=1'` injected a query string into the middle of the
28
+ path. Neither needed a literal `..`: the URL Standard percent-decodes when it
29
+ decides whether a segment is a double-dot path segment, so `%2e%2e` walked up
30
+ the path with no slash in the value at all. Every account-scoped command was
31
+ reachable this way, since all of them build the request URL from `--account`.
32
+ The value is now checked before any request is built, and a value that could
33
+ redirect one is refused with `[INVALID_PATH_SEGMENT]` (exit `2`) naming the
34
+ character it contains, rather than being sent.
35
+
36
+ - **`group get` / `group members` never actually accepted a group URL,
37
+ despite documenting it.** The help and this file both claimed the server
38
+ extracted the numeric id from a full `https://www.linkedin.com/groups/...`
39
+ URL passed through verbatim; it does not, and cannot: the URL's own slashes
40
+ split it into several path segments and the request landed on a route that
41
+ does not exist. The numeric id is now extracted client-side, the same way
42
+ member, company, chat, and job URLs already are. A bare numeric id is
43
+ unaffected.
44
+
45
+ ### Added
46
+
47
+ - **`--account` accepts a connected account's name, not just its id.** A value
48
+ that is not shaped like an account id is looked up against
49
+ `accounts.list`: an exact name match wins outright, otherwise a unique
50
+ prefix match resolves. A name matching more than one connected account
51
+ exits with `[ACCOUNT_AMBIGUOUS]` (exit `2`) rather than guessing, since
52
+ acting on the wrong live persona cannot be undone. A name matching none
53
+ exits with `[ACCOUNT_NAME_NOT_FOUND]` (exit `4`) and lists what is
54
+ connected. On an API key with more connected accounts than the resolver
55
+ reads (250 per page, 10 pages), a name lookup exits with
56
+ `[ACCOUNT_LIST_TRUNCATED]` (exit `2`) instead of matching against a list
57
+ that might be missing the very account the name would have matched; pass
58
+ the id instead, which needs no lookup. An id-shaped value still costs no
59
+ extra request. `--preview` never issues the lookup, consistent with it
60
+ never calling the API.
61
+
62
+ ### Changed
63
+
64
+ - **`@curviate/sdk` dependency bumped to `^0.20.1`.** ^0.20.0 still resolves
65
+ the vulnerable 0.20.0 build on a fresh install or an old lockfile; 0.20.1 is
66
+ a hard floor at the fix. Percent-encoding of every other command's path
67
+ parameters (chat, job, group, company and member ids, and so on) is the
68
+ SDK's job as of 0.20.0, not this CLI's: a previous CLI-side guard that
69
+ inspected each call's leading string argument has been removed, because it
70
+ could not know which argument actually became a path segment and was wrong
71
+ in both directions, missing a path parameter passed inside an object and
72
+ rejecting a body field that never reached a path (`post save <share URL>`
73
+ was one such false rejection). `--account` is guarded separately, above,
74
+ because it is the one value this CLI genuinely understands the meaning of.
75
+
11
76
  ## [0.22.0] - 2026-08-07
12
77
 
13
78
  Two correctness fixes for the same underlying failure: a command that answers
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ assertNoStdinPlaceholder
4
+ } from "./chunk-ZYURL5VK.js";
5
+ import {
6
+ getExitCode
7
+ } from "./chunk-PMRQXBCP.js";
8
+
9
+ // src/lib/path-safety.ts
10
+ var UNSAFE_CHARS = /[\u0000-\u0020\u007F/\\?#%]/;
11
+ var UNICODE_WHITESPACE = /[\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]/;
12
+ function describeChar(value, index) {
13
+ const ch = value[index] ?? "";
14
+ const named = {
15
+ "/": "a slash",
16
+ "\\": "a backslash",
17
+ "?": "a question mark",
18
+ "#": "a hash",
19
+ "%": "a percent sign",
20
+ " ": "a space",
21
+ " ": "a tab",
22
+ "\n": "a newline",
23
+ "\r": "a carriage return"
24
+ };
25
+ return named[ch] ?? `the character U+${ch.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0")}`;
26
+ }
27
+ function firstRedirectingIndex(value) {
28
+ for (let i = 0; i < value.length; i++) {
29
+ const ch = value[i];
30
+ if (ch === " ") continue;
31
+ if (UNSAFE_CHARS.test(ch) || UNICODE_WHITESPACE.test(ch)) return i;
32
+ }
33
+ return -1;
34
+ }
35
+ function redirectingViolation(value) {
36
+ if (value.length === 0) return "it is empty";
37
+ const i = firstRedirectingIndex(value);
38
+ if (i >= 0) return `it contains ${describeChar(value, i)}`;
39
+ if (value.includes("..")) return 'it contains ".."';
40
+ if (value === ".") return 'it is "."';
41
+ return null;
42
+ }
43
+ function pathSegmentViolation(value) {
44
+ const redirecting = redirectingViolation(value);
45
+ if (redirecting !== null) return redirecting;
46
+ if (value.includes(" ")) return "it contains a space";
47
+ return null;
48
+ }
49
+ function pathSegmentErrorMessage(label, value, reason) {
50
+ return `error: [INVALID_PATH_SEGMENT] ${label}: ${reason}, so it cannot be part of a request path. A value carrying a slash, backslash, question mark, hash, percent sign, whitespace, or ".." would redirect the request to a different endpoint. Received: ${JSON.stringify(value)}.
51
+ `;
52
+ }
53
+
54
+ // src/lib/account-arg.ts
55
+ var ACCOUNT_ID_RE = /^acc_[A-Za-z0-9_-]+$/;
56
+ var listCache = /* @__PURE__ */ new WeakMap();
57
+ var MAX_LOOKUP_PAGES = 10;
58
+ function toConnectedAccount(item) {
59
+ if (item === null || typeof item !== "object") return null;
60
+ const row = item;
61
+ const accountId = row["account_id"];
62
+ if (typeof accountId !== "string" || accountId.length === 0) return null;
63
+ const fullName = row["full_name"];
64
+ return {
65
+ accountId,
66
+ fullName: typeof fullName === "string" && fullName.length > 0 ? fullName : null
67
+ };
68
+ }
69
+ function listConnectedAccounts(client) {
70
+ const cached = listCache.get(client);
71
+ if (cached) return cached;
72
+ const pending = (async () => {
73
+ const accounts = [];
74
+ let cursor;
75
+ for (let page = 0; page < MAX_LOOKUP_PAGES; page++) {
76
+ const params = { limit: 250 };
77
+ if (cursor) params["cursor"] = cursor;
78
+ const result = await client.accounts.list(
79
+ params
80
+ );
81
+ for (const item of result.items ?? []) {
82
+ const account = toConnectedAccount(item);
83
+ if (account) accounts.push(account);
84
+ }
85
+ if (!result.cursor) return { accounts, complete: true };
86
+ cursor = result.cursor;
87
+ }
88
+ return { accounts, complete: false };
89
+ })();
90
+ listCache.set(client, pending);
91
+ return pending;
92
+ }
93
+ function describeAccount(account) {
94
+ return account.fullName === null ? account.accountId : `"${account.fullName}" (${account.accountId})`;
95
+ }
96
+ function describeAll(accounts) {
97
+ return accounts.map(describeAccount).join(", ");
98
+ }
99
+ function matchAccounts(accounts, selector) {
100
+ const needle = selector.toLowerCase();
101
+ const byId = accounts.filter((a) => a.accountId === selector);
102
+ if (byId.length > 0) return byId;
103
+ const exactName = accounts.filter((a) => a.fullName?.toLowerCase() === needle);
104
+ if (exactName.length > 0) return exactName;
105
+ return accounts.filter((a) => a.fullName?.toLowerCase().startsWith(needle));
106
+ }
107
+ async function requireAccount(client, flags, out) {
108
+ const account = flags.account;
109
+ if (!account) {
110
+ out.stderr.write(
111
+ "error: --account is required for this command. Set it via --account, CURVIATE_ACCOUNT, or `curviate config set-account`.\n"
112
+ );
113
+ process.exit(2);
114
+ }
115
+ const selector = account.trim();
116
+ assertNoStdinPlaceholder("the --account value", [selector]);
117
+ const redirecting = redirectingViolation(selector);
118
+ if (redirecting !== null) {
119
+ out.stderr.write(pathSegmentErrorMessage("--account", selector, redirecting));
120
+ process.exit(2);
121
+ }
122
+ if (ACCOUNT_ID_RE.test(selector)) return selector;
123
+ if (flags.preview === true) {
124
+ out.stderr.write(
125
+ `note: --preview does not call the API, so --account "${selector}" is shown as you typed it. A real run resolves it to an account id first, and fails if it matches no connected account or more than one.
126
+ `
127
+ );
128
+ return selector;
129
+ }
130
+ let listed;
131
+ try {
132
+ listed = await listConnectedAccounts(client);
133
+ } catch (err) {
134
+ const { CurviateError } = await import("@curviate/sdk");
135
+ if (err instanceof CurviateError) {
136
+ const e = err;
137
+ out.stderr.write(
138
+ `error: [${e.code}] could not look up connected accounts to resolve --account "${selector}": ${e.message}
139
+ `
140
+ );
141
+ process.exit(getExitCode(e.code));
142
+ }
143
+ throw err;
144
+ }
145
+ if (!listed.complete) {
146
+ out.stderr.write(
147
+ `error: [ACCOUNT_LIST_TRUNCATED] --account "${selector}" cannot be resolved by name: this API key has more connected accounts than the resolver reads (it stops after ${MAX_LOOKUP_PAGES} pages of 250), so the name would be matched against an incomplete list and a single match would not prove there is only one. Pass the account id instead; an id is used as given and needs no lookup.
148
+ `
149
+ );
150
+ process.exit(2);
151
+ }
152
+ const accounts = listed.accounts;
153
+ const matches = matchAccounts(accounts, selector);
154
+ if (matches.length === 1) {
155
+ const resolved = matches[0].accountId;
156
+ const bad = pathSegmentViolation(resolved);
157
+ if (bad !== null) {
158
+ out.stderr.write(
159
+ pathSegmentErrorMessage(`the account id resolved from "${selector}"`, resolved, bad)
160
+ );
161
+ process.exit(2);
162
+ }
163
+ return resolved;
164
+ }
165
+ if (matches.length > 1) {
166
+ out.stderr.write(
167
+ `error: [ACCOUNT_AMBIGUOUS] --account "${selector}" matches ${matches.length} connected accounts: ${describeAll(matches)}. Pass the account id of the one you mean; this is not resolved by guessing, because acting as the wrong account cannot be undone.
168
+ `
169
+ );
170
+ process.exit(2);
171
+ }
172
+ const known = accounts.length === 0 ? "No accounts are connected on this API key." : `Connected accounts: ${describeAll(accounts)}.`;
173
+ out.stderr.write(
174
+ `error: [ACCOUNT_NAME_NOT_FOUND] --account "${selector}" matched no connected account. ${known}
175
+ `
176
+ );
177
+ process.exit(4);
178
+ }
179
+
180
+ export {
181
+ requireAccount
182
+ };
@@ -15,7 +15,10 @@ import {
15
15
  import {
16
16
  normalizeChatId,
17
17
  resolveIdentifier
18
- } from "./chunk-DMQZEPQE.js";
18
+ } from "./chunk-UEAX6KUB.js";
19
+ import {
20
+ requireAccount
21
+ } from "./chunk-3BO6GVS2.js";
19
22
  import {
20
23
  buildPreviewOutput
21
24
  } from "./chunk-R3VLWLVV.js";
@@ -42,13 +45,6 @@ function buildOutputStreams() {
42
45
  stderr: { write: (s) => process.stderr.write(s) }
43
46
  };
44
47
  }
45
- function requireAccount(account, out) {
46
- if (!account) {
47
- out.stderr.write("error: --account is required for this command. Set it via --account, CURVIATE_ACCOUNT, or `curviate config set-account`.\n");
48
- process.exit(2);
49
- }
50
- return account;
51
- }
52
48
  function rejectPreviewOnRead(preview, out) {
53
49
  if (preview) {
54
50
  out.stderr.write("error: --preview is only valid on write commands (mutations). Reads just run.\n");
@@ -95,7 +91,7 @@ function willSendAsNotice(chatId) {
95
91
  return chatId.startsWith("COMPANY_") ? "Will send as a company page\n" : null;
96
92
  }
97
93
  async function runMessageNew(client, flags, out, _readStdin) {
98
- const accountId = requireAccount(flags.account, out);
94
+ const accountId = await requireAccount(client, flags, out);
99
95
  const rawTo = flags.to ?? "";
100
96
  const rawText = flags.text ?? "";
101
97
  const attachPaths = normalizeAttachPaths(flags.attach);
@@ -154,7 +150,7 @@ async function runMessageNew(client, flags, out, _readStdin) {
154
150
  }
155
151
  }
156
152
  async function runMessageSend(client, flags, out, _readStdin) {
157
- const accountId = requireAccount(flags.account, out);
153
+ const accountId = await requireAccount(client, flags, out);
158
154
  const chatId = normalizeChatId(flags.chatId ?? "");
159
155
  const rawText = flags.text ?? "";
160
156
  const attachPaths = normalizeAttachPaths(flags.attach);
@@ -205,7 +201,7 @@ async function runMessageSend(client, flags, out, _readStdin) {
205
201
  async function runMessageGet(client, flags, out) {
206
202
  rejectPreviewOnRead(flags.preview, out);
207
203
  rejectAllOnNonPaginated(flags.all, out);
208
- const accountId = requireAccount(flags.account, out);
204
+ const accountId = await requireAccount(client, flags, out);
209
205
  const chatId = normalizeChatId(flags.chatId ?? "");
210
206
  const messageId = flags.messageId ?? "";
211
207
  const ns = client.account(accountId);
@@ -218,7 +214,7 @@ async function runMessageGet(client, flags, out) {
218
214
  }
219
215
  }
220
216
  async function runMessageEdit(client, flags, out, _readStdin) {
221
- const accountId = requireAccount(flags.account, out);
217
+ const accountId = await requireAccount(client, flags, out);
222
218
  const chatId = normalizeChatId(flags.chatId ?? "");
223
219
  const messageId = flags.messageId ?? "";
224
220
  const rawText = flags.text ?? "";
@@ -243,7 +239,7 @@ async function runMessageEdit(client, flags, out, _readStdin) {
243
239
  }
244
240
  }
245
241
  async function runMessageDelete(client, flags, out) {
246
- const accountId = requireAccount(flags.account, out);
242
+ const accountId = await requireAccount(client, flags, out);
247
243
  const chatId = normalizeChatId(flags.chatId ?? "");
248
244
  const messageId = flags.messageId ?? "";
249
245
  if (flags.preview) {
@@ -266,7 +262,7 @@ async function runMessageDelete(client, flags, out) {
266
262
  }
267
263
  }
268
264
  async function runMessageReact(client, flags, out) {
269
- const accountId = requireAccount(flags.account, out);
265
+ const accountId = await requireAccount(client, flags, out);
270
266
  const chatId = normalizeChatId(flags.chatId ?? "");
271
267
  const messageId = flags.messageId ?? "";
272
268
  const reaction = flags.emoji ?? flags.emojiAlias ?? "";
@@ -296,7 +292,7 @@ async function runMessageReact(client, flags, out) {
296
292
  }
297
293
  async function runMessageAttachment(client, flags, out, isTTY) {
298
294
  rejectPreviewOnRead(flags.preview, out);
299
- const accountId = requireAccount(flags.account, out);
295
+ const accountId = await requireAccount(client, flags, out);
300
296
  const chatId = normalizeChatId(flags.chatId ?? "");
301
297
  const messageId = flags.messageId ?? "";
302
298
  const attachmentId = flags.attachmentId ?? "";
@@ -319,7 +315,7 @@ async function runMessageAttachment(client, flags, out, isTTY) {
319
315
  }
320
316
  }
321
317
  async function runMessageInMail(client, flags, out, _readStdin) {
322
- const accountId = requireAccount(flags.account, out);
318
+ const accountId = await requireAccount(client, flags, out);
323
319
  const rawTo = flags.to ?? "";
324
320
  if (!rawTo) {
325
321
  out.stderr.write(
@@ -373,7 +369,7 @@ async function runMessageInMail(client, flags, out, _readStdin) {
373
369
  async function runMessageInMailBalance(client, flags, out) {
374
370
  rejectPreviewOnRead(flags.preview, out);
375
371
  rejectAllOnNonPaginated(flags.all, out);
376
- const accountId = requireAccount(flags.account, out);
372
+ const accountId = await requireAccount(client, flags, out);
377
373
  const ns = client.account(accountId);
378
374
  const outOpts = resolveOutputOpts(flags);
379
375
  try {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveIdentifier
4
- } from "./chunk-DMQZEPQE.js";
4
+ } from "./chunk-UEAX6KUB.js";
5
5
 
6
6
  // src/lib/member-id.ts
7
7
  var MEMBER_PROVIDER_ID_RE = /^A[CDE][A-Za-z0-9_-]{4,}$/;
@@ -33,6 +33,15 @@ function normalizeChatId(raw) {
33
33
  if (match?.[1]) return match[1];
34
34
  return raw;
35
35
  }
36
+ var GROUP_URL_RE = /^https?:\/\/(?:[a-z0-9-]+\.)?linkedin\.com\/groups\/([^/?#]+)/i;
37
+ var GROUP_PATH_RE = /^\/groups\/([^/?#]+)\/?$/;
38
+ function normalizeGroupId(raw) {
39
+ const urlMatch = GROUP_URL_RE.exec(raw);
40
+ if (urlMatch?.[1]) return urlMatch[1];
41
+ const pathMatch = GROUP_PATH_RE.exec(raw);
42
+ if (pathMatch?.[1]) return pathMatch[1];
43
+ return raw;
44
+ }
36
45
  var JOB_URL_RE = /\/jobs\/view\/(\d+)/;
37
46
  function resolveJobIdentifier(raw) {
38
47
  const match = JOB_URL_RE.exec(raw);
@@ -43,5 +52,6 @@ function resolveJobIdentifier(raw) {
43
52
  export {
44
53
  resolveIdentifier,
45
54
  normalizeChatId,
55
+ normalizeGroupId,
46
56
  resolveJobIdentifier
47
57
  };
package/dist/cli.js CHANGED
@@ -299,23 +299,23 @@ var main = defineCommand({
299
299
  // ---------------------------------------------------------------------------
300
300
  // Noun groups, lazy-loaded on first invocation.
301
301
  // ---------------------------------------------------------------------------
302
- profile: () => import("./profile-TJS2YAZD.js").then((m) => m.profileCommand),
303
- company: () => import("./company-WDDLWP7E.js").then((m) => m.companyCommand),
304
- job: () => import("./job-75ML7R7I.js").then((m) => m.jobCommand),
305
- connect: () => import("./connect-5OROSY5C.js").then((m) => m.connectCommand),
306
- search: () => import("./search-TDSLK2MB.js").then((m) => m.searchCommand),
307
- inbox: () => import("./inbox-L6JBGZIB.js").then((m) => m.inboxCommand),
308
- inboxes: () => import("./inboxes-UIO74C5Q.js").then((m) => m.inboxesCommand),
309
- message: () => import("./message-DAQHRBSJ.js").then((m) => m.messageCommand),
310
- post: () => import("./post-RGDOCGC4.js").then((m) => m.postCommand),
311
- comment: () => import("./comment-MCGXFMN4.js").then((m) => m.commentCommand),
312
- account: () => import("./account-QRGWUQXF.js").then((m) => m.accountCommand),
302
+ profile: () => import("./profile-SUKHRWQP.js").then((m) => m.profileCommand),
303
+ company: () => import("./company-LHYDAO2C.js").then((m) => m.companyCommand),
304
+ job: () => import("./job-JQG34ATV.js").then((m) => m.jobCommand),
305
+ connect: () => import("./connect-5S4TFQAF.js").then((m) => m.connectCommand),
306
+ search: () => import("./search-MZQJDJTX.js").then((m) => m.searchCommand),
307
+ inbox: () => import("./inbox-3IQPPQMH.js").then((m) => m.inboxCommand),
308
+ inboxes: () => import("./inboxes-JK36F6SK.js").then((m) => m.inboxesCommand),
309
+ message: () => import("./message-2WIZESSM.js").then((m) => m.messageCommand),
310
+ post: () => import("./post-JRJMGV2I.js").then((m) => m.postCommand),
311
+ comment: () => import("./comment-TUXC7K72.js").then((m) => m.commentCommand),
312
+ account: () => import("./account-MIPWTAG5.js").then((m) => m.accountCommand),
313
313
  webhook: () => import("./webhook-7ESDSIRU.js").then((m) => m.webhookCommand),
314
- "sales-nav": () => import("./sales-nav-5O7FR57S.js").then((m) => m.salesNavCommand),
315
- recruiter: () => import("./recruiter-NSM33IEK.js").then((m) => m.recruiterCommand),
316
- group: () => import("./group-HSZY2IJU.js").then((m) => m.groupCommand),
317
- feed: () => import("./feed-SFVYEAYP.js").then((m) => m.feedCommand),
318
- notification: () => import("./notification-DYJN4ZHN.js").then((m) => m.notificationCommand)
314
+ "sales-nav": () => import("./sales-nav-4MFL2JSE.js").then((m) => m.salesNavCommand),
315
+ recruiter: () => import("./recruiter-NIKKDGMR.js").then((m) => m.recruiterCommand),
316
+ group: () => import("./group-PHGUOOJE.js").then((m) => m.groupCommand),
317
+ feed: () => import("./feed-ISNH4NXB.js").then((m) => m.feedCommand),
318
+ notification: () => import("./notification-ORSZY2IJ.js").then((m) => m.notificationCommand)
319
319
  },
320
320
  async run() {
321
321
  const { runMain } = await import("citty");
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveMemberOrMeProviderId
4
- } from "./chunk-QJZ3LWOX.js";
4
+ } from "./chunk-RJTG5YWE.js";
5
5
  import {
6
6
  AttachError,
7
7
  describeAttachment,
@@ -12,7 +12,10 @@ import {
12
12
  pageDelayFromFlags,
13
13
  streamAll
14
14
  } from "./chunk-H6XD3F66.js";
15
- import "./chunk-DMQZEPQE.js";
15
+ import "./chunk-UEAX6KUB.js";
16
+ import {
17
+ requireAccount
18
+ } from "./chunk-3BO6GVS2.js";
16
19
  import {
17
20
  buildPreviewOutput
18
21
  } from "./chunk-R3VLWLVV.js";
@@ -30,6 +33,7 @@ import {
30
33
  import {
31
34
  resolveTextOrStdin
32
35
  } from "./chunk-ZYURL5VK.js";
36
+ import "./chunk-PMRQXBCP.js";
33
37
 
34
38
  // src/commands/comment.ts
35
39
  import { defineCommand } from "citty";
@@ -40,13 +44,6 @@ function buildOutputStreams() {
40
44
  stderr: { write: (s) => process.stderr.write(s) }
41
45
  };
42
46
  }
43
- function requireAccount(account, out) {
44
- if (!account) {
45
- out.stderr.write("error: --account is required for this command. Set it via --account, CURVIATE_ACCOUNT, or `curviate config set-account`.\n");
46
- process.exit(2);
47
- }
48
- return account;
49
- }
50
47
  function rejectPreviewOnRead(preview, out) {
51
48
  if (preview) {
52
49
  out.stderr.write("error: --preview is only valid on write commands (mutations). Reads just run.\n");
@@ -92,7 +89,7 @@ function assertReaction(reaction, out) {
92
89
  }
93
90
  async function runCommentList(client, flags, out) {
94
91
  rejectPreviewOnRead(flags.preview, out);
95
- const accountId = requireAccount(flags.account, out);
92
+ const accountId = await requireAccount(client, flags, out);
96
93
  const postId = flags.postId ?? "";
97
94
  const ns = client.account(accountId);
98
95
  const outOpts = resolveOutputOpts(flags);
@@ -119,7 +116,7 @@ async function runCommentList(client, flags, out) {
119
116
  }
120
117
  async function runCommentReplies(client, flags, out) {
121
118
  rejectPreviewOnRead(flags.preview, out);
122
- const accountId = requireAccount(flags.account, out);
119
+ const accountId = await requireAccount(client, flags, out);
123
120
  const postId = flags.postId ?? "";
124
121
  const commentId = flags.commentId ?? "";
125
122
  const ns = client.account(accountId);
@@ -147,7 +144,7 @@ async function runCommentReplies(client, flags, out) {
147
144
  }
148
145
  async function runCommentReactions(client, flags, out) {
149
146
  rejectPreviewOnRead(flags.preview, out);
150
- const accountId = requireAccount(flags.account, out);
147
+ const accountId = await requireAccount(client, flags, out);
151
148
  const postId = flags.postId ?? "";
152
149
  const commentId = flags.commentId ?? "";
153
150
  const ns = client.account(accountId);
@@ -175,7 +172,7 @@ async function runCommentReactions(client, flags, out) {
175
172
  }
176
173
  async function runCommentUser(client, flags, out) {
177
174
  rejectPreviewOnRead(flags.preview, out);
178
- const accountId = requireAccount(flags.account, out);
175
+ const accountId = await requireAccount(client, flags, out);
179
176
  const ns = client.account(accountId);
180
177
  const outOpts = resolveOutputOpts(flags);
181
178
  let userId;
@@ -207,7 +204,7 @@ async function runCommentUser(client, flags, out) {
207
204
  }
208
205
  }
209
206
  async function runCommentAdd(client, flags, out, readStdin) {
210
- const accountId = requireAccount(flags.account, out);
207
+ const accountId = await requireAccount(client, flags, out);
211
208
  const postId = flags.postId ?? "";
212
209
  const attachPaths = normalizeAttachPaths(flags.attach);
213
210
  let attachBuffers = [];
@@ -248,7 +245,7 @@ async function runCommentAdd(client, flags, out, readStdin) {
248
245
  }
249
246
  }
250
247
  async function runCommentReply(client, flags, out, readStdin) {
251
- const accountId = requireAccount(flags.account, out);
248
+ const accountId = await requireAccount(client, flags, out);
252
249
  const postId = flags.postId ?? "";
253
250
  const commentId = flags.commentId ?? "";
254
251
  const attachPaths = normalizeAttachPaths(flags.attach);
@@ -290,7 +287,7 @@ async function runCommentReply(client, flags, out, readStdin) {
290
287
  }
291
288
  }
292
289
  async function runCommentEdit(client, flags, out, readStdin) {
293
- const accountId = requireAccount(flags.account, out);
290
+ const accountId = await requireAccount(client, flags, out);
294
291
  const postId = flags.postId ?? "";
295
292
  const commentId = flags.commentId ?? "";
296
293
  const text = await resolveTextOrStdin(flags.text ?? "", out, readStdin);
@@ -315,7 +312,7 @@ async function runCommentEdit(client, flags, out, readStdin) {
315
312
  }
316
313
  }
317
314
  async function runCommentDelete(client, flags, out) {
318
- const accountId = requireAccount(flags.account, out);
315
+ const accountId = await requireAccount(client, flags, out);
319
316
  const postId = flags.postId ?? "";
320
317
  const commentId = flags.commentId ?? "";
321
318
  if (flags.preview) {
@@ -338,7 +335,7 @@ async function runCommentDelete(client, flags, out) {
338
335
  }
339
336
  }
340
337
  async function runCommentReact(client, flags, out) {
341
- const accountId = requireAccount(flags.account, out);
338
+ const accountId = await requireAccount(client, flags, out);
342
339
  const postId = flags.postId ?? "";
343
340
  const commentId = flags.commentId ?? "";
344
341
  const reaction = flags.reaction ?? "";
@@ -364,7 +361,7 @@ async function runCommentReact(client, flags, out) {
364
361
  }
365
362
  }
366
363
  async function runCommentUnreact(client, flags, out) {
367
- const accountId = requireAccount(flags.account, out);
364
+ const accountId = await requireAccount(client, flags, out);
368
365
  const postId = flags.postId ?? "";
369
366
  const commentId = flags.commentId ?? "";
370
367
  const reaction = flags.reaction ?? "";