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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Janitr AI
3
+ Copyright (c) 2025 OpenClaw Team
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -6,10 +6,13 @@
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/acpx.svg)](https://www.npmjs.com/package/acpx)
8
8
  [![npm downloads](https://img.shields.io/npm/dm/acpx.svg)](https://www.npmjs.com/package/acpx)
9
- [![CI](https://github.com/janitrai/acpx/actions/workflows/ci.yml/badge.svg)](https://github.com/janitrai/acpx/actions/workflows/ci.yml)
9
+ [![CI](https://github.com/openclaw/acpx/actions/workflows/ci.yml/badge.svg)](https://github.com/openclaw/acpx/actions/workflows/ci.yml)
10
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
11
  [![Node.js](https://img.shields.io/node/v/acpx.svg)](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/janitrai/acpx/main/skills/acpx/SKILL.md
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/janitrai/acpx/main/docs/CLI.md
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
@@ -10,6 +10,7 @@ type SessionHistoryEntry = {
10
10
  type SessionRecord = {
11
11
  id: string;
12
12
  sessionId: string;
13
+ runtimeSessionId?: string;
13
14
  agentCommand: string;
14
15
  cwd: string;
15
16
  name?: string;
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 result.sessionId;
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
- sessionId = await withTimeout(
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
- sessionId = await withTimeout(client.createSession(record.cwd), options.timeoutMs);
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 sessionId = await withTimeout(
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 sessionId = await withTimeout(
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.7",
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": "Janitr AI",
39
+ "author": "",
40
40
  "license": "MIT",
41
41
  "repository": {
42
42
  "type": "git",
43
- "url": "git+https://github.com/janitrai/acpx.git"
43
+ "url": "git+https://github.com/openclaw/acpx.git"
44
44
  },
45
45
  "engines": {
46
46
  "node": ">=18"