@curviate/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.
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/lib/exit-codes.ts
4
+ var EXIT_CODE_MAP = {
5
+ // Auth (3)
6
+ UNAUTHORIZED: 3,
7
+ // Invalid input / usage (2)
8
+ INVALID_REQUEST: 2,
9
+ UNSUPPORTED_MEDIA_TYPE: 2,
10
+ PAYLOAD_TOO_LARGE: 2,
11
+ // Not found (4)
12
+ RESOURCE_NOT_FOUND: 4,
13
+ ACCOUNT_NOT_FOUND: 4,
14
+ SUBSCRIPTION_NOT_FOUND: 4,
15
+ SEAT_NOT_FOUND: 4,
16
+ // Tier / entitlement (5)
17
+ TIER_NOT_ACTIVE: 5,
18
+ LINKEDIN_FEATURE_NOT_SUBSCRIBED: 5,
19
+ // Rate-limited (6)
20
+ RATE_LIMIT_ACCOUNT: 6,
21
+ RATE_LIMIT_TENANT: 6,
22
+ PLATFORM_RATE_LIMIT: 6,
23
+ LINKEDIN_RATE_LIMITED: 6,
24
+ // Transient platform (7)
25
+ PLATFORM_ERROR: 7,
26
+ LINKEDIN_SERVICE_UNAVAILABLE: 7,
27
+ // Account / connection state (8)
28
+ ACCOUNT_RESTRICTED: 8,
29
+ LINKEDIN_AUTH_FAILED: 8,
30
+ LINKEDIN_COOKIE_INVALID: 8,
31
+ CONNECTION_IN_PROGRESS: 8,
32
+ // Checkpoint flow (9)
33
+ CHECKPOINT_NOT_FOUND: 9,
34
+ CHECKPOINT_EXPIRED: 9,
35
+ CHECKPOINT_INVALID_CODE: 9,
36
+ CHECKPOINT_MAX_ATTEMPTS: 9,
37
+ CHECKPOINT_ALREADY_RESOLVED: 9,
38
+ CHECKPOINT_UNSUPPORTED: 9,
39
+ // Messaging window / recipient (10)
40
+ MESSAGE_WINDOW_EXPIRED: 10,
41
+ RECIPIENT_UNREACHABLE: 10,
42
+ // Billing (11)
43
+ PAYMENT_REQUIRED: 11,
44
+ PAYMENT_FAILED: 11,
45
+ SUBSCRIPTION_BUSY: 11,
46
+ SEAT_CANCELLED: 11,
47
+ // Internal / uncaught (1) — last resort bucket
48
+ INTERNAL: 1,
49
+ PLATFORM_NOT_IMPLEMENTED: 1
50
+ };
51
+ function getExitCode(code) {
52
+ return EXIT_CODE_MAP[code] ?? 1;
53
+ }
54
+ export {
55
+ EXIT_CODE_MAP,
56
+ getExitCode
57
+ };
@@ -0,0 +1,294 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ streamAll
4
+ } from "./chunk-SND3NHCT.js";
5
+ import {
6
+ createClient,
7
+ renderError,
8
+ renderSuccess,
9
+ renderUnexpectedError,
10
+ resolveEffectiveConfig
11
+ } from "./chunk-2NCPJJPC.js";
12
+ import {
13
+ GLOBAL_FLAGS
14
+ } from "./chunk-6JNCLLNY.js";
15
+
16
+ // src/commands/inbox.ts
17
+ import { defineCommand } from "citty";
18
+ function buildOutputStreams() {
19
+ return {
20
+ stdout: { write: (s) => process.stdout.write(s) },
21
+ stderr: { write: (s) => process.stderr.write(s) }
22
+ };
23
+ }
24
+ function requireAccount(account, out) {
25
+ if (!account) {
26
+ out.stderr.write("error: --account is required for this command. Set it via --account, CURVIATE_ACCOUNT, or `curviate config set-account`.\n");
27
+ process.exit(2);
28
+ }
29
+ return account;
30
+ }
31
+ function rejectPreviewOnRead(preview, out) {
32
+ if (preview) {
33
+ out.stderr.write("error: --preview is only valid on write commands (mutations). Reads just run.\n");
34
+ process.exit(2);
35
+ }
36
+ }
37
+ function rejectAllOnNonPaginated(all, out) {
38
+ if (all) {
39
+ out.stderr.write("error: --all is not supported on non-paginated commands.\n");
40
+ process.exit(2);
41
+ }
42
+ }
43
+ function resolveOutputOpts(flags) {
44
+ return {
45
+ json: (flags.json ?? false) || !process.stdout.isTTY,
46
+ isTTY: process.stdout.isTTY ?? false,
47
+ fields: flags.fields
48
+ };
49
+ }
50
+ function buildPaginationParams(flags) {
51
+ const params = {};
52
+ if (flags.limit !== void 0) params["limit"] = parseInt(flags.limit, 10);
53
+ if (flags.cursor) params["cursor"] = flags.cursor;
54
+ return params;
55
+ }
56
+ async function handleSdkError(err, outOpts, out) {
57
+ const { CurviateError } = await import("@curviate/sdk");
58
+ if (err instanceof CurviateError) {
59
+ const { getExitCode } = await import("./exit-codes-NFIR57ZA.js");
60
+ renderError(err, outOpts, out);
61
+ process.exit(getExitCode(err.code));
62
+ }
63
+ renderUnexpectedError(err, out);
64
+ process.exit(1);
65
+ }
66
+ async function runInboxList(client, flags, out) {
67
+ rejectPreviewOnRead(flags.preview, out);
68
+ const accountId = requireAccount(flags.account, out);
69
+ const ns = client.account(accountId);
70
+ const outOpts = resolveOutputOpts(flags);
71
+ const all = flags.all ?? false;
72
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
73
+ const params = buildPaginationParams(flags);
74
+ try {
75
+ if (all) {
76
+ const fn = (p) => ns.messaging.listChats(p);
77
+ for await (const item of streamAll(fn, params, {
78
+ maxPages,
79
+ onTruncated: (msg) => out.stderr.write(msg + "\n")
80
+ })) {
81
+ out.stdout.write(JSON.stringify(item) + "\n");
82
+ }
83
+ } else {
84
+ const result = await ns.messaging.listChats(params);
85
+ renderSuccess(result, outOpts, out);
86
+ }
87
+ } catch (err) {
88
+ await handleSdkError(err, outOpts, out);
89
+ }
90
+ }
91
+ async function runInboxGet(client, flags, out) {
92
+ rejectPreviewOnRead(flags.preview, out);
93
+ rejectAllOnNonPaginated(flags.all, out);
94
+ const accountId = requireAccount(flags.account, out);
95
+ const chatId = flags.chatId ?? "";
96
+ const ns = client.account(accountId);
97
+ const outOpts = resolveOutputOpts(flags);
98
+ try {
99
+ const result = await ns.messaging.getChat(chatId);
100
+ renderSuccess(result, outOpts, out);
101
+ } catch (err) {
102
+ await handleSdkError(err, outOpts, out);
103
+ }
104
+ }
105
+ async function runInboxMessages(client, flags, out) {
106
+ rejectPreviewOnRead(flags.preview, out);
107
+ const accountId = requireAccount(flags.account, out);
108
+ const chatId = flags.chatId ?? "";
109
+ const ns = client.account(accountId);
110
+ const outOpts = resolveOutputOpts(flags);
111
+ const all = flags.all ?? false;
112
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
113
+ const params = buildPaginationParams(flags);
114
+ try {
115
+ if (all) {
116
+ const fn = (p) => ns.messaging.listMessages(chatId, p);
117
+ for await (const item of streamAll(fn, params, {
118
+ maxPages,
119
+ onTruncated: (msg) => out.stderr.write(msg + "\n")
120
+ })) {
121
+ out.stdout.write(JSON.stringify(item) + "\n");
122
+ }
123
+ } else {
124
+ const result = await ns.messaging.listMessages(chatId, params);
125
+ renderSuccess(result, outOpts, out);
126
+ }
127
+ } catch (err) {
128
+ await handleSdkError(err, outOpts, out);
129
+ }
130
+ }
131
+ async function runInboxSync(client, flags, out) {
132
+ rejectPreviewOnRead(flags.preview, out);
133
+ rejectAllOnNonPaginated(flags.all, out);
134
+ const accountId = requireAccount(flags.account, out);
135
+ const ns = client.account(accountId);
136
+ const outOpts = resolveOutputOpts(flags);
137
+ try {
138
+ const result = await ns.messaging.syncMessages();
139
+ renderSuccess(result, outOpts, out);
140
+ } catch (err) {
141
+ await handleSdkError(err, outOpts, out);
142
+ }
143
+ }
144
+ async function runInboxSyncChat(client, flags, out) {
145
+ rejectPreviewOnRead(flags.preview, out);
146
+ rejectAllOnNonPaginated(flags.all, out);
147
+ const accountId = requireAccount(flags.account, out);
148
+ const chatId = flags.chatId ?? "";
149
+ const ns = client.account(accountId);
150
+ const outOpts = resolveOutputOpts(flags);
151
+ try {
152
+ const result = await ns.messaging.syncChat(chatId);
153
+ renderSuccess(result, outOpts, out);
154
+ } catch (err) {
155
+ await handleSdkError(err, outOpts, out);
156
+ }
157
+ }
158
+ var inboxListCommand = defineCommand({
159
+ meta: { name: "list", description: "List inbox chats." },
160
+ args: { ...GLOBAL_FLAGS },
161
+ async run({ args }) {
162
+ const flags = args;
163
+ const cfg = await resolveEffectiveConfig({
164
+ apiKey: flags["api-key"],
165
+ baseUrl: flags["base-url"],
166
+ timeout: flags.timeout,
167
+ account: flags.account,
168
+ profile: flags.profile
169
+ });
170
+ if (!cfg.apiKey) {
171
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
172
+ process.exit(3);
173
+ }
174
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
175
+ const out = buildOutputStreams();
176
+ await runInboxList(client, { ...flags, account: flags.account ?? cfg.account }, out);
177
+ }
178
+ });
179
+ var inboxGetCommand = defineCommand({
180
+ meta: { name: "get", description: "Get details of a single chat." },
181
+ args: {
182
+ ...GLOBAL_FLAGS,
183
+ chatId: { type: "positional", description: "Chat ID." }
184
+ },
185
+ async run({ args }) {
186
+ const flags = args;
187
+ const cfg = await resolveEffectiveConfig({
188
+ apiKey: flags["api-key"],
189
+ baseUrl: flags["base-url"],
190
+ timeout: flags.timeout,
191
+ account: flags.account,
192
+ profile: flags.profile
193
+ });
194
+ if (!cfg.apiKey) {
195
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
196
+ process.exit(3);
197
+ }
198
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
199
+ const out = buildOutputStreams();
200
+ await runInboxGet(client, { ...flags, account: flags.account ?? cfg.account }, out);
201
+ }
202
+ });
203
+ var inboxMessagesCommand = defineCommand({
204
+ meta: { name: "messages", description: "List messages in a chat." },
205
+ args: {
206
+ ...GLOBAL_FLAGS,
207
+ chatId: { type: "positional", description: "Chat ID." }
208
+ },
209
+ async run({ args }) {
210
+ const flags = args;
211
+ const cfg = await resolveEffectiveConfig({
212
+ apiKey: flags["api-key"],
213
+ baseUrl: flags["base-url"],
214
+ timeout: flags.timeout,
215
+ account: flags.account,
216
+ profile: flags.profile
217
+ });
218
+ if (!cfg.apiKey) {
219
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
220
+ process.exit(3);
221
+ }
222
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
223
+ const out = buildOutputStreams();
224
+ await runInboxMessages(client, { ...flags, account: flags.account ?? cfg.account }, out);
225
+ }
226
+ });
227
+ var inboxSyncCommand = defineCommand({
228
+ meta: { name: "sync", description: "Re-sync account message history." },
229
+ args: { ...GLOBAL_FLAGS },
230
+ async run({ args }) {
231
+ const flags = args;
232
+ const cfg = await resolveEffectiveConfig({
233
+ apiKey: flags["api-key"],
234
+ baseUrl: flags["base-url"],
235
+ timeout: flags.timeout,
236
+ account: flags.account,
237
+ profile: flags.profile
238
+ });
239
+ if (!cfg.apiKey) {
240
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
241
+ process.exit(3);
242
+ }
243
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
244
+ const out = buildOutputStreams();
245
+ await runInboxSync(client, { ...flags, account: flags.account ?? cfg.account }, out);
246
+ }
247
+ });
248
+ var inboxSyncChatCommand = defineCommand({
249
+ meta: { name: "sync-chat", description: "Re-sync a specific chat's message history." },
250
+ args: {
251
+ ...GLOBAL_FLAGS,
252
+ chatId: { type: "positional", description: "Chat ID." }
253
+ },
254
+ async run({ args }) {
255
+ const flags = args;
256
+ const cfg = await resolveEffectiveConfig({
257
+ apiKey: flags["api-key"],
258
+ baseUrl: flags["base-url"],
259
+ timeout: flags.timeout,
260
+ account: flags.account,
261
+ profile: flags.profile
262
+ });
263
+ if (!cfg.apiKey) {
264
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
265
+ process.exit(3);
266
+ }
267
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
268
+ const out = buildOutputStreams();
269
+ await runInboxSyncChat(client, { ...flags, account: flags.account ?? cfg.account }, out);
270
+ }
271
+ });
272
+ var inboxCommand = defineCommand({
273
+ meta: { name: "inbox", description: "Read and sync LinkedIn message inbox." },
274
+ subCommands: {
275
+ list: inboxListCommand,
276
+ get: inboxGetCommand,
277
+ messages: inboxMessagesCommand,
278
+ sync: inboxSyncCommand,
279
+ "sync-chat": inboxSyncChatCommand
280
+ },
281
+ async run() {
282
+ process.stderr.write(
283
+ "Usage: curviate inbox <subcommand>\n list\n get <chat_id>\n messages <chat_id>\n sync\n sync-chat <chat_id>\n"
284
+ );
285
+ }
286
+ });
287
+ export {
288
+ inboxCommand,
289
+ runInboxGet,
290
+ runInboxList,
291
+ runInboxMessages,
292
+ runInboxSync,
293
+ runInboxSyncChat
294
+ };
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ GLOBAL_FLAGS,
4
+ writeProfile
5
+ } from "./chunk-6JNCLLNY.js";
6
+
7
+ // src/commands/login.ts
8
+ import { defineCommand } from "citty";
9
+
10
+ // src/lib/readline.ts
11
+ import { createInterface } from "readline";
12
+ async function readlineSync(prompt, opts = {}) {
13
+ return new Promise((resolve, reject) => {
14
+ process.stderr.write(prompt);
15
+ if (opts.mask && typeof process.stdin.setRawMode === "function") {
16
+ process.stdin.setRawMode(true);
17
+ process.stdin.resume();
18
+ process.stdin.setEncoding("utf8");
19
+ let input = "";
20
+ const onData = (char) => {
21
+ if (char === "\r" || char === "\n") {
22
+ process.stdin.setRawMode(false);
23
+ process.stdin.pause();
24
+ process.stdin.removeListener("data", onData);
25
+ process.stderr.write("\n");
26
+ resolve(input);
27
+ } else if (char === "") {
28
+ process.stdin.setRawMode(false);
29
+ process.stdin.pause();
30
+ process.stdin.removeListener("data", onData);
31
+ reject(new Error("Interrupted."));
32
+ } else if (char === "\x7F" || char === "\b") {
33
+ input = input.slice(0, -1);
34
+ } else {
35
+ input += char;
36
+ }
37
+ };
38
+ process.stdin.on("data", onData);
39
+ } else {
40
+ const rl = createInterface({
41
+ input: process.stdin,
42
+ output: void 0,
43
+ // suppress default echo (prompt already on stderr)
44
+ terminal: false
45
+ });
46
+ rl.once("line", (line) => {
47
+ rl.close();
48
+ resolve(line.trim());
49
+ });
50
+ rl.once("error", reject);
51
+ rl.once("close", () => resolve(""));
52
+ }
53
+ });
54
+ }
55
+
56
+ // src/commands/login.ts
57
+ var loginCommand = defineCommand({
58
+ meta: {
59
+ name: "login",
60
+ description: "Save an API key to a local profile. Run `curviate profile me` to verify."
61
+ },
62
+ args: {
63
+ ...GLOBAL_FLAGS,
64
+ "api-key": {
65
+ type: "string",
66
+ description: 'API key to save. Pass "-" to read from stdin (keeps the key off argv).'
67
+ },
68
+ account: {
69
+ type: "string",
70
+ description: "Default account id to store with this profile."
71
+ },
72
+ profile: {
73
+ type: "string",
74
+ description: "Profile name to write to (default: default).",
75
+ default: "default"
76
+ }
77
+ },
78
+ async run({ args }) {
79
+ const profileName = args.profile ?? "default";
80
+ let apiKey = args["api-key"];
81
+ if (apiKey === "-") {
82
+ apiKey = await readStdin();
83
+ }
84
+ if (apiKey === void 0) {
85
+ if (process.stdin.isTTY) {
86
+ apiKey = await promptMasked("Enter your API key: ");
87
+ } else {
88
+ process.stderr.write(
89
+ "error: no API key \u2014 pass --api-key or run interactively on a TTY.\n"
90
+ );
91
+ process.exit(2);
92
+ }
93
+ }
94
+ apiKey = apiKey.trim();
95
+ if (!apiKey) {
96
+ process.stderr.write("error: API key must not be empty.\n");
97
+ process.exit(2);
98
+ }
99
+ const account = args.account ?? void 0;
100
+ await writeProfile(profileName, { apiKey, account });
101
+ process.stderr.write(
102
+ `Saved to profile "${profileName}". Run \`curviate profile me\` to verify.
103
+ `
104
+ );
105
+ }
106
+ });
107
+ async function readStdin() {
108
+ return new Promise((resolve, reject) => {
109
+ const chunks = [];
110
+ process.stdin.on("data", (chunk) => chunks.push(chunk));
111
+ process.stdin.on("end", () => {
112
+ resolve(Buffer.concat(chunks).toString("utf8").trim());
113
+ });
114
+ process.stdin.on("error", reject);
115
+ });
116
+ }
117
+ async function promptMasked(prompt) {
118
+ return readlineSync(prompt, { mask: true });
119
+ }
120
+ export {
121
+ loginCommand
122
+ };