@rainbow-robotics/muscat-plugin-kit 0.1.2-dev.13 → 0.1.2-dev.14
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/cli/src/esbuild.mjs +1 -0
- package/cli/src/update.mjs +148 -30
- package/package.json +3 -3
package/cli/src/esbuild.mjs
CHANGED
package/cli/src/update.mjs
CHANGED
|
@@ -1,52 +1,170 @@
|
|
|
1
|
-
// muscat-pk update — update the
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
// muscat-pk update — update the CLI itself AND the plugin project's JS deps.
|
|
2
|
+
//
|
|
3
|
+
// Three install modes are handled:
|
|
4
|
+
// binary : Bun self-contained binary downloaded from S3
|
|
5
|
+
// → re-download from S3, replace process.execPath
|
|
6
|
+
// npm -g : globally installed Node.js package
|
|
7
|
+
// → npm install -g @rainbow-robotics/muscat-plugin-kit@<tag>
|
|
8
|
+
// local : plugin project's node_modules (fallback)
|
|
9
|
+
// → <pm> add @rainbow-robotics/muscat-plugin-kit@<tag>
|
|
10
|
+
//
|
|
11
|
+
// After updating the CLI itself, also bumps the plugin project's local deps.
|
|
12
|
+
import { execSync, spawn } from "node:child_process";
|
|
13
|
+
import { chmodSync, copyFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { tmpdir } from "node:os";
|
|
15
|
+
import { join, resolve } from "node:path";
|
|
16
|
+
import { findPluginRoot, KIT_PUBLISHED_NAME, kitVersion, log, parseArgs } from "./util.mjs";
|
|
6
17
|
|
|
7
18
|
const PLUGIN_UI_PACKAGE = "@rainbow-robotics/plugin-ui";
|
|
19
|
+
const S3_BASE = "https://rainbow-deploy.s3.ap-northeast-2.amazonaws.com/muscat-plugin-kit";
|
|
20
|
+
|
|
21
|
+
const isBinaryMode = typeof Bun !== "undefined";
|
|
22
|
+
|
|
23
|
+
// ── helpers ───────────────────────────────────────────────────────────────────
|
|
8
24
|
|
|
9
25
|
function detectPm(root) {
|
|
10
26
|
try {
|
|
11
27
|
const pkg = JSON.parse(readFileSync(resolve(root, "package.json"), "utf8"));
|
|
12
28
|
if (pkg.packageManager) return pkg.packageManager.split("@")[0];
|
|
13
|
-
} catch {
|
|
14
|
-
/* ignore */
|
|
15
|
-
}
|
|
29
|
+
} catch { /* ignore */ }
|
|
16
30
|
if (existsSync(resolve(root, "pnpm-lock.yaml"))) return "pnpm";
|
|
17
31
|
if (existsSync(resolve(root, "yarn.lock"))) return "yarn";
|
|
18
32
|
if (existsSync(resolve(root, "bun.lockb"))) return "bun";
|
|
19
33
|
return "npm";
|
|
20
34
|
}
|
|
21
35
|
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
36
|
+
async function fetchText(url) {
|
|
37
|
+
const res = await fetch(url);
|
|
38
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}: ${url}`);
|
|
39
|
+
return (await res.text()).trim();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function fetchBinary(url) {
|
|
43
|
+
const res = await fetch(url);
|
|
44
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}: ${url}`);
|
|
45
|
+
return Buffer.from(await res.arrayBuffer());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function s3BinaryName() {
|
|
49
|
+
const platform = process.platform;
|
|
50
|
+
const arch = process.arch;
|
|
51
|
+
const plat = platform === "win32" ? "win" : platform === "darwin" ? "darwin" : "linux";
|
|
52
|
+
const cpu = arch === "arm64" ? "arm64" : "x64";
|
|
53
|
+
const ext = platform === "win32" ? ".exe" : "";
|
|
54
|
+
return `muscat-pk-${plat}-${cpu}${ext}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function resolveS3Version(tag) {
|
|
58
|
+
const pointer = tag === "dev" ? "dev-version.txt" : "latest-version.txt";
|
|
59
|
+
return fetchText(`${S3_BASE}/${pointer}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ── self-update: binary ───────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
async function updateBinary(tag) {
|
|
65
|
+
const version = await resolveS3Version(tag);
|
|
66
|
+
const current = kitVersion();
|
|
67
|
+
if (version === current) {
|
|
68
|
+
log.ok(`이미 최신 버전입니다 (v${current})`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const binaryName = s3BinaryName();
|
|
73
|
+
const url = `${S3_BASE}/v${version}/${binaryName}`;
|
|
74
|
+
log.step(`바이너리 다운로드: v${current} → v${version}`);
|
|
75
|
+
|
|
76
|
+
const data = await fetchBinary(url);
|
|
77
|
+
const execPath = process.execPath;
|
|
78
|
+
|
|
79
|
+
if (process.platform === "win32") {
|
|
80
|
+
// Windows: cannot overwrite a running .exe — write .new then schedule replacement
|
|
81
|
+
const newPath = execPath + ".new";
|
|
82
|
+
writeFileSync(newPath, data);
|
|
26
83
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const list = [
|
|
34
|
-
`${KIT_PUBLISHED_NAME}@${range}`,
|
|
35
|
-
`${PLUGIN_UI_PACKAGE}@${range}`,
|
|
36
|
-
];
|
|
84
|
+
// PowerShell snippet that waits for this process to exit, then renames
|
|
85
|
+
const ps = `Start-Sleep -Milliseconds 500; Move-Item -Force '${newPath}' '${execPath}'`;
|
|
86
|
+
spawn("powershell", ["-NoProfile", "-Command", ps], {
|
|
87
|
+
detached: true,
|
|
88
|
+
stdio: "ignore",
|
|
89
|
+
}).unref();
|
|
37
90
|
|
|
91
|
+
log.ok(`v${version} 다운로드 완료. 다음 실행 시 자동 적용됩니다.`);
|
|
92
|
+
} else {
|
|
93
|
+
// macOS / Linux: can replace the file while it's mapped into memory
|
|
94
|
+
const tmp = join(tmpdir(), `muscat-pk-${version}`);
|
|
95
|
+
writeFileSync(tmp, data);
|
|
96
|
+
chmodSync(tmp, 0o755);
|
|
97
|
+
copyFileSync(tmp, execPath);
|
|
98
|
+
log.ok(`v${version} 업데이트 완료.`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ── self-update: npm global ───────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
function updateNpmGlobal(tag) {
|
|
105
|
+
log.step(`npm install -g ${KIT_PUBLISHED_NAME}@${tag}`);
|
|
106
|
+
execSync(`npm install -g ${KIT_PUBLISHED_NAME}@${tag}`, { stdio: "inherit" });
|
|
107
|
+
log.ok("글로벌 CLI 업데이트 완료.");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ── plugin project local deps ─────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
function updateLocalDeps(root, tag) {
|
|
113
|
+
const pm = detectPm(root);
|
|
114
|
+
const list = [`${KIT_PUBLISHED_NAME}@${tag}`, `${PLUGIN_UI_PACKAGE}@${tag}`];
|
|
38
115
|
const cmd =
|
|
39
|
-
pm === "npm"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
? `yarn add ${list.join(" ")}`
|
|
43
|
-
: `${pm} add ${list.join(" ")}`;
|
|
116
|
+
pm === "npm" ? `npm install ${list.join(" ")}`
|
|
117
|
+
: pm === "yarn" ? `yarn add ${list.join(" ")}`
|
|
118
|
+
: `${pm} add ${list.join(" ")}`;
|
|
44
119
|
|
|
45
|
-
log.step(
|
|
120
|
+
log.step(`플러그인 로컬 deps 업데이트 (${pm}): ${list.join(", ")}`);
|
|
46
121
|
try {
|
|
47
122
|
execSync(cmd, { cwd: root, stdio: "inherit" });
|
|
48
|
-
log.ok("
|
|
123
|
+
log.ok("로컬 deps 업데이트 완료.");
|
|
124
|
+
} catch {
|
|
125
|
+
log.warn("로컬 deps 업데이트 실패 (오프라인?). 수동 실행:\n " + cmd);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ── main ─────────────────────────────────────────────────────────────────────
|
|
130
|
+
|
|
131
|
+
export async function runUpdate(args = []) {
|
|
132
|
+
const opts = parseArgs(args);
|
|
133
|
+
const tag = opts._[0] || opts.version || opts.tag || "latest";
|
|
134
|
+
|
|
135
|
+
// 1. Update the CLI itself
|
|
136
|
+
if (isBinaryMode) {
|
|
137
|
+
log.step("바이너리 자기 업데이트 중…");
|
|
138
|
+
try {
|
|
139
|
+
await updateBinary(tag);
|
|
140
|
+
} catch (err) {
|
|
141
|
+
log.warn(`바이너리 업데이트 실패: ${err.message}`);
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
// Check if globally installed via npm (execPath's npm prefix contains this package)
|
|
145
|
+
const isGlobal = (() => {
|
|
146
|
+
try {
|
|
147
|
+
const prefix = execSync("npm prefix -g", { encoding: "utf8" }).trim();
|
|
148
|
+
const globalBin = join(prefix, "bin", "muscat-pk");
|
|
149
|
+
const globalBinCmd = join(prefix, "bin", "muscat-pk.cmd");
|
|
150
|
+
return existsSync(globalBin) || existsSync(globalBinCmd);
|
|
151
|
+
} catch { return false; }
|
|
152
|
+
})();
|
|
153
|
+
|
|
154
|
+
if (isGlobal) {
|
|
155
|
+
try {
|
|
156
|
+
updateNpmGlobal(tag);
|
|
157
|
+
} catch (err) {
|
|
158
|
+
log.warn(`글로벌 CLI 업데이트 실패: ${err.message}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 2. Update the plugin project's local deps (best-effort)
|
|
164
|
+
try {
|
|
165
|
+
const root = findPluginRoot();
|
|
166
|
+
updateLocalDeps(root, tag);
|
|
49
167
|
} catch {
|
|
50
|
-
|
|
168
|
+
// Not inside a plugin project — skip local update silently
|
|
51
169
|
}
|
|
52
170
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rainbow-robotics/muscat-plugin-kit",
|
|
3
|
-
"version": "0.1.2-dev.
|
|
3
|
+
"version": "0.1.2-dev.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20"
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"@types/react-dom": "^19.0.4"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@rainbow-robotics/preview-host": "
|
|
34
|
+
"@rainbow-robotics/preview-host": "workspace:*",
|
|
35
35
|
"socket.io": "^4.8.1"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
38
|
"esbuild-wasm": "^0.25.0"
|
|
39
39
|
}
|
|
40
|
-
}
|
|
40
|
+
}
|