comp-hub 0.27.19 → 0.28.1

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 (125) hide show
  1. package/README.md +71 -86
  2. package/bin/cli.js +42 -76
  3. package/bin/lib/commands.js +147 -0
  4. package/bin/lib/constants.js +22 -0
  5. package/bin/lib/http.js +62 -0
  6. package/bin/lib/startup.js +183 -0
  7. package/bin/lib/utils.js +80 -0
  8. package/dist/index.js +16 -16
  9. package/dist/master.js +403 -0
  10. package/dist/website/container/assets/{index-CdaB9oWd.js → index-BTW7AmWY.js} +9 -9
  11. package/dist/website/container/assets/index-DqV5-Zk-.css +1 -0
  12. package/dist/website/container/index.html +31 -34
  13. package/dist/website/container/js/vue2-sfc-loader.js +1 -1
  14. package/dist/website/container/js/vue3-sfc-loader.js +1 -1
  15. package/dist/website/item/assets/index-DNn8L2ik.css +1 -0
  16. package/dist/website/item/assets/index-eJgZiYQR.js +40 -0
  17. package/dist/website/item/index.html +28 -30
  18. package/dist/website/main/assets/{AuthCodeSendBtn.vue_vue_type_script_setup_true_lang-CfufrKbA.js → AuthCodeSendBtn.vue_vue_type_script_setup_true_lang-C2LcEFL4.js} +1 -1
  19. package/dist/website/main/assets/{BaseDialog.vue_vue_type_script_setup_true_lang-B6WkXWm7.js → BaseDialog.vue_vue_type_script_setup_true_lang-CgV6_zzd.js} +1 -1
  20. package/dist/website/main/assets/BaseSegmented.vue_vue_type_script_setup_true_lang-CW16Y3Jx.js +1 -0
  21. package/dist/website/main/assets/{CanvasAnimation.vue_vue_type_script_setup_true_lang-BwtYEYU5.js → CanvasAnimation.vue_vue_type_script_setup_true_lang-BVY2XxV8.js} +1 -1
  22. package/dist/website/main/assets/{EmptyStatusContainer.vue_vue_type_script_setup_true_lang-DIgE9MGd.js → EmptyStatusContainer.vue_vue_type_script_setup_true_lang-CofI0Rvq.js} +1 -1
  23. package/dist/website/main/assets/{LoadingWrapper.vue_vue_type_script_setup_true_lang-5GxduB08.js → LoadingWrapper.vue_vue_type_script_setup_true_lang-bBtkKtmz.js} +1 -1
  24. package/dist/website/main/assets/{PanelBackground.vue_vue_type_script_setup_true_lang-CM6wkI5V.js → PanelBackground.vue_vue_type_script_setup_true_lang-DBIlZFl0.js} +1 -1
  25. package/dist/website/main/assets/{cloud-upload-CyIQfnxU.js → cloud-upload-BRjLuSi4.js} +1 -1
  26. package/dist/website/main/assets/{core-DE5-zGKf.js → core-B1GcTOER.js} +1 -1
  27. package/dist/website/main/assets/{el-table-column-BiqynxkD.js → el-table-column-8qfe8CVK.js} +1 -1
  28. package/dist/website/main/assets/{home-rounded-Dq-TBvLG.js → home-rounded-8qNxvN2I.js} +1 -1
  29. package/dist/website/main/assets/{index-CMvx8gm3.js → index-0Y9kW7YJ.js} +1 -1
  30. package/dist/website/main/assets/index-2LGHX46G.js +1 -0
  31. package/dist/website/main/assets/index-B2xvPCaB.js +1 -0
  32. package/dist/website/main/assets/{index-CGgS1tZ0.js → index-B3dAdOL_.js} +1 -1
  33. package/dist/website/main/assets/{index-Cf69_nzt.js → index-B5qe6yln.js} +15 -15
  34. package/dist/website/main/assets/index-BANn4H7f.css +1 -0
  35. package/dist/website/main/assets/{index-DvyE3TrH.js → index-ByKMTPW3.js} +2 -2
  36. package/dist/website/main/assets/index-CDnNjG3p.css +1 -0
  37. package/dist/website/main/assets/index-CEQStqDa.js +1 -0
  38. package/dist/website/main/assets/index-CP6sOfKF.css +1 -0
  39. package/dist/website/main/assets/index-Cf5sOeOs.js +1 -0
  40. package/dist/website/main/assets/index-CmSN0r9I.css +1 -0
  41. package/dist/website/main/assets/index-Cn8OtDDR.js +1 -0
  42. package/dist/website/main/assets/{index-BQWeT5qu.js → index-CoWWi7z-.js} +2 -2
  43. package/dist/website/main/assets/index-Cqi9_pkc.js +1 -0
  44. package/dist/website/main/assets/{index-vnzmxexj.js → index-CrzWpCC3.js} +1 -1
  45. package/dist/website/main/assets/index-CtzG8xUz.js +1 -0
  46. package/dist/website/main/assets/index-DANPdG90.js +1 -0
  47. package/dist/website/main/assets/index-DI0kvKsV.js +1 -0
  48. package/dist/website/main/assets/index-DJ4AvgpT.css +1 -0
  49. package/dist/website/main/assets/index-DSED2-Jv.js +1 -0
  50. package/dist/website/main/assets/index-DUr8uU-d.js +1 -0
  51. package/dist/website/main/assets/index-DW-M9dmc.js +1 -0
  52. package/dist/website/main/assets/{index-BGLjC3BV.js → index-D_jNsofk.js} +1 -1
  53. package/dist/website/main/assets/index-DffjEud2.js +1 -0
  54. package/dist/website/main/assets/{index-ctwb4cB7.js → index-DkTzdi1V.js} +1 -1
  55. package/dist/website/main/assets/index-DoTR7Juh.css +1 -0
  56. package/dist/website/main/assets/index-DxG4_1zN.js +1 -0
  57. package/dist/website/main/assets/{index-CTLlcQoM.js → index-DyEkv8OS.js} +1 -1
  58. package/dist/website/main/assets/{index-CCFHORqg.js → index-RlxCYKYM.js} +1 -1
  59. package/dist/website/main/assets/index-ZwJcoRf3.js +2 -0
  60. package/dist/website/main/assets/index-bJb3z37F.js +1 -0
  61. package/dist/website/main/assets/{index-gOTpUrNM.js → index-dC2trX5C.js} +1 -1
  62. package/dist/website/main/assets/{index-Cu1YAWdz.js → index-dhG9Kj5W.js} +1 -1
  63. package/dist/website/main/assets/{index-q4Z3Q7p4.js → index-feqY_hvF.js} +1 -1
  64. package/dist/website/main/assets/{index-cFhtMyBi.js → index-op0bdgFk.js} +2 -2
  65. package/dist/website/main/assets/index-xqKWYiCC.js +1 -0
  66. package/dist/website/main/assets/{index.vue_vue_type_script_setup_true_lang-BDhf8t5D.js → index.vue_vue_type_script_setup_true_lang-B_VrULUy.js} +1 -1
  67. package/dist/website/main/assets/index.vue_vue_type_script_setup_true_lang-D3xHCy9f.js +2 -0
  68. package/dist/website/main/assets/{index.vue_vue_type_script_setup_true_lang-B4echric.js → index.vue_vue_type_script_setup_true_lang-DCQMqfel.js} +1 -1
  69. package/dist/website/main/assets/index.vue_vue_type_script_setup_true_lang-DM_Wm4GD.js +1 -0
  70. package/dist/website/main/assets/{index.vue_vue_type_script_setup_true_lang-qhJpeu7a.js → index.vue_vue_type_script_setup_true_lang-DX9EV5b8.js} +1 -1
  71. package/dist/website/main/assets/{index.vue_vue_type_script_setup_true_lang-aO0L9Tak.js → index.vue_vue_type_script_setup_true_lang-RJnk970E.js} +1 -1
  72. package/dist/website/main/assets/index.vue_vue_type_script_setup_true_lang-rk3Yu4M8.js +1 -0
  73. package/dist/website/main/assets/{index.vue_vue_type_style_index_0_lang-C3U7f9Ma.js → index.vue_vue_type_style_index_0_lang-BQWxY2F1.js} +5 -5
  74. package/dist/website/main/assets/{index.vue_vue_type_style_index_0_lang-C4fELX8m.js → index.vue_vue_type_style_index_0_lang-DQhqVyhA.js} +1 -1
  75. package/dist/website/main/assets/{index.vue_vue_type_style_index_0_lang-D_eT-tA_.js → index.vue_vue_type_style_index_0_lang-xD-wMtaK.js} +1 -1
  76. package/dist/website/main/assets/{kid-star-CFLIpXDC.js → kid-star-Cr1NlTdT.js} +1 -1
  77. package/dist/website/main/assets/{md5-BZr8xhBN.js → md5-DzJRYP5-.js} +1 -1
  78. package/dist/website/main/assets/{settings-B3XnnICj.js → settings-BFJXTJ9K.js} +1 -1
  79. package/dist/website/main/assets/{supervised-user-circle-CEgKC7n7.js → supervised-user-circle-Bnx5icEm.js} +1 -1
  80. package/dist/website/main/assets/{sync-saved-locally-rounded-CmlRPNS9.js → sync-saved-locally-rounded-DtyOT0dw.js} +1 -1
  81. package/dist/website/main/assets/{terminal-DykiTSV6.js → terminal-D72IJB2N.js} +1 -1
  82. package/dist/website/main/assets/{useCacheOssStore-CU4a8b24.js → useCacheOssStore-DApHt9lQ.js} +1 -1
  83. package/dist/website/main/assets/{useCompEditStore-Du_-rNtX.css → useCompEditStore-B9HAj9va.css} +1 -1
  84. package/dist/website/main/assets/{useCompEditStore-B7KaUbOi.js → useCompEditStore-KBTFiinR.js} +94 -94
  85. package/dist/website/main/assets/{useCompMetaLocalStore-pb1Ikkq3.js → useCompMetaLocalStore-eE-CBcE9.js} +1 -1
  86. package/dist/website/main/assets/{useKeyword-D1qu8Tz-.js → useKeyword-CoagiMo1.js} +1 -1
  87. package/dist/website/main/assets/useMessage-CYVXvlqq.js +1 -0
  88. package/dist/website/main/assets/{useTeamHeaders-DELMIzHt.js → useTeamHeaders-Cc060CP0.js} +1 -1
  89. package/dist/website/main/assets/useVscodeOpen-Dx3IRL0P.js +1 -0
  90. package/dist/website/main/assets/{vendor-core-B-Si3WEf.js → vendor-core-CzvSW5ae.js} +3 -3
  91. package/dist/website/main/assets/{vendor-ui-D6wVBlls.js → vendor-ui-DXwyveTF.js} +12 -12
  92. package/dist/website/main/index.html +92 -92
  93. package/package.json +5 -3
  94. package/dist/website/container/assets/index-BnbvpvZL.css +0 -1
  95. package/dist/website/item/assets/index-B0s1uwsa.js +0 -39
  96. package/dist/website/item/assets/index-BIcNxYiU.css +0 -1
  97. package/dist/website/main/assets/BaseSegmented.vue_vue_type_script_setup_true_lang-D5yw_wF0.js +0 -1
  98. package/dist/website/main/assets/index-B6f_06zP.js +0 -1
  99. package/dist/website/main/assets/index-BIGvC1SM.js +0 -1
  100. package/dist/website/main/assets/index-BfPdLll-.js +0 -1
  101. package/dist/website/main/assets/index-BkUBwon5.css +0 -1
  102. package/dist/website/main/assets/index-C9t3Yhe9.js +0 -1
  103. package/dist/website/main/assets/index-CFH_ugiT.js +0 -1
  104. package/dist/website/main/assets/index-CWW1M_cy.js +0 -1
  105. package/dist/website/main/assets/index-CuHNNhtE.js +0 -1
  106. package/dist/website/main/assets/index-D6Fz5rH9.css +0 -1
  107. package/dist/website/main/assets/index-D7eOWAPr.js +0 -1
  108. package/dist/website/main/assets/index-D8WDrGkh.js +0 -1
  109. package/dist/website/main/assets/index-DBM1x91X.js +0 -1
  110. package/dist/website/main/assets/index-DC94GyXj.js +0 -1
  111. package/dist/website/main/assets/index-Dl-mwEbG.js +0 -1
  112. package/dist/website/main/assets/index-DmO0JQ56.css +0 -1
  113. package/dist/website/main/assets/index-DrUAgWBX.js +0 -1
  114. package/dist/website/main/assets/index-Oo11MKfd.js +0 -1
  115. package/dist/website/main/assets/index-YUZjR2Eq.js +0 -2
  116. package/dist/website/main/assets/index-tEU6GnSH.js +0 -1
  117. package/dist/website/main/assets/index-tWc_GbBW.css +0 -1
  118. package/dist/website/main/assets/index-uu5oSUvx.js +0 -1
  119. package/dist/website/main/assets/index-wgeiSlf-.css +0 -1
  120. package/dist/website/main/assets/index-y8GEzH-z.css +0 -1
  121. package/dist/website/main/assets/index.vue_vue_type_script_setup_true_lang-COryHg9c.js +0 -1
  122. package/dist/website/main/assets/index.vue_vue_type_script_setup_true_lang-D_7jZ1zo.js +0 -2
  123. package/dist/website/main/assets/index.vue_vue_type_script_setup_true_lang-Dtuk2wrA.js +0 -1
  124. package/dist/website/main/assets/useMessage-D7WAp245.js +0 -1
  125. package/dist/website/main/assets/useVscodeOpen-DIYbcP1e.js +0 -1
