acpx 0.1.7 → 0.1.8
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/LICENSE +1 -1
- package/README.md +9 -3
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +89 -11
- package/package.json +3 -3
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -6,10 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/acpx)
|
|
8
8
|
[](https://www.npmjs.com/package/acpx)
|
|
9
|
-
[](https://github.com/openclaw/acpx/actions/workflows/ci.yml)
|
|
10
10
|
[](https://opensource.org/licenses/MIT)
|
|
11
11
|
[](https://nodejs.org)
|
|
12
12
|
|
|
13
|
+
> Alpha notice: `acpx` is in alpha and the CLI/runtime interfaces are likely to change.
|
|
14
|
+
> ACP coverage status: see [ACP Spec Coverage Roadmap](docs/2026-02-19-acp-coverage-roadmap.md).
|
|
15
|
+
|
|
13
16
|
Your agents love acpx! 🤖❤️ They hate having to scrape characters from a PTY session 😤
|
|
14
17
|
|
|
15
18
|
`acpx` is a headless CLI client for the [Agent Client Protocol (ACP)](https://agentclientprotocol.com), so AI agents and orchestrators can talk to coding agents over a structured protocol instead of PTY scraping.
|
|
@@ -84,10 +87,10 @@ I want you to use acpx to run coding agents over the Agent Client Protocol
|
|
|
84
87
|
|
|
85
88
|
3. Read the acpx skill reference so you know every command, flag, and
|
|
86
89
|
workflow pattern:
|
|
87
|
-
https://raw.githubusercontent.com/
|
|
90
|
+
https://raw.githubusercontent.com/openclaw/acpx/main/skills/acpx/SKILL.md
|
|
88
91
|
|
|
89
92
|
4. If you need the full CLI reference with all options and examples:
|
|
90
|
-
https://raw.githubusercontent.com/
|
|
93
|
+
https://raw.githubusercontent.com/openclaw/acpx/main/docs/CLI.md
|
|
91
94
|
|
|
92
95
|
From now on, when you need to delegate work to a coding agent, use acpx
|
|
93
96
|
instead of spawning raw terminal sessions. For example:
|
|
@@ -257,6 +260,9 @@ JSON events include a stable envelope for correlation:
|
|
|
257
260
|
}
|
|
258
261
|
```
|
|
259
262
|
|
|
263
|
+
Session-control JSON payloads (`sessions new|ensure`, `status`) may also include
|
|
264
|
+
`runtimeSessionId` when the adapter exposes a provider-native session ID.
|
|
265
|
+
|
|
260
266
|
## Built-in agents and custom servers
|
|
261
267
|
|
|
262
268
|
Built-ins:
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1715,6 +1715,40 @@ function classifyPermissionDecision(params, response) {
|
|
|
1715
1715
|
return "denied";
|
|
1716
1716
|
}
|
|
1717
1717
|
|
|
1718
|
+
// src/runtime-session-id.ts
|
|
1719
|
+
var RUNTIME_SESSION_ID_META_KEYS = [
|
|
1720
|
+
"runtimeSessionId",
|
|
1721
|
+
"providerSessionId",
|
|
1722
|
+
"codexSessionId",
|
|
1723
|
+
"claudeSessionId"
|
|
1724
|
+
];
|
|
1725
|
+
function normalizeRuntimeSessionId(value) {
|
|
1726
|
+
if (typeof value !== "string") {
|
|
1727
|
+
return void 0;
|
|
1728
|
+
}
|
|
1729
|
+
const trimmed = value.trim();
|
|
1730
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
1731
|
+
}
|
|
1732
|
+
function asMetaRecord(meta) {
|
|
1733
|
+
if (!meta || typeof meta !== "object" || Array.isArray(meta)) {
|
|
1734
|
+
return void 0;
|
|
1735
|
+
}
|
|
1736
|
+
return meta;
|
|
1737
|
+
}
|
|
1738
|
+
function extractRuntimeSessionId(meta) {
|
|
1739
|
+
const record = asMetaRecord(meta);
|
|
1740
|
+
if (!record) {
|
|
1741
|
+
return void 0;
|
|
1742
|
+
}
|
|
1743
|
+
for (const key of RUNTIME_SESSION_ID_META_KEYS) {
|
|
1744
|
+
const normalized = normalizeRuntimeSessionId(record[key]);
|
|
1745
|
+
if (normalized) {
|
|
1746
|
+
return normalized;
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
return void 0;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1718
1752
|
// src/terminal.ts
|
|
1719
1753
|
import { spawn } from "child_process";
|
|
1720
1754
|
import { randomUUID } from "crypto";
|
|
@@ -2373,18 +2407,22 @@ var AcpClient = class {
|
|
|
2373
2407
|
cwd: asAbsoluteCwd(cwd),
|
|
2374
2408
|
mcpServers: []
|
|
2375
2409
|
});
|
|
2376
|
-
return
|
|
2410
|
+
return {
|
|
2411
|
+
sessionId: result.sessionId,
|
|
2412
|
+
runtimeSessionId: extractRuntimeSessionId(result._meta)
|
|
2413
|
+
};
|
|
2377
2414
|
}
|
|
2378
2415
|
async loadSession(sessionId, cwd = this.options.cwd) {
|
|
2379
2416
|
this.getConnection();
|
|
2380
|
-
await this.loadSessionWithOptions(sessionId, cwd, {});
|
|
2417
|
+
return await this.loadSessionWithOptions(sessionId, cwd, {});
|
|
2381
2418
|
}
|
|
2382
2419
|
async loadSessionWithOptions(sessionId, cwd = this.options.cwd, options = {}) {
|
|
2383
2420
|
const connection = this.getConnection();
|
|
2384
2421
|
const previousSuppression = this.suppressSessionUpdates;
|
|
2385
2422
|
this.suppressSessionUpdates = previousSuppression || Boolean(options.suppressReplayUpdates);
|
|
2423
|
+
let response;
|
|
2386
2424
|
try {
|
|
2387
|
-
await connection.loadSession({
|
|
2425
|
+
response = await connection.loadSession({
|
|
2388
2426
|
sessionId,
|
|
2389
2427
|
cwd: asAbsoluteCwd(cwd),
|
|
2390
2428
|
mcpServers: []
|
|
@@ -2396,6 +2434,9 @@ var AcpClient = class {
|
|
|
2396
2434
|
} finally {
|
|
2397
2435
|
this.suppressSessionUpdates = previousSuppression;
|
|
2398
2436
|
}
|
|
2437
|
+
return {
|
|
2438
|
+
runtimeSessionId: extractRuntimeSessionId(response?._meta)
|
|
2439
|
+
};
|
|
2399
2440
|
}
|
|
2400
2441
|
async prompt(sessionId, text) {
|
|
2401
2442
|
const connection = this.getConnection();
|
|
@@ -4203,6 +4244,7 @@ function parseSessionRecord(raw) {
|
|
|
4203
4244
|
return null;
|
|
4204
4245
|
}
|
|
4205
4246
|
const record = raw;
|
|
4247
|
+
const runtimeSessionId = normalizeRuntimeSessionId(record.runtimeSessionId);
|
|
4206
4248
|
const name = record.name == null ? void 0 : typeof record.name === "string" && record.name.trim().length > 0 ? record.name.trim() : null;
|
|
4207
4249
|
const pid = record.pid == null ? void 0 : Number.isInteger(record.pid) && record.pid > 0 ? record.pid : null;
|
|
4208
4250
|
const closed = record.closed == null ? false : typeof record.closed === "boolean" ? record.closed : null;
|
|
@@ -4225,6 +4267,7 @@ function parseSessionRecord(raw) {
|
|
|
4225
4267
|
...record,
|
|
4226
4268
|
id: record.id,
|
|
4227
4269
|
sessionId: record.sessionId,
|
|
4270
|
+
runtimeSessionId,
|
|
4228
4271
|
agentCommand: record.agentCommand,
|
|
4229
4272
|
cwd: record.cwd,
|
|
4230
4273
|
name,
|
|
@@ -4617,6 +4660,13 @@ function applyLifecycleSnapshotToRecord(record, snapshot) {
|
|
|
4617
4660
|
record.lastAgentExitAt = void 0;
|
|
4618
4661
|
record.lastAgentDisconnectReason = void 0;
|
|
4619
4662
|
}
|
|
4663
|
+
function reconcileRuntimeSessionId(record, runtimeSessionId) {
|
|
4664
|
+
const normalized = normalizeRuntimeSessionId(runtimeSessionId);
|
|
4665
|
+
if (!normalized) {
|
|
4666
|
+
return;
|
|
4667
|
+
}
|
|
4668
|
+
record.runtimeSessionId = normalized;
|
|
4669
|
+
}
|
|
4620
4670
|
function shouldFallbackToNewSession(error) {
|
|
4621
4671
|
if (error instanceof TimeoutError || error instanceof InterruptedError) {
|
|
4622
4672
|
return false;
|
|
@@ -4653,31 +4703,40 @@ async function connectAndLoadSession(options) {
|
|
|
4653
4703
|
let sessionId = record.sessionId;
|
|
4654
4704
|
if (client.supportsLoadSession()) {
|
|
4655
4705
|
try {
|
|
4656
|
-
await withTimeout(
|
|
4706
|
+
const loadResult = await withTimeout(
|
|
4657
4707
|
client.loadSessionWithOptions(record.sessionId, record.cwd, {
|
|
4658
4708
|
suppressReplayUpdates: true
|
|
4659
4709
|
}),
|
|
4660
4710
|
options.timeoutMs
|
|
4661
4711
|
);
|
|
4712
|
+
reconcileRuntimeSessionId(record, loadResult.runtimeSessionId);
|
|
4662
4713
|
resumed = true;
|
|
4663
4714
|
} catch (error) {
|
|
4664
4715
|
loadError = formatErrorMessage(error);
|
|
4665
4716
|
if (!shouldFallbackToNewSession(error)) {
|
|
4666
4717
|
throw error;
|
|
4667
4718
|
}
|
|
4668
|
-
|
|
4719
|
+
const createdSession = await withTimeout(
|
|
4669
4720
|
client.createSession(record.cwd),
|
|
4670
4721
|
options.timeoutMs
|
|
4671
4722
|
);
|
|
4723
|
+
sessionId = createdSession.sessionId;
|
|
4672
4724
|
record.sessionId = sessionId;
|
|
4725
|
+
reconcileRuntimeSessionId(record, createdSession.runtimeSessionId);
|
|
4673
4726
|
}
|
|
4674
4727
|
} else {
|
|
4675
|
-
|
|
4728
|
+
const createdSession = await withTimeout(
|
|
4729
|
+
client.createSession(record.cwd),
|
|
4730
|
+
options.timeoutMs
|
|
4731
|
+
);
|
|
4732
|
+
sessionId = createdSession.sessionId;
|
|
4676
4733
|
record.sessionId = sessionId;
|
|
4734
|
+
reconcileRuntimeSessionId(record, createdSession.runtimeSessionId);
|
|
4677
4735
|
}
|
|
4678
4736
|
options.onSessionIdResolved?.(sessionId);
|
|
4679
4737
|
return {
|
|
4680
4738
|
sessionId,
|
|
4739
|
+
runtimeSessionId: record.runtimeSessionId,
|
|
4681
4740
|
resumed,
|
|
4682
4741
|
loadError
|
|
4683
4742
|
};
|
|
@@ -5030,10 +5089,11 @@ async function runOnce(options) {
|
|
|
5030
5089
|
return await withInterrupt(
|
|
5031
5090
|
async () => {
|
|
5032
5091
|
await withTimeout(client.start(), options.timeoutMs);
|
|
5033
|
-
const
|
|
5092
|
+
const createdSession = await withTimeout(
|
|
5034
5093
|
client.createSession(absolutePath(options.cwd)),
|
|
5035
5094
|
options.timeoutMs
|
|
5036
5095
|
);
|
|
5096
|
+
const sessionId = createdSession.sessionId;
|
|
5037
5097
|
output.setContext({
|
|
5038
5098
|
sessionId,
|
|
5039
5099
|
stream: "prompt"
|
|
@@ -5069,15 +5129,17 @@ async function createSession(options) {
|
|
|
5069
5129
|
return await withInterrupt(
|
|
5070
5130
|
async () => {
|
|
5071
5131
|
await withTimeout(client.start(), options.timeoutMs);
|
|
5072
|
-
const
|
|
5132
|
+
const createdSession = await withTimeout(
|
|
5073
5133
|
client.createSession(absolutePath(options.cwd)),
|
|
5074
5134
|
options.timeoutMs
|
|
5075
5135
|
);
|
|
5136
|
+
const sessionId = createdSession.sessionId;
|
|
5076
5137
|
const lifecycle = client.getAgentLifecycleSnapshot();
|
|
5077
5138
|
const now = isoNow2();
|
|
5078
5139
|
const record = {
|
|
5079
5140
|
id: sessionId,
|
|
5080
5141
|
sessionId,
|
|
5142
|
+
runtimeSessionId: createdSession.runtimeSessionId,
|
|
5081
5143
|
agentCommand: options.agentCommand,
|
|
5082
5144
|
cwd: absolutePath(options.cwd),
|
|
5083
5145
|
name: normalizeName(options.name),
|
|
@@ -5698,6 +5760,13 @@ function printClosedSessionByFormat(record, format) {
|
|
|
5698
5760
|
process.stdout.write(`${record.id}
|
|
5699
5761
|
`);
|
|
5700
5762
|
}
|
|
5763
|
+
function runtimeSessionIdPayload(runtimeSessionId) {
|
|
5764
|
+
const normalized = normalizeRuntimeSessionId(runtimeSessionId);
|
|
5765
|
+
if (!normalized) {
|
|
5766
|
+
return {};
|
|
5767
|
+
}
|
|
5768
|
+
return { runtimeSessionId: normalized };
|
|
5769
|
+
}
|
|
5701
5770
|
function printNewSessionByFormat(record, replaced, format) {
|
|
5702
5771
|
if (format === "json") {
|
|
5703
5772
|
process.stdout.write(
|
|
@@ -5706,7 +5775,8 @@ function printNewSessionByFormat(record, replaced, format) {
|
|
|
5706
5775
|
id: record.id,
|
|
5707
5776
|
sessionId: record.sessionId,
|
|
5708
5777
|
name: record.name,
|
|
5709
|
-
replacedSessionId: replaced?.id
|
|
5778
|
+
replacedSessionId: replaced?.id,
|
|
5779
|
+
...runtimeSessionIdPayload(record.runtimeSessionId)
|
|
5710
5780
|
})}
|
|
5711
5781
|
`
|
|
5712
5782
|
);
|
|
@@ -5733,7 +5803,8 @@ function printEnsuredSessionByFormat(record, created, format) {
|
|
|
5733
5803
|
id: record.id,
|
|
5734
5804
|
sessionId: record.sessionId,
|
|
5735
5805
|
name: record.name,
|
|
5736
|
-
created
|
|
5806
|
+
created,
|
|
5807
|
+
...runtimeSessionIdPayload(record.runtimeSessionId)
|
|
5737
5808
|
})}
|
|
5738
5809
|
`
|
|
5739
5810
|
);
|
|
@@ -6148,6 +6219,8 @@ function printSessionDetailsByFormat(record, format) {
|
|
|
6148
6219
|
process.stdout.write(`id: ${record.id}
|
|
6149
6220
|
`);
|
|
6150
6221
|
process.stdout.write(`sessionId: ${record.sessionId}
|
|
6222
|
+
`);
|
|
6223
|
+
process.stdout.write(`runtimeSessionId: ${record.runtimeSessionId ?? "-"}
|
|
6151
6224
|
`);
|
|
6152
6225
|
process.stdout.write(`agent: ${record.agentCommand}
|
|
6153
6226
|
`);
|
|
@@ -6316,7 +6389,8 @@ async function handleStatus(explicitAgentName, flags, command, config) {
|
|
|
6316
6389
|
uptime: running ? formatUptime(record.agentStartedAt) ?? null : null,
|
|
6317
6390
|
lastPromptTime: record.lastPromptAt ?? null,
|
|
6318
6391
|
exitCode: running ? null : record.lastAgentExitCode ?? null,
|
|
6319
|
-
signal: running ? null : record.lastAgentExitSignal ?? null
|
|
6392
|
+
signal: running ? null : record.lastAgentExitSignal ?? null,
|
|
6393
|
+
...runtimeSessionIdPayload(record.runtimeSessionId)
|
|
6320
6394
|
};
|
|
6321
6395
|
if (globalFlags.format === "json") {
|
|
6322
6396
|
process.stdout.write(`${JSON.stringify(payload)}
|
|
@@ -6330,6 +6404,10 @@ async function handleStatus(explicitAgentName, flags, command, config) {
|
|
|
6330
6404
|
}
|
|
6331
6405
|
process.stdout.write(`session: ${payload.sessionId}
|
|
6332
6406
|
`);
|
|
6407
|
+
if ("runtimeSessionId" in payload) {
|
|
6408
|
+
process.stdout.write(`runtimeSessionId: ${payload.runtimeSessionId}
|
|
6409
|
+
`);
|
|
6410
|
+
}
|
|
6333
6411
|
process.stdout.write(`agent: ${payload.agentCommand}
|
|
6334
6412
|
`);
|
|
6335
6413
|
process.stdout.write(`pid: ${payload.pid ?? "-"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "acpx",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Headless CLI client for the Agent Client Protocol (ACP) — talk to coding agents from the command line",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"coding-agent",
|
|
37
37
|
"ai"
|
|
38
38
|
],
|
|
39
|
-
"author": "
|
|
39
|
+
"author": "",
|
|
40
40
|
"license": "MIT",
|
|
41
41
|
"repository": {
|
|
42
42
|
"type": "git",
|
|
43
|
-
"url": "git+https://github.com/
|
|
43
|
+
"url": "git+https://github.com/openclaw/acpx.git"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
|
46
46
|
"node": ">=18"
|