@lazycatcloud/lzc-cli 1.1.3 → 1.1.6

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.
Files changed (59) hide show
  1. package/cmds/app.js +133 -0
  2. package/cmds/config.js +55 -0
  3. package/cmds/create.js +55 -0
  4. package/cmds/dev.js +130 -0
  5. package/cmds/init.js +125 -0
  6. package/cmds/log.js +103 -0
  7. package/cmds/publish.js +116 -0
  8. package/lib/api.js +21 -7
  9. package/lib/app/index.js +92 -0
  10. package/lib/app/lpk_build.js +229 -0
  11. package/lib/app/lpk_create.js +201 -0
  12. package/lib/app/lpk_devshell.js +621 -0
  13. package/lib/app/lpk_installer.js +67 -0
  14. package/lib/archiver.js +0 -42
  15. package/lib/autologin.js +84 -0
  16. package/lib/box/check_qemu.js +50 -0
  17. package/lib/box/hportal.js +8 -1
  18. package/lib/box/index.js +35 -15
  19. package/lib/box/qemu_vm_mgr.js +142 -56
  20. package/lib/builder.js +14 -3
  21. package/lib/dev.js +12 -6
  22. package/lib/env.js +10 -6
  23. package/lib/generator.js +2 -2
  24. package/lib/git/git-commit.sh +3 -3
  25. package/lib/sdk.js +29 -5
  26. package/lib/utils.js +69 -46
  27. package/package.json +13 -6
  28. package/scripts/cli.js +92 -13
  29. package/template/_lazycat/debug/shell/Dockerfile +5 -3
  30. package/template/_lazycat/debug/shell/docker-compose.override.yml.in +2 -12
  31. package/template/_lazycat/debug/shell/entrypoint.sh +3 -1
  32. package/template/_lpk/Dockerfile.in +8 -0
  33. package/template/_lpk/devshell/Dockerfile +18 -0
  34. package/template/_lpk/devshell/build.sh +5 -0
  35. package/template/_lpk/devshell/entrypoint.sh +8 -0
  36. package/template/_lpk/devshell/sshd_config +117 -0
  37. package/template/_lpk/manifest.yml.in +17 -0
  38. package/template/_lpk/sync/Dockerfile +16 -0
  39. package/template/_lpk/sync/build.sh +5 -0
  40. package/template/_lpk/sync/entrypoint.sh +8 -0
  41. package/template/_lpk/sync/sshd_config +117 -0
  42. package/template/_lpk/sync.manifest.yml.in +3 -0
  43. package/template/golang/build.sh +6 -0
  44. package/template/golang/lzc-build.yml +52 -0
  45. package/template/ionic_vue3/lzc-build.yml +53 -0
  46. package/template/ionic_vue3/vite.config.ts +1 -1
  47. package/template/release/golang/build.sh +1 -1
  48. package/template/release/ionic_vue3/Dockerfile +1 -1
  49. package/template/release/ionic_vue3/build.sh +1 -3
  50. package/template/release/ionic_vue3/docker-compose.yml.in +0 -5
  51. package/template/release/vue/Dockerfile +1 -1
  52. package/template/release/vue/build.sh +2 -3
  53. package/template/release/vue/docker-compose.yml.in +0 -5
  54. package/template/vue/lzc-build.yml +53 -0
  55. package/template/vue/src/main.js +3 -14
  56. package/template/vue/vue.config.js +16 -0
  57. package/scripts/auto-completion.sh +0 -46
  58. package/template/_lazycat/debug/shell/nginx.conf.template +0 -64
  59. package/template/vue/src/lzc.js +0 -110
package/lib/builder.js CHANGED
@@ -4,12 +4,12 @@ import path from "path";
4
4
  import chalk from "chalk";
5
5
  import execa from "execa";
6
6
  // import { archiveFolder } from "./utils.js";
7
- import { DockerClient } from "./sdk.js";
7
+ import { dockerPullLzcAppsImage, DockerClient } from "./sdk.js";
8
8
  import { DockerfileParser } from "dockerfile-ast";
9
9
  import glob from "fast-glob";
10
10
  import ignore from "@balena/dockerignore";
11
11
  import { createLogUpdate } from "log-update";
12
- import env from "./env.js";
12
+ import env, { sdkEnv } from "./env.js";
13
13
  import Dockerode from "dockerode";
