@usesocial/cli 0.3.0 → 0.3.2

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
@@ -1,5 +1,17 @@
1
1
  # @usesocial/cli
2
2
 
3
+ ## 0.3.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#12](https://github.com/usesocial/monorepo/pull/12) [`a85b525`](https://github.com/usesocial/monorepo/commit/a85b525d36908cf25da92a0538b77ac39eb817c6) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Read structured write payloads from stdin as JSON objects and remove `--body` from stdin-backed post, comment, and message commands. Plain stdin still becomes body text; valid non-object JSON now fails fast instead of being sent.
8
+
9
+ ## 0.3.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [#11](https://github.com/usesocial/monorepo/pull/11) [`60bc3e0`](https://github.com/usesocial/monorepo/commit/60bc3e003bf751a02c637e1a93a43f44353cd9a5) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Price LinkedIn connections as following and follower reads.
14
+
3
15
  ## 0.3.0
4
16
 
5
17
  ### Minor Changes
package/README.md CHANGED
@@ -74,8 +74,7 @@ connected account.
74
74
  ### Body text
75
75
 
76
76
  Commands that create a post, comment, message, or connection note read the body
77
- from **stdin** — there is no text argument. Pipe it in, or pass a raw `--body`
78
- JSON object:
77
+ from **stdin** — there is no text argument. Pipe it in:
79
78
 
80
79
  ```sh
81
80
  echo "gm" | social x post
@@ -83,8 +82,9 @@ social linkedin post < draft.md
83
82
  social linkedin requests send @handle < note.txt # optional connection note
84
83
  ```
85
84
 
86
- On an interactive terminal with nothing piped (and no `--body`), these commands
87
- fail fast rather than hang.
85
+ On an interactive terminal with nothing piped, required body-text commands fail
86
+ fast rather than hang. To send advanced payload fields, pipe a JSON object via
87
+ stdin; if stdin parses as JSON but is not an object, the command rejects it.
88
88
 
89
89
  ### Top level
90
90
 
@@ -292,6 +292,7 @@ social linkedin requests sent --limit 25 --offset 0
292
292
  social x bookmarks --limit 50
293
293
  social x followers --limit 100
294
294
  social x following profile_id:<x-user-id> --limit 100
295
+ social x replies post_id:<post-id> --limit 25
295
296
  social x messages --limit 50
296
297
 
297
298
  # Writes (body via stdin)
