auvezy-terminal-remote 0.7.2 → 0.7.4
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 +232 -51
- package/frontend-dist/assets/{eruda-3AA1luxn.js → eruda-Dq-QSehU.js} +1 -1
- package/frontend-dist/assets/{index-jLMclWkI.css → index-D5cRW0Y1.css} +1 -1
- package/frontend-dist/assets/index-Dq14sZYp.js +359 -0
- package/frontend-dist/assets/zxing_reader-9hFayGnH.wasm +0 -0
- package/frontend-dist/index.html +2 -2
- package/frontend-dist/sw.js +1 -1
- package/package.json +1 -1
- package/frontend-dist/assets/index-B3ycRkAn.js +0 -359
package/dist/cli.js
CHANGED
|
@@ -14,7 +14,7 @@ var DEFAULT_PORT, DEFAULT_SESSION_TTL_MS, DEFAULT_AUTH_RATE_LIMIT, DEFAULT_MAX_B
|
|
|
14
14
|
var init_constants = __esm({
|
|
15
15
|
"shared/dist/constants.js"() {
|
|
16
16
|
"use strict";
|
|
17
|
-
DEFAULT_PORT =
|
|
17
|
+
DEFAULT_PORT = 3737;
|
|
18
18
|
DEFAULT_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
19
19
|
DEFAULT_AUTH_RATE_LIMIT = 20;
|
|
20
20
|
DEFAULT_MAX_BUFFER_LINES = 1e4;
|
|
@@ -608,6 +608,9 @@ function assignFlag(out, key, value) {
|
|
|
608
608
|
case "--strict-port":
|
|
609
609
|
out.strictPort = value === true || value === "true";
|
|
610
610
|
return;
|
|
611
|
+
case "--foreground":
|
|
612
|
+
out.foreground = value === true || value === "true";
|
|
613
|
+
return;
|
|
611
614
|
case "--help":
|
|
612
615
|
out.help = true;
|
|
613
616
|
return;
|
|
@@ -719,7 +722,8 @@ var init_cli_utils = __esm({
|
|
|
719
722
|
"--version",
|
|
720
723
|
"--no-open",
|
|
721
724
|
"--wait-confirm",
|
|
722
|
-
"--strict-port"
|
|
725
|
+
"--strict-port",
|
|
726
|
+
"--foreground"
|
|
723
727
|
]);
|
|
724
728
|
KNOWN_FLAGS_VALUE = /* @__PURE__ */ new Set([
|
|
725
729
|
"--port",
|
|
@@ -774,8 +778,9 @@ Usage:
|
|
|
774
778
|
atr <subcommand> [...] manage the broker / instances (see below)
|
|
775
779
|
|
|
776
780
|
Subcommands:
|
|
777
|
-
start [--port n] [--host ip] start the background service (broker)
|
|
778
|
-
|
|
781
|
+
start [--port n] [--host ip] start the background service (broker); the command
|
|
782
|
+
returns immediately once the broker is healthy.
|
|
783
|
+
add --foreground to keep it attached (systemd / Docker).
|
|
779
784
|
stop stop the background service
|
|
780
785
|
status one-shot view: process, token, entry URLs, instances
|
|
781
786
|
list list all live instances
|
|
@@ -804,7 +809,7 @@ Strict argument order:
|
|
|
804
809
|
atr -- --weird '--' forces split; default shell with '--weird'
|
|
805
810
|
|
|
806
811
|
Run options (for atr [program]):
|
|
807
|
-
-p, --port <n> Background service (broker) port (default
|
|
812
|
+
-p, --port <n> Background service (broker) port (default 3737). If broker is
|
|
808
813
|
already running and on a different port, atr will refuse to
|
|
809
814
|
start \u2014 run 'atr stop' first if you want to switch.
|
|
810
815
|
Worker ports are internal and auto-assigned; you don't set them.
|
|
@@ -842,7 +847,7 @@ Run options (for atr [program]):
|
|
|
842
847
|
passes through automatically)
|
|
843
848
|
|
|
844
849
|
Multi-instance:
|
|
845
|
-
The background service (broker) runs once on port
|
|
850
|
+
The background service (broker) runs once on port 3737 and is shared by all
|
|
846
851
|
instances. Running atr [program] in different terminals all connect to the
|
|
847
852
|
same service; PTY children are independent. Click the tab bar in the browser
|
|
848
853
|
to switch between them. If the service isn't running, the first atr will
|
|
@@ -2278,6 +2283,15 @@ var init_session_controller = __esm({
|
|
|
2278
2283
|
lastError = null;
|
|
2279
2284
|
/** Stop 携带的 last_assistant_message,可用于推送正文 */
|
|
2280
2285
|
lastAssistantMessage = null;
|
|
2286
|
+
/**
|
|
2287
|
+
* 用户已请求跳过当前 pending(在 awaiting approval 状态下按了 ESC),
|
|
2288
|
+
* 但稳态确认信号(approval_resolved / turn_ended / user_prompt / 非 ESC
|
|
2289
|
+
* 输入)尚未到达。
|
|
2290
|
+
*
|
|
2291
|
+
* 用作两阶段取消的中间状态:前端在 status bar 显示 "已请求跳过,等待确认...";
|
|
2292
|
+
* 任意稳态信号一到就转 false 并清 pending。
|
|
2293
|
+
*/
|
|
2294
|
+
pendingCancelRequested = false;
|
|
2281
2295
|
buffer;
|
|
2282
2296
|
writeToProcessStdout;
|
|
2283
2297
|
// ──────────── WS 输出批合并 ────────────
|
|
@@ -2394,6 +2408,7 @@ var init_session_controller = __esm({
|
|
|
2394
2408
|
}
|
|
2395
2409
|
case "turn_ended": {
|
|
2396
2410
|
this.activeTool = null;
|
|
2411
|
+
this.pendingApprovals.clear();
|
|
2397
2412
|
if (e.lastMessage)
|
|
2398
2413
|
this.lastAssistantMessage = e.lastMessage;
|
|
2399
2414
|
break;
|
|
@@ -2401,6 +2416,7 @@ var init_session_controller = __esm({
|
|
|
2401
2416
|
case "turn_failed": {
|
|
2402
2417
|
this.lastError = { kind: e.errorKind, ...e.detail ? { detail: e.detail } : {}, at: Date.now() };
|
|
2403
2418
|
this.activeTool = null;
|
|
2419
|
+
this.pendingApprovals.clear();
|
|
2404
2420
|
pushTitle = `Claude turn \u5931\u8D25:${e.errorKind}`;
|
|
2405
2421
|
pushBody = e.detail ?? e.errorKind;
|
|
2406
2422
|
break;
|
|
@@ -2409,11 +2425,20 @@ var init_session_controller = __esm({
|
|
|
2409
2425
|
logger.info({ phase: e.phase, detail: e.detail }, "session event");
|
|
2410
2426
|
break;
|
|
2411
2427
|
}
|
|
2412
|
-
case "cwd_changed":
|
|
2428
|
+
case "cwd_changed": {
|
|
2429
|
+
break;
|
|
2430
|
+
}
|
|
2413
2431
|
case "user_prompt": {
|
|
2432
|
+
if (this.pendingApprovals.size === 0 && !this.activeTool)
|
|
2433
|
+
return;
|
|
2434
|
+
this.pendingApprovals.clear();
|
|
2435
|
+
this.activeTool = null;
|
|
2414
2436
|
break;
|
|
2415
2437
|
}
|
|
2416
2438
|
}
|
|
2439
|
+
if (this.pendingApprovals.size === 0) {
|
|
2440
|
+
this.pendingCancelRequested = false;
|
|
2441
|
+
}
|
|
2417
2442
|
this.broadcastStatus();
|
|
2418
2443
|
if (pushTitle && this.pushService && this.pushContext) {
|
|
2419
2444
|
const ctx = this.pushContext;
|
|
@@ -2461,10 +2486,48 @@ var init_session_controller = __esm({
|
|
|
2461
2486
|
activeTool: this.activeTool?.summary ?? null,
|
|
2462
2487
|
pendingApprovals: this.pendingApprovals.size,
|
|
2463
2488
|
pendingApprovalTools: tools,
|
|
2489
|
+
// pendingCancelRequested 只在仍有 pending 时有意义,否则前端不渲染
|
|
2490
|
+
pendingCancelRequested: this.pendingApprovals.size > 0 && this.pendingCancelRequested,
|
|
2464
2491
|
lastError: this.lastError,
|
|
2465
2492
|
lastAssistantMessage: this.lastAssistantMessage
|
|
2466
2493
|
};
|
|
2467
2494
|
}
|
|
2495
|
+
/**
|
|
2496
|
+
* 观察用户输入,推断审批是否被取消
|
|
2497
|
+
*
|
|
2498
|
+
* 两阶段取消:
|
|
2499
|
+
* 1. 收到纯 ESC(单字节 `\x1b`)→ 标记 cancel_requested,broadcast(UI 显示
|
|
2500
|
+
* "已请求跳过,等待确认...")。不立即清 pending,以防 claude 内部把 ESC
|
|
2501
|
+
* 拦住继续等审批。
|
|
2502
|
+
* 2. cancel_requested 后,任何非 ESC 输入(回车 / 字母 / 方向键 `\x1b[A` 等
|
|
2503
|
+
* length>1 的 ESC 序列)= prompt 已回 idle、用户在打新内容 → 清 pending。
|
|
2504
|
+
*
|
|
2505
|
+
* hook 路径(approval_resolved / turn_ended / turn_failed / user_prompt)在
|
|
2506
|
+
* `onIntegrationEvent` 末尾会清 cancel_requested。
|
|
2507
|
+
*
|
|
2508
|
+
* 误判防护:仅 `pendingApprovals.size > 0` 时触发——vim/htop 里按 ESC 是常态,
|
|
2509
|
+
* 但那时 pending 为 0,不会动状态。
|
|
2510
|
+
*/
|
|
2511
|
+
observeUserInputForCancel(data) {
|
|
2512
|
+
if (this.pendingApprovals.size === 0)
|
|
2513
|
+
return;
|
|
2514
|
+
if (data.length === 0)
|
|
2515
|
+
return;
|
|
2516
|
+
const isEscOnly = data === "\x1B";
|
|
2517
|
+
if (!this.pendingCancelRequested) {
|
|
2518
|
+
if (isEscOnly) {
|
|
2519
|
+
this.pendingCancelRequested = true;
|
|
2520
|
+
this.broadcastStatus();
|
|
2521
|
+
}
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
if (isEscOnly)
|
|
2525
|
+
return;
|
|
2526
|
+
this.pendingApprovals.clear();
|
|
2527
|
+
this.pendingCancelRequested = false;
|
|
2528
|
+
this.activeTool = null;
|
|
2529
|
+
this.broadcastStatus();
|
|
2530
|
+
}
|
|
2468
2531
|
// ──────────────── 公共 API ────────────────
|
|
2469
2532
|
get status() {
|
|
2470
2533
|
return this.deriveStatus();
|
|
@@ -2519,6 +2582,7 @@ var init_session_controller = __esm({
|
|
|
2519
2582
|
this._baseStatus = "idle";
|
|
2520
2583
|
this.activeTool = null;
|
|
2521
2584
|
this.pendingApprovals.clear();
|
|
2585
|
+
this.pendingCancelRequested = false;
|
|
2522
2586
|
this.ws.broadcast({
|
|
2523
2587
|
type: "session_ended",
|
|
2524
2588
|
exitCode,
|
|
@@ -2601,6 +2665,7 @@ var init_session_controller = __esm({
|
|
|
2601
2665
|
handleWsMessage(wsConn, raw, {
|
|
2602
2666
|
onUserInput: (data) => {
|
|
2603
2667
|
this.pty.write(data);
|
|
2668
|
+
this.observeUserInputForCancel(data);
|
|
2604
2669
|
},
|
|
2605
2670
|
onResize: (cols, rows, source, master) => {
|
|
2606
2671
|
const counts = this.ws.getClientCounts();
|
|
@@ -3813,7 +3878,7 @@ function buildHooksConfig(port, toggles = DEFAULT_CLAUDE_CODE_EVENTS) {
|
|
|
3813
3878
|
out["PostCompact"] = allMatcher;
|
|
3814
3879
|
out["CwdChanged"] = allMatcher;
|
|
3815
3880
|
}
|
|
3816
|
-
if (toggles.userPrompts) {
|
|
3881
|
+
if (toggles.userPrompts || toggles.approvals) {
|
|
3817
3882
|
out["UserPromptSubmit"] = allMatcher;
|
|
3818
3883
|
}
|
|
3819
3884
|
return out;
|
|
@@ -4437,7 +4502,7 @@ async function renderQrCode(url, opts = {}) {
|
|
|
4437
4502
|
try {
|
|
4438
4503
|
return await QRCode.toString(url, {
|
|
4439
4504
|
type: "utf8",
|
|
4440
|
-
errorCorrectionLevel: opts.errorCorrectionLevel ?? "
|
|
4505
|
+
errorCorrectionLevel: opts.errorCorrectionLevel ?? "M",
|
|
4441
4506
|
// utf8 模式本身就是半字符垂直压缩,体积约 qrcode-terminal small=true 的 1/2。
|
|
4442
4507
|
// margin: utf8 渲染器在 margin=1 时有"Invalid array length" bug,避开它;
|
|
4443
4508
|
// margin=2 视觉上仍然紧凑,且扫码识别率更高
|
|
@@ -5512,7 +5577,7 @@ var init_broker_server = __esm({
|
|
|
5512
5577
|
init_instance_router();
|
|
5513
5578
|
init_router();
|
|
5514
5579
|
init_port_finder();
|
|
5515
|
-
DEFAULT_BROKER_PORT =
|
|
5580
|
+
DEFAULT_BROKER_PORT = 3737;
|
|
5516
5581
|
DEFAULT_BROKER_HOST = "0.0.0.0";
|
|
5517
5582
|
}
|
|
5518
5583
|
});
|
|
@@ -5691,6 +5756,41 @@ var init_broker = __esm({
|
|
|
5691
5756
|
}
|
|
5692
5757
|
});
|
|
5693
5758
|
|
|
5759
|
+
// backend/dist/utils/wsl-detect.js
|
|
5760
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
5761
|
+
function isWsl(deps) {
|
|
5762
|
+
if (cached !== void 0 && deps === void 0)
|
|
5763
|
+
return cached;
|
|
5764
|
+
const platform2 = deps?.platform ?? process.platform;
|
|
5765
|
+
if (platform2 !== "linux") {
|
|
5766
|
+
if (deps === void 0)
|
|
5767
|
+
cached = false;
|
|
5768
|
+
return false;
|
|
5769
|
+
}
|
|
5770
|
+
let content;
|
|
5771
|
+
try {
|
|
5772
|
+
content = (deps?.readProcVersion ?? defaultReadProcVersion)();
|
|
5773
|
+
} catch {
|
|
5774
|
+
if (deps === void 0)
|
|
5775
|
+
cached = false;
|
|
5776
|
+
return false;
|
|
5777
|
+
}
|
|
5778
|
+
const lower = content.toLowerCase();
|
|
5779
|
+
const result = lower.includes("microsoft") || lower.includes("wsl");
|
|
5780
|
+
if (deps === void 0)
|
|
5781
|
+
cached = result;
|
|
5782
|
+
return result;
|
|
5783
|
+
}
|
|
5784
|
+
function defaultReadProcVersion() {
|
|
5785
|
+
return readFileSync9("/proc/version", "utf-8");
|
|
5786
|
+
}
|
|
5787
|
+
var cached;
|
|
5788
|
+
var init_wsl_detect = __esm({
|
|
5789
|
+
"backend/dist/utils/wsl-detect.js"() {
|
|
5790
|
+
"use strict";
|
|
5791
|
+
}
|
|
5792
|
+
});
|
|
5793
|
+
|
|
5694
5794
|
// backend/dist/broker/entry-discovery.js
|
|
5695
5795
|
var entry_discovery_exports = {};
|
|
5696
5796
|
__export(entry_discovery_exports, {
|
|
@@ -5737,13 +5837,8 @@ function discoverEntries(opts) {
|
|
|
5737
5837
|
url: buildEntryUrl("127.0.0.1", brokerPort, instanceId, urlOpts)
|
|
5738
5838
|
});
|
|
5739
5839
|
}
|
|
5740
|
-
const
|
|
5741
|
-
|
|
5742
|
-
lan: 1,
|
|
5743
|
-
ipv6: 2,
|
|
5744
|
-
other: 3,
|
|
5745
|
-
loopback: 4
|
|
5746
|
-
};
|
|
5840
|
+
const wsl = isWsl();
|
|
5841
|
+
const order = wsl ? { lan: 0, ipv6: 1, tailscale: 2, other: 3, loopback: 4 } : { tailscale: 0, lan: 1, ipv6: 2, other: 3, loopback: 4 };
|
|
5747
5842
|
out.sort((a, b) => {
|
|
5748
5843
|
if (a.kind !== b.kind)
|
|
5749
5844
|
return order[a.kind] - order[b.kind];
|
|
@@ -5804,6 +5899,7 @@ var init_entry_discovery = __esm({
|
|
|
5804
5899
|
"backend/dist/broker/entry-discovery.js"() {
|
|
5805
5900
|
"use strict";
|
|
5806
5901
|
init_network();
|
|
5902
|
+
init_wsl_detect();
|
|
5807
5903
|
}
|
|
5808
5904
|
});
|
|
5809
5905
|
|
|
@@ -6301,17 +6397,17 @@ hint: check whether ~/.atr/broker.json is held by a stale process; set ATR_DEBUG
|
|
|
6301
6397
|
setTimeout(() => triggerSpawn("timeout"), cfg.spawnTimeoutSec * 1e3).unref();
|
|
6302
6398
|
}
|
|
6303
6399
|
}
|
|
6400
|
+
const brokerHost = brokerState.host === "0.0.0.0" || brokerState.host === "::" ? displayIp : brokerState.host;
|
|
6304
6401
|
void registry.register({
|
|
6305
6402
|
instanceId,
|
|
6306
6403
|
name: cfg.instanceName,
|
|
6307
|
-
// 0.7.0:host 改为 worker 实际监听地址(loopback)。broker 阶段 3 反代时
|
|
6308
|
-
// 直接用这个 host:port 连 worker。displayIp 已不参与 worker 注册
|
|
6309
6404
|
host: "127.0.0.1",
|
|
6310
6405
|
port: cfg.port,
|
|
6311
6406
|
pid: process.pid,
|
|
6312
6407
|
cwd: cfg.claudeCwd,
|
|
6313
6408
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6314
|
-
headless: cfg.noTerminal
|
|
6409
|
+
headless: cfg.noTerminal,
|
|
6410
|
+
...brokerHost ? { brokerHost } : {}
|
|
6315
6411
|
}).catch((err) => logger.warn({ err }, "\u6CE8\u518C\u5B9E\u4F8B\u5931\u8D25"));
|
|
6316
6412
|
logger.info({
|
|
6317
6413
|
port: cfg.port,
|
|
@@ -7386,7 +7482,7 @@ __export(service_installer_exports, {
|
|
|
7386
7482
|
renderSystemdUnit: () => renderSystemdUnit,
|
|
7387
7483
|
uninstall: () => uninstall
|
|
7388
7484
|
});
|
|
7389
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as
|
|
7485
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync10, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
7390
7486
|
import { resolve as resolve15, dirname as dirname8 } from "node:path";
|
|
7391
7487
|
import { homedir as homedir9, platform } from "node:os";
|
|
7392
7488
|
function detectPlatform(env = process.env, plat = platform()) {
|
|
@@ -7408,7 +7504,7 @@ After=network.target
|
|
|
7408
7504
|
|
|
7409
7505
|
[Service]
|
|
7410
7506
|
Type=simple
|
|
7411
|
-
ExecStart=${opts.nodeBin} ${opts.cliPath} start
|
|
7507
|
+
ExecStart=${opts.nodeBin} ${opts.cliPath} start --foreground
|
|
7412
7508
|
Restart=on-failure
|
|
7413
7509
|
RestartSec=5s
|
|
7414
7510
|
${portEnv}[Install]
|
|
@@ -7433,6 +7529,7 @@ function renderLaunchdPlist(opts) {
|
|
|
7433
7529
|
<string>${opts.nodeBin}</string>
|
|
7434
7530
|
<string>${opts.cliPath}</string>
|
|
7435
7531
|
<string>start</string>
|
|
7532
|
+
<string>--foreground</string>
|
|
7436
7533
|
</array>
|
|
7437
7534
|
<key>RunAtLoad</key><true/>
|
|
7438
7535
|
<key>KeepAlive</key><true/>
|
|
@@ -7548,7 +7645,7 @@ var init_service_installer = __esm({
|
|
|
7548
7645
|
mkdirSync12(p, o);
|
|
7549
7646
|
},
|
|
7550
7647
|
writeFileSync: (p, d, o) => writeFileSync5(p, d, { encoding: "utf-8", ...o ?? {} }),
|
|
7551
|
-
readFileSync: (p) =>
|
|
7648
|
+
readFileSync: (p) => readFileSync10(p, "utf-8"),
|
|
7552
7649
|
rmSync: rmSync3
|
|
7553
7650
|
};
|
|
7554
7651
|
ServicePlatformUnsupportedError = class extends AppError {
|
|
@@ -7605,8 +7702,8 @@ var cli_exports = {};
|
|
|
7605
7702
|
__export(cli_exports, {
|
|
7606
7703
|
runServiceCli: () => runServiceCli
|
|
7607
7704
|
});
|
|
7608
|
-
import { execSync as execSync2 } from "node:child_process";
|
|
7609
|
-
import { readFileSync as
|
|
7705
|
+
import { execSync as execSync2, spawn as spawn4 } from "node:child_process";
|
|
7706
|
+
import { existsSync as existsSync16, openSync as openSync3, readFileSync as readFileSync11 } from "node:fs";
|
|
7610
7707
|
import { resolve as resolve16, dirname as dirname9 } from "node:path";
|
|
7611
7708
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
7612
7709
|
import { homedir as homedir10 } from "node:os";
|
|
@@ -7619,7 +7716,7 @@ function getBrokerVersion() {
|
|
|
7619
7716
|
];
|
|
7620
7717
|
for (const pkgPath of candidates) {
|
|
7621
7718
|
try {
|
|
7622
|
-
const pkg = JSON.parse(
|
|
7719
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
7623
7720
|
if (pkg.name === "auvezy-terminal-remote" && typeof pkg.version === "string") {
|
|
7624
7721
|
return pkg.version;
|
|
7625
7722
|
}
|
|
@@ -7631,18 +7728,19 @@ function getBrokerVersion() {
|
|
|
7631
7728
|
}
|
|
7632
7729
|
function getCliPath() {
|
|
7633
7730
|
const __dirname2 = dirname9(fileURLToPath3(import.meta.url));
|
|
7634
|
-
const
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
readFileSync10(p);
|
|
7641
|
-
return p;
|
|
7642
|
-
} catch {
|
|
7643
|
-
}
|
|
7731
|
+
const parentDir = resolve16(__dirname2, "..", "cli.js");
|
|
7732
|
+
const sameDir = resolve16(__dirname2, "cli.js");
|
|
7733
|
+
try {
|
|
7734
|
+
readFileSync11(parentDir);
|
|
7735
|
+
return parentDir;
|
|
7736
|
+
} catch {
|
|
7644
7737
|
}
|
|
7645
|
-
|
|
7738
|
+
try {
|
|
7739
|
+
readFileSync11(sameDir);
|
|
7740
|
+
return sameDir;
|
|
7741
|
+
} catch {
|
|
7742
|
+
}
|
|
7743
|
+
return parentDir;
|
|
7646
7744
|
}
|
|
7647
7745
|
async function runServiceCli(action, cli) {
|
|
7648
7746
|
switch (action) {
|
|
@@ -7663,6 +7761,10 @@ async function runServiceCli(action, cli) {
|
|
|
7663
7761
|
}
|
|
7664
7762
|
}
|
|
7665
7763
|
async function runBrokerStart(cli) {
|
|
7764
|
+
const wantForeground = cli.foreground === true || process.env["ATR_BROKER_FOREGROUND"] === "1";
|
|
7765
|
+
if (!wantForeground) {
|
|
7766
|
+
return runBrokerStartDaemonize(cli);
|
|
7767
|
+
}
|
|
7666
7768
|
const port = cli.port ?? parseEnvPort(process.env["ATR_BROKER_PORT"]) ?? DEFAULT_BROKER_PORT;
|
|
7667
7769
|
const host = cli.host ?? process.env["ATR_BROKER_HOST"] ?? DEFAULT_BROKER_HOST;
|
|
7668
7770
|
const brokerVersion = getBrokerVersion();
|
|
@@ -7705,7 +7807,7 @@ async function runBrokerStart(cli) {
|
|
|
7705
7807
|
const pushService = new PushService();
|
|
7706
7808
|
await pushService.init();
|
|
7707
7809
|
startInstanceWatcher(registry.filePath);
|
|
7708
|
-
const cliJsPath =
|
|
7810
|
+
const cliJsPath = getCliPath();
|
|
7709
7811
|
const workdirAllow = currentUserConfig.workdirAllow;
|
|
7710
7812
|
const workdirDeny = currentUserConfig.workdirDeny;
|
|
7711
7813
|
const spawner = new DefaultInstanceSpawner({
|
|
@@ -7780,6 +7882,83 @@ function installBrokerLogRotator() {
|
|
|
7780
7882
|
});
|
|
7781
7883
|
return rotator;
|
|
7782
7884
|
}
|
|
7885
|
+
async function runBrokerStartDaemonize(cli) {
|
|
7886
|
+
const tag = c.cyan("[atr]");
|
|
7887
|
+
const port = cli.port ?? parseEnvPort(process.env["ATR_BROKER_PORT"]) ?? DEFAULT_BROKER_PORT;
|
|
7888
|
+
const existing = readBrokerState();
|
|
7889
|
+
if (existing && isBrokerAlive(existing)) {
|
|
7890
|
+
process.stderr.write(`${tag} broker already running on ${existing.host}:${existing.port} (pid=${existing.pid})
|
|
7891
|
+
`);
|
|
7892
|
+
return 0;
|
|
7893
|
+
}
|
|
7894
|
+
const cliJsPath = getCliPath();
|
|
7895
|
+
const entry = resolveDaemonEntry(cliJsPath);
|
|
7896
|
+
const logFd = process.env["ATR_DEBUG_SPAWN"] ? openSync3(`/tmp/atr-broker-${Date.now()}.log`, "a") : "ignore";
|
|
7897
|
+
const childEnv = {
|
|
7898
|
+
...process.env,
|
|
7899
|
+
ATR_BROKER_FOREGROUND: "1"
|
|
7900
|
+
};
|
|
7901
|
+
if (cli.port !== void 0)
|
|
7902
|
+
childEnv["ATR_BROKER_PORT"] = String(cli.port);
|
|
7903
|
+
if (cli.host !== void 0)
|
|
7904
|
+
childEnv["ATR_BROKER_HOST"] = cli.host;
|
|
7905
|
+
if (cli.strictPort)
|
|
7906
|
+
childEnv["ATR_BROKER_STRICT_PORT"] = "1";
|
|
7907
|
+
const child = spawn4(entry.execPath, [...entry.args, "start", "--foreground"], {
|
|
7908
|
+
env: childEnv,
|
|
7909
|
+
detached: true,
|
|
7910
|
+
stdio: ["ignore", logFd, logFd]
|
|
7911
|
+
});
|
|
7912
|
+
if (typeof child.pid !== "number") {
|
|
7913
|
+
process.stderr.write(`${tag} failed to spawn broker subprocess (no pid)
|
|
7914
|
+
`);
|
|
7915
|
+
return 1;
|
|
7916
|
+
}
|
|
7917
|
+
const earlyExit = [];
|
|
7918
|
+
const earlyError = [];
|
|
7919
|
+
child.once("error", (e) => {
|
|
7920
|
+
earlyError.push(e);
|
|
7921
|
+
});
|
|
7922
|
+
child.once("exit", (code, signal) => {
|
|
7923
|
+
earlyExit.push({ code, signal });
|
|
7924
|
+
});
|
|
7925
|
+
child.unref();
|
|
7926
|
+
const t0 = Date.now();
|
|
7927
|
+
const statePath = defaultBrokerStatePath();
|
|
7928
|
+
while (Date.now() - t0 < DAEMONIZE_TIMEOUT_MS) {
|
|
7929
|
+
const st = readBrokerState(statePath);
|
|
7930
|
+
if (st && isBrokerAlive(st) && st.pid === child.pid) {
|
|
7931
|
+
process.stdout.write(`${tag} broker started on ${c.green(`${st.host}:${st.port}`)} (pid=${st.pid})
|
|
7932
|
+
`);
|
|
7933
|
+
return 0;
|
|
7934
|
+
}
|
|
7935
|
+
await sleep4(DAEMONIZE_POLL_INTERVAL_MS);
|
|
7936
|
+
}
|
|
7937
|
+
let detail = "";
|
|
7938
|
+
if (earlyError[0]) {
|
|
7939
|
+
detail = `
|
|
7940
|
+
- spawn error: ${earlyError[0].message}`;
|
|
7941
|
+
} else if (earlyExit[0]) {
|
|
7942
|
+
detail = `
|
|
7943
|
+
- child exited early (code=${earlyExit[0].code}, signal=${earlyExit[0].signal})`;
|
|
7944
|
+
}
|
|
7945
|
+
process.stderr.write(`${tag} broker did not become ready within ${DAEMONIZE_TIMEOUT_MS}ms.${detail}
|
|
7946
|
+
- check ~/.auvezy/terminal-remote/broker-*.log for errors
|
|
7947
|
+
- or set ATR_DEBUG_SPAWN=1 and retry to capture /tmp/atr-broker-*.log
|
|
7948
|
+
- port ${port} may be busy; try '--port <other>' or '--strict-port' to fail fast
|
|
7949
|
+
`);
|
|
7950
|
+
return 1;
|
|
7951
|
+
}
|
|
7952
|
+
function resolveDaemonEntry(cliJsPath) {
|
|
7953
|
+
if (existsSync16(cliJsPath)) {
|
|
7954
|
+
return { execPath: process.execPath, args: [cliJsPath] };
|
|
7955
|
+
}
|
|
7956
|
+
const tsPath = cliJsPath.replace(/\.js$/, ".ts");
|
|
7957
|
+
if (existsSync16(tsPath)) {
|
|
7958
|
+
return { execPath: process.execPath, args: ["--import", "tsx", tsPath] };
|
|
7959
|
+
}
|
|
7960
|
+
return { execPath: process.execPath, args: [cliJsPath] };
|
|
7961
|
+
}
|
|
7783
7962
|
async function runBrokerStop() {
|
|
7784
7963
|
const tag = c.cyan("[atr]");
|
|
7785
7964
|
const state = readBrokerState();
|
|
@@ -7937,12 +8116,12 @@ function writeServiceInstallSection() {
|
|
|
7937
8116
|
async function writeTokenSection() {
|
|
7938
8117
|
process.stdout.write(c.bold("=== Token ===\n"));
|
|
7939
8118
|
try {
|
|
7940
|
-
const { readFileSync:
|
|
8119
|
+
const { readFileSync: readFileSync12, statSync: statSync6 } = await import("node:fs");
|
|
7941
8120
|
const { resolve: pathResolve2 } = await import("node:path");
|
|
7942
8121
|
const { homedir: homedir11 } = await import("node:os");
|
|
7943
8122
|
const path = pathResolve2(homedir11(), ".atrrc");
|
|
7944
8123
|
const stat = statSync6(path);
|
|
7945
|
-
const cfg = JSON.parse(
|
|
8124
|
+
const cfg = JSON.parse(readFileSync12(path, "utf-8"));
|
|
7946
8125
|
if (typeof cfg.token === "string" && cfg.token.length > 0) {
|
|
7947
8126
|
process.stdout.write(` token: ${cfg.token}
|
|
7948
8127
|
`);
|
|
@@ -7964,10 +8143,10 @@ async function writeEntriesSection(brokerPort) {
|
|
|
7964
8143
|
const { discoverEntries: discoverEntries2, kindLabel: kindLabel2 } = await Promise.resolve().then(() => (init_entry_discovery(), entry_discovery_exports));
|
|
7965
8144
|
let token;
|
|
7966
8145
|
try {
|
|
7967
|
-
const { readFileSync:
|
|
8146
|
+
const { readFileSync: readFileSync12 } = await import("node:fs");
|
|
7968
8147
|
const { resolve: pathResolve2 } = await import("node:path");
|
|
7969
8148
|
const { homedir: homedir11 } = await import("node:os");
|
|
7970
|
-
const cfg = JSON.parse(
|
|
8149
|
+
const cfg = JSON.parse(readFileSync12(pathResolve2(homedir11(), ".atrrc"), "utf-8"));
|
|
7971
8150
|
if (typeof cfg.token === "string" && cfg.token.length > 0)
|
|
7972
8151
|
token = cfg.token;
|
|
7973
8152
|
} catch {
|
|
@@ -8026,12 +8205,12 @@ async function runListInstances() {
|
|
|
8026
8205
|
async function runShowLogs() {
|
|
8027
8206
|
const { homedir: homedir11 } = await import("node:os");
|
|
8028
8207
|
const { resolve: pathResolve2 } = await import("node:path");
|
|
8029
|
-
const { existsSync:
|
|
8030
|
-
const { spawn:
|
|
8208
|
+
const { existsSync: existsSync17 } = await import("node:fs");
|
|
8209
|
+
const { spawn: spawn5 } = await import("node:child_process");
|
|
8031
8210
|
const today = /* @__PURE__ */ new Date();
|
|
8032
8211
|
const day = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(today.getDate()).padStart(2, "0")}`;
|
|
8033
8212
|
const logPath = pathResolve2(homedir11(), ".atr", `broker-${day}.log`);
|
|
8034
|
-
if (!
|
|
8213
|
+
if (!existsSync17(logPath)) {
|
|
8035
8214
|
process.stderr.write(`[atr] today's log not found: ${logPath}
|
|
8036
8215
|
hint: is the service running? try atr status, or atr start to launch.
|
|
8037
8216
|
`);
|
|
@@ -8039,14 +8218,14 @@ hint: is the service running? try atr status, or atr start to launch.
|
|
|
8039
8218
|
}
|
|
8040
8219
|
process.stderr.write(`[atr] tail -F ${logPath} (Ctrl+C to quit)
|
|
8041
8220
|
`);
|
|
8042
|
-
const tail =
|
|
8221
|
+
const tail = spawn5("tail", ["-F", logPath], { stdio: "inherit" });
|
|
8043
8222
|
return new Promise((resolveExit) => {
|
|
8044
8223
|
tail.on("error", (err) => {
|
|
8045
8224
|
process.stderr.write(`[atr] cannot spawn tail (${err.message}); falling back to one-shot output:
|
|
8046
8225
|
`);
|
|
8047
|
-
void import("node:fs").then(({ readFileSync:
|
|
8226
|
+
void import("node:fs").then(({ readFileSync: readFileSync12 }) => {
|
|
8048
8227
|
try {
|
|
8049
|
-
process.stdout.write(
|
|
8228
|
+
process.stdout.write(readFileSync12(logPath, "utf-8"));
|
|
8050
8229
|
resolveExit(0);
|
|
8051
8230
|
} catch (e) {
|
|
8052
8231
|
process.stderr.write(`[atr] failed to read log: ${e.message}
|
|
@@ -8132,7 +8311,7 @@ function parseEnvPort(raw) {
|
|
|
8132
8311
|
function sleep4(ms) {
|
|
8133
8312
|
return new Promise((r) => setTimeout(r, ms));
|
|
8134
8313
|
}
|
|
8135
|
-
var STOP_GRACE_MS, STOP_POLL_INTERVAL_MS;
|
|
8314
|
+
var DAEMONIZE_TIMEOUT_MS, DAEMONIZE_POLL_INTERVAL_MS, STOP_GRACE_MS, STOP_POLL_INTERVAL_MS;
|
|
8136
8315
|
var init_cli = __esm({
|
|
8137
8316
|
"backend/dist/broker/cli.js"() {
|
|
8138
8317
|
"use strict";
|
|
@@ -8154,6 +8333,8 @@ var init_cli = __esm({
|
|
|
8154
8333
|
init_broker_state();
|
|
8155
8334
|
init_service_installer();
|
|
8156
8335
|
init_colors();
|
|
8336
|
+
DAEMONIZE_TIMEOUT_MS = 8e3;
|
|
8337
|
+
DAEMONIZE_POLL_INTERVAL_MS = 100;
|
|
8157
8338
|
STOP_GRACE_MS = 5e3;
|
|
8158
8339
|
STOP_POLL_INTERVAL_MS = 100;
|
|
8159
8340
|
}
|
|
@@ -8222,11 +8403,11 @@ void (async () => {
|
|
|
8222
8403
|
process.exit(0);
|
|
8223
8404
|
}
|
|
8224
8405
|
if (cli.version) {
|
|
8225
|
-
const { readFileSync:
|
|
8406
|
+
const { readFileSync: readFileSync12 } = await import("node:fs");
|
|
8226
8407
|
const { resolve: resolve17, dirname: dirname10 } = await import("node:path");
|
|
8227
8408
|
const { fileURLToPath: fileURLToPath4 } = await import("node:url");
|
|
8228
8409
|
const __dirname2 = dirname10(fileURLToPath4(import.meta.url));
|
|
8229
|
-
const pkg = JSON.parse(
|
|
8410
|
+
const pkg = JSON.parse(readFileSync12(resolve17(__dirname2, "..", "package.json"), "utf-8"));
|
|
8230
8411
|
process.stdout.write(`${pkg.version}
|
|
8231
8412
|
`);
|
|
8232
8413
|
process.exit(0);
|