handmux 0.23.0 → 0.24.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 +3 -3
- package/README.zh-CN.md +3 -3
- package/bin/handmux.js +3 -689
- package/dist/bin/handmux.js +850 -0
- package/{hooks → dist/hooks}/handmux-statusline.cjs +28 -6
- package/{hooks → dist/hooks}/handmux-write.cjs +24 -3
- package/dist/package.json +126 -0
- package/dist/public/assets/index-CicdY9E9.css +32 -0
- package/dist/public/assets/index-D4VP5t8h.js +337 -0
- package/dist/public/assets/pcm-worklet-CxcDy7PB.js +1 -0
- package/{public → dist/public}/index.html +5 -4
- package/{src → dist/src}/agents/claude.js +105 -83
- package/dist/src/agents/codex.js +217 -0
- package/{src → dist/src}/agents/index.js +7 -7
- package/dist/src/agents/processIdentity.js +80 -0
- package/dist/src/agents/scanUtils.js +262 -0
- package/dist/src/apiErrors.js +77 -0
- package/{src → dist/src}/appName.js +12 -13
- package/dist/src/asr/iflyConfig.js +7 -0
- package/dist/src/asr/iflySign.js +14 -0
- package/dist/src/auth.js +27 -0
- package/dist/src/browser/bootstrap.js +72 -0
- package/dist/src/browser/cookieProfiles.js +413 -0
- package/dist/src/browser/coordinator.js +51 -0
- package/dist/src/browser/hammerheadCompat.js +104 -0
- package/dist/src/browser/hammerheadRedirectCompat.js +37 -0
- package/dist/src/browser/manager.js +560 -0
- package/dist/src/browser/originLabel.js +15 -0
- package/dist/src/browser/profilePersistence.js +235 -0
- package/dist/src/browser/publicProxy.js +176 -0
- package/dist/src/browser/routes.js +159 -0
- package/dist/src/browser/sessionStore.js +72 -0
- package/dist/src/browser/siteVersion.js +121 -0
- package/dist/src/browser/targetPolicy.js +163 -0
- package/{src → dist/src}/browser/worker.js +14 -18
- package/dist/src/browser/workerClient.js +286 -0
- package/dist/src/browser/workerServer.js +91 -0
- package/dist/src/captureBackground.js +95 -0
- package/dist/src/claudeEvents.js +499 -0
- package/{src → dist/src}/cli/claudeHooks.js +146 -108
- package/{src → dist/src}/cli/cloudflareUrl.js +2 -3
- package/dist/src/cli/cloudflared.js +106 -0
- package/dist/src/cli/codexManaged.js +77 -0
- package/{src → dist/src}/cli/cpolarUrl.js +8 -9
- package/dist/src/cli/drivers.js +98 -0
- package/dist/src/cli/hookScaffold.js +36 -0
- package/dist/src/cli/i18n/en.js +366 -0
- package/{src → dist/src}/cli/i18n/index.js +27 -25
- package/dist/src/cli/i18n/zh.js +365 -0
- package/dist/src/cli/legacyCodexHooks.js +52 -0
- package/{src → dist/src}/cli/natappUrl.js +2 -3
- package/dist/src/cli/options.js +245 -0
- package/dist/src/cli/probe.js +16 -0
- package/{src → dist/src}/cli/prompt.js +4 -6
- package/dist/src/cli/pushCmd.js +102 -0
- package/{src → dist/src}/cli/qr.js +19 -19
- package/dist/src/cli/service.js +144 -0
- package/dist/src/cli/setupModel.js +194 -0
- package/dist/src/cli/setupWizard.js +647 -0
- package/dist/src/cli/shortcutEditor.js +351 -0
- package/dist/src/cli/sshTunnel.js +18 -0
- package/dist/src/cli/state.js +114 -0
- package/{src → dist/src}/cli/statusLine.js +63 -46
- package/dist/src/cli/supervisor.js +278 -0
- package/dist/src/cli/supervisorHealth.js +21 -0
- package/dist/src/cli/supervisorLaunch.js +148 -0
- package/dist/src/cli/supervisorProcesses.js +62 -0
- package/dist/src/cli/supervisorState.js +62 -0
- package/dist/src/cli/tmuxVersion.js +53 -0
- package/{src → dist/src}/cli/tunlite.js +7 -10
- package/dist/src/cli/tunnelClients.js +72 -0
- package/{src → dist/src}/cli/updateCheck.js +98 -69
- package/{src → dist/src}/cli/urlHost.js +8 -4
- package/dist/src/cli/workspaceCmd.js +347 -0
- package/dist/src/codexAppServer.js +2299 -0
- package/dist/src/codexConversationProjection.js +199 -0
- package/dist/src/codexDiff.js +118 -0
- package/dist/src/codexMessageIdentity.js +18 -0
- package/dist/src/codexPlan.js +30 -0
- package/dist/src/codexQueueProtocol.js +96 -0
- package/dist/src/codexStreamProtocol.js +207 -0
- package/dist/src/codexToolProtocol.js +68 -0
- package/dist/src/codexTranscriptParse.js +724 -0
- package/dist/src/codexUsageSnapshot.js +205 -0
- package/dist/src/config.js +8 -0
- package/{src → dist/src}/docPath.js +22 -24
- package/dist/src/docs.js +337 -0
- package/dist/src/git.js +272 -0
- package/dist/src/healthProtocol.js +97 -0
- package/dist/src/httpApi.js +68 -0
- package/dist/src/jsonStore.js +15 -0
- package/{src → dist/src}/keyNames.js +3 -3
- package/dist/src/notifications.js +111 -0
- package/dist/src/orphans.js +157 -0
- package/dist/src/pendingPrompt.js +194 -0
- package/dist/src/previewServer.js +202 -0
- package/dist/src/previews.js +179 -0
- package/dist/src/privateStateStore.js +89 -0
- package/dist/src/push.js +224 -0
- package/dist/src/routes/codex.js +606 -0
- package/dist/src/routes/files.js +230 -0
- package/dist/src/routes/git.js +78 -0
- package/dist/src/routes/health.js +16 -0
- package/dist/src/routes/notifications.js +16 -0
- package/dist/src/routes/previews.js +43 -0
- package/dist/src/routes/push.js +145 -0
- package/dist/src/routes/sessions.js +232 -0
- package/dist/src/routes/system.js +156 -0
- package/dist/src/routes/terminal.js +238 -0
- package/dist/src/routes/transcript.js +197 -0
- package/dist/src/routes/workspace.js +267 -0
- package/{src → dist/src}/server.js +100 -74
- package/dist/src/shortcutConfig.js +83 -0
- package/{src → dist/src}/staticCache.js +5 -3
- package/{src → dist/src}/staticCompression.js +5 -6
- package/dist/src/terminalStream.js +441 -0
- package/{src → dist/src}/tmux/commands.js +156 -171
- package/dist/src/tmux/format.js +47 -0
- package/dist/src/transcriptParse.js +240 -0
- package/dist/src/transcriptReader.js +113 -0
- package/{src → dist/src}/trimCapture.js +11 -11
- package/dist/src/uploadTypes.js +29 -0
- package/dist/src/urlPolicy.js +18 -0
- package/dist/src/usage.js +260 -0
- package/dist/src/workspace/agentRunner.js +204 -0
- package/dist/src/workspace/atomicJson.js +31 -0
- package/dist/src/workspace/capture.js +139 -0
- package/dist/src/workspace/checkpointer.js +228 -0
- package/dist/src/workspace/environment.js +71 -0
- package/dist/src/workspace/lock.js +137 -0
- package/dist/src/workspace/mapping.js +128 -0
- package/dist/src/workspace/operations.js +271 -0
- package/dist/src/workspace/paths.js +15 -0
- package/dist/src/workspace/planner.js +292 -0
- package/dist/src/workspace/restore.js +314 -0
- package/dist/src/workspace/runtime.js +318 -0
- package/dist/src/workspace/schema.js +156 -0
- package/dist/src/workspace/store.js +464 -0
- package/dist/src/workspace/tmuxAdapter.js +694 -0
- package/dist/src/workspaceProtocol.js +158 -0
- package/package.json +27 -15
- package/public/assets/index-C3N7OkyP.css +0 -32
- package/public/assets/index-D1DWcC5u.js +0 -337
- package/src/.gitkeep +0 -0
- package/src/agents/codex.js +0 -168
- package/src/agents/processIdentity.js +0 -72
- package/src/agents/scanUtils.js +0 -225
- package/src/asr/iflyConfig.js +0 -10
- package/src/asr/iflySign.js +0 -16
- package/src/auth.js +0 -30
- package/src/browser/bootstrap.js +0 -68
- package/src/browser/cookieProfiles.js +0 -403
- package/src/browser/coordinator.js +0 -47
- package/src/browser/hammerheadCompat.js +0 -86
- package/src/browser/hammerheadRedirectCompat.js +0 -38
- package/src/browser/manager.js +0 -556
- package/src/browser/originLabel.js +0 -17
- package/src/browser/profilePersistence.js +0 -241
- package/src/browser/publicProxy.js +0 -175
- package/src/browser/routes.js +0 -154
- package/src/browser/sessionStore.js +0 -78
- package/src/browser/siteVersion.js +0 -124
- package/src/browser/targetPolicy.js +0 -137
- package/src/browser/workerClient.js +0 -253
- package/src/browser/workerServer.js +0 -98
- package/src/captureBackground.js +0 -93
- package/src/claudeEvents.js +0 -399
- package/src/cli/cloudflared.js +0 -99
- package/src/cli/codexManaged.js +0 -77
- package/src/cli/drivers.js +0 -97
- package/src/cli/hookScaffold.js +0 -33
- package/src/cli/i18n/en.js +0 -385
- package/src/cli/i18n/zh.js +0 -384
- package/src/cli/legacyCodexHooks.js +0 -49
- package/src/cli/options.js +0 -211
- package/src/cli/probe.js +0 -16
- package/src/cli/pushCmd.js +0 -60
- package/src/cli/service.js +0 -126
- package/src/cli/setupModel.js +0 -154
- package/src/cli/setupWizard.js +0 -506
- package/src/cli/shortcutEditor.js +0 -288
- package/src/cli/sshTunnel.js +0 -12
- package/src/cli/state.js +0 -90
- package/src/cli/supervisor.js +0 -183
- package/src/cli/supervisorProcesses.js +0 -57
- package/src/cli/tmuxVersion.js +0 -49
- package/src/cli/tunnelClients.js +0 -62
- package/src/cli/workspaceCmd.js +0 -300
- package/src/codexAppServer.js +0 -1620
- package/src/codexDiff.js +0 -108
- package/src/codexTranscriptParse.js +0 -413
- package/src/codexUsageSnapshot.cjs +0 -129
- package/src/config.js +0 -9
- package/src/docs.js +0 -228
- package/src/git.js +0 -208
- package/src/httpApi.js +0 -72
- package/src/jsonStore.js +0 -24
- package/src/notifications.js +0 -68
- package/src/orphans.js +0 -152
- package/src/pendingPrompt.js +0 -163
- package/src/previewServer.js +0 -168
- package/src/previews.js +0 -116
- package/src/push.js +0 -183
- package/src/routes/codex.js +0 -473
- package/src/routes/files.js +0 -172
- package/src/routes/git.js +0 -57
- package/src/routes/notifications.js +0 -19
- package/src/routes/previews.js +0 -35
- package/src/routes/push.js +0 -119
- package/src/routes/sessions.js +0 -168
- package/src/routes/system.js +0 -132
- package/src/routes/terminal.js +0 -210
- package/src/routes/transcript.js +0 -171
- package/src/routes/workspace.js +0 -267
- package/src/shortcutConfig.js +0 -75
- package/src/terminalStream.js +0 -391
- package/src/tmux/format.js +0 -45
- package/src/transcriptParse.js +0 -180
- package/src/transcriptReader.js +0 -101
- package/src/uploadTypes.js +0 -30
- package/src/urlPolicy.js +0 -14
- package/src/usage.js +0 -260
- package/src/workspace/agentRunner.js +0 -188
- package/src/workspace/atomicJson.js +0 -32
- package/src/workspace/capture.js +0 -139
- package/src/workspace/checkpointer.js +0 -187
- package/src/workspace/environment.js +0 -75
- package/src/workspace/lock.js +0 -128
- package/src/workspace/mapping.js +0 -124
- package/src/workspace/operations.js +0 -252
- package/src/workspace/paths.js +0 -16
- package/src/workspace/planner.js +0 -247
- package/src/workspace/restore.js +0 -279
- package/src/workspace/runtime.js +0 -314
- package/src/workspace/schema.js +0 -136
- package/src/workspace/store.js +0 -382
- package/src/workspace/tmuxAdapter.js +0 -554
- /package/{hooks → dist/hooks}/handmux-notify.sh +0 -0
- /package/{public → dist/public}/fonts/JetBrainsMonoNerdFontMono-Regular.woff2 +0 -0
- /package/{public → dist/public}/fonts/TWUnifont.woff2 +0 -0
- /package/{public → dist/public}/icons/apple-touch-icon.png +0 -0
- /package/{public → dist/public}/icons/badge-96.png +0 -0
- /package/{public → dist/public}/icons/icon-192-maskable.png +0 -0
- /package/{public → dist/public}/icons/icon-192.png +0 -0
- /package/{public → dist/public}/icons/icon-512-maskable.png +0 -0
- /package/{public → dist/public}/icons/icon-512.png +0 -0
- /package/{public → dist/public}/icons/logo.svg +0 -0
- /package/{public → dist/public}/manifest.webmanifest +0 -0
- /package/{public → dist/public}/offline.html +0 -0
- /package/{public → dist/public}/sw.js +0 -0
- /package/{src → dist/src}/browser/protocol.js +0 -0
- /package/{src → dist/src}/cli/cfNamed.js +0 -0
|
@@ -21,6 +21,22 @@ const raw = (() => { try { return fs.readFileSync(0, 'utf8'); } catch { return '
|
|
|
21
21
|
let j = {};
|
|
22
22
|
try { j = JSON.parse(raw || '{}'); } catch { /* not JSON → leave j = {} */ }
|
|
23
23
|
|
|
24
|
+
function ensurePrivateDirectory(directory) {
|
|
25
|
+
const resolved = path.resolve(directory);
|
|
26
|
+
const parsed = path.parse(resolved);
|
|
27
|
+
const parts = resolved.slice(parsed.root.length).split(path.sep).filter(Boolean);
|
|
28
|
+
const privateRoot = parts.indexOf('.handmux');
|
|
29
|
+
if (privateRoot < 0) {
|
|
30
|
+
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
for (let i = privateRoot; i < parts.length; i++) {
|
|
34
|
+
const current = path.join(parsed.root, ...parts.slice(0, i + 1));
|
|
35
|
+
fs.mkdirSync(current, { recursive: true, mode: 0o700 });
|
|
36
|
+
fs.chmodSync(current, 0o700);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
24
40
|
// One rate-limit window → our shape, or undefined if the field is absent (rate_limits only appears for
|
|
25
41
|
// Pro/Max plans, and only after a session's first API response).
|
|
26
42
|
function win(o) {
|
|
@@ -48,7 +64,8 @@ if (file) {
|
|
|
48
64
|
rateLimits,
|
|
49
65
|
};
|
|
50
66
|
if (snap.context === undefined) delete snap.context;
|
|
51
|
-
|
|
67
|
+
ensurePrivateDirectory(path.dirname(file));
|
|
68
|
+
if (fs.existsSync(file)) fs.chmodSync(file, 0o600);
|
|
52
69
|
let previousHasQuota = false;
|
|
53
70
|
try {
|
|
54
71
|
const previous = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
@@ -58,12 +75,13 @@ if (file) {
|
|
|
58
75
|
// previous machine-wide quota until a real rate-limit payload refreshes it instead of flashing empty.
|
|
59
76
|
if (Object.keys(rateLimits).length > 0) {
|
|
60
77
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
61
|
-
fs.writeFileSync(tmp, JSON.stringify(snap));
|
|
78
|
+
fs.writeFileSync(tmp, JSON.stringify(snap), { mode: 0o600 });
|
|
62
79
|
fs.renameSync(tmp, file); // atomic: concurrent statuslines (multiple sessions) can't tear the snapshot
|
|
80
|
+
fs.chmodSync(file, 0o600);
|
|
63
81
|
} else if (!previousHasQuota) {
|
|
64
82
|
// Create the initial "capturer active, awaiting data" marker only if no concurrent session has
|
|
65
83
|
// already published a real quota snapshot. An empty session can therefore never win that race.
|
|
66
|
-
try { fs.writeFileSync(file, JSON.stringify(snap), { flag: 'wx' }); } catch { /* file now exists */ }
|
|
84
|
+
try { fs.writeFileSync(file, JSON.stringify(snap), { flag: 'wx', mode: 0o600 }); } catch { /* file now exists */ }
|
|
67
85
|
}
|
|
68
86
|
|
|
69
87
|
// Per-session context snapshot. The global file above is last-writer-wins across ALL sessions, so it
|
|
@@ -73,12 +91,13 @@ if (file) {
|
|
|
73
91
|
const sid = typeof j.session_id === 'string' ? j.session_id : null;
|
|
74
92
|
if (sid && /^[\w-]+$/.test(sid) && snap.context) {
|
|
75
93
|
const cdir = path.join(path.dirname(file), 'context');
|
|
76
|
-
|
|
94
|
+
ensurePrivateDirectory(cdir);
|
|
77
95
|
const cfile = path.join(cdir, `${sid}.json`);
|
|
78
96
|
const csnap = { sessionId: sid, model: snap.model, usedPercent: snap.context.usedPercent, updatedAt: snap.updatedAt };
|
|
79
97
|
const ctmp = `${cfile}.${process.pid}.tmp`;
|
|
80
|
-
fs.writeFileSync(ctmp, JSON.stringify(csnap));
|
|
98
|
+
fs.writeFileSync(ctmp, JSON.stringify(csnap), { mode: 0o600 });
|
|
81
99
|
fs.renameSync(ctmp, cfile);
|
|
100
|
+
fs.chmodSync(cfile, 0o600);
|
|
82
101
|
// Best-effort prune of stale session files (ended sessions never clean up after themselves) so the
|
|
83
102
|
// dir can't grow without bound. A day is well past any live session's last statusLine render.
|
|
84
103
|
try {
|
|
@@ -86,7 +105,10 @@ if (file) {
|
|
|
86
105
|
for (const nm of fs.readdirSync(cdir)) {
|
|
87
106
|
if (!nm.endsWith('.json')) continue;
|
|
88
107
|
const fp = path.join(cdir, nm);
|
|
89
|
-
try {
|
|
108
|
+
try {
|
|
109
|
+
fs.chmodSync(fp, 0o600);
|
|
110
|
+
if (fs.statSync(fp).mtimeMs < cutoff) fs.unlinkSync(fp);
|
|
111
|
+
} catch { /* skip */ }
|
|
90
112
|
}
|
|
91
113
|
} catch { /* prune is best-effort */ }
|
|
92
114
|
}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// or corrupt the file. Best-effort throughout and silent — the hook is fire-and-forget and must never
|
|
15
15
|
// fail Claude (the shell wrapper swallows errors and always exits 0).
|
|
16
16
|
const fs = require('node:fs');
|
|
17
|
+
const path = require('node:path');
|
|
17
18
|
|
|
18
19
|
const [, , file, pane, src, ts, host = ''] = process.argv;
|
|
19
20
|
if (!file || !pane || !src) process.exit(0);
|
|
@@ -34,7 +35,26 @@ const nap = (ms) => {
|
|
|
34
35
|
catch { const end = Date.now() + ms; while (Date.now() < end) { /* spin */ } }
|
|
35
36
|
};
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
function ensurePrivateDirectory(directory) {
|
|
39
|
+
const resolved = path.resolve(directory);
|
|
40
|
+
const parsed = path.parse(resolved);
|
|
41
|
+
const parts = resolved.slice(parsed.root.length).split(path.sep).filter(Boolean);
|
|
42
|
+
const privateRoot = parts.indexOf('.handmux');
|
|
43
|
+
if (privateRoot < 0) {
|
|
44
|
+
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
for (let i = privateRoot; i < parts.length; i++) {
|
|
48
|
+
const current = path.join(parsed.root, ...parts.slice(0, i + 1));
|
|
49
|
+
fs.mkdirSync(current, { recursive: true, mode: 0o700 });
|
|
50
|
+
fs.chmodSync(current, 0o700);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
ensurePrivateDirectory(path.dirname(file));
|
|
56
|
+
if (fs.existsSync(file)) fs.chmodSync(file, 0o600);
|
|
57
|
+
} catch { /* ignore */ }
|
|
38
58
|
|
|
39
59
|
function update() {
|
|
40
60
|
let obj = {};
|
|
@@ -61,14 +81,15 @@ function update() {
|
|
|
61
81
|
obj[pane] = { ts: Number(ts) || 0, src, host, payload };
|
|
62
82
|
}
|
|
63
83
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
64
|
-
fs.writeFileSync(tmp, JSON.stringify(obj));
|
|
84
|
+
fs.writeFileSync(tmp, JSON.stringify(obj), { mode: 0o600 });
|
|
65
85
|
fs.renameSync(tmp, file); // atomic: a torn write can't corrupt the file
|
|
86
|
+
fs.chmodSync(file, 0o600);
|
|
66
87
|
}
|
|
67
88
|
|
|
68
89
|
const lock = `${file}.lock`;
|
|
69
90
|
let held = false;
|
|
70
91
|
for (let i = 0; i < 60 && !held; i++) { // ~0.9s budget, then write lockless (best-effort)
|
|
71
|
-
try { fs.closeSync(fs.openSync(lock, 'wx')); held = true; } // O_EXCL → atomic "I hold it"
|
|
92
|
+
try { fs.closeSync(fs.openSync(lock, 'wx', 0o600)); held = true; } // O_EXCL → atomic "I hold it"
|
|
72
93
|
catch {
|
|
73
94
|
try { if (Date.now() - fs.statSync(lock).mtimeMs > 3000) fs.unlinkSync(lock); } catch { /* steal a stale lock */ }
|
|
74
95
|
nap(15);
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "handmux",
|
|
3
|
+
"version": "0.24.0",
|
|
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
|
+
"type": "module",
|
|
6
|
+
"license": "AGPL-3.0-only",
|
|
7
|
+
"author": "yuanyuanzijin",
|
|
8
|
+
"homepage": "https://handmux.com",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/handmux/handmux.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/handmux/handmux/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"tmux",
|
|
18
|
+
"mobile",
|
|
19
|
+
"terminal",
|
|
20
|
+
"claude-code",
|
|
21
|
+
"remote",
|
|
22
|
+
"pwa"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=20"
|
|
26
|
+
},
|
|
27
|
+
"bin": {
|
|
28
|
+
"handmux": "bin/handmux.js"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"bin/handmux.js",
|
|
32
|
+
"dist",
|
|
33
|
+
"README.md",
|
|
34
|
+
"README.zh-CN.md",
|
|
35
|
+
"LICENSE"
|
|
36
|
+
],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"start": "npm run build:server && node dist/bin/handmux.js start",
|
|
39
|
+
"dev": "npm run build:server && node dist/bin/handmux.js start --foreground",
|
|
40
|
+
"handmux": "npm run build:server && node dist/bin/handmux.js",
|
|
41
|
+
"build:server": "node scripts/build-server.mjs",
|
|
42
|
+
"bundle": "node scripts/bundle-web.mjs",
|
|
43
|
+
"prepack": "npm run bundle && npm run build:server",
|
|
44
|
+
"typecheck:source": "node scripts/check-typescript-product-source.mjs",
|
|
45
|
+
"typecheck": "tsc --project tsconfig.json",
|
|
46
|
+
"test": "npm run build:server && vitest run",
|
|
47
|
+
"test:pack": "node scripts/pack-smoke.mjs",
|
|
48
|
+
"test:workspace-host": "npm run build:server && HANDMUX_WORKSPACE_HOST=1 vitest run test/workspaceHost.test.js",
|
|
49
|
+
"test:workspace-docker": "npm run build:server && HANDMUX_WORKSPACE_DOCKER=1 vitest run test/workspaceDocker.test.js"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@clack/prompts": "0.11.0",
|
|
53
|
+
"busboy": "^1.6.0",
|
|
54
|
+
"compression": "^1.8.1",
|
|
55
|
+
"express": "^4.19.2",
|
|
56
|
+
"testcafe-hammerhead": "31.7.8",
|
|
57
|
+
"tunlite": "^0.10.0",
|
|
58
|
+
"web-push": "^3.6.7",
|
|
59
|
+
"ws": "^8.21.0"
|
|
60
|
+
},
|
|
61
|
+
"optionalDependencies": {
|
|
62
|
+
"qrcode-terminal": "^0.12.0"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@types/busboy": "^1.5.4",
|
|
66
|
+
"@types/compression": "^1.8.1",
|
|
67
|
+
"@types/express": "4.17.25",
|
|
68
|
+
"@types/node": "20.19.43",
|
|
69
|
+
"@types/supertest": "7.2.1",
|
|
70
|
+
"@types/web-push": "^3.6.4",
|
|
71
|
+
"@types/ws": "^8.18.1",
|
|
72
|
+
"supertest": "^7.0.0",
|
|
73
|
+
"typescript": "6.0.3",
|
|
74
|
+
"vitest": "^2.0.0"
|
|
75
|
+
},
|
|
76
|
+
"whatsNew": [
|
|
77
|
+
{
|
|
78
|
+
"version": "0.24.0",
|
|
79
|
+
"date": "2026-08-11",
|
|
80
|
+
"zh": "Codex 任务进度与 Goal 原生上线",
|
|
81
|
+
"en": "Native Codex task progress and Goals"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"version": "0.23.0",
|
|
85
|
+
"date": "2026-08-09",
|
|
86
|
+
"zh": "Codex 托管对话正式上线",
|
|
87
|
+
"en": "Managed Codex chat is here"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"version": "0.22.1",
|
|
91
|
+
"date": "2026-08-04",
|
|
92
|
+
"zh": "网页宽度与网站版本分开控制",
|
|
93
|
+
"en": "Separate page width and site-version controls"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"version": "0.22.0",
|
|
97
|
+
"date": "2026-08-03",
|
|
98
|
+
"zh": "全屏设置 · 窗口与分屏管理更清晰",
|
|
99
|
+
"en": "Full-screen Settings · clearer window and pane management"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"version": "0.21.0",
|
|
103
|
+
"date": "2026-08-03",
|
|
104
|
+
"zh": "网页预览:手机直连、电脑代理与静态目录",
|
|
105
|
+
"en": "Web preview: direct, computer proxy, and static folders"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"version": "0.20.3",
|
|
109
|
+
"date": "2026-08-01",
|
|
110
|
+
"zh": "实时终端显示更稳定流畅",
|
|
111
|
+
"en": "More stable, smoother live terminals"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"version": "0.20.2",
|
|
115
|
+
"date": "2026-07-27",
|
|
116
|
+
"zh": "实时终端长时间运行更流畅",
|
|
117
|
+
"en": "Smoother long-running live terminals"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"version": "0.20.1",
|
|
121
|
+
"date": "2026-07-26",
|
|
122
|
+
"zh": "聊天发送修复 · 电脑键盘不中断",
|
|
123
|
+
"en": "Reliable chat sending · uninterrupted desktop input"
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|