@my-life-buddies/cli 0.17.6 → 0.18.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.
- package/README.md +19 -3
- package/dist/bin/buddy.js +52 -15
- package/dist/bin/buddy.js.map +3 -3
- package/dist/bin/core.js +477 -294
- package/dist/bin/core.js.map +4 -4
- package/dist/bin/preview.js +17 -3
- package/dist/bin/preview.js.map +2 -2
- package/dist/web/app.css +6 -3
- package/dist/web/app.js +47 -9
- package/package.json +3 -3
package/dist/web/app.css
CHANGED
|
@@ -542,11 +542,11 @@ body[data-hosted-preview] .connection-detail-body dl > div { display:grid; grid-
|
|
|
542
542
|
body[data-hosted-preview] .connection-detail-body dt { color:var(--color-muted); }
|
|
543
543
|
body[data-hosted-preview] .connection-detail-body dd { margin:0; text-align:left; overflow-wrap:anywhere; }
|
|
544
544
|
body[data-hosted-preview] .environment-note { padding:8px 0 0; margin-top:8px; border:0; border-top:1px solid var(--color-rule); }
|
|
545
|
-
body[data-hosted-preview] #connect-instructions { padding:16px 20px; border-top:1px solid var(--color-rule); background:var(--color-paper); max-height:240px; overflow:auto; }
|
|
545
|
+
body[data-hosted-preview] :is(#connect-instructions, #disconnect-result) { padding:16px 20px; border-top:1px solid var(--color-rule); background:var(--color-paper); max-height:240px; overflow:auto; }
|
|
546
546
|
body[data-hosted-preview] .command-heading { display:flex; justify-content:space-between; align-items:center; gap:16px; }
|
|
547
547
|
body[data-hosted-preview] .command-heading strong { font-size:13px; font-weight:600; }
|
|
548
|
-
body[data-hosted-preview] #connect-instructions pre { padding:12px 14px; margin:12px 0 8px; white-space:pre-wrap; overflow-wrap:anywhere; border:1px solid var(--color-rule); border-radius:8px; background:var(--color-paper-raised); line-height:1.7; font-size:12px; }
|
|
549
|
-
body[data-hosted-preview] #connect-instructions p { margin:0; color:var(--color-muted); font-size:12px; line-height:1.6; }
|
|
548
|
+
body[data-hosted-preview] :is(#connect-instructions, #disconnect-result) pre { padding:12px 14px; margin:12px 0 8px; white-space:pre-wrap; overflow-wrap:anywhere; border:1px solid var(--color-rule); border-radius:8px; background:var(--color-paper-raised); line-height:1.7; font-size:12px; }
|
|
549
|
+
body[data-hosted-preview] :is(#connect-instructions, #disconnect-result) p { margin:0; color:var(--color-muted); font-size:12px; line-height:1.6; }
|
|
550
550
|
body[data-hosted-preview] .workspace { flex:1; min-height:0; grid-template-columns:minmax(350px,1fr) clamp(380px,43%,580px); overflow:hidden; }
|
|
551
551
|
body[data-hosted-preview] .debugger { display:flex; flex-direction:column; min-height:0; overflow:hidden; background:var(--color-paper-raised); }
|
|
552
552
|
body[data-hosted-preview] .hosted-page-heading { flex:none; padding:0 20px 20px; }
|
|
@@ -719,3 +719,6 @@ body[data-hosted-preview] .pairing-panel { top:80px; }
|
|
|
719
719
|
.diagnostic-entry time { font-size:10px; }
|
|
720
720
|
.diagnostic-source { display:none; }
|
|
721
721
|
}
|
|
722
|
+
|
|
723
|
+
body[data-hosted-preview] #disconnect-message { color:var(--color-ink); font-weight:600; margin-bottom:8px; }
|
|
724
|
+
body[data-hosted-preview] #copy-stop-command { margin:8px 0; }
|
package/dist/web/app.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
const hostedBuddyId = hosted ? new URL(location.href).searchParams.get("buddyId") : "";
|
|
6
6
|
const connectionUrl = hosted ? new URL(`../api/buddies/${encodeURIComponent(hostedBuddyId)}/preview`, location.href) : undefined;
|
|
7
7
|
let connectionInstance = "", connectionReady = !hosted, connectionBusy = false, devPollBusy = false;
|
|
8
|
+
let disconnectBusy = false, connectionEpoch = 0;
|
|
8
9
|
let connectionChecked = false, connectionFailure = "", devAction = "";
|
|
9
10
|
let eventSource, eventSourceInstance = "", liveEventsActive = false, pollingInterval = 0;
|
|
10
11
|
function previewApiUrl(path) {
|
|
@@ -112,7 +113,7 @@
|
|
|
112
113
|
},
|
|
113
114
|
});
|
|
114
115
|
const value = await response.json().catch(() => ({}));
|
|
115
|
-
if (hosted && (!connectionReady || instance !== connectionInstance)) throw Object.assign(new Error("本地连接已改变,请等待重新连接"), {status:409, code:"PREVIEW_CONNECTION_CHANGED"});
|
|
116
|
+
if (hosted && (disconnectBusy || !connectionReady || instance !== connectionInstance)) throw Object.assign(new Error("本地连接已改变,请等待重新连接"), {status:409, code:"PREVIEW_CONNECTION_CHANGED"});
|
|
116
117
|
if (!response.ok) {
|
|
117
118
|
const error = new Error((typeof value?.error === "string" ? value.error : value?.error?.message) || `请求失败(HTTP ${response.status})`);
|
|
118
119
|
error.code = value?.error?.code || "PREVIEW_REQUEST_FAILED";
|
|
@@ -256,7 +257,7 @@
|
|
|
256
257
|
if (!elements.pairingPanel.hidden && pairingRevision !== state.dev.revision) void togglePairing(true);
|
|
257
258
|
elements.connectionState.dataset.phase = phase;
|
|
258
259
|
elements.connectionLabel.textContent = phase === "disconnected" ? "未连接本地工程" : phaseCopy(phase);
|
|
259
|
-
elements.devControl.disabled = !connectionReady || Boolean(devAction) || phase === "starting" || phase === "stopping";
|
|
260
|
+
elements.devControl.disabled = disconnectBusy || !connectionReady || Boolean(devAction) || phase === "starting" || phase === "stopping";
|
|
260
261
|
elements.devControl.dataset.action = ["ready", "reloading", "reload_failed"].includes(phase) ? "stop" : "start";
|
|
261
262
|
elements.devControl.textContent = devAction === "start" ? "正在启动…" : devAction === "stop" ? "正在停止…" : phase === "failed" ? "重试启动" : ["ready", "reloading", "reload_failed"].includes(phase) ? "停止 DEV" : phase === "starting" ? "正在启动…" : phase === "stopping" ? "正在停止…" : "启动 DEV";
|
|
262
263
|
elements.environmentAgent.textContent = phase === "ready"
|
|
@@ -317,6 +318,9 @@
|
|
|
317
318
|
$("#workbench-state-title").textContent = copy[0];
|
|
318
319
|
$("#workbench-state-copy").textContent = copy[1];
|
|
319
320
|
$("#connection-description").textContent = !connectionChecked ? "检查中" : phase === "disconnected" ? "等待连接" : "保存自动重载,可能中断回复;Widget 数据不自动迁移。";
|
|
321
|
+
$("#force-disconnect").hidden = !connectionInstance;
|
|
322
|
+
$("#force-disconnect").disabled = disconnectBusy;
|
|
323
|
+
$("#force-disconnect").textContent = disconnectBusy ? "正在断开…" : "强制断连";
|
|
320
324
|
const connectButton = $("#get-connect-command");
|
|
321
325
|
connectButton.className = `button ${connectionReady ? "button-secondary" : "button-primary"}`;
|
|
322
326
|
connectButton.textContent = connectionReady ? "连接指令" : connectionInstance ? "重新连接" : "连接工程";
|
|
@@ -692,7 +696,7 @@
|
|
|
692
696
|
}
|
|
693
697
|
|
|
694
698
|
async function controlDev() {
|
|
695
|
-
if (!connectionReady || state.dev.phase === "starting" || state.dev.phase === "stopping") return;
|
|
699
|
+
if (disconnectBusy || !connectionReady || state.dev.phase === "starting" || state.dev.phase === "stopping") return;
|
|
696
700
|
if (devAction) return;
|
|
697
701
|
devAction = ["ready", "reloading", "reload_failed"].includes(state.dev.phase) ? "stop" : "start";
|
|
698
702
|
elements.errorBanner.hidden = true;
|
|
@@ -712,7 +716,7 @@
|
|
|
712
716
|
}
|
|
713
717
|
|
|
714
718
|
function updateSendButton() {
|
|
715
|
-
const ready = connectionReady && !devAction && state.simulatorLoaded && state.dev.phase === "ready" && !state.resetting && !state.sending;
|
|
719
|
+
const ready = connectionReady && !disconnectBusy && !devAction && state.simulatorLoaded && state.dev.phase === "ready" && !state.resetting && !state.sending;
|
|
716
720
|
elements.sendMessage.disabled = !ready || !elements.messageInput.value.trim();
|
|
717
721
|
}
|
|
718
722
|
|
|
@@ -948,18 +952,23 @@
|
|
|
948
952
|
}
|
|
949
953
|
|
|
950
954
|
async function refreshConnection() {
|
|
951
|
-
if (connectionBusy) return;
|
|
955
|
+
if (connectionBusy || disconnectBusy) return;
|
|
952
956
|
connectionBusy = true;
|
|
957
|
+
const epoch = connectionEpoch;
|
|
953
958
|
try {
|
|
954
959
|
const response = await fetch(connectionUrl, { signal: AbortSignal.timeout(5000) });
|
|
955
960
|
const value = await response.json();
|
|
956
961
|
if (!response.ok) throw new Error(value.error || "连接状态读取失败");
|
|
962
|
+
if (epoch !== connectionEpoch) return;
|
|
957
963
|
connectionChecked = true; connectionFailure = "";
|
|
958
964
|
$("#connect-command").textContent = value.command;
|
|
959
965
|
$("#copy-connect-command").disabled = false;
|
|
960
|
-
|
|
966
|
+
$("#stop-command").textContent = value.stopCommand || "buddy-cli dev stop";
|
|
967
|
+
if (value.projectRoot) $("#project-root").textContent = value.projectRoot;
|
|
968
|
+
if (value.machineName) $("#machine-name").textContent = value.machineName;
|
|
969
|
+
if (!value.connected) { connectionInstance = value.instanceId || ""; disconnected(); return; }
|
|
961
970
|
const changed = connectionInstance !== value.instanceId;
|
|
962
|
-
if (changed) closeEvents();
|
|
971
|
+
if (changed) { closeEvents(); $("#disconnect-result").hidden = true; }
|
|
963
972
|
const newlyConnected = !connectionReady || changed;
|
|
964
973
|
connectionInstance = value.instanceId;
|
|
965
974
|
connectionReady = true;
|
|
@@ -982,6 +991,7 @@
|
|
|
982
991
|
}
|
|
983
992
|
if (value.liveEvents) connectEvents();
|
|
984
993
|
} catch (cause) {
|
|
994
|
+
if (epoch !== connectionEpoch) return;
|
|
985
995
|
const message = cause.message || "连接已中断,正在重试…";
|
|
986
996
|
connectionChecked = true; connectionFailure = message;
|
|
987
997
|
disconnected(message);
|
|
@@ -990,8 +1000,31 @@
|
|
|
990
1000
|
finally { connectionBusy = false; }
|
|
991
1001
|
}
|
|
992
1002
|
|
|
1003
|
+
async function forceDisconnect() {
|
|
1004
|
+
if (disconnectBusy || !connectionInstance) return;
|
|
1005
|
+
if (!window.confirm("强制断开此工程并停止 DEV?若本机无法响应,需要在对应电脑的工程目录执行停止指令。")) return;
|
|
1006
|
+
disconnectBusy = true; connectionEpoch++;
|
|
1007
|
+
const url = previewApiUrl("/api/connection/disconnect");
|
|
1008
|
+
closeEvents(); renderDev();
|
|
1009
|
+
try {
|
|
1010
|
+
const response = await fetch(url, { method: "POST", signal: AbortSignal.timeout(35_000) });
|
|
1011
|
+
const value = await response.json();
|
|
1012
|
+
if (!response.ok) throw new Error(value.error || "断连请求失败,请刷新状态后重试");
|
|
1013
|
+
connectionInstance = "";
|
|
1014
|
+
disconnected();
|
|
1015
|
+
$("#disconnect-result").hidden = false;
|
|
1016
|
+
$("#disconnect-message").textContent = value.localStopped
|
|
1017
|
+
? "已断开后台连接,并确认当前工程的本地 DEV 已停止。"
|
|
1018
|
+
: "已断开后台连接,但无法确认本机 Runtime 已停止。请到原电脑的工程目录执行下面的停止指令。";
|
|
1019
|
+
} catch (cause) {
|
|
1020
|
+
$("#disconnect-result").hidden = false;
|
|
1021
|
+
$("#disconnect-message").textContent = "尚未确认断连和停止结果,请检查终端或执行下面的停止指令,再刷新连接状态。";
|
|
1022
|
+
showError(cause);
|
|
1023
|
+
} finally { disconnectBusy = false; renderDev(); void refreshConnection(); }
|
|
1024
|
+
}
|
|
1025
|
+
|
|
993
1026
|
async function pollHostedDev() {
|
|
994
|
-
if (!connectionReady || devPollBusy) return;
|
|
1027
|
+
if (!connectionReady || devPollBusy || disconnectBusy) return;
|
|
995
1028
|
devPollBusy = true;
|
|
996
1029
|
try {
|
|
997
1030
|
const [dev, debug] = await Promise.all([api("/api/dev"), api("/api/debug")]);
|
|
@@ -1017,13 +1050,18 @@
|
|
|
1017
1050
|
engineeringDetails.querySelector("summary").focus();
|
|
1018
1051
|
}
|
|
1019
1052
|
});
|
|
1053
|
+
$("#force-disconnect").addEventListener("click", () => void forceDisconnect());
|
|
1054
|
+
$("#copy-stop-command").addEventListener("click", async () => {
|
|
1055
|
+
try { await navigator.clipboard.writeText($("#stop-command").textContent); toast("停止指令已复制,请在原电脑的工程目录执行"); }
|
|
1056
|
+
catch { showError(new Error("请手动复制停止指令")); }
|
|
1057
|
+
});
|
|
1020
1058
|
$("#get-connect-command").addEventListener("click", () => {
|
|
1021
1059
|
$("#connect-instructions").hidden = !$("#connect-instructions").hidden;
|
|
1022
1060
|
$("#get-connect-command").setAttribute("aria-expanded", String(!$("#connect-instructions").hidden));
|
|
1023
1061
|
void refreshConnection();
|
|
1024
1062
|
});
|
|
1025
1063
|
$("#copy-connect-command").addEventListener("click", async () => {
|
|
1026
|
-
try { await navigator.clipboard.writeText($("#connect-command").textContent); toast("
|
|
1064
|
+
try { await navigator.clipboard.writeText($("#connect-command").textContent); toast("连接指令已复制,在工程目录执行后返回当前页面即可"); }
|
|
1027
1065
|
catch { showError(new Error("请手动复制下方的完整连接指令")); }
|
|
1028
1066
|
});
|
|
1029
1067
|
const statusTimer = window.setInterval(() => void refreshConnection(), 2000);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@my-life-buddies/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "搭搭 Developer Platform 命令行工具",
|
|
6
6
|
"publishConfig": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"ws": "8.21.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@buddy/cli-core": "0.
|
|
43
|
-
"@buddy/preview": "0.
|
|
42
|
+
"@buddy/cli-core": "0.18.0",
|
|
43
|
+
"@buddy/preview": "0.18.0"
|
|
44
44
|
}
|
|
45
45
|
}
|