botmux 3.18.3 → 3.18.5
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/adapters/hook-installer.d.ts.map +1 -1
- package/dist/adapters/hook-installer.js +75 -2
- package/dist/adapters/hook-installer.js.map +1 -1
- package/dist/cli/current-actor.d.ts.map +1 -1
- package/dist/cli/current-actor.js +2 -1
- package/dist/cli/current-actor.js.map +1 -1
- package/dist/cli/dashboard-endpoint.d.ts.map +1 -1
- package/dist/cli/dashboard-endpoint.js +5 -2
- package/dist/cli/dashboard-endpoint.js.map +1 -1
- package/dist/cli/exact-chat-grant-client.d.ts.map +1 -1
- package/dist/cli/exact-chat-grant-client.js +2 -1
- package/dist/cli/exact-chat-grant-client.js.map +1 -1
- package/dist/cli/vc-agent.d.ts.map +1 -1
- package/dist/cli/vc-agent.js +2 -1
- package/dist/cli/vc-agent.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +105 -11
- 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/daemon-ipc-auth.d.ts +9 -1
- package/dist/core/daemon-ipc-auth.d.ts.map +1 -1
- package/dist/core/daemon-ipc-auth.js +14 -3
- package/dist/core/daemon-ipc-auth.js.map +1 -1
- package/dist/core/loopback-fetch.d.ts +59 -0
- package/dist/core/loopback-fetch.d.ts.map +1 -0
- package/dist/core/loopback-fetch.js +347 -0
- package/dist/core/loopback-fetch.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/managed-origin-attestation.d.ts.map +1 -1
- package/dist/core/managed-origin-attestation.js +2 -1
- package/dist/core/managed-origin-attestation.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/daemon.d.ts.map +1 -1
- package/dist/daemon.js +2 -1
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/aggregator.d.ts.map +1 -1
- package/dist/dashboard/aggregator.js +2 -1
- package/dist/dashboard/aggregator.js.map +1 -1
- package/dist/dashboard/daemon-internal-client.d.ts.map +1 -1
- package/dist/dashboard/daemon-internal-client.js +6 -1
- package/dist/dashboard/daemon-internal-client.js.map +1 -1
- package/dist/dashboard/groups-action-helpers.d.ts +0 -10
- package/dist/dashboard/groups-action-helpers.d.ts.map +1 -1
- package/dist/dashboard/groups-action-helpers.js +3 -2
- package/dist/dashboard/groups-action-helpers.js.map +1 -1
- 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 +122 -14
- package/dist/dashboard.js.map +1 -1
- package/dist/services/hook-runner.d.ts.map +1 -1
- package/dist/services/hook-runner.js +2 -1
- package/dist/services/hook-runner.js.map +1 -1
- package/dist/services/voice/openai.d.ts.map +1 -1
- package/dist/services/voice/openai.js +10 -1
- package/dist/services/voice/openai.js.map +1 -1
- package/dist/services/worktree-slug-ai.d.ts.map +1 -1
- package/dist/services/worktree-slug-ai.js +8 -1
- package/dist/services/worktree-slug-ai.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/dist/workflows/v3/daemon-ipc-client.d.ts.map +1 -1
- package/dist/workflows/v3/daemon-ipc-client.js +2 -1
- package/dist/workflows/v3/daemon-ipc-client.js.map +1 -1
- package/dist/workflows/v3/session-relay-client.d.ts.map +1 -1
- package/dist/workflows/v3/session-relay-client.js +2 -1
- package/dist/workflows/v3/session-relay-client.js.map +1 -1
- package/package.json +8 -7
- package/scripts/install-path-entry.mjs +263 -0
- package/scripts/postinstall-bin.mjs +41 -7
package/dist/cli.js
CHANGED
|
@@ -56,7 +56,7 @@ import { validateCodexAppManagedSendOrigin, } from './utils/codex-app-dispatch-l
|
|
|
56
56
|
import { hasProtectedSessionMutationOwnership } from './core/session-mutation-guard.js';
|
|
57
57
|
import { logger } from './utils/logger.js';
|
|
58
58
|
import { reapLegacyPm2, liveGodAt } from './core/legacy-pm2-reaper.js';
|
|
59
|
-
import { withFileLock, withFileLockSync } from './utils/file-lock.js';
|
|
59
|
+
import { withFileLock, withFileLockSync, FileLockTimeoutError } from './utils/file-lock.js';
|
|
60
60
|
import { scheduleTimeZone } from './utils/timezone.js';
|
|
61
61
|
import { expandHomePath, invalidWorkingDirs } from './utils/working-dir.js';
|
|
62
62
|
import { firstPositional, hasFlagOrEq } from './cli/arg-utils.js';
|
|
@@ -78,7 +78,10 @@ import { isRemoteAccessEnabled } from './global-config.js';
|
|
|
78
78
|
import { DASHBOARD_COMMAND_USAGE, executeDashboardCommand, formatDashboardFallbackFailure, formatDashboardSuccessLines, } from './cli/dashboard-command.js';
|
|
79
79
|
import { globalInstallUpdateLockTarget, globalInstallUpdateLockTargetIn, installLatestBotmuxSync } from './core/maintenance.js';
|
|
80
80
|
import { formatGlobalInstallCommand, resolveGlobalInstallPlan, UnsupportedGlobalInstallError, } from './utils/global-install.js';
|
|
81
|
-
import { isLocalDevInstall, botmuxCliEntryAt, bakedBinaryVersion } from './utils/install-info.js';
|
|
81
|
+
import { isLocalDevInstall, botmuxCliEntryAt, bakedBinaryVersion, botmuxInstallRoot } from './utils/install-info.js';
|
|
82
|
+
import { currentUpdateStrategy, replaceStandaloneBinary } from './core/binary-self-update.js';
|
|
83
|
+
import { fetchLatestVersion, isNewerVersion } from './core/update-check.js';
|
|
84
|
+
import { resolveCurrentVersion } from './utils/install-diagnostics.js';
|
|
82
85
|
import { resolveLocalDevCheckoutDir, isGitWorktree, gitPorcelainStatus, localDevUpdateSteps, describeSpawnFailure, } from './utils/local-dev-update.js';
|
|
83
86
|
import { loadDashboardSecret } from './dashboard/auth.js';
|
|
84
87
|
import { postWorkflowDaemonMutation, } from './workflows/v3/daemon-ipc-client.js';
|
|
@@ -92,6 +95,7 @@ import { attestManagedOrigin, } from './core/managed-origin-attestation.js';
|
|
|
92
95
|
import { rejectLikelyWindowsStdinMojibake, decodeStdinBytes } from './cli/stdin-encoding.js';
|
|
93
96
|
import { collaborationHelp, formatBotInfoEntriesForCli, formatChatBotsForCli, } from './cli/bots-list-output.js';
|
|
94
97
|
import { ensureBotChatGrantMatrix, requestExactChatGrant } from './cli/exact-chat-grant-client.js';
|
|
98
|
+
import { loopbackFetch } from './core/loopback-fetch.js';
|
|
95
99
|
import { buildFooterAddressing, hasKnownBotMention, knownBotOpenIdsFromCrossRef, orderedFooterRecipients, stripCodeSpans, } from './utils/bot-routing.js';
|
|
96
100
|
import { isLocale, localeForBot, setDefaultLocale, SUPPORTED_LOCALES, t } from './i18n/index.js';
|
|
97
101
|
import { registerPromptOverrideResolver } from './skills/effective-builtins.js';
|
|
@@ -2667,7 +2671,7 @@ async function cmdStatus() {
|
|
|
2667
2671
|
// registry to reconcile against. Legacy pm2 still gets surfaced by
|
|
2668
2672
|
// warnIfLegacyBotmuxAlive above, which is what a pre-migration host needs.
|
|
2669
2673
|
}
|
|
2670
|
-
function cmdUpgrade() {
|
|
2674
|
+
async function cmdUpgrade() {
|
|
2671
2675
|
// 本地 checkout(有 .git/src):走 git pull --ff-only → 重新 build → 从本
|
|
2672
2676
|
// checkout 重启,而不是拿全局包管理器去升级(那对 dev 部署无效,见
|
|
2673
2677
|
// install-info.ts 的 isLocalDevInstall 说明)。
|
|
@@ -2675,8 +2679,66 @@ function cmdUpgrade() {
|
|
|
2675
2679
|
cmdUpgradeLocalDev();
|
|
2676
2680
|
return;
|
|
2677
2681
|
}
|
|
2682
|
+
// 编译版单文件二进制没有 package.json 落盘 ⟹ resolveGlobalInstallPlan 恒抛
|
|
2683
|
+
// Unsupported(实测真实 v3.18.4 二进制就是这条)。改为先按「二进制装在哪」
|
|
2684
|
+
// 判形态:npm 子包形态交回 npm/pnpm/bun,install.sh 形态自己换二进制。
|
|
2685
|
+
const strategy = currentUpdateStrategy(botmuxInstallRoot());
|
|
2686
|
+
if (strategy.kind === 'self-replace') {
|
|
2687
|
+
try {
|
|
2688
|
+
const latest = await fetchLatestVersion();
|
|
2689
|
+
if (!latest) {
|
|
2690
|
+
console.error('❌ 无法获取最新版本号(网络不可达或 registry 异常)。');
|
|
2691
|
+
process.exit(1);
|
|
2692
|
+
}
|
|
2693
|
+
const current = resolveCurrentVersion();
|
|
2694
|
+
if (!isNewerVersion(latest, current)) {
|
|
2695
|
+
console.log(`✅ 已是最新版本(${current})。`);
|
|
2696
|
+
return;
|
|
2697
|
+
}
|
|
2698
|
+
console.log(`🔄 升级中:下载 v${latest} 二进制并替换 ${strategy.target}`);
|
|
2699
|
+
// 握与 dashboard / maintenance 同一把跨进程锁:这条路径是**写同一个文件**,
|
|
2700
|
+
// 两个 update 并发跑会互相盖掉临时文件与 rename。锁文件父目录可能还不存在
|
|
2701
|
+
// (daemon 从未在本机起过就先跑 update),先建再握,否则 ENOENT 会盖掉真实错误。
|
|
2702
|
+
const lockTarget = globalInstallUpdateLockTarget();
|
|
2703
|
+
mkdirSync(dirname(lockTarget), { recursive: true });
|
|
2704
|
+
let acquired = false;
|
|
2705
|
+
try {
|
|
2706
|
+
await withFileLock(lockTarget, async () => {
|
|
2707
|
+
acquired = true;
|
|
2708
|
+
const r = await replaceStandaloneBinary(latest, strategy.target);
|
|
2709
|
+
console.log(`✅ 升级完成:${r.asset} → ${r.target}(${current} → ${latest})。运行 botmux restart 以应用更新。`);
|
|
2710
|
+
}, { maxWaitMs: 2_000 });
|
|
2711
|
+
}
|
|
2712
|
+
catch (error) {
|
|
2713
|
+
// ⚠️ 三态,不是二态。`withFileLock` 拿不到锁时是**抛异常**不是安静返回,
|
|
2714
|
+
// 但 `acquired === false` 只证明「回调没执行」,**不等于「别人持锁」**:
|
|
2715
|
+
// 回调之前还可能因 `open` 的 EACCES/ENOSPC、holder 写入失败、holder 元数据
|
|
2716
|
+
// 不可读、stale-claim `link` 失败而抛错。只看 `acquired` 会把这些**真实故障
|
|
2717
|
+
// 全部误报成「另一个更新正在进行」**——磁盘满被说成并发冲突,是最坏的那种
|
|
2718
|
+
// 误导。所以必须同时要求它是 timeout 类型:
|
|
2719
|
+
// ① 超时且回调未进入 → 友好并发提示(正常互斥结果,不是故障)
|
|
2720
|
+
// ② 回调已进入后失败 → 透出真实错误(下载/校验/替换)
|
|
2721
|
+
// ③ 回调前的基础设施失败 → 同样透出真实错误
|
|
2722
|
+
// 判类型而不是匹文案:file-lock 的文案被多处按字符串匹配,不能动,但新代码
|
|
2723
|
+
// 应该用 FileLockTimeoutError(async/sync 两处语义一致)。
|
|
2724
|
+
if (!acquired && error instanceof FileLockTimeoutError) {
|
|
2725
|
+
console.error('❌ 另一个更新正在进行中(dashboard 或定时任务),请稍后重试。');
|
|
2726
|
+
process.exit(1);
|
|
2727
|
+
}
|
|
2728
|
+
throw error; // ②③ 交给外层统一报错,不被友好文案吞掉
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
catch (error) {
|
|
2732
|
+
console.error(`❌ 升级失败:${error instanceof Error ? error.message : error}`);
|
|
2733
|
+
process.exit(1);
|
|
2734
|
+
}
|
|
2735
|
+
return;
|
|
2736
|
+
}
|
|
2678
2737
|
try {
|
|
2679
|
-
|
|
2738
|
+
if (strategy.kind === 'unsupported') {
|
|
2739
|
+
throw new UnsupportedGlobalInstallError('unknown', process.execPath);
|
|
2740
|
+
}
|
|
2741
|
+
const plan = resolveGlobalInstallPlan(strategy.packageRoot);
|
|
2680
2742
|
console.log(`🔄 升级中:${formatGlobalInstallCommand(plan)}`);
|
|
2681
2743
|
installLatestBotmuxSync(plan);
|
|
2682
2744
|
console.log('\n✅ 升级完成。运行 botmux restart 以应用更新。');
|
|
@@ -4417,7 +4479,7 @@ async function postSessionCliIpc(ipcPort, sessionId, route, payload) {
|
|
|
4417
4479
|
};
|
|
4418
4480
|
return hostSecret
|
|
4419
4481
|
? fetchDaemonIpc(ipcPort, path, init, hostSecret)
|
|
4420
|
-
:
|
|
4482
|
+
: loopbackFetch(`http://127.0.0.1:${ipcPort}${path}`, init);
|
|
4421
4483
|
}
|
|
4422
4484
|
/** `botmux preview <port>` registers a reachable loopback Web service for the
|
|
4423
4485
|
* exact current session. There is intentionally no `--session` escape hatch:
|
|
@@ -8802,7 +8864,7 @@ async function cmdSend(rest) {
|
|
|
8802
8864
|
catch { /* Seatbelt/read-isolated CLI */ }
|
|
8803
8865
|
const res = secret
|
|
8804
8866
|
? await fetchDaemonIpc(attentionPort, '/api/attention', request, secret)
|
|
8805
|
-
: await
|
|
8867
|
+
: await loopbackFetch(`http://127.0.0.1:${attentionPort}/api/attention`, request);
|
|
8806
8868
|
if (!res.ok)
|
|
8807
8869
|
throw new Error(`daemon HTTP ${res.status}`);
|
|
8808
8870
|
attentionRaised = true;
|
|
@@ -8915,7 +8977,7 @@ async function postCurrentSessionDaemonRoute(input) {
|
|
|
8915
8977
|
}, hostSecret);
|
|
8916
8978
|
}
|
|
8917
8979
|
const originClaim = readManagedOriginCapability(resolveDataDir(), input.sessionId, relayDir, process.env.BOTMUX_ORIGIN_CHANNEL_ID);
|
|
8918
|
-
return
|
|
8980
|
+
return loopbackFetch(`http://127.0.0.1:${port}${input.path}`, {
|
|
8919
8981
|
method: 'POST',
|
|
8920
8982
|
headers: { 'content-type': 'application/json' },
|
|
8921
8983
|
body: JSON.stringify({
|
|
@@ -10115,7 +10177,7 @@ async function postAsk(body) {
|
|
|
10115
10177
|
}
|
|
10116
10178
|
res = hostSecret
|
|
10117
10179
|
? await fetchDaemonIpc(daemon.ipcPort, '/api/asks', init, hostSecret)
|
|
10118
|
-
: await
|
|
10180
|
+
: await loopbackFetch(`http://127.0.0.1:${daemon.ipcPort}/api/asks`, init);
|
|
10119
10181
|
}
|
|
10120
10182
|
catch (fetchErr) {
|
|
10121
10183
|
// Socket refused / reset / timeout → daemon is down or restarting → retryable.
|
|
@@ -10575,7 +10637,7 @@ async function cmdSessionReady() {
|
|
|
10575
10637
|
catch { /* Seatbelt/read-isolated CLI */ }
|
|
10576
10638
|
}
|
|
10577
10639
|
if (!hostSecret) {
|
|
10578
|
-
await
|
|
10640
|
+
await loopbackFetch(`http://127.0.0.1:${ipcPort}/api/session-ready`, init);
|
|
10579
10641
|
}
|
|
10580
10642
|
else {
|
|
10581
10643
|
await fetchDaemonIpc(ipcPort, '/api/session-ready', init, hostSecret);
|
|
@@ -10684,7 +10746,7 @@ async function cmdUserPromptHook() {
|
|
|
10684
10746
|
const path = `/api/sessions/${encodeURIComponent(sessionId)}/prompt-ctx/claim`;
|
|
10685
10747
|
const res = hostSecret
|
|
10686
10748
|
? await fetchDaemonIpc(ipcPort, path, init, hostSecret)
|
|
10687
|
-
: await
|
|
10749
|
+
: await loopbackFetch(`http://127.0.0.1:${ipcPort}${path}`, init);
|
|
10688
10750
|
if (res.status !== 200)
|
|
10689
10751
|
process.exit(0);
|
|
10690
10752
|
const data = await res.json();
|
|
@@ -11387,6 +11449,38 @@ if (__entrySubcommand) {
|
|
|
11387
11449
|
// below never runs. This awaits forever; the imported module owns exit().
|
|
11388
11450
|
await new Promise(() => { });
|
|
11389
11451
|
}
|
|
11452
|
+
// Hidden: perform a compiled-binary self-replace and exit. Invoked by
|
|
11453
|
+
// `runSelfReplaceBlocking` (src/core/maintenance.ts) so the synchronous
|
|
11454
|
+
// maintenance tick / dashboard handler can wait on one child instead of
|
|
11455
|
+
// restructuring around an await. Not a user-facing command; it only ever makes
|
|
11456
|
+
// sense for the standalone binary, which owns its own file.
|
|
11457
|
+
if (command === '__self-update') {
|
|
11458
|
+
const requested = process.argv[3] || 'latest';
|
|
11459
|
+
try {
|
|
11460
|
+
const { replaceStandaloneBinary, currentBinaryInstallShape } = await import('./core/binary-self-update.js');
|
|
11461
|
+
if (currentBinaryInstallShape() !== 'curl-binary') {
|
|
11462
|
+
// Fail closed rather than write into a tree a package manager owns.
|
|
11463
|
+
console.error('__self-update: 当前不是独立二进制安装(install.sh 形态),拒绝自替换');
|
|
11464
|
+
process.exit(1);
|
|
11465
|
+
}
|
|
11466
|
+
const { fetchLatestVersion } = await import('./core/update-check.js');
|
|
11467
|
+
const version = requested === 'latest' ? await fetchLatestVersion() : requested;
|
|
11468
|
+
if (!version) {
|
|
11469
|
+
console.error('__self-update: 无法解析最新版本(网络不可达或 registry 异常)');
|
|
11470
|
+
process.exit(1);
|
|
11471
|
+
}
|
|
11472
|
+
const r = await replaceStandaloneBinary(version);
|
|
11473
|
+
// The caller parses this line: after a self-replace the running process still
|
|
11474
|
+
// reports its OWN baked version, so it cannot discover the new one by re-reading.
|
|
11475
|
+
console.log(`BOTMUX_SELF_UPDATE_VERSION=${version}`);
|
|
11476
|
+
console.log(`__self-update: ${r.asset} → ${r.target} (${r.bytes} bytes)`);
|
|
11477
|
+
process.exit(0);
|
|
11478
|
+
}
|
|
11479
|
+
catch (error) {
|
|
11480
|
+
console.error(`__self-update: ${error instanceof Error ? error.message : error}`);
|
|
11481
|
+
process.exit(1);
|
|
11482
|
+
}
|
|
11483
|
+
}
|
|
11390
11484
|
const ROOT_FLEET_MUTATION_COMMANDS = new Set(['start', 'stop', 'restart', 'upgrade', 'update']);
|
|
11391
11485
|
if (ROOT_FLEET_MUTATION_COMMANDS.has(command ?? '')
|
|
11392
11486
|
&& process.argv.slice(3).some(arg => arg === '--help' || arg === '-h')) {
|
|
@@ -12244,7 +12338,7 @@ switch (command) {
|
|
|
12244
12338
|
break;
|
|
12245
12339
|
case 'upgrade':
|
|
12246
12340
|
case 'update':
|
|
12247
|
-
cmdUpgrade();
|
|
12341
|
+
await cmdUpgrade();
|
|
12248
12342
|
break;
|
|
12249
12343
|
case 'dashboard':
|
|
12250
12344
|
await cmdDashboard(process.argv.slice(3));
|