@openclaw/acpx 2026.7.2-beta.7 → 2026.8.1-beta.3

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.
@@ -1,11 +1,11 @@
1
- import { _ as splitCommandParts, a as hashAcpxProcessCommand, l as readAcpxProcessLeaseIdentity, r as createAcpxProcessLeaseId, u as withAcpxLeaseEnvironment } from "./process-lease-DSLDgiNl.js";
1
+ import { d as withAcpxLeaseEnvironment, i as createAcpxProcessLeaseId, o as hashAcpxProcessCommand, t as ACPX_PROBE_LEASE_SESSION_KEY, u as readAcpxProcessLeaseIdentity, v as splitCommandParts } from "./process-lease-Cwvj7WGe.js";
2
2
  import { AcpRuntimeError } from "./runtime-api.js";
3
- import { c as CODEX_ACP_PACKAGE, n as isOpenClawLeaseAwareAcpxProcessCommand, t as cleanupOpenClawOwnedAcpxProcessTree, u as OPENCLAW_CODEX_CONFIG_ARG } from "./process-reaper-DFwbcdPa.js";
3
+ import { d as OPENCLAW_CODEX_CONFIG_ARG, l as CODEX_ACP_PACKAGE, n as cleanupOpenClawOwnedAcpxProcessTree, r as isOpenClawLeaseAwareAcpxProcessCommand, t as cleanupOpenClawOwnedAcpxPendingLease } from "./process-reaper-DduWm_7N.js";
4
4
  import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
5
5
  import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
6
- import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
7
- import fs from "node:fs/promises";
8
6
  import path, { resolve } from "node:path";
7
+ import fs from "node:fs/promises";
8
+ import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
9
9
  import { AsyncLocalStorage } from "node:async_hooks";
10
10
  import { ACPX_BACKEND_ID, AcpxRuntime as AcpxRuntime$1, createAcpRuntime, createAgentRegistry, createFileSessionStore, decodeAcpxRuntimeHandleState, encodeAcpxRuntimeHandleState, isRequestedModelUnsupportedError } from "acpx/runtime";
11
11
  import { redactSensitiveText } from "openclaw/plugin-sdk/security-runtime";
@@ -440,6 +440,7 @@ var AcpxRuntime = class {
440
440
  this.ensureSessionTails = /* @__PURE__ */ new Map();
441
441
  this.processLeaseTransitionTails = /* @__PURE__ */ new Map();
442
442
  this.processLeaseOperationCounts = /* @__PURE__ */ new Map();
443
+ this.uncertainProcessLeaseIds = /* @__PURE__ */ new Set();
443
444
  const { openclawProcessCleanup, ...delegateTestOptions } = testOptions ?? {};
444
445
  this.processCleanupDeps = openclawProcessCleanup;
445
446
  this.wrapperRoot = options.openclawWrapperRoot;
@@ -477,6 +478,7 @@ var AcpxRuntime = class {
477
478
  agentName: normalizeAgentName(options.probeAgent) ?? "codex",
478
479
  agentRegistry: this.agentRegistry
479
480
  });
481
+ this.probeCommand = probeCommand;
480
482
  const useBridgeSafeProbe = this.managedToolsMcpBridgeEnabled || shouldUseBridgeSafeDelegateForCommand(probeCommand);
481
483
  this.probeDelegate = useBridgeSafeProbe ? this.bridgeSafeDelegate : this.delegate;
482
484
  }
@@ -508,33 +510,22 @@ var AcpxRuntime = class {
508
510
  if (!normalizedSessionKey) return;
509
511
  this.managedToolsSessionDelegates.delete(normalizedSessionKey);
510
512
  }
