Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ tools/.sfmc-registry-cache.json
*.tmp
*.tmp.*
*.log
*.tgz

# Proactive-agent credentials (security-audit.sh)
.credentials/
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file removed sfmc-bds-sfmc-0.1.0.tgz
Binary file not shown.
19 changes: 10 additions & 9 deletions sfmc/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import process from "node:process";
import pkg from "../package.json" with { type: "json" };
import { cmdLogs, cmdRestart, cmdStart, cmdStartAll, cmdStatus, cmdStop, cmdStopAll, cmdUpdate } from "./commands.js";
import { HELP, startRepl } from "./repl.js";
import { dispatchModuleCommand, scanAndWarnUnknown } from "./module-commands.js";
import { dispatchModuleCommand, isModuleCommand, scanAndWarnUnknown } from "./module-commands.js";
import { cmdBehaviorPackBuild, cmdBehaviorPackDeploy } from "./commands-behavior-pack.js";
import { disableRemoteAgent, enrollRemoteAgent, remoteStatus, startRemoteAgent, stopRemoteAgent } from "./remote-agent.js";
import { c } from "./theme.js";

function printVersion(): void {
`${c.text(`⠪⡁⡯⠁`)}
/* 此前模板字符串未写入 stdout,导致 `sfmc --version` 无输出。 */
console.log(`${c.text(`⠪⡁⡯⠁`)}
${c.text(`⠒⠁⠃`)}${c.purple(`⠄`)}
${c.text(`⡷⡇⡎⠁`)} ${c.text(`S`)}${c.dim(`cripts`)} ${c.text(`F`)}${c.dim(`or`)} ${c.text(`M`)}${c.dim(`ine`)}${c.text(`c`)}${c.dim(`raft Server`)} v${pkg.version}
${c.text(`⠃⠃⠑⠂`)} ${c.dim(`https://github.com/DogeLakeDev/ScriptsForMinecraftServer`)}\n`;
${c.text(`⠃⠃⠑⠂`)} ${c.dim(`https://github.com/DogeLakeDev/ScriptsForMinecraftServer`)}`);
}

function printUsage(): void {
Expand Down Expand Up @@ -138,13 +139,13 @@ async function main(): Promise<void> {
}
break;
}
case "module":
case "mod": {
const [sub, ...subRest] = rest;
console.log(await dispatchModuleCommand(sub, subRest));
break;
}
default:
/* module/mod 别名只维护 MODULE_CMD_NAMES,避免 main/repl case 链漂移(OCP)。 */
if (isModuleCommand(cmd)) {
const [sub, ...subRest] = rest;
console.log(await dispatchModuleCommand(sub, subRest));
break;
}
console.log(c.red(`Unknown command: ${cmd}`));
printUsage();
process.exit(1);
Expand Down
10 changes: 9 additions & 1 deletion sfmc/src/module-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@
/** 顶层命令名(主名 + 短别名),供 HELP / 补全 / 分发共用。 */
export const MODULE_CMD_NAMES = ["module", "mod"] as const;

/** HELP 行首标签,如 `module/mod`(与 MODULE_CMD_NAMES 同源,避免两处漂移)。 */
export const MODULE_CMD_LABEL = MODULE_CMD_NAMES.join("/");

/** 是否为 module 顶层命令(含短别名)。新增别名只改 MODULE_CMD_NAMES。 */
export function isModuleCommand(name: string | undefined): boolean {
return !!name && (MODULE_CMD_NAMES as readonly string[]).includes(name);
}

/** 对外展示与 Tab 补全用的子命令列表(不含 remove 等同义别名)。 */
export const MODULE_SUBCOMMANDS = [
"list",
Expand All @@ -41,7 +49,7 @@ export const MODULE_SUBCOMMANDS = [
] as const;

export const MODULE_USAGE =
"Usage: sfmc module|mod <list|search|install|uninstall|verify|info|enable|disable> [args]";
`Usage: sfmc ${MODULE_CMD_NAMES.join("|")} <${MODULE_SUBCOMMANDS.join("|")}> [args]`;

import fs from "node:fs/promises";
import { existsSync, readdirSync } from "node:fs";
Expand Down
43 changes: 25 additions & 18 deletions sfmc/src/repl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import process, { stdin, stdout } from "node:process";
import pkg from "../package.json" with { type: "json" };
import { cmdLogs, cmdRestart, cmdSend, cmdStart, cmdStartAll, cmdStatus, cmdStop, cmdStopAll, cmdUpdate } from "./commands.js";
import { formatLog, getAllLogs, onLog, wrapLogLine, type LogLevel, type LogSource, type UnifiedLog } from "./logs.js";
import { dispatchModuleCommand, listInstalledModuleIdsSync, MODULE_CMD_NAMES, MODULE_SUBCOMMANDS } from "./module-commands.js";
import {
dispatchModuleCommand,
isModuleCommand,
listInstalledModuleIdsSync,
MODULE_CMD_NAMES,
MODULE_SUBCOMMANDS,
} from "./module-commands.js";
import { listRegistryModuleIdsSync } from "./registry.js";
import { disableRemoteAgent, enrollRemoteAgent, remoteStatus, startRemoteAgent } from "./remote-agent.js";
import { forceStopAll, SERVICE_NAMES, stopAll } from "./services.js";
Expand All @@ -14,6 +20,9 @@ function setRaw(v: boolean): void {
} catch {}
}

/** HELP 行首:把 MODULE_CMD_NAMES 着色后用 / 拼接(如 module/mod)。 */
const MODULE_HELP_LABEL = MODULE_CMD_NAMES.map((n) => c.green(n)).join("/");

