@ganglion/xacpx 0.17.0-beta.5 → 0.17.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/bridge/bridge-main.js +72 -20
- package/dist/cli.js +688 -94
- package/dist/config/agent-catalog.d.ts +24 -6
- package/dist/control/control-service.d.ts +36 -1
- package/dist/control/workspace-git.d.ts +93 -0
- package/dist/plugin-api.js +49 -14
- package/dist/transport/command-timeouts.d.ts +47 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ If you need to code or work remotely on a temporary basis, `xacpx` gives you a f
|
|
|
29
29
|
|
|
30
30
|
### Prerequisites
|
|
31
31
|
|
|
32
|
-
- Node.js 22+ or Bun
|
|
32
|
+
- Node.js 22.12+ or Bun
|
|
33
33
|
- A working agent CLI you intend to use, such as Codex / Claude Code / Gemini / OpenCode
|
|
34
34
|
- A phone with WeChat, Feishu, or Yuanbao installed
|
|
35
35
|
|
|
@@ -182,7 +182,7 @@ xacpx-relay add token # prints the access token once
|
|
|
182
182
|
xacpx-relay start # defaults: --host 0.0.0.0 --http-port 8787
|
|
183
183
|
|
|
184
184
|
# On each instance host:
|
|
185
|
-
xacpx plugin add @ganglion/xacpx-channel-relay # requires xacpx >= 0.
|
|
185
|
+
xacpx plugin add @ganglion/xacpx-channel-relay # requires xacpx >= 0.17.0-beta.6
|
|
186
186
|
xacpx channel add relay --url wss://relay.example.com --token <access-token> --name my-box
|
|
187
187
|
xacpx restart
|
|
188
188
|
```
|
|
@@ -3687,7 +3687,43 @@ async function deleteAcpxSessionFiles(options) {
|
|
|
3687
3687
|
var init_acpx_session_files = () => {};
|
|
3688
3688
|
|
|
3689
3689
|
// src/transport/command-timeouts.ts
|
|
3690
|
-
|
|
3690
|
+
function formatTimeout(timeoutMs) {
|
|
3691
|
+
return timeoutMs >= 1000 ? `${timeoutMs / 1000}s` : `${timeoutMs}ms`;
|
|
3692
|
+
}
|
|
3693
|
+
function captureOutputTail(value) {
|
|
3694
|
+
const normalized = value?.trim();
|
|
3695
|
+
if (!normalized)
|
|
3696
|
+
return;
|
|
3697
|
+
return normalized.slice(-COMMAND_OUTPUT_TAIL_CHARS);
|
|
3698
|
+
}
|
|
3699
|
+
function isCommandTimeoutError(error) {
|
|
3700
|
+
return error instanceof CommandTimeoutError;
|
|
3701
|
+
}
|
|
3702
|
+
var DEFAULT_MANAGEMENT_COMMAND_TIMEOUT_MS = 30000, DEFAULT_SESSION_INIT_TIMEOUT_MS = 120000, BRIDGE_REQUEST_TIMEOUT_GRACE_MS = 15000, COMMAND_OUTPUT_TAIL_CHARS = 2000, CommandTimeoutError;
|
|
3703
|
+
var init_command_timeouts = __esm(() => {
|
|
3704
|
+
CommandTimeoutError = class CommandTimeoutError extends Error {
|
|
3705
|
+
timeoutMs;
|
|
3706
|
+
command;
|
|
3707
|
+
stage;
|
|
3708
|
+
stdoutTail;
|
|
3709
|
+
stderrTail;
|
|
3710
|
+
constructor(timeoutMs, command, detail = {}) {
|
|
3711
|
+
const stdoutTail = captureOutputTail(detail.stdout);
|
|
3712
|
+
const stderrTail = captureOutputTail(detail.stderr);
|
|
3713
|
+
const output = [
|
|
3714
|
+
stdoutTail ? `stdout tail: ${stdoutTail}` : "",
|
|
3715
|
+
stderrTail ? `stderr tail: ${stderrTail}` : ""
|
|
3716
|
+
].filter(Boolean).join("; ");
|
|
3717
|
+
super(`acpx command timed out${detail.stage ? ` during ${detail.stage}` : ""} after ${formatTimeout(timeoutMs)}: ${command}` + (output ? `; ${output}` : ""));
|
|
3718
|
+
this.timeoutMs = timeoutMs;
|
|
3719
|
+
this.command = command;
|
|
3720
|
+
this.name = "CommandTimeoutError";
|
|
3721
|
+
this.stage = detail.stage;
|
|
3722
|
+
this.stdoutTail = stdoutTail;
|
|
3723
|
+
this.stderrTail = stderrTail;
|
|
3724
|
+
}
|
|
3725
|
+
};
|
|
3726
|
+
});
|
|
3691
3727
|
|
|
3692
3728
|
// src/transport/permission-mode-flag.ts
|
|
3693
3729
|
function permissionModeToFlag(permissionMode) {
|
|
@@ -3873,6 +3909,8 @@ init_acpx_queue_owner_launcher();
|
|
|
3873
3909
|
init_agent_session_list();
|
|
3874
3910
|
init_codex_subagent_filter();
|
|
3875
3911
|
init_acpx_session_files();
|
|
3912
|
+
init_command_timeouts();
|
|
3913
|
+
init_command_timeouts();
|
|
3876
3914
|
init_acpx_command_builder();
|
|
3877
3915
|
class EnsureSessionFailedError extends Error {
|
|
3878
3916
|
kind;
|
|
@@ -3885,15 +3923,6 @@ class EnsureSessionFailedError extends Error {
|
|
|
3885
3923
|
}
|
|
3886
3924
|
}
|
|
3887
3925
|
|
|
3888
|
-
class CommandTimeoutError extends Error {
|
|
3889
|
-
timeoutMs;
|
|
3890
|
-
constructor(timeoutMs, command) {
|
|
3891
|
-
super(`acpx command timed out after ${timeoutMs / 1000}s: ${command}`);
|
|
3892
|
-
this.timeoutMs = timeoutMs;
|
|
3893
|
-
this.name = "CommandTimeoutError";
|
|
3894
|
-
}
|
|
3895
|
-
}
|
|
3896
|
-
|
|
3897
3926
|
class BridgeRuntime {
|
|
3898
3927
|
command;
|
|
3899
3928
|
run;
|
|
@@ -3976,12 +4005,14 @@ class BridgeRuntime {
|
|
|
3976
4005
|
input.name
|
|
3977
4006
|
]));
|
|
3978
4007
|
const result = await this.run(spawnSpec.command, spawnSpec.args, {
|
|
3979
|
-
timeoutMs: this.managementCommandTimeoutMs()
|
|
4008
|
+
timeoutMs: this.managementCommandTimeoutMs(),
|
|
4009
|
+
stage: "has-session"
|
|
3980
4010
|
});
|
|
3981
4011
|
return { exists: result.code === 0 };
|
|
3982
4012
|
}
|
|
3983
4013
|
async tailSessionHistory(input) {
|
|
3984
4014
|
const candidates = [
|
|
4015
|
+
["sessions", "history", input.name, "--limit", String(input.lines)],
|
|
3985
4016
|
["sessions", "history", "quiet", "-s", input.name, String(input.lines)],
|
|
3986
4017
|
["sessions", "history", "quiet", input.name, String(input.lines)],
|
|
3987
4018
|
["sessions", "history", "-s", input.name, "--tail", String(input.lines)],
|
|
@@ -3993,7 +4024,8 @@ class BridgeRuntime {
|
|
|
3993
4024
|
for (const tailArgs of candidates) {
|
|
3994
4025
|
const spawnSpec = resolveSpawnCommand(this.command, this.buildSessionArgs(input, tailArgs));
|
|
3995
4026
|
const result = await this.run(spawnSpec.command, spawnSpec.args, {
|
|
3996
|
-
timeoutMs: Math.max(deadline - Date.now(), 1)
|
|
4027
|
+
timeoutMs: Math.max(deadline - Date.now(), 1),
|
|
4028
|
+
stage: "session-history"
|
|
3997
4029
|
});
|
|
3998
4030
|
if (result.code === 0) {
|
|
3999
4031
|
return { text: result.stdout.trimEnd() };
|
|
@@ -4162,7 +4194,8 @@ class BridgeRuntime {
|
|
|
4162
4194
|
input.name
|
|
4163
4195
|
]));
|
|
4164
4196
|
const result = await this.run(spawnSpec.command, spawnSpec.args, {
|
|
4165
|
-
timeoutMs: this.managementCommandTimeoutMs()
|
|
4197
|
+
timeoutMs: this.managementCommandTimeoutMs(),
|
|
4198
|
+
stage: "read-session-record"
|
|
4166
4199
|
});
|
|
4167
4200
|
if (result.code !== 0) {
|
|
4168
4201
|
throw new Error(result.stderr || result.stdout || "sessions show failed");
|
|
@@ -4184,7 +4217,8 @@ class BridgeRuntime {
|
|
|
4184
4217
|
input.modeId
|
|
4185
4218
|
]));
|
|
4186
4219
|
const result = await this.run(spawnSpec.command, spawnSpec.args, {
|
|
4187
|
-
timeoutMs: this.managementCommandTimeoutMs()
|
|
4220
|
+
timeoutMs: this.managementCommandTimeoutMs(),
|
|
4221
|
+
stage: "set-mode"
|
|
4188
4222
|
});
|
|
4189
4223
|
if (result.code !== 0) {
|
|
4190
4224
|
throw new Error(result.stderr || result.stdout || "set-mode failed");
|
|
@@ -4200,7 +4234,8 @@ class BridgeRuntime {
|
|
|
4200
4234
|
input.modelId
|
|
4201
4235
|
]));
|
|
4202
4236
|
const result = await this.run(spawnSpec.command, spawnSpec.args, {
|
|
4203
|
-
timeoutMs: this.managementCommandTimeoutMs()
|
|
4237
|
+
timeoutMs: this.managementCommandTimeoutMs(),
|
|
4238
|
+
stage: "set-model"
|
|
4204
4239
|
});
|
|
4205
4240
|
if (result.code !== 0) {
|
|
4206
4241
|
throw new Error(result.stderr || result.stdout || "set-model failed");
|
|
@@ -4214,7 +4249,8 @@ class BridgeRuntime {
|
|
|
4214
4249
|
input.name
|
|
4215
4250
|
], { format: "json" }));
|
|
4216
4251
|
const result = await this.run(spawnSpec.command, spawnSpec.args, {
|
|
4217
|
-
timeoutMs: this.managementCommandTimeoutMs()
|
|
4252
|
+
timeoutMs: this.managementCommandTimeoutMs(),
|
|
4253
|
+
stage: "get-session-model"
|
|
4218
4254
|
});
|
|
4219
4255
|
if (result.code !== 0) {
|
|
4220
4256
|
throw new Error(result.stderr || result.stdout || "status failed");
|
|
@@ -4236,7 +4272,8 @@ class BridgeRuntime {
|
|
|
4236
4272
|
input.name
|
|
4237
4273
|
]));
|
|
4238
4274
|
const result = await this.run(spawnSpec.command, spawnSpec.args, {
|
|
4239
|
-
timeoutMs: this.managementCommandTimeoutMs()
|
|
4275
|
+
timeoutMs: this.managementCommandTimeoutMs(),
|
|
4276
|
+
stage: "cancel"
|
|
4240
4277
|
});
|
|
4241
4278
|
if (result.code !== 0) {
|
|
4242
4279
|
throw new Error(result.stderr || result.stdout || "cancel failed");
|
|
@@ -4253,7 +4290,8 @@ class BridgeRuntime {
|
|
|
4253
4290
|
input.name
|
|
4254
4291
|
]));
|
|
4255
4292
|
const result = await this.run(spawnSpec.command, spawnSpec.args, {
|
|
4256
|
-
timeoutMs: this.managementCommandTimeoutMs()
|
|
4293
|
+
timeoutMs: this.managementCommandTimeoutMs(),
|
|
4294
|
+
stage: "remove-session"
|
|
4257
4295
|
});
|
|
4258
4296
|
if (result.code === 0) {
|
|
4259
4297
|
return {};
|
|
@@ -4326,7 +4364,11 @@ function spawnCapture(command, args, options) {
|
|
|
4326
4364
|
const timeoutId = typeof options?.timeoutMs === "number" && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? setTimeout(() => {
|
|
4327
4365
|
const kill = options.killProcessTreeFn ?? ((pid) => terminateProcessTree(pid, { detachedProcessGroup: false }));
|
|
4328
4366
|
kill(child.pid ?? 0);
|
|
4329
|
-
reject(new CommandTimeoutError(options.timeoutMs, [command, ...args].join(" ")
|
|
4367
|
+
reject(new CommandTimeoutError(options.timeoutMs, [command, ...args].join(" "), {
|
|
4368
|
+
stage: options.stage,
|
|
4369
|
+
stdout,
|
|
4370
|
+
stderr
|
|
4371
|
+
}));
|
|
4330
4372
|
}, options.timeoutMs) : undefined;
|
|
4331
4373
|
child.stdout.on("data", (chunk) => {
|
|
4332
4374
|
stdout += String(chunk);
|
|
@@ -4543,6 +4585,15 @@ class BridgeServer {
|
|
|
4543
4585
|
const message = error instanceof Error ? error.message : String(error);
|
|
4544
4586
|
const ensureSessionFields = error instanceof EnsureSessionFailedError ? { kind: error.kind, ...error.data ? { data: error.data } : {} } : {};
|
|
4545
4587
|
const promptDetails = error instanceof PromptCommandError ? { details: { exitCode: error.exitCode, stdout: error.stdout, stderr: error.stderr } } : {};
|
|
4588
|
+
const timeoutDetails = error instanceof CommandTimeoutError ? {
|
|
4589
|
+
timeout: {
|
|
4590
|
+
timeoutMs: error.timeoutMs,
|
|
4591
|
+
command: error.command,
|
|
4592
|
+
...error.stage ? { stage: error.stage } : {},
|
|
4593
|
+
...error.stdoutTail ? { stdoutTail: error.stdoutTail } : {},
|
|
4594
|
+
...error.stderrTail ? { stderrTail: error.stderrTail } : {}
|
|
4595
|
+
}
|
|
4596
|
+
} : {};
|
|
4546
4597
|
return `${JSON.stringify({
|
|
4547
4598
|
id: requestId,
|
|
4548
4599
|
ok: false,
|
|
@@ -4550,7 +4601,8 @@ class BridgeServer {
|
|
|
4550
4601
|
code: error instanceof BridgeInvalidRequestError ? "BRIDGE_INVALID_REQUEST" : "BRIDGE_INTERNAL_ERROR",
|
|
4551
4602
|
message,
|
|
4552
4603
|
...ensureSessionFields,
|
|
4553
|
-
...promptDetails
|
|
4604
|
+
...promptDetails,
|
|
4605
|
+
...timeoutDetails
|
|
4554
4606
|
}
|
|
4555
4607
|
})}
|
|
4556
4608
|
`;
|