@mu-cabin/muc-cli 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/muc.mjs +84 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -222,6 +222,19 @@ before using any chat-channel command if you have a real device logged in.**
|
|
|
222
222
|
Sending to anyone other than yourself requires the explicit `--yes-not-self`
|
|
223
223
|
flag — a guard against accidentally messaging real humans during testing.
|
|
224
224
|
|
|
225
|
+
**Message tail (signature)**: by default `muc send` appends a short tail to
|
|
226
|
+
the text it sends (e.g. `"\n—— 来自王璐璐的muc-cli"`) so recipients can
|
|
227
|
+
tell automated traffic from a typed message. The check is idempotent —
|
|
228
|
+
if your text already ends with the resolved tail, it is not appended a
|
|
229
|
+
second time. Customise it with the
|
|
230
|
+
`messageTail` field in `~/.muc/config.json` — set to a non-empty string to
|
|
231
|
+
override, or to `""` to disable entirely. You can also use
|
|
232
|
+
`muc init --message-tail "<custom>"` / `muc init --no-message-tail` to
|
|
233
|
+
write the value, and per-call flags `muc send --tail "<one-off>"` /
|
|
234
|
+
`muc send --no-tail` to override on a single send. Only `muc send`
|
|
235
|
+
(plain-text) is affected; `send-file` / `send-image` / `send-voice` are
|
|
236
|
+
not.
|
|
237
|
+
|
|
225
238
|
```bash
|
|
226
239
|
muc tcp-ping --wait 8 # safe protocol smoke test
|
|
227
240
|
muc send "hello from the CLI" # to-self (default)
|
package/dist/muc.mjs
CHANGED
|
@@ -21301,6 +21301,12 @@ var MucConfigSchema = external_exports.object({
|
|
|
21301
21301
|
imPort: external_exports.number().int().min(1).max(65535),
|
|
21302
21302
|
fileHost: external_exports.string().min(1, "fileHost required"),
|
|
21303
21303
|
filePort: external_exports.number().int().min(1).max(65535),
|
|
21304
|
+
// Optional signature appended to outbound `muc send` text. Tri-state:
|
|
21305
|
+
// undefined → use built-in default (defaultMessageTail in constants.ts)
|
|
21306
|
+
// "" → explicit opt-out (no tail appended)
|
|
21307
|
+
// any other → that literal string (e.g. "\n— bot")
|
|
21308
|
+
// Per-call `--tail` / `--no-tail` flags on `muc send` override this.
|
|
21309
|
+
messageTail: external_exports.string().max(200).optional(),
|
|
21304
21310
|
savedAt: external_exports.number().int().nonnegative(),
|
|
21305
21311
|
schemaVersion: external_exports.literal(CONFIG_SCHEMA_VERSION)
|
|
21306
21312
|
});
|
|
@@ -21700,6 +21706,11 @@ var SECURE_SYS_KEY = "mx_app_key";
|
|
|
21700
21706
|
var PWD_DES_IV = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
|
|
21701
21707
|
var DEFAULT_CHAT_OS = "iOS";
|
|
21702
21708
|
var DEFAULT_REST_PLATFORM = PLATFORM_IOS;
|
|
21709
|
+
function defaultMessageTail(userName) {
|
|
21710
|
+
const name = userName.trim() || "unknown";
|
|
21711
|
+
return `
|
|
21712
|
+
\u2014\u2014 \u6765\u81EA${name}\u7684muc-cli`;
|
|
21713
|
+
}
|
|
21703
21714
|
var DEFAULTS = {
|
|
21704
21715
|
// Hosts/ports for the 东航 deployment. Other tenants override at init.
|
|
21705
21716
|
restHost: "https://muc.ceair.com/",
|
|
@@ -22048,6 +22059,46 @@ function register(program3) {
|
|
|
22048
22059
|
|
|
22049
22060
|
// src/commands/init.ts
|
|
22050
22061
|
import * as readline2 from "node:readline";
|
|
22062
|
+
|
|
22063
|
+
// src/lib/tail.ts
|
|
22064
|
+
function resolveTail(configured, userName, override) {
|
|
22065
|
+
if (override.disable) return "";
|
|
22066
|
+
if (override.custom != null) return override.custom;
|
|
22067
|
+
if (configured === "") return "";
|
|
22068
|
+
if (configured != null) return configured;
|
|
22069
|
+
return defaultMessageTail(userName);
|
|
22070
|
+
}
|
|
22071
|
+
function applyTail(body, tail) {
|
|
22072
|
+
if (!tail) return body;
|
|
22073
|
+
if (body.endsWith(tail)) return body;
|
|
22074
|
+
return body + tail;
|
|
22075
|
+
}
|
|
22076
|
+
function detectFlagConflict(argv2, name) {
|
|
22077
|
+
const valueLong = `--${name}`;
|
|
22078
|
+
const negatedLong = `--no-${name}`;
|
|
22079
|
+
const valueEq = `${valueLong}=`;
|
|
22080
|
+
let sawValueForm = false;
|
|
22081
|
+
let sawNegatedForm = false;
|
|
22082
|
+
for (let i = 0; i < argv2.length; i++) {
|
|
22083
|
+
const a = argv2[i];
|
|
22084
|
+
if (a === "--") break;
|
|
22085
|
+
if (a === valueLong) {
|
|
22086
|
+
sawValueForm = true;
|
|
22087
|
+
i++;
|
|
22088
|
+
continue;
|
|
22089
|
+
}
|
|
22090
|
+
if (a.startsWith(valueEq)) {
|
|
22091
|
+
sawValueForm = true;
|
|
22092
|
+
continue;
|
|
22093
|
+
}
|
|
22094
|
+
if (a === negatedLong) {
|
|
22095
|
+
sawNegatedForm = true;
|
|
22096
|
+
}
|
|
22097
|
+
}
|
|
22098
|
+
return { sawValueForm, sawNegatedForm };
|
|
22099
|
+
}
|
|
22100
|
+
|
|
22101
|
+
// src/commands/init.ts
|
|
22051
22102
|
var FingerprintShape = external_exports.object({
|
|
22052
22103
|
appKey: external_exports.string(),
|
|
22053
22104
|
appId: external_exports.string(),
|
|
@@ -22060,6 +22111,8 @@ var FingerprintShape = external_exports.object({
|
|
|
22060
22111
|
imPort: external_exports.number(),
|
|
22061
22112
|
fileHost: external_exports.string(),
|
|
22062
22113
|
filePort: external_exports.number(),
|
|
22114
|
+
messageTail: external_exports.string(),
|
|
22115
|
+
// summary: "default" / "none" / "custom (N chars)"
|
|
22063
22116
|
savedAt: external_exports.number(),
|
|
22064
22117
|
schemaVersion: external_exports.literal(CONFIG_SCHEMA_VERSION)
|
|
22065
22118
|
});
|
|
@@ -22080,6 +22133,11 @@ function fingerprint2(v) {
|
|
|
22080
22133
|
if (v.length <= 8) return "***";
|
|
22081
22134
|
return `${v.slice(0, 4)}\u2026${v.slice(-4)}`;
|
|
22082
22135
|
}
|
|
22136
|
+
function summarizeTail(t) {
|
|
22137
|
+
if (t === void 0) return "default";
|
|
22138
|
+
if (t === "") return "none";
|
|
22139
|
+
return `custom (${t.length} chars)`;
|
|
22140
|
+
}
|
|
22083
22141
|
function redactConfig(c) {
|
|
22084
22142
|
return {
|
|
22085
22143
|
appKey: fingerprint2(c.appKey),
|
|
@@ -22093,6 +22151,7 @@ function redactConfig(c) {
|
|
|
22093
22151
|
imPort: c.imPort,
|
|
22094
22152
|
fileHost: c.fileHost,
|
|
22095
22153
|
filePort: c.filePort,
|
|
22154
|
+
messageTail: summarizeTail(c.messageTail),
|
|
22096
22155
|
savedAt: c.savedAt,
|
|
22097
22156
|
schemaVersion: c.schemaVersion
|
|
22098
22157
|
};
|
|
@@ -22238,7 +22297,7 @@ function register2(program3) {
|
|
|
22238
22297
|
description: "Bootstrap or update ~/.muc/config.json (tenant config: APP_KEY, APP_ID, signing secrets, hosts/ports). Interactive prompts by default; non-interactive via flags or MUC_* env vars. WARNING: env vars are visible to other processes via /proc/<pid>/environ and shell history \u2014 prefer interactive or flag-based for production.",
|
|
22239
22298
|
output: Output2,
|
|
22240
22299
|
configure: (cmd) => {
|
|
22241
|
-
cmd.option("--check", "verify config presence and validity (exit 0 ok / 6 missing / 7 invalid); does not modify").option("--show", "print the saved config (secrets are always redacted in both human and JSON output; cat ~/.muc/config.json for raw values)").option("--reset", "delete ~/.muc/config.json (requires --yes)").option("--yes", "confirm a destructive action like --reset").option("--no-interactive", "fail rather than prompt for missing fields").option("--app-key <hex>", "tenant APP_KEY (8 lowercase hex)").option("--app-id <hex>", "tenant APP_ID (24 lowercase hex)").option("--sign-secret-rest <s>", "REST signing secret").option("--sign-secret-secure <s>", "secure-API signing secret").option("--pwd-des-key <s>", "password DES key (defaults to APP_KEY)").option("--rest-host <url>", "REST host URL").option("--sso-host <url>", "SSO host URL (optional)").option("--im-host <h>", "IM TCP host").option("--im-port <n>", "IM TCP port").option("--file-host <h>", "file-channel TCP host").option("--file-port <n>", "file-channel TCP port");
|
|
22300
|
+
cmd.option("--check", "verify config presence and validity (exit 0 ok / 6 missing / 7 invalid); does not modify").option("--show", "print the saved config (secrets are always redacted in both human and JSON output; cat ~/.muc/config.json for raw values)").option("--reset", "delete ~/.muc/config.json (requires --yes)").option("--yes", "confirm a destructive action like --reset").option("--no-interactive", "fail rather than prompt for missing fields").option("--app-key <hex>", "tenant APP_KEY (8 lowercase hex)").option("--app-id <hex>", "tenant APP_ID (24 lowercase hex)").option("--sign-secret-rest <s>", "REST signing secret").option("--sign-secret-secure <s>", "secure-API signing secret").option("--pwd-des-key <s>", "password DES key (defaults to APP_KEY)").option("--rest-host <url>", "REST host URL").option("--sso-host <url>", "SSO host URL (optional)").option("--im-host <h>", "IM TCP host").option("--im-port <n>", "IM TCP port").option("--file-host <h>", "file-channel TCP host").option("--file-port <n>", "file-channel TCP port").option("--message-tail <text>", "custom signature appended to outbound `muc send` text (max 200 chars)").option("--no-message-tail", "explicitly disable the message tail (no signature appended)");
|
|
22242
22301
|
},
|
|
22243
22302
|
run: async (cmd) => {
|
|
22244
22303
|
const opts = cmd.opts();
|
|
@@ -22336,6 +22395,18 @@ function register2(program3) {
|
|
|
22336
22395
|
partial[f.key] = parsed;
|
|
22337
22396
|
}
|
|
22338
22397
|
}
|
|
22398
|
+
const mtConflict = detectFlagConflict(process.argv.slice(2), "message-tail");
|
|
22399
|
+
if (mtConflict.sawValueForm && mtConflict.sawNegatedForm) {
|
|
22400
|
+
throw new CliError("USAGE", "--message-tail and --no-message-tail are mutually exclusive");
|
|
22401
|
+
}
|
|
22402
|
+
let messageTail;
|
|
22403
|
+
if (opts.messageTail === false) {
|
|
22404
|
+
messageTail = "";
|
|
22405
|
+
} else if (typeof opts.messageTail === "string") {
|
|
22406
|
+
messageTail = opts.messageTail;
|
|
22407
|
+
} else if (existing && "messageTail" in existing) {
|
|
22408
|
+
messageTail = existing.messageTail;
|
|
22409
|
+
}
|
|
22339
22410
|
const draft = {
|
|
22340
22411
|
appKey: String(partial.appKey ?? ""),
|
|
22341
22412
|
appId: String(partial.appId ?? ""),
|
|
@@ -22348,6 +22419,7 @@ function register2(program3) {
|
|
|
22348
22419
|
imPort: Number(partial.imPort ?? 0),
|
|
22349
22420
|
fileHost: String(partial.fileHost ?? ""),
|
|
22350
22421
|
filePort: Number(partial.filePort ?? 0),
|
|
22422
|
+
messageTail,
|
|
22351
22423
|
savedAt: Date.now(),
|
|
22352
22424
|
schemaVersion: CONFIG_SCHEMA_VERSION
|
|
22353
22425
|
};
|
|
@@ -23519,7 +23591,7 @@ function register15(program3) {
|
|
|
23519
23591
|
description: "Send a plain-text chat message via the TCP chat channel. VISIBLE TO THE RECIPIENT \u2014 non-self targets require --yes-not-self.",
|
|
23520
23592
|
output: Output15,
|
|
23521
23593
|
configure: (cmd) => {
|
|
23522
|
-
cmd.argument("<text...>", "message text (variadic; words rejoined with spaces)").option("--peer <uid>", "1:1 chat with a peer uid").option("--team <id>", "group chat with a team id").option("--to-self", "send to your own uid (default if no target given)").option("--yes-not-self", "required to confirm sending to anyone other than yourself").option("--dry-run", "build the frame but do not connect").option("--os <os>", "chat-channel os slot", parseChatOs, DEFAULT_CHAT_OS).option("--debug", "forward wire-level debug events to stderr");
|
|
23594
|
+
cmd.argument("<text...>", "message text (variadic; words rejoined with spaces)").option("--peer <uid>", "1:1 chat with a peer uid").option("--team <id>", "group chat with a team id").option("--to-self", "send to your own uid (default if no target given)").option("--yes-not-self", "required to confirm sending to anyone other than yourself").option("--dry-run", "build the frame but do not connect").option("--os <os>", "chat-channel os slot", parseChatOs, DEFAULT_CHAT_OS).option("--tail <text>", "override message tail for this call only").option("--no-tail", "do not append a message tail for this call").option("--debug", "forward wire-level debug events to stderr");
|
|
23523
23595
|
},
|
|
23524
23596
|
run: async (cmd) => {
|
|
23525
23597
|
const text = cmd.args.join(" ").trim();
|
|
@@ -23528,6 +23600,15 @@ function register15(program3) {
|
|
|
23528
23600
|
const cfg = requireConfig();
|
|
23529
23601
|
const cred = requireAuth(loadCredentials());
|
|
23530
23602
|
requireSingleTarget(opts, "send");
|
|
23603
|
+
const conflict = detectFlagConflict(process.argv.slice(2), "tail");
|
|
23604
|
+
if (conflict.sawValueForm && conflict.sawNegatedForm) {
|
|
23605
|
+
throw new CliError("USAGE", "--tail and --no-tail are mutually exclusive");
|
|
23606
|
+
}
|
|
23607
|
+
const override = {};
|
|
23608
|
+
if (opts.tail === false) override.disable = true;
|
|
23609
|
+
else if (typeof opts.tail === "string") override.custom = opts.tail;
|
|
23610
|
+
const tail = resolveTail(cfg.messageTail, cred.name ?? "", override);
|
|
23611
|
+
const finalText = applyTail(text, tail);
|
|
23531
23612
|
let scene;
|
|
23532
23613
|
let toId;
|
|
23533
23614
|
if (opts.team) {
|
|
@@ -23554,7 +23635,7 @@ function register15(program3) {
|
|
|
23554
23635
|
scene,
|
|
23555
23636
|
type: 1,
|
|
23556
23637
|
subType: 1,
|
|
23557
|
-
body:
|
|
23638
|
+
body: finalText,
|
|
23558
23639
|
fName: cred.name,
|
|
23559
23640
|
platform: opts.os === "Mac" || opts.os === "OS X" ? "Mac" : "Windows",
|
|
23560
23641
|
appKey: cfg.appKey
|