handmux 0.14.0 → 0.16.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/bin/handmux.js +24 -3
- package/package.json +4 -4
- package/public/assets/index-Cf-WEkt5.js +330 -0
- package/public/assets/index-D5UQBvph.css +32 -0
- package/public/index.html +2 -2
- package/src/claudeEvents.js +70 -3
- package/src/cli/claudeHooks.js +3 -17
- package/src/cli/codexHooks.js +5 -17
- package/src/cli/hookScaffold.js +35 -0
- package/src/cli/i18n/en.js +2 -0
- package/src/cli/i18n/zh.js +2 -0
- package/src/cli/setupModel.js +145 -0
- package/src/cli/setupWizard.js +15 -140
- package/src/cli/state.js +7 -1
- package/src/cli/statusLine.js +1 -5
- package/src/cli/updateCheck.js +7 -1
- package/src/docPath.js +4 -2
- package/src/httpApi.js +26 -710
- package/src/jsonStore.js +24 -0
- package/src/previews.js +18 -22
- package/src/push.js +2 -6
- package/src/routes/files.js +172 -0
- package/src/routes/git.js +57 -0
- package/src/routes/previews.js +40 -0
- package/src/routes/push.js +82 -0
- package/src/routes/sessions.js +151 -0
- package/src/routes/system.js +130 -0
- package/src/routes/terminal.js +167 -0
- package/src/tmux/commands.js +33 -5
- package/public/assets/index-BIOe84T4.css +0 -32
- package/public/assets/index-CL5hFo5W.js +0 -162
package/bin/handmux.js
CHANGED
|
@@ -36,12 +36,15 @@ import { codexHooksStatus, installCodexHooks, uninstallCodexHooks } from '../src
|
|
|
36
36
|
import { statusLineStatus, installStatusLine, uninstallStatusLine, composeHint } from '../src/cli/statusLine.js';
|
|
37
37
|
import { claudeUsagePath } from '../src/usage.js';
|
|
38
38
|
import { probe } from '../src/cli/probe.js';
|
|
39
|
-
import { notifyUpdate, runUpdateCheck, PKG_NAME } from '../src/cli/updateCheck.js';
|
|
39
|
+
import { notifyUpdate, runUpdateCheck, isBrewInstall, PKG_NAME } from '../src/cli/updateCheck.js';
|
|
40
40
|
import { t, initLocale, setLocale } from '../src/cli/i18n/index.js';
|
|
41
41
|
import { runPush } from '../src/cli/pushCmd.js';
|
|
42
42
|
|
|
43
43
|
const HOME = homedir();
|
|
44
44
|
const SELF = fileURLToPath(import.meta.url);
|
|
45
|
+
// Symlink-resolved entry path — a brew (tap) install is symlinked from the prefix's bin into the Cellar,
|
|
46
|
+
// so isBrewInstall() needs the real target, not the symlink, to spot the `/Cellar/` segment.
|
|
47
|
+
const SELF_REAL = (() => { try { return fs.realpathSync(SELF); } catch { return SELF; } })();
|
|
45
48
|
const HOOKS_SRC = path.resolve(path.dirname(SELF), '../hooks'); // server/hooks (bundled scripts)
|
|
46
49
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
47
50
|
|
|
@@ -162,6 +165,7 @@ function version() {
|
|
|
162
165
|
// restart a running instance; on success we refresh the update cache so the "upgrade available" notice
|
|
163
166
|
// clears, and remind them to `handmux restart` to actually run the new code.
|
|
164
167
|
function updateCmd() {
|
|
168
|
+
if (isBrewInstall(SELF_REAL)) { console.log(t('update.brew')); return; }
|
|
165
169
|
console.log(t('update.running'));
|
|
166
170
|
const r = spawnSync('npm', ['install', '-g', `${PKG_NAME}@latest`], { stdio: 'inherit' });
|
|
167
171
|
if (r.status === 0) {
|
|
@@ -176,7 +180,7 @@ function updateCmd() {
|
|
|
176
180
|
|
|
177
181
|
// Best-effort upgrade notice from the cached "latest version" (never blocks; refreshes in the background).
|
|
178
182
|
function maybeNotifyUpdate() {
|
|
179
|
-
notifyUpdate(HOME, { version: requireOpt('../package.json').version, selfPath:
|
|
183
|
+
notifyUpdate(HOME, { version: requireOpt('../package.json').version, selfPath: SELF_REAL });
|
|
180
184
|
}
|
|
181
185
|
|
|
182
186
|
async function start() {
|
|
@@ -267,9 +271,26 @@ async function start() {
|
|
|
267
271
|
await waitAndPrint(true);
|
|
268
272
|
}
|
|
269
273
|
|
|
274
|
+
// Best-effort SIGTERM to the supervisor's recorded children. The supervisor reaps its own children on a
|
|
275
|
+
// graceful SIGTERM (supervisor.js shutdown), but if it was SIGKILL'd or crashed, its server/tunnel children
|
|
276
|
+
// are orphaned with no reaper — the classic "stray cloudflared after stop". Only called on the dead-
|
|
277
|
+
// supervisor branch, so these pids have no live parent to clean them up.
|
|
278
|
+
function reapOrphans(st) {
|
|
279
|
+
for (const pid of [st.serverPid, st.tunnelPid]) {
|
|
280
|
+
if (isAlive(pid)) { try { process.kill(pid, 'SIGTERM'); } catch { /* raced away */ } }
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
270
284
|
function stop() {
|
|
271
285
|
const st = readState(HOME);
|
|
272
|
-
if (!st || !isAlive(st.supervisorPid)) {
|
|
286
|
+
if (!st || !isAlive(st.supervisorPid)) {
|
|
287
|
+
// Supervisor already gone — but a non-graceful death may have orphaned its children. Reap them before
|
|
288
|
+
// dropping the state file, or nothing ever will.
|
|
289
|
+
if (st) reapOrphans(st);
|
|
290
|
+
console.log(t('stop.notRunning'));
|
|
291
|
+
clearState(HOME);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
273
294
|
try { process.kill(st.supervisorPid, 'SIGTERM'); } catch { /* race: already gone */ }
|
|
274
295
|
console.log(t('stop.stopped', { pid: st.supervisorPid }));
|
|
275
296
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "handmux",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "A mobile vibe-coding cockpit — built on tmux: drive your live session, Claude Code / Codex — anything a terminal can run — from your phone.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -57,13 +57,13 @@
|
|
|
57
57
|
"vitest": "^2.0.0"
|
|
58
58
|
},
|
|
59
59
|
"whatsNew": [
|
|
60
|
+
{"version":"0.16.0","date":"2026-07-15","zh":"分屏布局地图 · 手机也能建/删窗格","en":"Split-layout map · create & close panes from the phone"},
|
|
61
|
+
{"version":"0.15.0","date":"2026-07-14","zh":"键盘弹起终端自适应 · 全屏程序可上下滚动","en":"Keyboard-aware terminal · scroll inside full-screen apps"},
|
|
60
62
|
{"version":"0.14.0","date":"2026-07-13","zh":"终端文字选中拷贝 · 脚本复用推送通道","en":"Terminal select & copy · scripts reuse the push channel"},
|
|
61
63
|
{"version":"0.13.0","date":"2026-07-12","zh":"终端文件路径高亮可点","en":"Tappable, highlighted file paths"},
|
|
62
64
|
{"version":"0.12.3","date":"2026-07-11","zh":"接管会话可自定义名称 + Homebrew 一键安装","en":"Name a takeover session · Homebrew install"},
|
|
63
65
|
{"version":"0.12.2","date":"2026-07-11","zh":"修复主屏图标偏大 / 换图标后不刷新","en":"Home-screen icon: right size & always fresh"},
|
|
64
66
|
{"version":"0.12.1","date":"2026-07-11","zh":"全新品牌图标与双色字标","en":"New brand icon & two-tone wordmark"},
|
|
65
|
-
{"version":"0.12.0","date":"2026-07-11","zh":"全屏程序也能滑动滚动 · 反馈入口 · 聊天草稿不丢","en":"Swipe-scroll full-screen apps · feedback channels · chat drafts kept"}
|
|
66
|
-
{"version":"0.11.1","date":"2026-07-09","zh":"修复 Node 18 下无法启动的问题","en":"Fixes startup crash on Node 18"},
|
|
67
|
-
{"version":"0.11.0","date":"2026-07-08","zh":"国内可用隧道 natapp/cpolar · 配置向导重做","en":"China-usable tunnels · setup redesigned"}
|
|
67
|
+
{"version":"0.12.0","date":"2026-07-11","zh":"全屏程序也能滑动滚动 · 反馈入口 · 聊天草稿不丢","en":"Swipe-scroll full-screen apps · feedback channels · chat drafts kept"}
|
|
68
68
|
]
|
|
69
69
|
}
|