@wendongfly/myhi 1.0.41 → 1.0.43
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/bin/myhi.js +100 -0
- package/dist/attach.js +6 -0
- package/dist/chat.html +1 -0
- package/dist/index.js +3 -3
- package/dist/terminal.html +2 -0
- package/package.json +1 -1
package/bin/myhi.js
CHANGED
|
@@ -177,6 +177,105 @@ if (cmd === 'attach') {
|
|
|
177
177
|
`);
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
} else if (cmd === 'kick') {
|
|
181
|
+
// 踢出会话中的用户
|
|
182
|
+
const { createRequire } = await import('module');
|
|
183
|
+
const require = createRequire(import.meta.url);
|
|
184
|
+
const { io } = require('socket.io-client');
|
|
185
|
+
const { createInterface } = await import('readline');
|
|
186
|
+
|
|
187
|
+
const SERVER = process.env.MYHI_SERVER || 'http://localhost:3000';
|
|
188
|
+
let token;
|
|
189
|
+
try {
|
|
190
|
+
token = readFileSync(join(configDir, 'token'), 'utf8').trim();
|
|
191
|
+
} catch {
|
|
192
|
+
console.log('[myhi] 未找到 token,请先启动服务器');
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const socket = io(SERVER, { auth: { token }, reconnection: false });
|
|
197
|
+
|
|
198
|
+
socket.on('connect_error', (err) => {
|
|
199
|
+
console.log(`[myhi] 连接失败: ${err.message}`);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
socket.on('connect', () => {
|
|
204
|
+
// 获取所有会话
|
|
205
|
+
socket.emit('sessions', null, (sessions) => {
|
|
206
|
+
// sessions 事件可能不存在,用 HTTP 回退
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// 通过 HTTP 获取会话列表
|
|
210
|
+
fetch(`${SERVER}/api/sessions?token=${token}`)
|
|
211
|
+
.then(r => r.json())
|
|
212
|
+
.then(async (sessions) => {
|
|
213
|
+
const alive = sessions.filter(s => s.alive);
|
|
214
|
+
if (alive.length === 0) {
|
|
215
|
+
console.log('[myhi] 没有活跃的会话');
|
|
216
|
+
socket.disconnect();
|
|
217
|
+
process.exit(0);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// 收集所有会话的在线用户
|
|
221
|
+
const allViewers = [];
|
|
222
|
+
for (const session of alive) {
|
|
223
|
+
const result = await new Promise(resolve => {
|
|
224
|
+
socket.emit('join', session.id);
|
|
225
|
+
socket.emit('list-viewers', { sessionId: session.id }, resolve);
|
|
226
|
+
});
|
|
227
|
+
if (result.ok) {
|
|
228
|
+
for (const v of result.viewers) {
|
|
229
|
+
allViewers.push({ ...v, sessionId: session.id, sessionTitle: session.title });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (allViewers.length === 0) {
|
|
235
|
+
console.log('[myhi] 没有在线用户');
|
|
236
|
+
socket.disconnect();
|
|
237
|
+
process.exit(0);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// 去重(同一个 socket 可能只在一个会话中)
|
|
241
|
+
const unique = [...new Map(allViewers.map(v => [v.socketId, v])).values()];
|
|
242
|
+
|
|
243
|
+
console.log('\n 在线用户:');
|
|
244
|
+
console.log(' ────────────────────────────────────────');
|
|
245
|
+
unique.forEach((v, i) => {
|
|
246
|
+
const ctrl = v.isController ? ' [控制中]' : '';
|
|
247
|
+
console.log(` [${i + 1}] ${v.userName} (${v.role})${ctrl} 会话: ${v.sessionTitle}`);
|
|
248
|
+
});
|
|
249
|
+
console.log();
|
|
250
|
+
|
|
251
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
252
|
+
rl.question(' 输入序号踢出用户(0 取消): ', (answer) => {
|
|
253
|
+
rl.close();
|
|
254
|
+
const idx = parseInt(answer, 10);
|
|
255
|
+
if (!idx || idx < 1 || idx > unique.length) {
|
|
256
|
+
console.log('[myhi] 已取消');
|
|
257
|
+
socket.disconnect();
|
|
258
|
+
process.exit(0);
|
|
259
|
+
}
|
|
260
|
+
const target = unique[idx - 1];
|
|
261
|
+
socket.emit('kick-user', { socketId: target.socketId, sessionId: target.sessionId }, (res) => {
|
|
262
|
+
if (res.ok) {
|
|
263
|
+
console.log(`[myhi] 已踢出用户 "${res.name}"`);
|
|
264
|
+
} else {
|
|
265
|
+
console.log(`[myhi] 踢出失败: ${res.error}`);
|
|
266
|
+
}
|
|
267
|
+
socket.disconnect();
|
|
268
|
+
process.exit(0);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
})
|
|
272
|
+
.catch((err) => {
|
|
273
|
+
console.log(`[myhi] 获取会话失败: ${err.message}`);
|
|
274
|
+
socket.disconnect();
|
|
275
|
+
process.exit(1);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
180
279
|
} else if (cmd === 'help' || cmd === '--help' || cmd === '-h') {
|
|
181
280
|
console.log(`
|
|
182
281
|
myhi — 基于 Web 的终端共享工具
|
|
@@ -201,6 +300,7 @@ myhi — 基于 Web 的终端共享工具
|
|
|
201
300
|
myhi attach 列出活跃会话,交互式选择后附加
|
|
202
301
|
myhi attach <id> 直接附加到指定会话
|
|
203
302
|
myhi attach --new 创建新会话并附加
|
|
303
|
+
myhi kick 列出在线用户,交互式选择后踢出
|
|
204
304
|
|
|
205
305
|
快捷键(attach 模式):
|
|
206
306
|
Ctrl+] 分离终端(退出但不关闭会话)
|
package/dist/attach.js
CHANGED
|
@@ -78,6 +78,12 @@ function attach(socket, sessionId) {
|
|
|
78
78
|
}
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
+
socket.on('kicked', ({ reason }) => {
|
|
82
|
+
process.stderr.write(`\r\n[myhi] ${reason || '你已被管理员踢出'}\r\n`);
|
|
83
|
+
cleanup(socket);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
});
|
|
86
|
+
|
|
81
87
|
socket.on('session-exit', ({ code }) => {
|
|
82
88
|
process.stderr.write(`\r\n[myhi] 会话已退出 (code ${code})\r\n`);
|
|
83
89
|
cleanup(socket);
|
package/dist/chat.html
CHANGED
|
@@ -968,6 +968,7 @@
|
|
|
968
968
|
else addStatusMessage('控制权已释放');
|
|
969
969
|
});
|
|
970
970
|
socket.on('control-denied', ({ reason }) => addStatusMessage('无法获取控制: ' + reason));
|
|
971
|
+
socket.on('kicked', ({ reason }) => { addStatusMessage(reason || '你已被管理员踢出'); setTimeout(() => location.href = '/', 2000); });
|
|
971
972
|
socket.on('mode-changed', ({ sessionId, mode }) => { if (sessionId === SESSION_ID) { currentMode = mode; updateModeUI(); } });
|
|
972
973
|
|
|
973
974
|
// ── Agent 模式事件 ──────────────────────────────
|