@usesocial/cli 0.2.6 → 0.3.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/dist/index.mjs CHANGED
@@ -130,13 +130,13 @@ var CancelledError = class extends Error {
130
130
  }
131
131
  };
132
132
  //#endregion
133
- //#region ../../packages/local-sqlite/src/migrations.generated.ts
133
+ //#region ../../packages/sync-engine/src/migrations.generated.ts
134
134
  const MIGRATIONS = [{
135
135
  "tag": "0000_modern_stephen_strange",
136
136
  "sql": "CREATE TABLE `li_connections` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `object` text,\n `url` text,\n `user_id` text,\n `user_object` text,\n `user_type` text,\n `user_display_name` text,\n `user_public_identifier` text,\n `user_profile_url` text,\n `user_public_picture_url` text,\n `user_description` text,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `li_connections_created_at_idx` ON `li_connections` (`created_at`);--> statement-breakpoint\nCREATE TABLE `li_conversations` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `last_message_timestamp` integer,\n `muted_until` integer,\n `creator_id` text,\n `headline` text,\n `image_url` text,\n `name` text,\n `object` text,\n `provider` text,\n `type` text,\n `user_id` text,\n `is_1to1` integer,\n `is_archived` integer,\n `is_channel` integer,\n `is_group` integer,\n `is_pinned` integer,\n `is_readonly` integer,\n `unread_count` integer,\n `user_object` text,\n `user_type` text,\n `user_display_name` text,\n `user_public_identifier` text,\n `user_profile_url` text,\n `user_public_picture_url` text,\n `user_description` text,\n `user_specifics_network_distance` text,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `li_conversations_created_at_idx` ON `li_conversations` (`created_at`);--> statement-breakpoint\nCREATE INDEX `li_conversations_last_message_timestamp_idx` ON `li_conversations` (`last_message_timestamp`);--> statement-breakpoint\nCREATE TABLE `li_messages` (\n `id` text PRIMARY KEY NOT NULL,\n `timestamp` integer,\n `chat_id` text,\n `object` text,\n `provider` text,\n `text` text,\n `sender_id` text,\n `is_deleted` integer,\n `is_delivered` integer,\n `is_edited` integer,\n `is_event` integer,\n `is_hidden` integer,\n `is_mentionned` integer,\n `is_pinned` integer,\n `is_seen` integer,\n `is_sender` integer,\n `sender_object` text,\n `sender_type` text,\n `sender_display_name` text,\n `sender_public_identifier` text,\n `sender_profile_url` text,\n `sender_public_picture_url` text,\n `sender_description` text,\n `sender_specifics_network_distance` text,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `li_messages_timestamp_idx` ON `li_messages` (`timestamp`);--> statement-breakpoint\nCREATE INDEX `li_messages_chat_id_idx` ON `li_messages` (`chat_id`);--> statement-breakpoint\nCREATE TABLE `li_posts` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `object` text,\n `share_url` text,\n `text` text,\n `url` text,\n `is_repost` integer,\n `user_reacted` text,\n `comments_counter` integer,\n `reposts_counter` integer,\n `analytics_impressions_counter` integer,\n `author_id` text,\n `author_object` text,\n `author_type` text,\n `author_display_name` text,\n `author_public_identifier` text,\n `author_profile_url` text,\n `author_public_picture_url` text,\n `author_description` text,\n `author_specifics_network_distance` text,\n `permissions_can_post_comments` integer,\n `permissions_can_react` integer,\n `permissions_can_share` integer,\n `poll_id` text,\n `poll_question` text,\n `poll_is_open` integer,\n `poll_total_votes_count` integer,\n `quoted_post_id` text,\n `quoted_post_object` text,\n `quoted_post_created_at` integer,\n `quoted_post_text` text,\n `quoted_post_share_url` text,\n `quoted_post_user_reacted` text,\n `quoted_post_comments_counter` integer,\n `quoted_post_reposts_counter` integer,\n `quoted_post_permissions_can_post_comments` integer,\n `quoted_post_permissions_can_react` integer,\n `quoted_post_permissions_can_share` integer,\n `quoted_post_author_id` text,\n `quoted_post_author_object` text,\n `quoted_post_author_type` text,\n `quoted_post_author_display_name` text,\n `quoted_post_author_public_identifier` text,\n `quoted_post_author_profile_url` text,\n `quoted_post_author_public_picture_url` text,\n `quoted_post_author_description` text,\n `quoted_post_author_specifics_network_distance` text,\n `reposted_by_id` text,\n `reposted_by_object` text,\n `reposted_by_type` text,\n `reposted_by_display_name` text,\n `reposted_by_public_identifier` text,\n `reposted_by_profile_url` text,\n `reposted_by_public_picture_url` text,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `li_posts_created_at_idx` ON `li_posts` (`created_at`);--> statement-breakpoint\nCREATE TABLE `li_requests` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `object` text,\n `type` text,\n `user_id` text,\n `user_object` text,\n `user_type` text,\n `user_display_name` text,\n `user_public_identifier` text,\n `user_profile_url` text,\n `user_public_picture_url` text,\n `user_description` text,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `li_requests_created_at_idx` ON `li_requests` (`created_at`);--> statement-breakpoint\nCREATE TABLE `sync_state` (\n `collection` text PRIMARY KEY NOT NULL,\n `cursor` text,\n `last_synced` integer,\n `object_count` integer\n);\n--> statement-breakpoint\nCREATE TABLE `x_bookmarks` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `author_id` text,\n `conversation_id` text,\n `in_reply_to_user_id` text,\n `lang` text,\n `reply_settings` text,\n `text` text,\n `url` text,\n `paid_partnership` integer,\n `possibly_sensitive` integer,\n `edit_controls_editable_until` integer,\n `edit_controls_edits_remaining` integer,\n `edit_controls_is_edit_eligible` integer,\n `like_count` integer,\n `retweet_count` integer,\n `reply_count` integer,\n `quote_count` integer,\n `bookmark_count` integer,\n `impression_count` integer,\n `article_cover_media` text,\n `article_plain_text` text,\n `article_preview_text` text,\n `article_title` text,\n `note_tweet_text` text,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `x_bookmarks_created_at_idx` ON `x_bookmarks` (`created_at`);--> statement-breakpoint\nCREATE TABLE `x_followers` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `username` text,\n `name` text,\n `description` text,\n `location` text,\n `url` text,\n `is_identity_verified` integer,\n `protected` integer,\n `verified` integer,\n `verified_type` text,\n `subscription_type` text,\n `parody` integer,\n `most_recent_tweet_id` text,\n `pinned_tweet_id` text,\n `profile_banner_url` text,\n `profile_image_url` text,\n `affiliation_badge_url` text,\n `affiliation_description` text,\n `affiliation_url` text,\n `subscription_subscribes_to_you` integer,\n `followers_count` integer,\n `following_count` integer,\n `tweet_count` integer,\n `listed_count` integer,\n `like_count` integer,\n `media_count` integer,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `x_followers_created_at_idx` ON `x_followers` (`created_at`);--> statement-breakpoint\nCREATE TABLE `x_following` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `username` text,\n `name` text,\n `description` text,\n `location` text,\n `url` text,\n `is_identity_verified` integer,\n `protected` integer,\n `verified` integer,\n `verified_type` text,\n `subscription_type` text,\n `parody` integer,\n `most_recent_tweet_id` text,\n `pinned_tweet_id` text,\n `profile_banner_url` text,\n `profile_image_url` text,\n `affiliation_badge_url` text,\n `affiliation_description` text,\n `affiliation_url` text,\n `subscription_subscribes_to_you` integer,\n `followers_count` integer,\n `following_count` integer,\n `tweet_count` integer,\n `listed_count` integer,\n `like_count` integer,\n `media_count` integer,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `x_following_created_at_idx` ON `x_following` (`created_at`);--> statement-breakpoint\nCREATE TABLE `x_tweets` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `author_id` text,\n `conversation_id` text,\n `in_reply_to_user_id` text,\n `lang` text,\n `reply_settings` text,\n `text` text,\n `url` text,\n `paid_partnership` integer,\n `possibly_sensitive` integer,\n `edit_controls_editable_until` integer,\n `edit_controls_edits_remaining` integer,\n `edit_controls_is_edit_eligible` integer,\n `like_count` integer,\n `retweet_count` integer,\n `reply_count` integer,\n `quote_count` integer,\n `bookmark_count` integer,\n `impression_count` integer,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `x_tweets_created_at_idx` ON `x_tweets` (`created_at`);"
137
137
  }];
138
138
  //#endregion