14
14
 
15
15
  export const PRE_BUILD_FILE = "build.sh";
@@ -209,10 +209,21 @@ export default class Builder {
209
209
  */
210
210
  async dockerRemoteBuildV2(contextDir, dockerfile, tag = env.get("APP_ID")) {
211
211
  const src = await this.collectContextFromDockerFile(contextDir, dockerfile);
212
- const host = new URL(env.get("SDK_URL")).host;
212
+ const host = new URL(sdkEnv.sdkUrl).host;
213
213
  console.log(host);
214
214
  const docker = await new DockerClient(host).init();
215
215
  try {
216
+ // TODO, 使用 docker.pull 方法会失败, 原因未知, 使用 workaround 方案
217
+ // docker.pull(
218
+ // "hello-world",
219
+ // // "registry.lazycat.cloud/lzc/lzcapp:0.1",
220
+ // // { authconfig: { auth: "bG5rczpsbmtzMjAyMA==" } },
221
+ // (err, stream) => {
222
+ // console.log("====", err, stream);
223
+ // }
224
+ // );
225
+ await dockerPullLzcAppsImage(host);
226
+
216
227
  return new Promise(async (resolve, reject) => {
217
228
  let refresher = new StatusRefresher();
218
229
 
package/lib/dev.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import execa from "execa";
2
2
  import { execSync } from "child_process";
3
3
  import fs from "fs";
4
+ import chalk from "chalk";
4
5
  import {
5
6
  GitIgnore,
6
7
  isDirSync,
@@ -9,16 +10,16 @@ import {
9
10
  APP_SDK_HOSTNAME,
10
11
  } from "./utils.js";
11
12
  import path from "path";
12
- import env from "./env.js";
13
+ import env, { sdkEnv } from "./env.js";
13
14
  import _get from "lodash.get";
14
15
  import { execPreBuild } from "./builder.js";
15
- import Key from "./key.js";
16
16
  import chokidar from "chokidar";
17
+ import commandExists from "command-exists";
17
18
 
18
19
  import Archiver from "../lib/archiver.js";
19
20
 
20
21
  async function sdkSSHAddr(env) {
21
- let url = await env.get("SDK_URL");
22
+ let url = sdkEnv.sdkUrl;
22
23
  return `${APP_SDK_HOSTNAME}@${urlHostname(url)}:2222`;
23
24
  }
24
25
 
@@ -136,6 +137,13 @@ class DevModule {
136
137
  "-i",
137
138
  keyFile,
138
139
  ].join(" ");
140
+ // 检查rsync工具是否存在:提示用户
141
+ const rsyncExisted = commandExists.sync('rsync')
142
+ if (!rsyncExisted) {
143
+ console.log(chalk.red("请检查 rsync 是否安装,路径是否正确!"));
144
+ process.exit();
145
+ }
146
+ // FIXME: 下方执行命令不确定是否有兼容性问题
139
147
  execSync(
140
148
  `rsync --rsh='${rsh}' -czrPR . root@${appAddr}:/root/${this.appId} --filter=':- .gitignore' --exclude='node_modules' --exclude='.git' --delete`,
141
149
  { stdio: ["ignore", "ignore", "inherit"] }
@@ -196,6 +204,7 @@ class DevModule {
196
204
  ignoreInitial: true,
197
205
  })
198
206
  .on("all", (event, path) => {
207
+ // console.log(event, path);
199
208
  this.syncProject(keyFile, appAddr);
200
209
  });
201
210
  }
@@ -252,9 +261,6 @@ class DevModule {
252
261
  let appAddr;
253
262
 
254
263
  try {
255
- // 确保 sdk 能通过公钥正常访问
256
- await new Key().ensure(env.get("SDK_URL"));
257
-
258
264
  keyFile = path.join(this.tempDir, "debug/ssh/id_ed25519");
259
265
  appAddr = this.getAddress();
260
266
 
package/lib/env.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  import { debuglog } from "util";
13
13
  import inquirer from "inquirer";
14
14
  import chalk from "chalk";
15
- import fetch from "node-fetch";
15
+ import { request } from "./autologin.js";
16
16
  const debug = debuglog("lib/env");
17
17
 
18
18
  const GLOBAL_CONFIG_NAME = "box-config.json";
@@ -83,7 +83,7 @@ async function checkURL(url, suffix = "") {
83
83
  }, 5000);
84
84
 
85
85
  try {
86
- const resp = await fetch(url + suffix, { signal: controller.signal });
86
+ const resp = await request(url + suffix, { signal: controller.signal });
87
87
  if (resp.status != 200) {
88
88
  // 设备可以访问 (client 有正常连接), 但是sdk 这个服务无法访问
89
89
  throw new Error(
@@ -99,9 +99,6 @@ async function checkURL(url, suffix = "") {
99
99
  case "FetchError":
100
100
  console.log(chalk.red("盒子入口地址有误,请核对后再试"));
101
101
  process.exit();
102
- case "AbortError":
103
- console.log(chalk.red(`请求 ${url} 超时, 请确保懒猫云客户端已连接`));
104
- process.exit();
105
102
  default:
106
103
  throw error;
107
104
  }
@@ -246,6 +243,13 @@ class SDKEnv {
246
243
  return "";
247
244
  }
248
245
 
246
+ get sdkHostName() {
247
+ if (env.has("DEFAULT_BOXNAME")) {
248
+ return `sdk.${env.get("DEFAULT_BOXNAME")}.heiyu.space`;
249
+ }
250
+ return "";
251
+ }
252
+
249
253
  async ensure() {
250
254
  if (this.sdkUrl) {
251
255
  try {
@@ -270,7 +274,7 @@ class SDKEnv {
270
274
  await this.installSDK(url);
271
275
  }
272
276
 
273
- env.set({ DEFAULT_BOXNAME: boxname, SDK_URL: url }, true);
277
+ env.set({ DEFAULT_BOXNAME: boxname }, true);
274
278
  }
275
279
 
276
280
  buildSdkUrl(boxname) {
package/lib/generator.js CHANGED
@@ -12,7 +12,7 @@ export const TemplateConfig = {
12
12
  ionic_vue3: {
13
13
  template: "ionic_vue3",
14
14
  defaultEnvs: {
15
- HTTP_SERVICE_PORT: "8080",
15
+ HTTP_SERVICE_PORT: "80",
16
16
  BUILD_CONTEXT: ".lazycat/release",
17
17
  },
18
18
  after: async function (name) {
@@ -43,7 +43,7 @@ export const TemplateConfig = {
43
43
  vue: {
44
44
  template: "vue",
45
45
  defaultEnvs: {
46
- HTTP_SERVICE_PORT: "8080",
46
+ HTTP_SERVICE_PORT: "80",
47
47
  BUILD_CONTEXT: ".lazycat/release",
48
48
  },
49
49
  after: async function (name) {
@@ -1,7 +1,7 @@
1
1
  # executed under appdb
2
2
 
3
- git fetch origin
4
- git reset --hard
5
-
3
+ # git fetch origin
4
+ # git reset --hard
5
+ #
6
6
  git add ${APP_ID}
7
7
  git commit -m "[lzc-cli publish] bump ${APP_ID} version to ${APP_VERSION}"
package/lib/sdk.js CHANGED
@@ -4,8 +4,8 @@ import Docker from "dockerode";
4
4
  import process from "process";
5
5
  import fs from "fs";
6
6
  import { Client } from "ssh2";
7
- import chalk from "chalk";
8
7
  import Key from "./key.js";
8
+ import logger from "loglevel";
9
9
 
10
10
  export async function connectOptions(host) {
11
11
  const pairs = await new Key().getKeyPair();
@@ -38,7 +38,7 @@ export class DockerClient {
38
38
  async init() {
39
39
  this.docker = !!this.host
40
40
  ? new Docker({
41
- protocal: "http",
41
+ protocal: "ssh",
42
42
  agent: ssh(await connectOptions(this.host)),
43
43
  })
44
44
  : new Docker();
@@ -47,9 +47,7 @@ export class DockerClient {
47
47
 
48
48
  async function onUncaughtException(e) {
49
49
  if (e.code == "ECONNREFUSED") {
50
- console.log(
51
- chalk.red(`无法连接 sdk 服务, 请确保 ${chalk.yellow(host)} 可以访问`)
52
- );
50
+ logger.error(`无法连接 sdk 服务, 请确保 ${host} 可以访问`);
53
51
  process.exit(1);
54
52
  } else {
55
53
  throw e;
@@ -78,6 +76,7 @@ export class SSHClient {
78
76
  this.con
79
77
  .on("ready", () => resolve(this.con))
80
78
  .on("error", (err) => {
79
+ logger.error("ssh client ", err);
81
80
  reject(err);
82
81
  })
83
82
  .on("close", () => resolve(null))
@@ -124,3 +123,28 @@ export class SSHClient {
124
123
  );
125
124
  }
126
125
  }
126
+
127
+ export async function dockerPullLzcAppsImage(host) {
128
+ logger.warn("* 更新lzcapp镜像, 未来可能会移除此操作");
129
+ const opts = await connectOptions(host);
130
+ const client = new SSHClient(opts);
131
+ await client.connect();
132
+ try {
133
+ const stream = await client.exec(
134
+ "docker pull registry.lazycat.cloud/lzc/lzcapp:0.1"
135
+ );
136
+
137
+ return new Promise((resolve, reject) => {
138
+ stream.stdout.pipe(process.stdout);
139
+ stream.stderr.pipe(process.stdout);
140
+ stream.on("close", () => {
141
+ client.close();
142
+ resolve();
143
+ });
144
+ stream.on("error", (e) => reject(e));
145
+ });
146
+ } catch (e) {
147
+ client.close();
148
+ throw e;
149
+ }
150
+ }
package/lib/utils.js CHANGED
@@ -8,13 +8,14 @@ import glob from "fast-glob";
8
8
  import yaml from "js-yaml";
9
9
  import mergeWith from "lodash.mergewith";
10
10
  import isArray from "lodash.isarray";
11
- import fetch from "node-fetch";
11
+ import { request } from "./autologin.js";
12
12
  import { dirname } from "path";
13
13
  import { fileURLToPath } from "url";
14
14
  import ignore from "ignore";
15
15
  import ora from "ora";
16
16
  import { desireStatusTimer } from "../lib/api.js";
17
17
  import { warn } from "console";
18
+ import { createHash } from "node:crypto";
18
19
 
19
20
  const META_MARK = "x-lazycat-app";
20
21
  const APP_FOLDER = ".lazycat";
@@ -33,7 +34,7 @@ export const envsubstr = async (templateContents, args) => {
33
34
  async function InstallSDK(box_url) {
34
35
  try {
35
36
  let url = `${box_url}/api/app/apply?id=sdk`;
36
- const resp = await fetch(url, { method: "post" });
37
+ const resp = await request(url, { method: "post" });
37
38
  if (resp.status != 200) {
38
39
  throw new Error(
39
40
  chalk.red(
@@ -54,7 +55,7 @@ async function InstallSDK(box_url) {
54
55
  async function checkSDKInstallStatus(box_url) {
55
56
  const checkSDKstatus = async function (box_url) {
56
57
  let url = `${box_url}/api/app/status?id=sdk`;
57
- const resp = await fetch(url);
58
+ const resp = await request(url);
58
59
  if (resp.status == 200) {
59
60
  const status = await resp.json();
60
61
  return status;
@@ -102,7 +103,7 @@ async function checkSDKInstallStatus(box_url) {
102
103
  async function getInstalledApps(box_url) {
103
104
  try {
104
105
  let url = `${box_url}/api/app/dump`;
105
- const resp = await fetch(url);
106
+ const resp = await request(url);
106
107
  if (resp.status != 200) throw new Error(chalk.red("获取所有已安装App失败"));
107
108
  return await resp.json();
108
109
  } catch (e) {
@@ -191,9 +192,10 @@ function findAppRootPath(aPath) {
191
192
 
192
193
  function toPair(object) {
193
194
  return Object.keys(object).map((key) => {
195
+ let value = object[key] ? object[key].toString() : "";
194
196
  return {
195
197
  name: key,
196
- value: object[key].toString(),
198
+ value,
197
199
  };
198
200
  });
199
201
  }
@@ -203,43 +205,14 @@ function getMetaInfo(composeFile) {
203
205
  return doc[META_MARK];
204
206
  }
205
207
 
206
- async function createTemplateFile(templateFile, outputFile, env) {
208
+ async function envTemplateFile(templateFile, env) {
207
209
  const template = yaml.load(fs.readFileSync(templateFile, "utf8"));
208
- // const meta = template[META_MARK];
209
- // if (
210
- // meta &&
211
- // Array.isArray(meta["permissions"]) &&
212
- // meta["permissions"].includes("lzcapis")
213
- // ) {
214
- // template[META_MARK]["ingress"].push({
215
- // service: "lazycat-apis-sidecar",
216
- // port: 8888,
217
- // subdomain: "${APP_NAME}",
218
- // path: "/lzcapis/",
219
- // auth: "oidc",
220
- // authcallback: "/lzcapis/oidc-callback",
221
- // });
222
- // template["services"]["lazycat-apis-sidecar"] = {
223
- // image: "registry.lazycat.cloud/lazycat-apis-sidecar",
224
- // // volumes_from: ["${APP_NAME}:rw"],
225
- // volumes: ["lzcapis-lzcapp:/lzcapp"],
226
- // command: [
227
- // "--client-id=${LAZYCAT_AUTH_OIDC_CLIENT_ID}",
228
- // "--client-secret=${LAZYCAT_AUTH_OIDC_CLIENT_SECRET}",
229
- // "--client-url=https://${LAZYCAT_APP_ORIGIN}/lzcapis/",
230
- // "--issuer=${LAZYCAT_AUTH_OIDC_ISSUER_URL}",
231
- // "--prefix=lzcapis",
232
- // "--fs-root=/lzcapp/documents",
233
- // ],
234
- // };
235
- // }
236
- //
237
210
  const options = {
238
211
  envs: toPair(env),
239
212
  syntax: "default",
240
213
  protect: false,
241
214
  };
242
- const output = await envsubstr(
215
+ return await envsubstr(
243
216
  yaml.dump(template, {
244
217
  styles: {
245
218
  "!!null": "empty", // dump null as ""
@@ -247,7 +220,23 @@ async function createTemplateFile(templateFile, outputFile, env) {
247
220
  }),
248
221
  { options }
249
222
  );
223
+ }
224
+
225
+ async function createTemplateFile(templateFile, outputFile, env) {
226
+ let output = await envTemplateFile(templateFile, env);
227
+ fs.writeFileSync(outputFile, output);
228
+ }
250
229
 
230
+ async function createTemplateFileCommon(templateFile, outputFile, env) {
231
+ const template = yaml.load(fs.readFileSync(templateFile, "utf8"));
232
+ const options = {
233
+ envs: toPair(env),
234
+ syntax: "default",
235
+ protect: false,
236
+ };
237
+ const output = await envsubstr(fs.readFileSync(templateFile, "utf-8"), {
238
+ options,
239
+ });
251
240
  fs.writeFileSync(outputFile, output);
252
241
  }
253
242
 
@@ -262,7 +251,7 @@ async function copyDotAppDir(from, to, opts = {}) {
262
251
  if (fs.existsSync(to)) {
263
252
  fs.rmSync(to, { recursive: true });
264
253
  }
265
- const _files = await glob(["*"].concat(include), {
254
+ const _files = await glob(["**"].concat(include), {
266
255
  cwd: from,
267
256
  dot: true,
268
257
  ignore: ignore,
@@ -289,6 +278,22 @@ async function copyDotAppDir(from, to, opts = {}) {
289
278
  }
290
279
  }
291
280
 
281
+ function mergeYamlInMemory(args) {
282
+ if (args.length == 0) {
283
+ return {};
284
+ } else if (args.length == 1) {
285
+ return args[0];
286
+ }
287
+ return args.reduce((prev, curr) => {
288
+ let result = mergeWith(prev, curr, (objValue, srcValue) => {
289
+ if (isArray(objValue)) {
290
+ return objValue.concat(srcValue);
291
+ }
292
+ });
293
+ return result;
294
+ }, {});
295
+ }
296
+
292
297
  // override yaml, notice this will change target file
293
298
  function mergeYaml(target, source) {
294
299
  const targetContent = yaml.load(fs.readFileSync(target, "utf8"));
@@ -302,15 +307,7 @@ function mergeYaml(target, source) {
302
307
  }
303
308
  }
304
309
  );
305
-
306
- fs.writeFileSync(
307
- target,
308
- yaml.dump(merged, {
309
- styles: {
310
- "!!null": "empty", // dump null as ""
311
- },
312
- })
313
- );
310
+ dumpToYaml(merged, target);
314
311
  }
315
312
 
316
313
  function archiveFolder(appDir, format = "zip") {
@@ -393,6 +390,14 @@ function isDirSync(path) {
393
390
  return stat.isDirectory();
394
391
  }
395
392
 
393
+ function isDirExist(path) {
394
+ try {
395
+ return isDirSync(path);
396
+ } catch {
397
+ return false;
398
+ }
399
+ }
400
+
396
401
  function isFileExist(path) {
397
402
  try {
398
403
  fs.accessSync(
@@ -416,6 +421,18 @@ function parse2CorrectName(name) {
416
421
  return name.replaceAll(" ", "-").toLowerCase();
417
422
  }
418
423
 
424
+ async function sleep(ms) {
425
+ return new Promise((resolve) => {
426
+ setTimeout(resolve, ms);
427
+ });
428
+ }
429
+
430
+ async function md5String(str) {
431
+ const hash = createHash("md5");
432
+ hash.update(str);
433
+ return hash.digest("hex");
434
+ }
435
+
419
436
  export {
420
437
  ensureDir,
421
438
  copyDotAppDir,
@@ -424,6 +441,7 @@ export {
424
441
  findAppRootPath,
425
442
  archiveFolder,
426
443
  mergeYaml,
444
+ mergeYamlInMemory,
427
445
  loadFromYaml,
428
446
  dumpToYaml,
429
447
  importDefault,
@@ -434,6 +452,7 @@ export {
434
452
  toPair,
435
453
  contextDirname,
436
454
  isDirSync,
455
+ isDirExist,
437
456
  GitIgnore,
438
457
  isFileExist,
439
458
  urlHostname,
@@ -441,6 +460,10 @@ export {
441
460
  findAppIsInstalled,
442
461
  getInstalledApps,
443
462
  checkSDKInstallStatus,
463
+ envTemplateFile,
444
464
  createTemplateFile,
445
465
  parse2CorrectName,
466
+ sleep,
467
+ md5String,
468
+ createTemplateFileCommon
446
469
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazycatcloud/lzc-cli",
3
- "version": "1.1.3",
3
+ "version": "1.1.6",
4
4
  "description": "lazycat cloud developer kit",
5
5
  "scripts": {
6
6
  "test": "mocha",
@@ -14,7 +14,8 @@
14
14
  "files": [
15
15
  "template",
16
16
  "scripts",
17
- "lib"
17
+ "lib",
18
+ "cmds"
18
19
  ],
19
20
  "bin": {
20
21
  "lzc-cli": "./scripts/cli.js"
@@ -30,8 +31,7 @@
30
31
  "archiver": "^5.3.0",
31
32
  "chalk": "^4.1.2",
32
33
  "chokidar": "^3.5.3",
33
- "commander": "^8.3.0",
34
- "commander-completion": "^1.0.1",
34
+ "command-exists": "^1.2.9",
35
35
  "dockerfile-ast": "^0.4.1",
36
36
  "dockerode": "^3.3.1",
37
37
  "ejs": "^3.1.6",
@@ -48,18 +48,25 @@
48
48
  "lodash.merge": "^4.6.2",
49
49
  "lodash.mergewith": "^4.6.2",
50
50
  "log-update": "^5.0.0",
51
- "lz4": "^0.6.5",
51
+ "loglevel": "^1.8.0",
52
52
  "minimist": "^1.2.5",
53
53
  "node-fetch": "^2.6.6",
54
54
  "node-stream-zip": "^1.15.0",
55
55
  "ora": "^6.0.1",
56
56
  "semver": "^7.3.5",
57
57
  "ssh2": "^1.5.0",
58
- "ssh2-promise": "^1.0.2"
58
+ "ssh2-promise": "^1.0.2",
59
+ "tar": "^6.1.11",
60
+ "yargs": "^17.5.1"
59
61
  },
60
62
  "devDependencies": {
63
+ "@types/command-exists": "^1.2.0",
61
64
  "chai": "^4.3.6",
62
65
  "mocha": "^9.2.2",
63
66
  "prettier": "^2.5.0"
67
+ },
68
+ "publishConfig": {
69
+ "registry": "https://registry.npmjs.org",
70
+ "access": "public"
64
71
  }
65
72
  }