@curviate/cli 0.4.1 → 0.6.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 +35 -0
- package/dist/{account-47TRPUKL.js → account-ZWBNNQKQ.js} +2 -2
- package/dist/{chunk-U6ACUNLU.js → chunk-47SYFQRF.js} +1 -1
- package/dist/{chunk-5NS2G4WQ.js → chunk-6VBOKOQJ.js} +46 -0
- package/dist/chunk-CHFKVAEI.js +32 -0
- package/dist/{chunk-BNUTM6KD.js → chunk-SZB3CFRZ.js} +8 -1
- package/dist/{chunk-52RZLSWP.js → chunk-TDYIQHQX.js} +13 -1
- package/dist/cli.js +18 -14
- package/dist/{company-4MUABENR.js → company-SZPGJE3M.js} +4 -4
- package/dist/{config-6PNGYL5E.js → config-2GBLD4GN.js} +1 -1
- package/dist/{connect-ZXD7P5CA.js → connect-RMT7OS3I.js} +45 -19
- package/dist/{inbox-ME4TXGFV.js → inbox-MIKI4HU3.js} +102 -19
- package/dist/{login-UJQGIP7S.js → login-POKHNDYX.js} +1 -1
- package/dist/{message-KAESYHVJ.js → message-YRMLMHK7.js} +126 -40
- package/dist/{post-VDQF23WS.js → post-2FYHZAKC.js} +13 -8
- package/dist/{profile-CUVVESMY.js → profile-NDDG26PL.js} +7 -7
- package/dist/{recruiter-QKJKOWD7.js → recruiter-3DRGDOVV.js} +3 -3
- package/dist/{sales-nav-UL2H6J6V.js → sales-nav-7WPN7BT4.js} +3 -3
- package/dist/{search-M4WK3PDC.js → search-QO237C4O.js} +2 -2
- package/dist/{webhook-2SSNW25K.js → webhook-FDIERREB.js} +2 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,41 @@ a new command or flag is a minor; a breaking command/flag/exit-code change is a
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.6.0] - 2026-06-30
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `inbox list --unread` — filter the inbox to chats with unread messages.
|
|
16
|
+
- `messages` now accepts `--before` and `--after` to page a conversation by
|
|
17
|
+
timestamp window.
|
|
18
|
+
- `sync-chat --wait` — poll until a chat sync completes instead of returning
|
|
19
|
+
immediately.
|
|
20
|
+
- `message new --to` and `message inmail --to` now resolve a **LinkedIn profile
|
|
21
|
+
URL or vanity slug** (e.g. `linkedin.com/in/<slug>`) to the recipient, in
|
|
22
|
+
addition to provider ids and member URNs.
|
|
23
|
+
- Thread-URL `chat_id` normalization — a pasted conversation URL is normalized to
|
|
24
|
+
the underlying chat id wherever a `chat_id` is accepted.
|
|
25
|
+
- Write commands that take a TEXT positional accept `-` to read the value from
|
|
26
|
+
stdin (pipe message bodies in).
|
|
27
|
+
- `connect`: slim default projection + write-flag suppression + help text
|
|
28
|
+
(Invites-AX co-release).
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- Pagination flags are suppressed from the help output of non-list commands.
|
|
33
|
+
- Updated `@curviate/sdk` dependency to `^0.4.0` (regenerated types:
|
|
34
|
+
`primary_locale` on profile, account-sync `status` field).
|
|
35
|
+
|
|
36
|
+
## [0.5.0] - 2026-06-29
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- `message inmail --surface classic` — send an InMail from the account's own premium
|
|
41
|
+
InMail credits (in addition to `sales_nav` and `recruiter`). Use this to reach an
|
|
42
|
+
out-of-network member from a LinkedIn Premium/Core account.
|
|
43
|
+
- `message inmail --to` now accepts a member **provider id** (`ACoAAA…`) as well as a
|
|
44
|
+
member URN (`urn:li:member:<id>`). The server resolves the recipient either way.
|
|
45
|
+
|
|
11
46
|
## [0.4.1] - 2026-06-29
|
|
12
47
|
|
|
13
48
|
### Changed
|
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
renderSuccess,
|
|
12
12
|
renderUnexpectedError,
|
|
13
13
|
resolveEffectiveConfig
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-47SYFQRF.js";
|
|
15
15
|
import {
|
|
16
16
|
GLOBAL_FLAGS
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-TDYIQHQX.js";
|
|
18
18
|
|
|
19
19
|
// src/commands/account.ts
|
|
20
20
|
import { defineCommand } from "citty";
|
|
@@ -64,6 +64,48 @@ function slimProfile(data) {
|
|
|
64
64
|
current_position: currentPosition
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
+
function slimInviteSentItem(item) {
|
|
68
|
+
return {
|
|
69
|
+
id: item["id"] ?? null,
|
|
70
|
+
invited_user: item["invited_user"] ?? null,
|
|
71
|
+
invited_user_id: item["invited_user_id"] ?? null,
|
|
72
|
+
invited_user_public_id: item["invited_user_public_id"] ?? null,
|
|
73
|
+
invited_user_description: item["invited_user_description"] ?? null,
|
|
74
|
+
date: item["date"] ?? null,
|
|
75
|
+
parsed_datetime: item["parsed_datetime"] ?? null,
|
|
76
|
+
invitation_text: item["invitation_text"] ?? null
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function slimInviteSent(data) {
|
|
80
|
+
const d = data !== null && data !== void 0 && typeof data === "object" ? data : {};
|
|
81
|
+
const items = Array.isArray(d["items"]) ? d["items"].map(slimInviteSentItem) : [];
|
|
82
|
+
return {
|
|
83
|
+
object: d["object"] ?? null,
|
|
84
|
+
items,
|
|
85
|
+
cursor: d["cursor"] ?? null
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function slimInviteReceivedItem(item) {
|
|
89
|
+
const rawSpecifics = item["specifics"] !== null && item["specifics"] !== void 0 && typeof item["specifics"] === "object" ? item["specifics"] : null;
|
|
90
|
+
const specifics = rawSpecifics !== null ? { shared_secret: rawSpecifics["shared_secret"] ?? null } : null;
|
|
91
|
+
return {
|
|
92
|
+
id: item["id"] ?? null,
|
|
93
|
+
inviter: item["inviter"] ?? null,
|
|
94
|
+
date: item["date"] ?? null,
|
|
95
|
+
parsed_datetime: item["parsed_datetime"] ?? null,
|
|
96
|
+
invitation_text: item["invitation_text"] ?? null,
|
|
97
|
+
specifics
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function slimInviteReceived(data) {
|
|
101
|
+
const d = data !== null && data !== void 0 && typeof data === "object" ? data : {};
|
|
102
|
+
const items = Array.isArray(d["items"]) ? d["items"].map(slimInviteReceivedItem) : [];
|
|
103
|
+
return {
|
|
104
|
+
object: d["object"] ?? null,
|
|
105
|
+
items,
|
|
106
|
+
cursor: d["cursor"] ?? null
|
|
107
|
+
};
|
|
108
|
+
}
|
|
67
109
|
function slimCompany(data) {
|
|
68
110
|
const d = data !== null && data !== void 0 && typeof data === "object" ? data : {};
|
|
69
111
|
const rawMessaging = d["messaging"] !== null && d["messaging"] !== void 0 && typeof d["messaging"] === "object" ? d["messaging"] : null;
|
|
@@ -91,5 +133,9 @@ function slimCompany(data) {
|
|
|
91
133
|
export {
|
|
92
134
|
slimProfileMe,
|
|
93
135
|
slimProfile,
|
|
136
|
+
slimInviteSentItem,
|
|
137
|
+
slimInviteSent,
|
|
138
|
+
slimInviteReceivedItem,
|
|
139
|
+
slimInviteReceived,
|
|
94
140
|
slimCompany
|
|
95
141
|
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/stdin.ts
|
|
4
|
+
var STDIN_SENTINEL = "__curviate_stdin__";
|
|
5
|
+
async function defaultReadStdin() {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const chunks = [];
|
|
8
|
+
process.stdin.on("data", (chunk) => {
|
|
9
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
10
|
+
});
|
|
11
|
+
process.stdin.on("end", () => {
|
|
12
|
+
const full = Buffer.concat(chunks).toString("utf8");
|
|
13
|
+
resolve(full.replace(/\n+$/, ""));
|
|
14
|
+
});
|
|
15
|
+
process.stdin.on("error", reject);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async function resolveTextOrStdin(rawText, out, readStdin) {
|
|
19
|
+
if (rawText !== "-" && rawText !== STDIN_SENTINEL) return rawText;
|
|
20
|
+
const reader = readStdin ?? defaultReadStdin;
|
|
21
|
+
const text = await reader();
|
|
22
|
+
if (!text) {
|
|
23
|
+
out.stderr.write("error: stdin: empty input\n");
|
|
24
|
+
process.exit(2);
|
|
25
|
+
}
|
|
26
|
+
return text;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
STDIN_SENTINEL,
|
|
31
|
+
resolveTextOrStdin
|
|
32
|
+
};
|
|
@@ -27,7 +27,14 @@ function resolveIdentifier(raw) {
|
|
|
27
27
|
function stripTrailingSlash(s) {
|
|
28
28
|
return s.endsWith("/") ? s.slice(0, -1) : s;
|
|
29
29
|
}
|
|
30
|
+
var MESSAGING_THREAD_URL_RE = /messaging\/thread\/([^/?]+)/;
|
|
31
|
+
function normalizeChatId(raw) {
|
|
32
|
+
const match = MESSAGING_THREAD_URL_RE.exec(raw);
|
|
33
|
+
if (match?.[1]) return match[1];
|
|
34
|
+
return raw;
|
|
35
|
+
}
|
|
30
36
|
|
|
31
37
|
export {
|
|
32
|
-
resolveIdentifier
|
|
38
|
+
resolveIdentifier,
|
|
39
|
+
normalizeChatId
|
|
33
40
|
};
|
|
@@ -197,6 +197,17 @@ var WRITE_FLAGS = {
|
|
|
197
197
|
preview: GLOBAL_FLAGS.preview,
|
|
198
198
|
verbose: GLOBAL_FLAGS.verbose
|
|
199
199
|
};
|
|
200
|
+
var READ_SINGLE_FLAGS = {
|
|
201
|
+
"api-key": GLOBAL_FLAGS["api-key"],
|
|
202
|
+
profile: GLOBAL_FLAGS.profile,
|
|
203
|
+
account: GLOBAL_FLAGS.account,
|
|
204
|
+
"base-url": GLOBAL_FLAGS["base-url"],
|
|
205
|
+
timeout: GLOBAL_FLAGS.timeout,
|
|
206
|
+
json: GLOBAL_FLAGS.json,
|
|
207
|
+
fields: GLOBAL_FLAGS.fields,
|
|
208
|
+
preview: GLOBAL_FLAGS.preview,
|
|
209
|
+
verbose: GLOBAL_FLAGS.verbose
|
|
210
|
+
};
|
|
200
211
|
|
|
201
212
|
export {
|
|
202
213
|
getConfigPath,
|
|
@@ -207,5 +218,6 @@ export {
|
|
|
207
218
|
removeProfile,
|
|
208
219
|
updateProfileField,
|
|
209
220
|
GLOBAL_FLAGS,
|
|
210
|
-
WRITE_FLAGS
|
|
221
|
+
WRITE_FLAGS,
|
|
222
|
+
READ_SINGLE_FLAGS
|
|
211
223
|
};
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
STDIN_SENTINEL
|
|
4
|
+
} from "./chunk-CHFKVAEI.js";
|
|
2
5
|
|
|
3
6
|
// src/cli.ts
|
|
4
7
|
import { defineCommand } from "citty";
|
|
@@ -108,8 +111,9 @@ async function dispatch(root, rawArgs) {
|
|
|
108
111
|
if (unknown !== null) {
|
|
109
112
|
usageError(`unknown flag \`${unknown}\`.`);
|
|
110
113
|
}
|
|
114
|
+
const processedLeafArgs = leafArgs.map((a) => a === "-" ? STDIN_SENTINEL : a);
|
|
111
115
|
const leafToRun = { ...leaf, subCommands: void 0 };
|
|
112
|
-
await runCommand(leafToRun, { rawArgs:
|
|
116
|
+
await runCommand(leafToRun, { rawArgs: processedLeafArgs });
|
|
113
117
|
} catch (err) {
|
|
114
118
|
const message = err instanceof Error ? err.message : String(err);
|
|
115
119
|
const code = err?.code;
|
|
@@ -134,22 +138,22 @@ var main = defineCommand({
|
|
|
134
138
|
// Subcommand registry — names and descriptions are static for help rendering;
|
|
135
139
|
// the handler implementation is loaded lazily on first invocation.
|
|
136
140
|
subCommands: {
|
|
137
|
-
login: () => import("./login-
|
|
138
|
-
config: () => import("./config-
|
|
141
|
+
login: () => import("./login-POKHNDYX.js").then((m) => m.loginCommand),
|
|
142
|
+
config: () => import("./config-2GBLD4GN.js").then((m) => m.configCommand),
|
|
139
143
|
// ---------------------------------------------------------------------------
|
|
140
144
|
// Noun groups — lazy-loaded on first invocation.
|
|
141
145
|
// ---------------------------------------------------------------------------
|
|
142
|
-
profile: () => import("./profile-
|
|
143
|
-
company: () => import("./company-
|
|
144
|
-
connect: () => import("./connect-
|
|
145
|
-
search: () => import("./search-
|
|
146
|
-
inbox: () => import("./inbox-
|
|
147
|
-
message: () => import("./message-
|
|
148
|
-
post: () => import("./post-
|
|
149
|
-
account: () => import("./account-
|
|
150
|
-
webhook: () => import("./webhook-
|
|
151
|
-
"sales-nav": () => import("./sales-nav-
|
|
152
|
-
recruiter: () => import("./recruiter-
|
|
146
|
+
profile: () => import("./profile-NDDG26PL.js").then((m) => m.profileCommand),
|
|
147
|
+
company: () => import("./company-SZPGJE3M.js").then((m) => m.companyCommand),
|
|
148
|
+
connect: () => import("./connect-RMT7OS3I.js").then((m) => m.connectCommand),
|
|
149
|
+
search: () => import("./search-QO237C4O.js").then((m) => m.searchCommand),
|
|
150
|
+
inbox: () => import("./inbox-MIKI4HU3.js").then((m) => m.inboxCommand),
|
|
151
|
+
message: () => import("./message-YRMLMHK7.js").then((m) => m.messageCommand),
|
|
152
|
+
post: () => import("./post-2FYHZAKC.js").then((m) => m.postCommand),
|
|
153
|
+
account: () => import("./account-ZWBNNQKQ.js").then((m) => m.accountCommand),
|
|
154
|
+
webhook: () => import("./webhook-FDIERREB.js").then((m) => m.webhookCommand),
|
|
155
|
+
"sales-nav": () => import("./sales-nav-7WPN7BT4.js").then((m) => m.salesNavCommand),
|
|
156
|
+
recruiter: () => import("./recruiter-3DRGDOVV.js").then((m) => m.recruiterCommand)
|
|
153
157
|
},
|
|
154
158
|
async run() {
|
|
155
159
|
const { runMain } = await import("citty");
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
slimCompany
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6VBOKOQJ.js";
|
|
5
5
|
import {
|
|
6
6
|
resolveIdentifier
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-SZB3CFRZ.js";
|
|
8
8
|
import {
|
|
9
9
|
createClient,
|
|
10
10
|
renderError,
|
|
11
11
|
renderSuccess,
|
|
12
12
|
renderUnexpectedError,
|
|
13
13
|
resolveEffectiveConfig
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-47SYFQRF.js";
|
|
15
15
|
import {
|
|
16
16
|
GLOBAL_FLAGS
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-TDYIQHQX.js";
|
|
18
18
|
|
|
19
19
|
// src/commands/company.ts
|
|
20
20
|
import { defineCommand } from "citty";
|
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
import {
|
|
3
3
|
buildPreviewOutput
|
|
4
4
|
} from "./chunk-R3VLWLVV.js";
|
|
5
|
+
import {
|
|
6
|
+
slimInviteReceived,
|
|
7
|
+
slimInviteReceivedItem,
|
|
8
|
+
slimInviteSent,
|
|
9
|
+
slimInviteSentItem
|
|
10
|
+
} from "./chunk-6VBOKOQJ.js";
|
|
5
11
|
import {
|
|
6
12
|
resolveIdentifier
|
|
7
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-SZB3CFRZ.js";
|
|
8
14
|
import {
|
|
9
15
|
streamAll
|
|
10
16
|
} from "./chunk-SND3NHCT.js";
|
|
@@ -14,10 +20,11 @@ import {
|
|
|
14
20
|
renderSuccess,
|
|
15
21
|
renderUnexpectedError,
|
|
16
22
|
resolveEffectiveConfig
|
|
17
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-47SYFQRF.js";
|
|
18
24
|
import {
|
|
19
|
-
GLOBAL_FLAGS
|
|
20
|
-
|
|
25
|
+
GLOBAL_FLAGS,
|
|
26
|
+
WRITE_FLAGS
|
|
27
|
+
} from "./chunk-TDYIQHQX.js";
|
|
21
28
|
|
|
22
29
|
// src/commands/connect.ts
|
|
23
30
|
import { defineCommand } from "citty";
|
|
@@ -44,7 +51,8 @@ function resolveOutputOpts(flags) {
|
|
|
44
51
|
return {
|
|
45
52
|
json: (flags.json ?? false) || !process.stdout.isTTY,
|
|
46
53
|
isTTY: process.stdout.isTTY ?? false,
|
|
47
|
-
fields: flags.fields
|
|
54
|
+
fields: flags.fields,
|
|
55
|
+
verbose: flags.verbose ?? false
|
|
48
56
|
};
|
|
49
57
|
}
|
|
50
58
|
async function runConnectSend(client, flags, out) {
|
|
@@ -98,11 +106,12 @@ async function runConnectSent(client, flags, out) {
|
|
|
98
106
|
maxPages,
|
|
99
107
|
onTruncated: (msg) => out.stderr.write(msg + "\n")
|
|
100
108
|
})) {
|
|
101
|
-
|
|
109
|
+
const projected = !flags.verbose ? slimInviteSentItem(item) : item;
|
|
110
|
+
out.stdout.write(JSON.stringify(projected) + "\n");
|
|
102
111
|
}
|
|
103
112
|
} else {
|
|
104
113
|
const result = await ns.invites.listSent(params);
|
|
105
|
-
renderSuccess(result, outOpts, out);
|
|
114
|
+
renderSuccess(result, { ...outOpts, slim: slimInviteSent }, out);
|
|
106
115
|
}
|
|
107
116
|
} catch (err) {
|
|
108
117
|
const { CurviateError } = await import("@curviate/sdk");
|
|
@@ -134,11 +143,12 @@ async function runConnectReceived(client, flags, out) {
|
|
|
134
143
|
maxPages,
|
|
135
144
|
onTruncated: (msg) => out.stderr.write(msg + "\n")
|
|
136
145
|
})) {
|
|
137
|
-
|
|
146
|
+
const projected = !flags.verbose ? slimInviteReceivedItem(item) : item;
|
|
147
|
+
out.stdout.write(JSON.stringify(projected) + "\n");
|
|
138
148
|
}
|
|
139
149
|
} else {
|
|
140
150
|
const result = await ns.invites.listReceived(params);
|
|
141
|
-
renderSuccess(result, outOpts, out);
|
|
151
|
+
renderSuccess(result, { ...outOpts, slim: slimInviteReceived }, out);
|
|
142
152
|
}
|
|
143
153
|
} catch (err) {
|
|
144
154
|
const { CurviateError } = await import("@curviate/sdk");
|
|
@@ -219,7 +229,10 @@ async function runConnectCancel(client, flags, out) {
|
|
|
219
229
|
}
|
|
220
230
|
}
|
|
221
231
|
var connectSentCommand = defineCommand({
|
|
222
|
-
meta: {
|
|
232
|
+
meta: {
|
|
233
|
+
name: "sent",
|
|
234
|
+
description: "Returns pending sent invitations only \u2014 accepted and declined invitations are not returned (LinkedIn API limitation). Use `id` with `connect cancel`; use `invited_user_public_id` or `invited_user_id` with `curviate profile`. `parsed_datetime` is approximate \u2014 derived from LinkedIn's relative date label; invitations sharing a label get the same computed time. No total count is available; use `connect sent --all` and count client-side."
|
|
235
|
+
},
|
|
223
236
|
args: { ...GLOBAL_FLAGS },
|
|
224
237
|
async run({ args }) {
|
|
225
238
|
const flags = args;
|
|
@@ -242,7 +255,7 @@ var connectSentCommand = defineCommand({
|
|
|
242
255
|
var connectReceivedCommand = defineCommand({
|
|
243
256
|
meta: {
|
|
244
257
|
name: "received",
|
|
245
|
-
description: "
|
|
258
|
+
description: "Returns pending received invitations only \u2014 already-handled invitations are not returned. The `inviter.*` fields identify who sent the request. `specifics.shared_secret` is required for `connect respond`."
|
|
246
259
|
},
|
|
247
260
|
args: { ...GLOBAL_FLAGS },
|
|
248
261
|
async run({ args }) {
|
|
@@ -266,12 +279,15 @@ var connectReceivedCommand = defineCommand({
|
|
|
266
279
|
var connectRespondCommand = defineCommand({
|
|
267
280
|
meta: { name: "respond", description: "Accept or decline a received invitation." },
|
|
268
281
|
args: {
|
|
269
|
-
...
|
|
270
|
-
id: {
|
|
282
|
+
...WRITE_FLAGS,
|
|
283
|
+
id: {
|
|
284
|
+
type: "positional",
|
|
285
|
+
description: "Invitation id to respond to \u2014 use the `id` field from `connect received`."
|
|
286
|
+
},
|
|
271
287
|
action: { type: "string", description: "Response action: accept or decline.", required: true },
|
|
272
288
|
"shared-secret": {
|
|
273
289
|
type: "string",
|
|
274
|
-
description: "Per-invitation shared secret \u2014
|
|
290
|
+
description: "Per-invitation shared secret \u2014 use `specifics.shared_secret` from the same `connect received` item.",
|
|
275
291
|
required: true
|
|
276
292
|
}
|
|
277
293
|
},
|
|
@@ -296,7 +312,7 @@ var connectRespondCommand = defineCommand({
|
|
|
296
312
|
var connectCancelCommand = defineCommand({
|
|
297
313
|
meta: { name: "cancel", description: "Cancel a sent invitation." },
|
|
298
314
|
args: {
|
|
299
|
-
...
|
|
315
|
+
...WRITE_FLAGS,
|
|
300
316
|
id: { type: "positional", description: "Invitation id to cancel." }
|
|
301
317
|
},
|
|
302
318
|
async run({ args }) {
|
|
@@ -318,11 +334,21 @@ var connectCancelCommand = defineCommand({
|
|
|
318
334
|
}
|
|
319
335
|
});
|
|
320
336
|
var connectCommand = defineCommand({
|
|
321
|
-
meta: {
|
|
337
|
+
meta: {
|
|
338
|
+
name: "connect",
|
|
339
|
+
description: "Send or manage connection invitations. Connection requests may take 10\u201330 seconds to appear in the recipient's received list (LinkedIn propagation delay)."
|
|
340
|
+
},
|
|
322
341
|
args: {
|
|
323
|
-
...
|
|
324
|
-
id: {
|
|
325
|
-
|
|
342
|
+
...WRITE_FLAGS,
|
|
343
|
+
id: {
|
|
344
|
+
type: "positional",
|
|
345
|
+
description: "Recipient's LinkedIn URL, public slug, or provider_id (ACoAAA\u2026 from `curviate profile`). LinkedIn URN (`urn:li:member:N`) also accepted but the numeric member ID is not exposed by this API.",
|
|
346
|
+
required: false
|
|
347
|
+
},
|
|
348
|
+
note: {
|
|
349
|
+
type: "string",
|
|
350
|
+
description: "Personalized message shown to the recipient alongside the connection request (\u2264300 chars; LinkedIn cap). Omit to send a generic note. Personalized messages increase acceptance rates."
|
|
351
|
+
}
|
|
326
352
|
},
|
|
327
353
|
subCommands: {
|
|
328
354
|
sent: connectSentCommand,
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
normalizeChatId
|
|
4
|
+
} from "./chunk-SZB3CFRZ.js";
|
|
2
5
|
import {
|
|
3
6
|
streamAll
|
|
4
7
|
} from "./chunk-SND3NHCT.js";
|
|
@@ -8,10 +11,11 @@ import {
|
|
|
8
11
|
renderSuccess,
|
|
9
12
|
renderUnexpectedError,
|
|
10
13
|
resolveEffectiveConfig
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-47SYFQRF.js";
|
|
12
15
|
import {
|
|
13
|
-
GLOBAL_FLAGS
|
|
14
|
-
|
|
16
|
+
GLOBAL_FLAGS,
|
|
17
|
+
READ_SINGLE_FLAGS
|
|
18
|
+
} from "./chunk-TDYIQHQX.js";
|
|
15
19
|
|
|
16
20
|
// src/commands/inbox.ts
|
|
17
21
|
import { defineCommand } from "citty";
|
|
@@ -53,6 +57,15 @@ function buildPaginationParams(flags) {
|
|
|
53
57
|
if (flags.cursor) params["cursor"] = flags.cursor;
|
|
54
58
|
return params;
|
|
55
59
|
}
|
|
60
|
+
function validateIsoZTimestamp(value, flagName, out) {
|
|
61
|
+
if (Number.isNaN(new Date(value).getTime()) || !value.endsWith("Z")) {
|
|
62
|
+
out.stderr.write(
|
|
63
|
+
`error: --${flagName}: must be a UTC ISO-8601 timestamp ending in 'Z' (e.g. 2025-01-01T00:00:00Z).
|
|
64
|
+
`
|
|
65
|
+
);
|
|
66
|
+
process.exit(2);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
56
69
|
async function handleSdkError(err, outOpts, out) {
|
|
57
70
|
const { CurviateError } = await import("@curviate/sdk");
|
|
58
71
|
if (err instanceof CurviateError) {
|
|
@@ -71,6 +84,9 @@ async function runInboxList(client, flags, out) {
|
|
|
71
84
|
const all = flags.all ?? false;
|
|
72
85
|
const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
|
|
73
86
|
const params = buildPaginationParams(flags);
|
|
87
|
+
if (flags.unread !== void 0) {
|
|
88
|
+
params.unread = flags.unread;
|
|
89
|
+
}
|
|
74
90
|
try {
|
|
75
91
|
if (all) {
|
|
76
92
|
const fn = (p) => ns.messaging.listChats(p);
|
|
@@ -92,7 +108,7 @@ async function runInboxGet(client, flags, out) {
|
|
|
92
108
|
rejectPreviewOnRead(flags.preview, out);
|
|
93
109
|
rejectAllOnNonPaginated(flags.all, out);
|
|
94
110
|
const accountId = requireAccount(flags.account, out);
|
|
95
|
-
const chatId = flags.chatId ?? "";
|
|
111
|
+
const chatId = normalizeChatId(flags.chatId ?? "");
|
|
96
112
|
const ns = client.account(accountId);
|
|
97
113
|
const outOpts = resolveOutputOpts(flags);
|
|
98
114
|
try {
|
|
@@ -105,12 +121,20 @@ async function runInboxGet(client, flags, out) {
|
|
|
105
121
|
async function runInboxMessages(client, flags, out) {
|
|
106
122
|
rejectPreviewOnRead(flags.preview, out);
|
|
107
123
|
const accountId = requireAccount(flags.account, out);
|
|
108
|
-
const chatId = flags.chatId ?? "";
|
|
124
|
+
const chatId = normalizeChatId(flags.chatId ?? "");
|
|
109
125
|
const ns = client.account(accountId);
|
|
110
126
|
const outOpts = resolveOutputOpts(flags);
|
|
111
127
|
const all = flags.all ?? false;
|
|
112
128
|
const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
|
|
113
129
|
const params = buildPaginationParams(flags);
|
|
130
|
+
if (flags.before !== void 0) {
|
|
131
|
+
validateIsoZTimestamp(flags.before, "before", out);
|
|
132
|
+
params.before = flags.before;
|
|
133
|
+
}
|
|
134
|
+
if (flags.after !== void 0) {
|
|
135
|
+
validateIsoZTimestamp(flags.after, "after", out);
|
|
136
|
+
params.after = flags.after;
|
|
137
|
+
}
|
|
114
138
|
try {
|
|
115
139
|
if (all) {
|
|
116
140
|
const fn = (p) => ns.messaging.listMessages(chatId, p);
|
|
@@ -141,23 +165,58 @@ async function runInboxSync(client, flags, out) {
|
|
|
141
165
|
await handleSdkError(err, outOpts, out);
|
|
142
166
|
}
|
|
143
167
|
}
|
|
144
|
-
|
|
168
|
+
var SYNC_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["done", "error", "chat_deleted"]);
|
|
169
|
+
var SYNC_POLL_INTERVAL_MS = 2e3;
|
|
170
|
+
async function runInboxSyncChat(client, flags, out, _sleep) {
|
|
145
171
|
rejectPreviewOnRead(flags.preview, out);
|
|
146
172
|
rejectAllOnNonPaginated(flags.all, out);
|
|
147
173
|
const accountId = requireAccount(flags.account, out);
|
|
148
|
-
const chatId = flags.chatId ?? "";
|
|
174
|
+
const chatId = normalizeChatId(flags.chatId ?? "");
|
|
149
175
|
const ns = client.account(accountId);
|
|
150
176
|
const outOpts = resolveOutputOpts(flags);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
177
|
+
if (!flags.wait) {
|
|
178
|
+
try {
|
|
179
|
+
const result = await ns.messaging.syncChat(chatId);
|
|
180
|
+
renderSuccess(result, outOpts, out);
|
|
181
|
+
} catch (err) {
|
|
182
|
+
await handleSdkError(err, outOpts, out);
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const sleep = _sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
187
|
+
const timeoutSecs = parseInt(flags.timeout ?? "30", 10);
|
|
188
|
+
const timeoutMs = (Number.isNaN(timeoutSecs) ? 30 : timeoutSecs) * 1e3;
|
|
189
|
+
const startTime = Date.now();
|
|
190
|
+
while (true) {
|
|
191
|
+
let result;
|
|
192
|
+
try {
|
|
193
|
+
result = await ns.messaging.syncChat(chatId);
|
|
194
|
+
} catch (err) {
|
|
195
|
+
await handleSdkError(err, outOpts, out);
|
|
196
|
+
}
|
|
197
|
+
const resp = result;
|
|
198
|
+
if (resp.status !== void 0 && SYNC_TERMINAL_STATUSES.has(resp.status)) {
|
|
199
|
+
renderSuccess(result, outOpts, out);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (Date.now() - startTime >= timeoutMs) {
|
|
203
|
+
renderSuccess(result, outOpts, out);
|
|
204
|
+
process.exit(3);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
await sleep(SYNC_POLL_INTERVAL_MS);
|
|
156
208
|
}
|
|
157
209
|
}
|
|
158
210
|
var inboxListCommand = defineCommand({
|
|
159
211
|
meta: { name: "list", description: "List inbox chats." },
|
|
160
|
-
args: {
|
|
212
|
+
args: {
|
|
213
|
+
...GLOBAL_FLAGS,
|
|
214
|
+
unread: {
|
|
215
|
+
type: "boolean",
|
|
216
|
+
description: "Show unread chats only (--no-unread for read-only; omit for all)."
|
|
217
|
+
// No default → three-way semantics: undefined when omitted, true for --unread, false for --no-unread
|
|
218
|
+
}
|
|
219
|
+
},
|
|
161
220
|
async run({ args }) {
|
|
162
221
|
const flags = args;
|
|
163
222
|
const cfg = await resolveEffectiveConfig({
|
|
@@ -179,7 +238,8 @@ var inboxListCommand = defineCommand({
|
|
|
179
238
|
var inboxGetCommand = defineCommand({
|
|
180
239
|
meta: { name: "get", description: "Get details of a single chat." },
|
|
181
240
|
args: {
|
|
182
|
-
|
|
241
|
+
// Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
|
|
242
|
+
...READ_SINGLE_FLAGS,
|
|
183
243
|
chatId: { type: "positional", description: "Chat ID." }
|
|
184
244
|
},
|
|
185
245
|
async run({ args }) {
|
|
@@ -204,7 +264,15 @@ var inboxMessagesCommand = defineCommand({
|
|
|
204
264
|
meta: { name: "messages", description: "List messages in a chat." },
|
|
205
265
|
args: {
|
|
206
266
|
...GLOBAL_FLAGS,
|
|
207
|
-
chatId: { type: "positional", description: "Chat ID." }
|
|
267
|
+
chatId: { type: "positional", description: "Chat ID." },
|
|
268
|
+
before: {
|
|
269
|
+
type: "string",
|
|
270
|
+
description: "Return messages before this timestamp (ISO-8601, UTC \u2014 Z suffix required, e.g. 2025-01-01T00:00:00Z)."
|
|
271
|
+
},
|
|
272
|
+
after: {
|
|
273
|
+
type: "string",
|
|
274
|
+
description: "Return messages after this timestamp (ISO-8601, UTC \u2014 Z suffix required, e.g. 2025-01-01T00:00:00Z)."
|
|
275
|
+
}
|
|
208
276
|
},
|
|
209
277
|
async run({ args }) {
|
|
210
278
|
const flags = args;
|
|
@@ -226,7 +294,10 @@ var inboxMessagesCommand = defineCommand({
|
|
|
226
294
|
});
|
|
227
295
|
var inboxSyncCommand = defineCommand({
|
|
228
296
|
meta: { name: "sync", description: "Re-sync account message history." },
|
|
229
|
-
args: {
|
|
297
|
+
args: {
|
|
298
|
+
// Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
|
|
299
|
+
...READ_SINGLE_FLAGS
|
|
300
|
+
},
|
|
230
301
|
async run({ args }) {
|
|
231
302
|
const flags = args;
|
|
232
303
|
const cfg = await resolveEffectiveConfig({
|
|
@@ -248,15 +319,27 @@ var inboxSyncCommand = defineCommand({
|
|
|
248
319
|
var inboxSyncChatCommand = defineCommand({
|
|
249
320
|
meta: { name: "sync-chat", description: "Re-sync a specific chat's message history." },
|
|
250
321
|
args: {
|
|
251
|
-
|
|
252
|
-
|
|
322
|
+
// Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields.
|
|
323
|
+
// The timeout below overrides READ_SINGLE_FLAGS.timeout with a command-specific description.
|
|
324
|
+
...READ_SINGLE_FLAGS,
|
|
325
|
+
chatId: { type: "positional", description: "Chat ID." },
|
|
326
|
+
wait: {
|
|
327
|
+
type: "boolean",
|
|
328
|
+
description: "Poll until sync completes (or --timeout elapses).",
|
|
329
|
+
default: false
|
|
330
|
+
},
|
|
331
|
+
// Override READ_SINGLE_FLAGS.timeout: here --timeout is the polling wait timeout
|
|
332
|
+
// in seconds (default: 30), not the SDK request timeout.
|
|
333
|
+
timeout: {
|
|
334
|
+
type: "string",
|
|
335
|
+
description: "Polling timeout in seconds (default: 30, requires --wait)."
|
|
336
|
+
}
|
|
253
337
|
},
|
|
254
338
|
async run({ args }) {
|
|
255
339
|
const flags = args;
|
|
256
340
|
const cfg = await resolveEffectiveConfig({
|
|
257
341
|
apiKey: flags["api-key"],
|
|
258
342
|
baseUrl: flags["base-url"],
|
|
259
|
-
timeout: flags.timeout,
|
|
260
343
|
account: flags.account,
|
|
261
344
|
profile: flags.profile
|
|
262
345
|
});
|
|
@@ -7,22 +7,27 @@ import {
|
|
|
7
7
|
AttachError,
|
|
8
8
|
readAttachment
|
|
9
9
|
} from "./chunk-Q43HZUN3.js";
|
|
10
|
+
import {
|
|
11
|
+
resolveTextOrStdin
|
|
12
|
+
} from "./chunk-CHFKVAEI.js";
|
|
10
13
|
import {
|
|
11
14
|
buildPreviewOutput
|
|
12
15
|
} from "./chunk-R3VLWLVV.js";
|
|
13
16
|
import {
|
|
17
|
+
normalizeChatId,
|
|
14
18
|
resolveIdentifier
|
|
15
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-SZB3CFRZ.js";
|
|
16
20
|
import {
|
|
17
21
|
createClient,
|
|
18
22
|
renderError,
|
|
19
23
|
renderSuccess,
|
|
20
24
|
renderUnexpectedError,
|
|
21
25
|
resolveEffectiveConfig
|
|
22
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-47SYFQRF.js";
|
|
23
27
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
READ_SINGLE_FLAGS,
|
|
29
|
+
WRITE_FLAGS
|
|
30
|
+
} from "./chunk-TDYIQHQX.js";
|
|
26
31
|
|
|
27
32
|
// src/commands/message.ts
|
|
28
33
|
import { defineCommand } from "citty";
|
|
@@ -62,8 +67,9 @@ function normalizeAttachPaths(attach) {
|
|
|
62
67
|
if (!attach) return [];
|
|
63
68
|
return Array.isArray(attach) ? attach : [attach];
|
|
64
69
|
}
|
|
65
|
-
var INMAIL_SURFACES = ["sales_nav", "recruiter"];
|
|
70
|
+
var INMAIL_SURFACES = ["sales_nav", "recruiter", "classic"];
|
|
66
71
|
var MEMBER_URN_RE = /^urn:li:member:\d+$/;
|
|
72
|
+
var MEMBER_PROVIDER_ID_RE = /^A[CDE][A-Za-z0-9_-]{4,}$/;
|
|
67
73
|
async function handleSdkError(err, outOpts, out) {
|
|
68
74
|
const { CurviateError } = await import("@curviate/sdk");
|
|
69
75
|
if (err instanceof CurviateError) {
|
|
@@ -74,10 +80,10 @@ async function handleSdkError(err, outOpts, out) {
|
|
|
74
80
|
renderUnexpectedError(err, out);
|
|
75
81
|
process.exit(1);
|
|
76
82
|
}
|
|
77
|
-
async function runMessageNew(client, flags, out) {
|
|
83
|
+
async function runMessageNew(client, flags, out, _readStdin) {
|
|
78
84
|
const accountId = requireAccount(flags.account, out);
|
|
79
|
-
const
|
|
80
|
-
const
|
|
85
|
+
const rawTo = flags.to ?? "";
|
|
86
|
+
const rawText = flags.text ?? "";
|
|
81
87
|
const attachPaths = normalizeAttachPaths(flags.attach);
|
|
82
88
|
let attachBuffers = [];
|
|
83
89
|
try {
|
|
@@ -90,14 +96,30 @@ async function runMessageNew(client, flags, out) {
|
|
|
90
96
|
}
|
|
91
97
|
throw err;
|
|
92
98
|
}
|
|
99
|
+
const ns = client.account(accountId);
|
|
100
|
+
const outOpts = resolveOutputOpts(flags);
|
|
101
|
+
const text = await resolveTextOrStdin(rawText, out, _readStdin);
|
|
102
|
+
const resolvedSlugOrId = resolveIdentifier(rawTo);
|
|
103
|
+
let providerId;
|
|
104
|
+
if (MEMBER_PROVIDER_ID_RE.test(resolvedSlugOrId)) {
|
|
105
|
+
providerId = resolvedSlugOrId;
|
|
106
|
+
} else {
|
|
107
|
+
try {
|
|
108
|
+
const profileData = await ns.profiles.get(resolvedSlugOrId, {});
|
|
109
|
+
providerId = profileData["provider_id"];
|
|
110
|
+
} catch (err) {
|
|
111
|
+
await handleSdkError(err, outOpts, out);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
93
115
|
const body = {
|
|
94
|
-
attendees_ids: [
|
|
116
|
+
attendees_ids: [providerId],
|
|
95
117
|
text
|
|
96
118
|
};
|
|
97
119
|
if (flags.preview) {
|
|
98
120
|
const preview = buildPreviewOutput({
|
|
99
121
|
method: "messaging.startChat",
|
|
100
|
-
args: { attendees_ids: [
|
|
122
|
+
args: { attendees_ids: [providerId] },
|
|
101
123
|
body: { ...body },
|
|
102
124
|
account: accountId,
|
|
103
125
|
attachments: attachBuffers.map((buf, i) => ({
|
|
@@ -111,8 +133,6 @@ async function runMessageNew(client, flags, out) {
|
|
|
111
133
|
if (attachBuffers.length > 0) {
|
|
112
134
|
body["attachments"] = attachBuffers;
|
|
113
135
|
}
|
|
114
|
-
const ns = client.account(accountId);
|
|
115
|
-
const outOpts = resolveOutputOpts(flags);
|
|
116
136
|
try {
|
|
117
137
|
const result = await ns.messaging.startChat(body);
|
|
118
138
|
renderSuccess(result, outOpts, out);
|
|
@@ -120,11 +140,12 @@ async function runMessageNew(client, flags, out) {
|
|
|
120
140
|
await handleSdkError(err, outOpts, out);
|
|
121
141
|
}
|
|
122
142
|
}
|
|
123
|
-
async function runMessageSend(client, flags, out) {
|
|
143
|
+
async function runMessageSend(client, flags, out, _readStdin) {
|
|
124
144
|
const accountId = requireAccount(flags.account, out);
|
|
125
|
-
const chatId = flags.chatId ?? "";
|
|
126
|
-
const
|
|
145
|
+
const chatId = normalizeChatId(flags.chatId ?? "");
|
|
146
|
+
const rawText = flags.text ?? "";
|
|
127
147
|
const attachPaths = normalizeAttachPaths(flags.attach);
|
|
148
|
+
const text = await resolveTextOrStdin(rawText, out, _readStdin);
|
|
128
149
|
let attachBuffers = [];
|
|
129
150
|
try {
|
|
130
151
|
attachBuffers = await Promise.all(attachPaths.map((p) => readAttachment(p)));
|
|
@@ -177,10 +198,11 @@ async function runMessageGet(client, flags, out) {
|
|
|
177
198
|
await handleSdkError(err, outOpts, out);
|
|
178
199
|
}
|
|
179
200
|
}
|
|
180
|
-
async function runMessageEdit(client, flags, out) {
|
|
201
|
+
async function runMessageEdit(client, flags, out, _readStdin) {
|
|
181
202
|
const accountId = requireAccount(flags.account, out);
|
|
182
203
|
const messageId = flags.messageId ?? "";
|
|
183
|
-
const
|
|
204
|
+
const rawText = flags.text ?? "";
|
|
205
|
+
const text = await resolveTextOrStdin(rawText, out, _readStdin);
|
|
184
206
|
if (flags.preview) {
|
|
185
207
|
const preview = buildPreviewOutput({
|
|
186
208
|
method: "messaging.editMessage",
|
|
@@ -268,7 +290,7 @@ async function runMessageAttachment(client, flags, out, isTTY) {
|
|
|
268
290
|
await handleSdkError(err, outOpts, out);
|
|
269
291
|
}
|
|
270
292
|
}
|
|
271
|
-
async function runMessageInMail(client, flags, out) {
|
|
293
|
+
async function runMessageInMail(client, flags, out, _readStdin) {
|
|
272
294
|
const accountId = requireAccount(flags.account, out);
|
|
273
295
|
const surface = flags.surface ?? "";
|
|
274
296
|
if (!INMAIL_SURFACES.includes(surface)) {
|
|
@@ -278,15 +300,34 @@ async function runMessageInMail(client, flags, out) {
|
|
|
278
300
|
);
|
|
279
301
|
process.exit(2);
|
|
280
302
|
}
|
|
281
|
-
const
|
|
282
|
-
if (!
|
|
303
|
+
const rawTo = flags.to ?? "";
|
|
304
|
+
if (!rawTo) {
|
|
283
305
|
out.stderr.write(
|
|
284
|
-
"error: --to
|
|
306
|
+
"error: --to: not a valid LinkedIn URL, slug, provider-id, or URN.\n"
|
|
285
307
|
);
|
|
286
308
|
process.exit(2);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const ns = client.account(accountId);
|
|
312
|
+
const outOpts = resolveOutputOpts(flags);
|
|
313
|
+
const resolvedSlugOrId = resolveIdentifier(rawTo);
|
|
314
|
+
let recipientUrn;
|
|
315
|
+
if (MEMBER_URN_RE.test(resolvedSlugOrId)) {
|
|
316
|
+
recipientUrn = resolvedSlugOrId;
|
|
317
|
+
} else if (MEMBER_PROVIDER_ID_RE.test(resolvedSlugOrId)) {
|
|
318
|
+
recipientUrn = resolvedSlugOrId;
|
|
319
|
+
} else {
|
|
320
|
+
try {
|
|
321
|
+
const profileData = await ns.profiles.get(resolvedSlugOrId, {});
|
|
322
|
+
recipientUrn = profileData["provider_id"];
|
|
323
|
+
} catch (err) {
|
|
324
|
+
await handleSdkError(err, outOpts, out);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
287
327
|
}
|
|
288
328
|
const subject = flags.subject ?? "";
|
|
289
|
-
const
|
|
329
|
+
const rawText = flags.text ?? "";
|
|
330
|
+
const text = await resolveTextOrStdin(rawText, out, _readStdin);
|
|
290
331
|
const body = {
|
|
291
332
|
recipient_urn: recipientUrn,
|
|
292
333
|
surface,
|
|
@@ -303,8 +344,6 @@ async function runMessageInMail(client, flags, out) {
|
|
|
303
344
|
out.stdout.write(JSON.stringify(preview) + "\n");
|
|
304
345
|
return;
|
|
305
346
|
}
|
|
306
|
-
const ns = client.account(accountId);
|
|
307
|
-
const outOpts = resolveOutputOpts(flags);
|
|
308
347
|
try {
|
|
309
348
|
const result = await ns.messaging.sendInMail(body);
|
|
310
349
|
renderSuccess(result, outOpts, out);
|
|
@@ -328,9 +367,14 @@ async function runMessageInMailBalance(client, flags, out) {
|
|
|
328
367
|
var messageNewCommand = defineCommand({
|
|
329
368
|
meta: { name: "new", description: "Start a new chat with one or more members." },
|
|
330
369
|
args: {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
370
|
+
// Write command: WRITE_FLAGS omits pagination/projection flags
|
|
371
|
+
...WRITE_FLAGS,
|
|
372
|
+
to: {
|
|
373
|
+
type: "string",
|
|
374
|
+
description: "Recipient: LinkedIn profile URL (e.g. https://www.linkedin.com/in/some-slug), bare slug (e.g. some-slug), or provider ID (e.g. ACoAAA\u2026). URL and slug inputs resolve the provider ID automatically.",
|
|
375
|
+
required: true
|
|
376
|
+
},
|
|
377
|
+
text: { type: "positional", description: "Opening message text. Pass - to read from stdin (e.g. via heredoc or pipe)." },
|
|
334
378
|
attach: { type: "string", description: "File to attach (repeatable)." }
|
|
335
379
|
},
|
|
336
380
|
async run({ args }) {
|
|
@@ -354,7 +398,8 @@ var messageNewCommand = defineCommand({
|
|
|
354
398
|
var messageGetCommand = defineCommand({
|
|
355
399
|
meta: { name: "get", description: "Get a message by ID." },
|
|
356
400
|
args: {
|
|
357
|
-
|
|
401
|
+
// Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
|
|
402
|
+
...READ_SINGLE_FLAGS,
|
|
358
403
|
messageId: { type: "positional", description: "Message ID." }
|
|
359
404
|
},
|
|
360
405
|
async run({ args }) {
|
|
@@ -378,9 +423,10 @@ var messageGetCommand = defineCommand({
|
|
|
378
423
|
var messageEditCommand = defineCommand({
|
|
379
424
|
meta: { name: "edit", description: "Edit a message (within the allowed window)." },
|
|
380
425
|
args: {
|
|
381
|
-
|
|
426
|
+
// Write command: WRITE_FLAGS omits pagination/projection flags
|
|
427
|
+
...WRITE_FLAGS,
|
|
382
428
|
messageId: { type: "positional", description: "Message ID." },
|
|
383
|
-
text: { type: "positional", description: "Replacement text." }
|
|
429
|
+
text: { type: "positional", description: "Replacement text. Pass - to read from stdin." }
|
|
384
430
|
},
|
|
385
431
|
async run({ args }) {
|
|
386
432
|
const flags = args;
|
|
@@ -403,7 +449,8 @@ var messageEditCommand = defineCommand({
|
|
|
403
449
|
var messageDeleteCommand = defineCommand({
|
|
404
450
|
meta: { name: "delete", description: "Delete a message." },
|
|
405
451
|
args: {
|
|
406
|
-
|
|
452
|
+
// Write command: WRITE_FLAGS omits pagination/projection flags
|
|
453
|
+
...WRITE_FLAGS,
|
|
407
454
|
messageId: { type: "positional", description: "Message ID." }
|
|
408
455
|
},
|
|
409
456
|
async run({ args }) {
|
|
@@ -427,7 +474,8 @@ var messageDeleteCommand = defineCommand({
|
|
|
427
474
|
var messageReactCommand = defineCommand({
|
|
428
475
|
meta: { name: "react", description: "Add an emoji reaction to a message." },
|
|
429
476
|
args: {
|
|
430
|
-
|
|
477
|
+
// Write command: WRITE_FLAGS omits pagination/projection flags
|
|
478
|
+
...WRITE_FLAGS,
|
|
431
479
|
messageId: { type: "positional", description: "Message ID." },
|
|
432
480
|
emoji: { type: "string", description: "Native emoji reaction value (e.g. \u{1F44D}).", required: true }
|
|
433
481
|
},
|
|
@@ -452,7 +500,8 @@ var messageReactCommand = defineCommand({
|
|
|
452
500
|
var messageAttachmentCommand = defineCommand({
|
|
453
501
|
meta: { name: "attachment", description: "Download a message attachment." },
|
|
454
502
|
args: {
|
|
455
|
-
|
|
503
|
+
// Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
|
|
504
|
+
...READ_SINGLE_FLAGS,
|
|
456
505
|
messageId: { type: "positional", description: "Message ID." },
|
|
457
506
|
attachmentId: { type: "positional", description: "Attachment ID." },
|
|
458
507
|
output: { type: "string", alias: "o", description: "Path to write the file to." }
|
|
@@ -483,11 +532,16 @@ var messageAttachmentCommand = defineCommand({
|
|
|
483
532
|
var messageInMailCommand = defineCommand({
|
|
484
533
|
meta: { name: "inmail", description: "Send an InMail to a member." },
|
|
485
534
|
args: {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
535
|
+
// Write command: WRITE_FLAGS omits pagination/projection flags
|
|
536
|
+
...WRITE_FLAGS,
|
|
537
|
+
to: {
|
|
538
|
+
type: "string",
|
|
539
|
+
description: "Recipient: LinkedIn profile URL, bare slug, provider-id (ACoAAA\u2026), or member URN (urn:li:member:<id>). URL and slug inputs resolve the provider ID automatically.",
|
|
540
|
+
required: true
|
|
541
|
+
},
|
|
542
|
+
surface: { type: "string", description: "InMail surface: sales_nav, recruiter, or classic (classic uses the account's own premium InMail credits).", required: true },
|
|
489
543
|
subject: { type: "string", description: "InMail subject line.", required: true },
|
|
490
|
-
text: { type: "positional", description: "InMail body text." }
|
|
544
|
+
text: { type: "positional", description: "InMail body text. Pass - to read from stdin." }
|
|
491
545
|
},
|
|
492
546
|
async run({ args }) {
|
|
493
547
|
const flags = args;
|
|
@@ -507,9 +561,39 @@ var messageInMailCommand = defineCommand({
|
|
|
507
561
|
await runMessageInMail(client, { ...flags, account: flags.account ?? cfg.account }, out);
|
|
508
562
|
}
|
|
509
563
|
});
|
|
564
|
+
var messageSendCommand = defineCommand({
|
|
565
|
+
meta: { name: "send", description: "Send a message to an existing chat." },
|
|
566
|
+
args: {
|
|
567
|
+
// Write command: WRITE_FLAGS omits pagination/projection flags
|
|
568
|
+
...WRITE_FLAGS,
|
|
569
|
+
chatId: { type: "positional", description: "Chat ID or LinkedIn messaging thread URL." },
|
|
570
|
+
text: { type: "positional", description: "Message text. Pass - to read from stdin (e.g. via heredoc or pipe)." },
|
|
571
|
+
attach: { type: "string", description: "File to attach (repeatable)." }
|
|
572
|
+
},
|
|
573
|
+
async run({ args }) {
|
|
574
|
+
const flags = args;
|
|
575
|
+
const cfg = await resolveEffectiveConfig({
|
|
576
|
+
apiKey: flags["api-key"],
|
|
577
|
+
baseUrl: flags["base-url"],
|
|
578
|
+
timeout: flags.timeout,
|
|
579
|
+
account: flags.account,
|
|
580
|
+
profile: flags.profile
|
|
581
|
+
});
|
|
582
|
+
if (!cfg.apiKey) {
|
|
583
|
+
process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
|
|
584
|
+
process.exit(3);
|
|
585
|
+
}
|
|
586
|
+
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
587
|
+
const out = buildOutputStreams();
|
|
588
|
+
await runMessageSend(client, { ...flags, account: flags.account ?? cfg.account }, out);
|
|
589
|
+
}
|
|
590
|
+
});
|
|
510
591
|
var messageInMailBalanceCommand = defineCommand({
|
|
511
592
|
meta: { name: "inmail-balance", description: "Get InMail credit balance." },
|
|
512
|
-
args: {
|
|
593
|
+
args: {
|
|
594
|
+
// Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
|
|
595
|
+
...READ_SINGLE_FLAGS
|
|
596
|
+
},
|
|
513
597
|
async run({ args }) {
|
|
514
598
|
const flags = args;
|
|
515
599
|
const cfg = await resolveEffectiveConfig({
|
|
@@ -531,13 +615,15 @@ var messageInMailBalanceCommand = defineCommand({
|
|
|
531
615
|
var messageCommand = defineCommand({
|
|
532
616
|
meta: { name: "message", description: "Send and manage LinkedIn messages." },
|
|
533
617
|
args: {
|
|
534
|
-
|
|
618
|
+
// Write command (message send): WRITE_FLAGS omits pagination/projection flags
|
|
619
|
+
...WRITE_FLAGS,
|
|
535
620
|
chatId: { type: "positional", description: "Chat ID to send a message to.", required: false },
|
|
536
|
-
text: { type: "positional", description: "Message text.", required: false },
|
|
621
|
+
text: { type: "positional", description: "Message text. Pass - to read from stdin.", required: false },
|
|
537
622
|
attach: { type: "string", description: "File to attach (repeatable)." }
|
|
538
623
|
},
|
|
539
624
|
subCommands: {
|
|
540
625
|
new: messageNewCommand,
|
|
626
|
+
send: messageSendCommand,
|
|
541
627
|
get: messageGetCommand,
|
|
542
628
|
edit: messageEditCommand,
|
|
543
629
|
delete: messageDeleteCommand,
|
|
@@ -3,6 +3,9 @@ import {
|
|
|
3
3
|
AttachError,
|
|
4
4
|
readAttachment
|
|
5
5
|
} from "./chunk-Q43HZUN3.js";
|
|
6
|
+
import {
|
|
7
|
+
resolveTextOrStdin
|
|
8
|
+
} from "./chunk-CHFKVAEI.js";
|
|
6
9
|
import {
|
|
7
10
|
buildPreviewOutput
|
|
8
11
|
} from "./chunk-R3VLWLVV.js";
|
|
@@ -15,11 +18,11 @@ import {
|
|
|
15
18
|
renderSuccess,
|
|
16
19
|
renderUnexpectedError,
|
|
17
20
|
resolveEffectiveConfig
|
|
18
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-47SYFQRF.js";
|
|
19
22
|
import {
|
|
20
23
|
GLOBAL_FLAGS,
|
|
21
24
|
WRITE_FLAGS
|
|
22
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-TDYIQHQX.js";
|
|
23
26
|
|
|
24
27
|
// src/commands/post.ts
|
|
25
28
|
import { defineCommand } from "citty";
|
|
@@ -115,11 +118,12 @@ async function runPostGet(client, flags, out) {
|
|
|
115
118
|
await handleSdkError(err, outOpts, out);
|
|
116
119
|
}
|
|
117
120
|
}
|
|
118
|
-
async function runPostCreate(client, flags, out) {
|
|
121
|
+
async function runPostCreate(client, flags, out, _readStdin) {
|
|
119
122
|
const accountId = requireAccount(flags.account, out);
|
|
120
|
-
const
|
|
123
|
+
const rawText = flags.text ?? "";
|
|
121
124
|
const attachPaths = normalizeAttachPaths(flags.attach);
|
|
122
125
|
const thumbPath = flags["video-thumbnail"];
|
|
126
|
+
const text = await resolveTextOrStdin(rawText, out, _readStdin);
|
|
123
127
|
let attachBuffers = [];
|
|
124
128
|
try {
|
|
125
129
|
attachBuffers = await Promise.all(attachPaths.map((p) => readAttachment(p)));
|
|
@@ -181,11 +185,12 @@ async function runPostCreate(client, flags, out) {
|
|
|
181
185
|
await handleSdkError(err, outOpts, out);
|
|
182
186
|
}
|
|
183
187
|
}
|
|
184
|
-
async function runPostComment(client, flags, out) {
|
|
188
|
+
async function runPostComment(client, flags, out, _readStdin) {
|
|
185
189
|
const accountId = requireAccount(flags.account, out);
|
|
186
190
|
const postId = flags.postId ?? "";
|
|
187
|
-
const
|
|
191
|
+
const rawText = flags.text ?? "";
|
|
188
192
|
const replyTo = flags["reply-to"];
|
|
193
|
+
const text = await resolveTextOrStdin(rawText, out, _readStdin);
|
|
189
194
|
const attachPaths = normalizeAttachPaths(flags.attach);
|
|
190
195
|
let attachBuffers = [];
|
|
191
196
|
try {
|
|
@@ -368,7 +373,7 @@ var postCreateCommand = defineCommand({
|
|
|
368
373
|
args: {
|
|
369
374
|
// Write command: WRITE_FLAGS omits pagination/projection flags
|
|
370
375
|
...WRITE_FLAGS,
|
|
371
|
-
text: { type: "positional", description: "Post body text." },
|
|
376
|
+
text: { type: "positional", description: "Post body text. Pass - to read from stdin (enables multiline via heredoc or pipe)." },
|
|
372
377
|
attach: {
|
|
373
378
|
type: "string",
|
|
374
379
|
description: "Image/video/document to attach (repeatable for images; use --video-thumbnail when attaching a video). Supported: jpg, png, gif, mp4, pdf."
|
|
@@ -405,7 +410,7 @@ var postCommentCommand = defineCommand({
|
|
|
405
410
|
type: "positional",
|
|
406
411
|
description: "Numeric post id, urn:li:activity:N, or full LinkedIn share URL (activity-<N>- extracted). POSTID is always the post's id; use --reply-to <comment_id> to reply to a specific comment within this post."
|
|
407
412
|
},
|
|
408
|
-
text: { type: "positional", description: "Comment text (max ~1,250 characters per LinkedIn limits)." },
|
|
413
|
+
text: { type: "positional", description: "Comment text (max ~1,250 characters per LinkedIn limits). Pass - to read from stdin." },
|
|
409
414
|
attach: { type: "string", description: "Image to attach to the comment (optional; one image per comment)." },
|
|
410
415
|
"reply-to": {
|
|
411
416
|
type: "string",
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
slimProfile,
|
|
4
|
-
slimProfileMe
|
|
5
|
-
} from "./chunk-5NS2G4WQ.js";
|
|
6
2
|
import {
|
|
7
3
|
buildPreviewOutput
|
|
8
4
|
} from "./chunk-R3VLWLVV.js";
|
|
5
|
+
import {
|
|
6
|
+
slimProfile,
|
|
7
|
+
slimProfileMe
|
|
8
|
+
} from "./chunk-6VBOKOQJ.js";
|
|
9
9
|
import {
|
|
10
10
|
resolveIdentifier
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-SZB3CFRZ.js";
|
|
12
12
|
import {
|
|
13
13
|
streamAll
|
|
14
14
|
} from "./chunk-SND3NHCT.js";
|
|
@@ -18,10 +18,10 @@ import {
|
|
|
18
18
|
renderSuccess,
|
|
19
19
|
renderUnexpectedError,
|
|
20
20
|
resolveEffectiveConfig
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-47SYFQRF.js";
|
|
22
22
|
import {
|
|
23
23
|
GLOBAL_FLAGS
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-TDYIQHQX.js";
|
|
25
25
|
|
|
26
26
|
// src/commands/profile.ts
|
|
27
27
|
import { defineCommand } from "citty";
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-R3VLWLVV.js";
|
|
13
13
|
import {
|
|
14
14
|
resolveIdentifier
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-SZB3CFRZ.js";
|
|
16
16
|
import {
|
|
17
17
|
DEFAULT_FILTER_READERS,
|
|
18
18
|
assembleFilters,
|
|
@@ -27,10 +27,10 @@ import {
|
|
|
27
27
|
renderSuccess,
|
|
28
28
|
renderUnexpectedError,
|
|
29
29
|
resolveEffectiveConfig
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-47SYFQRF.js";
|
|
31
31
|
import {
|
|
32
32
|
GLOBAL_FLAGS
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-TDYIQHQX.js";
|
|
34
34
|
|
|
35
35
|
// src/commands/recruiter.ts
|
|
36
36
|
import { defineCommand } from "citty";
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-R3VLWLVV.js";
|
|
9
9
|
import {
|
|
10
10
|
resolveIdentifier
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-SZB3CFRZ.js";
|
|
12
12
|
import {
|
|
13
13
|
DEFAULT_FILTER_READERS,
|
|
14
14
|
assembleFilters,
|
|
@@ -24,10 +24,10 @@ import {
|
|
|
24
24
|
renderSuccess,
|
|
25
25
|
renderUnexpectedError,
|
|
26
26
|
resolveEffectiveConfig
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-47SYFQRF.js";
|
|
28
28
|
import {
|
|
29
29
|
GLOBAL_FLAGS
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-TDYIQHQX.js";
|
|
31
31
|
|
|
32
32
|
// src/commands/sales-nav.ts
|
|
33
33
|
import { defineCommand } from "citty";
|
|
@@ -14,10 +14,10 @@ import {
|
|
|
14
14
|
renderSuccess,
|
|
15
15
|
renderUnexpectedError,
|
|
16
16
|
resolveEffectiveConfig
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-47SYFQRF.js";
|
|
18
18
|
import {
|
|
19
19
|
GLOBAL_FLAGS
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-TDYIQHQX.js";
|
|
21
21
|
|
|
22
22
|
// src/commands/search.ts
|
|
23
23
|
import { defineCommand } from "citty";
|
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
renderSuccess,
|
|
12
12
|
renderUnexpectedError,
|
|
13
13
|
resolveEffectiveConfig
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-47SYFQRF.js";
|
|
15
15
|
import {
|
|
16
16
|
GLOBAL_FLAGS
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-TDYIQHQX.js";
|
|
18
18
|
|
|
19
19
|
// src/commands/webhook.ts
|
|
20
20
|
import { defineCommand } from "citty";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@curviate/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Official command-line interface for the Curviate API.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"clean": "rm -rf dist *.tsbuildinfo"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@curviate/sdk": "^0.
|
|
43
|
+
"@curviate/sdk": "^0.4.0",
|
|
44
44
|
"citty": "^0.1.6"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|