@@ -0,0 +1,183 @@
1
+ const path = require("path");
2
+ const fs = require("fs");
3
+ const { spawn } = require("child_process");
4
+ const { httpPost } = require("./http");
5
+ const { computeHash, projectRoot, readMasterRuntime, loadComphubConfig, colors, apiUrl } = require("./utils");
6
+ const { cyan, green, white, yellow, red } = colors;
7
+ const { ADMIN_API, POLL_INTERVAL, MAX_RETRIES, DEFAULT_PORT } = require("./constants");
8
+ const getPort = require("get-port");
9
+
10
+ // ---- Config ----
11
+
12
+ function mergeConfig(opts, cwd) {
13
+ // 加载项目配置文件,作为命令行参数的 fallback
14
+ const fileConfig = loadComphubConfig(cwd);
15
+ // 优先级:命令行 > 配置文件 > 默认值
16
+ return {
17
+ dir: opts.dir || fileConfig.dir || "./",
18
+ api: opts.api || fileConfig.api,
19
+ allowDebug: opts.allowDebug ?? fileConfig.allowDebug ?? false,
20
+ proxy: opts.proxy || fileConfig.proxy,
21
+ port: opts.port
22
+ };
23
+ }
24
+
25
+ // ---- Master lifecycle ----
26
+
27
+ async function waitForMasterRuntime() {
28
+ for (let i = 0; i < MAX_RETRIES; i++) {
29
+ const runtime = readMasterRuntime();
30
+ if (runtime) return runtime;
31
+ await new Promise(r => setTimeout(r, POLL_INTERVAL));
32
+ }
33
+ return null;
34
+ }
35
+
36
+ async function spawnMaster(publicPort, pkg, cwd) {
37
+ const masterEntry = path.join(projectRoot, "dist/master.js");
38
+
39
+ if (!fs.existsSync(masterEntry)) {
40
+ throw new Error("Master entry file not found, startup failed");
41
+ }
42
+
43
+ const masterArgs = ["--port", String(publicPort), "--public-port", String(publicPort)];
44
+ const child = spawn(process.execPath, [masterEntry, ...masterArgs], {
45
+ stdio: "ignore",
46
+ detached: true,
47
+ windowsHide: true,
48
+ cwd,
49
+ env: {
50
+ ...process.env,
51
+ COMP_HUB_VERSION: pkg.version
52
+ }
53
+ });
54
+
55
+ child.unref();
56
+
57
+ const runtime = await waitForMasterRuntime();
58
+ if (!runtime) {
59
+ child.kill();
60
+ throw new Error("Master startup timeout");
61
+ }
62
+
63
+ return runtime;
64
+ }
65
+
66
+ /**
67
+ * 确保 master 在运行,返回运行时信息。
68
+ * 如果已在运行则复用,否则 spawn 新的 master 进程。
69
+ */
70
+ async function ensureMasterRunning(opts, pkg) {
71
+ let portMismatch = false;
72
+ let runningPublicPort = 0;
73
+
74
+ const existingRuntime = readMasterRuntime();
75
+
76
+ if (existingRuntime) {
77
+ // Master 已在运行,检查用户指定的端口是否匹配
78
+ const expectedPort = opts.port ?? existingRuntime.publicPort;
79
+ if (opts.port != null && existingRuntime.publicPort !== expectedPort) {
80
+ portMismatch = true;
81
+ runningPublicPort = existingRuntime.publicPort;
82
+ }
83
+ return { runtime: existingRuntime, portMismatch, runningPublicPort };
84
+ }
85
+
86
+ // 启动新 master
87
+ const portHint = opts.port ?? DEFAULT_PORT;
88
+ const publicPort = await getPort({ port: getPort.makeRange(portHint, portHint + 100) });
89
+
90
+ const runtime = await spawnMaster(publicPort, pkg, process.cwd());
91
+ return { runtime, portMismatch, runningPublicPort };
92
+ }
93
+
94
+ // ---- Registration ----
95
+
96
+ async function registerProject(masterPort, hash, cwd, opts) {
97
+ const body = {
98
+ hash,
99
+ cwd,
100
+ dir: opts.dir || "./"
101
+ };
102
+ if (opts.api) body.api = opts.api;
103
+ if (opts.allowDebug) body.allowDebug = true;
104
+ if (opts.proxy) body.proxy = opts.proxy;
105
+
106
+ const res = await httpPost(apiUrl(masterPort, ADMIN_API.REGISTER), body);
107
+ if (!res.ok) {
108
+ throw new Error(res.error || "Registration failed");
109
+ }
110
+ console.log(`${green("✓")} Project registered (hash: ${hash})`);
111
+ return res;
112
+ }
113
+
114
+ // ---- Banner ----
115
+
116
+ function printBanner(pkg, cwd, hash, displayPort, opts, { portMismatch, runningPublicPort }) {
117
+ const url = `http://localhost:${displayPort}/${hash}/main/`;
118
+
119
+ const lines = [
120
+ "",
121
+ cyan(" ██████╗ ██████╗ ███╗ ███╗ ██████╗ ██╗ ██╗ ██╗ ██╗ ██████╗ "),
122
+ cyan(" ██╔════╝ ██╔═══██╗ ████╗ ████║ ██╔══██╗ ██║ ██║ ██║ ██║ ██╔══██╗"),
123
+ cyan(" ██║ ██║ ██║ ██╔████╔██║ ██████╔╝ ███████║ ██║ ██║ ██████╔╝"),
124
+ cyan(" ██║ ██║ ██║ ██║╚██╔╝██║ ██╔═══╝ ██╔══██║ ██║ ██║ ██╔══██╗"),
125
+ cyan(" ╚██████╗ ╚██████╔╝ ██║ ╚═╝ ██║ ██║ ██║ ██║ ╚██████╔╝ ██████╔╝"),
126
+ cyan(" ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ "),
127
+ "",
128
+ "",
129
+ ` ${green("Version")} ${pkg.version}`,
130
+ ` ${green("Project")} ${cwd}`,
131
+ ` ${green("Hash")} ${hash}`,
132
+ ` ${green("Port")} ${displayPort}`,
133
+ "",
134
+ ` ${yellow("URL")} ${cyan(url)}`,
135
+ "",
136
+ white(" ─────────────────────────────────────────────"),
137
+ "",
138
+ ` ${"comphub status".padEnd(30)}View all projects`,
139
+ ` ${`comphub stop ${hash}`.padEnd(30)}Stop current project`,
140
+ ` ${"comphub stop --all".padEnd(30)}Stop all projects`,
141
+ ` ${"comphub kill".padEnd(30)}Shutdown master`,
142
+ ""
143
+ ];
144
+
145
+ if (portMismatch) {
146
+ lines.push(
147
+ white(" ─────────────────────────────────────────────"),
148
+ "",
149
+ red(` ⚠ Master is already running on port ${runningPublicPort}, ignoring -p ${opts.port}`),
150
+ red(` To change port, please run comphub kill first`),
151
+ ""
152
+ );
153
+ }
154
+
155
+ console.log(lines.join("\n"));
156
+ }
157
+
158
+ // ---- Main ----
159
+
160
+ async function main(pkg, opts) {
161
+ if (!fs.existsSync(path.join(process.cwd(), "package.json"))) {
162
+ console.error(`${red("✗")} Current directory is not a Node.js project`);
163
+ process.exit(1);
164
+ }
165
+
166
+ const cwd = process.cwd();
167
+ const hash = computeHash(cwd);
168
+
169
+ opts = mergeConfig(opts, cwd);
170
+
171
+ console.log(`${green("✓")} ${pkg.name} v${pkg.version}`);
172
+
173
+ const { runtime, portMismatch, runningPublicPort } = await ensureMasterRunning(opts, pkg);
174
+
175
+ const masterPort = runtime.managementPort;
176
+ const displayPort = runtime.publicPort;
177
+
178
+ await registerProject(masterPort, hash, cwd, opts);
179
+
180
+ printBanner(pkg, cwd, hash, displayPort, opts, { portMismatch, runningPublicPort });
181
+ }
182
+
183
+ module.exports = { main };
@@ -0,0 +1,80 @@
1
+ const path = require("path");
2
+ const fs = require("fs");
3
+ const crypto = require("crypto");
4
+ const { MASTER_RUNTIME_FILE } = require("./constants");
5
+
6
+ const projectRoot = path.resolve(__dirname, "../..");
7
+
8
+ function readJson(p) {
9
+ return JSON.parse(fs.readFileSync(p, "utf8"));
10
+ }
11
+
12
+ /**
13
+ * 加载项目根目录的 .comphub.json 或 .comphub.js
14
+ * 作为命令行参数的 fallback,优先级低于 CLI 选项
15
+ */
16
+ function loadComphubConfig(cwd) {
17
+ const jsonPath = path.join(cwd, ".comphub.json");
18
+ const jsPath = path.join(cwd, ".comphub.js");
19
+
20
+ try {
21
+ if (fs.existsSync(jsonPath)) {
22
+ return readJson(jsonPath);
23
+ }
24
+ } catch {
25
+ /* corrupted json, try js */
26
+ }
27
+
28
+ try {
29
+ if (fs.existsSync(jsPath)) {
30
+ const mod = require(jsPath);
31
+ return mod.default || mod;
32
+ }
33
+ } catch {
34
+ /* ignore */
35
+ }
36
+
37
+ return {};
38
+ }
39
+
40
+ function getLocalPkgInfo() {
41
+ const pkgPath = path.join(projectRoot, "package.json");
42
+ const pkg = readJson(pkgPath);
43
+ const entry = path.join(projectRoot, pkg.main || "dist/index.js");
44
+ return { pkg, entry };
45
+ }
46
+
47
+ function computeHash(dir) {
48
+ return crypto.createHash("sha256").update(dir).digest("hex").slice(0, 8);
49
+ }
50
+
51
+ function readMasterRuntime() {
52
+ try {
53
+ if (fs.existsSync(MASTER_RUNTIME_FILE)) {
54
+ const data = JSON.parse(fs.readFileSync(MASTER_RUNTIME_FILE, "utf8"));
55
+ try {
56
+ process.kill(data.pid, 0);
57
+ return data;
58
+ } catch {
59
+ fs.unlinkSync(MASTER_RUNTIME_FILE);
60
+ }
61
+ }
62
+ } catch {
63
+ /* corrupted file */
64
+ }
65
+ return null;
66
+ }
67
+
68
+ const colors = {
69
+ cyan: s => `\x1b[36m${s}\x1b[0m`,
70
+ green: s => `\x1b[32m${s}\x1b[0m`,
71
+ white: s => `\x1b[37m${s}\x1b[0m`,
72
+ yellow: s => `\x1b[33m${s}\x1b[0m`,
73
+ red: s => `\x1b[31m${s}\x1b[0m`
74
+ };
75
+
76
+ function apiUrl(port, pathname) {
77
+ return `http://localhost:${port}${pathname}`;
78
+ }
79
+
80
+ module.exports = { getLocalPkgInfo, computeHash, projectRoot, readMasterRuntime, loadComphubConfig, colors, apiUrl };