feat: add standalone login renewal
CI / Client installer (macos-latest) (push) Canceled after 0s
CI / Client installer (ubuntu-latest) (push) Canceled after 0s
CI / Client installer (windows-latest) (push) Canceled after 0s
CI / test (22) (push) Canceled after 0s
CI / test (24) (push) Canceled after 0s
CI / release-smoke (push) Canceled after 0s
CI / Client installer (macos-latest) (push) Canceled after 0s
CI / Client installer (ubuntu-latest) (push) Canceled after 0s
CI / Client installer (windows-latest) (push) Canceled after 0s
CI / test (22) (push) Canceled after 0s
CI / test (24) (push) Canceled after 0s
CI / release-smoke (push) Canceled after 0s
This commit is contained in:
+26
-5
@@ -179,6 +179,7 @@ export async function runClientInstaller(
|
||||
assertSafeClientRoot(paths.root, context.home);
|
||||
let result: Record<string, unknown>;
|
||||
if (args.command === "install" || args.command === "update") result = await installClient(paths, args, context);
|
||||
else if (args.command === "login") result = loginClient(paths, context);
|
||||
else if (args.command === "uninstall") result = uninstallClient(paths, args, context);
|
||||
else if (args.command === "print-path") result = printPath(paths, args);
|
||||
else if (args.command === "print-config") result = printConfig(paths, args);
|
||||
@@ -232,6 +233,7 @@ function parseClientArgs(argv: string[]): ParsedArgs {
|
||||
}
|
||||
const allowed = new Set(command === "install" || command === "update"
|
||||
? ["--manifest-url", "--public-key", "--app-root", "--json", "--allow-downgrade"]
|
||||
: command === "login" ? ["--app-root", "--json"]
|
||||
: command === "uninstall" ? ["--app-root", "--json", "--yes"]
|
||||
: command === "print-path" ? ["--app-root", "--json"]
|
||||
: command === "print-config" ? ["--app-root", "--json", "--format"]
|
||||
@@ -319,7 +321,7 @@ async function installClient(paths: ClientPaths, args: ParsedArgs, context: Comm
|
||||
const legacyCleanupFailed: string[] = [];
|
||||
const legacyRemoved = cleanupLegacyInstallations(context.env, context.platform, context.home, legacyCleanupFailed);
|
||||
cleanupOldVersions(paths, versionDir);
|
||||
const postInstall = attemptPostInstallLogin(clientEntry, manifest.gatewayUrl, paths, context);
|
||||
const postInstall = attemptLogin(clientEntry, manifest.gatewayUrl, paths, context);
|
||||
return installResult(paths, state, legacyRemoved, legacyCleanupFailed, postInstall);
|
||||
} finally {
|
||||
rmSync(temporary, { recursive: true, force: true });
|
||||
@@ -483,6 +485,7 @@ function installResult(
|
||||
"立即处理 postInstall:若有 authChallenge.directUrl,必须在当前回复中原样展示,不得声称已另行推送,也不得等待用户首次查询审批。",
|
||||
"用户授权后调用 approval_login;登录成功后按 verifyTool 做一次双来源只读验证,并展示一次性使用示例。",
|
||||
"宿主若不能热加载 MCP,请新建会话或完整重启;恢复上述登录流程后再宣告安装完成,不得执行任何审批写操作。",
|
||||
"登录链接过期时绝不重新安装:MCP 已加载就再次调用 approval_login;尚未加载就执行 loginCommand。",
|
||||
];
|
||||
return {
|
||||
ok: true,
|
||||
@@ -491,17 +494,35 @@ function installResult(
|
||||
root: paths.root,
|
||||
bridgePath: paths.bridgeCommand,
|
||||
cliPath: paths.cliCommand,
|
||||
loginCommand: loginCommand(paths),
|
||||
skillPath: paths.skillDir,
|
||||
mcpConfig: mcpConfig(paths),
|
||||
legacyEntriesRemoved: legacyRemoved,
|
||||
legacyCleanupFailed,
|
||||
configurationModified: false,
|
||||
postInstall,
|
||||
postInstall: { ...postInstall, loginCommand: loginCommand(paths) },
|
||||
nextSteps,
|
||||
};
|
||||
}
|
||||
|
||||
function attemptPostInstallLogin(
|
||||
function loginClient(paths: ClientPaths, context: Pick<CommandContext, "env">): Record<string, unknown> {
|
||||
const state = assertInstalled(paths);
|
||||
const runtime = resolveInside(paths.root, state.runtimeDir);
|
||||
const clientEntry = join(runtime, "node_modules", "dingtalk-approval-client", "dist", "src", "bridge.js");
|
||||
if (!existsSync(clientEntry)) throw new Error("客户端运行时缺少 Bridge 入口,请运行 update 修复安装");
|
||||
return {
|
||||
ok: true,
|
||||
operation: "login",
|
||||
...attemptLogin(clientEntry, state.gatewayUrl, paths, context),
|
||||
loginCommand: loginCommand(paths),
|
||||
};
|
||||
}
|
||||
|
||||
function loginCommand(paths: ClientPaths): { command: string; args: ["login", "--json"] } {
|
||||
return { command: paths.cliCommand, args: ["login", "--json"] };
|
||||
}
|
||||
|
||||
function attemptLogin(
|
||||
clientEntry: string,
|
||||
gatewayUrl: string,
|
||||
paths: ClientPaths,
|
||||
@@ -514,7 +535,7 @@ function attemptPostInstallLogin(
|
||||
verifyTool: { name: "approval_list_todos" as const, arguments: { source: "all" as const, query: "" as const, limit: 1 as const } },
|
||||
completionCriteria: "登录确认并完成钉钉 OA 与薪福通双来源只读验证",
|
||||
};
|
||||
const result = spawnSync(process.execPath, [clientEntry, "--url", gatewayUrl, "--post-install-login"], {
|
||||
const result = spawnSync(process.execPath, [clientEntry, "--url", gatewayUrl, "--login"], {
|
||||
encoding: "utf8",
|
||||
timeout: 30_000,
|
||||
maxBuffer: 256 * 1024,
|
||||
@@ -815,7 +836,7 @@ function writeResult(value: Record<string, unknown>, args: ParsedArgs, context:
|
||||
}
|
||||
|
||||
function usage(): string {
|
||||
return "用法:dingtalk-approval install|update|uninstall|print-path|print-config|doctor [--manifest-url URL] [--format mcp-json] [--json]";
|
||||
return "用法:dingtalk-approval install|update|login|uninstall|print-path|print-config|doctor [--manifest-url URL] [--format mcp-json] [--json]";
|
||||
}
|
||||
|
||||
if (isClientDirectEntrypoint(import.meta.url, process.argv[1])) {
|
||||
|
||||
Reference in New Issue
Block a user