@openclaw/acpx 2026.10.5-beta.3 → 2026.10.10-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/.setup/{harness-attempt-CRe4WIFt.mjs → harness-attempt-lu4_bMfd.mjs} +2 -2
- package/dist/.setup/{pi-session-catalog-runtime-7jc50ZJ4.mjs → pi-session-catalog-runtime-BAM1pEMw.mjs} +43 -170
- package/dist/.setup/{register.runtime-DfAHoa8o.mjs → register.runtime-CdG6bROH.mjs} +1 -1
- package/dist/.setup/{service-De_oVTL3.mjs → service-5eVJSjDE.mjs} +326 -313
- package/dist/.setup/{session-owner-migration-DECUY80a.mjs → session-owner-migration-duvwZfxk.mjs} +4 -4
- package/dist/doctor-contract-api.js +3 -3
- package/dist/index.js +6 -8
- package/dist/register.runtime.js +1 -2
- package/package.json +6 -6
- package/skills/acp-router/SKILL.md +12 -5
package/README.md
CHANGED
|
@@ -21,10 +21,15 @@ to regenerate wrappers written by an older plugin version.
|
|
|
21
21
|
## What it provides
|
|
22
22
|
|
|
23
23
|
- ACP-backed agent runtime sessions.
|
|
24
|
+
- Built-in ACPX harness targets, including `grok-build` for the Grok Build CLI.
|
|
24
25
|
- Plugin-owned session and transport management.
|
|
25
26
|
- MCP bridge helpers for OpenClaw tools and plugin tools.
|
|
26
27
|
- Static runtime assets used by the ACP process bridge.
|
|
27
28
|
|
|
29
|
+
If the Gateway restarts before a one-shot session receives its first prompt, ACPX
|
|
30
|
+
reuses the initialized conversation when the agent supports loading or resuming
|
|
31
|
+
sessions. Completed one-shot runs still start a fresh conversation.
|
|
32
|
+
|
|
28
33
|
## Native agents in the model picker
|
|
29
34
|
|
|
30
35
|
Install GitHub Copilot CLI, Kilo Code, OpenCode, Pi ACP, or Qwen Code and complete its login on the Gateway host,
|
|
@@ -83,6 +88,10 @@ Use the ACP docs for harness-specific setup, permission modes, and model/runtime
|
|
|
83
88
|
- https://docs.openclaw.ai/tools/acp-agents-setup
|
|
84
89
|
- https://docs.openclaw.ai/tools/acp-agents
|
|
85
90
|
|
|
91
|
+
`grok-build` is an agent target (`agentId: "grok-build"`), not the xAI model id
|
|
92
|
+
`xai/grok-build-0.1`. The target launches the installed Grok Build CLI through
|
|
93
|
+
`grok agent stdio`.
|
|
94
|
+
|
|
86
95
|
## Package
|
|
87
96
|
|
|
88
97
|
- Plugin id: `acpx`
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createNativeSessionBindingAuthority } from "openclaw/plugin-sdk/agent-harness-session-runtime";
|
|
2
1
|
import { randomUUID } from "node:crypto";
|
|
3
2
|
import { consumeAcpTurnStream } from "openclaw/plugin-sdk/acp-runtime";
|
|
4
3
|
import { clearActiveEmbeddedRun, emitAgentEvent, resolveAgentHarnessBeforePromptBuildResult, resolveBootstrapContextForRun, setActiveEmbeddedRun } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
4
|
+
import { createNativeSessionBindingScope } from "openclaw/plugin-sdk/agent-harness-session-runtime";
|
|
5
5
|
import { SessionManager, buildSessionContext } from "openclaw/plugin-sdk/agent-sessions";
|
|
6
6
|
import { DEFAULT_PLUGIN_APPROVAL_TIMEOUT_MS } from "openclaw/plugin-sdk/approval-runtime";
|
|
7
7
|
import { toErrorObject } from "openclaw/plugin-sdk/error-runtime";
|
|
@@ -299,7 +299,7 @@ async function runAcpHarnessAttempt(params) {
|
|
|
299
299
|
...assistant,
|
|
300
300
|
idempotencyKey: assistantItemId
|
|
301
301
|
},
|
|
302
|
-
preparation: { source:
|
|
302
|
+
preparation: { source: createNativeSessionBindingScope(input.hostCapabilities.assertActive).assertLegacyCurrent }
|
|
303
303
|
});
|
|
304
304
|
if (written.kind !== "result") throw new Error("ACP assistant transcript was not committed");
|
|
305
305
|
assistant = written.result.message;
|
|
@@ -4,22 +4,22 @@ import { createReadStream } from "node:fs";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { isRecord, normalizeBoundedOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
6
6
|
import { resolveNodeHostExecutable } from "openclaw/plugin-sdk/node-host";
|
|
7
|
-
import { createSessionCatalogFamily
|
|
7
|
+
import { createSessionCatalogFamily } from "openclaw/plugin-sdk/session-catalog";
|
|
8
8
|
import { resolveAcpSessionAvailability } from "openclaw/plugin-sdk/acp-runtime";
|
|
9
9
|
import process from "node:process";
|
|
10
10
|
import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
11
|
+
import { createAcpSessionCatalogAdoption, readSessionCatalogJsonlActivity } from "openclaw/plugin-sdk/session-catalog-runtime";
|
|
11
12
|
import { sessionCatalogPaging } from "openclaw/plugin-sdk/session-catalog-paging";
|
|
12
13
|
import { safeParseJson, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
13
14
|
import fs$1 from "node:fs/promises";
|
|
14
15
|
import { runTasksWithConcurrency } from "openclaw/plugin-sdk/concurrency-runtime";
|
|
15
|
-
import { isPathStrictlyInside
|
|
16
|
+
import { isPathStrictlyInside } from "openclaw/plugin-sdk/file-access-runtime";
|
|
16
17
|
//#region extensions/acpx/src/pi-session-store.ts
|
|
17
18
|
const MAX_DISCOVERY_FILES = 1e4;
|
|
18
19
|
const SUMMARY_SCAN_BATCH_SIZE = 100;
|
|
19
20
|
const MAX_SUMMARY_CACHE_ENTRIES = 256;
|
|
20
21
|
const MAX_SESSION_BYTES = 33554432;
|
|
21
22
|
const MAX_SUMMARY_LINE_BYTES = 1048576;
|
|
22
|
-
const APPEND_PROOF_EDGE_BYTES = 65536;
|
|
23
23
|
const IO_CONCURRENCY = 8;
|
|
24
24
|
const PI_FILE_CANDIDATE_CACHE_TTL_MS = 32e3;
|
|
25
25
|
const PI_FILE_CANDIDATE_CACHE_MAX_ENTRIES = 8;
|
|
@@ -200,30 +200,6 @@ async function scanSummaryAppend(candidate, start, state) {
|
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
-
async function readAppendProof(file, size) {
|
|
204
|
-
const length = Math.min(size, APPEND_PROOF_EDGE_BYTES);
|
|
205
|
-
if (length === 0) return {
|
|
206
|
-
head: Buffer.alloc(0),
|
|
207
|
-
tail: Buffer.alloc(0)
|
|
208
|
-
};
|
|
209
|
-
const handle = await fs$1.open(file, "r");
|
|
210
|
-
try {
|
|
211
|
-
const head = Buffer.alloc(length);
|
|
212
|
-
const tail = Buffer.alloc(length);
|
|
213
|
-
const [headRead, tailRead] = await Promise.all([handle.read(head, 0, length, 0), handle.read(tail, 0, length, size - length)]);
|
|
214
|
-
return {
|
|
215
|
-
head: head.subarray(0, headRead.bytesRead),
|
|
216
|
-
tail: tail.subarray(0, tailRead.bytesRead)
|
|
217
|
-
};
|
|
218
|
-
} finally {
|
|
219
|
-
await handle.close();
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
async function cachedPrefixIsUnchanged(candidate, cached) {
|
|
223
|
-
if (cached.identity !== candidate.identity || cached.size >= candidate.size) return false;
|
|
224
|
-
const current = await readAppendProof(candidate.file, cached.size);
|
|
225
|
-
return current.head.equals(cached.appendProof.head) && current.tail.equals(cached.appendProof.tail);
|
|
226
|
-
}
|
|
227
203
|
async function readPiSessionSummary(candidate) {
|
|
228
204
|
const cached = summaryCache.get(candidate.file);
|
|
229
205
|
if (cached?.mtimeMs === candidate.mtimeMs && cached.size === candidate.size) {
|
|
@@ -236,9 +212,8 @@ async function readPiSessionSummary(candidate) {
|
|
|
236
212
|
}
|
|
237
213
|
let summary;
|
|
238
214
|
let scanState;
|
|
239
|
-
let appendProof;
|
|
240
215
|
try {
|
|
241
|
-
const resumable = cached &&
|
|
216
|
+
const resumable = cached?.identity === candidate.identity && cached.size < candidate.size ? cached : void 0;
|
|
242
217
|
scanState = resumable ? {
|
|
243
218
|
...resumable.scanState,
|
|
244
219
|
pending: Buffer.from(resumable.scanState.pending)
|
|
@@ -248,7 +223,6 @@ async function readPiSessionSummary(candidate) {
|
|
|
248
223
|
invalid: false
|
|
249
224
|
};
|
|
250
225
|
await scanSummaryAppend(candidate, resumable?.size ?? 0, scanState);
|
|
251
|
-
appendProof = await readAppendProof(candidate.file, candidate.size);
|
|
252
226
|
const projectedState = {
|
|
253
227
|
...scanState,
|
|
254
228
|
pending: Buffer.from(scanState.pending)
|
|
@@ -284,8 +258,7 @@ async function readPiSessionSummary(candidate) {
|
|
|
284
258
|
cacheSummary(candidate.file, {
|
|
285
259
|
...candidate,
|
|
286
260
|
summary,
|
|
287
|
-
scanState
|
|
288
|
-
appendProof
|
|
261
|
+
scanState
|
|
289
262
|
});
|
|
290
263
|
if (summary) threadFileCache.set(threadCacheKey(candidate.storeRoot, summary.threadId), candidate.file);
|
|
291
264
|
return summary;
|
|
@@ -349,24 +322,20 @@ async function readPiSessionFileBaseline(threadId, env) {
|
|
|
349
322
|
}
|
|
350
323
|
async function readPiSessionById(threadId, env) {
|
|
351
324
|
const cacheKey = threadCacheKey(piSessionStore(env).root, threadId);
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
} catch (error) {
|
|
363
|
-
if (error instanceof RangeError) throw error;
|
|
364
|
-
if (attempt > 0) throw new Error("Pi session is unavailable", { cause: error });
|
|
365
|
-
}
|
|
325
|
+
const file = threadFileCache.get(cacheKey) ?? (await findPiSummary(threadId, env))?.file;
|
|
326
|
+
if (!file) throw new Error("Pi session was not found");
|
|
327
|
+
try {
|
|
328
|
+
const stats = await fs$1.stat(file);
|
|
329
|
+
if (!stats.isFile()) throw new Error("Pi session is not a file");
|
|
330
|
+
if (stats.size > MAX_SESSION_BYTES) throw new RangeError("Pi session exceeds the 32 MiB read safety limit");
|
|
331
|
+
const entries = parsePiJsonLines(await fs$1.readFile(file, "utf8"));
|
|
332
|
+
if (entries[0]?.type !== "session" || entries[0].id !== threadId) throw new Error("Pi session changed during read");
|
|
333
|
+
return entries;
|
|
334
|
+
} catch (error) {
|
|
366
335
|
threadFileCache.delete(cacheKey);
|
|
367
|
-
|
|
336
|
+
if (error instanceof RangeError) throw error;
|
|
337
|
+
throw new Error("Pi session is unavailable", { cause: error });
|
|
368
338
|
}
|
|
369
|
-
throw new Error("Pi session changed during read");
|
|
370
339
|
}
|
|
371
340
|
//#endregion
|
|
372
341
|
//#region extensions/acpx/src/pi-session-catalog.ts
|
|
@@ -564,27 +533,6 @@ async function readLocalPiTranscriptPage(value) {
|
|
|
564
533
|
}
|
|
565
534
|
//#endregion
|
|
566
535
|
//#region extensions/acpx/src/pi-session-upstream-activity.ts
|
|
567
|
-
const MAX_PI_UPSTREAM_SCAN_BYTES = 1048576;
|
|
568
|
-
function parseCompletePiRows(tail) {
|
|
569
|
-
const entries = [];
|
|
570
|
-
let lineStart = 0;
|
|
571
|
-
let classifiedBytes = 0;
|
|
572
|
-
for (let index = 0; index < tail.length; index += 1) {
|
|
573
|
-
if (tail[index] !== 10) continue;
|
|
574
|
-
const line = tail.subarray(lineStart, index).toString("utf8").trim();
|
|
575
|
-
if (line) {
|
|
576
|
-
const value = safeParseJson(line);
|
|
577
|
-
if (!isRecord(value)) break;
|
|
578
|
-
entries.push(value);
|
|
579
|
-
}
|
|
580
|
-
classifiedBytes = index + 1;
|
|
581
|
-
lineStart = index + 1;
|
|
582
|
-
}
|
|
583
|
-
return {
|
|
584
|
-
entries,
|
|
585
|
-
classifiedBytes
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
536
|
function readFilePath(probe) {
|
|
589
537
|
return isRecord(probe.upstreamRef) && typeof probe.upstreamRef.filePath === "string" ? probe.upstreamRef.filePath : void 0;
|
|
590
538
|
}
|
|
@@ -611,48 +559,20 @@ async function checkPiSessionUpstreamActivity(probe) {
|
|
|
611
559
|
const filePath = readFilePath(probe);
|
|
612
560
|
const markerOffset = readMarkerOffset(probe);
|
|
613
561
|
if (!filePath || markerOffset === void 0) return;
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
kind: "missing",
|
|
627
|
-
sessionKey: probe.sessionKey
|
|
628
|
-
};
|
|
629
|
-
if (stat.size <= markerOffset) return;
|
|
630
|
-
const readLength = Math.min(stat.size - markerOffset, MAX_PI_UPSTREAM_SCAN_BYTES);
|
|
631
|
-
const { entries, classifiedBytes } = parseCompletePiRows(await readFileRangeAsync(handle, markerOffset, readLength));
|
|
632
|
-
if (classifiedBytes === 0) return;
|
|
633
|
-
let humanTurns = 0;
|
|
634
|
-
let occurredAt;
|
|
635
|
-
for (const entry of entries) {
|
|
636
|
-
if (entry.type !== "message" || !isRecord(entry.message) || entry.message.role !== "user") continue;
|
|
637
|
-
const text = piMessageText(entry.message.content);
|
|
638
|
-
if (!isExternalUserText(probe, text)) continue;
|
|
639
|
-
humanTurns += 1;
|
|
640
|
-
occurredAt = Math.max(occurredAt ?? 0, parseDateFirstTimestampMs(entry.message.timestamp) ?? parseDateFirstTimestampMs(entry.timestamp) ?? stat.mtimeMs);
|
|
562
|
+
return readSessionCatalogJsonlActivity({
|
|
563
|
+
probe,
|
|
564
|
+
filePath,
|
|
565
|
+
offset: markerOffset,
|
|
566
|
+
classifyLine(line) {
|
|
567
|
+
const entry = safeParseJson(line);
|
|
568
|
+
if (!isRecord(entry)) return false;
|
|
569
|
+
if (entry.type !== "message" || !isRecord(entry.message) || entry.message.role !== "user") return;
|
|
570
|
+
return {
|
|
571
|
+
userText: piMessageText(entry.message.content),
|
|
572
|
+
occurredAt: parseDateFirstTimestampMs(entry.message.timestamp) ?? parseDateFirstTimestampMs(entry.timestamp)
|
|
573
|
+
};
|
|
641
574
|
}
|
|
642
|
-
|
|
643
|
-
return {
|
|
644
|
-
kind: "activity",
|
|
645
|
-
sessionKey: probe.sessionKey,
|
|
646
|
-
humanTurns,
|
|
647
|
-
nextMarker: { offset: nextOffset },
|
|
648
|
-
...humanTurns > 0 ? {
|
|
649
|
-
occurredAt: occurredAt ?? stat.mtimeMs,
|
|
650
|
-
dedupeId: String(nextOffset)
|
|
651
|
-
} : {}
|
|
652
|
-
};
|
|
653
|
-
} finally {
|
|
654
|
-
await handle.close();
|
|
655
|
-
}
|
|
575
|
+
});
|
|
656
576
|
}
|
|
657
577
|
async function checkPiUpstreamActivity(probes) {
|
|
658
578
|
const outcomes = [];
|
|
@@ -677,7 +597,7 @@ async function requireLocalPiSession(threadId) {
|
|
|
677
597
|
return session;
|
|
678
598
|
}
|
|
679
599
|
function currentPiCatalogConfig(api) {
|
|
680
|
-
return api.runtime.config
|
|
600
|
+
return api.runtime.config.current();
|
|
681
601
|
}
|
|
682
602
|
function resolvePiContinuationAvailability(api) {
|
|
683
603
|
const availability = resolveAcpSessionAvailability({
|
|
@@ -695,64 +615,20 @@ function resolvePiContinuationAvailability(api) {
|
|
|
695
615
|
message: "Pi CLI is unavailable"
|
|
696
616
|
};
|
|
697
617
|
}
|
|
698
|
-
function listAdoptedPiSessions(api, agentId, sessionEntries) {
|
|
699
|
-
return listAdoptedSessionCatalogSessions({
|
|
700
|
-
...agentId ? { agentId } : {},
|
|
701
|
-
config: currentPiCatalogConfig(api),
|
|
702
|
-
pluginId: api.id,
|
|
703
|
-
runtime: api.runtime,
|
|
704
|
-
sessionEntries,
|
|
705
|
-
sourceFromEntry: (entry) => {
|
|
706
|
-
const acpx = isRecord(entry.pluginExtensions?.acpx) ? entry.pluginExtensions.acpx : void 0;
|
|
707
|
-
const marker = acpx && isRecord(acpx.piSessionCatalog) ? acpx.piSessionCatalog : void 0;
|
|
708
|
-
return marker && typeof marker.sourceThreadId === "string" ? {
|
|
709
|
-
hostId: PI_LOCAL_SESSION_HOST_ID,
|
|
710
|
-
threadId: marker.sourceThreadId
|
|
711
|
-
} : void 0;
|
|
712
|
-
}
|
|
713
|
-
});
|
|
714
|
-
}
|
|
715
|
-
async function createAdoptedPiSession(params) {
|
|
716
|
-
const config = currentPiCatalogConfig(params.api);
|
|
717
|
-
const marker = { sourceThreadId: params.threadId };
|
|
718
|
-
return { sessionKey: (await params.api.runtime.agent.session.createSessionEntry({
|
|
719
|
-
cfg: config,
|
|
720
|
-
key: sessionCatalogAdoptedSessionKey(PI_ADOPTED_SESSION_KEY_PREFIX, params.threadId),
|
|
721
|
-
agentId: params.agentId,
|
|
722
|
-
recoverMatchingInitialEntry: true,
|
|
723
|
-
...params.session.name ? { displayName: params.session.name } : {},
|
|
724
|
-
...params.session.cwd ? { spawnedCwd: params.session.cwd } : {},
|
|
725
|
-
initialEntry: {
|
|
726
|
-
acpBackendId: ACPX_BACKEND_ID,
|
|
727
|
-
acpSessionBinding: {
|
|
728
|
-
acpAgentId: PI_ACP_AGENT_ID,
|
|
729
|
-
agentSessionId: params.threadId
|
|
730
|
-
},
|
|
731
|
-
pluginExtensions: { acpx: { piSessionCatalog: marker } }
|
|
732
|
-
},
|
|
733
|
-
afterCreate: async (entry) => {
|
|
734
|
-
await importSessionCatalogHistory({
|
|
735
|
-
catalogId: "pi",
|
|
736
|
-
threadId: params.threadId,
|
|
737
|
-
read: async ({ cursor, limit }) => await readLocalPiTranscriptPage({
|
|
738
|
-
threadId: params.threadId,
|
|
739
|
-
limit,
|
|
740
|
-
...cursor ? { cursor } : {}
|
|
741
|
-
}),
|
|
742
|
-
sessionId: entry.sessionId,
|
|
743
|
-
sessionKey: entry.key,
|
|
744
|
-
agentId: entry.agentId,
|
|
745
|
-
...params.session.cwd ? { cwd: params.session.cwd } : {},
|
|
746
|
-
config
|
|
747
|
-
});
|
|
748
|
-
return { pluginExtensions: { acpx: { piSessionCatalog: marker } } };
|
|
749
|
-
}
|
|
750
|
-
})).key };
|
|
751
|
-
}
|
|
752
618
|
function assertPiLocalAccess(hostId, allowProcessHomeFallback) {
|
|
753
619
|
if (hostId === "gateway" && allowProcessHomeFallback === false && piSessionStore(process.env).usesProcessHomeFallback) throw new Error("local Pi sessions are unavailable in isolated state");
|
|
754
620
|
}
|
|
755
621
|
function createPiSessionCatalogRuntime(api) {
|
|
622
|
+
const adoption = createAcpSessionCatalogAdoption({
|
|
623
|
+
api,
|
|
624
|
+
config: () => currentPiCatalogConfig(api),
|
|
625
|
+
catalogId: PI_ACP_AGENT_ID,
|
|
626
|
+
hostId: PI_LOCAL_SESSION_HOST_ID,
|
|
627
|
+
keyPrefix: PI_ADOPTED_SESSION_KEY_PREFIX,
|
|
628
|
+
markerPluginId: "acpx",
|
|
629
|
+
markerKey: "piSessionCatalog",
|
|
630
|
+
read: readLocalPiTranscriptPage
|
|
631
|
+
});
|
|
756
632
|
return createSessionCatalogFamily({
|
|
757
633
|
runtime: api.runtime,
|
|
758
634
|
local: {
|
|
@@ -821,15 +697,12 @@ function createPiSessionCatalogRuntime(api) {
|
|
|
821
697
|
agentId
|
|
822
698
|
}).sessionAgentId,
|
|
823
699
|
availability: () => resolvePiContinuationAvailability(api),
|
|
824
|
-
listAdopted: (agentId, sessionEntries) =>
|
|
700
|
+
listAdopted: (agentId, sessionEntries) => adoption.listAdopted(agentId, sessionEntries),
|
|
825
701
|
loadSession: requireLocalPiSession,
|
|
826
702
|
validateSession: (session) => {
|
|
827
703
|
if (!session.canContinue) throw new Error("Pi session is outside the session store supported by pi-acp");
|
|
828
704
|
},
|
|
829
|
-
create:
|
|
830
|
-
api,
|
|
831
|
-
...params
|
|
832
|
-
}),
|
|
705
|
+
create: (params) => adoption.create(params),
|
|
833
706
|
complete: async (continued, threadId) => await linkContinuedPiSession(continued.sessionKey, threadId),
|
|
834
707
|
nodeReadOnlyMessage: "paired-node Pi session rows are view-only"
|
|
835
708
|
},
|
|
@@ -53,7 +53,7 @@ function createLazyAcpRuntimeProxy(resolveRuntime) {
|
|
|
53
53
|
* immediately, then imports the heavier service only when a session needs it.
|
|
54
54
|
*/
|
|
55
55
|
const ACPX_BACKEND_ID = "acpx";
|
|
56
|
-
const loadServiceModule = createLazyRuntimeModule(() => import("./service-
|
|
56
|
+
const loadServiceModule = createLazyRuntimeModule(() => import("./service-5eVJSjDE.mjs"));
|
|
57
57
|
function unregisterOwnedRuntime(runtime) {
|
|
58
58
|
if (runtime && getAcpRuntimeBackend(ACPX_BACKEND_ID)?.runtime === runtime) unregisterAcpRuntimeBackend(ACPX_BACKEND_ID);
|
|
59
59
|
}
|