botmux 2.13.2 → 2.15.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/cli.js +56 -11
- package/dist/cli.js.map +1 -1
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +10 -4
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +65 -3
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/dashboard-rows.d.ts.map +1 -1
- package/dist/core/dashboard-rows.js +6 -1
- package/dist/core/dashboard-rows.js.map +1 -1
- package/dist/core/scheduler.d.ts +1 -0
- package/dist/core/scheduler.d.ts.map +1 -1
- package/dist/core/scheduler.js +1 -0
- package/dist/core/scheduler.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +90 -52
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/types.d.ts +18 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +14 -3
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +22 -22
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +185 -90
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/operator-selector.d.ts +17 -0
- package/dist/dashboard/operator-selector.d.ts.map +1 -0
- package/dist/dashboard/operator-selector.js +37 -0
- package/dist/dashboard/operator-selector.js.map +1 -0
- package/dist/dashboard/web/groups.d.ts.map +1 -1
- package/dist/dashboard/web/groups.js +61 -7
- package/dist/dashboard/web/groups.js.map +1 -1
- package/dist/dashboard-web/app.js +60 -53
- package/dist/dashboard-web/style.css +10 -1
- package/dist/dashboard.js +119 -34
- package/dist/dashboard.js.map +1 -1
- package/dist/im/lark/card-handler.js +8 -8
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +27 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +102 -8
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts +42 -4
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +121 -47
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/services/groups-store.d.ts +22 -0
- package/dist/services/groups-store.d.ts.map +1 -1
- package/dist/services/groups-store.js +39 -1
- package/dist/services/groups-store.js.map +1 -1
- package/dist/services/schedule-store.d.ts +1 -0
- package/dist/services/schedule-store.d.ts.map +1 -1
- package/dist/services/schedule-store.js +1 -0
- package/dist/services/schedule-store.js.map +1 -1
- package/dist/services/session-store.d.ts +12 -0
- package/dist/services/session-store.d.ts.map +1 -1
- package/dist/services/session-store.js +19 -2
- package/dist/services/session-store.js.map +1 -1
- package/dist/setup/detect-platform.d.ts +14 -0
- package/dist/setup/detect-platform.d.ts.map +1 -0
- package/dist/setup/detect-platform.js +139 -0
- package/dist/setup/detect-platform.js.map +1 -0
- package/dist/setup/ensure-fonts.d.ts +13 -0
- package/dist/setup/ensure-fonts.d.ts.map +1 -0
- package/dist/setup/ensure-fonts.js +225 -0
- package/dist/setup/ensure-fonts.js.map +1 -0
- package/dist/setup/ensure-tmux.d.ts +11 -0
- package/dist/setup/ensure-tmux.d.ts.map +1 -0
- package/dist/setup/ensure-tmux.js +151 -0
- package/dist/setup/ensure-tmux.js.map +1 -0
- package/dist/setup/index.d.ts +9 -0
- package/dist/setup/index.d.ts.map +1 -0
- package/dist/setup/index.js +35 -0
- package/dist/setup/index.js.map +1 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/bot-mention-dedup.d.ts +26 -0
- package/dist/utils/bot-mention-dedup.d.ts.map +1 -0
- package/dist/utils/bot-mention-dedup.js +56 -0
- package/dist/utils/bot-mention-dedup.js.map +1 -0
- package/dist/utils/screenshot-renderer.d.ts.map +1 -1
- package/dist/utils/screenshot-renderer.js +12 -5
- package/dist/utils/screenshot-renderer.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-platform.d.ts","sourceRoot":"","sources":["../../src/setup/detect-platform.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,QAAQ,GAChB,QAAQ,GAAG,QAAQ,GACnB,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,WAAW,GACpD,MAAM,GAAG,SAAS,GAClB,QAAQ,GACR,UAAU,GAAG,eAAe,GAAG,qBAAqB,GACpD,SAAS,CAAC;AAEd,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,OAAO,GACP,KAAK,GACL,KAAK,GAAG,KAAK,GACb,QAAQ,GACR,QAAQ,GACR,KAAK,GACL,SAAS,CAAC;AAEd,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;IACjC,MAAM,EAAE,QAAQ,CAAC;IACjB,uEAAuE;IACvE,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,+EAA+E;IAC/E,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AA8GD,wBAAgB,cAAc,IAAI,YAAY,CAY7C"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform / package-manager detection for the auto-install flow.
|
|
3
|
+
*
|
|
4
|
+
* All probes are best-effort and synchronous; failures degrade gracefully
|
|
5
|
+
* to "unknown" so callers can route to a manual-install message.
|
|
6
|
+
*/
|
|
7
|
+
import { execSync } from 'node:child_process';
|
|
8
|
+
import { readFileSync } from 'node:fs';
|
|
9
|
+
function which(cmd) {
|
|
10
|
+
try {
|
|
11
|
+
execSync(`command -v ${cmd}`, { stdio: 'ignore' });
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function readOsRelease() {
|
|
19
|
+
try {
|
|
20
|
+
const raw = readFileSync('/etc/os-release', 'utf-8');
|
|
21
|
+
const out = {};
|
|
22
|
+
for (const line of raw.split('\n')) {
|
|
23
|
+
const m = line.match(/^([A-Z_]+)=(.*)$/);
|
|
24
|
+
if (!m)
|
|
25
|
+
continue;
|
|
26
|
+
let val = m[2];
|
|
27
|
+
if (val.startsWith('"') && val.endsWith('"'))
|
|
28
|
+
val = val.slice(1, -1);
|
|
29
|
+
out[m[1]] = val;
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function detectDistro() {
|
|
38
|
+
if (process.platform !== 'linux')
|
|
39
|
+
return 'unknown';
|
|
40
|
+
const rel = readOsRelease();
|
|
41
|
+
const id = (rel['ID'] ?? '').toLowerCase();
|
|
42
|
+
const idLike = (rel['ID_LIKE'] ?? '').toLowerCase();
|
|
43
|
+
const candidates = [id, ...idLike.split(/\s+/)].filter(Boolean);
|
|
44
|
+
for (const c of candidates) {
|
|
45
|
+
if (c === 'debian' || c === 'ubuntu')
|
|
46
|
+
return c;
|
|
47
|
+
if (c === 'fedora' || c === 'rhel' || c === 'centos' || c === 'rocky' || c === 'almalinux') {
|
|
48
|
+
return c;
|
|
49
|
+
}
|
|
50
|
+
if (c === 'arch' || c === 'manjaro')
|
|
51
|
+
return c;
|
|
52
|
+
if (c === 'alpine')
|
|
53
|
+
return 'alpine';
|
|
54
|
+
if (c === 'opensuse' || c === 'opensuse-leap' || c === 'opensuse-tumbleweed')
|
|
55
|
+
return c;
|
|
56
|
+
}
|
|
57
|
+
return 'unknown';
|
|
58
|
+
}
|
|
59
|
+
function detectPackageManagers(distro) {
|
|
60
|
+
const out = [];
|
|
61
|
+
// User-scope managers first. brew on Linux works the same as on macOS.
|
|
62
|
+
if (which('brew'))
|
|
63
|
+
out.push('brew');
|
|
64
|
+
if (which('conda') || which('mamba'))
|
|
65
|
+
out.push('conda');
|
|
66
|
+
// System managers — order by distro preference, but only include if the binary is present.
|
|
67
|
+
if (process.platform === 'linux') {
|
|
68
|
+
const tryAdd = (bin, pm) => {
|
|
69
|
+
if (which(bin))
|
|
70
|
+
out.push(pm);
|
|
71
|
+
};
|
|
72
|
+
switch (distro) {
|
|
73
|
+
case 'debian':
|
|
74
|
+
case 'ubuntu':
|
|
75
|
+
tryAdd('apt-get', 'apt');
|
|
76
|
+
break;
|
|
77
|
+
case 'fedora':
|
|
78
|
+
case 'rhel':
|
|
79
|
+
case 'centos':
|
|
80
|
+
case 'rocky':
|
|
81
|
+
case 'almalinux':
|
|
82
|
+
tryAdd('dnf', 'dnf');
|
|
83
|
+
if (!out.includes('dnf'))
|
|
84
|
+
tryAdd('yum', 'yum');
|
|
85
|
+
break;
|
|
86
|
+
case 'arch':
|
|
87
|
+
case 'manjaro':
|
|
88
|
+
tryAdd('pacman', 'pacman');
|
|
89
|
+
break;
|
|
90
|
+
case 'alpine':
|
|
91
|
+
tryAdd('apk', 'apk');
|
|
92
|
+
break;
|
|
93
|
+
case 'opensuse':
|
|
94
|
+
case 'opensuse-leap':
|
|
95
|
+
case 'opensuse-tumbleweed':
|
|
96
|
+
tryAdd('zypper', 'zypper');
|
|
97
|
+
break;
|
|
98
|
+
default:
|
|
99
|
+
// Unknown distro — try generic probes so we still pick something up.
|
|
100
|
+
for (const [bin, pm] of [
|
|
101
|
+
['apt-get', 'apt'], ['dnf', 'dnf'], ['yum', 'yum'],
|
|
102
|
+
['pacman', 'pacman'], ['apk', 'apk'], ['zypper', 'zypper'],
|
|
103
|
+
]) {
|
|
104
|
+
if (which(bin))
|
|
105
|
+
out.push(pm);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (out.length === 0)
|
|
110
|
+
out.push('unknown');
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
function detectPasswordlessSudo() {
|
|
114
|
+
if (process.getuid && process.getuid() === 0)
|
|
115
|
+
return true; // already root
|
|
116
|
+
if (!which('sudo'))
|
|
117
|
+
return false;
|
|
118
|
+
try {
|
|
119
|
+
execSync('sudo -n true', { stdio: 'ignore', timeout: 3000 });
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
export function detectPlatform() {
|
|
127
|
+
const os = process.platform === 'darwin' ? 'darwin'
|
|
128
|
+
: process.platform === 'linux' ? 'linux' : 'other';
|
|
129
|
+
const distro = detectDistro();
|
|
130
|
+
return {
|
|
131
|
+
os,
|
|
132
|
+
distro,
|
|
133
|
+
packageManagers: detectPackageManagers(distro),
|
|
134
|
+
isRoot: !!(process.getuid && process.getuid() === 0),
|
|
135
|
+
hasTty: !!(process.stdin.isTTY && process.stdout.isTTY),
|
|
136
|
+
passwordlessSudo: detectPasswordlessSudo(),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=detect-platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-platform.js","sourceRoot":"","sources":["../../src/setup/detect-platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type PlatformInfo } from './detect-platform.js';
|
|
2
|
+
export interface FontResult {
|
|
3
|
+
/** The directory we downloaded into (or would have, if any download was needed). */
|
|
4
|
+
fontDir: string;
|
|
5
|
+
/** Categories we successfully ensured (system OR downloaded). */
|
|
6
|
+
ready: string[];
|
|
7
|
+
/** Categories we failed to ensure (download failed, etc.). Non-fatal. */
|
|
8
|
+
failed: string[];
|
|
9
|
+
}
|
|
10
|
+
/** Public: paths the screenshot-renderer should also probe. */
|
|
11
|
+
export declare function botmuxFontDir(): string;
|
|
12
|
+
export declare function ensureFonts(info?: PlatformInfo): Promise<FontResult>;
|
|
13
|
+
//# sourceMappingURL=ensure-fonts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure-fonts.d.ts","sourceRoot":"","sources":["../../src/setup/ensure-fonts.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzE,MAAM,WAAW,UAAU;IACzB,oFAAoF;IACpF,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yEAAyE;IACzE,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAkFD,+DAA+D;AAC/D,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AA8FD,wBAAsB,WAAW,CAAC,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CAyB1E"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure the screenshot-renderer (`@napi-rs/canvas`) has CJK / Latin / emoji
|
|
3
|
+
* fonts available. Downloads missing categories from GitHub release
|
|
4
|
+
* artifacts to `~/.botmux/fonts/` so registration (`GlobalFonts.registerFromPath`)
|
|
5
|
+
* can find them at runtime.
|
|
6
|
+
*
|
|
7
|
+
* macOS is skipped entirely — PingFang + Menlo + Apple Color Emoji are
|
|
8
|
+
* preinstalled.
|
|
9
|
+
*
|
|
10
|
+
* Failures are NOT fatal: missing fonts only degrade the screenshot rendered
|
|
11
|
+
* for Lark (CJK becomes tofu, emoji becomes monochrome). The daemon should
|
|
12
|
+
* still come up. Tmux is the load-bearing dep, fonts are nice-to-have.
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, mkdirSync, createWriteStream, statSync, unlinkSync, renameSync } from 'node:fs';
|
|
15
|
+
import { homedir } from 'node:os';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { get as httpsGet } from 'node:https';
|
|
18
|
+
import { detectPlatform } from './detect-platform.js';
|
|
19
|
+
const FONT_DIR = join(homedir(), '.botmux', 'fonts');
|
|
20
|
+
/** Download targets — pinned to specific release tags so the URLs don't rot.
|
|
21
|
+
*
|
|
22
|
+
* Sources (all permissive licenses, GitHub-hosted):
|
|
23
|
+
* - notofonts/noto-cjk @ Sans2.004 (Mono variant) — OFL
|
|
24
|
+
* - JetBrains/JetBrainsMono @ v2.304 — Apache 2.0 (replaces DejaVu since
|
|
25
|
+
* DejaVu only ships .tar.bz2 release artifacts, not individual TTFs)
|
|
26
|
+
* - googlefonts/noto-emoji @ v2.047 — OFL
|
|
27
|
+
*/
|
|
28
|
+
const FONT_SPECS = [
|
|
29
|
+
{
|
|
30
|
+
category: 'CJK',
|
|
31
|
+
files: [
|
|
32
|
+
{
|
|
33
|
+
name: 'NotoSansMonoCJKsc-Regular.otf',
|
|
34
|
+
url: 'https://github.com/notofonts/noto-cjk/raw/Sans2.004/Sans/Mono/NotoSansMonoCJKsc-Regular.otf',
|
|
35
|
+
minBytes: 1_000_000,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'NotoSansMonoCJKsc-Bold.otf',
|
|
39
|
+
url: 'https://github.com/notofonts/noto-cjk/raw/Sans2.004/Sans/Mono/NotoSansMonoCJKsc-Bold.otf',
|
|
40
|
+
minBytes: 1_000_000,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
systemPaths: [
|
|
44
|
+
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
|
|
45
|
+
'/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc',
|
|
46
|
+
'/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc',
|
|
47
|
+
'/usr/share/fonts/opentype/noto/NotoSansMonoCJK-Regular.ttc',
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
category: 'Latin',
|
|
52
|
+
files: [
|
|
53
|
+
{
|
|
54
|
+
name: 'JetBrainsMono-Regular.ttf',
|
|
55
|
+
url: 'https://github.com/JetBrains/JetBrainsMono/raw/v2.304/fonts/ttf/JetBrainsMono-Regular.ttf',
|
|
56
|
+
minBytes: 100_000,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'JetBrainsMono-Bold.ttf',
|
|
60
|
+
url: 'https://github.com/JetBrains/JetBrainsMono/raw/v2.304/fonts/ttf/JetBrainsMono-Bold.ttf',
|
|
61
|
+
minBytes: 100_000,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
systemPaths: [
|
|
65
|
+
'/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf',
|
|
66
|
+
'/usr/share/fonts/dejavu/DejaVuSansMono.ttf',
|
|
67
|
+
'/usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf',
|
|
68
|
+
'/usr/share/fonts/liberation/LiberationMono-Regular.ttf',
|
|
69
|
+
'/usr/share/fonts/truetype/jetbrains-mono/JetBrainsMono-Regular.ttf',
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
category: 'Emoji',
|
|
74
|
+
files: [
|
|
75
|
+
{
|
|
76
|
+
name: 'NotoColorEmoji.ttf',
|
|
77
|
+
url: 'https://github.com/googlefonts/noto-emoji/raw/v2.047/fonts/NotoColorEmoji.ttf',
|
|
78
|
+
minBytes: 5_000_000,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
systemPaths: [
|
|
82
|
+
'/usr/share/fonts/truetype/noto/NotoColorEmoji.ttf',
|
|
83
|
+
'/usr/share/fonts/noto/NotoColorEmoji.ttf',
|
|
84
|
+
'/usr/share/fonts/google-noto-emoji/NotoColorEmoji.ttf',
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
/** Public: paths the screenshot-renderer should also probe. */
|
|
89
|
+
export function botmuxFontDir() {
|
|
90
|
+
return FONT_DIR;
|
|
91
|
+
}
|
|
92
|
+
function categoryAlreadyOk(spec) {
|
|
93
|
+
// 1. System path present?
|
|
94
|
+
if (spec.systemPaths.some(p => existsSync(p)))
|
|
95
|
+
return true;
|
|
96
|
+
// 2. We already downloaded it on a prior run?
|
|
97
|
+
return spec.files.every(f => {
|
|
98
|
+
const p = join(FONT_DIR, f.name);
|
|
99
|
+
if (!existsSync(p))
|
|
100
|
+
return false;
|
|
101
|
+
try {
|
|
102
|
+
return statSync(p).size >= f.minBytes;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/** Download a URL to disk, following redirects (GitHub raw → CDN).
|
|
110
|
+
* All FONT_SPECS URLs are https, so we don't bother with an http fallback.
|
|
111
|
+
* Hard timeout (default 60s) covers connect + transfer; on expiry the
|
|
112
|
+
* request is destroyed and the partial file is unlinked. */
|
|
113
|
+
function downloadFile(url, destPath, timeoutMs = 60_000) {
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
const tmp = destPath + '.part';
|
|
116
|
+
let settled = false;
|
|
117
|
+
let activeReq = null;
|
|
118
|
+
const cleanup = () => {
|
|
119
|
+
try {
|
|
120
|
+
unlinkSync(tmp);
|
|
121
|
+
}
|
|
122
|
+
catch { /* may not exist */ }
|
|
123
|
+
};
|
|
124
|
+
const finish = (err) => {
|
|
125
|
+
if (settled)
|
|
126
|
+
return;
|
|
127
|
+
settled = true;
|
|
128
|
+
clearTimeout(timer);
|
|
129
|
+
if (activeReq)
|
|
130
|
+
try {
|
|
131
|
+
activeReq.destroy();
|
|
132
|
+
}
|
|
133
|
+
catch { /* ignore */ }
|
|
134
|
+
if (err) {
|
|
135
|
+
cleanup();
|
|
136
|
+
reject(err);
|
|
137
|
+
}
|
|
138
|
+
else
|
|
139
|
+
resolve();
|
|
140
|
+
};
|
|
141
|
+
const timer = setTimeout(() => finish(new Error(`下载超时 (${timeoutMs}ms): ${url}`)), timeoutMs);
|
|
142
|
+
const followRedirect = (current, hops) => {
|
|
143
|
+
if (hops > 5)
|
|
144
|
+
return finish(new Error(`太多重定向: ${url}`));
|
|
145
|
+
const u = new URL(current);
|
|
146
|
+
if (u.protocol !== 'https:')
|
|
147
|
+
return finish(new Error(`仅支持 https://, got ${u.protocol} for ${current}`));
|
|
148
|
+
activeReq = httpsGet(u, { headers: { 'user-agent': 'botmux-font-installer' } }, (res) => {
|
|
149
|
+
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
150
|
+
res.resume();
|
|
151
|
+
followRedirect(new URL(res.headers.location, u).toString(), hops + 1);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (res.statusCode !== 200) {
|
|
155
|
+
res.resume();
|
|
156
|
+
return finish(new Error(`HTTP ${res.statusCode} for ${current}`));
|
|
157
|
+
}
|
|
158
|
+
const out = createWriteStream(tmp);
|
|
159
|
+
res.pipe(out);
|
|
160
|
+
out.on('error', (err) => finish(err));
|
|
161
|
+
out.on('finish', () => {
|
|
162
|
+
out.close(() => {
|
|
163
|
+
try {
|
|
164
|
+
renameSync(tmp, destPath);
|
|
165
|
+
finish();
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
finish(err);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
activeReq.on('error', (err) => finish(err));
|
|
174
|
+
};
|
|
175
|
+
followRedirect(url, 0);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
async function downloadCategory(spec) {
|
|
179
|
+
if (!existsSync(FONT_DIR))
|
|
180
|
+
mkdirSync(FONT_DIR, { recursive: true });
|
|
181
|
+
for (const f of spec.files) {
|
|
182
|
+
const dest = join(FONT_DIR, f.name);
|
|
183
|
+
// Skip if already present and big enough.
|
|
184
|
+
try {
|
|
185
|
+
if (existsSync(dest) && statSync(dest).size >= f.minBytes)
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
catch { /* fall through to redownload */ }
|
|
189
|
+
console.log(` 下载 ${spec.category}: ${f.name} ...`);
|
|
190
|
+
await downloadFile(f.url, dest);
|
|
191
|
+
const sz = statSync(dest).size;
|
|
192
|
+
if (sz < f.minBytes) {
|
|
193
|
+
try {
|
|
194
|
+
unlinkSync(dest);
|
|
195
|
+
}
|
|
196
|
+
catch { /* ignore */ }
|
|
197
|
+
throw new Error(`${f.name} 下载完毕但大小异常 (${sz} < ${f.minBytes})`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
export async function ensureFonts(info) {
|
|
202
|
+
const platform = info ?? detectPlatform();
|
|
203
|
+
const result = { fontDir: FONT_DIR, ready: [], failed: [] };
|
|
204
|
+
// macOS: skip — system fonts cover everything we need.
|
|
205
|
+
if (platform.os === 'darwin') {
|
|
206
|
+
result.ready.push('CJK', 'Latin', 'Emoji');
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
209
|
+
for (const spec of FONT_SPECS) {
|
|
210
|
+
if (categoryAlreadyOk(spec)) {
|
|
211
|
+
result.ready.push(spec.category);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
await downloadCategory(spec);
|
|
216
|
+
result.ready.push(spec.category);
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
console.warn(`⚠️ 字体下载失败 [${spec.category}]: ${err?.message ?? err}`);
|
|
220
|
+
result.failed.push(spec.category);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=ensure-fonts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure-fonts.js","sourceRoot":"","sources":["../../src/setup/ensure-fonts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type PackageManager, type PlatformInfo } from './detect-platform.js';
|
|
2
|
+
export interface TmuxResult {
|
|
3
|
+
installed: boolean;
|
|
4
|
+
version?: string;
|
|
5
|
+
/** True iff we ran an installer (vs. tmux was already present). */
|
|
6
|
+
freshInstall: boolean;
|
|
7
|
+
/** Which strategy actually ran the install. */
|
|
8
|
+
strategy?: PackageManager;
|
|
9
|
+
}
|
|
10
|
+
export declare function ensureTmux(info?: PlatformInfo): Promise<TmuxResult>;
|
|
11
|
+
//# sourceMappingURL=ensure-tmux.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure-tmux.d.ts","sourceRoot":"","sources":["../../src/setup/ensure-tmux.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAkB,KAAK,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE9F,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,YAAY,EAAE,OAAO,CAAC;IACtB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AA0ED,wBAAsB,UAAU,CAAC,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CA2DzE"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure tmux is installed before the daemon starts. Strategy (first one
|
|
3
|
+
* that fits wins):
|
|
4
|
+
*
|
|
5
|
+
* 1. Already installed → done.
|
|
6
|
+
* 2. brew available → `brew install tmux` (no sudo)
|
|
7
|
+
* 3. conda/mamba available → `conda install -y -c conda-forge tmux` (no sudo)
|
|
8
|
+
* 4. Linux + system pkg manager:
|
|
9
|
+
* a. NOPASSWD sudo or running as root → run non-interactively
|
|
10
|
+
* b. Has TTY → run interactively (sudo will prompt for password)
|
|
11
|
+
* c. No TTY (autostart / pm2 fork) → skip and throw with manual command
|
|
12
|
+
* 5. Otherwise → throw with manual command.
|
|
13
|
+
*
|
|
14
|
+
* The caller (cli.ts) treats a thrown error as fatal: tmux is non-negotiable
|
|
15
|
+
* for the /adopt + multi-pane Web terminal experience, and the user explicitly
|
|
16
|
+
* opted into hard-fail-on-missing.
|
|
17
|
+
*/
|
|
18
|
+
import { execSync, spawnSync } from 'node:child_process';
|
|
19
|
+
import { detectPlatform } from './detect-platform.js';
|
|
20
|
+
function probeTmuxVersion() {
|
|
21
|
+
try {
|
|
22
|
+
const out = execSync('tmux -V', { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 3000 });
|
|
23
|
+
return out.trim();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Wrap a system command with the appropriate sudo prefix for the current
|
|
30
|
+
* platform context, or return undefined if we cannot escalate (no
|
|
31
|
+
* passwordless sudo and no TTY to prompt on). */
|
|
32
|
+
function sudoPrefix(cmd, info) {
|
|
33
|
+
if (info.isRoot)
|
|
34
|
+
return cmd;
|
|
35
|
+
if (info.passwordlessSudo)
|
|
36
|
+
return ['sudo', '-n', ...cmd];
|
|
37
|
+
if (info.hasTty)
|
|
38
|
+
return ['sudo', ...cmd];
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
/** Build the install argv for a given package manager. Pure: returns argv[]
|
|
42
|
+
* ready for spawnSync, no side effects. Returns undefined if escalation
|
|
43
|
+
* isn't possible. */
|
|
44
|
+
function buildInstallArgv(pm, pkg, info) {
|
|
45
|
+
switch (pm) {
|
|
46
|
+
case 'brew': return ['brew', 'install', pkg];
|
|
47
|
+
case 'conda': return ['conda', 'install', '-y', '-c', 'conda-forge', pkg];
|
|
48
|
+
case 'apt': return sudoPrefix(['apt-get', 'install', '-y', pkg], info);
|
|
49
|
+
case 'dnf': return sudoPrefix(['dnf', 'install', '-y', pkg], info);
|
|
50
|
+
case 'yum': return sudoPrefix(['yum', 'install', '-y', pkg], info);
|
|
51
|
+
case 'pacman': return sudoPrefix(['pacman', '-S', '--noconfirm', pkg], info);
|
|
52
|
+
case 'apk': return sudoPrefix(['apk', 'add', pkg], info);
|
|
53
|
+
case 'zypper': return sudoPrefix(['zypper', 'install', '-y', pkg], info);
|
|
54
|
+
case 'unknown': return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** apt-get specifically needs an updated package list on minimal images
|
|
58
|
+
* before the install will find tmux. This is NOT part of buildInstallArgv
|
|
59
|
+
* (which is pure) — it runs once just before the apt install attempt.
|
|
60
|
+
* Failure here is non-fatal; the actual install will fail loudly if it
|
|
61
|
+
* can't find the package. */
|
|
62
|
+
function aptUpdateBeforeInstall(info) {
|
|
63
|
+
const argv = sudoPrefix(['apt-get', 'update'], info);
|
|
64
|
+
if (!argv)
|
|
65
|
+
return;
|
|
66
|
+
try {
|
|
67
|
+
spawnSync(argv[0], argv.slice(1), { stdio: 'inherit', timeout: 120_000 });
|
|
68
|
+
}
|
|
69
|
+
catch { /* best-effort */ }
|
|
70
|
+
}
|
|
71
|
+
/** Suggest the manual command we'd have run, for the failure message. */
|
|
72
|
+
function suggestManualCommand(pm, pkg) {
|
|
73
|
+
switch (pm) {
|
|
74
|
+
case 'brew': return `brew install ${pkg}`;
|
|
75
|
+
case 'conda': return `conda install -y -c conda-forge ${pkg}`;
|
|
76
|
+
case 'apt': return `sudo apt-get update && sudo apt-get install -y ${pkg}`;
|
|
77
|
+
case 'dnf': return `sudo dnf install -y ${pkg}`;
|
|
78
|
+
case 'yum': return `sudo yum install -y ${pkg}`;
|
|
79
|
+
case 'pacman': return `sudo pacman -S --noconfirm ${pkg}`;
|
|
80
|
+
case 'apk': return `sudo apk add ${pkg}`;
|
|
81
|
+
case 'zypper': return `sudo zypper install -y ${pkg}`;
|
|
82
|
+
default: return `(请手动安装 ${pkg})`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function runInstall(argv) {
|
|
86
|
+
const result = spawnSync(argv[0], argv.slice(1), {
|
|
87
|
+
stdio: 'inherit',
|
|
88
|
+
timeout: 10 * 60_000, // 10 min — apt-get on slow networks
|
|
89
|
+
});
|
|
90
|
+
return result.status === 0;
|
|
91
|
+
}
|
|
92
|
+
export async function ensureTmux(info) {
|
|
93
|
+
const platform = info ?? detectPlatform();
|
|
94
|
+
// Step 1: already installed?
|
|
95
|
+
const existing = probeTmuxVersion();
|
|
96
|
+
if (existing) {
|
|
97
|
+
return { installed: true, version: existing, freshInstall: false };
|
|
98
|
+
}
|
|
99
|
+
console.log('⚠️ tmux 未检测到,正在安装...');
|
|
100
|
+
// Step 2..4: walk the package-manager preference list.
|
|
101
|
+
const tried = [];
|
|
102
|
+
for (const pm of platform.packageManagers) {
|
|
103
|
+
if (pm === 'unknown')
|
|
104
|
+
continue;
|
|
105
|
+
const argv = buildInstallArgv(pm, 'tmux', platform);
|
|
106
|
+
if (!argv) {
|
|
107
|
+
tried.push(`${pm}(跳过:当前用户无 sudo 且无 TTY)`);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (pm === 'apt')
|
|
111
|
+
aptUpdateBeforeInstall(platform);
|
|
112
|
+
console.log(` 尝试 ${pm}: ${argv.join(' ')}`);
|
|
113
|
+
if (runInstall(argv)) {
|
|
114
|
+
const v = probeTmuxVersion();
|
|
115
|
+
if (v) {
|
|
116
|
+
console.log(`✅ tmux ${v} 安装完成 (via ${pm})`);
|
|
117
|
+
return { installed: true, version: v, freshInstall: true, strategy: pm };
|
|
118
|
+
}
|
|
119
|
+
tried.push(`${pm}(命令成功但 tmux -V 仍失败)`);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
tried.push(`${pm}(命令返回非零)`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Build a useful failure message with the most relevant manual command.
|
|
126
|
+
const preferred = platform.packageManagers.find(p => p !== 'unknown') ?? 'unknown';
|
|
127
|
+
const manual = suggestManualCommand(preferred, 'tmux');
|
|
128
|
+
const lines = [
|
|
129
|
+
'❌ 自动安装 tmux 失败',
|
|
130
|
+
'',
|
|
131
|
+
'已尝试:',
|
|
132
|
+
...tried.map(t => ` - ${t}`),
|
|
133
|
+
'',
|
|
134
|
+
'请手动安装后重试:',
|
|
135
|
+
` ${manual}`,
|
|
136
|
+
];
|
|
137
|
+
// macOS without Homebrew → guide the user to install brew first.
|
|
138
|
+
if (platform.os === 'darwin' && !platform.packageManagers.includes('brew')) {
|
|
139
|
+
lines.push('');
|
|
140
|
+
lines.push('macOS 推荐先安装 Homebrew:');
|
|
141
|
+
lines.push(' /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"');
|
|
142
|
+
lines.push('安装完成后重试 `botmux start`,会走 brew 自动装 tmux。');
|
|
143
|
+
}
|
|
144
|
+
if (!platform.hasTty && !platform.isRoot && !platform.passwordlessSudo && platform.os === 'linux') {
|
|
145
|
+
lines.push('');
|
|
146
|
+
lines.push('提示:当前不是交互式 TTY 且 sudo 需要密码,systemd/pm2 自启场景下无法弹密码。');
|
|
147
|
+
lines.push('请在 shell 中手动跑一次 `botmux start`,或配置 NOPASSWD sudoers 后再启用 autostart。');
|
|
148
|
+
}
|
|
149
|
+
throw new Error(lines.join('\n'));
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=ensure-tmux.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure-tmux.js","sourceRoot":"","sources":["../../src/setup/ensure-tmux.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type TmuxResult } from './ensure-tmux.js';
|
|
2
|
+
import { type FontResult } from './ensure-fonts.js';
|
|
3
|
+
export interface DependenciesReport {
|
|
4
|
+
tmux: TmuxResult;
|
|
5
|
+
fonts: FontResult;
|
|
6
|
+
}
|
|
7
|
+
export { botmuxFontDir } from './ensure-fonts.js';
|
|
8
|
+
export declare function ensureDependencies(): Promise<DependenciesReport>;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/setup/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEjE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,UAAU,CAAC;CACnB;AAED,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAsBtE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency bootstrap. Called from `botmux start` and `botmux restart` so
|
|
3
|
+
* a fresh machine that just `npm i -g botmux`'d gets tmux + screenshot fonts
|
|
4
|
+
* provisioned without manual setup.
|
|
5
|
+
*
|
|
6
|
+
* - tmux is required: a failed install throws so cli.ts can exit non-zero.
|
|
7
|
+
* - fonts are nice-to-have: failures only print a warning.
|
|
8
|
+
*/
|
|
9
|
+
import { detectPlatform } from './detect-platform.js';
|
|
10
|
+
import { ensureTmux } from './ensure-tmux.js';
|
|
11
|
+
import { ensureFonts } from './ensure-fonts.js';
|
|
12
|
+
export { botmuxFontDir } from './ensure-fonts.js';
|
|
13
|
+
export async function ensureDependencies() {
|
|
14
|
+
const platform = detectPlatform();
|
|
15
|
+
// tmux first — it's the load-bearing dep. Throws on failure.
|
|
16
|
+
const tmux = await ensureTmux(platform);
|
|
17
|
+
if (!tmux.freshInstall) {
|
|
18
|
+
console.log(`✓ tmux ${tmux.version} (existing)`);
|
|
19
|
+
}
|
|
20
|
+
// Fonts second — best-effort.
|
|
21
|
+
const fonts = await ensureFonts(platform);
|
|
22
|
+
if (fonts.failed.length === 0) {
|
|
23
|
+
if (platform.os === 'darwin') {
|
|
24
|
+
console.log('✓ 字体: 系统字体已就绪 (macOS)');
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.log(`✓ 字体: ${fonts.ready.join(' / ')} 已就绪`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
console.warn(`⚠️ 字体部分缺失: ${fonts.failed.join(' / ')} —— 飞书截图中相关字符可能渲染为方块`);
|
|
32
|
+
}
|
|
33
|
+
return { tmux, fonts };
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/setup/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAmB,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAmB,MAAM,mBAAmB,CAAC;AAOjE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAElC,6DAA6D;IAC7D,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,OAAO,aAAa,CAAC,CAAC;IACnD,CAAC;IAED,8BAA8B;IAC9B,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,IAAI,QAAQ,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC,eAAe,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC"}
|