@reepl/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -0
- package/dist/chunk-QSNFNE5Z.js +719 -0
- package/dist/chunk-QSNFNE5Z.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +982 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/index.d.ts +525 -0
- package/dist/core/index.js +57 -0
- package/dist/core/index.js.map +1 -0
- package/package.json +49 -0
- package/scripts/postinstall.mjs +56 -0
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical Reepl endpoints and auth identifiers.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the values the Reepl MCP server uses (reepl-mcp-server/wrangler.toml).
|
|
5
|
+
* The Cognito web-app client is a PUBLIC client (no secret) — safe to ship in a CLI.
|
|
6
|
+
*/
|
|
7
|
+
declare const REEPL_API_BASE_URL = "https://api.reepl.io/v1";
|
|
8
|
+
/** HTTP API v2 used only by unauthenticated carousel generation (userID in body). */
|
|
9
|
+
declare const REEPL_PUBLIC_API_BASE_URL = "https://4n7fgax35e.execute-api.eu-north-1.amazonaws.com/v1";
|
|
10
|
+
declare const COGNITO_DOMAIN = "https://auth.reepl.io";
|
|
11
|
+
/** Public Cognito app client (no secret) — the one the web app / MCP server refresh with. */
|
|
12
|
+
declare const COGNITO_WEB_APP_CLIENT_ID = "7np7fkkg920i4pqvgsmbct7bnn";
|
|
13
|
+
/** Web app that performs the login handoff and returns Cognito tokens. */
|
|
14
|
+
declare const REEPL_WEB_APP_URL = "https://app.reepl.io";
|
|
15
|
+
/** Path on the web app that brokers the token handoff for external clients. */
|
|
16
|
+
declare const MCP_CONNECT_PATH = "/mcp-connect";
|
|
17
|
+
/** Refresh the ID token this many ms before it actually expires. */
|
|
18
|
+
declare const TOKEN_REFRESH_BUFFER_MS: number;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Typed error hierarchy so both humans and agents can branch on a stable `code`.
|
|
22
|
+
*
|
|
23
|
+
* Every error carries a machine-readable `code` and a process `exitCode` the CLI maps
|
|
24
|
+
* straight to `process.exit`. Gating responses (plan/premium/reconnect) become distinct
|
|
25
|
+
* codes rather than an opaque HTTP 403.
|
|
26
|
+
*/
|
|
27
|
+
type ReeplErrorCode = "UNAUTHENTICATED" | "REFRESH_TOKEN_INVALID" | "PLAN_REQUIRED" | "PREMIUM_REQUIRED" | "RECONNECT_REQUIRED" | "MISSING_DM_SCOPES" | "GEMINI_NOT_LINKED" | "RATE_LIMITED" | "NOT_FOUND" | "VALIDATION" | "VERSION_CONFLICT" | "API_ERROR" | "NETWORK" | "CONFIG";
|
|
28
|
+
declare class ReeplError extends Error {
|
|
29
|
+
readonly code: ReeplErrorCode;
|
|
30
|
+
readonly status?: number;
|
|
31
|
+
readonly details?: unknown;
|
|
32
|
+
constructor(code: ReeplErrorCode, message: string, opts?: {
|
|
33
|
+
status?: number;
|
|
34
|
+
details?: unknown;
|
|
35
|
+
cause?: unknown;
|
|
36
|
+
});
|
|
37
|
+
get exitCode(): number;
|
|
38
|
+
toJSON(): {
|
|
39
|
+
status?: number | undefined;
|
|
40
|
+
code: ReeplErrorCode;
|
|
41
|
+
message: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Map a raw backend error payload + HTTP status onto a typed ReeplError.
|
|
46
|
+
*
|
|
47
|
+
* The backend is inconsistent about where the machine code lives (`code`, `error`,
|
|
48
|
+
* `errorCode`), so we probe a few shapes and fall back to status-based classification.
|
|
49
|
+
*/
|
|
50
|
+
declare function parseApiError(status: number, raw: string): ReeplError;
|
|
51
|
+
|
|
52
|
+
/** Persisted Cognito token set. `expiresAt` is epoch ms for the ID token. */
|
|
53
|
+
interface StoredTokens {
|
|
54
|
+
idToken: string;
|
|
55
|
+
refreshToken: string;
|
|
56
|
+
accessToken?: string;
|
|
57
|
+
expiresAt: number;
|
|
58
|
+
}
|
|
59
|
+
/** Storage-agnostic token persistence. The CLI supplies a file/keychain-backed impl. */
|
|
60
|
+
interface TokenStore {
|
|
61
|
+
load(): Promise<StoredTokens | null>;
|
|
62
|
+
save(tokens: StoredTokens): Promise<void>;
|
|
63
|
+
clear(): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
66
|
+
interface RequestOptions {
|
|
67
|
+
method: HttpMethod;
|
|
68
|
+
path: string;
|
|
69
|
+
query?: Record<string, string | number | boolean | undefined | null>;
|
|
70
|
+
body?: unknown;
|
|
71
|
+
/** Attach the Bearer token. Default true. */
|
|
72
|
+
auth?: boolean;
|
|
73
|
+
/** Which gateway to hit. Default "api" (Cognito REST). */
|
|
74
|
+
base?: "api" | "public";
|
|
75
|
+
/**
|
|
76
|
+
* Workspace to scope the call to. When provided, it is placed as a query param for
|
|
77
|
+
* GET/DELETE and as a body field for POST/PUT/PATCH — matching backend convention.
|
|
78
|
+
* Pass `null` to explicitly omit even the client default.
|
|
79
|
+
*/
|
|
80
|
+
workspace?: string | null;
|
|
81
|
+
}
|
|
82
|
+
/** Minimal shape of the account profile we rely on for `whoami` + gating hints. */
|
|
83
|
+
interface AccountProfile {
|
|
84
|
+
userID?: string;
|
|
85
|
+
email?: string;
|
|
86
|
+
name?: string;
|
|
87
|
+
subscriptionType?: string;
|
|
88
|
+
subscription_status?: {
|
|
89
|
+
hasActivePurchase?: boolean;
|
|
90
|
+
status?: string;
|
|
91
|
+
};
|
|
92
|
+
credits_available?: number;
|
|
93
|
+
[key: string]: unknown;
|
|
94
|
+
}
|
|
95
|
+
interface Workspace {
|
|
96
|
+
id: string;
|
|
97
|
+
name?: string;
|
|
98
|
+
isDefault?: boolean;
|
|
99
|
+
[key: string]: unknown;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
interface ReeplClientOptions {
|
|
103
|
+
/** Returns a valid ID token. Usually TokenManager.getIdToken bound. */
|
|
104
|
+
getToken: () => Promise<string>;
|
|
105
|
+
/** Default workspace injected into every scoped call unless overridden per-request. */
|
|
106
|
+
workspaceId?: string | null;
|
|
107
|
+
apiBaseUrl?: string;
|
|
108
|
+
publicBaseUrl?: string;
|
|
109
|
+
fetchImpl?: typeof fetch;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Thin, typed HTTP client for the Reepl backend. All endpoint modules build on `request`.
|
|
113
|
+
* This is the single place that knows about auth headers, workspace placement, and error
|
|
114
|
+
* normalization — the reusable heart of api-core.
|
|
115
|
+
*/
|
|
116
|
+
declare class ReeplClient {
|
|
117
|
+
private getToken;
|
|
118
|
+
private workspaceId;
|
|
119
|
+
private apiBaseUrl;
|
|
120
|
+
private publicBaseUrl;
|
|
121
|
+
private fetchImpl;
|
|
122
|
+
constructor(opts: ReeplClientOptions);
|
|
123
|
+
request<T = unknown>(opts: RequestOptions): Promise<T>;
|
|
124
|
+
get<T = unknown>(path: string, opts?: Omit<RequestOptions, "method" | "path">): Promise<T>;
|
|
125
|
+
post<T = unknown>(path: string, opts?: Omit<RequestOptions, "method" | "path">): Promise<T>;
|
|
126
|
+
put<T = unknown>(path: string, opts?: Omit<RequestOptions, "method" | "path">): Promise<T>;
|
|
127
|
+
delete<T = unknown>(path: string, opts?: Omit<RequestOptions, "method" | "path">): Promise<T>;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
interface TokenManagerOptions {
|
|
131
|
+
clientId?: string;
|
|
132
|
+
cognitoDomain?: string;
|
|
133
|
+
bufferMs?: number;
|
|
134
|
+
fetchImpl?: typeof fetch;
|
|
135
|
+
/** For deterministic tests. Defaults to Date.now. */
|
|
136
|
+
now?: () => number;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Returns a valid ID token, refreshing (and persisting) it when it is within the expiry
|
|
140
|
+
* buffer. Storage-agnostic: it delegates load/save to the injected TokenStore, so the CLI
|
|
141
|
+
* can back it with a file or OS keychain while core stays portable.
|
|
142
|
+
*/
|
|
143
|
+
declare class TokenManager {
|
|
144
|
+
private store;
|
|
145
|
+
private opts;
|
|
146
|
+
private inflight;
|
|
147
|
+
constructor(store: TokenStore, opts?: TokenManagerOptions);
|
|
148
|
+
private now;
|
|
149
|
+
/** Get a valid ID token or throw UNAUTHENTICATED if there are no stored credentials. */
|
|
150
|
+
getIdToken(): Promise<string>;
|
|
151
|
+
private resolveToken;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
interface RefreshResult {
|
|
155
|
+
idToken: string;
|
|
156
|
+
accessToken?: string;
|
|
157
|
+
/** Seconds until the new ID token expires. */
|
|
158
|
+
expiresIn: number;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Decode a JWT payload without verifying the signature (we only need `exp`/claims,
|
|
162
|
+
* verification is the backend's job). Returns null on any malformed token.
|
|
163
|
+
*/
|
|
164
|
+
declare function decodeJwt(token: string): Record<string, unknown> | null;
|
|
165
|
+
/** Epoch ms at which this ID token expires, or null if it has no `exp`. */
|
|
166
|
+
declare function jwtExpiryMs(token: string): number | null;
|
|
167
|
+
/**
|
|
168
|
+
* Exchange a Cognito refresh token for a fresh ID/access token via the public app client.
|
|
169
|
+
* Mirrors the MCP server's getValidIdToken refresh call (no Basic auth — public client).
|
|
170
|
+
*/
|
|
171
|
+
declare function refreshIdToken(refreshToken: string, opts?: {
|
|
172
|
+
clientId?: string;
|
|
173
|
+
cognitoDomain?: string;
|
|
174
|
+
fetchImpl?: typeof fetch;
|
|
175
|
+
}): Promise<RefreshResult>;
|
|
176
|
+
|
|
177
|
+
/** GET /account/profile — current authenticated user. */
|
|
178
|
+
declare function getProfile(client: ReeplClient): Promise<AccountProfile>;
|
|
179
|
+
/** Coarse paid/free signal derived from the profile, for gating hints in `whoami`. */
|
|
180
|
+
declare function hasActivePlan(profile: AccountProfile): boolean;
|
|
181
|
+
|
|
182
|
+
declare const profile_getProfile: typeof getProfile;
|
|
183
|
+
declare const profile_hasActivePlan: typeof hasActivePlan;
|
|
184
|
+
declare namespace profile {
|
|
185
|
+
export { profile_getProfile as getProfile, profile_hasActivePlan as hasActivePlan };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* GET /organizations — list the user's workspaces (Cognito "organizations").
|
|
190
|
+
* Field names vary across the backend (organisationID/organization_id/id), so we
|
|
191
|
+
* normalize to a stable {id,name,isDefault} shape and flag the default.
|
|
192
|
+
*/
|
|
193
|
+
declare function listWorkspaces(client: ReeplClient): Promise<Workspace[]>;
|
|
194
|
+
/** Resolve the default workspace id (or null if none is marked). */
|
|
195
|
+
declare function getDefaultWorkspaceId(client: ReeplClient): Promise<string | null>;
|
|
196
|
+
|
|
197
|
+
declare const workspaces_getDefaultWorkspaceId: typeof getDefaultWorkspaceId;
|
|
198
|
+
declare const workspaces_listWorkspaces: typeof listWorkspaces;
|
|
199
|
+
declare namespace workspaces {
|
|
200
|
+
export { workspaces_getDefaultWorkspaceId as getDefaultWorkspaceId, workspaces_listWorkspaces as listWorkspaces };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
interface DraftInput {
|
|
204
|
+
content: string;
|
|
205
|
+
title?: string;
|
|
206
|
+
mediaUrls?: string[];
|
|
207
|
+
tags?: string[];
|
|
208
|
+
}
|
|
209
|
+
interface ScheduleInput {
|
|
210
|
+
content: string;
|
|
211
|
+
/** ISO-8601 timestamp. */
|
|
212
|
+
scheduledFor: string;
|
|
213
|
+
title?: string;
|
|
214
|
+
mediaUrls?: string[];
|
|
215
|
+
}
|
|
216
|
+
/** POST /post/drafts — create a LinkedIn post draft. */
|
|
217
|
+
declare function createDraft$2(client: ReeplClient, input: DraftInput): Promise<unknown>;
|
|
218
|
+
/** GET /post/drafts — list drafts. */
|
|
219
|
+
declare function listDrafts$2(client: ReeplClient, opts?: {
|
|
220
|
+
limit?: number;
|
|
221
|
+
search?: string;
|
|
222
|
+
sortOrder?: string;
|
|
223
|
+
}): Promise<unknown>;
|
|
224
|
+
/** PUT /post/drafts — update a draft by id. */
|
|
225
|
+
declare function updateDraft$1(client: ReeplClient, draftId: string, patch: Partial<DraftInput>): Promise<unknown>;
|
|
226
|
+
/** DELETE /post/drafts?draftId= */
|
|
227
|
+
declare function deleteDraft$2(client: ReeplClient, draftId: string): Promise<unknown>;
|
|
228
|
+
/** POST /linkedin/posts — publish immediately. */
|
|
229
|
+
declare function publishNow(client: ReeplClient, input: DraftInput): Promise<unknown>;
|
|
230
|
+
/** POST /linkedin/posts/schedule — schedule for a future time. */
|
|
231
|
+
declare function schedulePost(client: ReeplClient, input: ScheduleInput): Promise<unknown>;
|
|
232
|
+
/** GET /linkedin/posts?status= — list published/scheduled/failed posts. */
|
|
233
|
+
declare function listPosts$1(client: ReeplClient, opts?: {
|
|
234
|
+
status?: "scheduled" | "published" | "failed" | "all";
|
|
235
|
+
limit?: number;
|
|
236
|
+
search?: string;
|
|
237
|
+
nextToken?: string;
|
|
238
|
+
userId?: string;
|
|
239
|
+
}): Promise<unknown>;
|
|
240
|
+
/** PUT /linkedin/posts/{id}/schedule — reschedule (also used for publish-now = now). */
|
|
241
|
+
declare function updateScheduledPost(client: ReeplClient, postId: string, patch: {
|
|
242
|
+
content?: string;
|
|
243
|
+
scheduledFor?: string;
|
|
244
|
+
mediaUrls?: string[];
|
|
245
|
+
}): Promise<unknown>;
|
|
246
|
+
/** DELETE /linkedin/posts/{id} */
|
|
247
|
+
declare function deletePost$1(client: ReeplClient, postId: string): Promise<unknown>;
|
|
248
|
+
/**
|
|
249
|
+
* POST /linkedin/posts/{id}/comments — comment on a LinkedIn post.
|
|
250
|
+
* NOTE: `postId` is Reepl's internal post id (resolved via the postId-index GSI), NOT a
|
|
251
|
+
* public LinkedIn activity URL. Only posts published/tracked through Reepl are commentable
|
|
252
|
+
* via this API; arbitrary public LinkedIn URLs are not addressable here.
|
|
253
|
+
*/
|
|
254
|
+
declare function addComment(client: ReeplClient, postId: string, commentText: string): Promise<unknown>;
|
|
255
|
+
|
|
256
|
+
type linkedin_DraftInput = DraftInput;
|
|
257
|
+
type linkedin_ScheduleInput = ScheduleInput;
|
|
258
|
+
declare const linkedin_addComment: typeof addComment;
|
|
259
|
+
declare const linkedin_publishNow: typeof publishNow;
|
|
260
|
+
declare const linkedin_schedulePost: typeof schedulePost;
|
|
261
|
+
declare const linkedin_updateScheduledPost: typeof updateScheduledPost;
|
|
262
|
+
declare namespace linkedin {
|
|
263
|
+
export { type linkedin_DraftInput as DraftInput, type linkedin_ScheduleInput as ScheduleInput, linkedin_addComment as addComment, createDraft$2 as createDraft, deleteDraft$2 as deleteDraft, deletePost$1 as deletePost, listDrafts$2 as listDrafts, listPosts$1 as listPosts, linkedin_publishNow as publishNow, linkedin_schedulePost as schedulePost, updateDraft$1 as updateDraft, linkedin_updateScheduledPost as updateScheduledPost };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
interface Tweet {
|
|
267
|
+
text: string;
|
|
268
|
+
mediaUrls?: string[];
|
|
269
|
+
}
|
|
270
|
+
interface TwitterPostInput {
|
|
271
|
+
/** One entry per tweet in the thread. A single tweet = a one-element array. */
|
|
272
|
+
threadTweets: Tweet[];
|
|
273
|
+
scheduledFor?: string;
|
|
274
|
+
quoteTweetId?: string;
|
|
275
|
+
linkedPostId?: string;
|
|
276
|
+
}
|
|
277
|
+
/** POST /twitter/posts — create/schedule a tweet or thread. `twitter_create_post` is paid-gated. */
|
|
278
|
+
declare function createPost(client: ReeplClient, input: TwitterPostInput): Promise<unknown>;
|
|
279
|
+
/** GET /twitter/posts?status= */
|
|
280
|
+
declare function listPosts(client: ReeplClient, opts?: {
|
|
281
|
+
status?: string;
|
|
282
|
+
limit?: number;
|
|
283
|
+
search?: string;
|
|
284
|
+
nextToken?: string;
|
|
285
|
+
}): Promise<unknown>;
|
|
286
|
+
/** PUT /twitter/posts/{id} */
|
|
287
|
+
declare function updatePost(client: ReeplClient, postId: string, patch: Partial<TwitterPostInput>): Promise<unknown>;
|
|
288
|
+
/** DELETE /twitter/posts/{id} */
|
|
289
|
+
declare function deletePost(client: ReeplClient, postId: string): Promise<unknown>;
|
|
290
|
+
/** POST /twitter/drafts — create a draft tweet/thread. */
|
|
291
|
+
declare function createDraft$1(client: ReeplClient, input: TwitterPostInput & {
|
|
292
|
+
title?: string;
|
|
293
|
+
}): Promise<unknown>;
|
|
294
|
+
/** GET /twitter/drafts */
|
|
295
|
+
declare function listDrafts$1(client: ReeplClient, opts?: {
|
|
296
|
+
limit?: number;
|
|
297
|
+
search?: string;
|
|
298
|
+
}): Promise<unknown>;
|
|
299
|
+
/** DELETE /twitter/drafts?draftId= */
|
|
300
|
+
declare function deleteDraft$1(client: ReeplClient, draftId: string): Promise<unknown>;
|
|
301
|
+
/**
|
|
302
|
+
* POST /twitter/engagement/reply — publish a reply to a tweet by id.
|
|
303
|
+
* Premium-gated; costs engagement credits. Works for any tweet id (extractable from a URL).
|
|
304
|
+
*/
|
|
305
|
+
declare function reply(client: ReeplClient, tweetId: string, text: string): Promise<unknown>;
|
|
306
|
+
|
|
307
|
+
type twitter_Tweet = Tweet;
|
|
308
|
+
type twitter_TwitterPostInput = TwitterPostInput;
|
|
309
|
+
declare const twitter_createPost: typeof createPost;
|
|
310
|
+
declare const twitter_deletePost: typeof deletePost;
|
|
311
|
+
declare const twitter_listPosts: typeof listPosts;
|
|
312
|
+
declare const twitter_reply: typeof reply;
|
|
313
|
+
declare const twitter_updatePost: typeof updatePost;
|
|
314
|
+
declare namespace twitter {
|
|
315
|
+
export { type twitter_Tweet as Tweet, type twitter_TwitterPostInput as TwitterPostInput, createDraft$1 as createDraft, twitter_createPost as createPost, deleteDraft$1 as deleteDraft, twitter_deletePost as deletePost, listDrafts$1 as listDrafts, twitter_listPosts as listPosts, twitter_reply as reply, twitter_updatePost as updatePost };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
interface ScheduledItem {
|
|
319
|
+
platform: "linkedin" | "x";
|
|
320
|
+
id: string;
|
|
321
|
+
scheduledFor?: string;
|
|
322
|
+
status?: string;
|
|
323
|
+
content: string;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Aggregate the content calendar (scheduled posts) across LinkedIn and X. There is no
|
|
327
|
+
* dedicated calendar endpoint — it is built from each platform's scheduled feed.
|
|
328
|
+
* X errors (e.g. account not connected) are swallowed so LinkedIn still renders.
|
|
329
|
+
*/
|
|
330
|
+
declare function getSchedule(client: ReeplClient, opts?: {
|
|
331
|
+
platform?: "linkedin" | "x" | "all";
|
|
332
|
+
limit?: number;
|
|
333
|
+
}): Promise<ScheduledItem[]>;
|
|
334
|
+
|
|
335
|
+
type calendar_ScheduledItem = ScheduledItem;
|
|
336
|
+
declare const calendar_getSchedule: typeof getSchedule;
|
|
337
|
+
declare namespace calendar {
|
|
338
|
+
export { type calendar_ScheduledItem as ScheduledItem, calendar_getSchedule as getSchedule };
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* GET /reddit/discovery/search?keyword= — on-demand Reddit keyword discovery.
|
|
343
|
+
* Pro-gated (403 UPGRADE_REQUIRED -> PLAN_REQUIRED); rate-limited per user.
|
|
344
|
+
*/
|
|
345
|
+
declare function search(client: ReeplClient, keyword: string): Promise<unknown>;
|
|
346
|
+
/** GET /reddit/discovery/status — remaining search quota / status. */
|
|
347
|
+
declare function searchStatus(client: ReeplClient): Promise<unknown>;
|
|
348
|
+
/**
|
|
349
|
+
* POST /reddit/comment — comment on (reply to) a Reddit submission.
|
|
350
|
+
* `postId` may be a bare id or a `t3_`-prefixed thing id (backend normalizes).
|
|
351
|
+
* No plan gate; requires a connected Reddit integration (403 reddit_not_connected).
|
|
352
|
+
*/
|
|
353
|
+
declare function comment(client: ReeplClient, postId: string, text: string): Promise<unknown>;
|
|
354
|
+
|
|
355
|
+
declare const reddit_comment: typeof comment;
|
|
356
|
+
declare const reddit_search: typeof search;
|
|
357
|
+
declare const reddit_searchStatus: typeof searchStatus;
|
|
358
|
+
declare namespace reddit {
|
|
359
|
+
export { reddit_comment as comment, reddit_search as search, reddit_searchStatus as searchStatus };
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* GET /signals — the user's personalized signals inbox (Reddit / YouTube / RSS / trends).
|
|
364
|
+
* NOTE: the route is `/signals`, not `/signals/inbox`. The live MCP server calls
|
|
365
|
+
* `/signals/inbox`, but that route isn't Cognito-authorized (AWS returns an auth-header
|
|
366
|
+
* error) and the MCP tool silently reports "no signals" — verified against the live API.
|
|
367
|
+
*/
|
|
368
|
+
declare function getInbox(client: ReeplClient): Promise<unknown>;
|
|
369
|
+
|
|
370
|
+
declare const signals_getInbox: typeof getInbox;
|
|
371
|
+
declare namespace signals {
|
|
372
|
+
export { signals_getInbox as getInbox };
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
interface SlideInput {
|
|
376
|
+
headline?: string;
|
|
377
|
+
title?: string;
|
|
378
|
+
body?: string;
|
|
379
|
+
content?: string;
|
|
380
|
+
layout?: string;
|
|
381
|
+
layoutType?: string;
|
|
382
|
+
}
|
|
383
|
+
/** Map user-facing slide shapes to the backend `carousels[]` item shape. */
|
|
384
|
+
declare function mapSlides(slides: SlideInput[]): Array<Record<string, unknown>>;
|
|
385
|
+
/** GET /carousel/drafts — list drafts. */
|
|
386
|
+
declare function listDrafts(client: ReeplClient, opts?: {
|
|
387
|
+
limit?: number;
|
|
388
|
+
search?: string;
|
|
389
|
+
}): Promise<unknown>;
|
|
390
|
+
/** GET /carousel/drafts?draftId= — get a single draft. */
|
|
391
|
+
declare function getDraft(client: ReeplClient, draftId: string): Promise<unknown>;
|
|
392
|
+
interface CarouselDraftInput {
|
|
393
|
+
title: string;
|
|
394
|
+
slides: SlideInput[];
|
|
395
|
+
theme?: string;
|
|
396
|
+
titleFontSize?: string;
|
|
397
|
+
bodyFontSize?: string;
|
|
398
|
+
}
|
|
399
|
+
/** POST /carousel/drafts — create a carousel draft. */
|
|
400
|
+
declare function createDraft(client: ReeplClient, input: CarouselDraftInput): Promise<unknown>;
|
|
401
|
+
interface CarouselUpdateInput {
|
|
402
|
+
title?: string;
|
|
403
|
+
slides?: SlideInput[];
|
|
404
|
+
theme?: string;
|
|
405
|
+
titleFontSize?: string;
|
|
406
|
+
bodyFontSize?: string;
|
|
407
|
+
}
|
|
408
|
+
/** PUT /carousel/drafts — update a draft. Only provided fields change. */
|
|
409
|
+
declare function updateDraft(client: ReeplClient, draftId: string, patch: CarouselUpdateInput): Promise<unknown>;
|
|
410
|
+
/** DELETE /carousel/drafts?draftId= */
|
|
411
|
+
declare function deleteDraft(client: ReeplClient, draftId: string): Promise<unknown>;
|
|
412
|
+
interface GenerateInput {
|
|
413
|
+
topic?: string;
|
|
414
|
+
url?: string;
|
|
415
|
+
numberOfSlides?: number;
|
|
416
|
+
aiInstructions?: string;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* POST /carousel (public HTTP API) — AI-generate slides. Unauthenticated: the caller's
|
|
420
|
+
* userID goes in the body. Returns generated slides (not a saved draft).
|
|
421
|
+
*/
|
|
422
|
+
declare function generate(client: ReeplClient, userID: string, input: GenerateInput): Promise<unknown>;
|
|
423
|
+
|
|
424
|
+
type carousel_CarouselDraftInput = CarouselDraftInput;
|
|
425
|
+
type carousel_CarouselUpdateInput = CarouselUpdateInput;
|
|
426
|
+
type carousel_GenerateInput = GenerateInput;
|
|
427
|
+
type carousel_SlideInput = SlideInput;
|
|
428
|
+
declare const carousel_createDraft: typeof createDraft;
|
|
429
|
+
declare const carousel_deleteDraft: typeof deleteDraft;
|
|
430
|
+
declare const carousel_generate: typeof generate;
|
|
431
|
+
declare const carousel_getDraft: typeof getDraft;
|
|
432
|
+
declare const carousel_listDrafts: typeof listDrafts;
|
|
433
|
+
declare const carousel_mapSlides: typeof mapSlides;
|
|
434
|
+
declare const carousel_updateDraft: typeof updateDraft;
|
|
435
|
+
declare namespace carousel {
|
|
436
|
+
export { type carousel_CarouselDraftInput as CarouselDraftInput, type carousel_CarouselUpdateInput as CarouselUpdateInput, type carousel_GenerateInput as GenerateInput, type carousel_SlideInput as SlideInput, carousel_createDraft as createDraft, carousel_deleteDraft as deleteDraft, carousel_generate as generate, carousel_getDraft as getDraft, carousel_listDrafts as listDrafts, carousel_mapSlides as mapSlides, carousel_updateDraft as updateDraft };
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/** Facets are plural in the backend: posts | comments | messages (singular is normalized). */
|
|
440
|
+
type StyleFacet = "posts" | "comments" | "messages";
|
|
441
|
+
/** GET /writing-style — summary of all facets + visibility. Requires workspace_id. */
|
|
442
|
+
declare function get$1(client: ReeplClient): Promise<unknown>;
|
|
443
|
+
/** POST /writing-style/override — save per-facet override instructions. */
|
|
444
|
+
declare function override(client: ReeplClient, facet: string, instructions: string): Promise<unknown>;
|
|
445
|
+
/** POST /writing-style/visibility — set visibility. */
|
|
446
|
+
declare function setVisibility(client: ReeplClient, visibility: string): Promise<unknown>;
|
|
447
|
+
/** POST /writing-style/train — (re)synthesize a facet's style. Pro+; posts/comments only. */
|
|
448
|
+
declare function train(client: ReeplClient, facet: string): Promise<unknown>;
|
|
449
|
+
/** POST /ai/test-voice-style — faceted playground: baseline vs styled generation. */
|
|
450
|
+
declare function testVoiceStyle(client: ReeplClient, facet: string, input: string): Promise<unknown>;
|
|
451
|
+
|
|
452
|
+
type writingStyle_StyleFacet = StyleFacet;
|
|
453
|
+
declare const writingStyle_override: typeof override;
|
|
454
|
+
declare const writingStyle_setVisibility: typeof setVisibility;
|
|
455
|
+
declare const writingStyle_testVoiceStyle: typeof testVoiceStyle;
|
|
456
|
+
declare const writingStyle_train: typeof train;
|
|
457
|
+
declare namespace writingStyle {
|
|
458
|
+
export { type writingStyle_StyleFacet as StyleFacet, get$1 as get, writingStyle_override as override, writingStyle_setVisibility as setVisibility, writingStyle_testVoiceStyle as testVoiceStyle, writingStyle_train as train };
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/** GET /profile/voice-profile — current user's voice profile. */
|
|
462
|
+
declare function get(client: ReeplClient): Promise<{
|
|
463
|
+
voiceProfile?: unknown;
|
|
464
|
+
hasProfile?: boolean;
|
|
465
|
+
}>;
|
|
466
|
+
/**
|
|
467
|
+
* PUT /profile/voice-profile — deep-merge update. Body may include allowAutoUpdate,
|
|
468
|
+
* isActive, userInstructions{...}, generatedProfile{...}, positioningProfile{...}.
|
|
469
|
+
*/
|
|
470
|
+
declare function update(client: ReeplClient, body: Record<string, unknown>): Promise<unknown>;
|
|
471
|
+
|
|
472
|
+
declare const voice_get: typeof get;
|
|
473
|
+
declare const voice_update: typeof update;
|
|
474
|
+
declare namespace voice {
|
|
475
|
+
export { voice_get as get, voice_update as update };
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* X (Twitter) DM inbox. All write/refresh operations are Premium-gated
|
|
480
|
+
* (403 UPGRADE_REQUIRED). Note: the conversation id in the path is the participant's X
|
|
481
|
+
* user id, which is what both the read and send endpoints expect.
|
|
482
|
+
*/
|
|
483
|
+
/** POST /inbox/twitter/refresh — pull the latest DM events from X (Premium). */
|
|
484
|
+
declare function refresh(client: ReeplClient): Promise<unknown>;
|
|
485
|
+
/** GET /inbox/twitter/refresh-status — throttle / last-refresh status. */
|
|
486
|
+
declare function refreshStatus(client: ReeplClient): Promise<unknown>;
|
|
487
|
+
/** GET /inbox/twitter/conversations — cached conversation list. */
|
|
488
|
+
declare function listConversations(client: ReeplClient, opts?: {
|
|
489
|
+
limit?: number;
|
|
490
|
+
offset?: number;
|
|
491
|
+
}): Promise<unknown>;
|
|
492
|
+
/** GET /inbox/twitter/conversations/{id}/messages — messages in one conversation. */
|
|
493
|
+
declare function getMessages(client: ReeplClient, conversationId: string): Promise<unknown>;
|
|
494
|
+
/**
|
|
495
|
+
* POST /inbox/twitter/conversations/{participantId}/messages — send/reply in a DM thread
|
|
496
|
+
* (Premium; costs credits). `participantId` is the conversation id from listConversations.
|
|
497
|
+
*/
|
|
498
|
+
declare function sendMessage(client: ReeplClient, participantId: string, text: string): Promise<unknown>;
|
|
499
|
+
|
|
500
|
+
declare const dms_getMessages: typeof getMessages;
|
|
501
|
+
declare const dms_listConversations: typeof listConversations;
|
|
502
|
+
declare const dms_refresh: typeof refresh;
|
|
503
|
+
declare const dms_refreshStatus: typeof refreshStatus;
|
|
504
|
+
declare const dms_sendMessage: typeof sendMessage;
|
|
505
|
+
declare namespace dms {
|
|
506
|
+
export { dms_getMessages as getMessages, dms_listConversations as listConversations, dms_refresh as refresh, dms_refreshStatus as refreshStatus, dms_sendMessage as sendMessage };
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Resolve a post reference (URL or raw id) to a platform + addressable id.
|
|
511
|
+
* Used by `comment add` to route to the right endpoint from a single --url/--post arg.
|
|
512
|
+
*/
|
|
513
|
+
type PostPlatform = "linkedin" | "x" | "reddit";
|
|
514
|
+
interface PostRef {
|
|
515
|
+
platform: PostPlatform;
|
|
516
|
+
/** The id passed to the platform's comment/reply endpoint. */
|
|
517
|
+
id: string;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Resolve a reference. `hint` forces a platform when the input is ambiguous (bare id).
|
|
521
|
+
* Throws with actionable guidance when it can't be resolved.
|
|
522
|
+
*/
|
|
523
|
+
declare function resolvePostRef(input: string, hint?: PostPlatform): PostRef;
|
|
524
|
+
|
|
525
|
+
export { type AccountProfile, COGNITO_DOMAIN, COGNITO_WEB_APP_CLIENT_ID, type CarouselDraftInput, type CarouselUpdateInput, type HttpMethod, MCP_CONNECT_PATH, type PostPlatform, type PostRef, REEPL_API_BASE_URL, REEPL_PUBLIC_API_BASE_URL, REEPL_WEB_APP_URL, ReeplClient, type ReeplClientOptions, ReeplError, type ReeplErrorCode, type RefreshResult, type RequestOptions, type ScheduledItem, type SlideInput, type StoredTokens, type StyleFacet, TOKEN_REFRESH_BUFFER_MS, TokenManager, type TokenManagerOptions, type TokenStore, type Workspace, calendar, carousel, decodeJwt, dms, jwtExpiryMs, linkedin, parseApiError, profile, reddit, refreshIdToken, resolvePostRef, signals, twitter, voice, workspaces, writingStyle };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {
|
|
2
|
+
COGNITO_DOMAIN,
|
|
3
|
+
COGNITO_WEB_APP_CLIENT_ID,
|
|
4
|
+
MCP_CONNECT_PATH,
|
|
5
|
+
REEPL_API_BASE_URL,
|
|
6
|
+
REEPL_PUBLIC_API_BASE_URL,
|
|
7
|
+
REEPL_WEB_APP_URL,
|
|
8
|
+
ReeplClient,
|
|
9
|
+
ReeplError,
|
|
10
|
+
TOKEN_REFRESH_BUFFER_MS,
|
|
11
|
+
TokenManager,
|
|
12
|
+
calendar_exports,
|
|
13
|
+
carousel_exports,
|
|
14
|
+
decodeJwt,
|
|
15
|
+
dms_exports,
|
|
16
|
+
jwtExpiryMs,
|
|
17
|
+
linkedin_exports,
|
|
18
|
+
parseApiError,
|
|
19
|
+
profile_exports,
|
|
20
|
+
reddit_exports,
|
|
21
|
+
refreshIdToken,
|
|
22
|
+
resolvePostRef,
|
|
23
|
+
signals_exports,
|
|
24
|
+
twitter_exports,
|
|
25
|
+
voice_exports,
|
|
26
|
+
workspaces_exports,
|
|
27
|
+
writingStyle_exports
|
|
28
|
+
} from "../chunk-QSNFNE5Z.js";
|
|
29
|
+
export {
|
|
30
|
+
COGNITO_DOMAIN,
|
|
31
|
+
COGNITO_WEB_APP_CLIENT_ID,
|
|
32
|
+
MCP_CONNECT_PATH,
|
|
33
|
+
REEPL_API_BASE_URL,
|
|
34
|
+
REEPL_PUBLIC_API_BASE_URL,
|
|
35
|
+
REEPL_WEB_APP_URL,
|
|
36
|
+
ReeplClient,
|
|
37
|
+
ReeplError,
|
|
38
|
+
TOKEN_REFRESH_BUFFER_MS,
|
|
39
|
+
TokenManager,
|
|
40
|
+
calendar_exports as calendar,
|
|
41
|
+
carousel_exports as carousel,
|
|
42
|
+
decodeJwt,
|
|
43
|
+
dms_exports as dms,
|
|
44
|
+
jwtExpiryMs,
|
|
45
|
+
linkedin_exports as linkedin,
|
|
46
|
+
parseApiError,
|
|
47
|
+
profile_exports as profile,
|
|
48
|
+
reddit_exports as reddit,
|
|
49
|
+
refreshIdToken,
|
|
50
|
+
resolvePostRef,
|
|
51
|
+
signals_exports as signals,
|
|
52
|
+
twitter_exports as twitter,
|
|
53
|
+
voice_exports as voice,
|
|
54
|
+
workspaces_exports as workspaces,
|
|
55
|
+
writingStyle_exports as writingStyle
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reepl/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Reepl command-line interface — create, schedule, and manage LinkedIn / X / Reddit content, carousels, signals, DMs, and writing styles.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"reepl": "dist/cli/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"scripts/postinstall.mjs"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup",
|
|
18
|
+
"dev": "tsup --watch",
|
|
19
|
+
"test": "vitest run --project unit",
|
|
20
|
+
"test:unit": "vitest run --project unit",
|
|
21
|
+
"test:e2e": "vitest run --project e2e",
|
|
22
|
+
"test:all": "vitest run",
|
|
23
|
+
"test:watch": "vitest --project unit",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"prepublishOnly": "npm run build",
|
|
26
|
+
"postinstall": "node scripts/postinstall.mjs",
|
|
27
|
+
"reepl": "node --import tsx src/cli/index.ts"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"reepl",
|
|
31
|
+
"linkedin",
|
|
32
|
+
"twitter",
|
|
33
|
+
"reddit",
|
|
34
|
+
"cli",
|
|
35
|
+
"social-media"
|
|
36
|
+
],
|
|
37
|
+
"license": "UNLICENSED",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"commander": "^12.1.0",
|
|
40
|
+
"open": "^10.1.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^22.10.0",
|
|
44
|
+
"tsup": "^8.3.5",
|
|
45
|
+
"tsx": "^4.19.2",
|
|
46
|
+
"typescript": "^5.7.2",
|
|
47
|
+
"vitest": "^2.1.8"
|
|
48
|
+
}
|
|
49
|
+
}
|