@lazycatcloud/lzc-cli 1.3.14 → 2.0.0-pre.0

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 (101) hide show
  1. package/README.md +30 -5
  2. package/changelog.md +4 -0
  3. package/lib/app/index.js +174 -58
  4. package/lib/app/lpk_build.js +192 -17
  5. package/lib/app/lpk_build_images.js +728 -0
  6. package/lib/app/lpk_create.js +93 -21
  7. package/lib/app/lpk_create_generator.js +144 -9
  8. package/lib/app/lpk_devshell.js +33 -19
  9. package/lib/app/lpk_embed_images.js +257 -0
  10. package/lib/app/lpk_installer.js +14 -7
  11. package/lib/app/project_cp.js +64 -0
  12. package/lib/app/project_deploy.js +33 -0
  13. package/lib/app/project_exec.js +45 -0
  14. package/lib/app/project_info.js +106 -0
  15. package/lib/app/project_log.js +67 -0
  16. package/lib/app/project_runtime.js +261 -0
  17. package/lib/app/project_start.js +100 -0
  18. package/lib/box/index.js +101 -4
  19. package/lib/box/ssh_remote.js +259 -0
  20. package/lib/build_remote.js +22 -0
  21. package/lib/config/index.js +1 -1
  22. package/lib/debug_bridge.js +837 -46
  23. package/lib/docker/index.js +30 -10
  24. package/lib/i18n/index.js +1 -0
  25. package/lib/i18n/locales/en/translation.json +17 -5
  26. package/lib/i18n/locales/zh/translation.json +16 -4
  27. package/lib/lpk/core.js +487 -0
  28. package/lib/lpk/index.js +210 -0
  29. package/lib/sig/core.js +254 -0
  30. package/lib/sig/index.js +88 -0
  31. package/lib/utils.js +3 -1
  32. package/package.json +2 -1
  33. package/scripts/cli.js +4 -0
  34. package/template/_lpk/README.md +11 -3
  35. package/template/_lpk/gui-vnc.manifest.yml.in +27 -0
  36. package/template/_lpk/manifest.yml.in +4 -2
  37. package/template/_lpk/todolist-golang.manifest.yml.in +16 -0
  38. package/template/_lpk/todolist-java.manifest.yml.in +15 -0
  39. package/template/_lpk/todolist-python.manifest.yml.in +15 -0
  40. package/template/_lpk/vue.lzc-build.yml.in +0 -44
  41. package/template/blank/_gitignore +1 -0
  42. package/template/blank/lzc-build.yml +25 -40
  43. package/template/blank/lzc-manifest.yml +14 -7
  44. package/template/golang/Dockerfile +19 -0
  45. package/template/golang/README.md +33 -0
  46. package/template/golang/_gitignore +3 -0
  47. package/template/golang/go.mod +3 -0
  48. package/template/golang/lzc-build.yml +21 -0
  49. package/template/golang/lzc-icon.png +0 -0
  50. package/template/golang/main.go +252 -0
  51. package/template/golang/run.sh +3 -0
  52. package/template/golang/web/index.html +238 -0
  53. package/template/gui-vnc/README.md +19 -0
  54. package/template/gui-vnc/_gitignore +2 -0
  55. package/template/gui-vnc/images/Dockerfile +30 -0
  56. package/template/gui-vnc/images/kasmvnc.yaml +33 -0
  57. package/template/gui-vnc/images/startup-script.desktop +9 -0
  58. package/template/gui-vnc/images/startup-script.sh +6 -0
  59. package/template/gui-vnc/lzc-build.yml +23 -0
  60. package/template/gui-vnc/lzc-icon.png +0 -0
  61. package/template/python/Dockerfile +15 -0
  62. package/template/python/README.md +33 -0
  63. package/template/python/_gitignore +3 -0
  64. package/template/python/app.py +110 -0
  65. package/template/python/lzc-build.yml +21 -0
  66. package/template/python/lzc-icon.png +0 -0
  67. package/template/python/requirements.txt +1 -0
  68. package/template/python/run.sh +3 -0
  69. package/template/python/web/index.html +238 -0
  70. package/template/springboot/Dockerfile +20 -0
  71. package/template/springboot/README.md +33 -0
  72. package/template/springboot/_gitignore +3 -0
  73. package/template/springboot/lzc-build.yml +21 -0
  74. package/template/springboot/lzc-icon.png +0 -0
  75. package/template/springboot/pom.xml +38 -0
  76. package/template/springboot/run.sh +3 -0
  77. package/template/springboot/src/main/java/cloud/lazycat/app/Application.java +132 -0
  78. package/template/springboot/src/main/resources/application.properties +1 -0
  79. package/template/springboot/src/main/resources/static/index.html +238 -0
  80. package/template/vue/README.md +17 -7
  81. package/template/vue/_gitignore +1 -0
  82. package/template/vue/lzc-build.yml +31 -42
  83. package/template/vue/src/App.vue +36 -25
  84. package/template/vue/src/style.css +106 -49
  85. package/template/vue-minidb/README.md +34 -0
  86. package/template/vue-minidb/_gitignore +26 -0
  87. package/template/vue-minidb/index.html +13 -0
  88. package/template/vue-minidb/lzc-build.yml +48 -0
  89. package/template/vue-minidb/lzc-icon.png +0 -0
  90. package/template/vue-minidb/package.json +21 -0
  91. package/template/vue-minidb/public/vite.svg +1 -0
  92. package/template/vue-minidb/src/App.vue +206 -0
  93. package/template/vue-minidb/src/assets/vue.svg +1 -0
  94. package/template/vue-minidb/src/main.ts +5 -0
  95. package/template/vue-minidb/src/style.css +136 -0
  96. package/template/vue-minidb/src/vite-env.d.ts +1 -0
  97. package/template/vue-minidb/tsconfig.app.json +24 -0
  98. package/template/vue-minidb/tsconfig.json +7 -0
  99. package/template/vue-minidb/tsconfig.node.json +22 -0
  100. package/template/vue-minidb/vite.config.ts +10 -0
  101. /package/template/{vue → vue-minidb}/src/components/HelloWorld.vue +0 -0
