pi-maestro-mobile 0.1.5 → 0.2.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/dist/extension.d.ts.map +1 -1
- package/dist/extension.js +119 -12
- package/dist/extension.js.map +1 -1
- package/package.json +1 -1
package/dist/extension.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,iCAAiC,CAAC;AA0FtF,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA2HnE"}
|
package/dist/extension.js
CHANGED
|
@@ -2,19 +2,24 @@
|
|
|
2
2
|
* maestro-mobile extension — 薄遥控器(用户提案:pi 扩展自动拉起 npm 包的 host)
|
|
3
3
|
*
|
|
4
4
|
* 职责边界(刻意保持薄):
|
|
5
|
-
* - start: 幂等启动 host 子进程(detached
|
|
6
|
-
* - status: 探测 /api/health + /api/status
|
|
5
|
+
* - start: 幂等启动 host 子进程(detached;已在监听则跳过;O_EXCL 竞争锁防多会话并发启动)
|
|
6
|
+
* - status: 探测 /api/health + /api/status,显示 token 摘要
|
|
7
|
+
* - qr: 终端二维码渲染 ws://<lan-ip>:port/ws?token=(手机 App 扫码即连)
|
|
7
8
|
* - stop: 杀掉由本扩展启动的 host(PID 文件校验,防误杀外部 launchd/systemd 实例)
|
|
9
|
+
* - widget: 状态栏常驻一行(● :port · N 窗口),30s 刷新
|
|
8
10
|
*
|
|
9
11
|
* host 仍是独立常驻进程(不随 Pi 会话生灭);本扩展只做生命周期遥控。
|
|
10
12
|
* 无 npm 包的 host 时(pi install 场景),spawn 同包 dist/cli.js。
|
|
11
13
|
*/
|
|
12
14
|
import { spawn } from "node:child_process";
|
|
15
|
+
import { networkInterfaces } from "node:os";
|
|
16
|
+
import qrcodeTerminal from "qrcode-terminal";
|
|
13
17
|
import { readFile, writeFile, unlink } from "node:fs/promises";
|
|
14
18
|
import { join } from "node:path";
|
|
15
19
|
import { homedir } from "node:os";
|
|
16
20
|
import { fileURLToPath } from "node:url";
|
|
17
21
|
const PID_FILE = join(homedir(), ".pi", "maestro-mobile.pid");
|
|
22
|
+
const TOKEN_FILE = join(homedir(), ".pi", "maestro-mobile-token");
|
|
18
23
|
const DEFAULT_PORT = 4739;
|
|
19
24
|
function hostPort() {
|
|
20
25
|
const raw = process.env.MAESTRO_MOBILE_PORT;
|
|
@@ -37,6 +42,16 @@ function hostStatus(port, timeoutMs = 800) {
|
|
|
37
42
|
.catch(() => resolve(null));
|
|
38
43
|
});
|
|
39
44
|
}
|
|
45
|
+
/** 探测本机局域网 IPv4(给手机连接 URL 用;找不到回退 127.0.0.1) */
|
|
46
|
+
function lanIp() {
|
|
47
|
+
for (const addrs of Object.values(networkInterfaces())) {
|
|
48
|
+
for (const a of addrs ?? []) {
|
|
49
|
+
if (a.family === "IPv4" && !a.internal)
|
|
50
|
+
return a.address;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return "127.0.0.1";
|
|
54
|
+
}
|
|
40
55
|
/** host cli.js 入口:同包 dist(pi install npm:pi-maestro-mobile 时随包分发) */
|
|
41
56
|
function hostCliPath() {
|
|
42
57
|
// dist/extension.js 与 dist/cli.js 同目录
|
|
@@ -52,9 +67,49 @@ async function readPid() {
|
|
|
52
67
|
return null;
|
|
53
68
|
}
|
|
54
69
|
}
|
|
70
|
+
/** 读取持久化 token(host start 时生成;未启动过返回空) */
|
|
71
|
+
async function readToken() {
|
|
72
|
+
try {
|
|
73
|
+
return (await readFile(TOKEN_FILE, "utf8")).trim();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return "";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// ── 状态栏 widget ──────────────────────────────────────────────
|
|
80
|
+
const WIDGET_KEY = "maestro-mobile-status";
|
|
81
|
+
let widgetCtx = null;
|
|
82
|
+
/** 刷新状态栏 widget:● 运行中 :4739 · N 窗口 / 未运行 */
|
|
83
|
+
async function refreshWidget() {
|
|
84
|
+
if (!widgetCtx)
|
|
85
|
+
return;
|
|
86
|
+
const port = hostPort();
|
|
87
|
+
const alive = await probeHealth(port);
|
|
88
|
+
if (!alive) {
|
|
89
|
+
widgetCtx.ui.setWidget(WIDGET_KEY, undefined);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
let windows = 0;
|
|
93
|
+
try {
|
|
94
|
+
const r = await fetch(`http://127.0.0.1:${port}/api/workspace-telemetry`);
|
|
95
|
+
if (r.ok) {
|
|
96
|
+
const d = (await r.json());
|
|
97
|
+
windows = d.aliveCount ?? 0;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch { /* 探测失败按 0 显示 */ }
|
|
101
|
+
widgetCtx.ui.setWidget(WIDGET_KEY, [`● maestro-mobile :${port} · ${windows} 窗口`]);
|
|
102
|
+
}
|
|
55
103
|
export default function maestroHostExtension(pi) {
|
|
104
|
+
// 会话启动后挂状态栏 widget;30s 周期刷新(host 状态变化时感知)
|
|
105
|
+
pi.on("session_start", (_event, ctx) => {
|
|
106
|
+
widgetCtx = ctx;
|
|
107
|
+
void refreshWidget();
|
|
108
|
+
const timer = setInterval(() => void refreshWidget(), 30_000);
|
|
109
|
+
pi.on("session_shutdown", () => { clearInterval(timer); widgetCtx = null; });
|
|
110
|
+
});
|
|
56
111
|
pi.registerCommand("maestro-mobile", {
|
|
57
|
-
description: "Maestro Mobile Host 遥控(status / start / stop)",
|
|
112
|
+
description: "Maestro Mobile Host 遥控(status / start / stop / qr)",
|
|
58
113
|
handler: async (args, ctx) => {
|
|
59
114
|
const sub = (args ?? "").trim().split(/\s+/)[0] || "status";
|
|
60
115
|
const port = hostPort();
|
|
@@ -64,11 +119,35 @@ export default function maestroHostExtension(pi) {
|
|
|
64
119
|
ctx.ui.notify(`maestro-mobile: 未运行(端口 ${port} 无响应)`, "info");
|
|
65
120
|
return;
|
|
66
121
|
}
|
|
122
|
+
const token = await readToken();
|
|
67
123
|
const s = await hostStatus(port);
|
|
68
124
|
const ver = s
|
|
69
125
|
? `${s.version} · pi ${s.piVersion ?? "?"} · flow ${s.flowVersion ?? "?"} · cli ${s.maestroCliVersion ?? "?"}`
|
|
70
|
-
: "
|
|
71
|
-
|
|
126
|
+
: "运行中(详情需 token,见下方)";
|
|
127
|
+
const tokenLine = token
|
|
128
|
+
? `token: ${token.slice(0, 6)}…${token.slice(-4)}(完整值: ~/.pi/maestro-mobile-token 或 /maestro-mobile qr)`
|
|
129
|
+
: "token: 未知(host 未持久化)";
|
|
130
|
+
ctx.ui.notify(`maestro-mobile: 运行中 :${port} — ${ver}\n${tokenLine}`, "info");
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (sub === "qr") {
|
|
134
|
+
if (!alive) {
|
|
135
|
+
ctx.ui.notify("maestro-mobile: host 未运行,先 /maestro-mobile start", "warning");
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const token = await readToken();
|
|
139
|
+
if (!token) {
|
|
140
|
+
ctx.ui.notify("maestro-mobile: 未找到 token(~/.pi/maestro-mobile-token),先用 /maestro-mobile start 启动一次", "warning");
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
// v0.2 配对码:scheme 格式(App 端 extractPairing 解析;裸 ws URL 也兼容)
|
|
144
|
+
const wsUrl = `ws://${lanIp()}:${port}/ws`;
|
|
145
|
+
const url = `maestro-mobile://pair?ws=${encodeURIComponent(wsUrl)}&token=${encodeURIComponent(token)}`;
|
|
146
|
+
ctx.ui.notify(`手机 App 连接地址:${wsUrl}\n(token 见二维码 / ~/.pi/maestro-mobile-token)`, "info");
|
|
147
|
+
qrcodeTerminal.generate(url, { small: true }, (q) => {
|
|
148
|
+
// 经 notify 逐行送出(QR 用 block 字符,等宽终端可扫)
|
|
149
|
+
ctx.ui.notify(q, "info");
|
|
150
|
+
});
|
|
72
151
|
return;
|
|
73
152
|
}
|
|
74
153
|
if (sub === "start") {
|
|
@@ -76,6 +155,27 @@ export default function maestroHostExtension(pi) {
|
|
|
76
155
|
ctx.ui.notify(`maestro-mobile: 已在运行(:${port}),跳过启动`, "info");
|
|
77
156
|
return;
|
|
78
157
|
}
|
|
158
|
+
// 多 Pi 会话同时 start 的竞争锁:O_EXCL 抢占式创建,抢不到的会话直接退出
|
|
159
|
+
const lockFile = PID_FILE + ".lock";
|
|
160
|
+
let gotLock = false;
|
|
161
|
+
try {
|
|
162
|
+
await writeFile(lockFile, String(process.pid), { flag: "wx" });
|
|
163
|
+
gotLock = true;
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// 锁已被占 —— 检查持锁者是否还活着,死了则接管
|
|
167
|
+
try {
|
|
168
|
+
const lockPid = Number((await readFile(lockFile, "utf8")).trim());
|
|
169
|
+
process.kill(lockPid, 0);
|
|
170
|
+
ctx.ui.notify(`maestro-mobile: 另一会话正在启动(pid=${lockPid}),本次跳过`, "warning");
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
await unlink(lockFile).catch(() => { });
|
|
175
|
+
await writeFile(lockFile, String(process.pid), { flag: "wx" });
|
|
176
|
+
gotLock = true;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
79
179
|
const child = spawn(process.execPath, [hostCliPath(), "--port", String(port)], {
|
|
80
180
|
detached: true,
|
|
81
181
|
stdio: "ignore",
|
|
@@ -84,14 +184,20 @@ export default function maestroHostExtension(pi) {
|
|
|
84
184
|
child.unref();
|
|
85
185
|
await writeFile(PID_FILE, String(child.pid ?? ""), "utf8");
|
|
86
186
|
// 等待端口就绪(最多 3s)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
187
|
+
try {
|
|
188
|
+
for (let i = 0; i < 10; i++) {
|
|
189
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
190
|
+
if (await probeHealth(port)) {
|
|
191
|
+
ctx.ui.notify(`maestro-mobile: 已启动 :${port} pid=${child.pid}`, "info");
|
|
192
|
+
await refreshWidget();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
92
195
|
}
|
|
196
|
+
ctx.ui.notify("maestro-mobile: 启动后 3s 内未见 health 通过,请查日志", "warning");
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
await unlink(lockFile).catch(() => { }); // 释放竞争锁
|
|
93
200
|
}
|
|
94
|
-
ctx.ui.notify("maestro-mobile: 启动后 3s 内未见 health 通过,请查日志", "warning");
|
|
95
201
|
return;
|
|
96
202
|
}
|
|
97
203
|
if (sub === "stop") {
|
|
@@ -109,9 +215,10 @@ export default function maestroHostExtension(pi) {
|
|
|
109
215
|
await unlink(PID_FILE).catch(() => { });
|
|
110
216
|
ctx.ui.notify(`maestro-mobile: pid=${pid} 已不存在,清理 PID 文件`, "info");
|
|
111
217
|
}
|
|
218
|
+
await refreshWidget();
|
|
112
219
|
return;
|
|
113
220
|
}
|
|
114
|
-
ctx.ui.notify(`maestro-mobile: 未知子命令 "${sub}"(可用:status / start / stop)`, "warning");
|
|
221
|
+
ctx.ui.notify(`maestro-mobile: 未知子命令 "${sub}"(可用:status / start / stop / qr)`, "warning");
|
|
115
222
|
},
|
|
116
223
|
});
|
|
117
224
|
}
|
package/dist/extension.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"}
|