@usesocial/cli 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,211 @@
1
1
  # @usesocial/cli
2
2
 
3
+ ## 0.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#38](https://github.com/usesocial/monorepo/pull/38) [`9f1f30d`](https://github.com/usesocial/monorepo/commit/9f1f30daeb89b5ad83bcc456a0ed71a5587e790c) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Add `social x sync timeline` for syncing the authenticated X home timeline into the local SQL mirror, remove the live `social x timeline` shortcut from the public command surface, and let local SQL reads query partial mirror rows.
8
+
9
+ ## 0.9.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`90cd296`](https://github.com/usesocial/monorepo/commit/90cd2967a18a271337c54414466c5d89e66649d2) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - `social account logs` auto-paginates and aggregates for spend audits.
14
+
15
+ - `--limit` above the server's 100-row page cap now follows `.meta.cursor`
16
+ across pages transparently and returns one merged envelope.
17
+ - `--sum-by <fields>` (comma-separated from `platform`, `path`, `method`,
18
+ `day`, `cacheStatus`) aggregates the selected window into
19
+ `{ …key, calls, credits, errors }` rows sorted by credits descending —
20
+ a one-command answer to "what did my agent spend this week, on what".
21
+ - `createdAt` is always an ISO string, and the declared contract stays
22
+ JSON-Schema-serializable (`social schema --leaves` works).
23
+
24
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`b8cddb4`](https://github.com/usesocial/monorepo/commit/b8cddb4d4c5c290a2add9498ce94c906427a12e5) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Error output and diagnostics are now debuggable end-to-end.
25
+
26
+ - API error JSON printed to stderr now includes a top-level `code` (stable
27
+ snake_case API error code) and `requestId` — quote the request id when
28
+ reporting a bug and we can trace the exact server-side call.
29
+ - Rate-limited commands surface `retryCount` and `retryBudgetExhausted` on the
30
+ error payload alongside the existing `retryAfterSeconds`.
31
+ - Diagnostic telemetry (opt-out unchanged: `DO_NOT_TRACK=1` /
32
+ `SOCIAL_DO_NOT_TRACK=1`) now records every command failure — not just API
33
+ 5xx — with a privacy-safe fingerprint (error class + status + stable code)
34
+ instead of raw messages. The first-run privacy promise is unchanged: no
35
+ arguments, stdin, response bodies, handles, or content ever leave the
36
+ machine.
37
+ - Crashes, unhandled rejections, and Ctrl-C now flush diagnostics before
38
+ exiting (signals exit `130`/`143`); a closed stdout pipe (`head`, `jq -e`)
39
+ exits `0` quietly instead of crashing.
40
+
41
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`e3fb8a2`](https://github.com/usesocial/monorepo/commit/e3fb8a2d09301494d95115f8409862d392d78fcb) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Schema contracts now declare advisory hazards instead of confirmation gates:
42
+ `confirmation.{required,recommended}` is replaced by `hazard { kind:
43
+ spends_credits | destructive | outbound_write, confirm: "advisory" }` on
44
+ mutating commands (billing portal and connect declare nothing). Non-TTY
45
+ `account login` and `account connect` become pollable state machines that
46
+ advance one step per call — `pending_approval { verificationURL, expiresAt }`
47
+ through `logged_in` / `connected` — with the in-flight device code persisted
48
+ between calls. New get-started skill reference walks agents through
49
+ login → connect → cost-estimated first sync.
50
+
51
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`84797f6`](https://github.com/usesocial/monorepo/commit/84797f67c496cef4f5e26b740550166dacba3876) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - `social linkedin message <target>` now accepts `--media <path>` (repeatable) to
52
+ attach files to a new or existing conversation. The caption (piped on stdin)
53
+ becomes optional when media is present, and the combined attachments must stay
54
+ under 20 MB. Media types are detected from file content (magic bytes) and render
55
+ natively.
56
+
57
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`f9c9916`](https://github.com/usesocial/monorepo/commit/f9c9916e67699ab1640b621205bb0ba498b061d5) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - `social linkedin post` now attaches media and supports quoting and posting as a
58
+ company. Pipe the caption on stdin as before, or omit it entirely when attaching
59
+ media or quoting.
60
+
61
+ - `--media <path>` (repeatable) attaches local files inline (base64). The media
62
+ type is detected from the file's content (magic bytes). LinkedIn allows
63
+ multiple images, OR a single non-image file (video, PDF, document).
64
+ - `--quote <post>` quotes/reposts an existing post — a LinkedIn post URL,
65
+ `post_id:<id>`, or URN. With caption text it's a quote post; with empty text
66
+ it's a bare repost.
67
+ - `--as <company>` publishes on behalf of a company you admin — a numeric
68
+ company id, or a company URL/vanity that is resolved to its id.
69
+
70
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`b89c2f9`](https://github.com/usesocial/monorepo/commit/b89c2f96d1acc4dfe21b796a9332732fa60681b4) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Own-data live reads now require a target; your own data is the local mirror.
71
+
72
+ `social x tweets`, `x followers`, `x following`, `x liked`, `x mentions`, and
73
+ `linkedin connections` invoked without a target no longer fall back to a
74
+ metered self-read. Each fails with a teaching error naming the free local
75
+ path instead — e.g. `social x sync tweets` then
76
+ `social x sql "SELECT text, like_count, impression_count FROM x_tweets ORDER BY created_at DESC LIMIT 25"`.
77
+ Live reads are for someone else's graph; `sync` + `sql` is the own-data
78
+ surface. A literal `@me`/`@self` target still resolves to that real X
79
+ username but emits a note pointing at the sync+sql path.
80
+
81
+ Bare `social x sync` / `social linkedin sync` listings now include
82
+ `totalRows` (current local table count) beside `objectCount` (last run's
83
+ fetched count), so a caught-up sync no longer reads as an empty mirror.
84
+
85
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`90cd296`](https://github.com/usesocial/monorepo/commit/90cd2967a18a271337c54414466c5d89e66649d2) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Cursor-based syncs are resumable after rate limits and aborts.
86
+
87
+ Sync progress (page cursor and phase, including LinkedIn messages' two-phase
88
+ conversations→messages walk) is persisted after every stored page. When a
89
+ sync dies mid-run — most commonly a LinkedIn `/chats` 429 — the rate-limit
90
+ JSON now reports `syncResume.cursorPersisted: true` with `behavior: "resume"`,
91
+ and re-running the printed `retryCommand` continues from the saved cursor
92
+ instead of restarting and re-billing already-fetched pages. Resume only
93
+ applies to the same collection, account, and `--since` window; `--reset`
94
+ clears saved cursors; a clean completion replaces them with the normal
95
+ checkpoint.
96
+
97
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`90cd296`](https://github.com/usesocial/monorepo/commit/90cd2967a18a271337c54414466c5d89e66649d2) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Successful writes now update the local SQL mirror immediately.
98
+
99
+ - `social x message` inserts the sent DM into `x_messages` using the send
100
+ response (and upserts the recipient profile, so `counterpart_username`
101
+ resolves even for conversations where the other side has never replied).
102
+ - `social linkedin requests cancel` / `accept` remove the pending row from
103
+ `li_requests`; `requests send` inserts the new sent row.
104
+ - `social x bookmark` / `unbookmark` add and remove `x_bookmarks` rows.
105
+ - `social linkedin message` inserts into `li_messages` once that collection
106
+ has been synced.
107
+
108
+ Your own write is queryable via `sql` the moment the command succeeds — no
109
+ re-sync, and no `--reset` (which re-bills a collection's full history) just
110
+ to verify a send. Write-through only applies to collections that have been
111
+ synced at least once, and a mirror write failure never breaks a successful
112
+ command: it degrades to a stderr warning.
113
+
114
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`4824400`](https://github.com/usesocial/monorepo/commit/4824400ebcabb56f27f616418b0e62bc382c8fae) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Posting now updates the local SQL mirror immediately, like messages and
115
+ bookmarks already do.
116
+
117
+ - `social x post` inserts the created post into `x_tweets` from the send
118
+ response; `social x delete` removes the row.
119
+ - `social linkedin post` inserts into `li_posts` when the response carries a
120
+ usable post id (`post_id` or `id`); without one the mirror write is skipped
121
+ silently.
122
+
123
+ Rows are sparse until the next sync enriches them from upstream (engagement
124
+ counters arrive then). Same semantics as the existing write-throughs: only
125
+ applies once the collection has been synced at least once, and a mirror
126
+ failure degrades to a stderr warning without breaking the command.
127
+
128
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`b89c2f9`](https://github.com/usesocial/monorepo/commit/b89c2f96d1acc4dfe21b796a9332732fa60681b4) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - `liked` and `mentions` are now syncable X collections with local mirror twins.
129
+
130
+ - `social x sync liked` populates `x_liked`; `social x sync mentions`
131
+ populates `x_mentions`. Both are tweet-shaped (text, url, created_at, all
132
+ public metrics, author columns) and query free via `social x sql`.
133
+ - `mentions` supports `--since <ISO date>` for cheap incremental pulls;
134
+ `liked` does not (the upstream API has no time filter — re-syncs walk from
135
+ the newest like to the local checkpoint).
136
+ - Sync requests carry the full live-read field presets, so mirror rows land
137
+ with `created_at` and metrics populated from the first pull.
138
+ - `social x like <post>` inserts the post into `x_liked` immediately on
139
+ success and `unlike` removes it — no re-sync needed to see your own action,
140
+ once the collection has been synced at least once.
141
+
142
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`a902314`](https://github.com/usesocial/monorepo/commit/a9023144ca92f9cc87dd753239b572e6d0f3bfda) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - `social x post` now attaches media and creates native polls. Pipe the caption
143
+ on stdin as before, or omit it entirely when attaching media — text is optional
144
+ once media is present.
145
+
146
+ - `--media <path>` (repeatable) uploads local image/gif/video files via X's
147
+ chunked upload, then attaches them. X combinatorics apply: up to 4 images, OR
148
+ 1 gif, OR 1 video — no mixing.
149
+ - `--media-id <id>` (repeatable) attaches an already-uploaded media id, skipping
150
+ upload (useful for retries).
151
+ - `--poll-option <text>` (repeatable, 2–4) with `--poll-duration <minutes>`
152
+ (5–10080) creates a native poll. Mutually exclusive with media.
153
+ - `--reply-settings <following|mentionedUsers|subscribers|verified>` limits who
154
+ can reply.
155
+ - `--timeout <seconds>` sets the wait budget for video/gif processing
156
+ (default 300).
157
+ - `--reply-to <post>`, `--account <selector>`, and the `--body <JSON>` escape
158
+ hatch for long-tail post fields (media title/description, `tagged_user_ids`,
159
+ `quote_tweet_id`, `made_with_ai`, community, geo, nullcast) are restored for
160
+ `post`.
161
+
162
+ Uploading media is free; each finalized file costs a flat 15 credits at the
163
+ finalize step, independent of file size, on top of the normal post-create
164
+ credits.
165
+
166
+ Posting media requires the `media.write` OAuth scope. Existing connected X
167
+ accounts must run `social account reconnect x <account>` to gain it — OAuth
168
+ scope upgrades are not retroactive.
169
+
170
+ ### Patch Changes
171
+
172
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`90cd296`](https://github.com/usesocial/monorepo/commit/90cd2967a18a271337c54414466c5d89e66649d2) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - `social linkedin message <person>` starts new conversations again.
173
+
174
+ Person-target sends (profile URL, `@username`, `profile_id:<id>`, URN) were
175
+ rejected upstream after the provider's v2 migration. New chats now follow the
176
+ v2 inbox contract — the CLI resolves the person, discovers the LinkedIn
177
+ classic inbox, and starts the chat there. The command's contract models both
178
+ response shapes: `MessageSent` for existing-chat sends (`chat_id:<id>`),
179
+ `ChatStarted` (with the new `chat_id`) for first messages.
180
+
181
+ - [#35](https://github.com/usesocial/monorepo/pull/35) [`0dacb7f`](https://github.com/usesocial/monorepo/commit/0dacb7fadb59067787e167e8a3ae84fcde673fe7) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Internal: the profile write-through primitives (`upsertProfiles`,
182
+ `lookupProfiles`, `ProfileRow`) moved from `@usesocial/api/proxy` to
183
+ `@usesocial/db/profiles`; the proxy re-exports them unchanged. No CLI-visible
184
+ behavior change.
185
+
186
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`5a2e56e`](https://github.com/usesocial/monorepo/commit/5a2e56e7fbd4b27edc11990192639aa9404f19b1) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Report local SQLite cache auto-migrations in JSON output instead of stderr banners.
187
+ Breaking: all `social x sync...` and `social linkedin sync...` outputs now return
188
+ `{ data, meta }`; previous bare sync arrays and summary/reset objects now live
189
+ under `.data`, and migration details appear under `.meta.cache.migration` only
190
+ when a cache migration runs.
191
+
192
+ - [#34](https://github.com/usesocial/monorepo/pull/34) [`90cd296`](https://github.com/usesocial/monorepo/commit/90cd2967a18a271337c54414466c5d89e66649d2) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - X syncs request full field presets, and incremental message refreshes are
193
+ ~10x cheaper.
194
+
195
+ - `social x sync tweets` / `bookmarks` / `followers` / `following` now send
196
+ the same field presets as live reads, so mirror rows land with `created_at`
197
+ and `public_metrics` populated — previously the upstream returned minimal
198
+ objects and the documented own-content audit recipe (`like_count`,
199
+ `impression_count`, …) silently came back all-NULL. Mirrors synced before
200
+ this fix need one `--reset` re-pull to heal (metered).
201
+ - Sync summaries gain an additive `warnings[]`; a `fieldCompleteness` warning
202
+ fires if a page arrives missing expected fields, so silent starvation
203
+ cannot recur.
204
+ - Checkpointed `x sync messages` refreshes request small pages instead of
205
+ full 100-event pages, cutting a caught-up refresh from ~1,470 to ~150
206
+ credits. `stoppedReason: "checkpoint"` now carries a note explaining it
207
+ means "caught up: no new events since the last sync checkpoint".
208
+
3
209
  ## 0.8.0
4
210
 
5
211
  ### Minor Changes
package/README.md CHANGED
@@ -48,7 +48,7 @@ social x profile
48
48
  | "Surface the ten warm contacts worth reaching out to this week." | `linkedin search people`, `linkedin reactions`, `linkedin sql` |
49
49
  | "Pull everyone who reacted to my last LinkedIn post and flag the warm leads." | `linkedin posts <target>`, `linkedin reactions`, `linkedin profile` |
50
50
  | "Read this creator's recent posts and break down what makes them land." | `linkedin posts <target>`, `x tweets <target>` |
51
- | "Find what people are saying about AI agents this week and summarize the themes." | `linkedin search posts`, `x timeline` |
51
+ | "Find what people are saying about AI agents this week and summarize the themes." | `linkedin search posts`, `x sync timeline`, `x sql` |
52
52
  | "Triage my inbox and draft replies for approval." | `sync messages`, `sql`, `linkedin message`, `x message` |
53
53
  | "Draft a reply to this thread and post it once I approve." | `linkedin comment`, `x post` |
54
54
 
@@ -94,10 +94,12 @@ that local mirror; it is free, instant, and read-only. Named read commands call
94
94
  the live network and cost credits; `x tweets <target>` and
95
95
  `linkedin posts <target>` require a target. Writes act.
96
96
 
97
+ `sync` output is always `{ data, meta }`: bare `sync` lists collections under
98
+ `.data[]`, while collection summaries and `--reset` results live under `.data`.
97
99
  `sync <collection> --since 2026-05-04` (ISO date or datetime) pulls only newer
98
100
  items where the bare `sync` listing shows `supportsSince: true` — cheaper than a
99
- full re-pull. `sync <collection> --reset` clears a collection's local
100
- rows and sync state so the next sync rebuilds it.
101
+ full re-pull. `sync <collection> --reset` clears a collection's local rows and
102
+ sync state so the next sync rebuilds it.
101
103
  `sync <collection> --timeout 900` opts into a wall-clock wait budget, in seconds,
102
104
  for rate-limit handling. LinkedIn sync may sleep and retry while the next wait
103
105
  fits the budget; X keeps its current no-new-retry behavior.
@@ -159,7 +161,7 @@ profile lookup is needed.
159
161
  | `jobs <target>` | List a company's job postings. | |
160
162
  | `search people\|posts\|jobs\|companies <keywords>` | Search LinkedIn. | |
161
163
  | `sync [collection]` | Pull your own `connections`, `posts`, `messages`, or `requests` into the local mirror; costs credits. | local |
162
- | `sql [query]` | Query your synced local mirror with read-only SQL - free; bare `sql` prints compact schema metadata. | |
164
+ | `sql [query]` | Query your local mirror with read-only SQL - free; bare `sql` prints compact schema metadata. | |
163
165
  | `post` | Create a post (body from stdin). | write |
164
166
  | `comment <target>` | Comment on a post (body from stdin). | write |
165
167
  | `react <target>` | React to a post; use `--type` for non-like reactions. | write |
@@ -178,7 +180,6 @@ profile lookup is needed.
178
180
  | --- | --- | --- |
179
181
  | `profile [target]` | Fetch a profile; omit target for your own account. | |
180
182
  | `tweets <target>` | Live posts for a user; target required. | |
181
- | `timeline` | Read the home timeline. | |
182
183
  | `mentions [target]` | List posts mentioning a user; omit target for your own account. | |
183
184
  | `liked [target]` | List posts a user liked; omit target for your own account. | |
184
185
  | `followers [target]` | Live follower graph read; omit target for your own account. Costs credits. | |
@@ -188,8 +189,8 @@ profile lookup is needed.
188
189
  | `quotes <target>` | List quote posts of a post. | |
189
190
  | `likers <target>` | List users who liked a post. | |
190
191
  | `reposters <target>` | List users who reposted a post. | |
191
- | `sync [collection]` | Pull your own `tweets`, `followers`, `following`, `bookmarks`, or `messages` into the local mirror; costs credits. | local |
192
- | `sql [query]` | Query your synced local mirror with read-only SQL - free; bare `sql` prints compact schema metadata. | |
192
+ | `sync [collection]` | Pull your own `tweets`, `timeline`, `followers`, `following`, `bookmarks`, `liked`, `mentions`, or `messages` into the local mirror; costs credits. | local |
193
+ | `sql [query]` | Query your local mirror with read-only SQL - free; bare `sql` prints compact schema metadata. | |
193
194
  | `post` | Create a post (body from stdin). | write |
194
195
  | `message <recipients>` | Send a DM (body from stdin). | write |
195
196
  | `like <target>` / `unlike <target>` | Like or unlike a post. | write |
@@ -202,8 +203,9 @@ profile lookup is needed.
202
203
 
203
204
  - Everything speaks JSON: success on stdout, structured errors on stderr.
204
205
  - Platform reads return one envelope: lists use `.items[]`, single resources use
205
- `.data`, metadata lives under `.meta`. `social account` service commands return
206
- bare JSON; `account logs` returns `{ items, meta: { cursor } }`.
206
+ `.data`, metadata lives under `.meta`. Sync commands use `{ data, meta }`.
207
+ `social account` service commands return bare JSON; `account logs` returns
208
+ `{ items, meta: { cursor } }`.
207
209
  - Schema-backed planning: `social schema --list` is the compact runnable index.
208
210
  - Local SQL is the free surface for your own synced data.
209
211
 
@@ -268,12 +270,14 @@ social linkedin profile @username -H "Cache-Control: max-age=60"
268
270
  ```
269
271
 
270
272
  The local mirror is separate: run `sync` when you want newer local data, then
271
- query it with `sql`. SQL reads show local freshness in `meta.cache.tables`:
273
+ query it with `sql`. SQL reads show local freshness in `meta.cache.tables` and auto-upgrades in `meta.cache.migration` when a migration runs:
272
274
 
273
275
  ```sh
274
276
  social x sql "SELECT sender_username, text FROM x_messages ORDER BY created_at DESC LIMIT 5" \
275
277
  | jq '{cost: .meta.cost, cache: .meta.cache}'
276
- social x timeline --limit 20 | jq '{cost: .meta.cost, cursor: .meta.cursor, cache: .meta.cache}'
278
+ social x sync timeline
279
+ social x sql "SELECT text, url FROM x_timeline ORDER BY created_at DESC LIMIT 20" \
280
+ | jq '{cost: .meta.cost, cache: .meta.cache}'
277
281
  ```
278
282
 
279
283
  Agents should watch `.meta.cost` during high-fanout loops, use
@@ -300,11 +304,12 @@ social x sync messages
300
304
  social x sql "SELECT sender_username, text FROM x_messages ORDER BY created_at DESC LIMIT 20"
301
305
  social x sql "SELECT text, url FROM x_bookmarks ORDER BY created_at DESC LIMIT 50"
302
306
  social x sql "SELECT username, name, followers_count FROM x_followers ORDER BY followers_count DESC LIMIT 100"
307
+ social x sync timeline
308
+ social x sql "SELECT text, url FROM x_timeline ORDER BY created_at DESC LIMIT 50"
303
309
 
304
310
  # X live reads.
305
311
  social x tweets profile_id:<x-user-id> --limit 30
306
312
  social x replies post_id:<post-id> --limit 25
307
- social x timeline --limit 50
308
313
 
309
314
  # Writes (body via stdin).
310
315
  echo "gm" | social x post