@@ -0,0 +1,259 @@
1
+ import env from '../config/env.js';
2
+
3
+ const SSH_BOXES_KEY = 'ssh_boxes';
4
+ const SSH_DEFAULT_BOX_KEY = 'default_ssh_box';
5
+ const DEFAULT_SSH_PORT = 22;
6
+
7
+ function parsePort(rawPort, source) {
8
+ if (rawPort === undefined || rawPort === null || rawPort === '') {
9
+ return DEFAULT_SSH_PORT;
10
+ }
11
+ const port = Number.parseInt(String(rawPort), 10);
12
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
13
+ throw new Error(`Invalid ssh port in ${source}: ${rawPort}`);
14
+ }
15
+ return port;
16
+ }
17
+
18
+ function normalizeLoginUser(loginUser) {
19
+ const user = String(loginUser ?? '').trim();
20
+ if (!user) {
21
+ throw new Error('loginUser is required');
22
+ }
23
+ return user;
24
+ }
25
+
26
+ function parseAddress(address) {
27
+ const value = String(address ?? '').trim();
28
+ if (!value) {
29
+ throw new Error('address is required');
30
+ }
31
+
32
+ if (value.startsWith('[')) {
33
+ const end = value.indexOf(']');
34
+ if (end <= 1) {
35
+ throw new Error(`Invalid address: ${address}`);
36
+ }
37
+ const host = value.slice(1, end).trim();
38
+ if (!host) {
39
+ throw new Error(`Invalid address: ${address}`);
40
+ }
41
+ const suffix = value.slice(end + 1).trim();
42
+ if (!suffix) {
43
+ return { sshHost: host, sshPort: DEFAULT_SSH_PORT };
44
+ }
45
+ if (!suffix.startsWith(':')) {
46
+ throw new Error(`Invalid address: ${address}`);
47
+ }
48
+ return { sshHost: host, sshPort: parsePort(suffix.slice(1), `address ${address}`) };
49
+ }
50
+
51
+ const colonCount = (value.match(/:/g) ?? []).length;
52
+ if (colonCount === 1) {
53
+ const splitIndex = value.lastIndexOf(':');
54
+ const host = value.slice(0, splitIndex).trim();
55
+ const port = value.slice(splitIndex + 1).trim();
56
+ if (!host) {
57
+ throw new Error(`Invalid address: ${address}`);
58
+ }
59
+ return { sshHost: host, sshPort: parsePort(port, `address ${address}`) };
60
+ }
61
+
62
+ if (colonCount > 1) {
63
+ return { sshHost: value, sshPort: DEFAULT_SSH_PORT };
64
+ }
65
+
66
+ return { sshHost: value, sshPort: DEFAULT_SSH_PORT };
67
+ }
68
+
69
+ function toBoxName(sshHost, sshPort) {
70
+ if (sshPort === DEFAULT_SSH_PORT) {
71
+ return sshHost;
72
+ }
73
+ return `${sshHost}:${sshPort}`;
74
+ }
75
+
76
+ function normalizeStoredBox(rawBox) {
77
+ if (!rawBox || typeof rawBox !== 'object') {
78
+ return null;
79
+ }
80
+ const loginUser = String(rawBox.login_user ?? '').trim();
81
+ const sshHost = String(rawBox.ssh_host ?? '').trim();
82
+ let sshPort;
83
+ try {
84
+ sshPort = parsePort(rawBox.ssh_port, 'saved ssh box');
85
+ } catch {
86
+ return null;
87
+ }
88
+ const boxName = String(rawBox.box_name ?? '').trim() || toBoxName(sshHost, sshPort);
89
+ if (!loginUser || !sshHost || !boxName) {
90
+ return null;
91
+ }
92
+ return {
93
+ box_name: boxName,
94
+ login_user: loginUser,
95
+ ssh_host: sshHost,
96
+ ssh_port: sshPort,
97
+ };
98
+ }
99
+
100
+ function readStoredBoxes() {
101
+ const rawBoxes = env.get(SSH_BOXES_KEY);
102
+ if (!Array.isArray(rawBoxes)) {
103
+ return [];
104
+ }
105
+ const result = [];
106
+ const indexByName = new Map();
107
+ for (const rawBox of rawBoxes) {
108
+ const box = normalizeStoredBox(rawBox);
109
+ if (!box) {
110
+ continue;
111
+ }
112
+ if (indexByName.has(box.box_name)) {
113
+ const index = indexByName.get(box.box_name);
114
+ result[index] = box;
115
+ continue;
116
+ }
117
+ indexByName.set(box.box_name, result.length);
118
+ result.push(box);
119
+ }
120
+ return result;
121
+ }
122
+
123
+ function saveStoredBoxes(boxes) {
124
+ env.set({
125
+ [SSH_BOXES_KEY]: boxes,
126
+ });
127
+ }
128
+
129
+ function readDefaultBoxName() {
130
+ return String(env.get(SSH_DEFAULT_BOX_KEY) ?? '').trim();
131
+ }
132
+
133
+ function saveDefaultBoxName(boxname) {
134
+ const name = String(boxname ?? '').trim();
135
+ if (!name) {
136
+ env.del(SSH_DEFAULT_BOX_KEY);
137
+ return;
138
+ }
139
+ env.set({
140
+ [SSH_DEFAULT_BOX_KEY]: name,
141
+ });
142
+ }
143
+
144
+ function resolveDefaultBoxName(storedBoxes) {
145
+ const currentDefault = readDefaultBoxName();
146
+ if (currentDefault && storedBoxes.some((item) => item.box_name === currentDefault)) {
147
+ return currentDefault;
148
+ }
149
+ return '';
150
+ }
151
+
152
+ function toPublicBox(stored, defaultName) {
153
+ const sshTarget = `${stored.login_user}@${stored.ssh_host}`;
154
+ return {
155
+ id: `ssh:${stored.box_name}`,
156
+ box_name: stored.box_name,
157
+ status: 'ssh',
158
+ login_user: stored.login_user,
159
+ is_admin_login: true,
160
+ is_default_box: stored.box_name === defaultName,
161
+ box_type: 'ssh',
162
+ ssh_host: stored.ssh_host,
163
+ ssh_port: stored.ssh_port,
164
+ ssh_target: sshTarget,
165
+ };
166
+ }
167
+
168
+ function toBuildRemote(box) {
169
+ return {
170
+ mode: 'build-remote',
171
+ source: `box:ssh:${box.box_name}`,
172
+ boxname: box.box_name,
173
+ sshUser: box.login_user,
174
+ sshHost: box.ssh_host,
175
+ sshPort: box.ssh_port,
176
+ sshTarget: box.ssh_target,
177
+ };
178
+ }
179
+
180
+ export function listSSHBoxes() {
181
+ const storedBoxes = readStoredBoxes();
182
+ const defaultName = resolveDefaultBoxName(storedBoxes);
183
+ return storedBoxes.map((item) => toPublicBox(item, defaultName));
184
+ }
185
+
186
+ export function addSSHBox(loginUser, address) {
187
+ const sshUser = normalizeLoginUser(loginUser);
188
+ const { sshHost, sshPort } = parseAddress(address);
189
+ const boxName = toBoxName(sshHost, sshPort);
190
+ const nextBox = normalizeStoredBox({
191
+ box_name: boxName,
192
+ login_user: sshUser,
193
+ ssh_host: sshHost,
194
+ ssh_port: sshPort,
195
+ });
196
+ if (!nextBox) {
197
+ throw new Error(`Invalid ssh box config: ${loginUser}@${address}`);
198
+ }
199
+
200
+ const savedBoxes = readStoredBoxes().filter((item) => item.box_name !== boxName);
201
+ savedBoxes.push(nextBox);
202
+ saveStoredBoxes(savedBoxes);
203
+ saveDefaultBoxName(boxName);
204
+
205
+ return toPublicBox(nextBox, boxName);
206
+ }
207
+
208
+ export function saveBuildRemoteBySSH(loginUser, address) {
209
+ return addSSHBox(loginUser, address);
210
+ }
211
+
212
+ export function getDefaultSSHBox() {
213
+ const boxes = listSSHBoxes();
214
+ const selected = boxes.find((item) => item.is_default_box);
215
+ return selected ?? null;
216
+ }
217
+
218
+ export function setDefaultSSHBox(boxname) {
219
+ const target = String(boxname ?? '').trim();
220
+ if (!target) {
221
+ throw new Error('boxname is required');
222
+ }
223
+ const exists = listSSHBoxes().some((item) => item.box_name === target);
224
+ if (!exists) {
225
+ throw new Error(`SSH box not found: ${target}`);
226
+ }
227
+ saveDefaultBoxName(target);
228
+ }
229
+
230
+ export function clearDefaultSSHBox() {
231
+ saveDefaultBoxName('');
232
+ }
233
+
234
+ export function removeSSHBox(boxname) {
235
+ const target = String(boxname ?? '').trim();
236
+ if (!target) {
237
+ throw new Error('boxname is required');
238
+ }
239
+ const storedBoxes = readStoredBoxes();
240
+ const exists = storedBoxes.some((item) => item.box_name === target);
241
+ if (!exists) {
242
+ return false;
243
+ }
244
+
245
+ const nextBoxes = storedBoxes.filter((item) => item.box_name !== target);
246
+ saveStoredBoxes(nextBoxes);
247
+ if (readDefaultBoxName() === target) {
248
+ saveDefaultBoxName('');
249
+ }
250
+ return true;
251
+ }
252
+
253
+ export function loadBuildRemoteFromConfig() {
254
+ const box = getDefaultSSHBox();
255
+ if (!box) {
256
+ return null;
257
+ }
258
+ return toBuildRemote(box);
259
+ }
@@ -0,0 +1,22 @@
1
+ import { loadBuildRemoteFromConfig } from './box/ssh_remote.js';
2
+
3
+ export const DEFAULT_BUILD_CONFIG_FILE = 'lzc-build.yml';
4
+ export const DEFAULT_BUILD_BASE_FILE = 'lzc-build.base.yml';
5
+
6
+ export function resolveBuildRemoteFromOptions(options, source = DEFAULT_BUILD_CONFIG_FILE) {
7
+ void options;
8
+ void source;
9
+ return loadBuildRemoteFromConfig();
10
+ }
11
+
12
+ export function resolveBuildRemoteFromFile(startDir = process.cwd(), buildConfigFile = DEFAULT_BUILD_CONFIG_FILE) {
13
+ void startDir;
14
+ void buildConfigFile;
15
+ return loadBuildRemoteFromConfig();
16
+ }
17
+
18
+ export function hasBuildRemote(startDir = process.cwd(), buildConfigFile = DEFAULT_BUILD_CONFIG_FILE) {
19
+ void startDir;
20
+ void buildConfigFile;
21
+ return !!loadBuildRemoteFromConfig();
22
+ }
@@ -51,7 +51,7 @@ export function configCommand(program) {
51
51
  ];
52
52
  program.command({
53
53
  command: 'config',
54
- desc: t('lzc_cli.lib.config.index.config_cmd_desc', '配置管理'),
54
+ desc: false,
55
55
  builder: (args) => {
56
56
  args.command(subCommands);
57
57
  args.example('$0 config get', t('lzc_cli.lib.config.index.config_cmd_list_tips', '列出所有配置'))