const welcome = `\n
${c.text(`⠪⡁⡯⠁`)}
${c.text(`⠒⠁⠃`)}${c.purple(`⠄`)}
Expand Down Expand Up @@ -43,19 +52,19 @@ ${c.bold("Commands")}
${c.green("remote enroll")} <url> <token> [name]
Enroll this supervisor with a controller
${c.green("remote disable")} Disable + disconnect remote agent
${c.green("module")}/${c.green("mod")} list
${MODULE_HELP_LABEL} list
List installed modules
${c.green("module")}/${c.green("mod")} search [id]
${MODULE_HELP_LABEL} search [id]
Fetch registry list / show one module's registry info
${c.green("module")}/${c.green("mod")} install <id> [--from <source>]
${MODULE_HELP_LABEL} install <id> [--from <source>]
Fetch + install a module
${c.green("module")}/${c.green("mod")} uninstall <id>
${MODULE_HELP_LABEL} uninstall <id>
Remove an installed module
${c.green("module")}/${c.green("mod")} verify [id]
${MODULE_HELP_LABEL} verify [id]
Verify installed modules (SHA-256)
${c.green("module")}/${c.green("mod")} info <id>
${MODULE_HELP_LABEL} info <id>
Show one installed module's details
${c.green("module")}/${c.green("mod")} enable|disable <id>
${MODULE_HELP_LABEL} enable|disable <id>
Toggle module (needs db-server)
${c.green("version")} Show version
${c.green("help")} Show this
Expand Down Expand Up @@ -148,8 +157,9 @@ function getCompletions(parsed: ParsedLine): string[] {
case "remote":
if (argIndex === 0) return ["status", "enroll", "disable"].filter(sw);
return [];
case "module":
case "mod": {
default: {
/* module/mod 等别名统一走 MODULE_CMD_NAMES,避免 case 链与权威源漂移。 */
if (!isModuleCommand(cmd)) return [];
if (argIndex === 0) return [...MODULE_SUBCOMMANDS].filter(sw);
const verb = words[0] ?? "";
/* search:补全 registry 缓存中的 id;其余本地已装 id */
Expand All @@ -167,8 +177,6 @@ function getCompletions(parsed: ParsedLine): string[] {
}
return [];
}
default:
return [];
}
}

Expand Down Expand Up @@ -659,17 +667,16 @@ async function execCmd(parts: string[]): Promise<void> {
}
break;
}
case "module":
case "mod": {
const [sub, ...subRest] = args;
stdout.write((await dispatchModuleCommand(sub, subRest)) + "\n");
break;
}
case "quit":
case "exit":
case "q":
throw "QUIT";
default:
if (isModuleCommand(cmd)) {
const [sub, ...subRest] = args;
stdout.write((await dispatchModuleCommand(sub, subRest)) + "\n");
break;
}
stdout.write(c.yellow(`Unknown: ${cmd} (try: help)\n`));
}
}
26 changes: 12 additions & 14 deletions sfmc/src/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,33 +164,31 @@ function nodeBinary(): string {
return IS_SEA ? "node" : process.execPath;
}

function serviceChildEnv(service: ServiceId, optsEnv?: NodeJS.ProcessEnv | null) {
return {
...process.env,
...optsEnv,
SFMC_SERVICE: service,
SFMC_ROOT: ROOT,
SFMC_PACKAGES_DIR: PACKAGES_DIR,
};
}

/**
* 启动一个子服务。
*
* 透传给子进程的 env:
* - SFMC_SERVICE / SFMC_ROOT / SFMC_PACKAGES_DIR
*/
export function spawnService(service: ServiceId, args: string[] = [], opts: SpawnOptions = {}) {
const env = {
...process.env,
...opts.env,
SFMC_SERVICE: service,
SFMC_ROOT: ROOT,
SFMC_PACKAGES_DIR: PACKAGES_DIR,
};
const env = serviceChildEnv(service, opts.env as NodeJS.ProcessEnv | undefined);
const script = resolveServiceScript(service);
return spawn(nodeBinary(), [script, ...args], { ...opts, env });
}

/** spawnService 的同步版本 */
export function spawnServiceSync(service: ServiceId, args: string[] = [], opts: SpawnSyncOptions = {}) {
const env = {
...process.env,
...opts.env,
SFMC_SERVICE: service,
SFMC_ROOT: ROOT,
SFMC_PACKAGES_DIR: PACKAGES_DIR,
};
const env = serviceChildEnv(service, opts.env as NodeJS.ProcessEnv | undefined);
const script = resolveServiceScript(service);
return spawnSync(nodeBinary(), [script, ...args], { ...opts, env });
}
5 changes: 4 additions & 1 deletion tools/check-ootb.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,10 @@ async function main() {
console.log("[ootb] WARN: sfmc/dist/main.js 缺失 — 跳过 CLI 检查");
} else {
const r = runSync(process.execPath, [SFMC_DIST, "--help"], { cwd: ROOT });
const hasModule = /module\s+(list|install)/.test(r.stdout + r.stderr);
/* HELP 现为 "module/mod list"(别名同行);兼容旧 "module list" / 裸 "mod list"。 */
const helpText = String(r.stdout || "") + String(r.stderr || "");
const hasModule =
/\bmodule(\/\S+)?\s+(list|install)\b/.test(helpText) || /\bmod\s+(list|install)\b/.test(helpText);
if (r.status === 0 && hasModule) pass("sfmc CLI module 子命令已注册");
else fail("sfmc CLI module 子命令已注册", (r.stderr || r.stdout || `exit ${r.status}`).trim());
}
Expand Down
Loading