@openclaw/acpx 2026.7.2-beta.4 → 2026.7.2-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/dist/doctor-contract-api.js +1 -1
- package/dist/index.js +327 -31
- package/dist/{process-lease-CU1cFI4I.js → process-lease-DSLDgiNl.js} +62 -1
- package/dist/{process-reaper-BIOtp_Ek.js → process-reaper-DFwbcdPa.js} +7 -51
- package/dist/{register.runtime-Dajn8myc.js → register.runtime-BbS2JTTv.js} +1 -1
- package/dist/register.runtime.js +1 -1
- package/dist/{runtime-CN4JQkdV.js → runtime-By_lR8uk.js} +274 -71
- package/dist/{service-DOsKw_R1.js → service-CBZSAymH.js} +5 -5
- package/package.json +8 -9
- package/npm-shrinkwrap.json +0 -2489
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as AcpxPluginConfigSchema } from "./config-schema-lrk5nlcV.js";
|
|
2
|
-
import "./process-lease-
|
|
2
|
+
import { _ as splitCommandParts } from "./process-lease-DSLDgiNl.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { formatPluginConfigIssue } from "openclaw/plugin-sdk/extension-shared";
|
|
5
5
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
@@ -13,54 +13,6 @@ const CODEX_ACP_BIN = "codex-acp";
|
|
|
13
13
|
const LEGACY_CODEX_ACP_PACKAGE = "@zed-industries/codex-acp";
|
|
14
14
|
const OPENCLAW_CODEX_CONFIG_ARG = "--openclaw-codex-config";
|
|
15
15
|
//#endregion
|
|
16
|
-
//#region extensions/acpx/src/command-line.ts
|
|
17
|
-
/**
|
|
18
|
-
* Small shell-command helpers for ACPX-launched processes. Splitting supports
|
|
19
|
-
* simple quoted command strings from config without invoking a shell parser.
|
|
20
|
-
*/
|
|
21
|
-
/** Quote one command argument for display or config serialization. */
|
|
22
|
-
function quoteCommandPart(value) {
|
|
23
|
-
return JSON.stringify(value);
|
|
24
|
-
}
|
|
25
|
-
/** Split a command string into argv-like parts using simple quote/backslash rules. */
|
|
26
|
-
function splitCommandParts(value) {
|
|
27
|
-
const parts = [];
|
|
28
|
-
let current = "";
|
|
29
|
-
let quote = null;
|
|
30
|
-
let escaping = false;
|
|
31
|
-
for (const ch of value) {
|
|
32
|
-
if (escaping) {
|
|
33
|
-
current += ch;
|
|
34
|
-
escaping = false;
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
if (ch === "\\" && quote !== "'") {
|
|
38
|
-
escaping = true;
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
if (quote) {
|
|
42
|
-
if (ch === quote) quote = null;
|
|
43
|
-
else current += ch;
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
if (ch === "'" || ch === "\"") {
|
|
47
|
-
quote = ch;
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
if (/\s/.test(ch)) {
|
|
51
|
-
if (current) {
|
|
52
|
-
parts.push(current);
|
|
53
|
-
current = "";
|
|
54
|
-
}
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
current += ch;
|
|
58
|
-
}
|
|
59
|
-
if (escaping) current += "\\";
|
|
60
|
-
if (current) parts.push(current);
|
|
61
|
-
return parts;
|
|
62
|
-
}
|
|
63
|
-
//#endregion
|
|
64
16
|
//#region extensions/acpx/src/config.ts
|
|
65
17
|
/**
|
|
66
18
|
* Resolves ACPX plugin config from raw user configuration. It locates the
|
|
@@ -439,7 +391,11 @@ async function cleanupOpenClawOwnedAcpxProcessTree(params) {
|
|
|
439
391
|
try {
|
|
440
392
|
processes = await (params.deps?.listProcesses ?? listPlatformProcesses)();
|
|
441
393
|
} catch {
|
|
442
|
-
|
|
394
|
+
return {
|
|
395
|
+
inspectedPids: [],
|
|
396
|
+
terminatedPids: [],
|
|
397
|
+
skippedReason: "process-list-unavailable"
|
|
398
|
+
};
|
|
443
399
|
}
|
|
444
400
|
const listedTree = collectProcessTree(processes, rootPid);
|
|
445
401
|
if (listedTree.length === 0) return {
|
|
@@ -510,4 +466,4 @@ async function reapStaleOpenClawOwnedAcpxOrphans(params) {
|
|
|
510
466
|
};
|
|
511
467
|
}
|
|
512
468
|
//#endregion
|
|
513
|
-
export { resolveAcpxPluginRoot as a,
|
|
469
|
+
export { resolveAcpxPluginRoot as a, CODEX_ACP_PACKAGE as c, resolveAcpxPluginConfig as i, LEGACY_CODEX_ACP_PACKAGE as l, isOpenClawLeaseAwareAcpxProcessCommand as n, toAcpMcpServers as o, reapStaleOpenClawOwnedAcpxOrphans as r, CODEX_ACP_BIN as s, cleanupOpenClawOwnedAcpxProcessTree as t, OPENCLAW_CODEX_CONFIG_ARG as u };
|
|
@@ -200,7 +200,7 @@ function createLazyAcpRuntimeProxy(resolveRuntime) {
|
|
|
200
200
|
* immediately, then imports the heavier service only when a session needs it.
|
|
201
201
|
*/
|
|
202
202
|
const ACPX_BACKEND_ID = "acpx";
|
|
203
|
-
const loadServiceModule = createLazyRuntimeModule(() => import("./service-
|
|
203
|
+
const loadServiceModule = createLazyRuntimeModule(() => import("./service-CBZSAymH.js"));
|
|
204
204
|
async function startRealService(state) {
|
|
205
205
|
if (state.realRuntime) return state.realRuntime;
|
|
206
206
|
if (!state.ctx) throw new Error("ACPX runtime service is not started");
|
package/dist/register.runtime.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createAcpxRuntimeService } from "./register.runtime-
|
|
1
|
+
import { t as createAcpxRuntimeService } from "./register.runtime-BbS2JTTv.js";
|
|
2
2
|
export { createAcpxRuntimeService };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as hashAcpxProcessCommand, l as
|
|
1
|
+
import { _ as splitCommandParts, a as hashAcpxProcessCommand, l as readAcpxProcessLeaseIdentity, r as createAcpxProcessLeaseId, u as withAcpxLeaseEnvironment } from "./process-lease-DSLDgiNl.js";
|
|
2
2
|
import { AcpRuntimeError } from "./runtime-api.js";
|
|
3
|
-
import { c as
|
|
3
|
+
import { c as CODEX_ACP_PACKAGE, n as isOpenClawLeaseAwareAcpxProcessCommand, t as cleanupOpenClawOwnedAcpxProcessTree, u as OPENCLAW_CODEX_CONFIG_ARG } from "./process-reaper-DFwbcdPa.js";
|
|
4
4
|
import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
5
5
|
import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
6
6
|
import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
@@ -128,29 +128,42 @@ function createResetAwareSessionStore(baseStore, params) {
|
|
|
128
128
|
let recordToSave = record;
|
|
129
129
|
const launch = params?.launchScope?.getStore();
|
|
130
130
|
const sessionName = readSessionRecordName(record);
|
|
131
|
-
const rootPid = readRecordAgentPid(record);
|
|
132
131
|
const agentCommand = readRecordAgentCommand(record);
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
132
|
+
const leasedCommand = launch?.leasedCommand ?? agentCommand;
|
|
133
|
+
const leaseIdentity = launch ?? readAcpxProcessLeaseIdentity(leasedCommand);
|
|
134
|
+
if (params?.leaseStore && params.gatewayInstanceId && params.wrapperRoot && (!launch || sessionName === launch.sessionKey) && leasedCommand && leaseIdentity?.gatewayInstanceId === params.gatewayInstanceId && isOpenClawLeaseAwareAcpxProcessCommand({
|
|
135
|
+
command: leasedCommand,
|
|
136
|
+
wrapperRoot: params.wrapperRoot
|
|
137
|
+
})) {
|
|
138
|
+
const existing = await params.leaseStore.load(leaseIdentity.leaseId);
|
|
139
|
+
if (!existing || existing.gatewayInstanceId === leaseIdentity.gatewayInstanceId && existing.sessionKey === sessionName && existing.wrapperRoot === params.wrapperRoot) {
|
|
140
|
+
const lifecycleRecord = Boolean(launch && launch.resolvedCommand !== launch.leasedCommand) ? {
|
|
141
|
+
...record,
|
|
142
|
+
pid: void 0,
|
|
143
|
+
processId: void 0,
|
|
144
|
+
agentStartedAt: void 0
|
|
145
|
+
} : record;
|
|
146
|
+
const rootPid = readRecordAgentPid(lifecycleRecord);
|
|
147
|
+
if (rootPid) await params.leaseStore.save({
|
|
148
|
+
leaseId: leaseIdentity.leaseId,
|
|
149
|
+
gatewayInstanceId: leaseIdentity.gatewayInstanceId,
|
|
150
|
+
sessionKey: sessionName,
|
|
151
|
+
wrapperRoot: params.wrapperRoot,
|
|
152
|
+
wrapperPath: extractGeneratedWrapperPath(leasedCommand),
|
|
153
|
+
rootPid,
|
|
154
|
+
...existing?.rootPid === rootPid && existing.processGroupId ? { processGroupId: existing.processGroupId } : {},
|
|
155
|
+
commandHash: hashAcpxProcessCommand(leasedCommand),
|
|
156
|
+
startedAt: existing?.rootPid === rootPid ? existing.startedAt : Date.now(),
|
|
157
|
+
state: "open"
|
|
158
|
+
});
|
|
159
|
+
recordToSave = withOpenClawLeaseSessionMetadata({
|
|
160
|
+
...lifecycleRecord,
|
|
161
|
+
agentCommand: leasedCommand
|
|
162
|
+
}, {
|
|
163
|
+
openclawLeaseId: leaseIdentity.leaseId,
|
|
164
|
+
openclawGatewayInstanceId: leaseIdentity.gatewayInstanceId
|
|
165
|
+
});
|
|
166
|
+
}
|
|
154
167
|
}
|
|
155
168
|
await baseStore.save(recordToSave);
|
|
156
169
|
if (sessionName) freshSessionKeys.delete(sessionName);
|
|
@@ -362,6 +375,9 @@ function quoteShellArg(value) {
|
|
|
362
375
|
if (/^[A-Za-z0-9_./:=@+-]+$/.test(value)) return value;
|
|
363
376
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
364
377
|
}
|
|
378
|
+
function normalizeAgentCommand(command) {
|
|
379
|
+
return (Array.isArray(command) ? command.map((part) => quoteShellArg(part)).join(" ") : command).trim() || void 0;
|
|
380
|
+
}
|
|
365
381
|
function appendCodexAcpConfigOverrides(command, override) {
|
|
366
382
|
const config = {
|
|
367
383
|
...override.model ? { model: override.model } : {},
|
|
@@ -373,7 +389,7 @@ function appendCodexAcpConfigOverrides(command, override) {
|
|
|
373
389
|
function createModelScopedAgentRegistry(params) {
|
|
374
390
|
return {
|
|
375
391
|
resolve(agentName) {
|
|
376
|
-
const command = params.agentRegistry.resolve(agentName);
|
|
392
|
+
const command = normalizeAgentCommand(params.agentRegistry.resolve(agentName)) ?? "";
|
|
377
393
|
const override = params.scope.getStore();
|
|
378
394
|
if (!override || normalizeAgentName(agentName) !== CODEX_ACP_AGENT_ID || !isCodexAcpCommand(command)) return params.leaseCommand(command);
|
|
379
395
|
return params.leaseCommand(appendCodexAcpConfigOverrides(command, override));
|
|
@@ -386,8 +402,7 @@ function createModelScopedAgentRegistry(params) {
|
|
|
386
402
|
function resolveAgentCommand(params) {
|
|
387
403
|
const normalizedAgentName = normalizeAgentName(params.agentName);
|
|
388
404
|
if (!normalizedAgentName) return;
|
|
389
|
-
|
|
390
|
-
return typeof resolvedCommand === "string" ? resolvedCommand.trim() || void 0 : void 0;
|
|
405
|
+
return normalizeAgentCommand(params.agentRegistry.resolve(normalizedAgentName));
|
|
391
406
|
}
|
|
392
407
|
function shouldUseBridgeSafeDelegateForCommand(command) {
|
|
393
408
|
return isOpenClawBridgeCommand(command);
|
|
@@ -422,6 +437,9 @@ var AcpxRuntime = class {
|
|
|
422
437
|
this.codexAcpModelOverrideScope = new AsyncLocalStorage();
|
|
423
438
|
this.managedToolsSessionDelegates = /* @__PURE__ */ new Map();
|
|
424
439
|
this.launchLeaseScope = new AsyncLocalStorage();
|
|
440
|
+
this.ensureSessionTails = /* @__PURE__ */ new Map();
|
|
441
|
+
this.processLeaseTransitionTails = /* @__PURE__ */ new Map();
|
|
442
|
+
this.processLeaseOperationCounts = /* @__PURE__ */ new Map();
|
|
425
443
|
const { openclawProcessCleanup, ...delegateTestOptions } = testOptions ?? {};
|
|
426
444
|
this.processCleanupDeps = openclawProcessCleanup;
|
|
427
445
|
this.wrapperRoot = options.openclawWrapperRoot;
|
|
@@ -434,7 +452,8 @@ var AcpxRuntime = class {
|
|
|
434
452
|
this.sessionStore = createResetAwareSessionStore(options.sessionStore, {
|
|
435
453
|
gatewayInstanceId: this.gatewayInstanceId,
|
|
436
454
|
leaseStore: this.processLeaseStore,
|
|
437
|
-
launchScope: this.launchLeaseScope
|
|
455
|
+
launchScope: this.launchLeaseScope,
|
|
456
|
+
wrapperRoot: this.wrapperRoot
|
|
438
457
|
});
|
|
439
458
|
this.agentRegistry = options.agentRegistry;
|
|
440
459
|
this.scopedAgentRegistry = createModelScopedAgentRegistry({
|
|
@@ -519,47 +538,206 @@ var AcpxRuntime = class {
|
|
|
519
538
|
commandWithLaunchLease(command) {
|
|
520
539
|
const launch = this.launchLeaseScope.getStore();
|
|
521
540
|
if (!launch) return command;
|
|
522
|
-
launch.stableCommand
|
|
541
|
+
if (command === launch.stableCommand) return launch.resolvedCommand;
|
|
523
542
|
return withAcpxLeaseEnvironment({
|
|
524
543
|
command,
|
|
525
544
|
leaseId: launch.leaseId,
|
|
526
545
|
gatewayInstanceId: launch.gatewayInstanceId
|
|
527
546
|
});
|
|
528
547
|
}
|
|
529
|
-
async
|
|
530
|
-
if (params.mode !== "persistent" || !params.command) return
|
|
548
|
+
async readReusablePersistentSessionCommand(params) {
|
|
549
|
+
if (params.mode !== "persistent" || !params.command) return;
|
|
531
550
|
const existing = await this.sessionStore.load(params.sessionKey);
|
|
532
|
-
if (!existing || readRecordResetOnNextEnsure(existing)) return
|
|
551
|
+
if (!existing || readRecordResetOnNextEnsure(existing)) return;
|
|
533
552
|
const recordCwd = readRecordCwd(existing);
|
|
534
|
-
if (!recordCwd || resolve(recordCwd) !== resolve(params.cwd?.trim() || this.cwd)) return
|
|
535
|
-
|
|
553
|
+
if (!recordCwd || resolve(recordCwd) !== resolve(params.cwd?.trim() || this.cwd)) return;
|
|
554
|
+
const recordCommand = readRecordAgentCommand(existing);
|
|
555
|
+
if (!recordCommand) return;
|
|
556
|
+
const leaseIdentity = readAcpxProcessLeaseIdentity(recordCommand);
|
|
557
|
+
if (leaseIdentity && leaseIdentity.gatewayInstanceId !== this.gatewayInstanceId) return;
|
|
558
|
+
if (recordCommand !== (leaseIdentity ? withAcpxLeaseEnvironment({
|
|
559
|
+
command: params.command,
|
|
560
|
+
leaseId: leaseIdentity.leaseId,
|
|
561
|
+
gatewayInstanceId: leaseIdentity.gatewayInstanceId
|
|
562
|
+
}) : params.command)) return;
|
|
536
563
|
const existingSessionId = typeof existing === "object" && existing !== null ? existing.acpSessionId : void 0;
|
|
537
|
-
return !params.resumeSessionId || existingSessionId === params.resumeSessionId;
|
|
564
|
+
return !params.resumeSessionId || existingSessionId === params.resumeSessionId ? recordCommand : void 0;
|
|
538
565
|
}
|
|
539
566
|
async runWithLaunchLease(params) {
|
|
540
|
-
if (
|
|
567
|
+
if (!params.command || !this.wrapperRoot || !this.gatewayInstanceId || !this.processLeaseStore || !isOpenClawLeaseAwareAcpxProcessCommand({
|
|
541
568
|
command: params.command,
|
|
542
569
|
wrapperRoot: this.wrapperRoot
|
|
543
570
|
})) return await params.run();
|
|
571
|
+
const processLeaseStore = this.processLeaseStore;
|
|
572
|
+
const reusableIdentity = readAcpxProcessLeaseIdentity(params.reusableCommand);
|
|
573
|
+
const canReuseLeaseIdentity = reusableIdentity?.gatewayInstanceId === this.gatewayInstanceId;
|
|
574
|
+
const leaseId = canReuseLeaseIdentity ? reusableIdentity.leaseId : createAcpxProcessLeaseId();
|
|
575
|
+
const leasedCommand = withAcpxLeaseEnvironment({
|
|
576
|
+
command: params.command,
|
|
577
|
+
leaseId,
|
|
578
|
+
gatewayInstanceId: this.gatewayInstanceId
|
|
579
|
+
});
|
|
544
580
|
const launch = {
|
|
545
|
-
leaseId
|
|
581
|
+
leaseId,
|
|
546
582
|
gatewayInstanceId: this.gatewayInstanceId,
|
|
547
583
|
sessionKey: params.sessionKey,
|
|
548
584
|
wrapperRoot: this.wrapperRoot,
|
|
549
|
-
stableCommand: params.command
|
|
585
|
+
stableCommand: params.command,
|
|
586
|
+
resolvedCommand: params.reusableCommand ?? leasedCommand,
|
|
587
|
+
leasedCommand
|
|
550
588
|
};
|
|
551
|
-
await this.
|
|
552
|
-
|
|
553
|
-
gatewayInstanceId
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
589
|
+
await this.retainProcessLeaseOperation(launch, async () => {
|
|
590
|
+
const reusableLease = canReuseLeaseIdentity ? await processLeaseStore.load(launch.leaseId) : void 0;
|
|
591
|
+
if (reusableLease && (reusableLease.gatewayInstanceId !== launch.gatewayInstanceId || reusableLease.sessionKey !== launch.sessionKey || reusableLease.wrapperRoot !== launch.wrapperRoot)) throw new AcpRuntimeError("ACP_SESSION_INIT_FAILED", `ACPX process lease ${launch.leaseId} belongs to another session`);
|
|
592
|
+
if (!(!reusableLease && (!params.reusableCommand || params.reusableCommand === leasedCommand))) return;
|
|
593
|
+
await processLeaseStore.save({
|
|
594
|
+
leaseId: launch.leaseId,
|
|
595
|
+
gatewayInstanceId: launch.gatewayInstanceId,
|
|
596
|
+
sessionKey: launch.sessionKey,
|
|
597
|
+
wrapperRoot: launch.wrapperRoot,
|
|
598
|
+
wrapperPath: extractGeneratedWrapperPath(leasedCommand),
|
|
599
|
+
rootPid: 0,
|
|
600
|
+
commandHash: hashAcpxProcessCommand(leasedCommand),
|
|
601
|
+
startedAt: Date.now(),
|
|
602
|
+
state: "open"
|
|
603
|
+
});
|
|
604
|
+
});
|
|
605
|
+
try {
|
|
606
|
+
const result = await this.launchLeaseScope.run(launch, params.run);
|
|
607
|
+
await this.finalizeProcessLeaseForSession(params.sessionKey, launch);
|
|
608
|
+
return result;
|
|
609
|
+
} catch (error) {
|
|
610
|
+
await this.retirePendingProcessLease(launch);
|
|
611
|
+
throw error;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
async prepareProcessLeaseForOperation(handle) {
|
|
615
|
+
if (!this.processLeaseStore || !this.gatewayInstanceId || !this.wrapperRoot) return;
|
|
616
|
+
const processLeaseStore = this.processLeaseStore;
|
|
617
|
+
const wrapperRoot = this.wrapperRoot;
|
|
618
|
+
const record = await this.sessionStore.load(handle.acpxRecordId ?? handle.sessionKey);
|
|
619
|
+
const recordPid = readRecordAgentPid(record);
|
|
620
|
+
const command = readAgentCommandFromRecord(record);
|
|
621
|
+
const identity = readAcpxProcessLeaseIdentity(command);
|
|
622
|
+
if (!command || !isOpenClawLeaseAwareAcpxProcessCommand({
|
|
623
|
+
command,
|
|
624
|
+
wrapperRoot
|
|
625
|
+
})) return;
|
|
626
|
+
if (!identity) return;
|
|
627
|
+
if (identity.gatewayInstanceId !== this.gatewayInstanceId) throw new AcpRuntimeError("ACP_TURN_FAILED", `ACPX process lease ${identity.leaseId} belongs to another gateway`);
|
|
628
|
+
await this.retainProcessLeaseOperation(identity, async () => {
|
|
629
|
+
const existing = await processLeaseStore.load(identity.leaseId);
|
|
630
|
+
if (!existing) {
|
|
631
|
+
await processLeaseStore.save({
|
|
632
|
+
leaseId: identity.leaseId,
|
|
633
|
+
gatewayInstanceId: identity.gatewayInstanceId,
|
|
634
|
+
sessionKey: handle.sessionKey,
|
|
635
|
+
wrapperRoot,
|
|
636
|
+
wrapperPath: extractGeneratedWrapperPath(command),
|
|
637
|
+
rootPid: recordPid ?? 0,
|
|
638
|
+
commandHash: hashAcpxProcessCommand(command),
|
|
639
|
+
startedAt: Date.now(),
|
|
640
|
+
state: "open"
|
|
641
|
+
});
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
if (existing.gatewayInstanceId !== identity.gatewayInstanceId || existing.sessionKey !== handle.sessionKey || existing.wrapperRoot !== wrapperRoot) throw new AcpRuntimeError("ACP_TURN_FAILED", `ACPX process lease ${identity.leaseId} belongs to another session`);
|
|
561
645
|
});
|
|
562
|
-
return
|
|
646
|
+
return identity;
|
|
647
|
+
}
|
|
648
|
+
async runSerializedProcessLeaseTransition(leaseId, run) {
|
|
649
|
+
const previous = this.processLeaseTransitionTails.get(leaseId) ?? Promise.resolve();
|
|
650
|
+
let release;
|
|
651
|
+
const current = new Promise((resolve) => {
|
|
652
|
+
release = resolve;
|
|
653
|
+
});
|
|
654
|
+
const tail = previous.then(() => current);
|
|
655
|
+
this.processLeaseTransitionTails.set(leaseId, tail);
|
|
656
|
+
await previous;
|
|
657
|
+
try {
|
|
658
|
+
return await run();
|
|
659
|
+
} finally {
|
|
660
|
+
release();
|
|
661
|
+
if (this.processLeaseTransitionTails.get(leaseId) === tail) this.processLeaseTransitionTails.delete(leaseId);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
async retainProcessLeaseOperation(identity, prepare) {
|
|
665
|
+
await this.runSerializedProcessLeaseTransition(identity.leaseId, async () => {
|
|
666
|
+
await prepare();
|
|
667
|
+
this.processLeaseOperationCounts.set(identity.leaseId, (this.processLeaseOperationCounts.get(identity.leaseId) ?? 0) + 1);
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
async releaseProcessLeaseOperation(identity, finalize) {
|
|
671
|
+
if (!identity) return;
|
|
672
|
+
await this.runSerializedProcessLeaseTransition(identity.leaseId, async () => {
|
|
673
|
+
const count = this.processLeaseOperationCounts.get(identity.leaseId) ?? 0;
|
|
674
|
+
if (count > 1) {
|
|
675
|
+
this.processLeaseOperationCounts.set(identity.leaseId, count - 1);
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
if (count === 0) return;
|
|
679
|
+
this.processLeaseOperationCounts.delete(identity.leaseId);
|
|
680
|
+
await finalize();
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
async finalizeProcessLeaseForOperation(handle, identity) {
|
|
684
|
+
await this.finalizeProcessLeaseForSession(handle.acpxRecordId ?? handle.sessionKey, identity);
|
|
685
|
+
}
|
|
686
|
+
async finalizeProcessLeaseForSession(sessionId, identity) {
|
|
687
|
+
if (!identity || !this.processLeaseStore) return;
|
|
688
|
+
const processLeaseStore = this.processLeaseStore;
|
|
689
|
+
await this.releaseProcessLeaseOperation(identity, async () => {
|
|
690
|
+
const lease = await processLeaseStore.load(identity.leaseId);
|
|
691
|
+
if (!lease || lease.gatewayInstanceId !== identity.gatewayInstanceId) return;
|
|
692
|
+
if (lease.rootPid <= 0) {
|
|
693
|
+
await processLeaseStore.markState(identity.leaseId, "lost");
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
try {
|
|
697
|
+
const recordIdentity = readAcpxProcessLeaseIdentity(readAgentCommandFromRecord(await this.sessionStore.load(sessionId)));
|
|
698
|
+
if (recordIdentity?.leaseId !== identity.leaseId || recordIdentity.gatewayInstanceId !== identity.gatewayInstanceId) await processLeaseStore.markState(identity.leaseId, "lost");
|
|
699
|
+
} catch {}
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
async retirePendingProcessLease(identity) {
|
|
703
|
+
if (!identity || !this.processLeaseStore) return;
|
|
704
|
+
const processLeaseStore = this.processLeaseStore;
|
|
705
|
+
await this.releaseProcessLeaseOperation(identity, async () => {
|
|
706
|
+
const lease = await processLeaseStore.load(identity.leaseId);
|
|
707
|
+
if (lease?.gatewayInstanceId === identity.gatewayInstanceId && lease.rootPid <= 0) await processLeaseStore.markState(identity.leaseId, "lost");
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
async runWithProcessLeaseForHandle(handle, run) {
|
|
711
|
+
const identity = await this.prepareProcessLeaseForOperation(handle);
|
|
712
|
+
try {
|
|
713
|
+
return await run();
|
|
714
|
+
} finally {
|
|
715
|
+
await this.finalizeProcessLeaseForOperation(handle, identity);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
async finalizeProcessLeaseAfter(handle, identityPromise, resultPromise) {
|
|
719
|
+
try {
|
|
720
|
+
return await resultPromise;
|
|
721
|
+
} finally {
|
|
722
|
+
await this.finalizeProcessLeaseForOperation(handle, await identityPromise);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
async runSerializedSessionEnsure(sessionKey, run) {
|
|
726
|
+
const key = sessionKey.trim() || sessionKey;
|
|
727
|
+
const previous = this.ensureSessionTails.get(key) ?? Promise.resolve();
|
|
728
|
+
let release;
|
|
729
|
+
const current = new Promise((resolve) => {
|
|
730
|
+
release = resolve;
|
|
731
|
+
});
|
|
732
|
+
const tail = previous.then(() => current);
|
|
733
|
+
this.ensureSessionTails.set(key, tail);
|
|
734
|
+
await previous;
|
|
735
|
+
try {
|
|
736
|
+
return await run();
|
|
737
|
+
} finally {
|
|
738
|
+
release();
|
|
739
|
+
if (this.ensureSessionTails.get(key) === tail) this.ensureSessionTails.delete(key);
|
|
740
|
+
}
|
|
563
741
|
}
|
|
564
742
|
async withCodexWrapperDiagnostics(params) {
|
|
565
743
|
try {
|
|
@@ -602,7 +780,7 @@ var AcpxRuntime = class {
|
|
|
602
780
|
wrapperRoot: lease.wrapperRoot,
|
|
603
781
|
deps: this.processCleanupDeps
|
|
604
782
|
});
|
|
605
|
-
await this.processLeaseStore?.markState(lease.leaseId, result.terminatedPids.length > 0 || result.skippedReason === "missing-root" ? "closed" : "lost");
|
|
783
|
+
await this.processLeaseStore?.markState(lease.leaseId, result.skippedReason === "process-list-unavailable" ? "open" : result.terminatedPids.length > 0 || result.skippedReason === "missing-root" ? "closed" : "lost");
|
|
606
784
|
return;
|
|
607
785
|
}
|
|
608
786
|
const rootCommand = readAgentCommandFromRecord(record) ?? resolveAgentCommand({
|
|
@@ -630,6 +808,9 @@ var AcpxRuntime = class {
|
|
|
630
808
|
return this.probeDelegate.doctor();
|
|
631
809
|
}
|
|
632
810
|
async ensureSession(input) {
|
|
811
|
+
return await this.runSerializedSessionEnsure(input.sessionKey, () => this.ensureSessionUnlocked(input));
|
|
812
|
+
}
|
|
813
|
+
async ensureSessionUnlocked(input) {
|
|
633
814
|
assertSupportedRuntimeSessionMode(input.mode);
|
|
634
815
|
const command = resolveAgentCommand({
|
|
635
816
|
agentName: input.agent,
|
|
@@ -655,7 +836,7 @@ var AcpxRuntime = class {
|
|
|
655
836
|
model: claudeModelOverride
|
|
656
837
|
} : input;
|
|
657
838
|
const stableLaunchCommand = codexModelOverride && command ? appendCodexAcpConfigOverrides(command, codexModelOverride) : command;
|
|
658
|
-
const
|
|
839
|
+
const reusableCommand = await this.readReusablePersistentSessionCommand({
|
|
659
840
|
sessionKey: input.sessionKey,
|
|
660
841
|
mode: input.mode,
|
|
661
842
|
cwd: input.cwd,
|
|
@@ -665,7 +846,7 @@ var AcpxRuntime = class {
|
|
|
665
846
|
const handle = !codexModelOverride ? await this.runWithLaunchLease({
|
|
666
847
|
sessionKey: ensureInput.sessionKey,
|
|
667
848
|
command: stableLaunchCommand,
|
|
668
|
-
|
|
849
|
+
reusableCommand,
|
|
669
850
|
run: () => this.withCodexWrapperDiagnostics({
|
|
670
851
|
command: stableLaunchCommand,
|
|
671
852
|
fallbackCode: "ACP_SESSION_INIT_FAILED",
|
|
@@ -674,7 +855,7 @@ var AcpxRuntime = class {
|
|
|
674
855
|
}) : await this.runWithLaunchLease({
|
|
675
856
|
sessionKey: input.sessionKey,
|
|
676
857
|
command: stableLaunchCommand,
|
|
677
|
-
|
|
858
|
+
reusableCommand,
|
|
678
859
|
run: () => this.codexAcpModelOverrideScope.run(codexModelOverride, () => this.withCodexWrapperDiagnostics({
|
|
679
860
|
command: stableLaunchCommand,
|
|
680
861
|
fallbackCode: "ACP_SESSION_INIT_FAILED",
|
|
@@ -687,9 +868,11 @@ var AcpxRuntime = class {
|
|
|
687
868
|
} : handle;
|
|
688
869
|
}
|
|
689
870
|
async *runTurn(input) {
|
|
690
|
-
const
|
|
691
|
-
|
|
871
|
+
const turnLease = await this.prepareProcessLeaseForOperation(input.handle);
|
|
872
|
+
let command;
|
|
692
873
|
try {
|
|
874
|
+
command = await this.resolveCommandForHandle(input.handle);
|
|
875
|
+
const delegate = await this.resolveDelegateForHandle(input.handle);
|
|
693
876
|
for await (const event of delegate.runTurn(withOpenClawManagedTurnTimeout(input))) {
|
|
694
877
|
if (event.type !== "error" || !isCodexAcpCommand(command) || !isGenericInternalAcpErrorMessage(event.message)) {
|
|
695
878
|
yield event;
|
|
@@ -711,11 +894,18 @@ var AcpxRuntime = class {
|
|
|
711
894
|
const stderrTail = await this.readCodexTurnFailureStderr({ handle: input.handle });
|
|
712
895
|
if (!stderrTail) throw error;
|
|
713
896
|
throw new AcpRuntimeError("ACP_TURN_FAILED", `Internal error: ${stderrTail}`, { cause: error });
|
|
897
|
+
} finally {
|
|
898
|
+
await this.finalizeProcessLeaseForOperation(input.handle, turnLease);
|
|
714
899
|
}
|
|
715
900
|
}
|
|
716
901
|
startTurn(input) {
|
|
717
902
|
const readCodexTurnFailureStderr = () => this.readCodexTurnFailureStderr({ handle: input.handle });
|
|
718
|
-
const
|
|
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]) => {
|
|
719
909
|
try {
|
|
720
910
|
return {
|
|
721
911
|
command,
|
|
@@ -756,7 +946,7 @@ var AcpxRuntime = class {
|
|
|
756
946
|
throw new AcpRuntimeError("ACP_TURN_FAILED", `Internal error: ${stderrTail}`, { cause: error });
|
|
757
947
|
}
|
|
758
948
|
} },
|
|
759
|
-
result: turnPromise.then(async ({ command, turn }) => {
|
|
949
|
+
result: this.finalizeProcessLeaseAfter(input.handle, turnLeasePromise, turnPromise.then(async ({ command, turn }) => {
|
|
760
950
|
try {
|
|
761
951
|
const result = await turn.result;
|
|
762
952
|
if (result.status !== "failed" || !isCodexAcpCommand(command) || !isGenericInternalAcpErrorMessage(result.error.message)) return result;
|
|
@@ -776,7 +966,7 @@ var AcpxRuntime = class {
|
|
|
776
966
|
if (!stderrTail) throw error;
|
|
777
967
|
throw new AcpRuntimeError("ACP_TURN_FAILED", `Internal error: ${stderrTail}`, { cause: error });
|
|
778
968
|
}
|
|
779
|
-
}),
|
|
969
|
+
})),
|
|
780
970
|
cancel(inputArgs) {
|
|
781
971
|
return turnPromise.then(({ turn }) => turn.cancel(inputArgs));
|
|
782
972
|
},
|
|
@@ -792,9 +982,13 @@ var AcpxRuntime = class {
|
|
|
792
982
|
return (await this.resolveDelegateForHandle(input.handle)).getStatus(input);
|
|
793
983
|
}
|
|
794
984
|
async setMode(input) {
|
|
795
|
-
|
|
985
|
+
const delegate = await this.resolveDelegateForHandle(input.handle);
|
|
986
|
+
await this.runWithProcessLeaseForHandle(input.handle, () => delegate.setMode(input));
|
|
796
987
|
}
|
|
797
988
|
async setConfigOption(input) {
|
|
989
|
+
await this.runWithProcessLeaseForHandle(input.handle, () => this.setConfigOptionUnlocked(input));
|
|
990
|
+
}
|
|
991
|
+
async setConfigOptionUnlocked(input) {
|
|
798
992
|
const delegate = await this.resolveDelegateForHandle(input.handle);
|
|
799
993
|
const command = await this.resolveCommandForHandle(input.handle);
|
|
800
994
|
const key = input.key.trim().toLowerCase();
|
|
@@ -846,21 +1040,29 @@ var AcpxRuntime = class {
|
|
|
846
1040
|
this.sessionStore.markFresh(input.sessionKey);
|
|
847
1041
|
}
|
|
848
1042
|
async close(input) {
|
|
849
|
-
const
|
|
850
|
-
let
|
|
851
|
-
const delegate = this.resolveDelegateForLoadedRecord(input.handle, record);
|
|
1043
|
+
const closeLease = await this.prepareProcessLeaseForOperation(input.handle);
|
|
1044
|
+
let cleanupSucceeded = false;
|
|
852
1045
|
try {
|
|
853
|
-
await
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
1046
|
+
const record = await this.sessionStore.load(input.handle.acpxRecordId ?? input.handle.sessionKey);
|
|
1047
|
+
let closeSucceeded;
|
|
1048
|
+
const delegate = this.resolveDelegateForLoadedRecord(input.handle, record);
|
|
1049
|
+
try {
|
|
1050
|
+
await delegate.close({
|
|
1051
|
+
handle: input.handle,
|
|
1052
|
+
reason: input.reason,
|
|
1053
|
+
discardPersistentState: input.discardPersistentState
|
|
1054
|
+
});
|
|
1055
|
+
closeSucceeded = true;
|
|
1056
|
+
} finally {
|
|
1057
|
+
await this.cleanupProcessTreeForRecord(input.handle, record);
|
|
1058
|
+
cleanupSucceeded = true;
|
|
1059
|
+
}
|
|
1060
|
+
if (closeSucceeded) this.releaseManagedToolsDelegateForSession(input.handle.sessionKey);
|
|
1061
|
+
if (closeSucceeded && input.discardPersistentState) this.sessionStore.markFresh(input.handle.sessionKey);
|
|
859
1062
|
} finally {
|
|
860
|
-
await this.
|
|
1063
|
+
if (cleanupSucceeded) await this.finalizeProcessLeaseForOperation(input.handle, closeLease);
|
|
1064
|
+
else await this.retirePendingProcessLease(closeLease);
|
|
861
1065
|
}
|
|
862
|
-
if (closeSucceeded) this.releaseManagedToolsDelegateForSession(input.handle.sessionKey);
|
|
863
|
-
if (closeSucceeded && input.discardPersistentState) this.sessionStore.markFresh(input.handle.sessionKey);
|
|
864
1066
|
}
|
|
865
1067
|
};
|
|
866
1068
|
/** Test-only hooks for ACPX runtime behavior that is otherwise private. */
|
|
@@ -870,6 +1072,7 @@ const testing = {
|
|
|
870
1072
|
classifyCodexAcpModelRequest,
|
|
871
1073
|
isClaudeAcpCommand,
|
|
872
1074
|
isCodexAcpCommand,
|
|
1075
|
+
normalizeAgentCommand,
|
|
873
1076
|
normalizeClaudeAcpModelOverride
|
|
874
1077
|
};
|
|
875
1078
|
//#endregion
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { n as createLazyAcpRuntimeProxy } from "./register.runtime-
|
|
1
|
+
import { n as createLazyAcpRuntimeProxy } from "./register.runtime-BbS2JTTv.js";
|
|
2
2
|
import "./config-schema-lrk5nlcV.js";
|
|
3
|
-
import { c as openAcpxProcessLeaseStateStore, d as ACPX_GATEWAY_INSTANCE_NAMESPACE,
|
|
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
4
|
import { registerAcpRuntimeBackend, unregisterAcpRuntimeBackend } from "./runtime-api.js";
|
|
5
|
-
import { a as resolveAcpxPluginRoot, c as
|
|
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";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
|
|
8
8
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
@@ -1026,7 +1026,7 @@ async function prepareAcpxCodexAuthConfig(params) {
|
|
|
1026
1026
|
const ENABLE_STARTUP_PROBE_ENV = "OPENCLAW_ACPX_RUNTIME_STARTUP_PROBE";
|
|
1027
1027
|
const SKIP_RUNTIME_PROBE_ENV = "OPENCLAW_SKIP_ACPX_RUNTIME_PROBE";
|
|
1028
1028
|
const ACPX_BACKEND_ID = "acpx";
|
|
1029
|
-
const loadRuntimeModule = createLazyRuntimeModule(() => import("./runtime-
|
|
1029
|
+
const loadRuntimeModule = createLazyRuntimeModule(() => import("./runtime-By_lR8uk.js"));
|
|
1030
1030
|
/** Convert ACPX timeout seconds into timer-safe milliseconds. */
|
|
1031
1031
|
function resolveAcpxTimerTimeoutMs(timeoutSeconds) {
|
|
1032
1032
|
if (timeoutSeconds === void 0) return;
|
|
@@ -1179,7 +1179,7 @@ async function reapOpenAcpxProcessLeases(params) {
|
|
|
1179
1179
|
});
|
|
1180
1180
|
inspectedPids.push(...result.inspectedPids);
|
|
1181
1181
|
terminatedPids.push(...result.terminatedPids);
|
|
1182
|
-
await params.leaseStore.markState(lease.leaseId, result.terminatedPids.length > 0 ? "closed" : "lost");
|
|
1182
|
+
await params.leaseStore.markState(lease.leaseId, result.skippedReason === "process-list-unavailable" ? "open" : result.terminatedPids.length > 0 ? "closed" : "lost");
|
|
1183
1183
|
}
|
|
1184
1184
|
return {
|
|
1185
1185
|
inspectedPids,
|