package/dist/index.d.mts CHANGED
@@ -1397,6 +1397,7 @@ declare const createSocialCommand: (deps?: {
1397
1397
  parseQueryString: (name: string, value: unknown) => string;
1398
1398
  parseBodyText: (name: string, value: unknown) => string;
1399
1399
  readStdin: () => Promise<string>;
1400
+ isStdinTTY: () => boolean;
1400
1401
  parseIntegerString: (name: string, value: unknown, options?: {
1401
1402
  min?: number;
1402
1403
  max?: number;
package/dist/index.mjs CHANGED
@@ -11367,10 +11367,18 @@ const { costBPSForCategory: costBPSForCategory$1 } = createPricing([
11367
11367
  "unitPriceUSD": .015,
11368
11368
  "featureId": "user_interaction_create_request"
11369
11369
  },
11370
+ {
11371
+ "key": "following_read",
11372
+ "label": "Following/Followers: Read",
11373
+ "description": "Read LinkedIn connections, priced to match X following and followers reads.",
11374
+ "unit": "per_resource",
11375
+ "unitPriceUSD": .01,
11376
+ "featureId": "following_followers_read_resource"
11377
+ },
11370
11378
  {
11371
11379
  "key": "owned_read",
11372
11380
  "label": "Owned: Read",
11373
- "description": "Read the connected LinkedIn account's own profile or first-party relation data.",
11381
+ "description": "Read the connected LinkedIn account's own profile.",
11374
11382
  "unit": "per_resource",
11375
11383
  "unitPriceUSD": .001,
11376
11384
  "featureId": "owned_read_resource"
@@ -12070,8 +12078,8 @@ const LINKEDIN_OPERATIONS = [
12070
12078
  totalCountPath: "total_count",
12071
12079
  itemsPath: "data"
12072
12080
  },
12073
- costBPS: 10,
12074
- billingCategory: "owned_read",
12081
+ costBPS: 100,
12082
+ billingCategory: "following_read",
12075
12083
  kind: "users"
12076
12084
  },
12077
12085
  parameters: [
@@ -12963,6 +12971,7 @@ const positionalDisplayKeyFor$1 = (op, param) => op.config.paramLabels?.[param.n
12963
12971
  const bodyTextDisplayKeyFor$1 = (op) => op.config.bodyTextArg === void 0 ? void 0 : op.config.paramLabels?.[op.config.bodyTextArg] ?? op.config.bodyTextArg;
12964
12972
  const hasStdinBodyText$1 = (op) => op.config.bodyTextArg !== void 0;
12965
12973
  const stdinBodyTextRequired$1 = (op) => hasStdinBodyText$1(op) && op.config.bodyTextRequired !== false;
12974
+ const hasBodyOption = (op) => op.hasBody && !hasStdinBodyText$1(op);
12966
12975
  const idempotencyFor$1 = (op) => {
12967
12976
  if (op.endpoint.capability === "read") return {
12968
12977
  safe: true,
@@ -13054,7 +13063,7 @@ const exampleCommandFor$1 = (op, commandName, root) => {
13054
13063
  parts.push(param.in === "path" || param.kind !== "array" ? hint : `${hint}...`);
13055
13064
  }
13056
13065
  if (hasStdinBodyText$1(op)) return `echo "..." | ${parts.join(" ")}`;
13057
- if (op.hasBody) parts.push("--body", "'{...}'");
13066
+ if (hasBodyOption(op)) parts.push("--body", "'{...}'");
13058
13067
  return parts.join(" ");
13059
13068
  };
13060
13069
  const operationModeFor$1 = (op) => {
@@ -13098,7 +13107,7 @@ const helpDescriptionFor$1 = (op, commandName, root) => {
13098
13107
  ...root ? [] : [op.config.group],
13099
13108
  commandName
13100
13109
  ].join(" ");
13101
- return `${description} | ${usage}${hasStdinBodyText$1(op) ? ` | body text is read from stdin: \`echo "..." | ${label}\` (or pass --body)` : ""}`;
13110
+ return `${description} | ${usage}${hasStdinBodyText$1(op) ? ` | body text is read from stdin: \`echo "..." | ${label}\`` : ""}`;
13102
13111
  };
13103
13112
  const commandPathFor = (op) => `linkedin ${op.config.root ? op.config.command : `${op.config.group} ${op.config.command}`}`;
13104
13113
  const contractInputSchemaName = (op) => op.hasBody ? `${op.schemaBaseName}ContractInput` : `${op.schemaBaseName}Input`;
@@ -13152,7 +13161,7 @@ const buildArgs$1 = (op) => {
13152
13161
  description: param.description
13153
13162
  };
13154
13163
  }
13155
- if (op.hasBody) args.body = {
13164
+ if (hasBodyOption(op)) args.body = {
13156
13165
  type: "string",
13157
13166
  description: "JSON request body"
13158
13167
  };
@@ -13244,7 +13253,7 @@ const buildBody = (deps, op, input) => {
13244
13253
  const bodyTextArg = op.config.bodyTextArg;
13245
13254
  const bodyParamEntries = Object.entries(op.config.bodyParams ?? {});
13246
13255
  if (!bodyTextArg && bodyParamEntries.length === 0) return input.body === void 0 ? void 0 : deps.parseJSONObject("--body", input.body);
13247
- const bodyFromJSON = input.body === void 0 ? void 0 : deps.parseJSONObject("--body", input.body);
13256
+ const bodyFromJSON = input.body === void 0 ? void 0 : deps.parseJSONObject(hasStdinBodyText$1(op) ? "stdin" : "--body", input.body);
13248
13257
  const bodyText = bodyTextArg && input[bodyTextArg] !== void 0 ? deps.parseBodyText(`<${bodyTextDisplayKeyFor$1(op) ?? bodyTextArg}>`, input[bodyTextArg]) : void 0;
13249
13258
  const bodyParamValues = /* @__PURE__ */ new Map();
13250
13259
  for (const [name, param] of bodyParamEntries) {
@@ -13258,7 +13267,7 @@ const buildBody = (deps, op, input) => {
13258
13267
  }
13259
13268
  if (bodyTextArg && bodyText !== void 0) body[bodyTextArg] = bodyText;
13260
13269
  if (op.config.bodyTextRequired !== false && (Boolean(bodyTextArg) || bodyParamEntries.some(([, param]) => param.required)) && bodyFromJSON === void 0) {
13261
- if ((bodyTextArg ? bodyText === void 0 : false) || bodyParamEntries.some(([name, param]) => param.required && bodyParamValues.get(name) === void 0)) throw new UsageError(bodyTextArg && bodyParamEntries.length === 0 ? `Pass <${bodyTextDisplayKeyFor$1(op) ?? bodyTextArg}> or --body.` : "Pass required body positional arguments or --body.");
13270
+ if ((bodyTextArg ? bodyText === void 0 : false) || bodyParamEntries.some(([name, param]) => param.required && bodyParamValues.get(name) === void 0)) throw new UsageError(bodyTextArg && bodyParamEntries.length === 0 ? `Pass <${bodyTextDisplayKeyFor$1(op) ?? bodyTextArg}>.` : "Pass required body positional arguments or --body.");
13262
13271
  }
13263
13272
  return body;
13264
13273
  };
@@ -13268,7 +13277,7 @@ const checkBodyRequired = (op, args) => {
13268
13277
  const bodyTextArg = op.config.bodyTextArg;
13269
13278
  if (bodyTextArg && op.config.bodyTextRequired !== false) expressions.push(args[bodyTextDisplayKeyFor$1(op) ?? bodyTextArg] === void 0);
13270
13279
  for (const [name, param] of Object.entries(op.config.bodyParams ?? {})) if (param.required) expressions.push(args[flagName(bodyParamArg(name, param))] === void 0);
13271
- if (expressions.length > 0 && typeof args.body !== "string" && expressions.some(Boolean)) throw new UsageError(op.config.bodyTextArg && Object.keys(op.config.bodyParams ?? {}).length === 0 ? `Pass <${bodyTextDisplayKeyFor$1(op) ?? op.config.bodyTextArg}> or --body.` : "Pass required body positional arguments or --body.");
13280
+ if (expressions.length > 0 && typeof args.body !== "string" && expressions.some(Boolean)) throw new UsageError(op.config.bodyTextArg && Object.keys(op.config.bodyParams ?? {}).length === 0 ? `Pass <${bodyTextDisplayKeyFor$1(op) ?? op.config.bodyTextArg}>.` : "Pass required body positional arguments or --body.");
13272
13281
  };
13273
13282
  const dataWithAuditableWriteTarget = (op, data, body) => {
13274
13283
  if (op.schemaBaseName !== "PostsReact") return data;
@@ -13281,18 +13290,27 @@ const dataWithAuditableWriteTarget = (op, data, body) => {
13281
13290
  };
13282
13291
  };
13283
13292
  const trimTrailingNewline$1 = (value) => value.endsWith("\r\n") ? value.slice(0, -2) : value.endsWith("\n") ? value.slice(0, -1) : value;
13284
- const noBodyTextError$1 = (commandLabel) => new UsageError(`No body text. Pipe it via stdin: \`echo "..." | ${commandLabel}\` (or pass --body '<json>').`);
13293
+ const noBodyTextError$1 = (commandLabel) => new UsageError(`No body text. Pipe it via stdin: \`echo "..." | ${commandLabel}\`.`);
13294
+ const parseStdinBody$1 = (deps, bodyTextName, bodyTextKey, value) => {
13295
+ try {
13296
+ JSON.parse(value);
13297
+ } catch {
13298
+ return { [bodyTextKey]: deps.parseBodyText(`<${bodyTextName}>`, value) };
13299
+ }
13300
+ return deps.parseJSONObject("stdin", value);
13301
+ };
13285
13302
  const resolveBodyTextFromStdin$1 = async (op, deps, args, commandLabel) => {
13286
13303
  if (!hasStdinBodyText$1(op)) return;
13287
- const bodyTextArg = bodyTextDisplayKeyFor$1(op) ?? op.config.bodyTextArg;
13304
+ const bodyTextArg = op.config.bodyTextArg;
13288
13305
  if (bodyTextArg === void 0) return;
13289
- const required = stdinBodyTextRequired$1(op) && typeof args.body !== "string";
13290
- if (process.stdin.isTTY) {
13306
+ const displayTextArg = bodyTextDisplayKeyFor$1(op) ?? bodyTextArg;
13307
+ const required = stdinBodyTextRequired$1(op);
13308
+ if (deps.isStdinTTY()) {
13291
13309
  if (required) throw noBodyTextError$1(commandLabel);
13292
13310
  return;
13293
13311
  }
13294
13312
  const piped = trimTrailingNewline$1(await deps.readStdin());
13295
- if (piped.length > 0) args[bodyTextArg] = piped;
13313
+ if (piped.length > 0) args.body = JSON.stringify(parseStdinBody$1(deps, displayTextArg, bodyTextArg, piped));
13296
13314
  else if (required) throw noBodyTextError$1(commandLabel);
13297
13315
  };
13298
13316
  const runOperation$1 = async (op, contract, deps, args, rawArgs = []) => {
@@ -13940,7 +13958,7 @@ const buildMessageEdit = (deps) => {
13940
13958
  const account = typeof args.account === "string" ? args.account : void 0;
13941
13959
  const message_id = messageIdFrom(deps, args.message_id ?? positionals[1]);
13942
13960
  let textInput;
13943
- if (process.stdin.isTTY) throw noBodyTextError$1("social linkedin message <target> edit message_id:<id>");
13961
+ if (deps.isStdinTTY()) throw noBodyTextError$1("social linkedin message <target> edit message_id:<id>");
13944
13962
  const piped = trimTrailingNewline$1(await deps.readStdin());
13945
13963
  if (piped.length > 0) textInput = piped;
13946
13964
  const text = textInput === void 0 ? void 0 : deps.parseBodyText("<text>", textInput);
@@ -13981,7 +13999,7 @@ const buildMessage$1 = (deps, sendCommand) => {
13981
13999
  return defineCommand({
13982
14000
  meta: commandMeta$2({
13983
14001
  name: "message",
13984
- description: "Send a LinkedIn message to a person or conversation [write] | usage: `social linkedin message <target> < body-text` | body text is read from stdin: `echo \"...\" | social linkedin message <target>` (or pass --body)",
14002
+ description: "Send a LinkedIn message to a person or conversation [write] | usage: `social linkedin message <target> < body-text` | body text is read from stdin: `echo \"...\" | social linkedin message <target>`",
13985
14003
  method: "POST",
13986
14004
  capability: "write",
13987
14005
  mutates: true,
@@ -13999,10 +14017,6 @@ const buildMessage$1 = (deps, sendCommand) => {
13999
14017
  description: "LinkedIn person or conversation target: @handle, profile URL, profile_id:<id>, chat_id:<id>, or a messaging thread URL",
14000
14018
  valueHint: "target"
14001
14019
  },
14002
- body: {
14003
- type: "string",
14004
- description: "JSON request body"
14005
- },
14006
14020
  account: {
14007
14021
  type: "string",
14008
14022
  description: "Account selector: @handle or profile_id:<id>; overrides config default"
@@ -14010,6 +14024,7 @@ const buildMessage$1 = (deps, sendCommand) => {
14010
14024
  },
14011
14025
  run: async ({ args }) => {
14012
14026
  const positionals = Array.isArray(args._) ? args._.map(String) : [];
14027
+ if (typeof args.body === "string") throw new UsageError("Unsupported option --body for linkedin message.");
14013
14028
  if (positionals[1] === "delete" || positionals[1] === "edit") {
14014
14029
  const verbCommand = positionals[1] === "delete" ? deleteCommand : editCommand;
14015
14030
  await verbCommand.run?.({
@@ -14025,23 +14040,13 @@ const buildMessage$1 = (deps, sendCommand) => {
14025
14040
  return;
14026
14041
  }
14027
14042
  const target = args.target ?? (Array.isArray(args._) && args._.length > 0 ? args._[0] : void 0);
14028
- const hasBody = typeof args.body === "string";
14029
- let textInput;
14030
- if (process.stdin.isTTY) {
14031
- if (!hasBody) throw noBodyTextError$1("social linkedin message <target>");
14032
- } else {
14033
- const piped = trimTrailingNewline$1(await deps.readStdin());
14034
- if (piped.length > 0) textInput = piped;
14035
- else if (!hasBody) throw noBodyTextError$1("social linkedin message <target>");
14036
- }
14043
+ let body;
14044
+ if (deps.isStdinTTY()) throw noBodyTextError$1("social linkedin message <target>");
14045
+ const piped = trimTrailingNewline$1(await deps.readStdin());
14046
+ if (piped.length > 0) body = parseStdinBody$1(deps, "text", "text", piped);
14047
+ else throw noBodyTextError$1("social linkedin message <target>");
14037
14048
  if (target === void 0) throw new UsageError("Pass a conversation or person target.");
14038
- const bodyFromJSON = typeof args.body === "string" ? deps.parseJSONObject("--body", args.body) : void 0;
14039
- const text = textInput === void 0 ? void 0 : deps.parseBodyText("<text>", textInput);
14040
- const body = text === void 0 ? bodyFromJSON : {
14041
- ...bodyFromJSON ?? {},
14042
- text
14043
- };
14044
- if (body === void 0 || typeof body.text !== "string") throw new UsageError("Pass <text> or --body.");
14049
+ if (body === void 0 || typeof body.text !== "string") throw new UsageError("Pass body text via stdin.");
14045
14050
  const account = typeof args.account === "string" ? args.account : void 0;
14046
14051
  const classified = await deps.classifyMessageTarget("target", target, {
14047
14052
  platform: "linkedin",
@@ -14286,6 +14291,7 @@ createLinkedinCommands({
14286
14291
  parseQueryString: unconfigured$1,
14287
14292
  parseBodyText: unconfigured$1,
14288
14293
  readStdin: unconfigured$1,
14294
+ isStdinTTY: unconfigured$1,
14289
14295
  parseIntegerString: unconfigured$1,
14290
14296
  parseEnumString: unconfigured$1,
14291
14297
  parseBooleanString: unconfigured$1,
@@ -17146,14 +17152,14 @@ const operationModeFor = (op) => {
17146
17152
  if (op.endpoint.method === "DELETE") return "destructive";
17147
17153
  return op.endpoint.mutates ? "write" : "read";
17148
17154
  };
17149
- const signaturePartFor = (op, name, arg) => {
17155
+ const signaturePartFor = (_op, name, arg) => {
17150
17156
  if (!isObjectRecord$1(arg)) return;
17151
17157
  if (arg.type === "positional") {
17152
17158
  const valueHint = typeof arg.valueHint === "string" ? arg.valueHint : name;
17153
17159
  return arg.required === true ? `<${valueHint}>` : `[${valueHint}]`;
17154
17160
  }
17155
17161
  if (name === "limit") return "--limit N";
17156
- if (name === "body" && !hasStdinBodyText(op)) return "--body JSON";
17162
+ if (name === "body") return "--body JSON";
17157
17163
  };
17158
17164
  const stdinSignaturePart = (op) => hasStdinBodyText(op) ? "< body-text" : void 0;
17159
17165
  const usageFor = (op, commandName, group) => {
@@ -17182,7 +17188,7 @@ const helpDescriptionFor = (op, commandName, group) => {
17182
17188
  group,
17183
17189
  commandName
17184
17190
  ].filter(Boolean).join(" ");
17185
- return `${description} | ${usage}${hasStdinBodyText(op) ? ` | body text is read from stdin: \`echo "..." | ${label}\` (or pass --body)` : ""}`;
17191
+ return `${description} | ${usage}${hasStdinBodyText(op) ? ` | body text is read from stdin: \`echo "..." | ${label}\`` : ""}`;
17186
17192
  };
17187
17193
  const contractFor$1 = (op, commandName, group) => {
17188
17194
  const mutates = op.endpoint.mutates;
@@ -17228,7 +17234,7 @@ const buildArgs = (op) => {
17228
17234
  description: param.description
17229
17235
  };
17230
17236
  }
17231
- if (op.hasBody) args.body = {
17237
+ if (op.hasBody && !hasStdinBodyText(op)) args.body = {
17232
17238
  type: "string",
17233
17239
  description: "JSON request body"
17234
17240
  };
@@ -17374,18 +17380,27 @@ const withEchoedTargetId = (op, data, body) => {
17374
17380
  };
17375
17381
  };
17376
17382
  const trimTrailingNewline = (value) => value.endsWith("\r\n") ? value.slice(0, -2) : value.endsWith("\n") ? value.slice(0, -1) : value;
17377
- const noBodyTextError = (commandLabel) => new UsageError(`No body text. Pipe it via stdin: \`echo "..." | ${commandLabel}\` (or pass --body '<json>').`);
17383
+ const noBodyTextError = (commandLabel) => new UsageError(`No body text. Pipe it via stdin: \`echo "..." | ${commandLabel}\`.`);
17384
+ const parseStdinBody = (deps, bodyTextName, bodyTextKey, value) => {
17385
+ try {
17386
+ JSON.parse(value);
17387
+ } catch {
17388
+ return { [bodyTextKey]: deps.parseBodyText(`<${bodyTextName}>`, value) };
17389
+ }
17390
+ return deps.parseJSONObject("stdin", value);
17391
+ };
17378
17392
  const resolveBodyTextFromStdin = async (op, deps, args, commandLabel) => {
17379
17393
  if (!hasStdinBodyText(op)) return;
17380
- const bodyTextArg = bodyTextDisplayKeyFor(op) ?? op.config.bodyTextArg;
17394
+ const bodyTextArg = op.config.bodyTextArg;
17381
17395
  if (bodyTextArg === void 0) return;
17382
- const required = stdinBodyTextRequired(op) && args.body === void 0;
17383
- if (process.stdin.isTTY) {
17396
+ const displayTextArg = bodyTextDisplayKeyFor(op) ?? bodyTextArg;
17397
+ const required = stdinBodyTextRequired(op);
17398
+ if (deps.isStdinTTY()) {
17384
17399
  if (required) throw noBodyTextError(commandLabel);
17385
17400
  return;
17386
17401
  }
17387
17402
  const piped = trimTrailingNewline(await deps.readStdin());
17388
- if (piped.length > 0) args[bodyTextArg] = piped;
17403
+ if (piped.length > 0) args.body = JSON.stringify(parseStdinBody(deps, displayTextArg, bodyTextArg, piped));
17389
17404
  else if (required) throw noBodyTextError(commandLabel);
17390
17405
  };
17391
17406
  const runOperation = async (op, contract, deps, args, rawArgs = []) => {
@@ -17474,7 +17489,7 @@ const runOperation = async (op, contract, deps, args, rawArgs = []) => {
17474
17489
  };
17475
17490
  let body;
17476
17491
  if (op.hasBody) {
17477
- const bodyFromJSON = input.body === void 0 ? void 0 : deps.parseJSONObject("--body", input.body);
17492
+ const bodyFromJSON = input.body === void 0 ? void 0 : deps.parseJSONObject(hasStdinBodyText(op) ? "stdin" : "--body", input.body);
17478
17493
  const textArg = op.config.bodyTextArg;
17479
17494
  if (textArg) {
17480
17495
  const displayTextArg = bodyTextDisplayKeyFor(op) ?? textArg;
@@ -17937,7 +17952,7 @@ const buildMessage = (deps) => {
17937
17952
  return defineCommand({
17938
17953
  meta: commandMeta$1({
17939
17954
  name: "message",
17940
- description: "Send a DM to a participant or conversation [write] | usage: `social x message <recipients> < body-text` | body text is read from stdin: `echo \"...\" | social x message <recipients>` (or pass --body)",
17955
+ description: "Send a DM to a participant or conversation [write] | usage: `social x message <recipients> < body-text` | body text is read from stdin: `echo \"...\" | social x message <recipients>`",
17941
17956
  method: "POST",
17942
17957
  capability: "write",
17943
17958
  mutates: true,
@@ -17951,36 +17966,23 @@ const buildMessage = (deps) => {
17951
17966
  description: "Recipient(s): chat URL, chat_id:<id>, @handle, profile URL, or profile_id:<id>; comma-separate profiles for a group",
17952
17967
  valueHint: "recipients"
17953
17968
  },
17954
- body: {
17955
- type: "string",
17956
- description: "JSON request body"
17957
- },
17958
17969
  account: {
17959
17970
  type: "string",
17960
17971
  description: "Account selector: @handle or profile_id:<id>; overrides config default"
17961
17972
  }
17962
17973
  },
17963
17974
  run: async ({ args }) => {
17975
+ if (typeof args.body === "string") throw new UsageError("Unsupported option --body for x message.");
17964
17976
  const recipientsInput = args.recipients ?? args.target ?? (Array.isArray(args._) && args._.length > 0 ? args._[0] : void 0);
17965
- const hasBody = typeof args.body === "string";
17966
- let textInput;
17967
- if (process.stdin.isTTY) {
17968
- if (!hasBody) throw noBodyTextError("social x message <recipients>");
17969
- } else {
17970
- const piped = trimTrailingNewline(await deps.readStdin());
17971
- if (piped.length > 0) textInput = piped;
17972
- else if (!hasBody) throw noBodyTextError("social x message <recipients>");
17973
- }
17977
+ let body;
17978
+ if (deps.isStdinTTY()) throw noBodyTextError("social x message <recipients>");
17979
+ const piped = trimTrailingNewline(await deps.readStdin());
17980
+ if (piped.length > 0) body = parseStdinBody(deps, "text", "text", piped);
17981
+ else throw noBodyTextError("social x message <recipients>");
17974
17982
  if (recipientsInput === void 0) throw new UsageError("Pass a conversation or user target.");
17975
17983
  const recipients = String(recipientsInput).split(",").map((recipient) => recipient.trim()).filter((recipient) => recipient.length > 0);
17976
17984
  if (recipients.length === 0) throw new UsageError("Pass at least one recipient.");
17977
- const bodyFromJSON = typeof args.body === "string" ? deps.parseJSONObject("--body", args.body) : void 0;
17978
- const text = textInput === void 0 ? void 0 : deps.parseBodyText("--text", textInput);
17979
- const body = text === void 0 ? bodyFromJSON : {
17980
- ...bodyFromJSON ?? {},
17981
- text
17982
- };
17983
- if (body === void 0) throw new UsageError("Pass <text> or --body.");
17985
+ if (body === void 0) throw noBodyTextError("social x message <recipients>");
17984
17986
  const resolved = [];
17985
17987
  const account = typeof args.account === "string" ? args.account : void 0;
17986
17988
  const selectedAccount = await deps.resolveAccount({
@@ -18009,12 +18011,13 @@ const buildMessage = (deps) => {
18009
18011
  })));
18010
18012
  for (const resolution of participantResolutions) resolved.push(resolution.record);
18011
18013
  const participant_ids = participantResolutions.map((resolution) => resolution.id);
18014
+ const { text, ...bodyFields } = body;
18012
18015
  requestPath = "x/dm_conversations";
18013
18016
  requestBody = {
18014
18017
  conversation_type: "Group",
18015
- ...bodyFromJSON ?? {},
18016
18018
  participant_ids,
18017
- ...text === void 0 ? {} : { message: { text } }
18019
+ ...bodyFields,
18020
+ ...typeof text === "string" ? { message: { text } } : {}
18018
18021
  };
18019
18022
  }
18020
18023
  const response = await deps.api.post(requestPath, {
@@ -18194,6 +18197,7 @@ createXCommands({
18194
18197
  parseQueryString: unconfigured,
18195
18198
  parseBodyText: unconfigured,
18196
18199
  readStdin: unconfigured,
18200
+ isStdinTTY: unconfigured,
18197
18201
  parseIntegerString: unconfigured,
18198
18202
  parseEnumString: unconfigured,
18199
18203
  parseBooleanString: unconfigured,
@@ -21054,7 +21058,7 @@ const createInstance = (defaults) => {
21054
21058
  const ky = createInstance();
21055
21059
  //#endregion
21056
21060
  //#region package.json
21057
- var version$1 = "0.3.0";
21061
+ var version$1 = "0.3.2";
21058
21062
  //#endregion
21059
21063
  //#region src/lib/env.ts
21060
21064
  const URLWithTrailingSlash = url().transform(ensureTrailingSlash);
@@ -28508,6 +28512,7 @@ const createCLIDeps = () => {
28508
28512
  parseQueryString,
28509
28513
  parseBodyText,
28510
28514
  readStdin,
28515
+ isStdinTTY: () => process.stdin.isTTY === true,
28511
28516
  parseIntegerString,
28512
28517
  parseEnumString,
28513
28518
  parseBooleanString,
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "access": "public"
12
12
  },
13
13
  "private": false,
14
- "version": "0.3.0",
14
+ "version": "0.3.2",
15
15
  "type": "module",
16
16
  "engines": {
17
17
  "node": ">=22.5.0"