botmux 3.18.4 → 3.18.6
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/.runtime-build-id +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +130 -21
- package/dist/cli.js.map +1 -1
- package/dist/core/binary-install-shape.d.ts +77 -0
- package/dist/core/binary-install-shape.d.ts.map +1 -0
- package/dist/core/binary-install-shape.js +117 -0
- package/dist/core/binary-install-shape.js.map +1 -0
- package/dist/core/binary-self-update.d.ts +82 -0
- package/dist/core/binary-self-update.d.ts.map +1 -0
- package/dist/core/binary-self-update.js +239 -0
- package/dist/core/binary-self-update.js.map +1 -0
- package/dist/core/maintenance.d.ts +88 -1
- package/dist/core/maintenance.d.ts.map +1 -1
- package/dist/core/maintenance.js +149 -8
- package/dist/core/maintenance.js.map +1 -1
- package/dist/core/release-download.d.ts +13 -0
- package/dist/core/release-download.d.ts.map +1 -0
- package/dist/core/release-download.js +130 -0
- package/dist/core/release-download.js.map +1 -0
- package/dist/dashboard/hd2d-assets.d.ts +2 -3
- package/dist/dashboard/hd2d-assets.d.ts.map +1 -1
- package/dist/dashboard/hd2d-assets.js +7 -109
- package/dist/dashboard/hd2d-assets.js.map +1 -1
- package/dist/dashboard/web/app.d.ts.map +1 -1
- package/dist/dashboard/web/app.js +7 -1
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/settings-page.d.ts.map +1 -1
- package/dist/dashboard/web/settings-page.js.map +1 -1
- package/dist/dashboard-web/app.js +1 -1
- package/dist/dashboard.js +120 -13
- package/dist/dashboard.js.map +1 -1
- package/dist/setup/open-platform-automation.d.ts.map +1 -1
- package/dist/setup/open-platform-automation.js +9 -12
- package/dist/setup/open-platform-automation.js.map +1 -1
- package/dist/utils/file-lock.d.ts +25 -0
- package/dist/utils/file-lock.d.ts.map +1 -1
- package/dist/utils/file-lock.js +34 -4
- package/dist/utils/file-lock.js.map +1 -1
- package/dist/utils/global-install.d.ts +19 -0
- package/dist/utils/global-install.d.ts.map +1 -1
- package/dist/utils/global-install.js +28 -1
- package/dist/utils/global-install.js.map +1 -1
- package/dist/utils/install-info.d.ts +37 -1
- package/dist/utils/install-info.d.ts.map +1 -1
- package/dist/utils/install-info.js +45 -3
- package/dist/utils/install-info.js.map +1 -1
- package/package.json +7 -7
package/dist/.runtime-build-id
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
772cb5082be7e1181051fb6e4344f92bc8a484024a69f8d8f5cbc607b014e30a
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA8BA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA8BA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAqLhD,OAAO,EAAE,KAAK,KAAK,EAA0C,MAAM,yBAAyB,CAAC;AA2iB7F;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,GAAG,OAAO,CACpF;IACE,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,oDAAoD;IACpD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CACrC,CA6LA;AAmlDD,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,GAAG,gBAAgB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,SAAS,GAAG,kBAAkB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtH,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,GAAG,iBAAiB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,SAAS,GAAG,kBAAkB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AA4rQxG;;;;;;;;;;;GAWG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACvC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,qBAAqB,EAAE,SAAS,CAAC,EAC9F,KAAK,EAAE,MAAM,EACb,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,2BAA2B,EAAE,UAAU,GAAG,IAAI,CAAC;AAC1F;qDACqD;AACrD,wBAAwB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,2BAA2B,EAAE,UAAU,GAAG,IAAI,CAAC,GAClH,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAuL7B"}
|
package/dist/cli.js
CHANGED
|
@@ -52,11 +52,12 @@ import { buildBotFromAddFlags, editInputFromFlags, isScriptedSetupInvocation, ma
|
|
|
52
52
|
import { detectUnusableOwnerEntries, normalizeManagedOwnerEntries, resolveScannerAllowedUser, } from './setup/owner-identity.js';
|
|
53
53
|
import { interactiveSelect, pickChoice, pickCliSelection } from './setup/interactive-select.js';
|
|
54
54
|
import { buildPreset, serializePreset, presetFilename } from './setup/agent-preset.js';
|
|
55
|
+
import bundledScopeManifest from './setup/lark-scopes.json' with { type: 'json' };
|
|
55
56
|
import { validateCodexAppManagedSendOrigin, } from './utils/codex-app-dispatch-ledger.js';
|
|
56
57
|
import { hasProtectedSessionMutationOwnership } from './core/session-mutation-guard.js';
|
|
57
58
|
import { logger } from './utils/logger.js';
|
|
58
59
|
import { reapLegacyPm2, liveGodAt } from './core/legacy-pm2-reaper.js';
|
|
59
|
-
import { withFileLock, withFileLockSync } from './utils/file-lock.js';
|
|
60
|
+
import { withFileLock, withFileLockSync, FileLockTimeoutError } from './utils/file-lock.js';
|
|
60
61
|
import { scheduleTimeZone } from './utils/timezone.js';
|
|
61
62
|
import { expandHomePath, invalidWorkingDirs } from './utils/working-dir.js';
|
|
62
63
|
import { firstPositional, hasFlagOrEq } from './cli/arg-utils.js';
|
|
@@ -78,7 +79,10 @@ import { isRemoteAccessEnabled } from './global-config.js';
|
|
|
78
79
|
import { DASHBOARD_COMMAND_USAGE, executeDashboardCommand, formatDashboardFallbackFailure, formatDashboardSuccessLines, } from './cli/dashboard-command.js';
|
|
79
80
|
import { globalInstallUpdateLockTarget, globalInstallUpdateLockTargetIn, installLatestBotmuxSync } from './core/maintenance.js';
|
|
80
81
|
import { formatGlobalInstallCommand, resolveGlobalInstallPlan, UnsupportedGlobalInstallError, } from './utils/global-install.js';
|
|
81
|
-
import { isLocalDevInstall, botmuxCliEntryAt, bakedBinaryVersion } from './utils/install-info.js';
|
|
82
|
+
import { isLocalDevInstall, botmuxCliEntryAt, bakedBinaryVersion, botmuxInstallRoot } from './utils/install-info.js';
|
|
83
|
+
import { currentUpdateStrategy, replaceStandaloneBinary } from './core/binary-self-update.js';
|
|
84
|
+
import { fetchLatestVersion, isNewerVersion } from './core/update-check.js';
|
|
85
|
+
import { resolveCurrentVersion } from './utils/install-diagnostics.js';
|
|
82
86
|
import { resolveLocalDevCheckoutDir, isGitWorktree, gitPorcelainStatus, localDevUpdateSteps, describeSpawnFailure, } from './utils/local-dev-update.js';
|
|
83
87
|
import { loadDashboardSecret } from './dashboard/auth.js';
|
|
84
88
|
import { postWorkflowDaemonMutation, } from './workflows/v3/daemon-ipc-client.js';
|
|
@@ -357,23 +361,8 @@ function botBrand(b) {
|
|
|
357
361
|
* Returns: 写出的 JSON 文件绝对路径.
|
|
358
362
|
*/
|
|
359
363
|
function writeScopesJsonToConfigDir() {
|
|
360
|
-
// build script 会把 src/setup/lark-scopes.json copy 到 dist/setup/.
|
|
361
|
-
// dist 模式下 __dirname 是 dist/, 找 ./setup/lark-scopes.json; dev (tsx)
|
|
362
|
-
// 模式找 src/setup/lark-scopes.json 在源码同目录也成立.
|
|
363
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
364
|
-
const srcCandidates = [
|
|
365
|
-
join(here, 'setup', 'lark-scopes.json'),
|
|
366
|
-
join(here, '..', 'src', 'setup', 'lark-scopes.json'),
|
|
367
|
-
];
|
|
368
|
-
let scopesPath = srcCandidates[0];
|
|
369
|
-
for (const p of srcCandidates) {
|
|
370
|
-
if (existsSync(p)) {
|
|
371
|
-
scopesPath = p;
|
|
372
|
-
break;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
364
|
const destPath = join(CONFIG_DIR, 'lark-scopes.json');
|
|
376
|
-
|
|
365
|
+
writeFileSync(destPath, `${JSON.stringify(bundledScopeManifest, null, 2)}\n`);
|
|
377
366
|
return destPath;
|
|
378
367
|
}
|
|
379
368
|
function printCopyHint(filePath) {
|
|
@@ -2668,7 +2657,7 @@ async function cmdStatus() {
|
|
|
2668
2657
|
// registry to reconcile against. Legacy pm2 still gets surfaced by
|
|
2669
2658
|
// warnIfLegacyBotmuxAlive above, which is what a pre-migration host needs.
|
|
2670
2659
|
}
|
|
2671
|
-
function cmdUpgrade() {
|
|
2660
|
+
async function cmdUpgrade() {
|
|
2672
2661
|
// 本地 checkout(有 .git/src):走 git pull --ff-only → 重新 build → 从本
|
|
2673
2662
|
// checkout 重启,而不是拿全局包管理器去升级(那对 dev 部署无效,见
|
|
2674
2663
|
// install-info.ts 的 isLocalDevInstall 说明)。
|
|
@@ -2676,8 +2665,66 @@ function cmdUpgrade() {
|
|
|
2676
2665
|
cmdUpgradeLocalDev();
|
|
2677
2666
|
return;
|
|
2678
2667
|
}
|
|
2668
|
+
// 编译版单文件二进制没有 package.json 落盘 ⟹ resolveGlobalInstallPlan 恒抛
|
|
2669
|
+
// Unsupported(实测真实 v3.18.4 二进制就是这条)。改为先按「二进制装在哪」
|
|
2670
|
+
// 判形态:npm 子包形态交回 npm/pnpm/bun,install.sh 形态自己换二进制。
|
|
2671
|
+
const strategy = currentUpdateStrategy(botmuxInstallRoot());
|
|
2672
|
+
if (strategy.kind === 'self-replace') {
|
|
2673
|
+
try {
|
|
2674
|
+
const latest = await fetchLatestVersion();
|
|
2675
|
+
if (!latest) {
|
|
2676
|
+
console.error('❌ 无法获取最新版本号(网络不可达或 registry 异常)。');
|
|
2677
|
+
process.exit(1);
|
|
2678
|
+
}
|
|
2679
|
+
const current = resolveCurrentVersion();
|
|
2680
|
+
if (!isNewerVersion(latest, current)) {
|
|
2681
|
+
console.log(`✅ 已是最新版本(${current})。`);
|
|
2682
|
+
return;
|
|
2683
|
+
}
|
|
2684
|
+
console.log(`🔄 升级中:下载 v${latest} 二进制并替换 ${strategy.target}`);
|
|
2685
|
+
// 握与 dashboard / maintenance 同一把跨进程锁:这条路径是**写同一个文件**,
|
|
2686
|
+
// 两个 update 并发跑会互相盖掉临时文件与 rename。锁文件父目录可能还不存在
|
|
2687
|
+
// (daemon 从未在本机起过就先跑 update),先建再握,否则 ENOENT 会盖掉真实错误。
|
|
2688
|
+
const lockTarget = globalInstallUpdateLockTarget();
|
|
2689
|
+
mkdirSync(dirname(lockTarget), { recursive: true });
|
|
2690
|
+
let acquired = false;
|
|
2691
|
+
try {
|
|
2692
|
+
await withFileLock(lockTarget, async () => {
|
|
2693
|
+
acquired = true;
|
|
2694
|
+
const r = await replaceStandaloneBinary(latest, strategy.target);
|
|
2695
|
+
console.log(`✅ 升级完成:${r.asset} → ${r.target}(${current} → ${latest})。运行 botmux restart 以应用更新。`);
|
|
2696
|
+
}, { maxWaitMs: 2_000 });
|
|
2697
|
+
}
|
|
2698
|
+
catch (error) {
|
|
2699
|
+
// ⚠️ 三态,不是二态。`withFileLock` 拿不到锁时是**抛异常**不是安静返回,
|
|
2700
|
+
// 但 `acquired === false` 只证明「回调没执行」,**不等于「别人持锁」**:
|
|
2701
|
+
// 回调之前还可能因 `open` 的 EACCES/ENOSPC、holder 写入失败、holder 元数据
|
|
2702
|
+
// 不可读、stale-claim `link` 失败而抛错。只看 `acquired` 会把这些**真实故障
|
|
2703
|
+
// 全部误报成「另一个更新正在进行」**——磁盘满被说成并发冲突,是最坏的那种
|
|
2704
|
+
// 误导。所以必须同时要求它是 timeout 类型:
|
|
2705
|
+
// ① 超时且回调未进入 → 友好并发提示(正常互斥结果,不是故障)
|
|
2706
|
+
// ② 回调已进入后失败 → 透出真实错误(下载/校验/替换)
|
|
2707
|
+
// ③ 回调前的基础设施失败 → 同样透出真实错误
|
|
2708
|
+
// 判类型而不是匹文案:file-lock 的文案被多处按字符串匹配,不能动,但新代码
|
|
2709
|
+
// 应该用 FileLockTimeoutError(async/sync 两处语义一致)。
|
|
2710
|
+
if (!acquired && error instanceof FileLockTimeoutError) {
|
|
2711
|
+
console.error('❌ 另一个更新正在进行中(dashboard 或定时任务),请稍后重试。');
|
|
2712
|
+
process.exit(1);
|
|
2713
|
+
}
|
|
2714
|
+
throw error; // ②③ 交给外层统一报错,不被友好文案吞掉
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
catch (error) {
|
|
2718
|
+
console.error(`❌ 升级失败:${error instanceof Error ? error.message : error}`);
|
|
2719
|
+
process.exit(1);
|
|
2720
|
+
}
|
|
2721
|
+
return;
|
|
2722
|
+
}
|
|
2679
2723
|
try {
|
|
2680
|
-
|
|
2724
|
+
if (strategy.kind === 'unsupported') {
|
|
2725
|
+
throw new UnsupportedGlobalInstallError('unknown', process.execPath);
|
|
2726
|
+
}
|
|
2727
|
+
const plan = resolveGlobalInstallPlan(strategy.packageRoot);
|
|
2681
2728
|
console.log(`🔄 升级中:${formatGlobalInstallCommand(plan)}`);
|
|
2682
2729
|
installLatestBotmuxSync(plan);
|
|
2683
2730
|
console.log('\n✅ 升级完成。运行 botmux restart 以应用更新。');
|
|
@@ -11388,6 +11435,38 @@ if (__entrySubcommand) {
|
|
|
11388
11435
|
// below never runs. This awaits forever; the imported module owns exit().
|
|
11389
11436
|
await new Promise(() => { });
|
|
11390
11437
|
}
|
|
11438
|
+
// Hidden: perform a compiled-binary self-replace and exit. Invoked by
|
|
11439
|
+
// `runSelfReplaceBlocking` (src/core/maintenance.ts) so the synchronous
|
|
11440
|
+
// maintenance tick / dashboard handler can wait on one child instead of
|
|
11441
|
+
// restructuring around an await. Not a user-facing command; it only ever makes
|
|
11442
|
+
// sense for the standalone binary, which owns its own file.
|
|
11443
|
+
if (command === '__self-update') {
|
|
11444
|
+
const requested = process.argv[3] || 'latest';
|
|
11445
|
+
try {
|
|
11446
|
+
const { replaceStandaloneBinary, currentBinaryInstallShape } = await import('./core/binary-self-update.js');
|
|
11447
|
+
if (currentBinaryInstallShape() !== 'curl-binary') {
|
|
11448
|
+
// Fail closed rather than write into a tree a package manager owns.
|
|
11449
|
+
console.error('__self-update: 当前不是独立二进制安装(install.sh 形态),拒绝自替换');
|
|
11450
|
+
process.exit(1);
|
|
11451
|
+
}
|
|
11452
|
+
const { fetchLatestVersion } = await import('./core/update-check.js');
|
|
11453
|
+
const version = requested === 'latest' ? await fetchLatestVersion() : requested;
|
|
11454
|
+
if (!version) {
|
|
11455
|
+
console.error('__self-update: 无法解析最新版本(网络不可达或 registry 异常)');
|
|
11456
|
+
process.exit(1);
|
|
11457
|
+
}
|
|
11458
|
+
const r = await replaceStandaloneBinary(version);
|
|
11459
|
+
// The caller parses this line: after a self-replace the running process still
|
|
11460
|
+
// reports its OWN baked version, so it cannot discover the new one by re-reading.
|
|
11461
|
+
console.log(`BOTMUX_SELF_UPDATE_VERSION=${version}`);
|
|
11462
|
+
console.log(`__self-update: ${r.asset} → ${r.target} (${r.bytes} bytes)`);
|
|
11463
|
+
process.exit(0);
|
|
11464
|
+
}
|
|
11465
|
+
catch (error) {
|
|
11466
|
+
console.error(`__self-update: ${error instanceof Error ? error.message : error}`);
|
|
11467
|
+
process.exit(1);
|
|
11468
|
+
}
|
|
11469
|
+
}
|
|
11391
11470
|
const ROOT_FLEET_MUTATION_COMMANDS = new Set(['start', 'stop', 'restart', 'upgrade', 'update']);
|
|
11392
11471
|
if (ROOT_FLEET_MUTATION_COMMANDS.has(command ?? '')
|
|
11393
11472
|
&& process.argv.slice(3).some(arg => arg === '--help' || arg === '-h')) {
|
|
@@ -12245,7 +12324,7 @@ switch (command) {
|
|
|
12245
12324
|
break;
|
|
12246
12325
|
case 'upgrade':
|
|
12247
12326
|
case 'update':
|
|
12248
|
-
cmdUpgrade();
|
|
12327
|
+
await cmdUpgrade();
|
|
12249
12328
|
break;
|
|
12250
12329
|
case 'dashboard':
|
|
12251
12330
|
await cmdDashboard(process.argv.slice(3));
|
|
@@ -12275,6 +12354,36 @@ switch (command) {
|
|
|
12275
12354
|
case '__zmx-attach-managed':
|
|
12276
12355
|
cmdManagedZmxAttach(process.argv.slice(3));
|
|
12277
12356
|
break;
|
|
12357
|
+
// Hidden self-check for the compiled single-file binary: exercise the two
|
|
12358
|
+
// setup-time code paths that load lark-scopes.json off a module-relative path —
|
|
12359
|
+
// readDefaultScopeManifest() (real Open Platform setup) and
|
|
12360
|
+
// writeScopesJsonToConfigDir() (writes ~/.botmux/lark-scopes.json). In compiled
|
|
12361
|
+
// mode the module graph lives in the read-only virtual /$bunfs, so the old
|
|
12362
|
+
// readFileSync/copyFileSync of a __dirname-derived path threw
|
|
12363
|
+
// "找不到 botmux lark-scopes.json". The npm/Node unit tests can't catch that —
|
|
12364
|
+
// dist/ physically exists there — so smoke-bun-binary.mjs drives THIS against
|
|
12365
|
+
// the actual binary. Prints a one-line JSON summary and exits 0; any throw
|
|
12366
|
+
// (missing/empty manifest, unwritable path) exits non-zero and fails the smoke.
|
|
12367
|
+
case '__selfcheck': {
|
|
12368
|
+
const { readDefaultScopeManifest } = await import('./setup/open-platform-automation.js');
|
|
12369
|
+
const manifest = readDefaultScopeManifest();
|
|
12370
|
+
const tenant = manifest.scopes?.tenant?.length ?? 0;
|
|
12371
|
+
const user = manifest.scopes?.user?.length ?? 0;
|
|
12372
|
+
if (tenant <= 0 || user <= 0) {
|
|
12373
|
+
console.error(`__selfcheck: lark-scopes manifest empty (tenant=${tenant}, user=${user})`);
|
|
12374
|
+
process.exit(1);
|
|
12375
|
+
}
|
|
12376
|
+
const written = writeScopesJsonToConfigDir();
|
|
12377
|
+
const onDisk = JSON.parse(readFileSync(written, 'utf-8'));
|
|
12378
|
+
const wroteTenant = onDisk?.scopes?.tenant?.length ?? 0;
|
|
12379
|
+
const wroteUser = onDisk?.scopes?.user?.length ?? 0;
|
|
12380
|
+
if (wroteTenant !== tenant || wroteUser !== user) {
|
|
12381
|
+
console.error(`__selfcheck: written manifest mismatch (${wroteTenant}/${wroteUser} vs ${tenant}/${user})`);
|
|
12382
|
+
process.exit(1);
|
|
12383
|
+
}
|
|
12384
|
+
console.log(JSON.stringify({ ok: true, tenant, user, written }));
|
|
12385
|
+
process.exit(0);
|
|
12386
|
+
}
|
|
12278
12387
|
case 'delete':
|
|
12279
12388
|
case 'del':
|
|
12280
12389
|
case 'rm':
|