@wirecat/cli-core 0.346.0 → 0.347.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 +21 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/meetings/cli/query-options.js +5 -1
- package/dist/sends/permissions.js +2 -0
- package/dist/terminal/login-qr.d.ts +27 -0
- package/dist/terminal/login-qr.js +44 -0
- package/package.json +1 -1
- package/parity.json +14 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,27 @@ shape of this file.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## 0.347.0 — 18.10.2026
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`loginQr` shows a login QR code the same way in every messenger CLI**: drawn on the diagnostic stream, which
|
|
15
|
+
`--quiet` does not hide, or written to the `--qr-file` PNG with `writeSecurely` (a temporary file created with
|
|
16
|
+
mode `0600`, renamed over the path, never chmodded afterwards). On a terminal too narrow for the code it draws
|
|
17
|
+
nothing and says to widen the terminal or pass `--qr-file`; it opens nothing. `close()` removes the image it
|
|
18
|
+
wrote, never a file it did not. `qrNeedsTerminal(command)` is the shared refusal when nobody could scan, and
|
|
19
|
+
`atTerminal(input)` the shared test. `parity.json` plans `--qr-file` on `session start` and `setup` for max, beside tg and wa.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **A list that takes a query prints its help for `--help`.** Since 0.343.0, `chats list --help`, `tasks list --help`,
|
|
24
|
+
`contacts list --help` and every other list with `[query...]` refused `--help` as a mistyped option (exit 2), because
|
|
25
|
+
commander looks for it only after the query check had run. A mistyped `--limt` is still refused.
|
|
26
|
+
- **`help` and `guide` need no permission key**: `keyForCommand` returned nothing for them, so a tool that maps every
|
|
27
|
+
command to a key (max) crashed on `help options`. They are housekeeping now, like `commands` and `skill`.
|
|
28
|
+
- **`parity.json` has a `guide` row**, planned for max, tg and wa, so `cli-core-parity` stops failing a tool that
|
|
29
|
+
mounts it with "guide: not in the manifest".
|
|
30
|
+
|
|
10
31
|
## 0.346.0 — 18.10.2026
|
|
11
32
|
|
|
12
33
|
### Added
|
package/dist/index.d.ts
CHANGED
|
@@ -22,5 +22,6 @@ export { defaultRules, ModerationRules, moderationPathFor } from "./moderation/r
|
|
|
22
22
|
export { type OutputOptions, resolveOutput } from "./output.js";
|
|
23
23
|
export { pollLines, type RenderOptions, renderMessage, renderMessages } from "./render/messages.js";
|
|
24
24
|
export { isId, type PeopleLookup, pickChat, pickPerson } from "./resolve.js";
|
|
25
|
+
export { atTerminal, type LoginQr, type LoginQrOptions, loginQr, qrNeedsTerminal, } from "./terminal/login-qr.js";
|
|
25
26
|
export { readSecret, type SecretInput } from "./terminal/prompt.js";
|
|
26
27
|
export { qrPng, terminalQr } from "./terminal/qr.js";
|
package/dist/index.js
CHANGED
|
@@ -15,5 +15,6 @@ export { defaultRules, ModerationRules, moderationPathFor } from "./moderation/r
|
|
|
15
15
|
export { resolveOutput } from "./output.js";
|
|
16
16
|
export { pollLines, renderMessage, renderMessages } from "./render/messages.js";
|
|
17
17
|
export { isId, pickChat, pickPerson } from "./resolve.js";
|
|
18
|
+
export { atTerminal, loginQr, qrNeedsTerminal, } from "./terminal/login-qr.js";
|
|
18
19
|
export { readSecret } from "./terminal/prompt.js";
|
|
19
20
|
export { qrPng, terminalQr } from "./terminal/qr.js";
|
|
@@ -8,7 +8,11 @@ export const queryWordsAfterOptions = (command) => {
|
|
|
8
8
|
command.parseOptions = (args) => {
|
|
9
9
|
const parsed = parse(args);
|
|
10
10
|
const end = parsed.unknown.indexOf("--");
|
|
11
|
-
|
|
11
|
+
// Commander looks for --help in what parseOptions leaves unknown, after it returns.
|
|
12
|
+
const help = command._getHelpOption();
|
|
13
|
+
const typo = parsed.unknown
|
|
14
|
+
.slice(0, end < 0 ? undefined : end)
|
|
15
|
+
.find((word) => word.startsWith("--") && !help?.is(word));
|
|
12
16
|
if (typo !== undefined) {
|
|
13
17
|
command.allowUnknownOption(false);
|
|
14
18
|
command.unknownOption(typo);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { CliError } from "@wirecat/cli-base";
|
|
2
|
+
/** Whether a person can scan a code drawn here and answer what the login asks next. */
|
|
3
|
+
export declare const atTerminal: (input: NodeJS.ReadableStream & {
|
|
4
|
+
isTTY?: boolean;
|
|
5
|
+
}) => boolean;
|
|
6
|
+
/** The one refusal of a QR login that nobody could scan. */
|
|
7
|
+
export declare const qrNeedsTerminal: (command: string) => CliError;
|
|
8
|
+
export interface LoginQrOptions {
|
|
9
|
+
/** `--qr-file`: the PNG to write instead of drawing the code. */
|
|
10
|
+
qrFile?: string;
|
|
11
|
+
/** Where the code and the narrow-terminal hint go; `--quiet` must not hide either. */
|
|
12
|
+
diagnostic: (text: string) => void;
|
|
13
|
+
/** Where the file's location is said. */
|
|
14
|
+
note: (text: string) => void;
|
|
15
|
+
/** How far the code sits right, to line up under a setup step. */
|
|
16
|
+
indent?: number;
|
|
17
|
+
/** Read on every code, so a widened terminal draws the next one. Unknown draws the code. */
|
|
18
|
+
columns?: () => number | undefined;
|
|
19
|
+
}
|
|
20
|
+
export interface LoginQr {
|
|
21
|
+
readonly path: string | undefined;
|
|
22
|
+
/** Never throws for a code that does not fit: the messengers call it from inside their own event loops. */
|
|
23
|
+
show: (link: string) => void;
|
|
24
|
+
/** The image logs the account in while it is valid; call this in `finally`. */
|
|
25
|
+
close: () => void;
|
|
26
|
+
}
|
|
27
|
+
export declare const loginQr: ({ qrFile, diagnostic, note, indent: pad, columns, }: LoginQrOptions) => LoginQr;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { rmSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { CliError, indent, writeSecurely } from "@wirecat/cli-base";
|
|
4
|
+
import { inputPolicy } from "../cli/input-policy.js";
|
|
5
|
+
import { qrPng, terminalQr } from "./qr.js";
|
|
6
|
+
const MARGIN = 2;
|
|
7
|
+
/** Whether a person can scan a code drawn here and answer what the login asks next. */
|
|
8
|
+
export const atTerminal = (input) => input.isTTY === true && !inputPolicy(input).noInput;
|
|
9
|
+
/** The one refusal of a QR login that nobody could scan. */
|
|
10
|
+
export const qrNeedsTerminal = (command) => new CliError("validation_error", `${command} shows a QR code to scan — run it in a terminal, or pass --qr-file <png>`, {
|
|
11
|
+
param: "--qr-file",
|
|
12
|
+
reason: "input.required",
|
|
13
|
+
});
|
|
14
|
+
export const loginQr = ({ qrFile, diagnostic, note, indent: pad = 0, columns = () => process.stderr.columns, }) => {
|
|
15
|
+
const path = qrFile === undefined ? undefined : resolve(qrFile);
|
|
16
|
+
// Only what this login wrote is removed: a refused or never-reached write leaves the owner's file alone.
|
|
17
|
+
let written = false;
|
|
18
|
+
return {
|
|
19
|
+
path,
|
|
20
|
+
show: (link) => {
|
|
21
|
+
if (path) {
|
|
22
|
+
writeSecurely(path, qrPng(link), 0o600);
|
|
23
|
+
written = true;
|
|
24
|
+
note(`the QR code is in ${path} — it is replaced when the code renews`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const drawn = terminalQr(link);
|
|
28
|
+
const need = drawn.width + pad + MARGIN;
|
|
29
|
+
const width = columns();
|
|
30
|
+
if (width !== undefined && need > width) {
|
|
31
|
+
diagnostic(`the terminal is ${width} columns wide and the QR code needs ${need} — widen it, ` +
|
|
32
|
+
"or run again with --qr-file <png>");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
diagnostic(`\n${indent(drawn.text, pad + MARGIN)}`);
|
|
36
|
+
},
|
|
37
|
+
close: () => {
|
|
38
|
+
if (!path || !written)
|
|
39
|
+
return;
|
|
40
|
+
written = false;
|
|
41
|
+
rmSync(path, { force: true });
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wirecat/cli-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.347.0",
|
|
4
4
|
"description": "The messenger-neutral half of a messaging CLI: domain model, message locators, rendering, name resolution, the SQLite seam, the command skeleton and shared read commands, the send guard, run records and the message store",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Viacheslav Ptsarev",
|
package/parity.json
CHANGED
|
@@ -2847,6 +2847,14 @@
|
|
|
2847
2847
|
"wa": "wa backlog: mount the shared flood command"
|
|
2848
2848
|
}
|
|
2849
2849
|
},
|
|
2850
|
+
"guide": {
|
|
2851
|
+
"in": [],
|
|
2852
|
+
"planned": {
|
|
2853
|
+
"max": "help-navigation pass: max-cli#737 mounts guide with scenarios",
|
|
2854
|
+
"tg": "help-navigation pass: mount guide with scenarios",
|
|
2855
|
+
"wa": "help-navigation pass: mount guide with scenarios"
|
|
2856
|
+
}
|
|
2857
|
+
},
|
|
2850
2858
|
"images": {
|
|
2851
2859
|
"in": "all"
|
|
2852
2860
|
},
|
|
@@ -4047,7 +4055,9 @@
|
|
|
4047
4055
|
},
|
|
4048
4056
|
"--qr-file": {
|
|
4049
4057
|
"in": ["tg", "wa"],
|
|
4050
|
-
"
|
|
4058
|
+
"planned": {
|
|
4059
|
+
"max": "max-cli#736, on the cli-core release that exports loginQr"
|
|
4060
|
+
}
|
|
4051
4061
|
},
|
|
4052
4062
|
"--sms": {
|
|
4053
4063
|
"in": ["tg"],
|
|
@@ -4066,7 +4076,9 @@
|
|
|
4066
4076
|
"--method": "all",
|
|
4067
4077
|
"--qr-file": {
|
|
4068
4078
|
"in": ["tg", "wa"],
|
|
4069
|
-
"
|
|
4079
|
+
"planned": {
|
|
4080
|
+
"max": "max-cli#736, on the cli-core release that exports loginQr"
|
|
4081
|
+
}
|
|
4070
4082
|
}
|
|
4071
4083
|
}
|
|
4072
4084
|
},
|