@lazycatcloud/lzc-cli 1.2.63 → 1.2.65

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 CHANGED
@@ -1,3 +1,12 @@
1
+ # 1.2.65
2
+
3
+ 1. 适配新版本开发者平台接口
4
+
5
+ # 1.2.64
6
+
7
+ 1. 升级 dozzle,支持查看所有容器日志
8
+ 2. 修复 devshell ssh 多路复用错误
9
+
1
10
  # 1.2.63
2
11
 
3
12
  1. 处理开发者账号无法登陆问题
package/lib/app/index.js CHANGED
@@ -149,6 +149,7 @@ export function lpkAppCommand(program) {
149
149
  const bridge = new DebugBridge()
150
150
  await bridge.init()
151
151
  await bridge.uninstall(pkgId)
152
+ console.log(`默认微服设备: ${bridge.boxname} ,卸载应用 ${pkgId} 完成`)
152
153
  }
153
154
  },
154
155
  {
@@ -25,9 +25,9 @@ function findOnceLpkByDir(dir = process.cwd()) {
25
25
  }
26
26
 
27
27
  export class LpkInstaller {
28
- constructor() {}
28
+ constructor() { }
29
29
 
30
- async init() {}
30
+ async init() { }
31
31
 
32
32
  // deploy 构建和安装
33
33
  async deploy(builder) {
@@ -119,17 +119,23 @@ export class LpkInstaller {
119
119
  fs.rmSync(tempDir, { recursive: true })
120
120
  }
121
121
 
122
- const bridge = new DebugBridge()
123
- await bridge.init()
124
- logger.info("开始安装应用")
125
- await bridge.install(pkgPath, manifest ? manifest["package"] : "")
126
- logger.info("\n")
127
- logger.info(`安装成功!`)
128
- if (manifest) {
129
- logger.info(
130
- `👉 请在浏览器中访问 https://${manifest["application"]["subdomain"]}.${shellapi.boxname}.heiyu.space`
122
+ try {
123
+ const bridge = new DebugBridge()
124
+ await bridge.init()
125
+ logger.info("开始安装应用")
126
+ await bridge.install(pkgPath, manifest ? manifest["package"] : "")
127
+ logger.info("\n")
128
+ logger.info(`安装成功!`)
129
+ if (manifest) {
130
+ logger.info(
131
+ `👉 请在浏览器中访问 https://${manifest["application"]["subdomain"]}.${shellapi.boxname}.heiyu.space`
132
+ )
133
+ logger.info(`👉 并使用微服的用户名和密码登录`)
134
+ }
135
+ } catch(error) {
136
+ logger.error(
137
+ `安装失败: ${error}`
131
138
  )
132
- logger.info(`👉 并使用微服的用户名和密码登录`)
133
139
  }
134
140
  }
135
141
  }
@@ -0,0 +1,10 @@
1
+ /*
2
+ * @Author: Bin
3
+ * @Date: 2025-04-14
4
+ * @FilePath: /lzc-cli/lib/appstore/env.js
5
+ */
6
+
7
+ const accountServerUrl = "https://account.lazycat.cloud"
8
+ const appStoreServerUrl = "https://appstore.api.lazycat.cloud"
9
+
10
+ export { accountServerUrl, appStoreServerUrl }
@@ -4,6 +4,7 @@ import { PrePublish } from "./prePublish.js"
4
4
  import { reLogin, request } from "./login.js"
5
5
  import fs from "node:fs"
6
6
  import { sleep } from "../utils.js"
7
+ import { appStoreServerUrl } from "./env.js"
7
8
 
8
9
  export function appstoreCommand(program) {
9
10
  let subCommands = [
@@ -58,24 +59,27 @@ export function appstoreCommand(program) {
58
59
  })
59
60
  },
60
61
  handler: async ({ pkgPath, changelog, file }) => {
62
+ const locale = program.locale()
61
63
  const p = new Publish()
62
64
  if (!changelog && file) {
63
65
  changelog = fs.readFileSync(file, "utf8")
64
66
  }
65
- await p.publish(pkgPath, changelog)
67
+ await p.publish(pkgPath, changelog, locale)
66
68
  }
67
69
  },
68
70
  {
69
71
  command: "copy-image <imageName>",
70
72
  desc: "复制镜像至懒猫微服官方源",
71
73
  handler: async ({ imageName }) => {
72
- const baseUrl = "https://appstore.api.lazycat.cloud/api/v2/developer"
74
+ const baseUrl = `${appStoreServerUrl}/api/v3/developer`
73
75
  logger.info(
74
76
  `Waiting ... ( copy ${imageName} to lazycat offical registry)`
75
77
  )
76
78
  try {
77
- for (; ;) {
78
- const resp = await request(`${baseUrl}/push-image?image=${imageName}&v=2`)
79
+ for (;;) {
80
+ const resp = await request(
81
+ `${baseUrl}/app/docker/image/push?image=${imageName}&v=2`
82
+ )
79
83
  if (resp.ok) {
80
84
  const tag = await resp.text()
81
85
  if (tag.length == 0) {
@@ -87,7 +91,7 @@ export function appstoreCommand(program) {
87
91
  logger.error("error: ", await resp.text())
88
92
  }
89
93
 
90
- break;
94
+ break
91
95
  }
92
96
  } catch (err) {
93
97
  console.error(err)
@@ -4,160 +4,163 @@ import url from "url"
4
4
  import logger from "loglevel"
5
5
  import env from "../config/env.js"
6
6
  import inquirer from "inquirer"
7
-
8
- const accountServerUrl = "https://account.lazycat.cloud"
7
+ import { accountServerUrl } from "./env.js"
9
8
 
10
9
  function join(...params) {
11
- let x = ""
12
- try {
13
- // fix: url path join failed for windows
14
- const u = new url.URL(params[0])
15
- params.splice(0, 1)
16
- u.pathname = path.posix.join(u.pathname, ...params)
17
- x = u.toString()
18
- } catch (error) {
19
- console.warn(error)
20
- x = path.join(...params)
21
- }
22
- return x
10
+ let x = ""
11
+ try {
12
+ // fix: url path join failed for windows
13
+ const u = new url.URL(params[0])
14
+ params.splice(0, 1)
15
+ u.pathname = path.posix.join(u.pathname, ...params)
16
+ x = u.toString()
17
+ } catch (error) {
18
+ console.warn(error)
19
+ x = path.join(...params)
20
+ }
21
+ return x
23
22
  }
24
23
 
25
24
  async function login(username, password) {
26
- return fetch(join(accountServerUrl, "/api/login/signin"), {
27
- method: "POST",
28
- body: new URLSearchParams({
29
- username: username,
30
- password: password
31
- })
32
- })
33
- .then(async (res) => {
34
- let bodyText = await res.text()
35
- let body = JSON.parse(bodyText)
36
- if (body.success) {
37
- return Promise.resolve(body.data)
38
- }
39
- return Promise.reject(body.message)
40
- })
41
- .then((data) => {
42
- env.set({ token: data.token }, true)
43
- logger.info("登录成功!")
44
- })
25
+ return fetch(join(accountServerUrl, "/api/login/signin"), {
26
+ method: "POST",
27
+ body: new URLSearchParams({
28
+ username: username,
29
+ password: password
30
+ })
31
+ })
32
+ .then(async (res) => {
33
+ let bodyText = await res.text()
34
+ let body = JSON.parse(bodyText)
35
+ if (body.success) {
36
+ return Promise.resolve(body.data)
37
+ }
38
+ return Promise.reject(body.message)
39
+ })
40
+ .then((data) => {
41
+ env.set({ token: data.token }, true)
42
+ logger.info("登录成功!")
43
+ })
45
44
  }
46
45
 
47
46
  async function isLogin() {
48
- try {
49
- let token = env.get("token")
50
- if (!token) {
51
- return false
52
- }
53
- return fetch(join(accountServerUrl, "/api/user/current"), {
54
- method: "GET",
55
- headers: {
56
- "X-User-Token": token
57
- }
58
- }).then(async (res) => {
59
- let bodyText = await res.text()
60
- let body = JSON.parse(bodyText)
61
- if (body.success) {
62
- return token
63
- }
64
- logger.debug(body.message)
65
- return false
66
- })
67
- } catch (e) {
68
- logger.trace(e)
69
- return false
70
- }
47
+ try {
48
+ let token = env.get("token")
49
+ if (!token) {
50
+ return false
51
+ }
52
+ return fetch(join(accountServerUrl, "/api/user/current"), {
53
+ method: "GET",
54
+ headers: {
55
+ "X-User-Token": token
56
+ }
57
+ }).then(async (res) => {
58
+ let bodyText = await res.text()
59
+ let body = JSON.parse(bodyText)
60
+ if (body.success) {
61
+ return token
62
+ }
63
+ logger.debug(body.message)
64
+ return false
65
+ })
66
+ } catch (e) {
67
+ logger.trace(e)
68
+ return false
69
+ }
71
70
  }
72
71
 
73
72
  async function askUserInfo() {
74
- const noEmpty = (value) => value != ""
75
- return await inquirer.prompt([
76
- {
77
- type: "input",
78
- name: "username",
79
- message: "请输入登录用户名",
80
- validate: noEmpty
81
- },
82
- {
83
- type: "password",
84
- mask: "*",
85
- name: "password",
86
- message: "请输入登录密码",
87
- validate: noEmpty
88
- }
89
- ])
73
+ const noEmpty = (value) => value != ""
74
+ return await inquirer.prompt([
75
+ {
76
+ type: "input",
77
+ name: "username",
78
+ message: "请输入登录用户名",
79
+ validate: noEmpty
80
+ },
81
+ {
82
+ type: "password",
83
+ mask: "*",
84
+ name: "password",
85
+ message: "请输入登录密码",
86
+ validate: noEmpty
87
+ }
88
+ ])
90
89
  }
91
90
 
92
91
  async function interactiveLogin() {
93
- try {
94
- let info = await askUserInfo()
95
- await login(info.username, info.password)
96
- } catch (e) {
97
- logger.debug("login error: ", e)
98
- logger.error("帐号或者密码错误,请重新输入!")
99
- return interactiveLogin()
100
- }
92
+ try {
93
+ let info = await askUserInfo()
94
+ await login(info.username, info.password)
95
+ } catch (e) {
96
+ logger.debug("login error: ", e)
97
+ logger.error("帐号或者密码错误,请重新输入!")
98
+ return interactiveLogin()
99
+ }
101
100
  }
102
101
 
103
102
  function tipsFirstLogin() {
104
- let token = env.get("token")
105
- if (!token) {
106
- // 还没登录过的用户提示用户前往 https://developer.lazycat.cloud/manage 注册开发者账号
107
- logger.info("请登录懒猫微服社区账号,账号注册以及开发者权限申请地址: https://developer.lazycat.cloud/manage")
108
- }
103
+ let token = env.get("token")
104
+ if (!token) {
105
+ // 还没登录过的用户提示用户前往 https://developer.lazycat.cloud/manage 注册开发者账号
106
+ logger.info(
107
+ "请登录懒猫微服社区账号,账号注册以及开发者权限申请地址: https://developer.lazycat.cloud/manage"
108
+ )
109
+ }
109
110
  }
110
111
 
111
112
  export async function reLogin() {
112
- let token = await isLogin()
113
- if (token) {
114
- const questions = [
115
- {
116
- name: "relogin",
117
- type: "input",
118
- default: "n",
119
- message: "检测到已经登录,是否重新登录(y/n):"
120
- }
121
- ]
122
- const answers = await inquirer.prompt(questions)
123
- if (answers.relogin.toLowerCase() === "n") {
124
- logger.info(`token: ${token}`)
125
- return
126
- }
127
- } else {
128
- tipsFirstLogin()
129
- }
130
- await interactiveLogin()
113
+ let token = await isLogin()
114
+ if (token) {
115
+ const questions = [
116
+ {
117
+ name: "relogin",
118
+ type: "input",
119
+ default: "n",
120
+ message: "检测到已经登录,是否重新登录(y/n):"
121
+ }
122
+ ]
123
+ const answers = await inquirer.prompt(questions)
124
+ if (answers.relogin.toLowerCase() === "n") {
125
+ logger.info(`token: ${token}`)
126
+ return
127
+ }
128
+ } else {
129
+ tipsFirstLogin()
130
+ }
131
+ await interactiveLogin()
131
132
  }
132
133
 
133
134
  export async function autoLogin() {
134
- let token = await isLogin()
135
- if (token) {
136
- logger.debug("appstore 已经登录")
137
- return
138
- } else {
139
- tipsFirstLogin()
140
- }
135
+ let token = await isLogin()
136
+ if (token) {
137
+ logger.debug("appstore 已经登录")
138
+ return
139
+ } else {
140
+ tipsFirstLogin()
141
+ }
141
142
 
142
- logger.debug("token错误,尝试自动登录")
143
- await interactiveLogin()
143
+ logger.debug("token错误,尝试自动登录")
144
+ await interactiveLogin()
144
145
  }
145
146
 
146
147
  export async function request(url, options = {}) {
147
- await autoLogin()
148
+ await autoLogin()
149
+
150
+ const token = env.get("token")
148
151
 
149
- const token = env.get("token")
152
+ let headers = {
153
+ "X-User-Token": token,
154
+ cookie: `userToken=${token}`
155
+ }
156
+ if (options.headers) {
157
+ headers = Object.assign({}, options.headers, headers)
158
+ }
150
159
 
151
- let headers = {
152
- "X-User-Token": token,
153
- cookie: `userToken=${token}`
154
- }
155
- if (options.headers) {
156
- headers = Object.assign({}, options.headers, headers)
157
- }
160
+ // logger.debug("token", token)
158
161
 
159
- options = Object.assign({}, options, { headers })
160
- logger.trace(`fetch ${url}`, options)
162
+ options = Object.assign({}, options, { headers })
163
+ logger.trace(`fetch ${url}`, options)
161
164
 
162
- return fetch(url, options)
165
+ return fetch(url, options)
163
166
  }
@@ -9,35 +9,45 @@ import {
9
9
  isPngWithFile,
10
10
  unzipSync,
11
11
  loadFromYaml,
12
- isValidPackageName
12
+ isValidPackageName,
13
+ getLanguageForLocale
13
14
  } from "../utils.js"
15
+ import { appStoreServerUrl } from "./env.js"
14
16
 
15
- async function askChangeLog() {
17
+ async function askChangeLog(locale) {
16
18
  const noEmpty = (value) => value != ""
17
19
  return await inquirer.prompt([
18
20
  {
19
21
  name: "changelog",
20
22
  type: "editor",
21
- message: "填写 changelog 内容",
23
+ message: `填写 changelog 内容 (${locale})`,
22
24
  validate: noEmpty
23
25
  }
24
26
  ])
25
27
  }
26
28
 
27
- async function getCategories(baseUrl) {
28
- const response = await request(`${baseUrl}/categories`, { method: "GET" })
29
- const data = await response.json()
29
+ async function getCategories(baseUrl, locale = "zh") {
30
+ const response = await request(`${baseUrl}/app/category?size=100`, {
31
+ method: "GET"
32
+ })
33
+ const langKey = getLanguageForLocale(locale)
34
+ const { items: data } = await response.json()
35
+ console.log("data", data)
30
36
  return data
31
37
  .sort((a, b) => a.index - b.index)
32
- .map((cat) => ({
33
- name: cat.name,
34
- value: cat.name
35
- }))
38
+ .map((cat) => {
39
+ let localize_name = (cat?.localize_name ?? {})[langKey] ?? undefined
40
+ return {
41
+ name: localize_name ?? cat.name,
42
+ value: cat.id
43
+ }
44
+ })
36
45
  }
37
46
 
38
- async function askPublishAppInfo(baseUrl, manifest) {
47
+ async function askPublishAppInfo(baseUrl, manifest, locale) {
39
48
  // 获取分类列表
40
- const categories = await getCategories(baseUrl)
49
+ // const categories = await getCategories(baseUrl, locale)
50
+ const langKey = getLanguageForLocale(locale)
41
51
 
42
52
  const questions = [
43
53
  {
@@ -49,56 +59,62 @@ async function askPublishAppInfo(baseUrl, manifest) {
49
59
  },
50
60
  {
51
61
  type: "input",
52
- name: "appId",
53
- message: "请输入应用ID:",
62
+ name: "package",
63
+ message: "请输入应用包标识符:",
54
64
  default: manifest["package"],
55
65
  validate: (input) =>
56
- isValidPackageName(input) ? true : "应用ID不符合规范"
57
- },
58
- {
59
- type: "input",
60
- name: "description",
61
- message: "请输入应用描述:",
62
- default: manifest["description"] || ""
63
- },
64
- {
65
- type: "input",
66
- name: "brief",
67
- message: "请输入应用简介(简单的概述):",
68
- default: ""
69
- },
70
- {
71
- type: "checkbox",
72
- name: "category",
73
- message: "请选择应用分类:",
74
- choices: categories,
75
- validate: (input) => (input.length > 0 ? true : "请至少选择一个分类")
76
- },
77
- {
78
- type: "input",
79
- name: "keywords",
80
- message: "请输入关键词(用逗号分隔):",
81
- default: ""
66
+ isValidPackageName(input)
67
+ ? true
68
+ : "应用包标识符不符合规范,建议使用反向域名表示法"
82
69
  },
70
+ // {
71
+ // type: "input",
72
+ // name: "description",
73
+ // message: "请输入应用描述:",
74
+ // default: manifest["description"] || ""
75
+ // },
76
+ // {
77
+ // type: "input",
78
+ // name: "brief",
79
+ // message: "请输入应用简介(简单的概述):",
80
+ // default: ""
81
+ // },
82
+ // 开发者暂时不能配置应用分类
83
+ // {
84
+ // type: "checkbox",
85
+ // name: "category",
86
+ // message: "请选择应用分类:",
87
+ // choices: categories,
88
+ // validate: (input) => (input.length > 0 ? true : "请至少选择一个分类")
89
+ // },
90
+ // {
91
+ // type: "input",
92
+ // name: "keywords",
93
+ // message: "请输入关键词(用逗号分隔):",
94
+ // default: ""
95
+ // },
83
96
  {
84
97
  type: "input",
85
98
  name: "source",
86
- message: "请输入应用来源:",
99
+ message: "请输入应用来源(原创应用可不填):",
87
100
  default: manifest["homepage"] || ""
88
101
  },
89
102
  {
90
103
  type: "input",
91
104
  name: "author",
92
- message: "请输入作者名称:",
105
+ message: "请输入作者名称(原创应用可不填):",
93
106
  default: manifest["author"] || ""
94
107
  }
95
108
  ]
96
109
 
97
110
  const answers = await inquirer.prompt(questions)
98
- return answers
111
+ return {
112
+ language: langKey, // 应用主要语言(后续需要做成可以让用户选择)
113
+ ...answers
114
+ }
99
115
  }
100
116
 
101
- async function askWhetherCreateLPK(baseUrl, manifest) {
117
+ async function askWhetherCreateLPK(baseUrl, manifest, locale) {
102
118
  const answers = await inquirer.prompt([
103
119
  {
104
120
  name: "continue",
@@ -109,10 +125,16 @@ async function askWhetherCreateLPK(baseUrl, manifest) {
109
125
  }
110
126
  ])
111
127
  if (answers.continue.toLowerCase() === "y") {
112
- const appInfo = await askPublishAppInfo(baseUrl, manifest)
113
- const crateAppRes = await request(`${baseUrl}/apps`, {
128
+ const appInfo = await askPublishAppInfo(baseUrl, manifest, locale)
129
+ const crateAppRes = await request(`${baseUrl}/app/create`, {
114
130
  method: "POST",
115
- body: JSON.stringify(appInfo)
131
+ body: JSON.stringify({
132
+ package: appInfo.package,
133
+ language: appInfo.language,
134
+ name: appInfo.name,
135
+ source: appInfo.source,
136
+ source_author: appInfo.author
137
+ })
116
138
  })
117
139
  logger.debug("create app res: ", await crateAppRes.text())
118
140
  logger.info(`创建 ${manifest["package"]} 应用成功!`)
@@ -131,7 +153,7 @@ async function askWhetherCreateLPK(baseUrl, manifest) {
131
153
  }
132
154
 
133
155
  export class Publish {
134
- constructor(baseUrl = "https://appstore.api.lazycat.cloud/api/v2/developer") {
156
+ constructor(baseUrl = `${appStoreServerUrl}/api/v3/developer`) {
135
157
  this.baseUrl = baseUrl
136
158
  }
137
159
 
@@ -170,16 +192,17 @@ export class Publish {
170
192
  try {
171
193
  unzipSync(pkgPath, tempDir, ["manifest.yml"])
172
194
  const manifest = loadFromYaml(path.join(tempDir, "manifest.yml"))
173
- const checkUrl = this.baseUrl + `/apps/${manifest["package"]}/check_exist`
195
+ const checkUrl =
196
+ this.baseUrl + `/app/check/exist?package=${manifest["package"]}`
174
197
  const res = await request(checkUrl, { method: "GET" })
175
198
  if (res.status >= 400) {
176
199
  logger.error("检测应用是否存在出错, 错误状态码为: ", res.status)
177
- logger.error(await res.text())
200
+ logger.error(await res.json())
178
201
  return { manifest, appIdExisted: true } // 默认认为已经存在
179
202
  } else {
180
- const text = (await res.text()).trim()
181
- logger.debug(`check appId[${manifest["package"]}] exist: ${text}`)
182
- return { manifest, appIdExisted: text == "true" }
203
+ const { exist = false } = await res.json()
204
+ logger.debug(`check appId[${manifest["package"]}] exist: ${exist}`)
205
+ return { manifest, appIdExisted: exist }
183
206
  }
184
207
  } finally {
185
208
  fs.rmSync(tempDir, { recursive: true })
@@ -189,19 +212,20 @@ export class Publish {
189
212
  /**
190
213
  * @param {string} pkgPath
191
214
  * @param {string} changelog
215
+ * @param {string} locale
192
216
  */
193
- async publish(pkgPath, changelog) {
217
+ async publish(pkgPath, changelog, locale = "zh") {
194
218
  if (!Publish.preCheck(pkgPath)) return
195
219
 
196
220
  const { manifest, appIdExisted } = await this.checkAppIdExist(pkgPath)
197
221
  if (!appIdExisted) {
198
- await askWhetherCreateLPK(this.baseUrl, manifest)
222
+ await askWhetherCreateLPK(this.baseUrl, manifest, locale)
199
223
  }
200
224
 
201
225
  await autoLogin()
202
226
 
203
227
  if (!changelog) {
204
- const answer = await askChangeLog()
228
+ const answer = await askChangeLog(locale)
205
229
  changelog = answer.changelog
206
230
  }
207
231
  changelog = changelog.trim() // clean space ^:)
@@ -210,7 +234,7 @@ export class Publish {
210
234
  const form = new FormData()
211
235
  form.append("file", fs.createReadStream(pkgPath))
212
236
 
213
- const uploadURL = this.baseUrl + "/upload_lpk"
237
+ const uploadURL = this.baseUrl + "/app/lpk/upload"
214
238
  logger.debug("upload url is", uploadURL)
215
239
 
216
240
  const res = await request(uploadURL, {
@@ -225,17 +249,25 @@ export class Publish {
225
249
  const lpkInfo = await JSON.parse(text)
226
250
  logger.debug("upload lpk response", lpkInfo)
227
251
 
228
- const sendURL = this.baseUrl + `/apps/${lpkInfo.package}/reviews`
252
+ const sendURL = this.baseUrl + `/app/${lpkInfo.package}/review/create`
229
253
  logger.debug("publish url is", sendURL)
230
254
 
231
255
  const formData = {
232
- changelog,
233
- name: lpkInfo.name,
234
- iconPath: lpkInfo.iconPath,
235
- pkgPath: lpkInfo.url,
236
- supportPC: lpkInfo.supportPC,
237
- supportMobile: lpkInfo.supportMobile
256
+ version: {
257
+ // supportPC: lpkInfo.supportPC,
258
+ // supportMobile: lpkInfo.supportMobile,
259
+ package: lpkInfo.package,
260
+ name: lpkInfo.version,
261
+ icon_path: lpkInfo.iconPath,
262
+ pkg_path: lpkInfo.url,
263
+ unsupported_platforms: lpkInfo.unsupportedPlatforms,
264
+ min_os_version: lpkInfo.minOsVersion,
265
+ changelogs: {}
266
+ }
238
267
  }
268
+ // changelogs 本地化
269
+ const langKey = getLanguageForLocale(locale)
270
+ formData.version.changelogs[langKey] = changelog
239
271
 
240
272
  logger.debug("form data is", formData)
241
273
 
@@ -30,6 +30,7 @@ export function sshCmdArgs(...args) {
30
30
  const defaultOptions = [
31
31
  `-o "StrictHostKeyChecking=no"`,
32
32
  `-o "UserKnownHostsFile=/dev/null"`,
33
+ `-o "ControlMaster=no"`,
33
34
  "-q",
34
35
  "-p 22222",
35
36
  `${isTraceMode() ? "-v" : ""}`
@@ -126,7 +127,11 @@ export class DebugBridge {
126
127
  return true
127
128
  } catch (err) {
128
129
  logger.debug("canPublicKey error: ", err)
129
- return false
130
+ if (err?.code == "ETIMEOUT") {
131
+ throw `域名解析失败,请检查代理软件是否对*.heiyu.space拦截`
132
+ } else {
133
+ return false
134
+ }
130
135
  }
131
136
  }
132
137
 
package/lib/utils.js CHANGED
@@ -484,21 +484,20 @@ export async function resolveDomain(domain) {
484
484
  try {
485
485
  // Set machine's dns server as defalut dns server
486
486
  dns.setServers(["[fc03:1136:3800::1]"])
487
-
488
487
  const [ipv6Addresses, ipv4Addresses] = await Promise.allSettled([
489
488
  __resolveDomain(domain, true),
490
489
  __resolveDomain(domain, false)
491
490
  ])
492
491
  if (ipv6Addresses.status == "fulfilled") {
493
492
  return ipv6Addresses.value
494
- } else if (ipv4Addresses.status != "fulfilled") {
493
+ } else if (ipv4Addresses.status == "fulfilled") {
495
494
  return ipv4Addresses.value
496
495
  } else {
497
- throw `无法解析域名 ${domain}`
496
+ throw ipv6Addresses.reason
498
497
  }
499
498
  } catch (error) {
500
- logger.error("resolve domain: ", error)
501
- throw `无法解析域名 ${domain}: ${error}`
499
+ logger.error(`无法解析域名 ${domain}: `, error)
500
+ throw error
502
501
  }
503
502
  }
504
503
 
@@ -656,3 +655,13 @@ export function checkRsync() {
656
655
  resolve()
657
656
  })
658
657
  }
658
+
659
+ export function getLanguageForLocale(locale) {
660
+ locale = locale.replace("_", "-")
661
+ try {
662
+ let l = new Intl.Locale(locale)
663
+ return l.language
664
+ } catch (error) {
665
+ return locale
666
+ }
667
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazycatcloud/lzc-cli",
3
- "version": "1.2.63",
3
+ "version": "1.2.65",
4
4
  "description": "lazycat cloud developer kit",
5
5
  "scripts": {
6
6
  "prepublishOnly": "node check-changelog.js"