139
- //#region ../../packages/local-sqlite/src/migrate.ts
139
+ //#region ../../packages/sync-engine/src/migrate.ts
140
140
  const readUserVersion = (db) => {
141
141
  const version = db.prepare("PRAGMA user_version").get()?.user_version;
142
142
  return typeof version === "number" ? version : Number(version ?? 0);
@@ -161,7 +161,7 @@ const assertAtLatest = (db) => {
161
161
  if (currentVersion < MIGRATIONS.length) throw new Error(`Local SQLite cache schema is at version ${currentVersion}; expected ${MIGRATIONS.length}`);
162
162
  };
163
163
  //#endregion
164
- //#region ../../packages/local-sqlite/src/sqlite.ts
164
+ //#region ../../packages/sync-engine/src/sqlite.ts
165
165
  const loadModule = createRequire(import.meta.url);
166
166
  const isBunRuntime = () => typeof Bun !== "undefined";
167
167
  const normalizeValue = (value) => {
@@ -219,7 +219,7 @@ const openDatabase = (path, opts) => {
219
219
  };
220
220
  };
221
221
  //#endregion
222
- //#region ../../packages/local-sqlite/src/cache.ts
222
+ //#region ../../packages/sync-engine/src/cache.ts
223
223
  const cacheTables = new Set([
224
224
  "x_tweets",
225
225
  "x_followers",
@@ -307,8 +307,8 @@ const createCache = (path, db) => ({
307
307
  }
308
308
  });
309
309
  //#endregion
310
- //#region ../../packages/local-sqlite/src/collections/linkedin.ts
311
- const linkedinPagination = {
310
+ //#region ../../packages/sync-engine/src/collections/linkedin.ts
311
+ const linkedinCursorPagination = {
312
312
  style: "cursor",
313
313
  limitParam: "limit",
314
314
  cursorParam: "cursor",
@@ -316,6 +316,13 @@ const linkedinPagination = {
316
316
  totalCountPath: "total_count",
317
317
  itemsPath: "data"
318
318
  };
319
+ const linkedinOffsetPagination = {
320
+ style: "offset",
321
+ limitParam: "limit",
322
+ offsetParam: "offset",
323
+ totalCountPath: "total_count",
324
+ itemsPath: "data"
325
+ };
319
326
  const asRecord$1 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
320
327
  const read$1 = (value) => value === null || value === void 0 ? null : value;
321
328
  const readReaction = (value) => typeof value === "string" ? value : null;
@@ -504,7 +511,7 @@ const LINKEDIN_COLLECTIONS = [
504
511
  key: "li_conversations",
505
512
  platform: "linkedin",
506
513
  requests: [{ path: "/chats" }],
507
- pagination: linkedinPagination,
514
+ pagination: linkedinCursorPagination,
508
515
  pageSize: 20,
509
516
  estCostBPS: 100,
510
517
  estUnitsPerPage: 10,
@@ -517,7 +524,7 @@ const LINKEDIN_COLLECTIONS = [
517
524
  requests: [{ path: "/chats/:chat_id/messages" }],
518
525
  parentCollection: "li_conversations",
519
526
  parentIdToken: ":chat_id",
520
- pagination: linkedinPagination,
527
+ pagination: linkedinCursorPagination,
521
528
  pageSize: 250,
522
529
  estCostBPS: 100,
523
530
  estUnitsPerPage: 5,
@@ -528,7 +535,7 @@ const LINKEDIN_COLLECTIONS = [
528
535
  key: "li_connections",
529
536
  platform: "linkedin",
530
537
  requests: [{ path: "/users/connections" }],
531
- pagination: linkedinPagination,
538
+ pagination: linkedinCursorPagination,
532
539
  pageSize: 100,
533
540
  estCostBPS: 10,
534
541
  estUnitsPerPage: 100,
@@ -540,7 +547,7 @@ const LINKEDIN_COLLECTIONS = [
540
547
  platform: "linkedin",
541
548
  requests: [{ path: "/users/:identifier/posts" }],
542
549
  ownIdToken: ":identifier",
543
- pagination: linkedinPagination,
550
+ pagination: linkedinCursorPagination,
544
551
  pageSize: 50,
545
552
  estCostBPS: 50,
546
553
  estUnitsPerPage: 50,
@@ -557,7 +564,7 @@ const LINKEDIN_COLLECTIONS = [
557
564
  path: "/users/me/relation-requests/sent",
558
565
  bakedQuery: { type: "sent" }
559
566
  }],
560
- pagination: linkedinPagination,
567
+ pagination: linkedinOffsetPagination,
561
568
  pageSize: 100,
562
569
  estCostBPS: 100,
563
570
  estUnitsPerPage: 100,
@@ -565,7 +572,7 @@ const LINKEDIN_COLLECTIONS = [
565
572
  }
566
573
  ];
567
574
  //#endregion
568
- //#region ../../packages/local-sqlite/src/collections/x.ts
575
+ //#region ../../packages/sync-engine/src/collections/x.ts
569
576
  const xPagination = {
570
577
  style: "cursor",
571
578
  limitParam: "max_results",
@@ -664,7 +671,7 @@ const liftXUser = (item) => {
664
671
  };
665
672
  };
666
673
  //#endregion
667
- //#region ../../packages/local-sqlite/src/collections/index.ts
674
+ //#region ../../packages/sync-engine/src/collections/index.ts
668
675
  const COLLECTIONS = [...[
669
676
  {
670
677
  key: "x_tweets",
@@ -9753,7 +9760,7 @@ const createPricing = (resources) => {
9753
9760
  };
9754
9761
  };
9755
9762
  //#endregion
9756
- //#region ../../packages/local-sqlite/src/cost.ts
9763
+ //#region ../../packages/sync-engine/src/cost.ts
9757
9764
  const creditsToUSD = (credits) => credits / 1e3;
9758
9765
  const usdToCredits = (usd) => Math.round(usd * 1e3);
9759
9766
  const estimatePageCredits = (estCostBPS, estUnitsPerPage) => creditsForBPS(billedBPSFor(estCostBPS * estUnitsPerPage));
@@ -10352,7 +10359,7 @@ function index(name) {
10352
10359
  return new IndexBuilderOn(name, false);
10353
10360
  }
10354
10361
  //#endregion
10355
- //#region ../../packages/local-sqlite/src/schema.ts
10362
+ //#region ../../packages/sync-engine/src/schema.ts
10356
10363
  const idColumn = () => text("id").primaryKey();
10357
10364
  const rawColumns = () => ({
10358
10365
  raw: text("raw").notNull(),
@@ -10592,7 +10599,7 @@ sqliteTable("sync_state", {
10592
10599
  objectCount: integer("object_count")
10593
10600
  });
10594
10601
  //#endregion
10595
- //#region ../../packages/local-sqlite/src/since.ts
10602
+ //#region ../../packages/sync-engine/src/since.ts
10596
10603
  const durationPattern = /^(\d+):(hours|days|weeks)$/;
10597
10604
  const isoPattern = /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}Z)?$/;
10598
10605
  const unitMs = {
@@ -10645,10 +10652,11 @@ const substitutePath = (path, args) => {
10645
10652
  if (args.parentIdToken && args.chatId !== void 0) resolved = resolved.replaceAll(args.parentIdToken, args.chatId);
10646
10653
  return resolved;
10647
10654
  };
10648
- const buildQuery = (pagination, pageSize, cursor, bakedQuery) => {
10655
+ const buildQuery = (pagination, pageSize, cursor, offset, bakedQuery) => {
10649
10656
  const params = new URLSearchParams();
10650
10657
  if (pagination.style !== "none" && pagination.limitParam) params.set(pagination.limitParam, String(pageSize));
10651
10658
  if (pagination.style !== "none" && cursor && pagination.cursorParam) params.set(pagination.cursorParam, cursor);
10659
+ if (pagination.style === "offset" && pagination.offsetParam) params.set(pagination.offsetParam, String(offset));
10652
10660
  for (const [key, value] of Object.entries(bakedQuery ?? {})) params.set(key, value);
10653
10661
  const query = params.toString();
10654
10662
  return query ? `?${query}` : "";
@@ -10690,6 +10698,7 @@ const walkRequest = async (args) => {
10690
10698
  const checkpoint = args.useCheckpoint ? args.deps.cache.getCursor(args.collection.key)?.cursor ?? null : null;
10691
10699
  const ids = [];
10692
10700
  let cursor = null;
10701
+ let offset = 0;
10693
10702
  let newestId = null;
10694
10703
  let lastPageCredits = null;
10695
10704
  let pages = 0;
@@ -10707,7 +10716,7 @@ const walkRequest = async (args) => {
10707
10716
  ownIdToken: args.collection.ownIdToken,
10708
10717
  chatId: args.parentId,
10709
10718
  parentIdToken: args.parentIdToken
10710
- }) + buildQuery(args.collection.pagination, args.collection.pageSize, cursor, args.request.bakedQuery);
10719
+ }) + buildQuery(args.collection.pagination, args.collection.pageSize, cursor, offset, args.request.bakedQuery);
10711
10720
  const response = await args.deps.api.get(path, { headers: args.deps.accountHeaders });
10712
10721
  const credits = creditsFromHeader(response.headers);
10713
10722
  args.tracker.add(credits);
@@ -10744,6 +10753,15 @@ const walkRequest = async (args) => {
10744
10753
  args.deps.cache.upsert(args.collection.key, rows);
10745
10754
  upserted += rows.length;
10746
10755
  if (hitStop) break;
10756
+ if (args.collection.pagination.style === "offset") {
10757
+ const nextOffset = offset + args.collection.pageSize;
10758
+ if (page.items.length === 0 || page.totalCount != null && nextOffset >= page.totalCount || page.totalCount == null && page.items.length < args.collection.pageSize) {
10759
+ stoppedReason = "complete";
10760
+ break;
10761
+ }
10762
+ offset = nextOffset;
10763
+ continue;
10764
+ }
10747
10765
  cursor = page.cursor;
10748
10766
  if (!cursor) {
10749
10767
  stoppedReason = "complete";
@@ -11442,7 +11460,6 @@ const LINKEDIN_OPERATIONS = [
11442
11460
  style: "cursor",
11443
11461
  limitParam: "limit",
11444
11462
  cursorParam: "cursor",
11445
- offsetParam: "offset",
11446
11463
  cursorPath: "next_cursor",
11447
11464
  totalCountPath: "total_count",
11448
11465
  itemsPath: "data"
@@ -11557,10 +11574,9 @@ const LINKEDIN_OPERATIONS = [
11557
11574
  capability: "read",
11558
11575
  mutates: false,
11559
11576
  pagination: {
11560
- style: "cursor",
11577
+ style: "offset",
11561
11578
  limitParam: "limit",
11562
11579
  offsetParam: "offset",
11563
- cursorPath: "next_cursor",
11564
11580
  totalCountPath: "total_count",
11565
11581
  itemsPath: "data"
11566
11582
  },
@@ -11612,11 +11628,9 @@ const LINKEDIN_OPERATIONS = [
11612
11628
  capability: "read",
11613
11629
  mutates: false,
11614
11630
  pagination: {
11615
- style: "cursor",
11631
+ style: "offset",
11616
11632
  limitParam: "limit",
11617
- cursorParam: "cursor",
11618
11633
  offsetParam: "offset",
11619
- cursorPath: "next_cursor",
11620
11634
  totalCountPath: "total_count",
11621
11635
  itemsPath: "data"
11622
11636
  },
@@ -11630,7 +11644,7 @@ const LINKEDIN_OPERATIONS = [
11630
11644
  in: "query",
11631
11645
  required: false,
11632
11646
  kind: "integer",
11633
- description: "An offset used for pagination, if supported by the provider, else use cursor."
11647
+ description: "Pagination offset"
11634
11648
  },
11635
11649
  {
11636
11650
  name: "limit",
@@ -11639,13 +11653,6 @@ const LINKEDIN_OPERATIONS = [
11639
11653
  kind: "integer",
11640
11654
  description: "Rows to return (1-100)"
11641
11655
  },
11642
- {
11643
- name: "cursor",
11644
- in: "query",
11645
- required: false,
11646
- kind: "string",
11647
- description: "Pagination cursor"
11648
- },
11649
11656
  {
11650
11657
  name: "sort_by",
11651
11658
  in: "query",
@@ -11683,11 +11690,9 @@ const LINKEDIN_OPERATIONS = [
11683
11690
  capability: "read",
11684
11691
  mutates: false,
11685
11692
  pagination: {
11686
- style: "cursor",
11693
+ style: "offset",
11687
11694
  limitParam: "limit",
11688
- cursorParam: "cursor",
11689
11695
  offsetParam: "offset",
11690
- cursorPath: "next_cursor",
11691
11696
  totalCountPath: "total_count",
11692
11697
  itemsPath: "data"
11693
11698
  },
@@ -11701,7 +11706,7 @@ const LINKEDIN_OPERATIONS = [
11701
11706
  in: "query",
11702
11707
  required: false,
11703
11708
  kind: "integer",
11704
- description: "An offset used for pagination, if supported by the provider, else use cursor."
11709
+ description: "Pagination offset"
11705
11710
  },
11706
11711
  {
11707
11712
  name: "limit",
@@ -11710,13 +11715,6 @@ const LINKEDIN_OPERATIONS = [
11710
11715
  kind: "integer",
11711
11716
  description: "Rows to return (1-100)"
11712
11717
  },
11713
- {
11714
- name: "cursor",
11715
- in: "query",
11716
- required: false,
11717
- kind: "string",
11718
- description: "Pagination cursor"
11719
- },
11720
11718
  {
11721
11719
  name: "post_id",
11722
11720
  in: "path",
@@ -11746,10 +11744,9 @@ const LINKEDIN_OPERATIONS = [
11746
11744
  capability: "read",
11747
11745
  mutates: false,
11748
11746
  pagination: {
11749
- style: "cursor",
11747
+ style: "offset",
11750
11748
  limitParam: "limit",
11751
11749
  offsetParam: "offset",
11752
- cursorPath: "next_cursor",
11753
11750
  totalCountPath: "total_count",
11754
11751
  itemsPath: "data"
11755
11752
  },
@@ -11800,10 +11797,9 @@ const LINKEDIN_OPERATIONS = [
11800
11797
  capability: "read",
11801
11798
  mutates: false,
11802
11799
  pagination: {
11803
- style: "cursor",
11800
+ style: "offset",
11804
11801
  limitParam: "limit",
11805
11802
  offsetParam: "offset",
11806
- cursorPath: "next_cursor",
11807
11803
  totalCountPath: "total_count",
11808
11804
  itemsPath: "data"
11809
11805
  },
@@ -11854,10 +11850,9 @@ const LINKEDIN_OPERATIONS = [
11854
11850
  capability: "read",
11855
11851
  mutates: false,
11856
11852
  pagination: {
11857
- style: "cursor",
11853
+ style: "offset",
11858
11854
  limitParam: "limit",
11859
11855
  offsetParam: "offset",
11860
- cursorPath: "next_cursor",
11861
11856
  totalCountPath: "total_count",
11862
11857
  itemsPath: "data"
11863
11858
  },
@@ -11908,10 +11903,9 @@ const LINKEDIN_OPERATIONS = [
11908
11903
  capability: "read",
11909
11904
  mutates: false,
11910
11905
  pagination: {
11911
- style: "cursor",
11906
+ style: "offset",
11912
11907
  limitParam: "limit",
11913
11908
  offsetParam: "offset",
11914
- cursorPath: "next_cursor",
11915
11909
  totalCountPath: "total_count",
11916
11910
  itemsPath: "data"
11917
11911
  },
@@ -12013,11 +12007,9 @@ const LINKEDIN_OPERATIONS = [
12013
12007
  capability: "read",
12014
12008
  mutates: false,
12015
12009
  pagination: {
12016
- style: "cursor",
12010
+ style: "offset",
12017
12011
  limitParam: "limit",
12018
- cursorParam: "cursor",
12019
12012
  offsetParam: "offset",
12020
- cursorPath: "next_cursor",
12021
12013
  totalCountPath: "total_count",
12022
12014
  itemsPath: "data"
12023
12015
  },
@@ -12031,7 +12023,7 @@ const LINKEDIN_OPERATIONS = [
12031
12023
  in: "query",
12032
12024
  required: false,
12033
12025
  kind: "integer",
12034
- description: "An offset used for pagination, if supported by the provider, else use cursor."
12026
+ description: "Pagination offset"
12035
12027
  },
12036
12028
  {
12037
12029
  name: "limit",
@@ -12040,13 +12032,6 @@ const LINKEDIN_OPERATIONS = [
12040
12032
  kind: "integer",
12041
12033
  description: "The limit of items to be returned."
12042
12034
  },
12043
- {
12044
- name: "cursor",
12045
- in: "query",
12046
- required: false,
12047
- kind: "string",
12048
- description: "A cursor used for pagination. If supported by the provider, use next_cursor given by the previous page of the list, else use offset."
12049
- },
12050
12035
  {
12051
12036
  name: "identifier",
12052
12037
  in: "path",
@@ -12079,11 +12064,9 @@ const LINKEDIN_OPERATIONS = [
12079
12064
  capability: "read",
12080
12065
  mutates: false,
12081
12066
  pagination: {
12082
- style: "cursor",
12067
+ style: "offset",
12083
12068
  limitParam: "limit",
12084
- cursorParam: "cursor",
12085
12069
  offsetParam: "offset",
12086
- cursorPath: "next_cursor",
12087
12070
  totalCountPath: "total_count",
12088
12071
  itemsPath: "data"
12089
12072
  },
@@ -12097,7 +12080,7 @@ const LINKEDIN_OPERATIONS = [
12097
12080
  in: "query",
12098
12081
  required: false,
12099
12082
  kind: "integer",
12100
- description: "An offset used for pagination, if supported by the provider, else use cursor."
12083
+ description: "Pagination offset"
12101
12084
  },
12102
12085
  {
12103
12086
  name: "limit",
@@ -12106,13 +12089,6 @@ const LINKEDIN_OPERATIONS = [
12106
12089
  kind: "integer",
12107
12090
  description: "Rows to return (1-1000)"
12108
12091
  },
12109
- {
12110
- name: "cursor",
12111
- in: "query",
12112
- required: false,
12113
- kind: "string",
12114
- description: "Pagination cursor"
12115
- },
12116
12092
  {
12117
12093
  name: "user_id",
12118
12094
  in: "query",
@@ -12147,11 +12123,9 @@ const LINKEDIN_OPERATIONS = [
12147
12123
  capability: "read",
12148
12124
  mutates: false,
12149
12125
  pagination: {
12150
- style: "cursor",
12126
+ style: "offset",
12151
12127
  limitParam: "limit",
12152
- cursorParam: "cursor",
12153
12128
  offsetParam: "offset",
12154
- cursorPath: "next_cursor",
12155
12129
  totalCountPath: "total_count",
12156
12130
  itemsPath: "data"
12157
12131
  },
@@ -12159,29 +12133,19 @@ const LINKEDIN_OPERATIONS = [
12159
12133
  billingCategory: "user_read",
12160
12134
  kind: "users"
12161
12135
  },
12162
- parameters: [
12163
- {
12164
- name: "offset",
12165
- in: "query",
12166
- required: false,
12167
- kind: "integer",
12168
- description: "Pagination offset"
12169
- },
12170
- {
12171
- name: "limit",
12172
- in: "query",
12173
- required: false,
12174
- kind: "integer",
12175
- description: "Rows to return (1-100)"
12176
- },
12177
- {
12178
- name: "cursor",
12179
- in: "query",
12180
- required: false,
12181
- kind: "string",
12182
- description: "Pagination cursor"
12183
- }
12184
- ]
12136
+ parameters: [{
12137
+ name: "offset",
12138
+ in: "query",
12139
+ required: false,
12140
+ kind: "integer",
12141
+ description: "Pagination offset"
12142
+ }, {
12143
+ name: "limit",
12144
+ in: "query",
12145
+ required: false,
12146
+ kind: "integer",
12147
+ description: "Rows to return (1-100)"
12148
+ }]
12185
12149
  },
12186
12150
  {
12187
12151
  schemaBaseName: "RequestsSent",
@@ -12200,11 +12164,9 @@ const LINKEDIN_OPERATIONS = [
12200
12164
  capability: "read",
12201
12165
  mutates: false,
12202
12166
  pagination: {
12203
- style: "cursor",
12167
+ style: "offset",
12204
12168
  limitParam: "limit",
12205
- cursorParam: "cursor",
12206
12169
  offsetParam: "offset",
12207
- cursorPath: "next_cursor",
12208
12170
  totalCountPath: "total_count",
12209
12171
  itemsPath: "data"
12210
12172
  },
@@ -12212,29 +12174,19 @@ const LINKEDIN_OPERATIONS = [
12212
12174
  billingCategory: "user_read",
12213
12175
  kind: "users"
12214
12176
  },
12215
- parameters: [
12216
- {
12217
- name: "offset",
12218
- in: "query",
12219
- required: false,
12220
- kind: "integer",
12221
- description: "Pagination offset"
12222
- },
12223
- {
12224
- name: "limit",
12225
- in: "query",
12226
- required: false,
12227
- kind: "integer",
12228
- description: "Rows to return (1-100)"
12229
- },
12230
- {
12231
- name: "cursor",
12232
- in: "query",
12233
- required: false,
12234
- kind: "string",
12235
- description: "Pagination cursor"
12236
- }
12237
- ]
12177
+ parameters: [{
12178
+ name: "offset",
12179
+ in: "query",
12180
+ required: false,
12181
+ kind: "integer",
12182
+ description: "Pagination offset"
12183
+ }, {
12184
+ name: "limit",
12185
+ in: "query",
12186
+ required: false,
12187
+ kind: "integer",
12188
+ description: "Rows to return (1-100)"
12189
+ }]
12238
12190
  },
12239
12191
  {
12240
12192
  schemaBaseName: "MessagesMessage",
@@ -12640,7 +12592,6 @@ const CompaniesJobsOutput = object({
12640
12592
  const PostsCommentsInput = object({
12641
12593
  offset: union([string(), number()]).optional(),
12642
12594
  limit: union([string(), number()]).optional(),
12643
- cursor: string().optional(),
12644
12595
  sort_by: _enum(["MOST_RECENT", "MOST_RELEVANT"]).optional(),
12645
12596
  post_id: string()
12646
12597
  });
@@ -12652,7 +12603,6 @@ const PostsCommentsOutput = object({
12652
12603
  const PostsReactionsInput = object({
12653
12604
  offset: union([string(), number()]).optional(),
12654
12605
  limit: union([string(), number()]).optional(),
12655
- cursor: string().optional(),
12656
12606
  post_id: string()
12657
12607
  });
12658
12608
  const PostsReactionsOutput = object({
@@ -12709,7 +12659,6 @@ const UserProfileOutput = record(string(), unknown());
12709
12659
  const UserPostsInput = object({
12710
12660
  offset: union([string(), number()]).optional(),
12711
12661
  limit: union([string(), number()]).optional(),
12712
- cursor: string().optional(),
12713
12662
  identifier: string().optional()
12714
12663
  });
12715
12664
  const UserPostsOutput = object({
@@ -12720,7 +12669,6 @@ const UserPostsOutput = object({
12720
12669
  const UserConnectionsInput = object({
12721
12670
  offset: union([string(), number()]).optional(),
12722
12671
  limit: union([string(), number()]).optional(),
12723
- cursor: string().optional(),
12724
12672
  user_id: string().optional(),
12725
12673
  filter: string().optional()
12726
12674
  });
@@ -12731,8 +12679,7 @@ const UserConnectionsOutput = object({
12731
12679
  }).passthrough();
12732
12680
  const RequestsReceivedInput = object({
12733
12681
  offset: union([string(), number()]).optional(),
12734
- limit: union([string(), number()]).optional(),
12735
- cursor: string().optional()
12682
+ limit: union([string(), number()]).optional()
12736
12683
  });
12737
12684
  const RequestsReceivedOutput = object({
12738
12685
  data: array(record(string(), unknown())),
@@ -12741,8 +12688,7 @@ const RequestsReceivedOutput = object({
12741
12688
  }).passthrough();
12742
12689
  const RequestsSentInput = object({
12743
12690
  offset: union([string(), number()]).optional(),
12744
- limit: union([string(), number()]).optional(),
12745
- cursor: string().optional()
12691
+ limit: union([string(), number()]).optional()
12746
12692
  });
12747
12693
  const RequestsSentOutput = object({
12748
12694
  data: array(record(string(), unknown())),
@@ -13015,6 +12961,8 @@ const targetKindsFor = (op) => {
13015
12961
  };
13016
12962
  const positionalDisplayKeyFor$1 = (op, param) => op.config.paramLabels?.[param.name] ?? flagName(param.name);
13017
12963
  const bodyTextDisplayKeyFor$1 = (op) => op.config.bodyTextArg === void 0 ? void 0 : op.config.paramLabels?.[op.config.bodyTextArg] ?? op.config.bodyTextArg;
12964
+ const hasStdinBodyText$1 = (op) => op.config.bodyTextArg !== void 0;
12965
+ const stdinBodyTextRequired$1 = (op) => hasStdinBodyText$1(op) && op.config.bodyTextRequired !== false;
13018
12966
  const idempotencyFor$1 = (op) => {
13019
12967
  if (op.endpoint.capability === "read") return {
13020
12968
  safe: true,
@@ -13105,6 +13053,7 @@ const exampleCommandFor$1 = (op, commandName, root) => {
13105
13053
  const hint = `<${positionalDisplayKeyFor$1(op, param)}>`;
13106
13054
  parts.push(param.in === "path" || param.kind !== "array" ? hint : `${hint}...`);
13107
13055
  }
13056
+ if (hasStdinBodyText$1(op)) return `echo "..." | ${parts.join(" ")}`;
13108
13057
  if (op.hasBody) parts.push("--body", "'{...}'");
13109
13058
  return parts.join(" ");
13110
13059
  };
@@ -13119,16 +13068,19 @@ const signaturePartFor$1 = (op, name, arg) => {
13119
13068
  return arg.required === true ? `<${valueHint}>` : `[${valueHint}]`;
13120
13069
  }
13121
13070
  if (name === "limit") return "--limit N";
13122
- if (name === "body" && op.config.bodyTextArg === void 0) return "--body JSON";
13071
+ if (name === "body" && !hasStdinBodyText$1(op)) return "--body JSON";
13123
13072
  };
13073
+ const stdinSignaturePart$1 = (op) => hasStdinBodyText$1(op) ? "< body-text" : void 0;
13124
13074
  const usageFor$1 = (op, commandName, root) => {
13125
- const signature = Object.entries(buildArgs$1(op)).map(([name, arg]) => {
13075
+ const signatureParts = Object.entries(buildArgs$1(op)).map(([name, arg]) => {
13126
13076
  const part = signaturePartFor$1(op, name, arg);
13127
13077
  return part === void 0 ? void 0 : {
13128
13078
  positional: isObjectRecord$2(arg) && arg.type === "positional",
13129
13079
  part
13130
13080
  };
13131
- }).filter((entry) => entry !== void 0).sort((left, right) => Number(right.positional) - Number(left.positional)).map((entry) => entry.part).join(" ");
13081
+ }).filter((entry) => entry !== void 0).sort((left, right) => Number(right.positional) - Number(left.positional)).map((entry) => entry.part);
13082
+ const stdinPart = stdinSignaturePart$1(op);
13083
+ const signature = [...signatureParts, ...stdinPart ? [stdinPart] : []].join(" ");
13132
13084
  return [
13133
13085
  "social",
13134
13086
  "linkedin",
@@ -13138,7 +13090,15 @@ const usageFor$1 = (op, commandName, root) => {
13138
13090
  ].filter(Boolean).join(" ");
13139
13091
  };
13140
13092
  const helpDescriptionFor$1 = (op, commandName, root) => {
13141
- return `${`${op.config.summary} [${operationModeFor$1(op)}]`} | usage: \`${usageFor$1(op, commandName, root)}\``;
13093
+ const description = `${op.config.summary} [${operationModeFor$1(op)}]`;
13094
+ const usage = `usage: \`${usageFor$1(op, commandName, root)}\``;
13095
+ const label = [
13096
+ "social",
13097
+ "linkedin",
13098
+ ...root ? [] : [op.config.group],
13099
+ commandName
13100
+ ].join(" ");
13101
+ return `${description} | ${usage}${hasStdinBodyText$1(op) ? ` | body text is read from stdin: \`echo "..." | ${label}\` (or pass --body)` : ""}`;
13142
13102
  };
13143
13103
  const commandPathFor = (op) => `linkedin ${op.config.root ? op.config.command : `${op.config.group} ${op.config.command}`}`;
13144
13104
  const contractInputSchemaName = (op) => op.hasBody ? `${op.schemaBaseName}ContractInput` : `${op.schemaBaseName}Input`;
@@ -13196,15 +13156,6 @@ const buildArgs$1 = (op) => {
13196
13156
  type: "string",
13197
13157
  description: "JSON request body"
13198
13158
  };
13199
- if (op.config.bodyTextArg) {
13200
- const displayKey = bodyTextDisplayKeyFor$1(op) ?? op.config.bodyTextArg;
13201
- args[displayKey] = {
13202
- type: "positional",
13203
- required: false,
13204
- description: "Body value.",
13205
- valueHint: displayKey
13206
- };
13207
- }
13208
13159
  for (const [name, param] of Object.entries(op.config.bodyParams ?? {})) {
13209
13160
  const argName = bodyParamArg(name, param);
13210
13161
  args[flagName(argName)] = {
@@ -13294,7 +13245,7 @@ const buildBody = (deps, op, input) => {
13294
13245
  const bodyParamEntries = Object.entries(op.config.bodyParams ?? {});
13295
13246
  if (!bodyTextArg && bodyParamEntries.length === 0) return input.body === void 0 ? void 0 : deps.parseJSONObject("--body", input.body);
13296
13247
  const bodyFromJSON = input.body === void 0 ? void 0 : deps.parseJSONObject("--body", input.body);
13297
- const bodyText = bodyTextArg && input[bodyTextArg] !== void 0 ? deps.parseQueryString(`<${bodyTextDisplayKeyFor$1(op) ?? bodyTextArg}>`, input[bodyTextArg]) : void 0;
13248
+ const bodyText = bodyTextArg && input[bodyTextArg] !== void 0 ? deps.parseBodyText(`<${bodyTextDisplayKeyFor$1(op) ?? bodyTextArg}>`, input[bodyTextArg]) : void 0;
13298
13249
  const bodyParamValues = /* @__PURE__ */ new Map();
13299
13250
  for (const [name, param] of bodyParamEntries) {
13300
13251
  const value = input[name];
@@ -13329,8 +13280,29 @@ const dataWithAuditableWriteTarget = (op, data, body) => {
13329
13280
  post_id: postId
13330
13281
  };
13331
13282
  };
13283
+ 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>').`);
13285
+ const resolveBodyTextFromStdin$1 = async (op, deps, args, commandLabel) => {
13286
+ if (!hasStdinBodyText$1(op)) return;
13287
+ const bodyTextArg = bodyTextDisplayKeyFor$1(op) ?? op.config.bodyTextArg;
13288
+ if (bodyTextArg === void 0) return;
13289
+ const required = stdinBodyTextRequired$1(op) && typeof args.body !== "string";
13290
+ if (process.stdin.isTTY) {
13291
+ if (required) throw noBodyTextError$1(commandLabel);
13292
+ return;
13293
+ }
13294
+ const piped = trimTrailingNewline$1(await deps.readStdin());
13295
+ if (piped.length > 0) args[bodyTextArg] = piped;
13296
+ else if (required) throw noBodyTextError$1(commandLabel);
13297
+ };
13332
13298
  const runOperation$1 = async (op, contract, deps, args, rawArgs = []) => {
13333
13299
  rejectUnsupportedArgs(commandPathFor(op), args, Object.keys(buildArgs$1(op)));
13300
+ await resolveBodyTextFromStdin$1(op, deps, args, [
13301
+ "social",
13302
+ "linkedin",
13303
+ ...op.config.root ? [] : [op.config.group],
13304
+ op.config.command
13305
+ ].join(" "));
13334
13306
  checkBodyRequired(op, args);
13335
13307
  const account = typeof args.account === "string" ? args.account : void 0;
13336
13308
  const input = buildInput$1(op, args);
@@ -13487,7 +13459,8 @@ const defineOperationCommand$1 = (op, deps) => {
13487
13459
  method: op.endpoint.method,
13488
13460
  capability: op.endpoint.capability,
13489
13461
  mutates: op.endpoint.mutates,
13490
- schemaContract: contract
13462
+ schemaContract: contract,
13463
+ ...hasStdinBodyText$1(op) ? { stdin: true } : {}
13491
13464
  }),
13492
13465
  args: buildArgs$1(op),
13493
13466
  run: async ({ args, rawArgs }) => runOperation$1(op, contract, deps, args, rawArgs)
@@ -13718,7 +13691,7 @@ const buildMark = (deps) => {
13718
13691
  reason: "Setting a LinkedIn chat read status is safe to retry."
13719
13692
  },
13720
13693
  confirmation: { required: false },
13721
- pagination: null,
13694
+ pagination: { style: "none" },
13722
13695
  responseShaping: {
13723
13696
  supported: true,
13724
13697
  formats: ["json"],
@@ -13839,7 +13812,7 @@ const buildMessageDelete = (deps) => {
13839
13812
  required: true,
13840
13813
  reason: "Deletes a LinkedIn message immediately."
13841
13814
  },
13842
- pagination: null,
13815
+ pagination: { style: "none" },
13843
13816
  responseShaping: {
13844
13817
  supported: true,
13845
13818
  formats: ["json"],
@@ -13909,7 +13882,7 @@ const buildMessageEdit = (deps) => {
13909
13882
  return defineCommand({
13910
13883
  meta: commandMeta$2({
13911
13884
  name: "edit",
13912
- description: "Edit one of your LinkedIn messages [write] | usage: `social linkedin message <target> edit message_id:<id> <text>`",
13885
+ description: "Edit one of your LinkedIn messages [write] | usage: `social linkedin message <target> edit message_id:<id> < body-text` | new text is read from stdin: `echo \"...\" | social linkedin message <target> edit message_id:<id>`",
13913
13886
  method: "POST",
13914
13887
  capability: "write",
13915
13888
  mutates: true,
@@ -13929,19 +13902,20 @@ const buildMessageEdit = (deps) => {
13929
13902
  reason: "Re-applying the same LinkedIn message edit is safe."
13930
13903
  },
13931
13904
  confirmation: { required: false },
13932
- pagination: null,
13905
+ pagination: { style: "none" },
13933
13906
  responseShaping: {
13934
13907
  supported: true,
13935
13908
  formats: ["json"],
13936
13909
  projection: true
13937
13910
  },
13938
13911
  cost: writeCost(creditsForCostBPS$1(DM_INTERACTION_ENDPOINT_BILLING.costBPS)),
13939
- examples: [{ command: "linkedin message <target> edit message_id:<id> \"fixed text\"" }],
13912
+ examples: [{ command: "echo \"fixed text\" | linkedin message <target> edit message_id:<id>" }],
13940
13913
  hazards: [{
13941
13914
  code: "remote_write",
13942
13915
  message: "Edits a LinkedIn message immediately."
13943
13916
  }]
13944
- }
13917
+ },
13918
+ stdin: true
13945
13919
  }),
13946
13920
  args: {
13947
13921
  target: {
@@ -13956,12 +13930,6 @@ const buildMessageEdit = (deps) => {
13956
13930
  description: "Message to edit, as message_id:<id> (from `messages <target>`)",
13957
13931
  valueHint: "message_id:<id>"
13958
13932
  },
13959
- text: {
13960
- type: "positional",
13961
- required: true,
13962
- description: "New message text",
13963
- valueHint: "text"
13964
- },
13965
13933
  account: {
13966
13934
  type: "string",
13967
13935
  description: "Account selector: @handle or profile_id:<id>; overrides config default"
@@ -13971,9 +13939,12 @@ const buildMessageEdit = (deps) => {
13971
13939
  const positionals = Array.isArray(args._) ? args._ : [];
13972
13940
  const account = typeof args.account === "string" ? args.account : void 0;
13973
13941
  const message_id = messageIdFrom(deps, args.message_id ?? positionals[1]);
13974
- const textInput = args.text ?? positionals[2];
13975
- const text = textInput === void 0 ? void 0 : deps.parseQueryString("<text>", textInput);
13976
- if (text === void 0) throw new UsageError("Pass the new message <text>.");
13942
+ let textInput;
13943
+ if (process.stdin.isTTY) throw noBodyTextError$1("social linkedin message <target> edit message_id:<id>");
13944
+ const piped = trimTrailingNewline$1(await deps.readStdin());
13945
+ if (piped.length > 0) textInput = piped;
13946
+ const text = textInput === void 0 ? void 0 : deps.parseBodyText("<text>", textInput);
13947
+ if (text === void 0) throw noBodyTextError$1("social linkedin message <target> edit message_id:<id>");
13977
13948
  const resolved = [];
13978
13949
  const chatIdResolved = await deps.resolveTarget("target", args.target ?? positionals[0], {
13979
13950
  platform: "linkedin",
@@ -14010,11 +13981,16 @@ const buildMessage$1 = (deps, sendCommand) => {
14010
13981
  return defineCommand({
14011
13982
  meta: commandMeta$2({
14012
13983
  name: "message",
14013
- description: "Send a LinkedIn message to a person or conversation [write] | usage: `social linkedin message <target> [text]`",
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)",
14014
13985
  method: "POST",
14015
13986
  capability: "write",
14016
13987
  mutates: true,
14017
- schemaContract
13988
+ schemaContract,
13989
+ stdin: true,
13990
+ schemaSubCommands: {
13991
+ delete: deleteCommand,
13992
+ edit: editCommand
13993
+ }
14018
13994
  }),
14019
13995
  args: {
14020
13996
  target: {
@@ -14023,11 +13999,9 @@ const buildMessage$1 = (deps, sendCommand) => {
14023
13999
  description: "LinkedIn person or conversation target: @handle, profile URL, profile_id:<id>, chat_id:<id>, or a messaging thread URL",
14024
14000
  valueHint: "target"
14025
14001
  },
14026
- text: {
14027
- type: "positional",
14028
- required: true,
14029
- description: "Message text",
14030
- valueHint: "text"
14002
+ body: {
14003
+ type: "string",
14004
+ description: "JSON request body"
14031
14005
  },
14032
14006
  account: {
14033
14007
  type: "string",
@@ -14044,18 +14018,25 @@ const buildMessage$1 = (deps, sendCommand) => {
14044
14018
  _: [],
14045
14019
  account: args.account,
14046
14020
  target: positionals[0],
14047
- message_id: positionals[2],
14048
- ...positionals[1] === "edit" ? { text: positionals[3] } : {}
14021
+ message_id: positionals[2]
14049
14022
  },
14050
14023
  cmd: verbCommand
14051
14024
  });
14052
14025
  return;
14053
14026
  }
14054
14027
  const target = args.target ?? (Array.isArray(args._) && args._.length > 0 ? args._[0] : void 0);
14055
- const textInput = args.text ?? (Array.isArray(args._) && args._.length > 1 ? args._[1] : 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
+ }
14056
14037
  if (target === void 0) throw new UsageError("Pass a conversation or person target.");
14057
14038
  const bodyFromJSON = typeof args.body === "string" ? deps.parseJSONObject("--body", args.body) : void 0;
14058
- const text = textInput === void 0 ? void 0 : deps.parseQueryString("<text>", textInput);
14039
+ const text = textInput === void 0 ? void 0 : deps.parseBodyText("<text>", textInput);
14059
14040
  const body = text === void 0 ? bodyFromJSON : {
14060
14041
  ...bodyFromJSON ?? {},
14061
14042
  text
@@ -14147,7 +14128,8 @@ const buildMessages$1 = (deps, listCommand, readCommand) => {
14147
14128
  method: "GET",
14148
14129
  capability: "read",
14149
14130
  mutates: false,
14150
- schemaContract: listCommand.meta.schemaContract
14131
+ schemaContract: listCommand.meta.schemaContract,
14132
+ schemaSubCommands: { mark: markCommand }
14151
14133
  }),
14152
14134
  args: {
14153
14135
  target: {
@@ -14302,6 +14284,8 @@ createLinkedinCommands({
14302
14284
  },
14303
14285
  parseResourceId: unconfigured$1,
14304
14286
  parseQueryString: unconfigured$1,
14287
+ parseBodyText: unconfigured$1,
14288
+ readStdin: unconfigured$1,
14305
14289
  parseIntegerString: unconfigured$1,
14306
14290
  parseEnumString: unconfigured$1,
14307
14291
  parseBooleanString: unconfigured$1,
@@ -17017,6 +17001,9 @@ const isRequired = (op, param, positional) => {
17017
17001
  };
17018
17002
  const positionalDisplayKeyFor = (op, param) => op.config.paramLabels?.[param.name] ?? flagName(param.name);
17019
17003
  const bodyTextDisplayKeyFor = (op) => op.config.bodyTextArg === void 0 ? void 0 : op.config.paramLabels?.[op.config.bodyTextArg] ?? op.config.bodyTextArg;
17004
+ const resolvesTargetArg = (op) => op.config.bodyTextArg !== void 0 && (op.config.resolveResourceParams ?? []).includes(op.config.bodyTextArg);
17005
+ const hasStdinBodyText = (op) => op.config.bodyTextArg !== void 0 && !resolvesTargetArg(op);
17006
+ const stdinBodyTextRequired = (op) => hasStdinBodyText(op) && op.config.bodyTextRequired !== false;
17020
17007
  const kindsOf = (targetKind, fallback) => {
17021
17008
  const kind = targetKind ?? fallback;
17022
17009
  if (kind === void 0) throw new Error("target_kind_missing");
@@ -17151,6 +17138,7 @@ const exampleCommandFor = (op, commandName, group) => {
17151
17138
  }
17152
17139
  }
17153
17140
  if (op.parameters.some((p) => p.name === "max_results")) parts.push("--limit", "10");
17141
+ if (hasStdinBodyText(op)) return `echo "Hello from social" | ${parts.join(" ")}`;
17154
17142
  if (op.hasBody) parts.push("--body", JSON.stringify(exampleBodyFor(op)));
17155
17143
  return parts.join(" ");
17156
17144
  };
@@ -17165,16 +17153,19 @@ const signaturePartFor = (op, name, arg) => {
17165
17153
  return arg.required === true ? `<${valueHint}>` : `[${valueHint}]`;
17166
17154
  }
17167
17155
  if (name === "limit") return "--limit N";
17168
- if (name === "body" && op.config.bodyTextArg === void 0) return "--body JSON";
17156
+ if (name === "body" && !hasStdinBodyText(op)) return "--body JSON";
17169
17157
  };
17158
+ const stdinSignaturePart = (op) => hasStdinBodyText(op) ? "< body-text" : void 0;
17170
17159
  const usageFor = (op, commandName, group) => {
17171
- const signature = Object.entries(buildArgs(op)).map(([name, arg]) => {
17160
+ const signatureParts = Object.entries(buildArgs(op)).map(([name, arg]) => {
17172
17161
  const part = signaturePartFor(op, name, arg);
17173
17162
  return part === void 0 ? void 0 : {
17174
17163
  positional: isObjectRecord$1(arg) && arg.type === "positional",
17175
17164
  part
17176
17165
  };
17177
- }).filter((entry) => entry !== void 0).sort((left, right) => Number(right.positional) - Number(left.positional)).map((entry) => entry.part).join(" ");
17166
+ }).filter((entry) => entry !== void 0).sort((left, right) => Number(right.positional) - Number(left.positional)).map((entry) => entry.part);
17167
+ const stdinPart = stdinSignaturePart(op);
17168
+ const signature = [...signatureParts, ...stdinPart ? [stdinPart] : []].join(" ");
17178
17169
  return [
17179
17170
  "social",
17180
17171
  "x",
@@ -17183,7 +17174,15 @@ const usageFor = (op, commandName, group) => {
17183
17174
  ].filter(Boolean).join(" ");
17184
17175
  };
17185
17176
  const helpDescriptionFor = (op, commandName, group) => {
17186
- return `${`${op.config.summary} [${operationModeFor(op)}]`} | usage: \`${usageFor(op, commandName, group)}\``;
17177
+ const description = `${op.config.summary} [${operationModeFor(op)}]`;
17178
+ const usage = `usage: \`${usageFor(op, commandName, group)}\``;
17179
+ const label = [
17180
+ "social",
17181
+ "x",
17182
+ group,
17183
+ commandName
17184
+ ].filter(Boolean).join(" ");
17185
+ return `${description} | ${usage}${hasStdinBodyText(op) ? ` | body text is read from stdin: \`echo "..." | ${label}\` (or pass --body)` : ""}`;
17187
17186
  };
17188
17187
  const contractFor$1 = (op, commandName, group) => {
17189
17188
  const mutates = op.endpoint.mutates;
@@ -17233,12 +17232,12 @@ const buildArgs = (op) => {
17233
17232
  type: "string",
17234
17233
  description: "JSON request body"
17235
17234
  };
17236
- if (op.config.bodyTextArg) {
17235
+ if (op.config.bodyTextArg && resolvesTargetArg(op)) {
17237
17236
  const displayKey = bodyTextDisplayKeyFor(op) ?? op.config.bodyTextArg;
17238
17237
  args[displayKey] = {
17239
17238
  type: "positional",
17240
17239
  required: false,
17241
- description: (op.config.resolveResourceParams ?? []).includes(op.config.bodyTextArg) ? targetDescriptionFor(op.config.targetKind) : "Body value.",
17240
+ description: targetDescriptionFor(op.config.targetKind),
17242
17241
  valueHint: displayKey
17243
17242
  };
17244
17243
  }
@@ -17374,8 +17373,29 @@ const withEchoedTargetId = (op, data, body) => {
17374
17373
  }
17375
17374
  };
17376
17375
  };
17376
+ 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>').`);
17378
+ const resolveBodyTextFromStdin = async (op, deps, args, commandLabel) => {
17379
+ if (!hasStdinBodyText(op)) return;
17380
+ const bodyTextArg = bodyTextDisplayKeyFor(op) ?? op.config.bodyTextArg;
17381
+ if (bodyTextArg === void 0) return;
17382
+ const required = stdinBodyTextRequired(op) && args.body === void 0;
17383
+ if (process.stdin.isTTY) {
17384
+ if (required) throw noBodyTextError(commandLabel);
17385
+ return;
17386
+ }
17387
+ const piped = trimTrailingNewline(await deps.readStdin());
17388
+ if (piped.length > 0) args[bodyTextArg] = piped;
17389
+ else if (required) throw noBodyTextError(commandLabel);
17390
+ };
17377
17391
  const runOperation = async (op, contract, deps, args, rawArgs = []) => {
17378
17392
  rejectUnknownArgs(op, args);
17393
+ await resolveBodyTextFromStdin(op, deps, args, [
17394
+ "social",
17395
+ "x",
17396
+ op.config.root ? "" : op.config.group,
17397
+ op.config.command
17398
+ ].filter(Boolean).join(" "));
17379
17399
  const account = typeof args.account === "string" ? args.account : void 0;
17380
17400
  let ownAccount;
17381
17401
  const resolveOwnAccount = async () => {
@@ -17458,12 +17478,12 @@ const runOperation = async (op, contract, deps, args, rawArgs = []) => {
17458
17478
  const textArg = op.config.bodyTextArg;
17459
17479
  if (textArg) {
17460
17480
  const displayTextArg = bodyTextDisplayKeyFor(op) ?? textArg;
17461
- const bodyText = input[textArg] === void 0 ? void 0 : deps.parseQueryString(`<${displayTextArg}>`, input[textArg]);
17481
+ const bodyText = input[textArg] === void 0 ? void 0 : deps.parseBodyText(`<${displayTextArg}>`, input[textArg]);
17462
17482
  body = bodyText === void 0 ? bodyFromJSON : {
17463
17483
  ...bodyFromJSON ?? {},
17464
17484
  [textArg]: bodyText
17465
17485
  };
17466
- if (body === void 0 && op.config.bodyTextRequired === true) throw new UsageError(`Pass <${displayTextArg}> or --body.`);
17486
+ if (body === void 0 && resolvesTargetArg(op) && op.config.bodyTextRequired === true) throw new UsageError(`Pass <${displayTextArg}> or --body.`);
17467
17487
  } else body = bodyFromJSON;
17468
17488
  body = await applyCreatePostReply(deps, op, input, body, resolved, account);
17469
17489
  }
@@ -17493,7 +17513,8 @@ const defineOperationCommand = (op, deps) => {
17493
17513
  method: op.endpoint.method,
17494
17514
  capability: op.endpoint.capability,
17495
17515
  mutates: op.endpoint.mutates,
17496
- contract
17516
+ contract,
17517
+ ...hasStdinBodyText(op) ? { stdin: true } : {}
17497
17518
  }),
17498
17519
  args: buildArgs(op),
17499
17520
  run: async ({ args, rawArgs }) => runOperation(op, contract, deps, args, rawArgs)
@@ -17916,11 +17937,12 @@ const buildMessage = (deps) => {
17916
17937
  return defineCommand({
17917
17938
  meta: commandMeta$1({
17918
17939
  name: "message",
17919
- description: "Send a DM to a participant or conversation [write] | usage: `social x message <recipients> [text]`",
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)",
17920
17941
  method: "POST",
17921
17942
  capability: "write",
17922
17943
  mutates: true,
17923
- contract
17944
+ contract,
17945
+ stdin: true
17924
17946
  }),
17925
17947
  args: {
17926
17948
  recipients: {
@@ -17929,12 +17951,6 @@ const buildMessage = (deps) => {
17929
17951
  description: "Recipient(s): chat URL, chat_id:<id>, @handle, profile URL, or profile_id:<id>; comma-separate profiles for a group",
17930
17952
  valueHint: "recipients"
17931
17953
  },
17932
- text: {
17933
- type: "positional",
17934
- required: false,
17935
- description: "Message text",
17936
- valueHint: "text"
17937
- },
17938
17954
  body: {
17939
17955
  type: "string",
17940
17956
  description: "JSON request body"
@@ -17946,12 +17962,20 @@ const buildMessage = (deps) => {
17946
17962
  },
17947
17963
  run: async ({ args }) => {
17948
17964
  const recipientsInput = args.recipients ?? args.target ?? (Array.isArray(args._) && args._.length > 0 ? args._[0] : void 0);
17949
- const textInput = args.text ?? (Array.isArray(args._) && args._.length > 1 ? args._[1] : 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
+ }
17950
17974
  if (recipientsInput === void 0) throw new UsageError("Pass a conversation or user target.");
17951
17975
  const recipients = String(recipientsInput).split(",").map((recipient) => recipient.trim()).filter((recipient) => recipient.length > 0);
17952
17976
  if (recipients.length === 0) throw new UsageError("Pass at least one recipient.");
17953
17977
  const bodyFromJSON = typeof args.body === "string" ? deps.parseJSONObject("--body", args.body) : void 0;
17954
- const text = textInput === void 0 ? void 0 : deps.parseQueryString("--text", textInput);
17978
+ const text = textInput === void 0 ? void 0 : deps.parseBodyText("--text", textInput);
17955
17979
  const body = text === void 0 ? bodyFromJSON : {
17956
17980
  ...bodyFromJSON ?? {},
17957
17981
  text
@@ -18008,9 +18032,110 @@ const buildMessage = (deps) => {
18008
18032
  }
18009
18033
  });
18010
18034
  };
18035
+ const searchOp = (() => {
18036
+ const op = X_OPERATIONS.find((candidate) => candidate.config.command === "search");
18037
+ if (op === void 0) throw new Error("x_cli_search_operation_missing");
18038
+ return op;
18039
+ })();
18040
+ const repliesOp = {
18041
+ schemaBaseName: searchOp.schemaBaseName,
18042
+ hasBody: false,
18043
+ config: {
18044
+ command: "replies",
18045
+ group: "tweets",
18046
+ root: true,
18047
+ summary: "List replies to a post",
18048
+ itemUrlTemplate: "https://x.com/i/web/status/{id}",
18049
+ fieldPresets: searchOp.config.fieldPresets
18050
+ },
18051
+ endpoint: searchOp.endpoint,
18052
+ parameters: []
18053
+ };
18054
+ const conversationIdPrefix = "conversation_id:";
18055
+ const buildReplies = (deps) => {
18056
+ const contract = contractFor$1(repliesOp, "replies", "");
18057
+ const presets = repliesOp.config.fieldPresets ?? {};
18058
+ return defineCommand({
18059
+ meta: commandMeta$1({
18060
+ name: "replies",
18061
+ description: "List replies to a post [read] | usage: `social x replies <post-or-conversation> --limit N` | accepts conversation_id:<id>, post_id:<id>, or a post URL",
18062
+ method: "GET",
18063
+ capability: "read",
18064
+ mutates: false,
18065
+ contract
18066
+ }),
18067
+ args: {
18068
+ target: {
18069
+ type: "positional",
18070
+ required: true,
18071
+ description: "Post or conversation: conversation_id:<id>, post_id:<id>, or a post URL",
18072
+ valueHint: "target"
18073
+ },
18074
+ limit: {
18075
+ type: "string",
18076
+ description: "Rows to return (10-100)"
18077
+ },
18078
+ cursor: {
18079
+ type: "string",
18080
+ description: "Cursor from a previous response"
18081
+ },
18082
+ account: {
18083
+ type: "string",
18084
+ description: "Account selector: @handle or profile_id:<id>; overrides config default"
18085
+ }
18086
+ },
18087
+ run: async ({ args }) => {
18088
+ const positional = Array.isArray(args._) ? args._ : [];
18089
+ const targetInput = args.target ?? (positional.length > 0 ? positional[0] : void 0);
18090
+ if (targetInput === void 0) throw new UsageError("Pass a post or conversation target.");
18091
+ const target = String(targetInput).trim();
18092
+ const account = typeof args.account === "string" ? args.account : void 0;
18093
+ const selectedAccount = await deps.resolveAccount({
18094
+ platform: "x",
18095
+ account
18096
+ });
18097
+ const accountIdHeader = selectedAccount.selector;
18098
+ const headers = { ...accountIdHeader === void 0 ? {} : { "x-social-account-id": accountIdHeader } };
18099
+ const resolved = [];
18100
+ let conversationId;
18101
+ if (target.startsWith(conversationIdPrefix)) conversationId = deps.parseResourceId("conversation_id", target.slice(16));
18102
+ else {
18103
+ const resolution = await deps.resolveTarget("target", target, {
18104
+ platform: "x",
18105
+ expect: ["post"],
18106
+ account
18107
+ });
18108
+ resolved.push(resolution.record);
18109
+ const lookupData = await (await deps.api.get(`x/tweets/${encodeURIComponent(resolution.id)}?tweet.fields=conversation_id`, { headers })).json();
18110
+ const post = isObjectRecord(lookupData) ? lookupData.data : void 0;
18111
+ const candidate = isObjectRecord(post) ? post.conversation_id : void 0;
18112
+ if (typeof candidate !== "string" || candidate.length === 0) throw new UsageError(`Could not read conversation_id for ${target} (the post may be deleted or protected).`);
18113
+ conversationId = candidate;
18114
+ }
18115
+ const params = new URLSearchParams();
18116
+ params.set("query", `${conversationIdPrefix}${conversationId} is:reply`);
18117
+ if (args.limit !== void 0) params.set("max_results", String(deps.parseIntegerString("--limit", args.limit, {
18118
+ min: 10,
18119
+ max: 100
18120
+ })));
18121
+ if (args.cursor !== void 0) params.set("next_token", deps.parseQueryString("--cursor", args.cursor));
18122
+ for (const [field, value] of Object.entries(presets)) params.set(field, deps.parseQueryString(`--${field}`, value));
18123
+ const response = await deps.api.get(`x/tweets/search/recent?${params.toString()}`, { headers });
18124
+ const data = await response.json();
18125
+ await deps.printResult({
18126
+ account: selectedAccount,
18127
+ contract,
18128
+ data,
18129
+ resolved,
18130
+ responseHeaders: response.headers
18131
+ });
18132
+ }
18133
+ });
18134
+ };
18011
18135
  const createXCommands = (deps) => {
18012
18136
  const messages = buildMessages(deps);
18013
18137
  const message = buildMessage(deps);
18138
+ const replies = buildReplies(deps);
18014
18139
  const sync = buildSync(deps, "x");
18015
18140
  const sql = buildSql(deps, "x");
18016
18141
  const entries = X_OPERATIONS.map((op, index) => ({
@@ -18029,16 +18154,21 @@ const createXCommands = (deps) => {
18029
18154
  command: message,
18030
18155
  rank: 1,
18031
18156
  index: X_OPERATIONS.length + 1
18157
+ }, {
18158
+ name: "replies",
18159
+ command: replies,
18160
+ rank: 0,
18161
+ index: X_OPERATIONS.length + 2
18032
18162
  }, {
18033
18163
  name: "sync",
18034
18164
  command: sync,
18035
18165
  rank: 0,
18036
- index: X_OPERATIONS.length + 2
18166
+ index: X_OPERATIONS.length + 3
18037
18167
  }, {
18038
18168
  name: "sql",
18039
18169
  command: sql,
18040
18170
  rank: 0,
18041
- index: X_OPERATIONS.length + 3
18171
+ index: X_OPERATIONS.length + 4
18042
18172
  });
18043
18173
  entries.sort((left, right) => left.rank - right.rank || left.index - right.index);
18044
18174
  return defineCommand({
@@ -18062,6 +18192,8 @@ createXCommands({
18062
18192
  },
18063
18193
  parseResourceId: unconfigured,
18064
18194
  parseQueryString: unconfigured,
18195
+ parseBodyText: unconfigured,
18196
+ readStdin: unconfigured,
18065
18197
  parseIntegerString: unconfigured,
18066
18198
  parseEnumString: unconfigured,
18067
18199
  parseBooleanString: unconfigured,
@@ -20922,7 +21054,7 @@ const createInstance = (defaults) => {
20922
21054
  const ky = createInstance();
20923
21055
  //#endregion
20924
21056
  //#region package.json
20925
- var version$1 = "0.2.6";
21057
+ var version$1 = "0.3.0";
20926
21058
  //#endregion
20927
21059
  //#region src/lib/env.ts
20928
21060
  const URLWithTrailingSlash = url().transform(ensureTrailingSlash);
@@ -21312,6 +21444,12 @@ let outputWriters = {
21312
21444
  stdout: writeStdout,
21313
21445
  stderr: (value) => process.stderr.write(`${value}\n`)
21314
21446
  };
21447
+ const readStdin = async () => {
21448
+ process.stdin.setEncoding("utf8");
21449
+ let input = "";
21450
+ for await (const chunk of process.stdin) input += chunk;
21451
+ return input;
21452
+ };
21315
21453
  const printLine = (value) => {
21316
21454
  outputWriters.stdout(value);
21317
21455
  };
@@ -21331,6 +21469,10 @@ const stringAtPath = (value, path) => {
21331
21469
  const found = valueAtPath(value, path);
21332
21470
  return typeof found === "string" && found.length > 0 ? found : void 0;
21333
21471
  };
21472
+ const numberAtPath = (value, path) => {
21473
+ const found = valueAtPath(value, path);
21474
+ return typeof found === "number" && Number.isFinite(found) ? found : void 0;
21475
+ };
21334
21476
  const idForRecord = (record) => {
21335
21477
  for (const key of [
21336
21478
  "id",
@@ -21424,11 +21566,18 @@ const nextCursorFrom = (contract, data) => {
21424
21566
  const response = pagination.response;
21425
21567
  return stringAtPath(data, isRecord$3(response) ? response.nextCursorPath : null) ?? stringAtPath(data, pagination.cursorPath);
21426
21568
  };
21569
+ const totalCountFrom = (contract, data) => {
21570
+ if (!isRecord$3(contract)) return;
21571
+ const pagination = contract.pagination;
21572
+ if (!isRecord$3(pagination)) return;
21573
+ return numberAtPath(data, pagination.totalCountPath);
21574
+ };
21427
21575
  const resultEnvelope = ({ account, contract, data, resolved = [], responseHeaders }) => {
21428
21576
  const payload = outputPayloadFor(data, itemURLTemplateFrom(contract), idFieldFrom(contract));
21429
21577
  const cache = cacheFromHeaders(responseHeaders);
21430
21578
  const itemCount = "items" in payload && Array.isArray(payload.items) ? payload.items.length : 1;
21431
21579
  const cursor = nextCursorFrom(contract, data);
21580
+ const totalCount = totalCountFrom(contract, data);
21432
21581
  return {
21433
21582
  account: {
21434
21583
  platform: account.platform,
@@ -21439,7 +21588,8 @@ const resultEnvelope = ({ account, contract, data, resolved = [], responseHeader
21439
21588
  resolved,
21440
21589
  cost: costFromContract(contract, itemCount, cache.hit, responseHeaders),
21441
21590
  cache,
21442
- ...cursor === void 0 ? {} : { cursor }
21591
+ ...cursor === void 0 ? {} : { cursor },
21592
+ ...totalCount === void 0 ? {} : { totalCount }
21443
21593
  }
21444
21594
  };
21445
21595
  };
@@ -21486,16 +21636,21 @@ const BOOLEAN_STRINGS = [
21486
21636
  "off"
21487
21637
  ];
21488
21638
  const hasControlCharacter = (value) => [...value].some((character) => character.charCodeAt(0) < 32);
21639
+ const hasDisallowedControlCharacter = (value) => [...value].some((character) => {
21640
+ const code = character.charCodeAt(0);
21641
+ return code < 32 && code !== 9 && code !== 10 && code !== 13;
21642
+ });
21489
21643
  const validationError = (path, message) => new ZodError([{
21490
21644
  code: "custom",
21491
21645
  path,
21492
21646
  message
21493
21647
  }]);
21494
21648
  const rejectControlCharacters = (name) => string().refine((value) => !hasControlCharacter(value), { message: `${name} must not contain control characters.` });
21649
+ const BodyText = (name) => string().refine((value) => !hasDisallowedControlCharacter(value), { message: `${name} must not contain control characters.` });
21495
21650
  const ResourceId = (name) => rejectControlCharacters(name).min(1, `${name} is required`).refine((value) => !UNSAFE_RESOURCE_CHARACTER_PATTERN.test(value), { message: `${name} must be a plain resource ID, not a URL, path, query string, or encoded value.` });
21496
21651
  const QueryString = (name) => rejectControlCharacters(name).check(/* @__PURE__ */ _minLength(1, `${name} must not be empty.`));
21497
21652
  const rejectControlCharactersInJSON = (name, value, path = []) => {
21498
- if (typeof value === "string" && hasControlCharacter(value)) throw validationError(path.length > 0 ? path : ["value"], `${name} must not contain control characters.`);
21653
+ if (typeof value === "string" && hasDisallowedControlCharacter(value)) throw validationError(path.length > 0 ? path : ["value"], `${name} must not contain control characters.`);
21499
21654
  if (Array.isArray(value)) {
21500
21655
  for (const [index, item] of value.entries()) rejectControlCharactersInJSON(name, item, [...path, String(index)]);
21501
21656
  return;
@@ -21509,6 +21664,7 @@ const parseWithSchema = (value, schema) => {
21509
21664
  };
21510
21665
  const parseResourceId = (name, value) => parseWithSchema(value, ResourceId(name));
21511
21666
  const parseQueryString = (name, value) => parseWithSchema(value, QueryString(name));
21667
+ const parseBodyText = (name, value) => parseWithSchema(value, BodyText(name));
21512
21668
  const parseResourceIdList = (name, values) => {
21513
21669
  const parsed = array(ResourceId(name)).min(1, `${name} requires at least one ID.`).safeParse(values.map((value) => String(value)));
21514
21670
  if (parsed.success) return parsed.data;
@@ -28350,6 +28506,8 @@ const createCLIDeps = () => {
28350
28506
  api,
28351
28507
  parseResourceId,
28352
28508
  parseQueryString,
28509
+ parseBodyText,
28510
+ readStdin,
28353
28511
  parseIntegerString,
28354
28512
  parseEnumString,
28355
28513
  parseBooleanString,
@@ -28465,7 +28623,12 @@ const pathPartsFrom = (...values) => {
28465
28623
  const commandName = (command, fallback) => typeof command.meta?.name === "string" ? command.meta.name : fallback;
28466
28624
  const commandDescription = (command) => typeof command.meta?.description === "string" ? command.meta.description : "";
28467
28625
  const isHiddenCommand = (command) => command.meta?.hidden === true;
28626
+ const inputSourceFor = (command) => command.meta?.stdin === true ? { inputSource: "stdin" } : {};
28468
28627
  const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
28628
+ const childCommandsFor = (command) => ({
28629
+ ...command.subCommands ?? {},
28630
+ ...isRecord(command.meta?.schemaSubCommands) ? command.meta.schemaSubCommands : {}
28631
+ });
28469
28632
  const firstDefined = (...values) => values.find((value) => value !== void 0);
28470
28633
  const JSONMetadata = lazy(() => union([
28471
28634
  _null(),
@@ -28624,7 +28787,8 @@ const compactSchemaForCommand = (command, path) => {
28624
28787
  description: commandDescription(command),
28625
28788
  ...method ? { method } : {},
28626
28789
  capability: capability ?? "unknown",
28627
- mutates: mutates ?? false
28790
+ mutates: mutates ?? false,
28791
+ ...inputSourceFor(command)
28628
28792
  };
28629
28793
  };
28630
28794
  const schemaForCommand = (command, path) => {
@@ -28644,6 +28808,7 @@ const schemaForCommand = (command, path) => {
28644
28808
  name: path.join(".") || commandName(command, "social"),
28645
28809
  description: commandDescription(command),
28646
28810
  ...method ? { method } : {},
28811
+ ...inputSourceFor(command),
28647
28812
  args: metadataValueFor(contract.args, `${label}.args`) ?? positionalArgs,
28648
28813
  flags: metadataValueFor(contract.flags, `${label}.flags`) ?? flags,
28649
28814
  params: metadataValueFor(contract.params, `${label}.params`) ?? args,
@@ -28663,25 +28828,26 @@ const schemaForCommand = (command, path) => {
28663
28828
  };
28664
28829
  };
28665
28830
  const treeForCommand = (command, path = []) => {
28666
- const subCommands = command.subCommands ?? {};
28831
+ const subCommands = childCommandsFor(command);
28667
28832
  return {
28668
28833
  ...compactSchemaForCommand(command, path),
28669
28834
  subCommands: Object.fromEntries(Object.entries(subCommands).filter(([, subCommand]) => !isHiddenCommand(subCommand)).map(([name, subCommand]) => [name, treeForCommand(subCommand, [...path, commandName(subCommand, name)])]))
28670
28835
  };
28671
28836
  };
28672
28837
  const leafSchemasForCommand = (command, path = []) => {
28673
- const subCommands = command.subCommands ?? {};
28674
- const entries = Object.entries(subCommands).filter(([, subCommand]) => !isHiddenCommand(subCommand));
28838
+ const subCommands = childCommandsFor(command);
28839
+ const allEntries = Object.entries(subCommands);
28840
+ const entries = allEntries.filter(([, subCommand]) => !isHiddenCommand(subCommand));
28675
28841
  const runnable = typeof command.run === "function";
28676
- return [...path.length > 0 && (runnable || entries.length === 0) ? [[path.join(" "), schemaForCommand(command, path)]] : [], ...entries.flatMap(([name, subCommand]) => leafSchemasForCommand(subCommand, [...path, commandName(subCommand, name)]))];
28842
+ return [...path.length > 0 && (runnable || allEntries.length === 0) ? [[path.join(" "), schemaForCommand(command, path)]] : [], ...entries.flatMap(([name, subCommand]) => leafSchemasForCommand(subCommand, [...path, commandName(subCommand, name)]))];
28677
28843
  };
28678
28844
  const commandAtPath = (command, path) => {
28679
28845
  let current = command;
28680
28846
  const parts = path[0] === commandName(command, "social") ? path.slice(1) : path;
28681
28847
  const resolved = [];
28682
28848
  for (const part of parts) {
28683
- const next = current.subCommands?.[part];
28684
- if (!next || isHiddenCommand(next)) throw new Error(`Unknown command path: ${path.join(".")}`);
28849
+ const next = childCommandsFor(current)[part];
28850
+ if (!next) throw new Error(`Unknown command path: ${path.join(".")}`);
28685
28851
  current = next;
28686
28852
  resolved.push(commandName(current, part));
28687
28853
  }