511
- async resolveDelegateForHandle(handle) {
513
+ async loadOperationSnapshotForHandle(handle) {
512
514
  const record = await this.sessionStore.load(handle.acpxRecordId ?? handle.sessionKey);
513
- return this.resolveDelegateForLoadedRecord(handle, record);
515
+ return {
516
+ record,
517
+ command: readAgentCommandFromRecord(record) ?? resolveAgentCommand({
518
+ agentName: readAgentFromHandle(handle),
519
+ agentRegistry: this.agentRegistry
520
+ })
521
+ };
514
522
  }
515
- resolveDelegateForLoadedRecord(handle, record) {
516
- const recordCommand = readAgentCommandFromRecord(record);
517
- if (recordCommand) return this.resolveDelegateForSession({
518
- command: recordCommand,
519
- sessionKey: handle.sessionKey
520
- });
521
- const command = resolveAgentCommand({
522
- agentName: readAgentFromHandle(handle),
523
- agentRegistry: this.agentRegistry
524
- });
523
+ resolveDelegateForOperationSnapshot(handle, snapshot) {
525
524
  return this.resolveDelegateForSession({
526
- command,
525
+ command: snapshot.command,
527
526
  sessionKey: handle.sessionKey
528
527
  });
529
528
  }
530
- async resolveCommandForHandle(handle) {
531
- const recordCommand = readAgentCommandFromRecord(await this.sessionStore.load(handle.acpxRecordId ?? handle.sessionKey));
532
- if (recordCommand) return recordCommand;
533
- return resolveAgentCommand({
534
- agentName: readAgentFromHandle(handle),
535
- agentRegistry: this.agentRegistry
536
- });
537
- }
538
529
  commandWithLaunchLease(command) {
539
530
  const launch = this.launchLeaseScope.getStore();
540
531
  if (!launch) return command;
@@ -571,7 +562,7 @@ var AcpxRuntime = class {
571
562
  const processLeaseStore = this.processLeaseStore;
572
563
  const reusableIdentity = readAcpxProcessLeaseIdentity(params.reusableCommand);
573
564
  const canReuseLeaseIdentity = reusableIdentity?.gatewayInstanceId === this.gatewayInstanceId;
574
- const leaseId = canReuseLeaseIdentity ? reusableIdentity.leaseId : createAcpxProcessLeaseId();
565
+ const leaseId = canReuseLeaseIdentity ? reusableIdentity.leaseId : params.finalizeCompletedProbe ? `probe-${hashAcpxProcessCommand(`${this.gatewayInstanceId}\0${extractGeneratedWrapperPath(params.command)}`)}` : createAcpxProcessLeaseId();
575
566
  const leasedCommand = withAcpxLeaseEnvironment({
576
567
  command: params.command,
577
568
  leaseId,
@@ -604,18 +595,18 @@ var AcpxRuntime = class {
604
595
  });
605
596
  try {
606
597
  const result = await this.launchLeaseScope.run(launch, params.run);
607
- await this.finalizeProcessLeaseForSession(params.sessionKey, launch);
598
+ if (params.finalizeCompletedProbe) await this.finalizeCompletedProbeLease(launch);
599
+ else await this.finalizeProcessLeaseForSession(params.sessionKey, launch);
608
600
  return result;
609
601
  } catch (error) {
610
- await this.retirePendingProcessLease(launch);
602
+ await this.releaseProcessLeaseAfterUncertainFailure(launch);
611
603
  throw error;
612
604
  }
613
605
  }
614
- async prepareProcessLeaseForOperation(handle) {
606
+ async prepareProcessLeaseForOperation(handle, record) {
615
607
  if (!this.processLeaseStore || !this.gatewayInstanceId || !this.wrapperRoot) return;
616
608
  const processLeaseStore = this.processLeaseStore;
617
609
  const wrapperRoot = this.wrapperRoot;
618
- const record = await this.sessionStore.load(handle.acpxRecordId ?? handle.sessionKey);
619
610
  const recordPid = readRecordAgentPid(record);
620
611
  const command = readAgentCommandFromRecord(record);
621
612
  const identity = readAcpxProcessLeaseIdentity(command);
@@ -690,25 +681,44 @@ var AcpxRuntime = class {
690
681
  const lease = await processLeaseStore.load(identity.leaseId);
691
682
  if (!lease || lease.gatewayInstanceId !== identity.gatewayInstanceId) return;
692
683
  if (lease.rootPid <= 0) {
684
+ if (this.uncertainProcessLeaseIds.has(identity.leaseId)) return;
693
685
  await processLeaseStore.markState(identity.leaseId, "lost");
694
686
  return;
695
687
  }
688
+ this.uncertainProcessLeaseIds.delete(identity.leaseId);
696
689
  try {
697
690
  const recordIdentity = readAcpxProcessLeaseIdentity(readAgentCommandFromRecord(await this.sessionStore.load(sessionId)));
698
691
  if (recordIdentity?.leaseId !== identity.leaseId || recordIdentity.gatewayInstanceId !== identity.gatewayInstanceId) await processLeaseStore.markState(identity.leaseId, "lost");
699
692
  } catch {}
700
693
  });
701
694
  }
702
- async retirePendingProcessLease(identity) {
695
+ async finalizeCompletedProbeLease(identity) {
696
+ if (!this.processLeaseStore) return;
697
+ const processLeaseStore = this.processLeaseStore;
698
+ await this.releaseProcessLeaseOperation(identity, async () => {
699
+ const lease = await processLeaseStore.load(identity.leaseId);
700
+ if (!lease || lease.gatewayInstanceId !== identity.gatewayInstanceId) return;
701
+ if (lease.rootPid > 0) return;
702
+ await cleanupOpenClawOwnedAcpxPendingLease({
703
+ leaseId: lease.leaseId,
704
+ gatewayInstanceId: lease.gatewayInstanceId,
705
+ wrapperRoot: lease.wrapperRoot,
706
+ wrapperPath: lease.wrapperPath,
707
+ deps: this.processCleanupDeps
708
+ });
709
+ });
710
+ }
711
+ async releaseProcessLeaseAfterUncertainFailure(identity) {
703
712
  if (!identity || !this.processLeaseStore) return;
713
+ this.uncertainProcessLeaseIds.add(identity.leaseId);
704
714
  const processLeaseStore = this.processLeaseStore;
705
715
  await this.releaseProcessLeaseOperation(identity, async () => {
706
716
  const lease = await processLeaseStore.load(identity.leaseId);
707
- if (lease?.gatewayInstanceId === identity.gatewayInstanceId && lease.rootPid <= 0) await processLeaseStore.markState(identity.leaseId, "lost");
717
+ if (!lease || lease.gatewayInstanceId !== identity.gatewayInstanceId || lease.rootPid > 0) this.uncertainProcessLeaseIds.delete(identity.leaseId);
708
718
  });
709
719
  }
710
- async runWithProcessLeaseForHandle(handle, run) {
711
- const identity = await this.prepareProcessLeaseForOperation(handle);
720
+ async runWithProcessLeaseForHandle(handle, record, run) {
721
+ const identity = await this.prepareProcessLeaseForOperation(handle, record);
712
722
  try {
713
723
  return await run();
714
724
  } finally {
@@ -780,7 +790,7 @@ var AcpxRuntime = class {
780
790
  wrapperRoot: lease.wrapperRoot,
781
791
  deps: this.processCleanupDeps
782
792
  });
783
- await this.processLeaseStore?.markState(lease.leaseId, result.skippedReason === "process-list-unavailable" ? "open" : result.terminatedPids.length > 0 || result.skippedReason === "missing-root" ? "closed" : "lost");
793
+ await this.processLeaseStore?.markState(lease.leaseId, result.skippedReason === "process-list-unavailable" || result.skippedReason === "unsupported-platform" ? "open" : result.terminatedPids.length > 0 || result.skippedReason === "missing-root" ? "closed" : "lost");
784
794
  return;
785
795
  }
786
796
  const rootCommand = readAgentCommandFromRecord(record) ?? resolveAgentCommand({
@@ -801,11 +811,21 @@ var AcpxRuntime = class {
801
811
  isHealthy() {
802
812
  return this.probeDelegate.isHealthy();
803
813
  }
804
- probeAvailability() {
805
- return this.probeDelegate.probeAvailability();
814
+ async probeAvailability() {
815
+ await this.runWithLaunchLease({
816
+ sessionKey: ACPX_PROBE_LEASE_SESSION_KEY,
817
+ command: this.probeCommand,
818
+ finalizeCompletedProbe: true,
819
+ run: () => this.probeDelegate.probeAvailability()
820
+ });
806
821
  }
807
- doctor() {
808
- return this.probeDelegate.doctor();
822
+ async doctor() {
823
+ return await this.runWithLaunchLease({
824
+ sessionKey: ACPX_PROBE_LEASE_SESSION_KEY,
825
+ command: this.probeCommand,
826
+ finalizeCompletedProbe: true,
827
+ run: () => this.probeDelegate.doctor()
828
+ });
809
829
  }
810
830
  async ensureSession(input) {
811
831
  return await this.runSerializedSessionEnsure(input.sessionKey, () => this.ensureSessionUnlocked(input));
@@ -868,11 +888,12 @@ var AcpxRuntime = class {
868
888
  } : handle;
869
889
  }
870
890
  async *runTurn(input) {
871
- const turnLease = await this.prepareProcessLeaseForOperation(input.handle);
891
+ const record = await this.sessionStore.load(input.handle.acpxRecordId ?? input.handle.sessionKey);
892
+ const turnLease = await this.prepareProcessLeaseForOperation(input.handle, record);
872
893
  let command;
873
894
  try {
874
- command = await this.resolveCommandForHandle(input.handle);
875
- const delegate = await this.resolveDelegateForHandle(input.handle);
895
+ command = (await this.loadOperationSnapshotForHandle(input.handle)).command;
896
+ const delegate = this.resolveDelegateForOperationSnapshot(input.handle, await this.loadOperationSnapshotForHandle(input.handle));
876
897
  for await (const event of delegate.runTurn(withOpenClawManagedTurnTimeout(input))) {
877
898
  if (event.type !== "error" || !isCodexAcpCommand(command) || !isGenericInternalAcpErrorMessage(event.message)) {
878
899
  yield event;
@@ -900,12 +921,11 @@ var AcpxRuntime = class {
900
921
  }
901
922
  startTurn(input) {
902
923
  const readCodexTurnFailureStderr = () => this.readCodexTurnFailureStderr({ handle: input.handle });
903
- const turnLeasePromise = this.prepareProcessLeaseForOperation(input.handle);
904
- const turnPromise = Promise.all([
905
- turnLeasePromise,
906
- this.resolveCommandForHandle(input.handle),
907
- this.resolveDelegateForHandle(input.handle)
908
- ]).then(async ([, command, delegate]) => {
924
+ const snapshotPromise = this.loadOperationSnapshotForHandle(input.handle);
925
+ const turnLeasePromise = snapshotPromise.then(({ record }) => this.prepareProcessLeaseForOperation(input.handle, record));
926
+ const turnPromise = Promise.all([snapshotPromise, turnLeasePromise]).then(async ([snapshot]) => {
927
+ const { command } = snapshot;
928
+ const delegate = this.resolveDelegateForOperationSnapshot(input.handle, snapshot);
909
929
  try {
910
930
  return {
911
931
  command,
@@ -920,6 +940,9 @@ var AcpxRuntime = class {
920
940
  });
921
941
  return {
922
942
  requestId: input.requestId,
943
+ get promptStarted() {
944
+ return turnPromise.then(({ turn }) => turn.promptStarted);
945
+ },
923
946
  events: { async *[Symbol.asyncIterator]() {
924
947
  const { command, turn } = await turnPromise;
925
948
  try {
@@ -979,18 +1002,20 @@ var AcpxRuntime = class {
979
1002
  return this.delegate.getCapabilities(input);
980
1003
  }
981
1004
  async getStatus(input) {
982
- return (await this.resolveDelegateForHandle(input.handle)).getStatus(input);
1005
+ const snapshot = await this.loadOperationSnapshotForHandle(input.handle);
1006
+ return this.resolveDelegateForOperationSnapshot(input.handle, snapshot).getStatus(input);
983
1007
  }
984
1008
  async setMode(input) {
985
- const delegate = await this.resolveDelegateForHandle(input.handle);
986
- await this.runWithProcessLeaseForHandle(input.handle, () => delegate.setMode(input));
1009
+ const snapshot = await this.loadOperationSnapshotForHandle(input.handle);
1010
+ await this.runWithProcessLeaseForHandle(input.handle, snapshot.record, () => this.resolveDelegateForOperationSnapshot(input.handle, snapshot).setMode(input));
987
1011
  }
988
1012
  async setConfigOption(input) {
989
- await this.runWithProcessLeaseForHandle(input.handle, () => this.setConfigOptionUnlocked(input));
1013
+ const snapshot = await this.loadOperationSnapshotForHandle(input.handle);
1014
+ await this.runWithProcessLeaseForHandle(input.handle, snapshot.record, () => this.setConfigOptionUnlocked(input, snapshot));
990
1015
  }
991
- async setConfigOptionUnlocked(input) {
992
- const delegate = await this.resolveDelegateForHandle(input.handle);
993
- const command = await this.resolveCommandForHandle(input.handle);
1016
+ async setConfigOptionUnlocked(input, snapshot) {
1017
+ const { command } = snapshot;
1018
+ const delegate = this.resolveDelegateForOperationSnapshot(input.handle, snapshot);
994
1019
  const key = input.key.trim().toLowerCase();
995
1020
  const isCodexAcp = isCodexAcpCommand(command);
996
1021
  if (WIRE_TIMEOUT_CONFIG_KEYS.has(key) && (isCodexAcp || isClaudeAcpCommand(command))) return;
@@ -1033,19 +1058,19 @@ var AcpxRuntime = class {
1033
1058
  await delegate.setConfigOption(input);
1034
1059
  }
1035
1060
  async cancel(input) {
1036
- const record = await this.sessionStore.load(input.handle.acpxRecordId ?? input.handle.sessionKey);
1037
- await this.resolveDelegateForLoadedRecord(input.handle, record).cancel(input);
1061
+ const snapshot = await this.loadOperationSnapshotForHandle(input.handle);
1062
+ await this.resolveDelegateForOperationSnapshot(input.handle, snapshot).cancel(input);
1038
1063
  }
1039
1064
  async prepareFreshSession(input) {
1040
1065
  this.sessionStore.markFresh(input.sessionKey);
1041
1066
  }
1042
1067
  async close(input) {
1043
- const closeLease = await this.prepareProcessLeaseForOperation(input.handle);
1068
+ const snapshot = await this.loadOperationSnapshotForHandle(input.handle);
1069
+ const closeLease = await this.prepareProcessLeaseForOperation(input.handle, snapshot.record);
1044
1070
  let cleanupSucceeded = false;
1045
1071
  try {
1046
- const record = await this.sessionStore.load(input.handle.acpxRecordId ?? input.handle.sessionKey);
1072
+ const delegate = this.resolveDelegateForOperationSnapshot(input.handle, snapshot);
1047
1073
  let closeSucceeded;
1048
- const delegate = this.resolveDelegateForLoadedRecord(input.handle, record);
1049
1074
  try {
1050
1075
  await delegate.close({
1051
1076
  handle: input.handle,
@@ -1054,26 +1079,23 @@ var AcpxRuntime = class {
1054
1079
  });
1055
1080
  closeSucceeded = true;
1056
1081
  } finally {
1057
- await this.cleanupProcessTreeForRecord(input.handle, record);
1082
+ await this.cleanupProcessTreeForRecord(input.handle, snapshot.record);
1058
1083
  cleanupSucceeded = true;
1059
1084
  }
1060
1085
  if (closeSucceeded) this.releaseManagedToolsDelegateForSession(input.handle.sessionKey);
1061
1086
  if (closeSucceeded && input.discardPersistentState) this.sessionStore.markFresh(input.handle.sessionKey);
1062
1087
  } finally {
1063
1088
  if (cleanupSucceeded) await this.finalizeProcessLeaseForOperation(input.handle, closeLease);
1064
- else await this.retirePendingProcessLease(closeLease);
1089
+ else await this.releaseProcessLeaseAfterUncertainFailure(closeLease);
1065
1090
  }
1066
1091
  }
1067
1092
  };
1068
1093
  /** Test-only hooks for ACPX runtime behavior that is otherwise private. */
1069
1094
  const testing = {
1070
1095
  appendCodexAcpConfigOverrides,
1071
- assertSupportedRuntimeSessionMode,
1072
- classifyCodexAcpModelRequest,
1073
1096
  isClaudeAcpCommand,
1074
1097
  isCodexAcpCommand,
1075
- normalizeAgentCommand,
1076
- normalizeClaudeAcpModelOverride
1098
+ normalizeAgentCommand
1077
1099
  };
1078
1100
  //#endregion
1079
- export { ACPX_BACKEND_ID, AcpxRuntime, testing as __testing, testing, createAcpRuntime, createAgentRegistry, createFileSessionStore, decodeAcpxRuntimeHandleState, encodeAcpxRuntimeHandleState };
1101
+ export { ACPX_BACKEND_ID, AcpxRuntime, createAcpRuntime, createAgentRegistry, createFileSessionStore, decodeAcpxRuntimeHandleState, encodeAcpxRuntimeHandleState, testing };
@@ -1,16 +1,15 @@
1
- import { n as createLazyAcpRuntimeProxy } from "./register.runtime-BbS2JTTv.js";
2
- import "./config-schema-lrk5nlcV.js";
3
- import { _ as splitCommandParts, c as openAcpxProcessLeaseStateStore, d as ACPX_GATEWAY_INSTANCE_KEY, f as ACPX_GATEWAY_INSTANCE_NAMESPACE, g as quoteCommandPart, h as normalizeAcpxGatewayInstanceRecord, i as createAcpxProcessLeaseStore, n as OPENCLAW_GATEWAY_INSTANCE_ID_ARG, t as OPENCLAW_ACPX_LEASE_ID_ARG } from "./process-lease-DSLDgiNl.js";
4
- import { registerAcpRuntimeBackend, unregisterAcpRuntimeBackend } from "./runtime-api.js";
5
- import { a as resolveAcpxPluginRoot, c as CODEX_ACP_PACKAGE, i as resolveAcpxPluginConfig, l as LEGACY_CODEX_ACP_PACKAGE, o as toAcpMcpServers, r as reapStaleOpenClawOwnedAcpxOrphans, s as CODEX_ACP_BIN, t as cleanupOpenClawOwnedAcpxProcessTree, u as OPENCLAW_CODEX_CONFIG_ARG } from "./process-reaper-DFwbcdPa.js";
1
+ import { n as createLazyAcpRuntimeProxy } from "./register.runtime-Dj29TKFy.js";
2
+ import "./config-schema-DN_uAi4R.js";
3
+ import { _ as quoteCommandPart, a as createAcpxProcessLeaseStore, f as ACPX_GATEWAY_INSTANCE_KEY, g as normalizeAcpxGatewayInstanceRecord, l as openAcpxProcessLeaseStateStore, n as OPENCLAW_ACPX_LEASE_ID_ARG, p as ACPX_GATEWAY_INSTANCE_NAMESPACE, r as OPENCLAW_GATEWAY_INSTANCE_ID_ARG, v as splitCommandParts } from "./process-lease-Cwvj7WGe.js";
4
+ import { a as resolveAcpxPluginConfig, c as CODEX_ACP_BIN, d as OPENCLAW_CODEX_CONFIG_ARG, i as reapStaleOpenClawOwnedAcpxOrphans, l as CODEX_ACP_PACKAGE, n as cleanupOpenClawOwnedAcpxProcessTree, o as resolveAcpxPluginRoot, s as toAcpMcpServers, t as cleanupOpenClawOwnedAcpxPendingLease, u as LEGACY_CODEX_ACP_PACKAGE } from "./process-reaper-DduWm_7N.js";
6
5
  import { createRequire } from "node:module";
7
6
  import { finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
8
7
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
9
- import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
8
+ import { isRecord, normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
10
9
  import fs from "node:fs";
11
- import fs$1 from "node:fs/promises";
12
- import path from "node:path";
13
10
  import os from "node:os";
11
+ import path from "node:path";
12
+ import fs$1 from "node:fs/promises";
14
13
  import { randomUUID } from "node:crypto";
15
14
  import { inspect } from "node:util";
16
15
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
@@ -893,14 +892,11 @@ function extractConfiguredAdapterArgs(params) {
893
892
  if (isAcpBinName(parts[0] ?? "", params.binName)) return parts.slice(1);
894
893
  if (basename(parts[0] ?? "") === "node" && isAcpBinName(parts[1] ?? "", params.binName)) return parts.slice(2);
895
894
  }
896
- function isConfigRecord(value) {
897
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
898
- }
899
895
  function mergeConfigRecords(base, override) {
900
896
  const merged = { ...base };
901
897
  for (const [key, value] of Object.entries(override)) {
902
898
  const existing = merged[key];
903
- const nextValue = isConfigRecord(existing) && isConfigRecord(value) ? mergeConfigRecords(existing, value) : value;
899
+ const nextValue = isRecord(existing) && isRecord(value) ? mergeConfigRecords(existing, value) : value;
904
900
  Object.defineProperty(merged, key, {
905
901
  value: nextValue,
906
902
  configurable: true,
@@ -976,7 +972,7 @@ function buildCodexAcpWrapperCommand(wrapperPath, configuredCommand) {
976
972
  }
977
973
  async function persistMigratedCodexMcpConfig(params) {
978
974
  const mcpServers = params.migratedConfig?.mcp_servers;
979
- if (!isConfigRecord(mcpServers)) return;
975
+ if (!isRecord(mcpServers)) return;
980
976
  const configPath = path.join(params.codexHome, "config.toml");
981
977
  const merged = mergeConfigRecords(parse(await fs$1.readFile(configPath, "utf8")), { mcp_servers: mcpServers });
982
978
  await fs$1.writeFile(configPath, stringify(merged), "utf8");
@@ -1025,8 +1021,7 @@ async function prepareAcpxCodexAuthConfig(params) {
1025
1021
  */
1026
1022
  const ENABLE_STARTUP_PROBE_ENV = "OPENCLAW_ACPX_RUNTIME_STARTUP_PROBE";
1027
1023
  const SKIP_RUNTIME_PROBE_ENV = "OPENCLAW_SKIP_ACPX_RUNTIME_PROBE";
1028
- const ACPX_BACKEND_ID = "acpx";
1029
- const loadRuntimeModule = createLazyRuntimeModule(() => import("./runtime-By_lR8uk.js"));
1024
+ const loadRuntimeModule = createLazyRuntimeModule(() => import("./runtime-BmOxa15I.js"));
1030
1025
  /** Convert ACPX timeout seconds into timer-safe milliseconds. */
1031
1026
  function resolveAcpxTimerTimeoutMs(timeoutSeconds) {
1032
1027
  if (timeoutSeconds === void 0) return;
@@ -1051,6 +1046,7 @@ function createLazyDefaultRuntime(params) {
1051
1046
  openclawToolsMcpBridgeEnabled: params.pluginConfig.openClawToolsMcpBridge,
1052
1047
  permissionMode: params.pluginConfig.permissionMode,
1053
1048
  nonInteractivePermissions: params.pluginConfig.nonInteractivePermissions,
1049
+ elicitationModes: ["form", "url"],
1054
1050
  timeoutMs: resolveAcpxTimerTimeoutMs(params.pluginConfig.timeoutSeconds)
1055
1051
  });
1056
1052
  return runtime;
@@ -1067,13 +1063,6 @@ function createLazyDefaultRuntime(params) {
1067
1063
  }
1068
1064
  };
1069
1065
  }
1070
- function warnOnIgnoredLegacyCompatibilityConfig(params) {
1071
- const ignoredFields = [];
1072
- if (params.pluginConfig.legacyCompatibilityConfig.queueOwnerTtlSeconds != null) ignoredFields.push("queueOwnerTtlSeconds");
1073
- if (params.pluginConfig.legacyCompatibilityConfig.strictWindowsCmdWrapper === false) ignoredFields.push("strictWindowsCmdWrapper=false");
1074
- if (ignoredFields.length === 0) return;
1075
- params.logger?.warn(`embedded acpx runtime ignores legacy compatibility config: ${ignoredFields.join(", ")}`);
1076
- }
1077
1066
  function formatDoctorDetail(detail) {
1078
1067
  if (!detail) return null;
1079
1068
  if (typeof detail === "string") return detail.trim() || null;
@@ -1152,21 +1141,22 @@ async function reapOpenAcpxProcessLeases(params) {
1152
1141
  const leases = await params.leaseStore.listOpen(params.gatewayInstanceId);
1153
1142
  const inspectedPids = [];
1154
1143
  const terminatedPids = [];
1155
- const pendingLeaseRootResults = /* @__PURE__ */ new Map();
1144
+ const legacyWrapperRoots = /* @__PURE__ */ new Set();
1156
1145
  for (const lease of leases) {
1157
1146
  if (lease.rootPid <= 0) {
1147
+ legacyWrapperRoots.add(lease.wrapperRoot);
1158
1148
  await params.leaseStore.markState(lease.leaseId, "closing");
1159
- let result = pendingLeaseRootResults.get(lease.wrapperRoot);
1160
- if (!result) {
1161
- result = await reapStaleOpenClawOwnedAcpxOrphans({
1162
- wrapperRoot: lease.wrapperRoot,
1163
- deps: params.deps
1164
- });
1165
- pendingLeaseRootResults.set(lease.wrapperRoot, result);
1166
- inspectedPids.push(...result.inspectedPids);
1167
- terminatedPids.push(...result.terminatedPids);
1168
- }
1169
- await params.leaseStore.markState(lease.leaseId, result.terminatedPids.length > 0 ? "closed" : "lost");
1149
+ const result = await cleanupOpenClawOwnedAcpxPendingLease({
1150
+ leaseId: lease.leaseId,
1151
+ gatewayInstanceId: lease.gatewayInstanceId,
1152
+ wrapperRoot: lease.wrapperRoot,
1153
+ wrapperPath: lease.wrapperPath,
1154
+ deps: params.deps
1155
+ });
1156
+ inspectedPids.push(...result.inspectedPids);
1157
+ terminatedPids.push(...result.terminatedPids);
1158
+ const retryableEvidenceFailure = result.skippedReason === "ambiguous-root" || result.skippedReason === "process-list-unavailable" || result.skippedReason === "unsupported-platform" || result.skippedReason === "unverified-root" || lease.sessionKey === "openclaw:acpx:probe" && result.skippedReason === "missing-root";
1159
+ await params.leaseStore.markState(lease.leaseId, retryableEvidenceFailure ? "open" : result.terminatedPids.length > 0 ? "closed" : "lost");
1170
1160
  continue;
1171
1161
  }
1172
1162
  await params.leaseStore.markState(lease.leaseId, "closing");
@@ -1179,7 +1169,15 @@ async function reapOpenAcpxProcessLeases(params) {
1179
1169
  });
1180
1170
  inspectedPids.push(...result.inspectedPids);
1181
1171
  terminatedPids.push(...result.terminatedPids);
1182
- await params.leaseStore.markState(lease.leaseId, result.skippedReason === "process-list-unavailable" ? "open" : result.terminatedPids.length > 0 ? "closed" : "lost");
1172
+ await params.leaseStore.markState(lease.leaseId, result.skippedReason === "process-list-unavailable" || result.skippedReason === "unsupported-platform" ? "open" : result.terminatedPids.length > 0 ? "closed" : "lost");
1173
+ }
1174
+ for (const wrapperRoot of legacyWrapperRoots) {
1175
+ const legacyResult = await reapStaleOpenClawOwnedAcpxOrphans({
1176
+ wrapperRoot,
1177
+ deps: params.deps
1178
+ });
1179
+ inspectedPids.push(...legacyResult.inspectedPids);
1180
+ terminatedPids.push(...legacyResult.terminatedPids);
1183
1181
  }
1184
1182
  return {
1185
1183
  inspectedPids,
@@ -1187,7 +1185,7 @@ async function reapOpenAcpxProcessLeases(params) {
1187
1185
  };
1188
1186
  }
1189
1187
  /** Create the ACPX plugin service that owns runtime registration and cleanup. */
1190
- function createAcpxRuntimeService(params = {}) {
1188
+ function createAcpxRuntimeService(params) {
1191
1189
  let runtime = null;
1192
1190
  let lifecycleRevision = 0;
1193
1191
  return {
@@ -1225,10 +1223,6 @@ function createAcpxRuntimeService(params = {}) {
1225
1223
  deps: params.processCleanupDeps
1226
1224
  }));
1227
1225
  if (startupReap.terminatedPids.length > 0) ctx.logger.info(`reaped ${startupReap.terminatedPids.length} stale OpenClaw-owned ACPX process${startupReap.terminatedPids.length === 1 ? "" : "es"}`);
1228
- warnOnIgnoredLegacyCompatibilityConfig({
1229
- pluginConfig,
1230
- logger: ctx.logger
1231
- });
1232
1226
  const startedRuntime = await measureAcpxStartup(ctx, "runtime.create", () => params.runtimeFactory ? params.runtimeFactory({
1233
1227
  pluginConfig,
1234
1228
  gatewayInstanceId,
@@ -1246,11 +1240,11 @@ function createAcpxRuntimeService(params = {}) {
1246
1240
  const shouldProbeRuntime = shouldProbeRuntimeAtStartup();
1247
1241
  detailAcpxStartup(ctx, "probe-policy", [["startupProbeEnabledCount", shouldProbeRuntime ? 1 : 0], ["probeAgent", pluginConfig.probeAgent ?? "default"]]);
1248
1242
  await measureAcpxStartup(ctx, "backend.register", () => {
1249
- registerAcpRuntimeBackend({
1250
- id: ACPX_BACKEND_ID,
1243
+ const backend = {
1251
1244
  runtime: startedRuntime,
1252
1245
  ...shouldProbeRuntime ? { healthy: () => runtime?.isHealthy() ?? false } : {}
1253
- });
1246
+ };
1247
+ params.backendLifecycle.publish(backend);
1254
1248
  ctx.logger.info(`embedded acpx runtime backend registered (cwd: ${pluginConfig.cwd})`);
1255
1249
  });
1256
1250
  if (!shouldProbeRuntime) return;
@@ -1267,7 +1261,7 @@ function createAcpxRuntimeService(params = {}) {
1267
1261
  ctx.logger.info("embedded acpx runtime backend ready");
1268
1262
  return;
1269
1263
  }
1270
- const doctorReport = await measureAcpxStartup(ctx, "probe.doctor", () => startedRuntime.doctor?.());
1264
+ const doctorReport = await measureAcpxStartup(ctx, "probe.doctor", () => startedRuntime.doctor());
1271
1265
  if (currentRevision !== lifecycleRevision) return;
1272
1266
  detailAcpxStartup(ctx, "probe.result", [["healthyCount", 0]]);
1273
1267
  ctx.logger.warn(`embedded acpx runtime backend probe failed: ${doctorReport ? formatDoctorFailureMessage(doctorReport) : "backend remained unhealthy after probe"}`);
@@ -1279,7 +1273,7 @@ function createAcpxRuntimeService(params = {}) {
1279
1273
  },
1280
1274
  async stop(_ctx) {
1281
1275
  lifecycleRevision += 1;
1282
- unregisterAcpRuntimeBackend(ACPX_BACKEND_ID);
1276
+ if (runtime) params.backendLifecycle.retract(runtime);
1283
1277
  runtime = null;
1284
1278
  }
1285
1279
  };
@@ -1,5 +1,9 @@
1
1
  {
2
2
  "id": "acpx",
3
+ "doctorContract": {
4
+ "configRepair": true,
5
+ "stateMigrations": true
6
+ },
3
7
  "activation": {
4
8
  "onStartup": true
5
9
  },
@@ -37,18 +41,11 @@
37
41
  "openClawToolsMcpBridge": {
38
42
  "type": "boolean"
39
43
  },
40
- "strictWindowsCmdWrapper": {
41
- "type": "boolean"
42
- },
43
44
  "timeoutSeconds": {
44
45
  "type": "number",
45
46
  "minimum": 0.001,
46
47
  "default": 120
47
48
  },
48
- "queueOwnerTtlSeconds": {
49
- "type": "number",
50
- "minimum": 0
51
- },
52
49
  "piSessionCatalog": {
53
50
  "type": "object",
54
51
  "additionalProperties": false,
@@ -87,6 +84,7 @@
87
84
  "type": "object",
88
85
  "additionalProperties": {
89
86
  "type": "object",
87
+ "additionalProperties": false,
90
88
  "properties": {
91
89
  "command": {
92
90
  "type": "string",
@@ -129,21 +127,11 @@
129
127
  "help": "Default off. When enabled, inject the built-in OpenClaw core-tools MCP server into embedded ACP sessions so ACP agents can call selected built-in tools such as cron.",
130
128
  "advanced": true
131
129
  },
132
- "strictWindowsCmdWrapper": {
133
- "label": "Strict Windows cmd Wrapper",
134
- "help": "Legacy compatibility field. The current embedded acpx/runtime package uses its own Windows command resolution behavior. Setting this to false is accepted for compatibility and logged as ignored.",
135
- "advanced": true
136
- },
137
130
  "timeoutSeconds": {
138
131
  "label": "Runtime Operation Timeout Seconds",
139
132
  "help": "Timeout for embedded ACP runtime startup and control operations. ACP turns use OpenClaw agent/run timeouts.",
140
133
  "advanced": true
141
134
  },
142
- "queueOwnerTtlSeconds": {
143
- "label": "Queue Owner TTL Seconds",
144
- "help": "Reserved compatibility field for the older embedded ACPX queue-owner path. Accepted for compatibility and logged as ignored.",
145
- "advanced": true
146
- },
147
135
  "piSessionCatalog.enabled": {
148
136
  "label": "Pi Session Catalog",
149
137
  "help": "Auto-detect Pi sessions on the Gateway and paired nodes, then show them in the sessions sidebar."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/acpx",
3
- "version": "2026.7.2-beta.7",
3
+ "version": "2026.8.1-beta.3",
4
4
  "description": "OpenClaw ACP runtime backend with plugin-owned session and transport management.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,7 +10,7 @@
10
10
  "dependencies": {
11
11
  "@agentclientprotocol/claude-agent-acp": "0.62.0",
12
12
  "@agentclientprotocol/codex-acp": "1.1.7",
13
- "acpx": "0.13.0",
13
+ "acpx": "0.13.1",
14
14
  "smol-toml": "1.7.1",
15
15
  "zod": "4.4.3"
16
16
  },
@@ -43,10 +43,10 @@
43
43
  ]
44
44
  },
45
45
  "compat": {
46
- "pluginApi": ">=2026.7.2-beta.7"
46
+ "pluginApi": ">=2026.8.1-beta.3"
47
47
  },
48
48
  "build": {
49
- "openclawVersion": "2026.7.2-beta.7",
49
+ "openclawVersion": "2026.8.1-beta.3",
50
50
  "staticAssets": [
51
51
  {
52
52
  "source": "./src/runtime-internals/mcp-proxy.mjs",
@@ -74,7 +74,7 @@
74
74
  "skills/**"
75
75
  ],
76
76
  "peerDependencies": {
77
- "openclaw": ">=2026.7.2-beta.7"
77
+ "openclaw": ">=2026.8.1-beta.3"
78
78
  },
79
79
  "peerDependenciesMeta": {
80
80
  "openclaw": {