ali-skills 0.1.4 → 0.1.5
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.
|
@@ -16,7 +16,7 @@ import { spawn } from "child_process";
|
|
|
16
16
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
17
17
|
import { basename, dirname, join, normalize, relative, resolve, sep } from "path";
|
|
18
18
|
import { homedir, platform as platform$1 } from "os";
|
|
19
|
-
import { createHash } from "crypto";
|
|
19
|
+
import { createHash, randomBytes, randomInt } from "crypto";
|
|
20
20
|
import { URL as URL$1, fileURLToPath } from "url";
|
|
21
21
|
import * as readline from "readline";
|
|
22
22
|
import { Writable } from "stream";
|
|
@@ -1386,7 +1386,7 @@ var WellKnownProvider = class {
|
|
|
1386
1386
|
}
|
|
1387
1387
|
};
|
|
1388
1388
|
const wellKnownProvider = new WellKnownProvider();
|
|
1389
|
-
var version$1 = "2.1.
|
|
1389
|
+
var version$1 = "2.1.6";
|
|
1390
1390
|
async function checkGithubVersions$1(requests, debugLog = () => {}) {
|
|
1391
1391
|
const results = [];
|
|
1392
1392
|
for (let offset = 0; offset < requests.length; offset += 100) results.push(...await checkGithubVersionBatch(requests.slice(offset, offset + 100), debugLog));
|
|
@@ -3834,6 +3834,56 @@ function listPlatforms() {
|
|
|
3834
3834
|
config
|
|
3835
3835
|
}));
|
|
3836
3836
|
}
|
|
3837
|
+
function isTruthy(value) {
|
|
3838
|
+
return value !== void 0 && [
|
|
3839
|
+
"1",
|
|
3840
|
+
"true",
|
|
3841
|
+
"yes"
|
|
3842
|
+
].includes(value.trim().toLowerCase());
|
|
3843
|
+
}
|
|
3844
|
+
function detectLoginEnvironment({ platform, env }) {
|
|
3845
|
+
if (isTruthy(env.CI)) return {
|
|
3846
|
+
mode: "manual",
|
|
3847
|
+
reason: "检测到 CI 环境"
|
|
3848
|
+
};
|
|
3849
|
+
if (platform === "linux" && !env.DISPLAY && !env.WAYLAND_DISPLAY) return {
|
|
3850
|
+
mode: "manual",
|
|
3851
|
+
reason: "未检测到 Linux 图形桌面"
|
|
3852
|
+
};
|
|
3853
|
+
return { mode: "browser" };
|
|
3854
|
+
}
|
|
3855
|
+
function parseLoginCallbackUrl(rawValue, expectation) {
|
|
3856
|
+
let url;
|
|
3857
|
+
try {
|
|
3858
|
+
url = new URL(rawValue.trim());
|
|
3859
|
+
} catch {
|
|
3860
|
+
throw new Error("回调地址格式无效,请粘贴浏览器地址栏中的完整 URL");
|
|
3861
|
+
}
|
|
3862
|
+
if (url.protocol !== "http:") throw new Error("回调地址协议无效");
|
|
3863
|
+
if (url.hostname !== "localhost" && url.hostname !== "127.0.0.1") throw new Error("回调地址主机无效");
|
|
3864
|
+
if (url.port !== String(expectation.port) || url.pathname !== "/callback") throw new Error("回调地址不属于本次登录");
|
|
3865
|
+
if (url.searchParams.get("state") !== expectation.state) throw new Error("回调地址 state 校验失败,请使用本次登录生成的地址");
|
|
3866
|
+
const empId = url.searchParams.get("emp_id") || "";
|
|
3867
|
+
const account = url.searchParams.get("account") || "";
|
|
3868
|
+
const name = url.searchParams.get("name") || "";
|
|
3869
|
+
const email = url.searchParams.get("email") || "";
|
|
3870
|
+
const privateToken = url.searchParams.get("private_token") || "";
|
|
3871
|
+
const ssoRefreshToken = url.searchParams.get("sso_refresh_token") || "";
|
|
3872
|
+
const expiresAtRaw = url.searchParams.get("expires_at") || "";
|
|
3873
|
+
if (!empId || !privateToken) throw new Error("回调地址缺少必要的登录凭证");
|
|
3874
|
+
const expiresAt = Number(expiresAtRaw);
|
|
3875
|
+
const nowSeconds = expectation.nowSeconds ?? Math.floor(Date.now() / 1e3);
|
|
3876
|
+
if (!Number.isSafeInteger(expiresAt) || expiresAt <= nowSeconds) throw new Error("回调地址中的登录凭证已过期或无效");
|
|
3877
|
+
return {
|
|
3878
|
+
empId,
|
|
3879
|
+
account,
|
|
3880
|
+
name,
|
|
3881
|
+
email,
|
|
3882
|
+
privateToken,
|
|
3883
|
+
ssoRefreshToken,
|
|
3884
|
+
expiresAt
|
|
3885
|
+
};
|
|
3886
|
+
}
|
|
3837
3887
|
const DIM$4 = "\x1B[38;5;102m";
|
|
3838
3888
|
const TEXT$3 = "\x1B[38;5;145m";
|
|
3839
3889
|
const RESET$4 = "\x1B[0m";
|
|
@@ -3863,34 +3913,34 @@ function displayWidth$1(str) {
|
|
|
3863
3913
|
function printJson(payload, pretty = false) {
|
|
3864
3914
|
console.log(JSON.stringify(payload, null, pretty ? 2 : 0));
|
|
3865
3915
|
}
|
|
3866
|
-
function startLocalServer() {
|
|
3916
|
+
function startLocalServer(state) {
|
|
3867
3917
|
return new Promise((resolve) => {
|
|
3868
3918
|
let resolveCallback;
|
|
3869
3919
|
const callbackPromise = new Promise((resolve) => {
|
|
3870
3920
|
resolveCallback = resolve;
|
|
3871
3921
|
});
|
|
3872
3922
|
const server = http.createServer((req, res) => {
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
if (!empId || !privateToken) {
|
|
3923
|
+
if (new URL$1(req.url || "/", `http://localhost`).pathname === "/callback") {
|
|
3924
|
+
let callbackData;
|
|
3925
|
+
try {
|
|
3926
|
+
const address = server.address();
|
|
3927
|
+
callbackData = parseLoginCallbackUrl(`http://localhost:${address.port}${req.url || ""}`, {
|
|
3928
|
+
port: address.port,
|
|
3929
|
+
state
|
|
3930
|
+
});
|
|
3931
|
+
} catch (error) {
|
|
3883
3932
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
3884
3933
|
res.end(`
|
|
3885
3934
|
<html>
|
|
3886
3935
|
<body style="font-family: sans-serif; text-align: center; padding: 50px;">
|
|
3887
3936
|
<h1 style="color: #ff4d4f;">登录失败</h1>
|
|
3888
|
-
<p
|
|
3937
|
+
<p>${error instanceof Error ? error.message : "回调地址无效"}</p>
|
|
3889
3938
|
</body>
|
|
3890
3939
|
</html>
|
|
3891
3940
|
`);
|
|
3892
3941
|
return;
|
|
3893
3942
|
}
|
|
3943
|
+
const { empId, account, name } = callbackData;
|
|
3894
3944
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
3895
3945
|
res.end(`
|
|
3896
3946
|
<html>
|
|
@@ -4028,22 +4078,14 @@ function startLocalServer() {
|
|
|
4028
4078
|
</body>
|
|
4029
4079
|
</html>
|
|
4030
4080
|
`);
|
|
4031
|
-
resolveCallback(
|
|
4032
|
-
empId,
|
|
4033
|
-
account,
|
|
4034
|
-
name,
|
|
4035
|
-
email,
|
|
4036
|
-
privateToken,
|
|
4037
|
-
ssoRefreshToken,
|
|
4038
|
-
expiresAt: parseInt(expiresAt, 10)
|
|
4039
|
-
});
|
|
4081
|
+
resolveCallback(callbackData);
|
|
4040
4082
|
setTimeout(() => server.close(), 1e3);
|
|
4041
4083
|
} else {
|
|
4042
4084
|
res.writeHead(404);
|
|
4043
4085
|
res.end("Not Found");
|
|
4044
4086
|
}
|
|
4045
4087
|
});
|
|
4046
|
-
server.listen(0, "
|
|
4088
|
+
server.listen(0, "127.0.0.1", () => {
|
|
4047
4089
|
const port = server.address().port;
|
|
4048
4090
|
resolve({
|
|
4049
4091
|
port,
|
|
@@ -4053,13 +4095,106 @@ function startLocalServer() {
|
|
|
4053
4095
|
});
|
|
4054
4096
|
});
|
|
4055
4097
|
}
|
|
4056
|
-
function
|
|
4057
|
-
const
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4098
|
+
function requestBrowserOpen(url) {
|
|
4099
|
+
const command = process.platform === "darwin" ? {
|
|
4100
|
+
cmd: "open",
|
|
4101
|
+
args: [url]
|
|
4102
|
+
} : process.platform === "win32" ? {
|
|
4103
|
+
cmd: "cmd",
|
|
4104
|
+
args: [
|
|
4105
|
+
"/c",
|
|
4106
|
+
"start",
|
|
4107
|
+
"",
|
|
4108
|
+
url
|
|
4109
|
+
]
|
|
4110
|
+
} : {
|
|
4111
|
+
cmd: "xdg-open",
|
|
4112
|
+
args: [url]
|
|
4113
|
+
};
|
|
4114
|
+
return new Promise((resolve, reject) => {
|
|
4115
|
+
const child = spawn(command.cmd, command.args, { stdio: "ignore" });
|
|
4116
|
+
let settled = false;
|
|
4117
|
+
const finish = (error) => {
|
|
4118
|
+
if (settled) return;
|
|
4119
|
+
settled = true;
|
|
4120
|
+
if (error) reject(error);
|
|
4121
|
+
else resolve();
|
|
4122
|
+
};
|
|
4123
|
+
child.once("error", (error) => finish(error));
|
|
4124
|
+
child.once("exit", (code) => {
|
|
4125
|
+
if (code === 0) finish();
|
|
4126
|
+
else finish(/* @__PURE__ */ new Error(`浏览器启动命令退出,code=${String(code)}`));
|
|
4127
|
+
});
|
|
4128
|
+
child.unref();
|
|
4129
|
+
setTimeout(() => finish(), 1500).unref();
|
|
4061
4130
|
});
|
|
4062
4131
|
}
|
|
4132
|
+
function startManualCallbackReader(expectation) {
|
|
4133
|
+
let settled = false;
|
|
4134
|
+
let resolveCallback;
|
|
4135
|
+
const callbackPromise = new Promise((resolve) => {
|
|
4136
|
+
resolveCallback = resolve;
|
|
4137
|
+
});
|
|
4138
|
+
const rl = readline.createInterface({
|
|
4139
|
+
input: process.stdin,
|
|
4140
|
+
output: process.stdout,
|
|
4141
|
+
terminal: Boolean(process.stdin.isTTY)
|
|
4142
|
+
});
|
|
4143
|
+
const writable = rl;
|
|
4144
|
+
let maskedLength = 0;
|
|
4145
|
+
let maskTruncated = false;
|
|
4146
|
+
if (process.stdin.isTTY) writable._writeToOutput = (chunk) => {
|
|
4147
|
+
const visible = chunk.replace(/\u001b\[[0-9;]*[A-Za-z]/g, "").replace(/[\u0000-\u001f\u007f]/g, "");
|
|
4148
|
+
if (!visible) return;
|
|
4149
|
+
const remaining = Math.max(0, 12 - maskedLength);
|
|
4150
|
+
const nextCount = Math.min(remaining, visible.length);
|
|
4151
|
+
if (nextCount > 0) {
|
|
4152
|
+
process.stdout.write("*".repeat(nextCount));
|
|
4153
|
+
maskedLength += nextCount;
|
|
4154
|
+
}
|
|
4155
|
+
if (visible.length > nextCount && !maskTruncated) {
|
|
4156
|
+
process.stdout.write("…");
|
|
4157
|
+
maskTruncated = true;
|
|
4158
|
+
}
|
|
4159
|
+
};
|
|
4160
|
+
const resetMask = () => {
|
|
4161
|
+
maskedLength = 0;
|
|
4162
|
+
maskTruncated = false;
|
|
4163
|
+
};
|
|
4164
|
+
const showPrompt = () => {
|
|
4165
|
+
process.stdout.write(`${TEXT$3}请粘贴浏览器地址栏中的完整 localhost 回调地址(仅显示掩码):${RESET$4}\n> `);
|
|
4166
|
+
};
|
|
4167
|
+
rl.on("line", (line) => {
|
|
4168
|
+
if (settled || !line.trim()) {
|
|
4169
|
+
if (!settled) {
|
|
4170
|
+
process.stdout.write("\n");
|
|
4171
|
+
resetMask();
|
|
4172
|
+
showPrompt();
|
|
4173
|
+
}
|
|
4174
|
+
return;
|
|
4175
|
+
}
|
|
4176
|
+
try {
|
|
4177
|
+
const data = parseLoginCallbackUrl(line, expectation);
|
|
4178
|
+
settled = true;
|
|
4179
|
+
process.stdout.write("\n");
|
|
4180
|
+
resolveCallback(data);
|
|
4181
|
+
} catch (error) {
|
|
4182
|
+
process.stdout.write("\n");
|
|
4183
|
+
const message = error instanceof Error ? error.message : "回调地址无效";
|
|
4184
|
+
console.error(`${YELLOW$3}⚠ ${message}${RESET$4}`);
|
|
4185
|
+
resetMask();
|
|
4186
|
+
showPrompt();
|
|
4187
|
+
}
|
|
4188
|
+
});
|
|
4189
|
+
showPrompt();
|
|
4190
|
+
return {
|
|
4191
|
+
waitForCallback: () => callbackPromise,
|
|
4192
|
+
close: () => {
|
|
4193
|
+
settled = true;
|
|
4194
|
+
rl.close();
|
|
4195
|
+
}
|
|
4196
|
+
};
|
|
4197
|
+
}
|
|
4063
4198
|
async function revokeGatewaySessionIfPossible(auth) {
|
|
4064
4199
|
try {
|
|
4065
4200
|
const revokeUrl = `${auth.gatewayUrl || getGatewayUrl()}/api/gateway/revoke`;
|
|
@@ -4090,18 +4225,50 @@ async function login(options) {
|
|
|
4090
4225
|
return;
|
|
4091
4226
|
}
|
|
4092
4227
|
}
|
|
4093
|
-
console.log(`${TEXT$3}
|
|
4094
|
-
const
|
|
4095
|
-
const
|
|
4228
|
+
console.log(`${TEXT$3}正在准备登录回调...${RESET$4}`);
|
|
4229
|
+
const state = randomBytes(24).toString("hex");
|
|
4230
|
+
const environment = detectLoginEnvironment({
|
|
4231
|
+
platform: process.platform,
|
|
4232
|
+
env: process.env
|
|
4233
|
+
});
|
|
4234
|
+
const localServer = environment.mode === "browser" ? await startLocalServer(state) : void 0;
|
|
4235
|
+
const callbackPort = localServer?.port ?? randomInt(49152, 65536);
|
|
4236
|
+
const callbackUrl = `http://127.0.0.1:${callbackPort}/callback?state=${state}`;
|
|
4096
4237
|
const gatewayUrl = getGatewayUrl();
|
|
4097
4238
|
const loginUrl = `${gatewayUrl}/api/gateway/login?callback_url=${encodeURIComponent(callbackUrl)}&type=cli`;
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4239
|
+
const expectation = {
|
|
4240
|
+
port: callbackPort,
|
|
4241
|
+
state
|
|
4242
|
+
};
|
|
4243
|
+
if (environment.mode === "manual") {
|
|
4244
|
+
console.log(`${YELLOW$3}${environment.reason},将使用手动浏览器授权。${RESET$4}`);
|
|
4245
|
+
console.log(`${TEXT$3}请在本机浏览器访问以下地址:${RESET$4}`);
|
|
4246
|
+
console.log();
|
|
4247
|
+
console.log(`${DIM$4} ${loginUrl}${RESET$4}`);
|
|
4248
|
+
console.log();
|
|
4249
|
+
console.log(`${DIM$4}授权后页面可能提示无法访问 localhost;请复制地址栏中的完整地址并粘贴到终端。${RESET$4}`);
|
|
4250
|
+
} else {
|
|
4251
|
+
console.log(`${TEXT$3}正在打开浏览器进行 BUC 授权...${RESET$4}`);
|
|
4252
|
+
console.log(`${DIM$4}如果浏览器没有自动打开,请手动访问:${RESET$4}`);
|
|
4253
|
+
console.log();
|
|
4254
|
+
console.log(`${DIM$4} ${loginUrl}${RESET$4}`);
|
|
4255
|
+
console.log();
|
|
4256
|
+
try {
|
|
4257
|
+
await requestBrowserOpen(loginUrl);
|
|
4258
|
+
} catch {
|
|
4259
|
+
console.log(`${YELLOW$3}未能打开浏览器,请使用上方地址在任意本机浏览器完成授权。${RESET$4}`);
|
|
4260
|
+
}
|
|
4261
|
+
}
|
|
4262
|
+
console.log(`${TEXT$3}${localServer ? "等待自动回调或手动粘贴" : "等待手动粘贴回调地址"}...${RESET$4}`);
|
|
4263
|
+
const manualReader = startManualCallbackReader(expectation);
|
|
4103
4264
|
try {
|
|
4104
|
-
const { empId, account, name, email, privateToken, ssoRefreshToken, expiresAt } = await
|
|
4265
|
+
const { empId, account, name, email, privateToken, ssoRefreshToken, expiresAt } = await Promise.race([
|
|
4266
|
+
localServer?.waitForCallback(),
|
|
4267
|
+
manualReader.waitForCallback(),
|
|
4268
|
+
new Promise((_, reject) => {
|
|
4269
|
+
setTimeout(() => reject(/* @__PURE__ */ new Error("登录授权等待超时,请重新执行 login")), 900 * 1e3).unref();
|
|
4270
|
+
})
|
|
4271
|
+
].filter((promise) => promise !== void 0));
|
|
4105
4272
|
saveAuth({
|
|
4106
4273
|
empId,
|
|
4107
4274
|
account,
|
|
@@ -4123,8 +4290,10 @@ async function login(options) {
|
|
|
4123
4290
|
console.log(`${DIM$4}可尝试:在网页端(https://ali-skills.alibaba-inc.com)退出平台登录后重新执行 login 命令。同时请将此问题反馈给本工具开发者处理,感谢!${RESET$4}`);
|
|
4124
4291
|
}
|
|
4125
4292
|
} catch (error) {
|
|
4126
|
-
close();
|
|
4127
4293
|
throw error;
|
|
4294
|
+
} finally {
|
|
4295
|
+
manualReader.close();
|
|
4296
|
+
localServer?.close();
|
|
4128
4297
|
}
|
|
4129
4298
|
}
|
|
4130
4299
|
async function logout(platformInput, yuqueGroup, clearAll) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ali-skills",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "The open agent skills ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"author": "",
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@ali/cli-skills": "^2.1.
|
|
35
|
+
"@ali/cli-skills": "^2.1.6"
|
|
36
36
|
},
|
|
37
37
|
"bundleDependencies": [
|
|
38
38
|
"@ali/cli-skills"
|