@moxt-ai/mobius 0.0.30 → 0.0.32
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/acp/activity.d.ts +1 -1
- package/dist/acp/activity.d.ts.map +1 -1
- package/dist/acp/activity.js +8 -6
- package/dist/acp/activity.js.map +1 -1
- package/dist/acp/session-manager.d.ts +2 -0
- package/dist/acp/session-manager.d.ts.map +1 -1
- package/dist/acp/session-manager.js +23 -10
- package/dist/acp/session-manager.js.map +1 -1
- package/dist/agent-catalog/agent-discovery.d.ts.map +1 -1
- package/dist/agent-catalog/agent-discovery.js +4 -0
- package/dist/agent-catalog/agent-discovery.js.map +1 -1
- package/dist/agent-catalog/local-agent.d.ts.map +1 -1
- package/dist/agent-catalog/local-agent.js +1 -0
- package/dist/agent-catalog/local-agent.js.map +1 -1
- package/dist/agent-installation/agent-installation-manager.d.ts.map +1 -1
- package/dist/agent-installation/agent-installation-manager.js +3 -0
- package/dist/agent-installation/agent-installation-manager.js.map +1 -1
- package/dist/authorization/local-raster.d.ts +1 -0
- package/dist/authorization/local-raster.d.ts.map +1 -1
- package/dist/authorization/local-raster.js +17 -0
- package/dist/authorization/local-raster.js.map +1 -1
- package/dist/cli.js +131 -328
- package/dist/cli.js.map +4 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -10
- package/dist/config.js.map +1 -1
- package/dist/index.js +132 -338
- package/dist/index.js.map +4 -4
- package/dist/native-sessions/service.d.ts.map +1 -1
- package/dist/native-sessions/service.js +1 -30
- package/dist/native-sessions/service.js.map +1 -1
- package/dist/relay-connection/session-event-outbox.d.ts +0 -2
- package/dist/relay-connection/session-event-outbox.d.ts.map +1 -1
- package/dist/relay-connection/session-event-outbox.js +6 -12
- package/dist/relay-connection/session-event-outbox.js.map +1 -1
- package/dist/run-daemon.d.ts.map +1 -1
- package/dist/run-daemon.js +47 -5
- package/dist/run-daemon.js.map +1 -1
- package/dist/runtime.js +130 -327
- package/dist/runtime.js.map +4 -4
- package/package.json +1 -1
- package/dist/native-sessions/codex-history.d.ts +0 -11
- package/dist/native-sessions/codex-history.d.ts.map +0 -1
- package/dist/native-sessions/codex-history.js +0 -233
- package/dist/native-sessions/codex-history.js.map +0 -1
package/dist/runtime.js
CHANGED
|
@@ -536,6 +536,7 @@ var InstallableAgentDefinition = class {
|
|
|
536
536
|
};
|
|
537
537
|
var MissingAgentDefinition = class extends InstallableAgentDefinition {
|
|
538
538
|
status = "agent_not_installed";
|
|
539
|
+
// biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
|
|
539
540
|
constructor(id, label) {
|
|
540
541
|
super(id, label);
|
|
541
542
|
}
|
|
@@ -630,6 +631,7 @@ var MissingAdapter = class extends UnavailableInstalledAgent {
|
|
|
630
631
|
code = "adapter_not_found";
|
|
631
632
|
message = "ACP adapter not found";
|
|
632
633
|
status = "missing_adapter";
|
|
634
|
+
// biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
|
|
633
635
|
constructor(specification, agent) {
|
|
634
636
|
super(specification, agent);
|
|
635
637
|
}
|
|
@@ -638,6 +640,7 @@ var MissingAgent = class extends UnavailableAgent {
|
|
|
638
640
|
code = "agent_not_found";
|
|
639
641
|
message = "Agent executable not found";
|
|
640
642
|
status = "missing_agent";
|
|
643
|
+
// biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
|
|
641
644
|
constructor(specification) {
|
|
642
645
|
super(specification);
|
|
643
646
|
}
|
|
@@ -666,6 +669,7 @@ var IncompatibleAdapter = class extends UnavailableInstalledAgent {
|
|
|
666
669
|
code = "acp_incompatible";
|
|
667
670
|
message = "ACP adapter is incompatible";
|
|
668
671
|
status = "incompatible_adapter";
|
|
672
|
+
// biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
|
|
669
673
|
constructor(specification, agent) {
|
|
670
674
|
super(specification, agent);
|
|
671
675
|
}
|
|
@@ -674,6 +678,7 @@ var AuthenticationRequiredAgent = class extends UnavailableInstalledAgent {
|
|
|
674
678
|
code = "authentication_required";
|
|
675
679
|
message = "Agent authentication is required";
|
|
676
680
|
status = "authentication_required";
|
|
681
|
+
// biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
|
|
677
682
|
constructor(specification, agent) {
|
|
678
683
|
super(specification, agent);
|
|
679
684
|
}
|
|
@@ -23117,6 +23122,7 @@ var decodeNativeSessionTurnForkCommand = (encoded) => decode4(nativeSessionTurnF
|
|
|
23117
23122
|
var SESSION_EVENT_KIND = "session.event";
|
|
23118
23123
|
var SESSION_EVENT_ACK_KIND = "session.event.ack";
|
|
23119
23124
|
var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
|
|
23125
|
+
var SESSION_EVENT_DEFERRED_KIND = "session.event.deferred";
|
|
23120
23126
|
var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
|
|
23121
23127
|
var SessionEventRejectionCode = {
|
|
23122
23128
|
SessionDeleted: "session_deleted",
|
|
@@ -23163,6 +23169,12 @@ var eventAcknowledgementSchema = external_exports.strictObject({
|
|
|
23163
23169
|
sequence: external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN),
|
|
23164
23170
|
sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4)
|
|
23165
23171
|
}).readonly();
|
|
23172
|
+
var eventDeferredSchema = external_exports.strictObject({
|
|
23173
|
+
eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
|
|
23174
|
+
kind: external_exports.literal(SESSION_EVENT_DEFERRED_KIND),
|
|
23175
|
+
retryAfterMilliseconds: external_exports.number().int().min(100).max(6e4),
|
|
23176
|
+
sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4)
|
|
23177
|
+
}).readonly();
|
|
23166
23178
|
var eventRejectionSchema = external_exports.strictObject({
|
|
23167
23179
|
code: external_exports.enum(SessionEventRejectionCode),
|
|
23168
23180
|
eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
|
|
@@ -23196,6 +23208,7 @@ var encode4 = (message, schema) => {
|
|
|
23196
23208
|
var decodeSessionEventEnvelope = (encoded) => decode5(encoded, eventEnvelopeSchema);
|
|
23197
23209
|
var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
|
|
23198
23210
|
var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
|
|
23211
|
+
var decodeSessionEventDeferred = (encoded) => decode5(encoded, eventDeferredSchema);
|
|
23199
23212
|
var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSchema);
|
|
23200
23213
|
|
|
23201
23214
|
// src/config.ts
|
|
@@ -23274,6 +23287,23 @@ function sniffRasterMime(bytes) {
|
|
|
23274
23287
|
}
|
|
23275
23288
|
return null;
|
|
23276
23289
|
}
|
|
23290
|
+
function readInlineRaster(data, name = "Image") {
|
|
23291
|
+
if (data.length === 0 || data.length > Math.ceil(MAX_LOCAL_RASTER_BYTES / 3) * 4 || data.length % 4 !== 0) {
|
|
23292
|
+
return null;
|
|
23293
|
+
}
|
|
23294
|
+
if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(data)) {
|
|
23295
|
+
return null;
|
|
23296
|
+
}
|
|
23297
|
+
const bytes = new Uint8Array(Buffer.from(data, "base64"));
|
|
23298
|
+
if (bytes.byteLength < 1 || bytes.byteLength > MAX_LOCAL_RASTER_BYTES) {
|
|
23299
|
+
return null;
|
|
23300
|
+
}
|
|
23301
|
+
const mimeType = sniffRasterMime(bytes);
|
|
23302
|
+
if (mimeType === null) {
|
|
23303
|
+
return null;
|
|
23304
|
+
}
|
|
23305
|
+
return new LocalRasterImage(basename(name) || "Image", mimeType, bytes);
|
|
23306
|
+
}
|
|
23277
23307
|
function isInsideRoot(root, target) {
|
|
23278
23308
|
const relation = relative4(root, target);
|
|
23279
23309
|
return relation !== ".." && !relation.startsWith(`..${sep4}`) && !isAbsolute8(relation);
|
|
@@ -23638,7 +23668,7 @@ function normalizeContentBlock(content) {
|
|
|
23638
23668
|
mimeType: content.mimeType
|
|
23639
23669
|
};
|
|
23640
23670
|
}
|
|
23641
|
-
function normalizeToolContent(content) {
|
|
23671
|
+
async function normalizeToolContent(content, prepareContent) {
|
|
23642
23672
|
const normalized = [];
|
|
23643
23673
|
for (const item of content) {
|
|
23644
23674
|
if (item.type === "diff") {
|
|
@@ -23657,7 +23687,7 @@ function normalizeToolContent(content) {
|
|
|
23657
23687
|
});
|
|
23658
23688
|
continue;
|
|
23659
23689
|
}
|
|
23660
|
-
normalized.push(normalizeContentBlock(item.content));
|
|
23690
|
+
normalized.push(await prepareContent(normalizeContentBlock(item.content)));
|
|
23661
23691
|
}
|
|
23662
23692
|
return normalized;
|
|
23663
23693
|
}
|
|
@@ -23731,10 +23761,12 @@ var AcpActivityTracker = class {
|
|
|
23731
23761
|
#activities = /* @__PURE__ */ new Map();
|
|
23732
23762
|
#identities = /* @__PURE__ */ new Map();
|
|
23733
23763
|
#onActivity;
|
|
23764
|
+
#prepareContent;
|
|
23734
23765
|
#activeNarrativeKey = "";
|
|
23735
23766
|
#nextSequence = 0;
|
|
23736
|
-
constructor(onActivity) {
|
|
23767
|
+
constructor(onActivity, prepareContent = (content) => Promise.resolve(content)) {
|
|
23737
23768
|
this.#onActivity = onActivity;
|
|
23769
|
+
this.#prepareContent = prepareContent;
|
|
23738
23770
|
}
|
|
23739
23771
|
recordNarrative = async (activityType, messageId, text) => {
|
|
23740
23772
|
const key = `${activityType}:${messageId}`;
|
|
@@ -23822,7 +23854,7 @@ var AcpActivityTracker = class {
|
|
|
23822
23854
|
const output2 = update.rawOutput === void 0 ? readContentOutput(update.content) : formatUnknown(update.rawOutput);
|
|
23823
23855
|
const detailInput = update.rawInput === void 0 ? "" : formatUnknownDetail(update.rawInput);
|
|
23824
23856
|
const detailOutput = update.rawOutput === void 0 ? readContentOutputDetail(update.content) : formatUnknownDetail(update.rawOutput);
|
|
23825
|
-
const detailContent = normalizeToolContent(update.content ?? []);
|
|
23857
|
+
const detailContent = await normalizeToolContent(update.content ?? [], this.#prepareContent);
|
|
23826
23858
|
await this.#record(
|
|
23827
23859
|
key,
|
|
23828
23860
|
new AcpActivity(
|
|
@@ -23848,10 +23880,10 @@ var AcpActivityTracker = class {
|
|
|
23848
23880
|
const identity2 = this.#identity(key);
|
|
23849
23881
|
const previousDetail = recordedDetail(previous);
|
|
23850
23882
|
const output2 = update.rawOutput !== void 0 ? formatUnknown(update.rawOutput) : update.content !== void 0 && update.content !== null ? readContentOutput(update.content) : previous?.output ?? "";
|
|
23851
|
-
const content = update.content === void 0 || update.content === null ? previous?.content ?? [] : normalizeToolContent(update.content);
|
|
23883
|
+
const content = update.content === void 0 || update.content === null ? previous?.content ?? [] : await normalizeToolContent(update.content, this.#prepareContent);
|
|
23852
23884
|
const detailInput = update.rawInput === void 0 ? previousDetail?.input ?? previous?.input ?? "" : formatUnknownDetail(update.rawInput);
|
|
23853
23885
|
const detailOutput = update.rawOutput !== void 0 ? formatUnknownDetail(update.rawOutput) : update.content !== void 0 && update.content !== null ? readContentOutputDetail(update.content) : previousDetail?.output ?? previous?.output ?? "";
|
|
23854
|
-
const detailContent = update.content === void 0 || update.content === null ? previousDetail?.content ?? previous?.content ?? [] :
|
|
23886
|
+
const detailContent = update.content === void 0 || update.content === null ? previousDetail?.content ?? previous?.content ?? [] : content;
|
|
23855
23887
|
await this.#record(
|
|
23856
23888
|
key,
|
|
23857
23889
|
new AcpActivity(
|
|
@@ -25017,10 +25049,10 @@ var RunningAcpTurn = class extends AcpTurnState {
|
|
|
25017
25049
|
running = true;
|
|
25018
25050
|
activities;
|
|
25019
25051
|
onText;
|
|
25020
|
-
constructor(commandId, onActivity, onText) {
|
|
25052
|
+
constructor(commandId, onActivity, onText, prepareContent) {
|
|
25021
25053
|
super();
|
|
25022
25054
|
this.commandId = commandId;
|
|
25023
|
-
this.activities = new AcpActivityTracker(onActivity);
|
|
25055
|
+
this.activities = new AcpActivityTracker(onActivity, prepareContent);
|
|
25024
25056
|
this.onText = onText;
|
|
25025
25057
|
}
|
|
25026
25058
|
};
|
|
@@ -25304,18 +25336,27 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
25304
25336
|
await this.#turn.onText(leftover, messageId);
|
|
25305
25337
|
}
|
|
25306
25338
|
};
|
|
25307
|
-
|
|
25339
|
+
prepareAgentContent = async (content) => {
|
|
25340
|
+
if (content.type === "image" && content.data.length > 0) {
|
|
25341
|
+
const raster = readInlineRaster(content.data, content.name);
|
|
25342
|
+
if (raster !== null) {
|
|
25343
|
+
return await this.importRaster(raster, AbortSignal.timeout(2e4));
|
|
25344
|
+
}
|
|
25345
|
+
}
|
|
25308
25346
|
if (content.type === "image" && content.data.length === 0 && content.uri.length > 0) {
|
|
25309
25347
|
const signal = AbortSignal.timeout(2e4);
|
|
25310
25348
|
const raster = await readAuthorizedRaster(content.uri, this.imageRoots(), signal);
|
|
25311
25349
|
if (raster !== null) {
|
|
25312
|
-
await this.
|
|
25313
|
-
return;
|
|
25350
|
+
return await this.importRaster(raster, signal);
|
|
25314
25351
|
}
|
|
25315
25352
|
}
|
|
25353
|
+
return content;
|
|
25354
|
+
};
|
|
25355
|
+
emitAgentContent = async (content, messageId) => {
|
|
25356
|
+
const prepared = await this.prepareAgentContent(content);
|
|
25316
25357
|
await this.#getObserver().onContent({
|
|
25317
25358
|
commandId: this.#turn.commandId,
|
|
25318
|
-
content,
|
|
25359
|
+
content: prepared,
|
|
25319
25360
|
contentId: `content-${crypto.randomUUID()}`,
|
|
25320
25361
|
kind: AGENT_CONTENT_KIND,
|
|
25321
25362
|
messageId,
|
|
@@ -25323,21 +25364,25 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
25323
25364
|
});
|
|
25324
25365
|
};
|
|
25325
25366
|
emitRaster = async (raster, messageId, signal) => {
|
|
25326
|
-
const
|
|
25367
|
+
const content = await this.importRaster(raster, signal);
|
|
25327
25368
|
await this.#getObserver().onContent({
|
|
25328
25369
|
commandId: this.#turn.commandId,
|
|
25329
|
-
content
|
|
25330
|
-
raster.mimeType,
|
|
25331
|
-
raster.name,
|
|
25332
|
-
artifactId.length > 0 ? "" : raster.base64(),
|
|
25333
|
-
artifactId
|
|
25334
|
-
),
|
|
25370
|
+
content,
|
|
25335
25371
|
contentId: `content-${crypto.randomUUID()}`,
|
|
25336
25372
|
kind: AGENT_CONTENT_KIND,
|
|
25337
25373
|
messageId,
|
|
25338
25374
|
sessionId: this.#mobiusSessionId
|
|
25339
25375
|
});
|
|
25340
25376
|
};
|
|
25377
|
+
importRaster = async (raster, signal) => {
|
|
25378
|
+
const artifactId = await this.#getObserver().importLocalImage(this.#mobiusSessionId, raster, signal);
|
|
25379
|
+
return imageDisplayContent(
|
|
25380
|
+
raster.mimeType,
|
|
25381
|
+
raster.name,
|
|
25382
|
+
artifactId.length > 0 ? "" : raster.base64(),
|
|
25383
|
+
artifactId
|
|
25384
|
+
);
|
|
25385
|
+
};
|
|
25341
25386
|
async #initializeAgent(signal) {
|
|
25342
25387
|
const initialized = await this.race(
|
|
25343
25388
|
this.#connection.agent.request(
|
|
@@ -25705,7 +25750,12 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
25705
25750
|
)
|
|
25706
25751
|
);
|
|
25707
25752
|
this.#prompted = true;
|
|
25708
|
-
const running = new RunningAcpTurn(
|
|
25753
|
+
const running = new RunningAcpTurn(
|
|
25754
|
+
options.commandId,
|
|
25755
|
+
options.onActivity,
|
|
25756
|
+
options.onText,
|
|
25757
|
+
this.prepareAgentContent
|
|
25758
|
+
);
|
|
25709
25759
|
this.#turn = running;
|
|
25710
25760
|
try {
|
|
25711
25761
|
const response = await this.race(
|
|
@@ -26957,6 +27007,7 @@ var AgentInstallation = class {
|
|
|
26957
27007
|
};
|
|
26958
27008
|
var RequestedInstallation = class extends AgentInstallation {
|
|
26959
27009
|
status = "requested";
|
|
27010
|
+
// biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
|
|
26960
27011
|
constructor(requestId, agentId) {
|
|
26961
27012
|
super(requestId, agentId);
|
|
26962
27013
|
}
|
|
@@ -26972,6 +27023,7 @@ var RunningInstallation = class extends AgentInstallation {
|
|
|
26972
27023
|
var SucceededInstallation = class extends AgentInstallation {
|
|
26973
27024
|
authenticationMayBeRequired = true;
|
|
26974
27025
|
status = "succeeded";
|
|
27026
|
+
// biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
|
|
26975
27027
|
constructor(requestId, agentId) {
|
|
26976
27028
|
super(requestId, agentId);
|
|
26977
27029
|
}
|
|
@@ -26988,6 +27040,7 @@ var FailedInstallation = class extends AgentInstallation {
|
|
|
26988
27040
|
};
|
|
26989
27041
|
var CancelledInstallation = class extends AgentInstallation {
|
|
26990
27042
|
status = "cancelled";
|
|
27043
|
+
// biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
|
|
26991
27044
|
constructor(requestId, agentId) {
|
|
26992
27045
|
super(requestId, agentId);
|
|
26993
27046
|
}
|
|
@@ -28775,255 +28828,6 @@ var BotOutboundIpcServer = class {
|
|
|
28775
28828
|
// src/native-sessions/service.ts
|
|
28776
28829
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
28777
28830
|
import { basename as basename3 } from "node:path";
|
|
28778
|
-
|
|
28779
|
-
// src/native-sessions/codex-history.ts
|
|
28780
|
-
import { spawn as spawn4 } from "node:child_process";
|
|
28781
|
-
var responseSchema = external_exports.union([
|
|
28782
|
-
external_exports.object({
|
|
28783
|
-
id: external_exports.number(),
|
|
28784
|
-
error: external_exports.object({ code: external_exports.number(), message: external_exports.string() })
|
|
28785
|
-
}),
|
|
28786
|
-
external_exports.object({ id: external_exports.number(), result: external_exports.unknown() }),
|
|
28787
|
-
external_exports.object({ method: external_exports.string() })
|
|
28788
|
-
]);
|
|
28789
|
-
var threadSchema = external_exports.object({
|
|
28790
|
-
thread: external_exports.object({
|
|
28791
|
-
id: nativeSessionIdSchema,
|
|
28792
|
-
cwd: external_exports.string().min(1).max(2048).refine((path2) => !path2.includes("\0"))
|
|
28793
|
-
})
|
|
28794
|
-
});
|
|
28795
|
-
var turnsSchema = external_exports.object({
|
|
28796
|
-
data: external_exports.array(external_exports.object({ items: external_exports.array(external_exports.unknown()).max(1e5) })).max(SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT),
|
|
28797
|
-
nextCursor: external_exports.string().nullish()
|
|
28798
|
-
});
|
|
28799
|
-
var itemTypeSchema = external_exports.object({ type: external_exports.string().min(1).max(80) });
|
|
28800
|
-
var userMessageSchema = external_exports.object({
|
|
28801
|
-
content: external_exports.array(external_exports.unknown()).max(1e4)
|
|
28802
|
-
});
|
|
28803
|
-
var textSchema = external_exports.object({ text: external_exports.string() });
|
|
28804
|
-
var imageSchema = external_exports.object({ url: external_exports.string() });
|
|
28805
|
-
var agentMessageSchema = textSchema.extend({ phase: external_exports.string().nullish() });
|
|
28806
|
-
function decodeHistory(thread, value) {
|
|
28807
|
-
const page = turnsSchema.parse(value);
|
|
28808
|
-
const messages = [];
|
|
28809
|
-
let characters = 0;
|
|
28810
|
-
let truncated = page.nextCursor != null;
|
|
28811
|
-
for (const turn of page.data.toReversed()) {
|
|
28812
|
-
for (const item of turn.items) {
|
|
28813
|
-
const { type } = itemTypeSchema.parse(item);
|
|
28814
|
-
let message;
|
|
28815
|
-
if (type === "userMessage") {
|
|
28816
|
-
const { content } = userMessageSchema.parse(item);
|
|
28817
|
-
const text2 = content.map((block) => {
|
|
28818
|
-
const { type: type2 } = itemTypeSchema.parse(block);
|
|
28819
|
-
if (type2 === "text") {
|
|
28820
|
-
return textSchema.parse(block).text;
|
|
28821
|
-
}
|
|
28822
|
-
if (type2 === "image") {
|
|
28823
|
-
return `[@image](${imageSchema.parse(block).url})`;
|
|
28824
|
-
}
|
|
28825
|
-
return "[Attachment]";
|
|
28826
|
-
}).join("");
|
|
28827
|
-
message = {
|
|
28828
|
-
role: "user",
|
|
28829
|
-
text: text2
|
|
28830
|
-
};
|
|
28831
|
-
} else if (type === "agentMessage") {
|
|
28832
|
-
const agent = agentMessageSchema.parse(item);
|
|
28833
|
-
if (agent.phase === "commentary") {
|
|
28834
|
-
continue;
|
|
28835
|
-
}
|
|
28836
|
-
message = { role: "assistant", text: agent.text };
|
|
28837
|
-
} else {
|
|
28838
|
-
continue;
|
|
28839
|
-
}
|
|
28840
|
-
const text = message.text.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
|
|
28841
|
-
if (text.length === 0 && (message.images?.length ?? 0) === 0) {
|
|
28842
|
-
continue;
|
|
28843
|
-
}
|
|
28844
|
-
truncated ||= text.length < message.text.length;
|
|
28845
|
-
messages.push({ ...message, text });
|
|
28846
|
-
characters += text.length;
|
|
28847
|
-
while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT) {
|
|
28848
|
-
const removed = messages.shift();
|
|
28849
|
-
if (removed !== void 0) {
|
|
28850
|
-
characters -= removed.text.length;
|
|
28851
|
-
}
|
|
28852
|
-
truncated = true;
|
|
28853
|
-
}
|
|
28854
|
-
}
|
|
28855
|
-
}
|
|
28856
|
-
return {
|
|
28857
|
-
nativeSessionId: thread.id,
|
|
28858
|
-
cwd: thread.cwd,
|
|
28859
|
-
history: {
|
|
28860
|
-
status: "available",
|
|
28861
|
-
messages,
|
|
28862
|
-
truncated,
|
|
28863
|
-
coveredCommandIds: [],
|
|
28864
|
-
coveredMessageIds: []
|
|
28865
|
-
}
|
|
28866
|
-
};
|
|
28867
|
-
}
|
|
28868
|
-
async function readCodexHistory(agent, cwd, nativeSessionId, signal) {
|
|
28869
|
-
signal.throwIfAborted();
|
|
28870
|
-
nativeSessionIdSchema.parse(nativeSessionId);
|
|
28871
|
-
if (agent.id !== "codex" || !await revalidateExecutable(agent.agentIdentity)) {
|
|
28872
|
-
throw new AcpExecutionError(
|
|
28873
|
-
"The local Codex executable changed. Restart Mobius to discover it again.",
|
|
28874
|
-
{},
|
|
28875
|
-
"agent_executable_changed"
|
|
28876
|
-
);
|
|
28877
|
-
}
|
|
28878
|
-
signal.throwIfAborted();
|
|
28879
|
-
const child = spawn4(agent.agentIdentity.realPath, ["app-server"], {
|
|
28880
|
-
cwd,
|
|
28881
|
-
env: { ...process.env, ...agent.environment },
|
|
28882
|
-
detached: process.platform !== "win32",
|
|
28883
|
-
shell: false,
|
|
28884
|
-
stdio: ["pipe", "pipe", "ignore"]
|
|
28885
|
-
});
|
|
28886
|
-
const response = Promise.withResolvers();
|
|
28887
|
-
let state = { kind: "initializing", requestId: 1 };
|
|
28888
|
-
let pending = "";
|
|
28889
|
-
let receivedBytes = 0;
|
|
28890
|
-
const fail = (cause) => response.reject(
|
|
28891
|
-
cause instanceof AcpExecutionError ? cause : new AcpExecutionError(
|
|
28892
|
-
"Saved Codex history could not be read.",
|
|
28893
|
-
{ cause },
|
|
28894
|
-
"native_history_unavailable"
|
|
28895
|
-
)
|
|
28896
|
-
);
|
|
28897
|
-
const send2 = (message) => {
|
|
28898
|
-
child.stdin.write(`${JSON.stringify(message)}
|
|
28899
|
-
`);
|
|
28900
|
-
};
|
|
28901
|
-
const onData = (chunk) => {
|
|
28902
|
-
try {
|
|
28903
|
-
receivedBytes += Buffer.byteLength(chunk);
|
|
28904
|
-
if (receivedBytes > 32 * 1024 * 1024) {
|
|
28905
|
-
throw new AcpExecutionError(
|
|
28906
|
-
"This saved conversation is too large to preview.",
|
|
28907
|
-
{},
|
|
28908
|
-
"native_history_too_large"
|
|
28909
|
-
);
|
|
28910
|
-
}
|
|
28911
|
-
pending += chunk;
|
|
28912
|
-
let newline = pending.indexOf("\n");
|
|
28913
|
-
while (newline >= 0) {
|
|
28914
|
-
const line = pending.slice(0, newline);
|
|
28915
|
-
pending = pending.slice(newline + 1);
|
|
28916
|
-
newline = pending.indexOf("\n");
|
|
28917
|
-
if (line.trim().length === 0) {
|
|
28918
|
-
continue;
|
|
28919
|
-
}
|
|
28920
|
-
const value = JSON.parse(line);
|
|
28921
|
-
const message = responseSchema.parse(value);
|
|
28922
|
-
if (!("id" in message)) {
|
|
28923
|
-
continue;
|
|
28924
|
-
}
|
|
28925
|
-
if (message.id !== state.requestId) {
|
|
28926
|
-
throw new AcpExecutionError(
|
|
28927
|
-
"Codex returned an invalid history response.",
|
|
28928
|
-
{},
|
|
28929
|
-
"invalid_native_session_response"
|
|
28930
|
-
);
|
|
28931
|
-
}
|
|
28932
|
-
if ("error" in message) {
|
|
28933
|
-
fail(
|
|
28934
|
-
new AcpExecutionError(
|
|
28935
|
-
"Saved Codex history could not be read.",
|
|
28936
|
-
{ cause: message.error },
|
|
28937
|
-
"native_history_unavailable"
|
|
28938
|
-
)
|
|
28939
|
-
);
|
|
28940
|
-
return;
|
|
28941
|
-
}
|
|
28942
|
-
switch (state.kind) {
|
|
28943
|
-
case "initializing":
|
|
28944
|
-
state = { kind: "metadata", requestId: 2 };
|
|
28945
|
-
send2({ method: "initialized", params: {} });
|
|
28946
|
-
send2({
|
|
28947
|
-
id: state.requestId,
|
|
28948
|
-
method: "thread/read",
|
|
28949
|
-
params: { threadId: nativeSessionId, includeTurns: false }
|
|
28950
|
-
});
|
|
28951
|
-
break;
|
|
28952
|
-
case "metadata": {
|
|
28953
|
-
const { thread } = threadSchema.parse(message.result);
|
|
28954
|
-
state = { kind: "turns", requestId: 3, thread };
|
|
28955
|
-
send2({
|
|
28956
|
-
id: state.requestId,
|
|
28957
|
-
method: "thread/turns/list",
|
|
28958
|
-
params: {
|
|
28959
|
-
threadId: nativeSessionId,
|
|
28960
|
-
limit: SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT,
|
|
28961
|
-
sortDirection: "desc",
|
|
28962
|
-
itemsView: "summary"
|
|
28963
|
-
}
|
|
28964
|
-
});
|
|
28965
|
-
break;
|
|
28966
|
-
}
|
|
28967
|
-
case "turns":
|
|
28968
|
-
response.resolve(decodeHistory(state.thread, message.result));
|
|
28969
|
-
return;
|
|
28970
|
-
default: {
|
|
28971
|
-
const unhandled = state;
|
|
28972
|
-
throw new Error(`Unknown history read state: ${String(unhandled)}`);
|
|
28973
|
-
}
|
|
28974
|
-
}
|
|
28975
|
-
}
|
|
28976
|
-
} catch (cause) {
|
|
28977
|
-
fail(cause);
|
|
28978
|
-
}
|
|
28979
|
-
};
|
|
28980
|
-
const abort = () => response.reject(signal.reason);
|
|
28981
|
-
const onExit = () => fail(
|
|
28982
|
-
new AcpExecutionError(
|
|
28983
|
-
"Codex stopped before its saved history was available.",
|
|
28984
|
-
{},
|
|
28985
|
-
"native_history_unavailable"
|
|
28986
|
-
)
|
|
28987
|
-
);
|
|
28988
|
-
const timeout = setTimeout(
|
|
28989
|
-
() => fail(new AcpExecutionError("Reading saved Codex history timed out.", {}, "native_history_timeout")),
|
|
28990
|
-
15e3
|
|
28991
|
-
);
|
|
28992
|
-
child.stdout.setEncoding("utf8");
|
|
28993
|
-
child.stdout.on("data", onData);
|
|
28994
|
-
child.stdin.on("error", fail);
|
|
28995
|
-
child.on("error", fail);
|
|
28996
|
-
child.on("exit", onExit);
|
|
28997
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
28998
|
-
try {
|
|
28999
|
-
if (signal.aborted) {
|
|
29000
|
-
abort();
|
|
29001
|
-
} else {
|
|
29002
|
-
send2({
|
|
29003
|
-
id: 1,
|
|
29004
|
-
method: "initialize",
|
|
29005
|
-
params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
|
|
29006
|
-
});
|
|
29007
|
-
}
|
|
29008
|
-
const snapshot = await response.promise;
|
|
29009
|
-
return {
|
|
29010
|
-
...snapshot,
|
|
29011
|
-
history: await embedLocalHistoryImages(snapshot.history, [cwd, snapshot.cwd], signal)
|
|
29012
|
-
};
|
|
29013
|
-
} finally {
|
|
29014
|
-
clearTimeout(timeout);
|
|
29015
|
-
signal.removeEventListener("abort", abort);
|
|
29016
|
-
child.stdout.removeListener("data", onData);
|
|
29017
|
-
if (child.pid !== void 0) {
|
|
29018
|
-
await stopProcessTree(child);
|
|
29019
|
-
}
|
|
29020
|
-
child.stdin.removeListener("error", fail);
|
|
29021
|
-
child.removeListener("error", fail);
|
|
29022
|
-
child.removeListener("exit", onExit);
|
|
29023
|
-
}
|
|
29024
|
-
}
|
|
29025
|
-
|
|
29026
|
-
// src/native-sessions/service.ts
|
|
29027
28831
|
var NativeSessionService = class {
|
|
29028
28832
|
#entries = /* @__PURE__ */ new Map();
|
|
29029
28833
|
#cursors = /* @__PURE__ */ new Map();
|
|
@@ -29186,7 +28990,7 @@ var NativeSessionService = class {
|
|
|
29186
28990
|
"native_session_unsupported"
|
|
29187
28991
|
);
|
|
29188
28992
|
}
|
|
29189
|
-
const
|
|
28993
|
+
const opened = await this.#sessions.openNativeSession(
|
|
29190
28994
|
{
|
|
29191
28995
|
...options,
|
|
29192
28996
|
cwd: target.cwd,
|
|
@@ -29195,35 +28999,6 @@ var NativeSessionService = class {
|
|
|
29195
28999
|
},
|
|
29196
29000
|
{ kind: command.action, nativeSessionId: target.info.sessionId }
|
|
29197
29001
|
);
|
|
29198
|
-
const opened = await opening.catch(async (cause) => {
|
|
29199
|
-
signal.throwIfAborted();
|
|
29200
|
-
if (command.action !== "import" || options.agent.id !== "codex" || !(cause instanceof AcpExecutionError) || cause.code !== "acp_execution_failed") {
|
|
29201
|
-
throw cause;
|
|
29202
|
-
}
|
|
29203
|
-
const snapshot = await readCodexHistory(options.agent, target.cwd, target.info.sessionId, signal);
|
|
29204
|
-
const resolved = await this.#directories.identify(command.bindingId, snapshot.cwd, signal);
|
|
29205
|
-
if (snapshot.nativeSessionId !== target.info.sessionId || resolved.path !== target.cwd) {
|
|
29206
|
-
throw new AcpExecutionError(
|
|
29207
|
-
"Codex returned history for a different session or workspace.",
|
|
29208
|
-
{ cause },
|
|
29209
|
-
"invalid_native_session_response"
|
|
29210
|
-
);
|
|
29211
|
-
}
|
|
29212
|
-
signal.throwIfAborted();
|
|
29213
|
-
this.record(command, "native_session_previewed");
|
|
29214
|
-
return { kind: "preview", history: snapshot.history };
|
|
29215
|
-
});
|
|
29216
|
-
if ("kind" in opened) {
|
|
29217
|
-
return {
|
|
29218
|
-
...envelope2,
|
|
29219
|
-
action: "preview",
|
|
29220
|
-
entryId: command.entryId,
|
|
29221
|
-
reason: "continuation_unavailable",
|
|
29222
|
-
targetSessionId: command.targetSessionId,
|
|
29223
|
-
title: target.info.title ?? "Untitled session",
|
|
29224
|
-
history: opened.history
|
|
29225
|
-
};
|
|
29226
|
-
}
|
|
29227
29002
|
signal.throwIfAborted();
|
|
29228
29003
|
const ready = {
|
|
29229
29004
|
additionalDirectories: target.additionalEntries,
|
|
@@ -29959,11 +29734,9 @@ import { dirname as dirname7 } from "node:path";
|
|
|
29959
29734
|
import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
|
|
29960
29735
|
var DEFAULT_OUTBOX_LIMITS = {
|
|
29961
29736
|
criticalEventBytes: 136 * 1024 * 1024,
|
|
29962
|
-
criticalEventCount: 10128,
|
|
29963
29737
|
runtimeDeliveryBytes: 64 * 1024 * 1024,
|
|
29964
29738
|
runtimeDeliveryCount: 64,
|
|
29965
|
-
standardEventBytes: 128 * 1024 * 1024
|
|
29966
|
-
standardEventCount: 1e4
|
|
29739
|
+
standardEventBytes: 128 * 1024 * 1024
|
|
29967
29740
|
};
|
|
29968
29741
|
var SessionEventOutboxCapacityError = class extends Error {
|
|
29969
29742
|
code = "session_event_outbox_full";
|
|
@@ -30246,21 +30019,9 @@ var SessionEventOutbox = class {
|
|
|
30246
30019
|
this.#database.close();
|
|
30247
30020
|
};
|
|
30248
30021
|
enqueue = (sessionId, payload, attemptId = null) => {
|
|
30249
|
-
return this.#enqueueBounded(
|
|
30250
|
-
sessionId,
|
|
30251
|
-
payload,
|
|
30252
|
-
attemptId ?? "",
|
|
30253
|
-
this.#limits.standardEventCount,
|
|
30254
|
-
this.#limits.standardEventBytes
|
|
30255
|
-
);
|
|
30022
|
+
return this.#enqueueBounded(sessionId, payload, attemptId ?? "", this.#limits.standardEventBytes);
|
|
30256
30023
|
};
|
|
30257
|
-
enqueueCritical = (sessionId, payload, attemptId = "") => this.#enqueueBounded(
|
|
30258
|
-
sessionId,
|
|
30259
|
-
payload,
|
|
30260
|
-
attemptId,
|
|
30261
|
-
this.#limits.criticalEventCount,
|
|
30262
|
-
this.#limits.criticalEventBytes
|
|
30263
|
-
);
|
|
30024
|
+
enqueueCritical = (sessionId, payload, attemptId = "") => this.#enqueueBounded(sessionId, payload, attemptId, this.#limits.criticalEventBytes);
|
|
30264
30025
|
claimRuntimeDelivery = (delivery) => {
|
|
30265
30026
|
const payloadBytes = new TextEncoder().encode(delivery.payload).byteLength;
|
|
30266
30027
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
@@ -30367,7 +30128,7 @@ var SessionEventOutbox = class {
|
|
|
30367
30128
|
true
|
|
30368
30129
|
)
|
|
30369
30130
|
);
|
|
30370
|
-
#enqueueBounded = (sessionId, payload, attemptId,
|
|
30131
|
+
#enqueueBounded = (sessionId, payload, attemptId, maximumEventBytes) => {
|
|
30371
30132
|
const sourceKey = attemptId.length === 0 ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
|
|
30372
30133
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
30373
30134
|
try {
|
|
@@ -30394,11 +30155,11 @@ var SessionEventOutbox = class {
|
|
|
30394
30155
|
const encoded = encodeSessionEventEnvelope(envelope2);
|
|
30395
30156
|
const byteLength = new TextEncoder().encode(encoded).byteLength;
|
|
30396
30157
|
const state = this.#database.prepare(
|
|
30397
|
-
`SELECT
|
|
30158
|
+
`SELECT total_bytes
|
|
30398
30159
|
FROM relay_session_event_outbox_state
|
|
30399
30160
|
WHERE singleton = 1`
|
|
30400
30161
|
).get();
|
|
30401
|
-
if (rowNumber(state, "
|
|
30162
|
+
if (rowNumber(state, "total_bytes") + byteLength > maximumEventBytes) {
|
|
30402
30163
|
throw new SessionEventOutboxCapacityError();
|
|
30403
30164
|
}
|
|
30404
30165
|
this.#database.prepare(
|
|
@@ -30532,16 +30293,14 @@ var SessionEventOutbox = class {
|
|
|
30532
30293
|
function validateLimits(limits) {
|
|
30533
30294
|
const values = [
|
|
30534
30295
|
limits.criticalEventBytes,
|
|
30535
|
-
limits.criticalEventCount,
|
|
30536
30296
|
limits.runtimeDeliveryBytes,
|
|
30537
30297
|
limits.runtimeDeliveryCount,
|
|
30538
|
-
limits.standardEventBytes
|
|
30539
|
-
limits.standardEventCount
|
|
30298
|
+
limits.standardEventBytes
|
|
30540
30299
|
];
|
|
30541
30300
|
if (values.some((value) => !Number.isSafeInteger(value) || value < 1)) {
|
|
30542
30301
|
throw new Error("Session event outbox limits must be positive integers");
|
|
30543
30302
|
}
|
|
30544
|
-
if (limits.criticalEventBytes < limits.standardEventBytes
|
|
30303
|
+
if (limits.criticalEventBytes < limits.standardEventBytes) {
|
|
30545
30304
|
throw new Error("Critical Session event capacity must include the standard capacity");
|
|
30546
30305
|
}
|
|
30547
30306
|
}
|
|
@@ -30891,10 +30650,13 @@ function sessionEventSourceKey(envelope2) {
|
|
|
30891
30650
|
var DaemonSessionEventPublisher = class {
|
|
30892
30651
|
#outbox;
|
|
30893
30652
|
#inFlightEvents = /* @__PURE__ */ new Map();
|
|
30653
|
+
#pausedSources = /* @__PURE__ */ new Map();
|
|
30654
|
+
#timer;
|
|
30894
30655
|
#inFlightBytes = 0;
|
|
30895
30656
|
#connection = new DisconnectedDaemonSessionEventState();
|
|
30896
|
-
constructor(outbox) {
|
|
30657
|
+
constructor(outbox, timer) {
|
|
30897
30658
|
this.#outbox = outbox;
|
|
30659
|
+
this.#timer = timer;
|
|
30898
30660
|
}
|
|
30899
30661
|
connect = (socket) => {
|
|
30900
30662
|
this.#connection = new ConnectedDaemonSessionEventState(socket);
|
|
@@ -30937,6 +30699,30 @@ var DaemonSessionEventPublisher = class {
|
|
|
30937
30699
|
this.#publishNextBatch();
|
|
30938
30700
|
return true;
|
|
30939
30701
|
};
|
|
30702
|
+
defer = (deferred) => {
|
|
30703
|
+
const inFlight = this.#inFlightEvents.get(deferred.eventId);
|
|
30704
|
+
if (inFlight === void 0) {
|
|
30705
|
+
return;
|
|
30706
|
+
}
|
|
30707
|
+
this.#clearInFlightSource(inFlight.sourceKey);
|
|
30708
|
+
if (!this.#pausedSources.has(inFlight.sourceKey)) {
|
|
30709
|
+
this.#pausedSources.set(
|
|
30710
|
+
inFlight.sourceKey,
|
|
30711
|
+
this.#timer.schedule(() => {
|
|
30712
|
+
this.#pausedSources.delete(inFlight.sourceKey);
|
|
30713
|
+
this.#publishNextBatch();
|
|
30714
|
+
}, deferred.retryAfterMilliseconds)
|
|
30715
|
+
);
|
|
30716
|
+
}
|
|
30717
|
+
this.#publishNextBatch();
|
|
30718
|
+
};
|
|
30719
|
+
close = () => {
|
|
30720
|
+
for (const task of this.#pausedSources.values()) {
|
|
30721
|
+
task.cancel();
|
|
30722
|
+
}
|
|
30723
|
+
this.#pausedSources.clear();
|
|
30724
|
+
this.#clearInFlight();
|
|
30725
|
+
};
|
|
30940
30726
|
#publishNextBatch = () => {
|
|
30941
30727
|
while (this.#inFlightEvents.size < SESSION_EVENT_REPLAY_WINDOW) {
|
|
30942
30728
|
const sourceCounts = /* @__PURE__ */ new Map();
|
|
@@ -30947,7 +30733,7 @@ var DaemonSessionEventPublisher = class {
|
|
|
30947
30733
|
const batch = this.#outbox.pendingSourceHeads(
|
|
30948
30734
|
SESSION_EVENT_REPLAY_WINDOW - this.#inFlightEvents.size,
|
|
30949
30735
|
[...this.#inFlightEvents.keys()],
|
|
30950
|
-
saturatedSources
|
|
30736
|
+
[...this.#pausedSources.keys(), ...saturatedSources]
|
|
30951
30737
|
);
|
|
30952
30738
|
let sent = 0;
|
|
30953
30739
|
for (const encoded of batch) {
|
|
@@ -30987,6 +30773,15 @@ var DaemonSessionEventPublisher = class {
|
|
|
30987
30773
|
this.#inFlightEvents.clear();
|
|
30988
30774
|
this.#inFlightBytes = 0;
|
|
30989
30775
|
};
|
|
30776
|
+
#clearInFlightSource = (sourceKey) => {
|
|
30777
|
+
for (const [eventId, inFlight] of this.#inFlightEvents) {
|
|
30778
|
+
if (inFlight.sourceKey !== sourceKey) {
|
|
30779
|
+
continue;
|
|
30780
|
+
}
|
|
30781
|
+
this.#inFlightEvents.delete(eventId);
|
|
30782
|
+
this.#inFlightBytes -= inFlight.byteLength;
|
|
30783
|
+
}
|
|
30784
|
+
};
|
|
30990
30785
|
};
|
|
30991
30786
|
var CoalescingDaemonActivityPublisher = class {
|
|
30992
30787
|
#pending = /* @__PURE__ */ new Map();
|
|
@@ -31921,6 +31716,10 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31921
31716
|
publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
|
|
31922
31717
|
return;
|
|
31923
31718
|
}
|
|
31719
|
+
if (kind === SESSION_EVENT_DEFERRED_KIND) {
|
|
31720
|
+
publisher.defer(decodeSessionEventDeferred(encoded));
|
|
31721
|
+
return;
|
|
31722
|
+
}
|
|
31924
31723
|
if (kind === SESSION_EVENT_REJECTED_KIND) {
|
|
31925
31724
|
const rejection = decodeSessionEventRejection(encoded);
|
|
31926
31725
|
if (publisher.quarantine(rejection)) {
|
|
@@ -32414,7 +32213,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
32414
32213
|
});
|
|
32415
32214
|
const sessionStore = new SqliteAcpSessionStore(config2.auditDatabasePath);
|
|
32416
32215
|
const outbox = new SessionEventOutbox(config2.auditDatabasePath);
|
|
32417
|
-
const publisher = new DaemonSessionEventPublisher(outbox);
|
|
32216
|
+
const publisher = new DaemonSessionEventPublisher(outbox, timer);
|
|
32418
32217
|
const grants = new LocalBotGrantStore(config2.auditDatabasePath);
|
|
32419
32218
|
const contexts = new BotExecutionContextRegistry();
|
|
32420
32219
|
const applicator = new EmbeddedBotContextApplicator();
|
|
@@ -32516,7 +32315,11 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
32516
32315
|
try {
|
|
32517
32316
|
grants.close();
|
|
32518
32317
|
} finally {
|
|
32519
|
-
|
|
32318
|
+
try {
|
|
32319
|
+
publisher.close();
|
|
32320
|
+
} finally {
|
|
32321
|
+
outbox.close();
|
|
32322
|
+
}
|
|
32520
32323
|
}
|
|
32521
32324
|
}
|
|
32522
32325
|
}
|