@curviate/cli 0.19.0 → 0.20.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 +95 -0
- package/dist/{account-EGJJNBXW.js → account-2SOSCEB6.js} +26 -26
- package/dist/{chunk-TMU3CSPR.js → chunk-DW2HCRXJ.js} +1 -1
- package/dist/{chunk-M33MI53G.js → chunk-HDQUEFD2.js} +1 -1
- package/dist/chunk-HOQ7EUHJ.js +50 -0
- package/dist/{chunk-KVV6LZ7E.js → chunk-IGCQNDIG.js} +53 -17
- package/dist/cli.js +33 -33
- package/dist/{comment-VT6PO4MN.js → comment-AXDINBPS.js} +3 -3
- package/dist/{company-XEEBBCRZ.js → company-BX4VDXZX.js} +19 -18
- package/dist/{config-P5CPF5WC.js → config-3O4N2XSH.js} +2 -2
- package/dist/{connect-6PU7QCOL.js → connect-KWOJKCIB.js} +36 -15
- package/dist/{feed-KAUDRE5K.js → feed-4ROKUBG5.js} +3 -3
- package/dist/{group-LPVVJ2JX.js → group-L7TQEEFN.js} +7 -7
- package/dist/{inbox-BXCWHGWP.js → inbox-GMGZVDTQ.js} +9 -9
- package/dist/{inboxes-MTPWLP5F.js → inboxes-YVYLSM5W.js} +4 -4
- package/dist/{job-EIXBJXLW.js → job-TYBA2DUQ.js} +7 -7
- package/dist/{login-GDLWR542.js → login-W7NCDZOQ.js} +2 -2
- package/dist/{message-UWMRE2SJ.js → message-C6FV6JH6.js} +6 -3
- package/dist/{notification-RYFDHM3G.js → notification-45XFT3S4.js} +5 -5
- package/dist/{post-HK6HHIKV.js → post-RETV3WUG.js} +8 -8
- package/dist/{profile-PES67647.js → profile-A2TWF4HB.js} +13 -13
- package/dist/{recruiter-MVPSTH2V.js → recruiter-FQAKY6Z2.js} +30 -30
- package/dist/{sales-nav-TMXWDKSE.js → sales-nav-SSJIZUNB.js} +16 -16
- package/dist/{search-O2LACGHE.js → search-DH6BJFQC.js} +13 -13
- package/dist/{webhook-QFSZN3P2.js → webhook-LED6AKF3.js} +50 -19
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,101 @@ 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.20.0] - 2026-08-03
|
|
12
|
+
|
|
13
|
+
A safety and correctness release. Upgrade promptly: it closes a path by which a
|
|
14
|
+
mistyped command sent a message, and it is the first release in which
|
|
15
|
+
`curviate webhook verify` works at all.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **An unknown subcommand under `message` no longer becomes a send.**
|
|
20
|
+
`curviate message search "sophie"` did not error. `message` accepts both
|
|
21
|
+
subcommands and a bare `message <chat_id> "<text>"` form, and an unregistered
|
|
22
|
+
first token fell through to the bare form, so it bound `chatId="search"`,
|
|
23
|
+
`text="sophie"` and **sent a message**. That applied to any unknown or
|
|
24
|
+
mistyped subcommand: with `search` it 404s, but with a real chat id in that
|
|
25
|
+
position, or a paste that lands one there, it messaged a real person.
|
|
26
|
+
|
|
27
|
+
An unknown subcommand now exits 2 with usage and issues **no request at all**.
|
|
28
|
+
The legitimate `curviate message <chat_id> "<text>"` form is unchanged, and
|
|
29
|
+
`curviate message send <chat_id> "<text>"` is always available for a chat id
|
|
30
|
+
the check does not recognise.
|
|
31
|
+
|
|
32
|
+
To search your messages, the command is `curviate inbox search`.
|
|
33
|
+
|
|
34
|
+
- **A mistyped `connect` subcommand no longer sends a connection invitation.**
|
|
35
|
+
Same shape: `curviate connect <id>` sends an invitation, so `connect snet`
|
|
36
|
+
(for `sent`) invited whoever owns the slug `snet`. A first argument that is a
|
|
37
|
+
near-miss of a `connect` subcommand is now refused with a suggestion. If the
|
|
38
|
+
slug really was intended, pass the full profile URL or the provider id.
|
|
39
|
+
|
|
40
|
+
- **`curviate webhook verify` now verifies real deliveries.** It inherited a
|
|
41
|
+
defect from `@curviate/sdk`: the platform sends the event name in `event` and
|
|
42
|
+
the SDK required a `type` field no delivery has ever carried, so verification
|
|
43
|
+
failed on 100% of genuine webhooks and reported `malformed_header`, pointing
|
|
44
|
+
at the header and the secret when both were correct. Fixed by the `@curviate/sdk`
|
|
45
|
+
0.19.0 dependency bump. A body that verifies but cannot be parsed now reports
|
|
46
|
+
`malformed_payload`.
|
|
47
|
+
|
|
48
|
+
- **`webhook verify --body` accepts the raw body inline, as a file path, or on
|
|
49
|
+
stdin.** Every documented invocation failed before this: the flag value was
|
|
50
|
+
handed straight to the filesystem, so inline JSON was opened as a filename
|
|
51
|
+
(`ENOENT`/`ENAMETOOLONG`), and `--body -` opened the internal placeholder the
|
|
52
|
+
argument parser substitutes for a bare dash. Only a file path ever worked, and
|
|
53
|
+
the failure surfaced as exit `1` with a raw filesystem error rather than a
|
|
54
|
+
usage error. A body is now recognised by its leading `{`, `-` reads stdin on
|
|
55
|
+
every platform, and anything unreadable exits `2` naming all three accepted
|
|
56
|
+
forms. A trailing newline added by a shell redirect, `curl -o`, or an editor
|
|
57
|
+
save is ignored; newlines inside the body are preserved.
|
|
58
|
+
|
|
59
|
+
- **`webhook verify --help` named the wrong signature header.** It said
|
|
60
|
+
`X-Curviate-Signature`; the platform sends `Curviate-Signature`, so a reader
|
|
61
|
+
who copied the name read for a header that is never present. The same help
|
|
62
|
+
also claimed `--header` falls back to stdin, which it never did. Both flags
|
|
63
|
+
are now marked required, so omitting one is a usage error instead of a
|
|
64
|
+
signature failure that points at a secret which was never wrong.
|
|
65
|
+
|
|
66
|
+
- **`group list` help said `--profile`; the flag is `--target`.** `--profile` is
|
|
67
|
+
the global config-profile selector, so following the help text selected a
|
|
68
|
+
config profile and silently returned your own groups instead of the target
|
|
69
|
+
member's.
|
|
70
|
+
|
|
71
|
+
- **`job publish` and `recruiter job publish` help said `--budget-*`.** The glob
|
|
72
|
+
is not a flag anyone can type; the help now names `--budget-amount`,
|
|
73
|
+
`--budget-currency`, and `--budget-scope`.
|
|
74
|
+
|
|
75
|
+
- **Em dashes removed from all CLI output** (error messages, help text, usage
|
|
76
|
+
blocks), including the `no API key` error.
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- `@curviate/sdk` dependency bumped to `^0.19.0`. If you also call the SDK
|
|
81
|
+
directly, note that its webhook event discriminant moved from `event.type` to
|
|
82
|
+
`event.event`; see the SDK's 0.19.0 changelog.
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
|
|
86
|
+
- Two mechanical guards in the test suite, both derived from the live command
|
|
87
|
+
tree rather than a hand-maintained list, so this class of defect cannot
|
|
88
|
+
quietly return:
|
|
89
|
+
- a fall-through audit that forces an explicit safe/read-only/write-bearing
|
|
90
|
+
verdict on every command group that mixes subcommands with a positional
|
|
91
|
+
fallback, and
|
|
92
|
+
- a help-vs-args check that fails when any command's help text names a flag
|
|
93
|
+
that command does not declare (resolving cross-references, so a reference
|
|
94
|
+
to another command's flag is checked against that command).
|
|
95
|
+
|
|
96
|
+
- Two further mechanical guards, in the same spirit:
|
|
97
|
+
- an em-dash check that walks the TypeScript syntax tree, so it inspects
|
|
98
|
+
string and template literals only and leaves comments exempt structurally
|
|
99
|
+
rather than by a fragile line-based heuristic, and
|
|
100
|
+
- a pre-publish binary gate that runs every documented `webhook verify --body`
|
|
101
|
+
form against a recorded delivery: the exact body bytes and the exact
|
|
102
|
+
signature header the platform put on the wire, replayed verbatim and never
|
|
103
|
+
re-signed. Tampering with a single field is still rejected, so the gate
|
|
104
|
+
proves the verdict as well as the plumbing.
|
|
105
|
+
|
|
11
106
|
## [0.19.0] - 2026-07-29
|
|
12
107
|
|
|
13
108
|
A minor release closing the remaining SDK-parity gap: 25 new commands across seven
|
|
@@ -26,12 +26,12 @@ import {
|
|
|
26
26
|
renderSuccess,
|
|
27
27
|
renderUnexpectedError,
|
|
28
28
|
resolveEffectiveConfig
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-HDQUEFD2.js";
|
|
30
30
|
import {
|
|
31
31
|
GLOBAL_FLAGS,
|
|
32
32
|
READ_SINGLE_FLAGS,
|
|
33
33
|
WRITE_SINGLE_FLAGS
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-DW2HCRXJ.js";
|
|
35
35
|
|
|
36
36
|
// src/commands/account.ts
|
|
37
37
|
import { defineCommand } from "citty";
|
|
@@ -90,15 +90,15 @@ function checkCredentialConflicts(flags, out) {
|
|
|
90
90
|
const passwordStdin = flags["password-stdin"] ?? false;
|
|
91
91
|
const liAtStdin = flags["li-at-stdin"] ?? false;
|
|
92
92
|
if (flags.password !== void 0 && passwordStdin) {
|
|
93
|
-
failConflict(out, "--password and --password-stdin cannot both be set
|
|
93
|
+
failConflict(out, "--password and --password-stdin cannot both be set. Choose one source.");
|
|
94
94
|
}
|
|
95
95
|
if (flags["li-at"] !== void 0 && liAtStdin) {
|
|
96
|
-
failConflict(out, "--li-at and --li-at-stdin cannot both be set
|
|
96
|
+
failConflict(out, "--li-at and --li-at-stdin cannot both be set. Choose one source.");
|
|
97
97
|
}
|
|
98
98
|
if (passwordStdin && liAtStdin) {
|
|
99
99
|
failConflict(
|
|
100
100
|
out,
|
|
101
|
-
"--password-stdin and --li-at-stdin cannot both be set
|
|
101
|
+
"--password-stdin and --li-at-stdin cannot both be set. stdin can feed only one secret per invocation."
|
|
102
102
|
);
|
|
103
103
|
}
|
|
104
104
|
if (liAtStdin && flags["auth-method"] === "credentials") {
|
|
@@ -164,7 +164,7 @@ function challengeDescription(type) {
|
|
|
164
164
|
case "two_factor_app":
|
|
165
165
|
return "Enter the current code from your authenticator app.";
|
|
166
166
|
case "mobile_app_approval":
|
|
167
|
-
return "Open your LinkedIn mobile app and approve this sign-in
|
|
167
|
+
return "Open your LinkedIn mobile app and approve this sign-in. This will continue automatically once you tap approve.";
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
function printChallengeCopy(type, out) {
|
|
@@ -293,7 +293,7 @@ async function buildAuthBody(flags, ctx) {
|
|
|
293
293
|
// of --email — an email-less body still fails downstream validation,
|
|
294
294
|
// as expected, rather than the flag being silently ignored.
|
|
295
295
|
allowInteractiveStdinRead: !ctx.previewMode,
|
|
296
|
-
failMessage: "no password
|
|
296
|
+
failMessage: "no password. Pass --password, --password-stdin, or set CURVIATE_LINKEDIN_PASSWORD",
|
|
297
297
|
prompt: { isTTY: ctx.isTTY, readline: ctx.readline, promptText: "LinkedIn password: " },
|
|
298
298
|
out: ctx.out
|
|
299
299
|
});
|
|
@@ -314,7 +314,7 @@ async function buildAuthBody(flags, ctx) {
|
|
|
314
314
|
readSingleLine: ctx.readSingleLine,
|
|
315
315
|
required: true,
|
|
316
316
|
allowInteractive: !ctx.previewMode,
|
|
317
|
-
failMessage: "no li_at
|
|
317
|
+
failMessage: "no li_at. Pass --li-at, --li-at-stdin, or set CURVIATE_LINKEDIN_LI_AT",
|
|
318
318
|
out: ctx.out
|
|
319
319
|
});
|
|
320
320
|
const liA = await resolveSecret({
|
|
@@ -377,7 +377,7 @@ function printConnected(result, ctx) {
|
|
|
377
377
|
}
|
|
378
378
|
function printInvalidCodeRetryHint(err, out) {
|
|
379
379
|
const attemptsRemaining = err.attempts_remaining;
|
|
380
|
-
const message = typeof attemptsRemaining === "number" ? `That code was not accepted
|
|
380
|
+
const message = typeof attemptsRemaining === "number" ? `That code was not accepted. ${attemptsRemaining} attempt(s) remaining.` : "That code was not accepted. Please try again.";
|
|
381
381
|
out.stderr.write(`${message}
|
|
382
382
|
`);
|
|
383
383
|
}
|
|
@@ -620,7 +620,7 @@ async function runAccountConnectSessionPoll(client, flags, out, io = {}) {
|
|
|
620
620
|
}
|
|
621
621
|
renderSuccess(outcome.result, outOpts, out);
|
|
622
622
|
out.stderr.write(
|
|
623
|
-
`Still waiting for the account to connect
|
|
623
|
+
`Still waiting for the account to connect. The wait window elapsed. Check again: curviate account connect-session poll --session ${flags.session} --wait
|
|
624
624
|
`
|
|
625
625
|
);
|
|
626
626
|
process.exit(AUTH_NEEDED);
|
|
@@ -851,7 +851,7 @@ async function runAccountCheckpointPoll(client, flags, out, io = {}) {
|
|
|
851
851
|
}
|
|
852
852
|
renderSuccess(outcome.result, outOpts, out);
|
|
853
853
|
out.stderr.write(
|
|
854
|
-
`Still waiting for approval
|
|
854
|
+
`Still waiting for approval. The wait window elapsed. Check again: curviate account checkpoint poll ${accountId} --wait
|
|
855
855
|
`
|
|
856
856
|
);
|
|
857
857
|
process.exit(AUTH_NEEDED);
|
|
@@ -868,7 +868,7 @@ var accountListCommand = defineCommand({
|
|
|
868
868
|
profile: flags.profile
|
|
869
869
|
});
|
|
870
870
|
if (!cfg.apiKey) {
|
|
871
|
-
process.stderr.write("error: no API key
|
|
871
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
872
872
|
process.exit(3);
|
|
873
873
|
}
|
|
874
874
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -892,7 +892,7 @@ var accountGetCommand = defineCommand({
|
|
|
892
892
|
profile: flags.profile
|
|
893
893
|
});
|
|
894
894
|
if (!cfg.apiKey) {
|
|
895
|
-
process.stderr.write("error: no API key
|
|
895
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
896
896
|
process.exit(3);
|
|
897
897
|
}
|
|
898
898
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -924,10 +924,10 @@ var accountLinkCommand = defineCommand({
|
|
|
924
924
|
"proxy-password": { type: "string", description: `Proxy auth password. ${OPTIONAL_SECRET_WARNING("CURVIATE_PROXY_PASSWORD")}` },
|
|
925
925
|
"user-agent": { type: "string", description: "Browser User-Agent to pin for this account." },
|
|
926
926
|
"recruiter-contract-id": { type: "string", description: "Recruiter contract to bind to (Recruiter tier only)." },
|
|
927
|
-
"account-id": { type: "string", description: "Existing account id (acc_\u2026) to re-authenticate IN PLACE
|
|
927
|
+
"account-id": { type: "string", description: "Existing account id (acc_\u2026) to re-authenticate IN PLACE. Passing it makes this an in-place reconnect of that account. Omit to connect a NEW account into --seat-id." },
|
|
928
928
|
"no-interactive": {
|
|
929
929
|
type: "boolean",
|
|
930
|
-
description: "Never prompt for a checkpoint code
|
|
930
|
+
description: "Never prompt for a checkpoint code. On a checkpoint, always render the envelope and exit 12, even on a TTY.",
|
|
931
931
|
default: false
|
|
932
932
|
}
|
|
933
933
|
},
|
|
@@ -940,7 +940,7 @@ var accountLinkCommand = defineCommand({
|
|
|
940
940
|
profile: flags.profile
|
|
941
941
|
});
|
|
942
942
|
if (!cfg.apiKey) {
|
|
943
|
-
process.stderr.write("error: no API key
|
|
943
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
944
944
|
process.exit(3);
|
|
945
945
|
}
|
|
946
946
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -951,7 +951,7 @@ var accountLinkCommand = defineCommand({
|
|
|
951
951
|
var accountConnectSessionPollCommand = defineCommand({
|
|
952
952
|
meta: {
|
|
953
953
|
name: "poll",
|
|
954
|
-
description: "Poll the status of an in-progress connect (auth intent) for completion. Without --wait: a single poll
|
|
954
|
+
description: "Poll the status of an in-progress connect (auth intent) for completion. Without --wait: a single poll. The JSON `status` field (pending | resolved | expired | failed) tells you what to do next. With --wait: block on the same adaptive cadence as `account link` until a terminal state."
|
|
955
955
|
},
|
|
956
956
|
args: {
|
|
957
957
|
...WRITE_SINGLE_FLAGS,
|
|
@@ -982,7 +982,7 @@ var accountConnectSessionPollCommand = defineCommand({
|
|
|
982
982
|
profile: flags.profile
|
|
983
983
|
});
|
|
984
984
|
if (!cfg.apiKey) {
|
|
985
|
-
process.stderr.write("error: no API key
|
|
985
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
986
986
|
process.exit(3);
|
|
987
987
|
}
|
|
988
988
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -1004,7 +1004,7 @@ var accountUpdateCommand = defineCommand({
|
|
|
1004
1004
|
args: {
|
|
1005
1005
|
...WRITE_SINGLE_FLAGS,
|
|
1006
1006
|
"account-id": { type: "positional", description: "Account id (acc_\u2026)." },
|
|
1007
|
-
metadata: { type: "string", description: `Custom metadata as a JSON object (flat string\u2192string map)
|
|
1007
|
+
metadata: { type: "string", description: `Custom metadata as a JSON object (flat string\u2192string map). Replaces the store wholesale. Example: '{"team":"growth"}'.` },
|
|
1008
1008
|
"clear-proxy": { type: "boolean", description: "Clear the custom proxy (revert to automatic proxy protection). Mutually exclusive with --proxy-host.", default: false },
|
|
1009
1009
|
"proxy-protocol": { type: "string", description: "Proxy protocol: http | https | socks5." },
|
|
1010
1010
|
"proxy-host": { type: "string", description: "Proxy host or IP." },
|
|
@@ -1021,7 +1021,7 @@ var accountUpdateCommand = defineCommand({
|
|
|
1021
1021
|
profile: flags.profile
|
|
1022
1022
|
});
|
|
1023
1023
|
if (!cfg.apiKey) {
|
|
1024
|
-
process.stderr.write("error: no API key
|
|
1024
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
1025
1025
|
process.exit(3);
|
|
1026
1026
|
}
|
|
1027
1027
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -1044,7 +1044,7 @@ var accountDisconnectCommand = defineCommand({
|
|
|
1044
1044
|
profile: flags.profile
|
|
1045
1045
|
});
|
|
1046
1046
|
if (!cfg.apiKey) {
|
|
1047
|
-
process.stderr.write("error: no API key
|
|
1047
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
1048
1048
|
process.exit(3);
|
|
1049
1049
|
}
|
|
1050
1050
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -1075,7 +1075,7 @@ var accountCheckpointSolveCommand = defineCommand({
|
|
|
1075
1075
|
profile: flags.profile
|
|
1076
1076
|
});
|
|
1077
1077
|
if (!cfg.apiKey) {
|
|
1078
|
-
process.stderr.write("error: no API key
|
|
1078
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
1079
1079
|
process.exit(3);
|
|
1080
1080
|
}
|
|
1081
1081
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -1105,7 +1105,7 @@ var accountCheckpointPollCommand = defineCommand({
|
|
|
1105
1105
|
// --timeout`. Default: the time remaining to the checkpoint's own expiry.
|
|
1106
1106
|
timeout: {
|
|
1107
1107
|
type: "string",
|
|
1108
|
-
description: "Wait-loop timeout in milliseconds (requires --wait; default: time remaining to the checkpoint's expiry). Note the unit: this is milliseconds
|
|
1108
|
+
description: "Wait-loop timeout in milliseconds (requires --wait; default: time remaining to the checkpoint's expiry). Note the unit: this is milliseconds; `inbox sync-chat --timeout` is seconds."
|
|
1109
1109
|
}
|
|
1110
1110
|
},
|
|
1111
1111
|
async run({ args }) {
|
|
@@ -1116,7 +1116,7 @@ var accountCheckpointPollCommand = defineCommand({
|
|
|
1116
1116
|
profile: flags.profile
|
|
1117
1117
|
});
|
|
1118
1118
|
if (!cfg.apiKey) {
|
|
1119
|
-
process.stderr.write("error: no API key
|
|
1119
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
1120
1120
|
process.exit(3);
|
|
1121
1121
|
}
|
|
1122
1122
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -1127,7 +1127,7 @@ var accountCheckpointPollCommand = defineCommand({
|
|
|
1127
1127
|
var accountCheckpointRequestCommand = defineCommand({
|
|
1128
1128
|
meta: {
|
|
1129
1129
|
name: "request",
|
|
1130
|
-
description: "Re-request the challenge notification for a pending checkpoint (e.g. re-send an OTP email, SMS code, or mobile-app approval push). Not every challenge type supports it
|
|
1130
|
+
description: "Re-request the challenge notification for a pending checkpoint (e.g. re-send an OTP email, SMS code, or mobile-app approval push). Not every challenge type supports it; an authenticator- app code has nothing to re-send. The response's `resent` boolean tells you honestly whether a new notification actually went out; the command still exits 0 either way."
|
|
1131
1131
|
},
|
|
1132
1132
|
args: {
|
|
1133
1133
|
...WRITE_SINGLE_FLAGS,
|
|
@@ -1145,7 +1145,7 @@ var accountCheckpointRequestCommand = defineCommand({
|
|
|
1145
1145
|
profile: flags.profile
|
|
1146
1146
|
});
|
|
1147
1147
|
if (!cfg.apiKey) {
|
|
1148
|
-
process.stderr.write("error: no API key
|
|
1148
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
1149
1149
|
process.exit(3);
|
|
1150
1150
|
}
|
|
1151
1151
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -87,7 +87,7 @@ async function renameProfile(oldName, newName) {
|
|
|
87
87
|
}
|
|
88
88
|
if (cfg.profiles[newName]) {
|
|
89
89
|
throw new Error(
|
|
90
|
-
`Profile "${newName}" already exists
|
|
90
|
+
`Profile "${newName}" already exists. Remove it first or choose another name.`
|
|
91
91
|
);
|
|
92
92
|
}
|
|
93
93
|
cfg.profiles[newName] = cfg.profiles[oldName];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/bare-form-guard.ts
|
|
4
|
+
var COMMAND_WORD_RE = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
5
|
+
function looksLikeCommandWord(token) {
|
|
6
|
+
return COMMAND_WORD_RE.test(token);
|
|
7
|
+
}
|
|
8
|
+
function editDistance(a, b) {
|
|
9
|
+
const m = a.length;
|
|
10
|
+
const n = b.length;
|
|
11
|
+
if (m === 0) return n;
|
|
12
|
+
if (n === 0) return m;
|
|
13
|
+
const d = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
|
|
14
|
+
for (let i = 0; i <= m; i++) d[i][0] = i;
|
|
15
|
+
for (let j = 0; j <= n; j++) d[0][j] = j;
|
|
16
|
+
for (let i = 1; i <= m; i++) {
|
|
17
|
+
for (let j = 1; j <= n; j++) {
|
|
18
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
19
|
+
let best = Math.min(
|
|
20
|
+
d[i - 1][j] + 1,
|
|
21
|
+
// deletion
|
|
22
|
+
d[i][j - 1] + 1,
|
|
23
|
+
// insertion
|
|
24
|
+
d[i - 1][j - 1] + cost
|
|
25
|
+
// substitution
|
|
26
|
+
);
|
|
27
|
+
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
|
|
28
|
+
best = Math.min(best, d[i - 2][j - 2] + 1);
|
|
29
|
+
}
|
|
30
|
+
d[i][j] = best;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return d[m][n];
|
|
34
|
+
}
|
|
35
|
+
function nearestSubcommand(token, subcommandNames) {
|
|
36
|
+
let best = null;
|
|
37
|
+
for (const name of subcommandNames) {
|
|
38
|
+
const threshold = name.length < 6 ? 1 : 2;
|
|
39
|
+
const isPrefix = token.length >= 2 && token.length < name.length && name.startsWith(token);
|
|
40
|
+
const distance = isPrefix ? 1 : editDistance(token, name);
|
|
41
|
+
if (distance > threshold) continue;
|
|
42
|
+
if (best === null || distance < best.distance) best = { name, distance };
|
|
43
|
+
}
|
|
44
|
+
return best?.name ?? null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
looksLikeCommandWord,
|
|
49
|
+
nearestSubcommand
|
|
50
|
+
};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
looksLikeCommandWord,
|
|
4
|
+
nearestSubcommand
|
|
5
|
+
} from "./chunk-HOQ7EUHJ.js";
|
|
2
6
|
import {
|
|
3
7
|
resolveTextOrStdin
|
|
4
8
|
} from "./chunk-U7Y4EXHT.js";
|
|
@@ -24,11 +28,11 @@ import {
|
|
|
24
28
|
renderSuccess,
|
|
25
29
|
renderUnexpectedError,
|
|
26
30
|
resolveEffectiveConfig
|
|
27
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-HDQUEFD2.js";
|
|
28
32
|
import {
|
|
29
33
|
READ_SINGLE_FLAGS,
|
|
30
34
|
WRITE_FLAGS
|
|
31
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-DW2HCRXJ.js";
|
|
32
36
|
|
|
33
37
|
// src/commands/message.ts
|
|
34
38
|
import { defineCommand } from "citty";
|
|
@@ -267,7 +271,7 @@ async function runMessageReact(client, flags, out) {
|
|
|
267
271
|
const messageId = flags.messageId ?? "";
|
|
268
272
|
const reaction = flags.emoji ?? flags.emojiAlias ?? "";
|
|
269
273
|
if (!reaction) {
|
|
270
|
-
out.stderr.write("error: a reaction is required
|
|
274
|
+
out.stderr.write("error: a reaction is required. Pass it as `message react <chat_id> <message_id> <emoji>` (or --emoji <e>).\n");
|
|
271
275
|
process.exit(2);
|
|
272
276
|
return;
|
|
273
277
|
}
|
|
@@ -402,7 +406,7 @@ var messageNewCommand = defineCommand({
|
|
|
402
406
|
profile: flags.profile
|
|
403
407
|
});
|
|
404
408
|
if (!cfg.apiKey) {
|
|
405
|
-
process.stderr.write("error: no API key
|
|
409
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
406
410
|
process.exit(3);
|
|
407
411
|
}
|
|
408
412
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -428,7 +432,7 @@ var messageGetCommand = defineCommand({
|
|
|
428
432
|
profile: flags.profile
|
|
429
433
|
});
|
|
430
434
|
if (!cfg.apiKey) {
|
|
431
|
-
process.stderr.write("error: no API key
|
|
435
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
432
436
|
process.exit(3);
|
|
433
437
|
}
|
|
434
438
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -455,7 +459,7 @@ var messageEditCommand = defineCommand({
|
|
|
455
459
|
profile: flags.profile
|
|
456
460
|
});
|
|
457
461
|
if (!cfg.apiKey) {
|
|
458
|
-
process.stderr.write("error: no API key
|
|
462
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
459
463
|
process.exit(3);
|
|
460
464
|
}
|
|
461
465
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -481,7 +485,7 @@ var messageDeleteCommand = defineCommand({
|
|
|
481
485
|
profile: flags.profile
|
|
482
486
|
});
|
|
483
487
|
if (!cfg.apiKey) {
|
|
484
|
-
process.stderr.write("error: no API key
|
|
488
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
485
489
|
process.exit(3);
|
|
486
490
|
}
|
|
487
491
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -513,7 +517,7 @@ var messageReactCommand = defineCommand({
|
|
|
513
517
|
profile: flags.profile
|
|
514
518
|
});
|
|
515
519
|
if (!cfg.apiKey) {
|
|
516
|
-
process.stderr.write("error: no API key
|
|
520
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
517
521
|
process.exit(3);
|
|
518
522
|
}
|
|
519
523
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -541,7 +545,7 @@ var messageAttachmentCommand = defineCommand({
|
|
|
541
545
|
profile: flags.profile
|
|
542
546
|
});
|
|
543
547
|
if (!cfg.apiKey) {
|
|
544
|
-
process.stderr.write("error: no API key
|
|
548
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
545
549
|
process.exit(3);
|
|
546
550
|
}
|
|
547
551
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -577,7 +581,7 @@ var messageInMailCommand = defineCommand({
|
|
|
577
581
|
profile: flags.profile
|
|
578
582
|
});
|
|
579
583
|
if (!cfg.apiKey) {
|
|
580
|
-
process.stderr.write("error: no API key
|
|
584
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
581
585
|
process.exit(3);
|
|
582
586
|
}
|
|
583
587
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -610,7 +614,7 @@ var messageSendCommand = defineCommand({
|
|
|
610
614
|
profile: flags.profile
|
|
611
615
|
});
|
|
612
616
|
if (!cfg.apiKey) {
|
|
613
|
-
process.stderr.write("error: no API key
|
|
617
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
614
618
|
process.exit(3);
|
|
615
619
|
}
|
|
616
620
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -634,7 +638,7 @@ var messageInMailBalanceCommand = defineCommand({
|
|
|
634
638
|
profile: flags.profile
|
|
635
639
|
});
|
|
636
640
|
if (!cfg.apiKey) {
|
|
637
|
-
process.stderr.write("error: no API key
|
|
641
|
+
process.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
638
642
|
process.exit(3);
|
|
639
643
|
}
|
|
640
644
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
@@ -642,6 +646,38 @@ var messageInMailBalanceCommand = defineCommand({
|
|
|
642
646
|
await runMessageInMailBalance(client, { ...flags, account: flags.account ?? cfg.account }, out);
|
|
643
647
|
}
|
|
644
648
|
});
|
|
649
|
+
var MESSAGE_SUBCOMMANDS = [
|
|
650
|
+
"new",
|
|
651
|
+
"send",
|
|
652
|
+
"get",
|
|
653
|
+
"edit",
|
|
654
|
+
"delete",
|
|
655
|
+
"react",
|
|
656
|
+
"attachment",
|
|
657
|
+
"inmail",
|
|
658
|
+
"inmail-balance"
|
|
659
|
+
];
|
|
660
|
+
var MESSAGE_USAGE = 'Usage: curviate message new --to <attendee> "<text>" [--attach <file>\u2026]\n curviate message send <chat_id> "<text>" [--attach <file>\u2026]\n curviate message <chat_id> "<text>" [--attach <file>\u2026]\n curviate message get <chat_id> <message_id>\n curviate message edit <chat_id> <message_id> "<text>"\n curviate message delete <chat_id> <message_id>\n curviate message react <chat_id> <message_id> <emoji>\n curviate message attachment <chat_id> <message_id> <attachment_id> [-o <file>]\n curviate message inmail --to <id> --subject <s> "<text>"\n curviate message inmail-balance\n';
|
|
661
|
+
function guardBareMessageForm(chatId, out) {
|
|
662
|
+
if (!looksLikeCommandWord(chatId)) return;
|
|
663
|
+
const suggestion = nearestSubcommand(chatId, [...MESSAGE_SUBCOMMANDS]);
|
|
664
|
+
out.stderr.write(
|
|
665
|
+
`error: \`${chatId}\` is not a curviate message subcommand, and it is not a chat id (a chat id looks like 2-\u2026 or COMPANY_\u2026, or a linkedin.com/messaging/thread/\u2026 URL).
|
|
666
|
+
`
|
|
667
|
+
);
|
|
668
|
+
if (suggestion) {
|
|
669
|
+
out.stderr.write(`hint: did you mean \`curviate message ${suggestion}\`?
|
|
670
|
+
`);
|
|
671
|
+
} else if (chatId === "search") {
|
|
672
|
+
out.stderr.write("hint: to search your messages, use `curviate inbox search`.\n");
|
|
673
|
+
}
|
|
674
|
+
out.stderr.write(
|
|
675
|
+
`hint: to send to a chat id this check does not recognise, name the action explicitly: curviate message send <chat_id> "<text>".
|
|
676
|
+
`
|
|
677
|
+
);
|
|
678
|
+
out.stderr.write(MESSAGE_USAGE);
|
|
679
|
+
process.exit(2);
|
|
680
|
+
}
|
|
645
681
|
var messageCommand = defineCommand({
|
|
646
682
|
meta: {
|
|
647
683
|
name: "message",
|
|
@@ -671,12 +707,12 @@ var messageCommand = defineCommand({
|
|
|
671
707
|
},
|
|
672
708
|
async run({ args }) {
|
|
673
709
|
const flags = args;
|
|
710
|
+
const out = buildOutputStreams();
|
|
674
711
|
if (!flags.chatId) {
|
|
675
|
-
|
|
676
|
-
'Usage: curviate message new --to <attendee> "<text>" [--attach <file>\u2026]\n curviate message <chat_id> "<text>" [--attach <file>\u2026]\n curviate message get <chat_id> <message_id>\n curviate message edit <chat_id> <message_id> "<text>"\n curviate message delete <chat_id> <message_id>\n curviate message react <chat_id> <message_id> <emoji>\n curviate message attachment <chat_id> <message_id> <attachment_id> [-o <file>]\n curviate message inmail --to <id> --subject <s> "<text>"\n curviate message inmail-balance\n'
|
|
677
|
-
);
|
|
712
|
+
out.stderr.write(MESSAGE_USAGE);
|
|
678
713
|
process.exit(2);
|
|
679
714
|
}
|
|
715
|
+
guardBareMessageForm(normalizeChatId(flags.chatId), out);
|
|
680
716
|
const cfg = await resolveEffectiveConfig({
|
|
681
717
|
apiKey: flags["api-key"],
|
|
682
718
|
baseUrl: flags["base-url"],
|
|
@@ -685,11 +721,10 @@ var messageCommand = defineCommand({
|
|
|
685
721
|
profile: flags.profile
|
|
686
722
|
});
|
|
687
723
|
if (!cfg.apiKey) {
|
|
688
|
-
|
|
724
|
+
out.stderr.write("error: no API key, run `curviate login` or pass --api-key.\n");
|
|
689
725
|
process.exit(3);
|
|
690
726
|
}
|
|
691
727
|
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
692
|
-
const out = buildOutputStreams();
|
|
693
728
|
await runMessageSend(client, { ...flags, account: flags.account ?? cfg.account }, out);
|
|
694
729
|
}
|
|
695
730
|
});
|
|
@@ -706,5 +741,6 @@ export {
|
|
|
706
741
|
runMessageAttachment,
|
|
707
742
|
runMessageInMail,
|
|
708
743
|
runMessageInMailBalance,
|
|
744
|
+
guardBareMessageForm,
|
|
709
745
|
messageCommand
|
|
710
746
|
};
|