@canonmsg/agent-sdk 12.6.1 → 13.0.2
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 +23 -21
- package/dist/chunks/{chunk-S7BV74DN.js → chunk-5WPAB5MB.js} +293 -8
- package/dist/chunks/{chunk-DAJ7L7TN.js → chunk-DNHJGAEL.js} +378 -663
- package/dist/chunks/{chunk-HH7KR22P.js → chunk-DTAWEQCM.js} +2 -2
- package/dist/chunks/{chunk-5J4YPLNW.js → chunk-TYZT346O.js} +266 -1217
- package/dist/chunks/{chunk-QK37HAHC.js → chunk-YHDDOADK.js} +1 -1
- package/dist/chunks/{chunk-FVYKLH6I.js → chunk-YJUPKU47.js} +20 -5
- package/dist/chunks/{mls-crypto-4DZT2UFH.js → mls-crypto-NZVMSUFU.js} +2 -2
- package/dist/cli.js +32 -36
- package/dist/drivers/subprocess.d.ts +4 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -6
- package/dist/internal/backend-contracts/mlsDevGroup.d.ts +17 -0
- package/dist/internal/core/completed-output-journal.d.ts +0 -5
- package/dist/internal/core/index.d.ts +3 -9
- package/dist/internal/core/retry.d.ts +2 -89
- package/dist/internal/core/silent-turn.d.ts +4 -33
- package/dist/internal/endpoint/engine.d.ts +3 -0
- package/dist/internal/endpoint/mls-dev-groups.d.ts +12 -0
- package/dist/internal/endpoint/mls-dev-text.d.ts +29 -0
- package/dist/internal/endpoint/transport.d.ts +1 -1
- package/dist/media.js +4 -4
- package/dist/mls-wasm-host.js +3 -3
- package/dist/runner/mls.d.ts +4 -7
- package/dist/runner/runner.d.ts +9 -12
- package/dist/runner/types.d.ts +31 -0
- package/package.json +1 -1
- package/dist/internal/core/approval-manager.d.ts +0 -43
- package/dist/internal/core/runtime-request-manager.d.ts +0 -283
- package/dist/internal/core/turn-verbosity.d.ts +0 -79
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
createHttpEndpointTransport,
|
|
6
6
|
createNodeEndpointStore,
|
|
7
7
|
validateEndpointContentBoundary
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-YJUPKU47.js";
|
|
9
9
|
import {
|
|
10
10
|
CANON_ENDPOINT_PROTOCOL,
|
|
11
11
|
CANON_VERB_WIRE_SCHEMA_VERSION,
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
isMlsPrincipalAlias,
|
|
43
43
|
logicalMediaBlobId,
|
|
44
44
|
mergeDeliveryObservation,
|
|
45
|
+
mlsAdmissionWait,
|
|
45
46
|
mlsDevProtocolCarriesCards,
|
|
46
47
|
normalizePublicRuntimeDescriptor,
|
|
47
48
|
normalizePublicRuntimeFacts,
|
|
@@ -106,11 +107,11 @@ import {
|
|
|
106
107
|
readMembershipChangeMetadata,
|
|
107
108
|
resolveAllowedUploadMimeType,
|
|
108
109
|
sanitizeDownloadFileName
|
|
109
|
-
} from "./chunk-
|
|
110
|
+
} from "./chunk-5WPAB5MB.js";
|
|
110
111
|
|
|
111
112
|
// src/media.ts
|
|
112
113
|
import { createWriteStream as createWriteStream2 } from "node:fs";
|
|
113
|
-
import { randomUUID as
|
|
114
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
114
115
|
import { mkdir as mkdir2, open as open2, rename as rename2, stat as stat2, unlink as unlink2 } from "node:fs/promises";
|
|
115
116
|
import { basename, dirname as dirname2, extname, join as join5 } from "node:path";
|
|
116
117
|
import { Readable, Transform as Transform2 } from "node:stream";
|
|
@@ -4904,6 +4905,38 @@ async function isMlsDevOwnAnswerSending(tx, conversationId, agentId, requestId)
|
|
|
4904
4905
|
return !!authored && authored.feedOrdinal === null && (authored.status === "queued" || authored.status === "uncertain");
|
|
4905
4906
|
}
|
|
4906
4907
|
__name(isMlsDevOwnAnswerSending, "isMlsDevOwnAnswerSending");
|
|
4908
|
+
var mlsDevHeldTextPrefix = /* @__PURE__ */ __name((conversationId) => `mls-dev-group/held-text/${conversationId === void 0 ? "" : `${encoded2(conversationId)}/`}`, "mlsDevHeldTextPrefix");
|
|
4909
|
+
var mlsDevHeldTextKey = /* @__PURE__ */ __name((conversationId, messageId) => `${mlsDevHeldTextPrefix(conversationId)}${encoded2(messageId)}`, "mlsDevHeldTextKey");
|
|
4910
|
+
async function readMlsDevHeldTexts(tx, conversationId) {
|
|
4911
|
+
const rows = await tx.scan(mlsDevHeldTextPrefix(conversationId), { limit: MLS_DEV_HELD_TEXT_MAX });
|
|
4912
|
+
return rows.map((row) => row.value).sort((a, b) => a.sequence - b.sequence);
|
|
4913
|
+
}
|
|
4914
|
+
__name(readMlsDevHeldTexts, "readMlsDevHeldTexts");
|
|
4915
|
+
var MLS_DEV_HELD_TEXT_MAX = 100;
|
|
4916
|
+
async function projectMlsDevHeldText(tx, value, account) {
|
|
4917
|
+
const { body } = value;
|
|
4918
|
+
const quote = body.replyTo ? mlsDevReplyQuote(
|
|
4919
|
+
await tx.get(mlsDevTextMessageKey(body.conversationId, body.replyTo)),
|
|
4920
|
+
MLS_DEV_REPLY_QUOTE_MAX_CHARACTERS
|
|
4921
|
+
) : void 0;
|
|
4922
|
+
return {
|
|
4923
|
+
id: body.messageId,
|
|
4924
|
+
conversationId: body.conversationId,
|
|
4925
|
+
senderId: account({ type: value.senderType, id: value.senderId }),
|
|
4926
|
+
senderType: value.senderType,
|
|
4927
|
+
contentType: "text",
|
|
4928
|
+
text: body.text,
|
|
4929
|
+
mentions: body.mentions ?? [],
|
|
4930
|
+
attachments: [],
|
|
4931
|
+
replyTo: body.replyTo ?? null,
|
|
4932
|
+
...quote ? { replyQuote: quote } : {},
|
|
4933
|
+
status: value.failed ? "failed" : "sending",
|
|
4934
|
+
deleted: false,
|
|
4935
|
+
createdAt: new Date(value.createdAtMs).toISOString(),
|
|
4936
|
+
mlsFeedOrdinal: null
|
|
4937
|
+
};
|
|
4938
|
+
}
|
|
4939
|
+
__name(projectMlsDevHeldText, "projectMlsDevHeldText");
|
|
4907
4940
|
var mlsDevTextDeletedKey = /* @__PURE__ */ __name((conversationId, messageId) => `mls-dev-group/message-deleted/${encoded2(conversationId)}/${encoded2(messageId)}`, "mlsDevTextDeletedKey");
|
|
4908
4941
|
var mlsDevTextReactionsKey = /* @__PURE__ */ __name((conversationId, messageId) => `mls-dev-group/message-reactions/${encoded2(conversationId)}/${encoded2(messageId)}`, "mlsDevTextReactionsKey");
|
|
4909
4942
|
var erased = /* @__PURE__ */ __name((value) => {
|
|
@@ -5036,7 +5069,8 @@ async function queryMlsDevTextHistory(tx, conversationId, name, parameters, audi
|
|
|
5036
5069
|
const messages2 = [], missingMessageIds = [];
|
|
5037
5070
|
for (const id2 of parameters.messageIds) {
|
|
5038
5071
|
const value = await tx.get(mlsDevTextMessageKey(conversationId, id2));
|
|
5039
|
-
const
|
|
5072
|
+
const held = value ? void 0 : await tx.get(mlsDevHeldTextKey(conversationId, id2));
|
|
5073
|
+
const projected = value ? await projectLocal(tx, value, audience) : held && await projectMlsDevHeldText(tx, held, audience.account);
|
|
5040
5074
|
if (projected) messages2.push(projected);
|
|
5041
5075
|
else missingMessageIds.push(id2);
|
|
5042
5076
|
}
|
|
@@ -5060,10 +5094,15 @@ async function queryMlsDevTextHistory(tx, conversationId, name, parameters, audi
|
|
|
5060
5094
|
return { ...row.value, ordinal: position };
|
|
5061
5095
|
});
|
|
5062
5096
|
const messages = [];
|
|
5063
|
-
if (parameters.before === void 0)
|
|
5064
|
-
const
|
|
5065
|
-
|
|
5066
|
-
|
|
5097
|
+
if (parameters.before === void 0) {
|
|
5098
|
+
for (const held of (await readMlsDevHeldTexts(tx, conversationId)).reverse()) {
|
|
5099
|
+
if (await tx.get(mlsDevTextMessageKey(conversationId, held.body.messageId)) === void 0) messages.push(await projectMlsDevHeldText(tx, held, audience.account));
|
|
5100
|
+
}
|
|
5101
|
+
for (const row of await tx.scan(pendingPrefix(conversationId), { limit: 100 })) {
|
|
5102
|
+
const value = await tx.get(mlsDevTextMessageKey(conversationId, row.value.messageId));
|
|
5103
|
+
const projected = value && await projectLocal(tx, value, audience);
|
|
5104
|
+
if (projected) messages.push(projected);
|
|
5105
|
+
}
|
|
5067
5106
|
}
|
|
5068
5107
|
for (const item of selected) {
|
|
5069
5108
|
const value = await tx.get(mlsDevTextMessageKey(conversationId, item.messageId));
|
|
@@ -5166,6 +5205,7 @@ var recoveryFailureKey = /* @__PURE__ */ __name((id2) => `mls-dev-group/recovery
|
|
|
5166
5205
|
var authorityKey = /* @__PURE__ */ __name((id2) => `mls-dev-group/authority/${encodeURIComponent(id2)}`, "authorityKey");
|
|
5167
5206
|
var acceptedKey = /* @__PURE__ */ __name((id2, sequence) => `mls-dev-group/accepted/${encodeURIComponent(id2)}/${sequence}`, "acceptedKey");
|
|
5168
5207
|
var feedKey = /* @__PURE__ */ __name((id2) => `mls-dev-group/feed/${encodeURIComponent(id2)}`, "feedKey");
|
|
5208
|
+
var missedEarlierKey = /* @__PURE__ */ __name((id2) => `mls-dev-group/missed-earlier/${encodeURIComponent(id2)}`, "missedEarlierKey");
|
|
5169
5209
|
var feedEntryKey = /* @__PURE__ */ __name((id2, ordinal3) => `mls-dev-group/feed-entry/${encodeURIComponent(id2)}/${ordinal3}`, "feedEntryKey");
|
|
5170
5210
|
var appIntentKey = /* @__PURE__ */ __name((operationId) => `mls-dev-group/application/${encodeURIComponent(operationId)}`, "appIntentKey");
|
|
5171
5211
|
var appOperationKey = /* @__PURE__ */ __name((deviceId, operationId) => `mls-dev-group/application-operation/${encodeURIComponent(deviceId)}/${encodeURIComponent(operationId)}`, "appOperationKey");
|
|
@@ -5840,6 +5880,8 @@ function createMlsDevGroups(options, context, keyPackages, bridge) {
|
|
|
5840
5880
|
observedSequence: current.envelope?.head?.sequence ?? 0
|
|
5841
5881
|
});
|
|
5842
5882
|
await rememberMlsDevRoomMode(tx, cid, response.marker);
|
|
5883
|
+
if (initialWelcome && captured.feedOrdinal === 0 && first.kind === "control" && first.ordinal > first.accepted.head.sequence)
|
|
5884
|
+
await tx.put(missedEarlierKey(cid), true);
|
|
5843
5885
|
});
|
|
5844
5886
|
for (const entry of response.entries) {
|
|
5845
5887
|
if (entry.kind === "control") {
|
|
@@ -5897,17 +5939,35 @@ function createMlsDevGroups(options, context, keyPackages, bridge) {
|
|
|
5897
5939
|
}
|
|
5898
5940
|
}
|
|
5899
5941
|
__name(validItem, "validItem");
|
|
5942
|
+
function validText(text) {
|
|
5943
|
+
try {
|
|
5944
|
+
parseMlsDevTextPayload({
|
|
5945
|
+
version: 1,
|
|
5946
|
+
kind: "text",
|
|
5947
|
+
conversationId: "validation",
|
|
5948
|
+
groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
5949
|
+
messageId: "validation",
|
|
5950
|
+
operationId: "validation",
|
|
5951
|
+
senderDeviceId: "00000000-0000-4000-8000-000000000000",
|
|
5952
|
+
text
|
|
5953
|
+
});
|
|
5954
|
+
} catch {
|
|
5955
|
+
fail6("MLS_DEV_TEXT_INVALID");
|
|
5956
|
+
}
|
|
5957
|
+
}
|
|
5958
|
+
__name(validText, "validText");
|
|
5900
5959
|
function textInput(value) {
|
|
5901
|
-
const data = record4(value, ["conversationId"], ["text", "messageId", "contentType", "mentions", "attachments", "replyTo", "replyToPosition", "metadata", "forwarded", "contactCardUserId"]);
|
|
5960
|
+
const data = record4(value, ["conversationId"], ["text", "messageId", "contentType", "mentions", "attachments", "replyTo", "replyToPosition", "metadata", "forwarded", "contactCardUserId", "replyAuthority"]);
|
|
5902
5961
|
const attachments = data.attachments ?? [];
|
|
5903
5962
|
if (!Array.isArray(attachments) || attachments.length > 1) fail6(Array.isArray(attachments) ? "MLS_DEV_ONE_ITEM_PER_MESSAGE" : "MLS_DEV_TEXT_ONLY");
|
|
5904
5963
|
const item = attachments.length ? itemInput(attachments[0], data.text) : void 0;
|
|
5905
|
-
if (data.contentType !== void 0 && data.contentType !== (item ? item.type : "text") || !item && typeof data.text !== "string" || item && data.text !== void 0 && data.text !== null && typeof data.text !== "string" || data.mentions !== void 0 && (!Array.isArray(data.mentions) || data.mentions.some((mention) => typeof mention !== "string")) || data.replyTo !== void 0 && data.replyTo !== null && typeof data.replyTo !== "string" || ["replyToPosition", "metadata", "forwarded", "contactCardUserId"].some((key) => data[key] !== void 0 && data[key] !== null)) fail6("MLS_DEV_TEXT_ONLY");
|
|
5964
|
+
if (data.contentType !== void 0 && data.contentType !== (item ? item.type : "text") || !item && typeof data.text !== "string" || item && data.text !== void 0 && data.text !== null && typeof data.text !== "string" || data.mentions !== void 0 && (!Array.isArray(data.mentions) || data.mentions.some((mention) => typeof mention !== "string")) || data.replyTo !== void 0 && data.replyTo !== null && typeof data.replyTo !== "string" || ["replyToPosition", "metadata", "forwarded", "contactCardUserId"].some((key) => data[key] !== void 0 && data[key] !== null) || data.replyAuthority !== void 0 && (!!item || !data.replyAuthority || typeof data.replyAuthority !== "object" || Array.isArray(data.replyAuthority))) fail6("MLS_DEV_TEXT_ONLY");
|
|
5906
5965
|
const mentions = [...new Set(data.mentions ?? [])].map(id);
|
|
5907
5966
|
return {
|
|
5908
5967
|
conversationId: id(data.conversationId),
|
|
5909
5968
|
...item ? { item } : { text: data.text },
|
|
5910
5969
|
...data.messageId === void 0 ? {} : { messageId: id(data.messageId) },
|
|
5970
|
+
...data.replyAuthority === void 0 ? {} : { replyAuthority: data.replyAuthority },
|
|
5911
5971
|
...typeof data.replyTo === "string" ? { replyTo: id(data.replyTo) } : {},
|
|
5912
5972
|
...mentions.length ? { mentions } : {}
|
|
5913
5973
|
};
|
|
@@ -5919,18 +5979,23 @@ function createMlsDevGroups(options, context, keyPackages, bridge) {
|
|
|
5919
5979
|
return store.transaction(async (tx) => {
|
|
5920
5980
|
const room = await tx.get(`conversation/${conversationId}`);
|
|
5921
5981
|
const group = envelope((await readPreparationSnapshot(tx, scope4(conversationId))).protocolState, init.binding, conversationId);
|
|
5982
|
+
const missed = await tx.get(missedEarlierKey(conversationId)) === true ? { missedEarlier: true } : {};
|
|
5922
5983
|
if (room?.mlsAdmissionHold !== true) {
|
|
5923
5984
|
const joining = !!room && !!room.mls && (!group || group.removed);
|
|
5924
|
-
return Object.freeze({ held: joining, waitingPrincipalIds: Object.freeze(joining ? [init.identity.principalId] : []) });
|
|
5985
|
+
return Object.freeze({ held: joining, waitingPrincipalIds: Object.freeze(joining ? [init.identity.principalId] : []), ...missed });
|
|
5925
5986
|
}
|
|
5926
5987
|
const accounts = mlsRoomAccounts(room, init.binding.environmentId);
|
|
5927
5988
|
const admitted = new Set((group && !group.removed ? group.roster : []).map((entry) => mlsAccountOf(accounts, entry.device.principal)));
|
|
5928
|
-
const
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5989
|
+
const ids = /* @__PURE__ */ __name((value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [], "ids");
|
|
5990
|
+
const waiting = mlsAdmissionWait({
|
|
5991
|
+
senderId: init.identity.principalId,
|
|
5992
|
+
memberIds: ids(room.memberIds),
|
|
5993
|
+
admitted,
|
|
5994
|
+
unacceptedIds: [...ids([room.mlsInviteeId]), ...ids(room.mlsPendingFounderIds)],
|
|
5995
|
+
joinedAtMs: Number(room.mlsMemberJoinedAtMs),
|
|
5996
|
+
nowMs: context.clock()
|
|
5997
|
+
});
|
|
5998
|
+
return Object.freeze({ held: waiting.length > 0, waitingPrincipalIds: Object.freeze(waiting), ...missed });
|
|
5934
5999
|
});
|
|
5935
6000
|
}
|
|
5936
6001
|
__name(admissionHold, "admissionHold");
|
|
@@ -5965,6 +6030,10 @@ function createMlsDevGroups(options, context, keyPackages, bridge) {
|
|
|
5965
6030
|
const current = await capture(tx, state, init, cid), group = current.envelope;
|
|
5966
6031
|
if (!isMlsDevTextProtocol(current.protocol)) fail6("MLS_DEV_TEXT_PROTOCOL_UNSUPPORTED");
|
|
5967
6032
|
if ((input.replyTo || input.mentions || input.item) && current.protocol !== MLS_DEV_TEXT_PROTOCOL_V3) fail6("MLS_DEV_TEXT_ONLY");
|
|
6033
|
+
if (input.mentions) {
|
|
6034
|
+
const members = (await tx.get(`conversation/${cid}`))?.memberIds;
|
|
6035
|
+
if (!Array.isArray(members) || input.mentions.some((mention) => !members.includes(mention))) fail6("MLS_DEV_MENTION_NOT_MEMBER");
|
|
6036
|
+
}
|
|
5968
6037
|
if (input.item && !canonItemReference(input.item, cid, init.binding.environmentId)) fail6("MLS_DEV_ITEM_INVALID");
|
|
5969
6038
|
if (input.replyTo) {
|
|
5970
6039
|
const quote = mlsDevReplyQuote(await tx.get(mlsDevTextMessageKey(cid, input.replyTo)), MLS_DEV_REPLY_QUOTE_MAX_CHARACTERS);
|
|
@@ -6038,6 +6107,7 @@ function createMlsDevGroups(options, context, keyPackages, bridge) {
|
|
|
6038
6107
|
feedOrdinal: null
|
|
6039
6108
|
});
|
|
6040
6109
|
const media = prepared.text.kind === "item" ? { mediaUploadIds: [prepared.text.item.uploadId] } : {};
|
|
6110
|
+
const reply = input.replyAuthority ? { replyAuthority: input.replyAuthority } : {};
|
|
6041
6111
|
return bridge.queue(tx, {
|
|
6042
6112
|
operationId,
|
|
6043
6113
|
installationId: init.identity.installationId,
|
|
@@ -6058,7 +6128,7 @@ function createMlsDevGroups(options, context, keyPackages, bridge) {
|
|
|
6058
6128
|
operationId,
|
|
6059
6129
|
installationId: init.identity.installationId,
|
|
6060
6130
|
action: "mls_application",
|
|
6061
|
-
body: { encoding: "json", value: { ...prepared.wire, ...media } },
|
|
6131
|
+
body: { encoding: "json", value: { ...prepared.wire, ...media, ...reply } },
|
|
6062
6132
|
...init.identity.ownershipVersion === void 0 ? {} : { ownershipVersion: init.identity.ownershipVersion }
|
|
6063
6133
|
}
|
|
6064
6134
|
});
|
|
@@ -6068,6 +6138,76 @@ function createMlsDevGroups(options, context, keyPackages, bridge) {
|
|
|
6068
6138
|
return operation;
|
|
6069
6139
|
}
|
|
6070
6140
|
__name(sendText, "sendText");
|
|
6141
|
+
async function holdText(input, operationId) {
|
|
6142
|
+
const cid = input.conversationId;
|
|
6143
|
+
if (input.item || input.replyAuthority || typeof input.text !== "string") return sendText(input, operationId);
|
|
6144
|
+
const messageId = input.messageId ?? await bridge.hash(canonicalEndpointJson(["canon.held-text-message.v1", operationId]));
|
|
6145
|
+
const body = {
|
|
6146
|
+
conversationId: cid,
|
|
6147
|
+
messageId,
|
|
6148
|
+
text: input.text,
|
|
6149
|
+
...input.replyTo ? { replyTo: input.replyTo } : {},
|
|
6150
|
+
...input.mentions ? { mentions: input.mentions } : {}
|
|
6151
|
+
};
|
|
6152
|
+
const init = await initialized(), key = mlsDevHeldTextKey(cid, messageId);
|
|
6153
|
+
const kept = await store.transaction(async (tx) => {
|
|
6154
|
+
const existing = await tx.get(key);
|
|
6155
|
+
if (!existing) return await tx.get(`operation/${operationId}`) !== void 0 ? "made" : (await readMlsDevHeldTexts(tx, cid)).some((held) => !held.failed) ? "behind" : "none";
|
|
6156
|
+
if (existing.operationId !== operationId || canonicalEndpointJson(existing.body) !== canonicalEndpointJson(body)) fail6("OPERATION_ID_COLLISION");
|
|
6157
|
+
if (existing.failed) {
|
|
6158
|
+
const { failed: _failed, ...again } = existing;
|
|
6159
|
+
await tx.put(key, again);
|
|
6160
|
+
}
|
|
6161
|
+
return "kept";
|
|
6162
|
+
});
|
|
6163
|
+
if (kept === "kept") return void 0;
|
|
6164
|
+
if (kept !== "behind") {
|
|
6165
|
+
try {
|
|
6166
|
+
return await sendText({ ...input, messageId }, operationId);
|
|
6167
|
+
} catch (error) {
|
|
6168
|
+
if (kept === "made" || !(error instanceof EndpointError) || error.code !== "MLS_DEV_GROUP_ADMISSION_PENDING") throw error;
|
|
6169
|
+
}
|
|
6170
|
+
}
|
|
6171
|
+
validText(body.text);
|
|
6172
|
+
await store.transaction(async (tx) => {
|
|
6173
|
+
const held = await readMlsDevHeldTexts(tx, cid);
|
|
6174
|
+
if (held.length >= MLS_DEV_HELD_TEXT_MAX) fail6("MLS_DEV_HELD_TEXT_LIMIT");
|
|
6175
|
+
await tx.put(key, {
|
|
6176
|
+
version: 1,
|
|
6177
|
+
body,
|
|
6178
|
+
operationId,
|
|
6179
|
+
senderId: init.binding.principal.id,
|
|
6180
|
+
senderType: principal.type,
|
|
6181
|
+
createdAtMs: context.clock(),
|
|
6182
|
+
sequence: (held.at(-1)?.sequence ?? 0) + 1
|
|
6183
|
+
});
|
|
6184
|
+
});
|
|
6185
|
+
bridge.historyChanged?.(cid);
|
|
6186
|
+
return void 0;
|
|
6187
|
+
}
|
|
6188
|
+
__name(holdText, "holdText");
|
|
6189
|
+
async function sendHeldTexts(conversationId) {
|
|
6190
|
+
const sent = [], failed = [];
|
|
6191
|
+
const kept = (await store.transaction((tx) => readMlsDevHeldTexts(tx, conversationId))).filter((held) => !held.failed);
|
|
6192
|
+
for (const held of kept) {
|
|
6193
|
+
const key = mlsDevHeldTextKey(conversationId, held.body.messageId);
|
|
6194
|
+
try {
|
|
6195
|
+
sent.push(await sendText(textInput(held.body), held.operationId));
|
|
6196
|
+
} catch (error) {
|
|
6197
|
+
if (error instanceof EndpointError && ["ENDPOINT_CLOSED", "PREPARATION_INSTALLATION_FENCED"].includes(error.code)) throw error;
|
|
6198
|
+
if (!(error instanceof EndpointError) || error.retryable) return { sent, failed, waiting: true };
|
|
6199
|
+
await store.transaction(async (tx) => {
|
|
6200
|
+
if (await tx.get(key) !== void 0) await tx.put(key, { ...held, failed: error.code });
|
|
6201
|
+
});
|
|
6202
|
+
failed.push({ operationId: held.operationId, error });
|
|
6203
|
+
bridge.historyChanged?.(conversationId);
|
|
6204
|
+
continue;
|
|
6205
|
+
}
|
|
6206
|
+
await store.transaction((tx) => tx.delete(key));
|
|
6207
|
+
}
|
|
6208
|
+
return { sent, failed, waiting: false };
|
|
6209
|
+
}
|
|
6210
|
+
__name(sendHeldTexts, "sendHeldTexts");
|
|
6071
6211
|
async function roomAccounts(tx, conversationId, init) {
|
|
6072
6212
|
return mlsRoomAccounts(await tx.get(`conversation/${conversationId}`), init.binding.environmentId);
|
|
6073
6213
|
}
|
|
@@ -6844,6 +6984,15 @@ function createMlsDevGroups(options, context, keyPackages, bridge) {
|
|
|
6844
6984
|
const input = textInput(value), selectedId = id(operationId), selectedGuard = guardId === void 0 ? void 0 : id(guardId);
|
|
6845
6985
|
return run(() => serializeInboundPreparation(store, input.conversationId, () => sendText(input, selectedId, selectedGuard)));
|
|
6846
6986
|
},
|
|
6987
|
+
/** `sendText` for a person's composer: in a held room the text is kept, not refused (undefined), until `sendHeldTexts`. */
|
|
6988
|
+
holdText(value, operationId) {
|
|
6989
|
+
const input = textInput(value), selectedId = id(operationId);
|
|
6990
|
+
return run(() => serializeInboundPreparation(store, input.conversationId, () => holdText(input, selectedId)));
|
|
6991
|
+
},
|
|
6992
|
+
sendHeldTexts(conversationId) {
|
|
6993
|
+
const cid = id(conversationId);
|
|
6994
|
+
return run(() => serializeInboundPreparation(store, cid, () => sendHeldTexts(cid)));
|
|
6995
|
+
},
|
|
6847
6996
|
/** A room this device holds caught up is read as it holds it: what fetches the room's new entries says so
|
|
6848
6997
|
* (bridge.historyChanged). Otherwise a read fetches the feed first, which the polling fallback and the connected
|
|
6849
6998
|
* stream's minute-long safety poll rely on. */
|
|
@@ -7127,6 +7276,7 @@ function createEndpoint(options) {
|
|
|
7127
7276
|
clearTimeout(admissionTimers.get(conversationId));
|
|
7128
7277
|
admissionTimers.delete(conversationId);
|
|
7129
7278
|
scheduleAdmission(conversationId, 0);
|
|
7279
|
+
void releaseHeldTexts(conversationId);
|
|
7130
7280
|
}, "controlSettled"),
|
|
7131
7281
|
// Whatever fetched them (a hint, the reconnect sweep, a send, recovery), the room's local reads show them now.
|
|
7132
7282
|
historyChanged: /* @__PURE__ */ __name((conversationId) => queryObserver.invalidate((query, parameters) => options.localInboxPreviews && query === "list_conversations" || parameters.conversationId === conversationId && ["list_messages", "get_messages", "get_runtime_card_state"].includes(query)), "historyChanged"),
|
|
@@ -7497,6 +7647,86 @@ function createEndpoint(options) {
|
|
|
7497
7647
|
}
|
|
7498
7648
|
}
|
|
7499
7649
|
__name(sendDeferredOpeners, "sendDeferredOpeners");
|
|
7650
|
+
const heldWaiters = /* @__PURE__ */ new Map();
|
|
7651
|
+
const heldRooms = /* @__PURE__ */ new Set(), heldTimers = /* @__PURE__ */ new Map(), heldDelays = /* @__PURE__ */ new Map();
|
|
7652
|
+
const releasingHeld = /* @__PURE__ */ new Set(), releaseAgain = /* @__PURE__ */ new Set();
|
|
7653
|
+
function settleHeldWaiters(operationId, settle) {
|
|
7654
|
+
const waiters = heldWaiters.get(operationId) ?? [];
|
|
7655
|
+
heldWaiters.delete(operationId);
|
|
7656
|
+
for (const waiter of waiters) settle(waiter);
|
|
7657
|
+
}
|
|
7658
|
+
__name(settleHeldWaiters, "settleHeldWaiters");
|
|
7659
|
+
function scheduleHeldTexts(conversationId) {
|
|
7660
|
+
if (closed || heldTimers.has(conversationId)) return;
|
|
7661
|
+
const delay = heldDelays.get(conversationId) ?? 3e3;
|
|
7662
|
+
heldDelays.set(conversationId, Math.min(delay * 2, 3e4));
|
|
7663
|
+
const timer = setTimeout(() => {
|
|
7664
|
+
heldTimers.delete(conversationId);
|
|
7665
|
+
void releaseHeldTexts(conversationId);
|
|
7666
|
+
}, delay);
|
|
7667
|
+
timer.unref?.();
|
|
7668
|
+
heldTimers.set(conversationId, timer);
|
|
7669
|
+
}
|
|
7670
|
+
__name(scheduleHeldTexts, "scheduleHeldTexts");
|
|
7671
|
+
async function releaseHeldTexts(conversationId) {
|
|
7672
|
+
if (!mlsDevGroups || closed || !heldRooms.has(conversationId)) return;
|
|
7673
|
+
if (releasingHeld.has(conversationId)) {
|
|
7674
|
+
releaseAgain.add(conversationId);
|
|
7675
|
+
return;
|
|
7676
|
+
}
|
|
7677
|
+
releasingHeld.add(conversationId);
|
|
7678
|
+
try {
|
|
7679
|
+
let waiting;
|
|
7680
|
+
do {
|
|
7681
|
+
releaseAgain.delete(conversationId);
|
|
7682
|
+
const result = await mlsDevGroups.sendHeldTexts(conversationId);
|
|
7683
|
+
for (const operation of result.sent) settleHeldWaiters(operation.operationId, (waiter) => waiter.resolve(operation));
|
|
7684
|
+
for (const { operationId, error } of result.failed) settleHeldWaiters(operationId, (waiter) => waiter.reject(error));
|
|
7685
|
+
waiting = result.waiting;
|
|
7686
|
+
} while (releaseAgain.has(conversationId));
|
|
7687
|
+
if (waiting) scheduleHeldTexts(conversationId);
|
|
7688
|
+
else {
|
|
7689
|
+
heldRooms.delete(conversationId);
|
|
7690
|
+
heldDelays.delete(conversationId);
|
|
7691
|
+
clearTimeout(heldTimers.get(conversationId));
|
|
7692
|
+
heldTimers.delete(conversationId);
|
|
7693
|
+
}
|
|
7694
|
+
} catch (error) {
|
|
7695
|
+
if (!(error instanceof EndpointError) || !["ENDPOINT_CLOSED", "PREPARATION_INSTALLATION_FENCED"].includes(error.code)) scheduleHeldTexts(conversationId);
|
|
7696
|
+
} finally {
|
|
7697
|
+
releasingHeld.delete(conversationId);
|
|
7698
|
+
}
|
|
7699
|
+
}
|
|
7700
|
+
__name(releaseHeldTexts, "releaseHeldTexts");
|
|
7701
|
+
function closeHeldTexts() {
|
|
7702
|
+
for (const timer of heldTimers.values()) clearTimeout(timer);
|
|
7703
|
+
heldTimers.clear();
|
|
7704
|
+
const closedError = new EndpointError("Endpoint is closed", { code: "ENDPOINT_CLOSED", retryable: false });
|
|
7705
|
+
for (const operationId of [...heldWaiters.keys()]) settleHeldWaiters(operationId, (waiter) => waiter.reject(closedError));
|
|
7706
|
+
}
|
|
7707
|
+
__name(closeHeldTexts, "closeHeldTexts");
|
|
7708
|
+
async function sendTextWhenReady(body, operationId) {
|
|
7709
|
+
const queued = await mlsDevGroups.holdText(body, operationId);
|
|
7710
|
+
if (queued) return queued;
|
|
7711
|
+
const conversationId = body.conversationId;
|
|
7712
|
+
const sent = new Promise((resolve3, reject) => {
|
|
7713
|
+
heldWaiters.set(operationId, [...heldWaiters.get(operationId) ?? [], { resolve: resolve3, reject }]);
|
|
7714
|
+
});
|
|
7715
|
+
heldRooms.add(conversationId);
|
|
7716
|
+
void releaseHeldTexts(conversationId);
|
|
7717
|
+
return sent;
|
|
7718
|
+
}
|
|
7719
|
+
__name(sendTextWhenReady, "sendTextWhenReady");
|
|
7720
|
+
async function resumeHeldTexts() {
|
|
7721
|
+
for (let after; ; ) {
|
|
7722
|
+
const page = await store.transaction((tx) => tx.scan(mlsDevHeldTextPrefix(), { limit: 100, ...after ? { after } : {} }));
|
|
7723
|
+
for (const row of page) if (!row.value.failed) heldRooms.add(row.value.body.conversationId);
|
|
7724
|
+
if (page.length < 100) break;
|
|
7725
|
+
after = page[page.length - 1].key;
|
|
7726
|
+
}
|
|
7727
|
+
for (const conversationId of heldRooms) void releaseHeldTexts(conversationId);
|
|
7728
|
+
}
|
|
7729
|
+
__name(resumeHeldTexts, "resumeHeldTexts");
|
|
7500
7730
|
const stubReads = /* @__PURE__ */ new Map();
|
|
7501
7731
|
const stubNames = /* @__PURE__ */ new Map();
|
|
7502
7732
|
let liveActionCounter = 0;
|
|
@@ -7601,6 +7831,7 @@ function createEndpoint(options) {
|
|
|
7601
7831
|
await mlsDevGroups.commitHeldRemoval(conversationId).catch((error) => {
|
|
7602
7832
|
if (!(error instanceof EndpointError) || ["ENDPOINT_CLOSED", "PREPARATION_INSTALLATION_FENCED"].includes(error.code)) throw error;
|
|
7603
7833
|
});
|
|
7834
|
+
void releaseHeldTexts(conversationId);
|
|
7604
7835
|
}
|
|
7605
7836
|
return true;
|
|
7606
7837
|
}
|
|
@@ -8117,6 +8348,7 @@ function createEndpoint(options) {
|
|
|
8117
8348
|
if (mode.required) {
|
|
8118
8349
|
if (!isMlsDevTextProtocol(mode.protocol) || !mlsDevGroups) throw new EndpointError("Encrypted text is unavailable for this room", { code: "MLS_DEV_ENCRYPTED_CONTENT_REQUIRED", retryable: false });
|
|
8119
8350
|
if (executeOptions.sensitive || authored.envelope || authored.preconditions) throw new EndpointError("Unsupported encrypted text fields", { code: "INVALID_MLS_DEV_TEXT_INPUT", retryable: false });
|
|
8351
|
+
if (executeOptions.waitWhileHeld && !executeOptions.guardId) return sendTextWhenReady(authored.body, operationId);
|
|
8120
8352
|
return mlsDevGroups.sendText(authored.body, operationId, executeOptions.guardId);
|
|
8121
8353
|
}
|
|
8122
8354
|
}
|
|
@@ -8741,6 +8973,7 @@ function createEndpoint(options) {
|
|
|
8741
8973
|
admissionTimers.clear();
|
|
8742
8974
|
for (const timer of openerTimers.values()) clearTimeout(timer);
|
|
8743
8975
|
openerTimers.clear();
|
|
8976
|
+
closeHeldTexts();
|
|
8744
8977
|
queryObserver.close();
|
|
8745
8978
|
listeners.clear();
|
|
8746
8979
|
closing = (async () => {
|
|
@@ -8763,6 +8996,7 @@ function createEndpoint(options) {
|
|
|
8763
8996
|
admissionTimers.clear();
|
|
8764
8997
|
for (const timer of openerTimers.values()) clearTimeout(timer);
|
|
8765
8998
|
openerTimers.clear();
|
|
8999
|
+
closeHeldTexts();
|
|
8766
9000
|
queryObserver.close();
|
|
8767
9001
|
sensitiveRequests.clear();
|
|
8768
9002
|
sensitiveFingerprints.clear();
|
|
@@ -8774,6 +9008,7 @@ function createEndpoint(options) {
|
|
|
8774
9008
|
registerArtifactEndpoint(endpoint, { store, closed: /* @__PURE__ */ __name(() => closed, "closed"), assertCurrent: assertCurrentInstallation });
|
|
8775
9009
|
void initialization.then(() => scheduleRetry(0)).catch(() => void 0);
|
|
8776
9010
|
void initialization.then(() => sendDeferredOpeners()).catch(() => void 0);
|
|
9011
|
+
if (mlsDevGroups) void initialization.then(() => resumeHeldTexts()).catch(() => void 0);
|
|
8777
9012
|
return endpoint;
|
|
8778
9013
|
}
|
|
8779
9014
|
__name(createEndpoint, "createEndpoint");
|
|
@@ -8828,7 +9063,7 @@ async function acquireAgentEndpoint(input) {
|
|
|
8828
9063
|
}
|
|
8829
9064
|
const requestedMls = input.options.mlsDev;
|
|
8830
9065
|
const mls = requestedMls ? await (async () => {
|
|
8831
|
-
const crypto2 = await import("./mls-crypto-
|
|
9066
|
+
const crypto2 = await import("./mls-crypto-NZVMSUFU.js");
|
|
8832
9067
|
const configuration = crypto2.parseMlsDevClientConfiguration(requestedMls.configuration);
|
|
8833
9068
|
if (configuration.environmentId !== environmentId || baseUrl !== CANON_RUNTIME_ENDPOINT_DEFAULTS[configuration.environmentId]?.apiBaseUrl || configuration.principalIds && !configuration.principalIds.includes(input.principalId) || !Number.isSafeInteger(input.ownershipVersion) || input.ownershipVersion < 0) throw new Error("MLS_DEV_AGENT_CONFIGURATION_BINDING_MISMATCH");
|
|
8834
9069
|
const custody = requestedMls.custody;
|
|
@@ -9433,7 +9668,7 @@ var CanonClient = class {
|
|
|
9433
9668
|
return result.status === "unavailable" && result.reason === "opening-text-required" ? void 0 : result;
|
|
9434
9669
|
}
|
|
9435
9670
|
async blockUser(userId) {
|
|
9436
|
-
await this.endpointAction("set_block", { userId, blocked: true });
|
|
9671
|
+
await this.endpointAction("set_block", { targetUserId: userId, blocked: true });
|
|
9437
9672
|
}
|
|
9438
9673
|
async deleteMessage(conversationId, messageId) {
|
|
9439
9674
|
await this.endpointAction("delete_message", { conversationId, messageId });
|
|
@@ -10330,1028 +10565,14 @@ async function ensureAgentProfile(options) {
|
|
|
10330
10565
|
}
|
|
10331
10566
|
__name(ensureAgentProfile, "ensureAgentProfile");
|
|
10332
10567
|
|
|
10333
|
-
// ../core/src/runtime-cards.ts
|
|
10334
|
-
var FIELD_TYPE_SET = new Set(RUNTIME_CARD_FIELD_TYPES);
|
|
10335
|
-
var LINE_ITEM_COLUMN_TYPE_SET = new Set(RUNTIME_CARD_LINE_ITEM_COLUMN_TYPES);
|
|
10336
|
-
function buildRuntimeInputOutcome(inputId, status, details) {
|
|
10337
|
-
return {
|
|
10338
|
-
text: status === "timeout" ? "Input request expired" : status === "cancelled" ? "Input request cancelled" : "Input request resolved",
|
|
10339
|
-
metadata: {
|
|
10340
|
-
type: "runtime_input_outcome",
|
|
10341
|
-
inputId,
|
|
10342
|
-
...details?.kind ? { kind: details.kind } : {},
|
|
10343
|
-
status,
|
|
10344
|
-
...details?.reason ? { reason: details.reason } : {}
|
|
10345
|
-
}
|
|
10346
|
-
};
|
|
10347
|
-
}
|
|
10348
|
-
__name(buildRuntimeInputOutcome, "buildRuntimeInputOutcome");
|
|
10349
|
-
function buildRuntimeCardOutcome(cardId, status, details) {
|
|
10350
|
-
return {
|
|
10351
|
-
text: status === "timeout" ? "Card request expired" : status === "cancelled" ? "Card request cancelled" : "Card request resolved",
|
|
10352
|
-
metadata: {
|
|
10353
|
-
type: "runtime_card_outcome",
|
|
10354
|
-
cardId,
|
|
10355
|
-
status,
|
|
10356
|
-
...details?.reason ? { reason: details.reason } : {},
|
|
10357
|
-
turnSemantics: "control",
|
|
10358
|
-
replyBehavior: "suppress_auto_reply"
|
|
10359
|
-
}
|
|
10360
|
-
};
|
|
10361
|
-
}
|
|
10362
|
-
__name(buildRuntimeCardOutcome, "buildRuntimeCardOutcome");
|
|
10363
|
-
|
|
10364
|
-
// ../core/src/runtime-request-manager.ts
|
|
10365
|
-
var RuntimeRequestCancelledError = class extends Error {
|
|
10366
|
-
static {
|
|
10367
|
-
__name(this, "RuntimeRequestCancelledError");
|
|
10368
|
-
}
|
|
10369
|
-
constructor(message = "Runtime request cancelled") {
|
|
10370
|
-
super(message);
|
|
10371
|
-
this.name = "RuntimeRequestCancelledError";
|
|
10372
|
-
}
|
|
10373
|
-
};
|
|
10374
|
-
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
10375
|
-
var DEFAULT_POLL_MS = 1e3;
|
|
10376
|
-
function pendingKey(kind, conversationId, requestId) {
|
|
10377
|
-
return `${kind}::${conversationId}::${requestId}`;
|
|
10378
|
-
}
|
|
10379
|
-
__name(pendingKey, "pendingKey");
|
|
10380
|
-
var RuntimeRequestManager = class {
|
|
10381
|
-
static {
|
|
10382
|
-
__name(this, "RuntimeRequestManager");
|
|
10383
|
-
}
|
|
10384
|
-
client;
|
|
10385
|
-
ctx;
|
|
10386
|
-
descriptors = /* @__PURE__ */ new Map();
|
|
10387
|
-
pending = /* @__PURE__ */ new Map();
|
|
10388
|
-
rules = [];
|
|
10389
|
-
constructor(client, ctx) {
|
|
10390
|
-
this.client = client;
|
|
10391
|
-
this.ctx = ctx;
|
|
10392
|
-
this.registerBuiltins();
|
|
10393
|
-
}
|
|
10394
|
-
/** Register (or override) the descriptor for a kind. */
|
|
10395
|
-
register(kind, descriptor) {
|
|
10396
|
-
this.descriptors.set(kind, descriptor);
|
|
10397
|
-
}
|
|
10398
|
-
/** Built-in input, card, and plan descriptors. Subclasses add approval policy. */
|
|
10399
|
-
registerBuiltins() {
|
|
10400
|
-
this.register("input", runtimeInputDescriptor);
|
|
10401
|
-
this.register("card", runtimeCardDescriptor);
|
|
10402
|
-
this.register("plan", runtimePlanDescriptor);
|
|
10403
|
-
}
|
|
10404
|
-
get pendingCount() {
|
|
10405
|
-
return this.pending.size;
|
|
10406
|
-
}
|
|
10407
|
-
/**
|
|
10408
|
-
* Run one interactive runtime request end to end:
|
|
10409
|
-
* preflight → create → onCreated → register pending → poll (racing push wakeup
|
|
10410
|
-
* and abort) → post-deadline consume → finalize → onOutcome → resolve.
|
|
10411
|
-
*/
|
|
10412
|
-
async request(kind, conversationId, payload, options = {}) {
|
|
10413
|
-
const descriptor = this.descriptors.get(kind);
|
|
10414
|
-
if (!descriptor) {
|
|
10415
|
-
throw new Error(`No runtime-request descriptor registered for kind '${kind}'`);
|
|
10416
|
-
}
|
|
10417
|
-
if (options.signal?.aborted) {
|
|
10418
|
-
throw new RuntimeRequestCancelledError();
|
|
10419
|
-
}
|
|
10420
|
-
const pre = descriptor.preflight?.({
|
|
10421
|
-
client: this.client,
|
|
10422
|
-
ctx: this.ctx,
|
|
10423
|
-
conversationId,
|
|
10424
|
-
payload,
|
|
10425
|
-
options
|
|
10426
|
-
});
|
|
10427
|
-
if (pre != null) return pre;
|
|
10428
|
-
const requestId = options.requestId ?? descriptor.generateId(payload);
|
|
10429
|
-
const expiresAt = descriptor.resolveExpiry?.({ payload, options }) ?? options.expiresAt ?? Date.now() + (options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
10430
|
-
const pollMs = descriptor.pollMs?.(payload) ?? options.pollMs ?? DEFAULT_POLL_MS;
|
|
10431
|
-
const created = await descriptor.create({
|
|
10432
|
-
client: this.client,
|
|
10433
|
-
ctx: this.ctx,
|
|
10434
|
-
conversationId,
|
|
10435
|
-
requestId,
|
|
10436
|
-
payload,
|
|
10437
|
-
expiresAt,
|
|
10438
|
-
state: void 0,
|
|
10439
|
-
options
|
|
10440
|
-
});
|
|
10441
|
-
const effectiveId = created.requestId || requestId;
|
|
10442
|
-
const effectiveExpiry = created.expiresAt ?? expiresAt;
|
|
10443
|
-
const state = created.state;
|
|
10444
|
-
const base = {
|
|
10445
|
-
client: this.client,
|
|
10446
|
-
ctx: this.ctx,
|
|
10447
|
-
conversationId,
|
|
10448
|
-
requestId: effectiveId,
|
|
10449
|
-
payload,
|
|
10450
|
-
expiresAt: effectiveExpiry,
|
|
10451
|
-
state
|
|
10452
|
-
};
|
|
10453
|
-
if (options.signal?.aborted) {
|
|
10454
|
-
await descriptor.cancel?.(base).catch(() => {
|
|
10455
|
-
});
|
|
10456
|
-
throw signalReason(options.signal) ?? new RuntimeRequestCancelledError();
|
|
10457
|
-
}
|
|
10458
|
-
if (options.onCreated) {
|
|
10459
|
-
await options.onCreated({
|
|
10460
|
-
requestId: effectiveId,
|
|
10461
|
-
expiresAt: effectiveExpiry,
|
|
10462
|
-
...created.messageId !== void 0 ? { messageId: created.messageId } : {},
|
|
10463
|
-
...created.interactive !== void 0 ? { interactive: created.interactive } : {}
|
|
10464
|
-
});
|
|
10465
|
-
}
|
|
10466
|
-
if (options.signal?.aborted) {
|
|
10467
|
-
await descriptor.cancel?.(base).catch(() => {
|
|
10468
|
-
});
|
|
10469
|
-
throw signalReason(options.signal) ?? new RuntimeRequestCancelledError();
|
|
10470
|
-
}
|
|
10471
|
-
const key = pendingKey(kind, conversationId, effectiveId);
|
|
10472
|
-
const signal = options.signal;
|
|
10473
|
-
return await new Promise((resolve3, reject) => {
|
|
10474
|
-
let settled = false;
|
|
10475
|
-
const finishCommon = /* @__PURE__ */ __name(() => {
|
|
10476
|
-
settled = true;
|
|
10477
|
-
entry.wake();
|
|
10478
|
-
clearTimeout(entry.timer);
|
|
10479
|
-
this.pending.delete(key);
|
|
10480
|
-
if (signal) signal.removeEventListener("abort", onAbort);
|
|
10481
|
-
}, "finishCommon");
|
|
10482
|
-
const settle = /* @__PURE__ */ __name((result, reason) => {
|
|
10483
|
-
if (settled) return;
|
|
10484
|
-
finishCommon();
|
|
10485
|
-
void (async () => {
|
|
10486
|
-
let finalResult = result;
|
|
10487
|
-
try {
|
|
10488
|
-
const override = descriptor.finalize?.({ ...base, result, reason });
|
|
10489
|
-
if (override !== void 0) finalResult = override;
|
|
10490
|
-
} catch {
|
|
10491
|
-
}
|
|
10492
|
-
if (options.onOutcome && descriptor.buildOutcome) {
|
|
10493
|
-
try {
|
|
10494
|
-
const env = descriptor.buildOutcome({ ...base, result: finalResult, reason });
|
|
10495
|
-
if (env) await options.onOutcome(env);
|
|
10496
|
-
} catch {
|
|
10497
|
-
}
|
|
10498
|
-
}
|
|
10499
|
-
resolve3(finalResult);
|
|
10500
|
-
})();
|
|
10501
|
-
}, "settle");
|
|
10502
|
-
const abort = /* @__PURE__ */ __name((error) => {
|
|
10503
|
-
if (settled) return;
|
|
10504
|
-
finishCommon();
|
|
10505
|
-
void descriptor.cancel?.(base).catch(() => {
|
|
10506
|
-
});
|
|
10507
|
-
reject(error);
|
|
10508
|
-
}, "abort");
|
|
10509
|
-
const onAbort = /* @__PURE__ */ __name(() => abort(signalReason(signal) ?? new RuntimeRequestCancelledError()), "onAbort");
|
|
10510
|
-
const entry = {
|
|
10511
|
-
kind,
|
|
10512
|
-
conversationId,
|
|
10513
|
-
requestId: effectiveId,
|
|
10514
|
-
timer: setTimeout(
|
|
10515
|
-
() => settle(descriptor.timeoutResult(base), "timeout"),
|
|
10516
|
-
Math.max(0, effectiveExpiry - Date.now())
|
|
10517
|
-
),
|
|
10518
|
-
wake: /* @__PURE__ */ __name(() => {
|
|
10519
|
-
}, "wake"),
|
|
10520
|
-
wakeRequested: false,
|
|
10521
|
-
settle: /* @__PURE__ */ __name((result, reason) => settle(result, reason), "settle"),
|
|
10522
|
-
abort
|
|
10523
|
-
};
|
|
10524
|
-
this.pending.set(key, entry);
|
|
10525
|
-
if (signal) signal.addEventListener("abort", onAbort, { once: true });
|
|
10526
|
-
const pollOnce = /* @__PURE__ */ __name(async () => {
|
|
10527
|
-
try {
|
|
10528
|
-
const outcome = await descriptor.consume(base);
|
|
10529
|
-
if (settled) return true;
|
|
10530
|
-
if (outcome.state === "resolved") {
|
|
10531
|
-
settle(outcome.result, "replied");
|
|
10532
|
-
return true;
|
|
10533
|
-
}
|
|
10534
|
-
if (outcome.state === "timeout") {
|
|
10535
|
-
settle(descriptor.timeoutResult(base), "timeout");
|
|
10536
|
-
return true;
|
|
10537
|
-
}
|
|
10538
|
-
} catch {
|
|
10539
|
-
}
|
|
10540
|
-
return false;
|
|
10541
|
-
}, "pollOnce");
|
|
10542
|
-
const poll = /* @__PURE__ */ __name(async () => {
|
|
10543
|
-
while (!settled && Date.now() < effectiveExpiry) {
|
|
10544
|
-
if (await pollOnce()) return;
|
|
10545
|
-
if (settled) return;
|
|
10546
|
-
await this.sleep(key, Math.min(pollMs, Math.max(1, effectiveExpiry - Date.now())));
|
|
10547
|
-
}
|
|
10548
|
-
if (settled) return;
|
|
10549
|
-
if (await pollOnce()) return;
|
|
10550
|
-
if (!settled) settle(descriptor.timeoutResult(base), "timeout");
|
|
10551
|
-
}, "poll");
|
|
10552
|
-
void poll();
|
|
10553
|
-
});
|
|
10554
|
-
}
|
|
10555
|
-
/** Push short-circuit: wake the pending request's poll to consume immediately. */
|
|
10556
|
-
notify(kind, conversationId, requestId) {
|
|
10557
|
-
const entry = this.pending.get(pendingKey(kind, conversationId, requestId));
|
|
10558
|
-
if (!entry) return;
|
|
10559
|
-
entry.wakeRequested = true;
|
|
10560
|
-
entry.wake();
|
|
10561
|
-
}
|
|
10562
|
-
/**
|
|
10563
|
-
* Feed an inbound message to the manager. Returns true when a matching pending
|
|
10564
|
-
* request was woken to consume canonical state. Receipt metadata never settles
|
|
10565
|
-
* the request directly. Fails closed on unknown / mismatched ids.
|
|
10566
|
-
*/
|
|
10567
|
-
handleMessage(conversationId, message) {
|
|
10568
|
-
if (this.pending.size === 0) return false;
|
|
10569
|
-
for (const descriptor of this.descriptors.values()) {
|
|
10570
|
-
const match = descriptor.matchPush?.({ conversationId, message, ctx: this.ctx });
|
|
10571
|
-
if (!match) continue;
|
|
10572
|
-
const entry = this.pending.get(pendingKey(descriptor.kind, conversationId, match.requestId));
|
|
10573
|
-
if (!entry) return false;
|
|
10574
|
-
entry.wakeRequested = true;
|
|
10575
|
-
entry.wake();
|
|
10576
|
-
return true;
|
|
10577
|
-
}
|
|
10578
|
-
return false;
|
|
10579
|
-
}
|
|
10580
|
-
/** Cancel a specific pending request (rejects its promise, best-effort server cancel). */
|
|
10581
|
-
async cancel(kind, conversationId, requestId) {
|
|
10582
|
-
this.pending.get(pendingKey(kind, conversationId, requestId))?.abort(new RuntimeRequestCancelledError());
|
|
10583
|
-
}
|
|
10584
|
-
// ── Session rules (approval descriptor uses these) ─────────────────
|
|
10585
|
-
checkSessionRules(toolName, conversationId) {
|
|
10586
|
-
this.pruneExpiredRules();
|
|
10587
|
-
for (const stored of this.rules) {
|
|
10588
|
-
if (conversationId && stored.conversationId !== conversationId) continue;
|
|
10589
|
-
const { rule } = stored;
|
|
10590
|
-
if (rule.type === "approve-all") return rule;
|
|
10591
|
-
if ((rule.type === "approve-tool" || rule.type === "deny-tool") && rule.toolPattern) {
|
|
10592
|
-
try {
|
|
10593
|
-
const re = new RegExp(`^${rule.toolPattern}$`, "i");
|
|
10594
|
-
if (re.test(toolName)) return rule;
|
|
10595
|
-
} catch {
|
|
10596
|
-
continue;
|
|
10597
|
-
}
|
|
10598
|
-
}
|
|
10599
|
-
}
|
|
10600
|
-
return null;
|
|
10601
|
-
}
|
|
10602
|
-
addSessionRule(conversationId, rule) {
|
|
10603
|
-
this.rules.push({ conversationId, rule });
|
|
10604
|
-
}
|
|
10605
|
-
getSessionRules() {
|
|
10606
|
-
this.pruneExpiredRules();
|
|
10607
|
-
return this.rules.map((stored) => stored.rule);
|
|
10608
|
-
}
|
|
10609
|
-
clearSessionRules() {
|
|
10610
|
-
this.rules = [];
|
|
10611
|
-
}
|
|
10612
|
-
dispose() {
|
|
10613
|
-
for (const entry of this.pending.values()) {
|
|
10614
|
-
clearTimeout(entry.timer);
|
|
10615
|
-
}
|
|
10616
|
-
this.pending.clear();
|
|
10617
|
-
this.rules = [];
|
|
10618
|
-
}
|
|
10619
|
-
pruneExpiredRules() {
|
|
10620
|
-
const now = Date.now();
|
|
10621
|
-
this.rules = this.rules.filter(({ rule }) => {
|
|
10622
|
-
if (!rule.expiresAt) return true;
|
|
10623
|
-
return new Date(rule.expiresAt).getTime() > now;
|
|
10624
|
-
});
|
|
10625
|
-
}
|
|
10626
|
-
/** Sleep that resolves on timeout, on `notify()` wakeup, or when the request settles. */
|
|
10627
|
-
sleep(key, ms) {
|
|
10628
|
-
const pending = this.pending.get(key);
|
|
10629
|
-
if (pending?.wakeRequested) {
|
|
10630
|
-
pending.wakeRequested = false;
|
|
10631
|
-
return Promise.resolve();
|
|
10632
|
-
}
|
|
10633
|
-
return new Promise((resolve3) => {
|
|
10634
|
-
let done = false;
|
|
10635
|
-
const finish = /* @__PURE__ */ __name(() => {
|
|
10636
|
-
if (done) return;
|
|
10637
|
-
done = true;
|
|
10638
|
-
clearTimeout(timer);
|
|
10639
|
-
const current = this.pending.get(key);
|
|
10640
|
-
if (current) {
|
|
10641
|
-
current.wakeRequested = false;
|
|
10642
|
-
current.wake = () => {
|
|
10643
|
-
};
|
|
10644
|
-
}
|
|
10645
|
-
resolve3();
|
|
10646
|
-
}, "finish");
|
|
10647
|
-
const timer = setTimeout(finish, ms);
|
|
10648
|
-
const entry = this.pending.get(key);
|
|
10649
|
-
if (entry) entry.wake = finish;
|
|
10650
|
-
});
|
|
10651
|
-
}
|
|
10652
|
-
};
|
|
10653
|
-
function signalReason(signal) {
|
|
10654
|
-
const reason = signal?.reason;
|
|
10655
|
-
return reason instanceof Error ? reason : void 0;
|
|
10656
|
-
}
|
|
10657
|
-
__name(signalReason, "signalReason");
|
|
10658
|
-
function resolveResponder(explicit, ownerId, policy) {
|
|
10659
|
-
if (explicit) return explicit;
|
|
10660
|
-
return policy === "owner" ? ownerId || void 0 : void 0;
|
|
10661
|
-
}
|
|
10662
|
-
__name(resolveResponder, "resolveResponder");
|
|
10663
|
-
var inputSeq = 0;
|
|
10664
|
-
var cardSeq = 0;
|
|
10665
|
-
var planSeq = 0;
|
|
10666
|
-
var runtimeInputDescriptor = {
|
|
10667
|
-
kind: "input",
|
|
10668
|
-
generateId(payload) {
|
|
10669
|
-
return `${payload.kind}_${Date.now().toString(36)}${(++inputSeq).toString(36)}`;
|
|
10670
|
-
},
|
|
10671
|
-
async create({ client, ctx, conversationId, requestId, payload, expiresAt, options }) {
|
|
10672
|
-
const responder = resolveResponder(payload.responseUserId, ctx.ownerId, options.responderPolicy ?? "owner");
|
|
10673
|
-
const created = await client.createRuntimeInputRequest({
|
|
10674
|
-
conversationId,
|
|
10675
|
-
inputId: requestId,
|
|
10676
|
-
kind: payload.kind,
|
|
10677
|
-
expiresAt,
|
|
10678
|
-
...responder !== void 0 ? { responseUserId: responder } : {},
|
|
10679
|
-
...payload.title !== void 0 ? { title: payload.title } : {},
|
|
10680
|
-
...payload.prompt !== void 0 ? { prompt: payload.prompt } : {},
|
|
10681
|
-
...payload.choices ? { choices: payload.choices } : {},
|
|
10682
|
-
...payload.questions ? { questions: payload.questions } : {},
|
|
10683
|
-
...payload.secretName ? { secretName: payload.secretName } : {},
|
|
10684
|
-
...payload.native ? { native: payload.native } : {},
|
|
10685
|
-
...payload.sensitive !== void 0 ? { sensitive: payload.sensitive } : {},
|
|
10686
|
-
...payload.turnId ? { turnId: payload.turnId } : {}
|
|
10687
|
-
});
|
|
10688
|
-
return { requestId, ...created.messageId !== void 0 ? { messageId: created.messageId } : {} };
|
|
10689
|
-
},
|
|
10690
|
-
async consume({ client, conversationId, requestId }) {
|
|
10691
|
-
const response = await client.consumeRuntimeInputResponse({ conversationId, inputId: requestId });
|
|
10692
|
-
if (response.status === "submitted") {
|
|
10693
|
-
return {
|
|
10694
|
-
state: "resolved",
|
|
10695
|
-
result: {
|
|
10696
|
-
status: "submitted",
|
|
10697
|
-
inputId: requestId,
|
|
10698
|
-
value: response.value,
|
|
10699
|
-
...response.answers ? { answers: response.answers } : {}
|
|
10700
|
-
}
|
|
10701
|
-
};
|
|
10702
|
-
}
|
|
10703
|
-
if (response.status === "cancelled") {
|
|
10704
|
-
return { state: "resolved", result: { status: "cancelled", inputId: requestId } };
|
|
10705
|
-
}
|
|
10706
|
-
if (response.status === "timeout") return { state: "timeout" };
|
|
10707
|
-
return { state: "pending" };
|
|
10708
|
-
},
|
|
10709
|
-
async cancel({ client, conversationId, requestId }) {
|
|
10710
|
-
await client.consumeRuntimeInputResponse({ conversationId, inputId: requestId, cancel: true });
|
|
10711
|
-
},
|
|
10712
|
-
timeoutResult({ requestId }) {
|
|
10713
|
-
return { status: "timeout", inputId: requestId };
|
|
10714
|
-
},
|
|
10715
|
-
buildOutcome({ payload, result }) {
|
|
10716
|
-
const outcome = buildRuntimeInputOutcome(result.inputId, result.status, {
|
|
10717
|
-
kind: payload.kind,
|
|
10718
|
-
reason: result.status
|
|
10719
|
-
});
|
|
10720
|
-
return { text: outcome.text, metadata: outcome.metadata };
|
|
10721
|
-
}
|
|
10722
|
-
};
|
|
10723
|
-
var runtimeCardDescriptor = {
|
|
10724
|
-
kind: "card",
|
|
10725
|
-
generateId(payload) {
|
|
10726
|
-
return payload.card.cardId ?? `card_${Date.now().toString(36)}${(++cardSeq).toString(36)}`;
|
|
10727
|
-
},
|
|
10728
|
-
async create({ client, ctx, conversationId, requestId, payload, expiresAt, options }) {
|
|
10729
|
-
const responder = resolveResponder(payload.responseUserId, ctx.ownerId, options.responderPolicy ?? "infer");
|
|
10730
|
-
const created = await client.createRuntimeCardRequest({
|
|
10731
|
-
conversationId,
|
|
10732
|
-
// Embed cardId into the card body (as hosts do) so the wire shape is
|
|
10733
|
-
// byte-identical whether a host folds onto this built-in or not.
|
|
10734
|
-
card: { ...payload.card, cardId: requestId },
|
|
10735
|
-
cardId: requestId,
|
|
10736
|
-
expiresAt,
|
|
10737
|
-
...responder !== void 0 ? { responseUserId: responder } : {},
|
|
10738
|
-
...payload.runtimeId ? { runtimeId: payload.runtimeId } : {},
|
|
10739
|
-
...payload.turnId ? { turnId: payload.turnId } : {},
|
|
10740
|
-
...payload.native ? { native: payload.native } : {}
|
|
10741
|
-
});
|
|
10742
|
-
return {
|
|
10743
|
-
requestId: created.cardId ?? requestId,
|
|
10744
|
-
interactive: created.interactive,
|
|
10745
|
-
...created.expiresAt ? { expiresAt: created.expiresAt } : {},
|
|
10746
|
-
...created.messageId !== void 0 ? { messageId: created.messageId } : {}
|
|
10747
|
-
};
|
|
10748
|
-
},
|
|
10749
|
-
async consume({ client, conversationId, requestId }) {
|
|
10750
|
-
const response = await client.consumeRuntimeCardResponse({ conversationId, cardId: requestId });
|
|
10751
|
-
if (response.status === "submitted") {
|
|
10752
|
-
return {
|
|
10753
|
-
state: "resolved",
|
|
10754
|
-
result: {
|
|
10755
|
-
status: "submitted",
|
|
10756
|
-
cardId: requestId,
|
|
10757
|
-
...response.actionId ? { actionId: response.actionId } : {},
|
|
10758
|
-
...response.values ? { values: response.values } : {},
|
|
10759
|
-
...response.respondedBy ? { respondedBy: response.respondedBy } : {}
|
|
10760
|
-
}
|
|
10761
|
-
};
|
|
10762
|
-
}
|
|
10763
|
-
if (response.status === "cancelled") {
|
|
10764
|
-
return {
|
|
10765
|
-
state: "resolved",
|
|
10766
|
-
result: {
|
|
10767
|
-
status: "cancelled",
|
|
10768
|
-
cardId: requestId,
|
|
10769
|
-
...response.respondedBy ? { respondedBy: response.respondedBy } : {}
|
|
10770
|
-
}
|
|
10771
|
-
};
|
|
10772
|
-
}
|
|
10773
|
-
if (response.status === "timeout") return { state: "timeout" };
|
|
10774
|
-
return { state: "pending" };
|
|
10775
|
-
},
|
|
10776
|
-
async cancel({ client, conversationId, requestId }) {
|
|
10777
|
-
await client.consumeRuntimeCardResponse({ conversationId, cardId: requestId, cancel: true });
|
|
10778
|
-
},
|
|
10779
|
-
timeoutResult({ requestId }) {
|
|
10780
|
-
return { status: "timeout", cardId: requestId };
|
|
10781
|
-
},
|
|
10782
|
-
buildOutcome({ result }) {
|
|
10783
|
-
const status = result.status;
|
|
10784
|
-
const outcome = buildRuntimeCardOutcome(result.cardId, status, { reason: status });
|
|
10785
|
-
return { text: outcome.text, metadata: outcome.metadata };
|
|
10786
|
-
}
|
|
10787
|
-
};
|
|
10788
|
-
var runtimePlanDescriptor = {
|
|
10789
|
-
kind: "plan",
|
|
10790
|
-
generateId() {
|
|
10791
|
-
return `plan_${Date.now().toString(36)}${(++planSeq).toString(36)}`;
|
|
10792
|
-
},
|
|
10793
|
-
async create({ client, ctx, conversationId, requestId, payload, expiresAt, options }) {
|
|
10794
|
-
const responder = resolveResponder(payload.responseUserId, ctx.ownerId, options.responderPolicy ?? "infer");
|
|
10795
|
-
const created = await client.createRuntimePlanRequest({
|
|
10796
|
-
conversationId,
|
|
10797
|
-
planId: requestId,
|
|
10798
|
-
expiresAt,
|
|
10799
|
-
...responder !== void 0 ? { responseUserId: responder } : {},
|
|
10800
|
-
...payload.title !== void 0 ? { title: payload.title } : {},
|
|
10801
|
-
...payload.summary !== void 0 ? { summary: payload.summary } : {},
|
|
10802
|
-
...payload.body !== void 0 ? { body: payload.body } : {},
|
|
10803
|
-
...payload.allowedPrompts ? { allowedPrompts: payload.allowedPrompts } : {},
|
|
10804
|
-
...payload.turnId ? { turnId: payload.turnId } : {}
|
|
10805
|
-
});
|
|
10806
|
-
return {
|
|
10807
|
-
requestId: created.planId ?? requestId,
|
|
10808
|
-
expiresAt: created.expiresAt,
|
|
10809
|
-
...created.messageId !== void 0 ? { messageId: created.messageId } : {}
|
|
10810
|
-
};
|
|
10811
|
-
},
|
|
10812
|
-
async consume({ client, conversationId, requestId }) {
|
|
10813
|
-
const response = await client.consumeRuntimePlanResponse({ conversationId, planId: requestId });
|
|
10814
|
-
if (response.status === "approve" || response.status === "revise" || response.status === "reject") {
|
|
10815
|
-
return {
|
|
10816
|
-
state: "resolved",
|
|
10817
|
-
result: {
|
|
10818
|
-
status: response.status,
|
|
10819
|
-
planId: requestId,
|
|
10820
|
-
...response.feedback ? { feedback: response.feedback } : {},
|
|
10821
|
-
...response.grantedPrompts ? { grantedPrompts: response.grantedPrompts } : {},
|
|
10822
|
-
...response.receiptId ? { receiptId: response.receiptId } : {}
|
|
10823
|
-
}
|
|
10824
|
-
};
|
|
10825
|
-
}
|
|
10826
|
-
if (response.status === "cancelled") {
|
|
10827
|
-
return { state: "resolved", result: { status: "cancelled", planId: requestId } };
|
|
10828
|
-
}
|
|
10829
|
-
if (response.status === "timeout") return { state: "timeout" };
|
|
10830
|
-
return { state: "pending" };
|
|
10831
|
-
},
|
|
10832
|
-
async cancel({ client, conversationId, requestId }) {
|
|
10833
|
-
await client.consumeRuntimePlanResponse({ conversationId, planId: requestId, cancel: true });
|
|
10834
|
-
},
|
|
10835
|
-
timeoutResult({ requestId }) {
|
|
10836
|
-
return { status: "timeout", planId: requestId };
|
|
10837
|
-
},
|
|
10838
|
-
matchPush({ message }) {
|
|
10839
|
-
if (message.metadata?.type !== "plan_approval_reply") return null;
|
|
10840
|
-
const requestId = message.metadata.planId;
|
|
10841
|
-
return typeof requestId === "string" ? { requestId } : null;
|
|
10842
|
-
}
|
|
10843
|
-
};
|
|
10844
|
-
|
|
10845
|
-
// ../core/src/approval-types.ts
|
|
10846
|
-
var DEFAULT_APPROVAL_CONFIG = {
|
|
10847
|
-
enabled: true,
|
|
10848
|
-
timeoutSeconds: 300,
|
|
10849
|
-
defaultOnTimeout: "deny",
|
|
10850
|
-
// Applied to every host's approval previews via ApprovalManager. Covers both
|
|
10851
|
-
// key=value assignments and common bare-credential shapes (bearer headers,
|
|
10852
|
-
// provider keys, cloud keys, PEM blocks, credentialed URLs) so a redacted
|
|
10853
|
-
// command preview does not leak secrets that the narrow key=value rule misses.
|
|
10854
|
-
// Order matters: redactSecrets applies patterns sequentially, so specific
|
|
10855
|
-
// credential shapes run BEFORE the broad key=value rule — otherwise the kv
|
|
10856
|
-
// rule would consume "Authorization: Bearer" and leave the opaque token.
|
|
10857
|
-
// Bare-credential shapes carry a left boundary so ordinary tokens whose tail
|
|
10858
|
-
// happens to embed a prefix (risk-assessment…, disk-cleanup…) are not mangled
|
|
10859
|
-
// in the command preview the owner must read before approving.
|
|
10860
|
-
redactPatterns: [
|
|
10861
|
-
"(?<![A-Za-z0-9])bearer\\s+[A-Za-z0-9._~+/=-]{12,}",
|
|
10862
|
-
"(?<![A-Za-z0-9])sk-[A-Za-z0-9_-]{16,}",
|
|
10863
|
-
"(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}",
|
|
10864
|
-
"(?<![A-Za-z0-9])gh[posru]_[A-Za-z0-9]{20,}",
|
|
10865
|
-
"(?<![A-Za-z0-9])xox[baprs]-[A-Za-z0-9-]{10,}",
|
|
10866
|
-
"(?<![A-Za-z0-9])eyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}",
|
|
10867
|
-
"-----BEGIN [A-Z ]*PRIVATE KEY-----[\\s\\S]*?-----END [A-Z ]*PRIVATE KEY-----",
|
|
10868
|
-
"://[^\\s:@/]+:[^\\s:@/]+@",
|
|
10869
|
-
"(?:api[_-]?key|access[_-]?token|client[_-]?secret|secret|token|password|passwd|pwd|authorization|auth[_-]?token|private[_-]?key)\\s*[:=]\\s*\\S+"
|
|
10870
|
-
]
|
|
10871
|
-
};
|
|
10872
|
-
function isRecord2(value) {
|
|
10873
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
10874
|
-
}
|
|
10875
|
-
__name(isRecord2, "isRecord");
|
|
10876
|
-
function normalizeString(value, maxLength) {
|
|
10877
|
-
if (typeof value !== "string") return null;
|
|
10878
|
-
const trimmed = value.trim();
|
|
10879
|
-
if (!trimmed || trimmed.length > maxLength) return null;
|
|
10880
|
-
return trimmed;
|
|
10881
|
-
}
|
|
10882
|
-
__name(normalizeString, "normalizeString");
|
|
10883
|
-
function parseSessionRule(value) {
|
|
10884
|
-
if (!isRecord2(value)) return null;
|
|
10885
|
-
const type = value.type;
|
|
10886
|
-
if (type !== "approve-all" && type !== "approve-tool" && type !== "deny-tool") {
|
|
10887
|
-
return null;
|
|
10888
|
-
}
|
|
10889
|
-
let expiresAt;
|
|
10890
|
-
if (value.expiresAt !== void 0) {
|
|
10891
|
-
if (value.expiresAt === null) {
|
|
10892
|
-
expiresAt = null;
|
|
10893
|
-
} else {
|
|
10894
|
-
const normalizedExpiresAt = normalizeString(value.expiresAt, 128);
|
|
10895
|
-
if (!normalizedExpiresAt) return null;
|
|
10896
|
-
const expiresMs = Date.parse(normalizedExpiresAt);
|
|
10897
|
-
if (!Number.isFinite(expiresMs) || expiresMs <= Date.now()) return null;
|
|
10898
|
-
expiresAt = new Date(expiresMs).toISOString();
|
|
10899
|
-
}
|
|
10900
|
-
}
|
|
10901
|
-
if (type === "approve-all") {
|
|
10902
|
-
return {
|
|
10903
|
-
type,
|
|
10904
|
-
...expiresAt !== void 0 ? { expiresAt } : {}
|
|
10905
|
-
};
|
|
10906
|
-
}
|
|
10907
|
-
const toolPattern = normalizeString(value.toolPattern, 128);
|
|
10908
|
-
if (!toolPattern || !/^[\w.*:-]+$/.test(toolPattern)) {
|
|
10909
|
-
return null;
|
|
10910
|
-
}
|
|
10911
|
-
return {
|
|
10912
|
-
type,
|
|
10913
|
-
toolPattern,
|
|
10914
|
-
...expiresAt !== void 0 ? { expiresAt } : {}
|
|
10915
|
-
};
|
|
10916
|
-
}
|
|
10917
|
-
__name(parseSessionRule, "parseSessionRule");
|
|
10918
|
-
function parseApprovalReplyMetadata(value) {
|
|
10919
|
-
if (!isRecord2(value) || value.type !== "approval_reply") return null;
|
|
10920
|
-
const approvalId = normalizeString(value.approvalId, 128);
|
|
10921
|
-
if (!approvalId) return null;
|
|
10922
|
-
const decision = value.decision;
|
|
10923
|
-
if (decision !== "allow" && decision !== "deny") return null;
|
|
10924
|
-
let sessionRule;
|
|
10925
|
-
if (value.sessionRule !== void 0) {
|
|
10926
|
-
const parsed = parseSessionRule(value.sessionRule);
|
|
10927
|
-
if (!parsed) return null;
|
|
10928
|
-
sessionRule = parsed;
|
|
10929
|
-
}
|
|
10930
|
-
return {
|
|
10931
|
-
type: "approval_reply",
|
|
10932
|
-
approvalId,
|
|
10933
|
-
decision,
|
|
10934
|
-
...sessionRule ? { sessionRule } : {}
|
|
10935
|
-
};
|
|
10936
|
-
}
|
|
10937
|
-
__name(parseApprovalReplyMetadata, "parseApprovalReplyMetadata");
|
|
10938
|
-
|
|
10939
10568
|
// ../core/src/unified-diff.ts
|
|
10940
10569
|
var UNIFIED_DIFF_MAX_TOTAL_BYTES = 96 * 1024;
|
|
10941
10570
|
var UNIFIED_DIFF_MAX_FILE_BYTES = 24 * 1024;
|
|
10942
|
-
var UNIFIED_DIFF_MAX_FILES = 100;
|
|
10943
10571
|
var textEncoder = new TextEncoder();
|
|
10944
|
-
function byteLength(text) {
|
|
10945
|
-
return textEncoder.encode(text).length;
|
|
10946
|
-
}
|
|
10947
|
-
__name(byteLength, "byteLength");
|
|
10948
|
-
function clipDiffText(text, maxBytes) {
|
|
10949
|
-
if (maxBytes <= 0) return { text: "", clipped: true };
|
|
10950
|
-
if (byteLength(text) <= maxBytes) return { text, clipped: false };
|
|
10951
|
-
const lines = text.split("\n");
|
|
10952
|
-
const kept = [];
|
|
10953
|
-
let used = 0;
|
|
10954
|
-
for (const line of lines) {
|
|
10955
|
-
const cost = byteLength(line) + (kept.length > 0 ? 1 : 0);
|
|
10956
|
-
if (used + cost > maxBytes) break;
|
|
10957
|
-
kept.push(line);
|
|
10958
|
-
used += cost;
|
|
10959
|
-
}
|
|
10960
|
-
return { text: kept.join("\n"), clipped: true };
|
|
10961
|
-
}
|
|
10962
|
-
__name(clipDiffText, "clipDiffText");
|
|
10963
|
-
function truncateUnifiedDiff(diff, options) {
|
|
10964
|
-
const maxTotalBytes = options?.maxTotalBytes ?? UNIFIED_DIFF_MAX_TOTAL_BYTES;
|
|
10965
|
-
const maxFileBytes = options?.maxFileBytes ?? UNIFIED_DIFF_MAX_FILE_BYTES;
|
|
10966
|
-
const maxFiles = options?.maxFiles ?? UNIFIED_DIFF_MAX_FILES;
|
|
10967
|
-
let totalBytes = 0;
|
|
10968
|
-
let anyClipped = false;
|
|
10969
|
-
const files = diff.files.slice(0, maxFiles).map((file) => {
|
|
10970
|
-
if (typeof file.diff !== "string" || file.diff.length === 0) {
|
|
10971
|
-
const { diff: _omitted, ...rest } = file;
|
|
10972
|
-
return rest;
|
|
10973
|
-
}
|
|
10974
|
-
let truncated2 = file.truncated === true;
|
|
10975
|
-
let text = file.diff;
|
|
10976
|
-
const perFile = clipDiffText(text, maxFileBytes);
|
|
10977
|
-
if (perFile.clipped) {
|
|
10978
|
-
text = perFile.text;
|
|
10979
|
-
truncated2 = true;
|
|
10980
|
-
}
|
|
10981
|
-
const remaining = maxTotalBytes - totalBytes;
|
|
10982
|
-
const withinTotal = clipDiffText(text, remaining);
|
|
10983
|
-
if (withinTotal.clipped) {
|
|
10984
|
-
text = withinTotal.text;
|
|
10985
|
-
truncated2 = true;
|
|
10986
|
-
}
|
|
10987
|
-
if (truncated2) anyClipped = true;
|
|
10988
|
-
if (text.length === 0) {
|
|
10989
|
-
const { diff: _dropped, ...rest } = file;
|
|
10990
|
-
return { ...rest, truncated: true };
|
|
10991
|
-
}
|
|
10992
|
-
totalBytes += byteLength(text);
|
|
10993
|
-
return { ...file, diff: text, ...truncated2 ? { truncated: true } : {} };
|
|
10994
|
-
});
|
|
10995
|
-
const droppedFiles = diff.files.length > files.length;
|
|
10996
|
-
const truncated = diff.truncated === true || droppedFiles || anyClipped;
|
|
10997
|
-
return { files, ...truncated ? { truncated: true } : {} };
|
|
10998
|
-
}
|
|
10999
|
-
__name(truncateUnifiedDiff, "truncateUnifiedDiff");
|
|
11000
|
-
|
|
11001
|
-
// ../core/src/approval-format.ts
|
|
11002
|
-
var seq = 0;
|
|
11003
|
-
function generateApprovalId() {
|
|
11004
|
-
const ts = Date.now().toString(36);
|
|
11005
|
-
const r = Math.random().toString(36).slice(2, 6);
|
|
11006
|
-
return `apr_${ts}${r}${++seq}`;
|
|
11007
|
-
}
|
|
11008
|
-
__name(generateApprovalId, "generateApprovalId");
|
|
11009
|
-
function summarizeToolInput(toolName, toolInput) {
|
|
11010
|
-
if (toolName === "Bash" && typeof toolInput.command === "string") {
|
|
11011
|
-
return toolInput.command;
|
|
11012
|
-
}
|
|
11013
|
-
if ((toolName === "Edit" || toolName === "Write") && typeof toolInput.file_path === "string") {
|
|
11014
|
-
return toolInput.file_path;
|
|
11015
|
-
}
|
|
11016
|
-
const json = JSON.stringify(toolInput);
|
|
11017
|
-
return json.length > 200 ? json.slice(0, 200) + "..." : json;
|
|
11018
|
-
}
|
|
11019
|
-
__name(summarizeToolInput, "summarizeToolInput");
|
|
11020
|
-
function redactSecrets(text, patterns) {
|
|
11021
|
-
let result = text;
|
|
11022
|
-
for (const pat of patterns) {
|
|
11023
|
-
result = result.replace(new RegExp(pat, "gi"), "[REDACTED]");
|
|
11024
|
-
}
|
|
11025
|
-
return result;
|
|
11026
|
-
}
|
|
11027
|
-
__name(redactSecrets, "redactSecrets");
|
|
11028
|
-
function redactApprovalDetails(details, patterns) {
|
|
11029
|
-
if (!details?.length) return void 0;
|
|
11030
|
-
return details.slice(0, 8).map((detail) => ({
|
|
11031
|
-
...detail,
|
|
11032
|
-
label: detail.label.slice(0, 80),
|
|
11033
|
-
value: patterns?.length ? redactSecrets(detail.value.slice(0, 500), patterns) : detail.value.slice(0, 500)
|
|
11034
|
-
}));
|
|
11035
|
-
}
|
|
11036
|
-
__name(redactApprovalDetails, "redactApprovalDetails");
|
|
11037
|
-
function buildApprovalRequest(approvalId, toolName, toolInput, opts) {
|
|
11038
|
-
let summary = opts.toolSummary ?? summarizeToolInput(toolName, toolInput);
|
|
11039
|
-
if (opts.redactPatterns?.length) {
|
|
11040
|
-
summary = redactSecrets(summary, opts.redactPatterns);
|
|
11041
|
-
}
|
|
11042
|
-
summary = summary.slice(0, 1e3);
|
|
11043
|
-
const risk = opts.risk ?? opts.riskLevel ?? "normal";
|
|
11044
|
-
const riskLevel = risk === "destructive" ? "destructive" : opts.riskLevel ?? "normal";
|
|
11045
|
-
const details = redactApprovalDetails(opts.details, opts.redactPatterns);
|
|
11046
|
-
const diff = opts.diff ? truncateUnifiedDiff(opts.diff) : void 0;
|
|
11047
|
-
const timeoutMin = Math.round(
|
|
11048
|
-
(new Date(opts.expiresAt).getTime() - Date.now()) / 6e4
|
|
11049
|
-
);
|
|
11050
|
-
const lines = [
|
|
11051
|
-
`Action Approval Required [${approvalId}]`,
|
|
11052
|
-
"",
|
|
11053
|
-
`Tool: ${toolName}`,
|
|
11054
|
-
summary,
|
|
11055
|
-
""
|
|
11056
|
-
];
|
|
11057
|
-
if (risk === "high" || risk === "destructive") {
|
|
11058
|
-
lines.push(risk === "destructive" ? "This is a destructive operation" : "This is a high-risk operation");
|
|
11059
|
-
lines.push("");
|
|
11060
|
-
}
|
|
11061
|
-
lines.push(`Reply "approve" or "deny" (expires in ${timeoutMin}m)`);
|
|
11062
|
-
const metadata = {
|
|
11063
|
-
type: "approval_request",
|
|
11064
|
-
approvalId,
|
|
11065
|
-
...opts.responseUserId ? { responseUserId: opts.responseUserId.slice(0, 128) } : {},
|
|
11066
|
-
toolName,
|
|
11067
|
-
toolSummary: summary,
|
|
11068
|
-
...opts.category ? { category: opts.category } : {},
|
|
11069
|
-
risk,
|
|
11070
|
-
riskLevel,
|
|
11071
|
-
...opts.runtimeId ? { runtimeId: opts.runtimeId } : {},
|
|
11072
|
-
...opts.turnId ? { turnId: opts.turnId } : {},
|
|
11073
|
-
...opts.native ? { native: opts.native } : {},
|
|
11074
|
-
...details ? { details } : {},
|
|
11075
|
-
...diff ? { diff } : {},
|
|
11076
|
-
expiresAt: opts.expiresAt
|
|
11077
|
-
};
|
|
11078
|
-
return { text: lines.join("\n"), metadata };
|
|
11079
|
-
}
|
|
11080
|
-
__name(buildApprovalRequest, "buildApprovalRequest");
|
|
11081
|
-
function buildApprovalOutcome(approvalId, toolName, toolSummary, decision, reason) {
|
|
11082
|
-
const icon = decision === "allow" ? "Approved" : "Denied";
|
|
11083
|
-
const short = toolSummary.length > 60 ? toolSummary.slice(0, 60) + "..." : toolSummary;
|
|
11084
|
-
if (reason === "timeout") {
|
|
11085
|
-
return `Expired [${approvalId}] -- ${toolName}: ${short} (auto-denied)`;
|
|
11086
|
-
}
|
|
11087
|
-
if (reason === "session-rule") {
|
|
11088
|
-
const label = decision === "allow" ? "Auto-approved" : "Auto-denied";
|
|
11089
|
-
return `${label} (session rule) -- ${toolName}: ${short}`;
|
|
11090
|
-
}
|
|
11091
|
-
return `${icon} [${approvalId}] -- ${toolName}: ${short}`;
|
|
11092
|
-
}
|
|
11093
|
-
__name(buildApprovalOutcome, "buildApprovalOutcome");
|
|
11094
|
-
|
|
11095
|
-
// ../core/src/approval-manager.ts
|
|
11096
|
-
var ApprovalManager = class extends RuntimeRequestManager {
|
|
11097
|
-
static {
|
|
11098
|
-
__name(this, "ApprovalManager");
|
|
11099
|
-
}
|
|
11100
|
-
config;
|
|
11101
|
-
constructor(client, agentId, ownerId, config) {
|
|
11102
|
-
super(client, { agentId, ownerId });
|
|
11103
|
-
this.config = { ...DEFAULT_APPROVAL_CONFIG, ...config };
|
|
11104
|
-
this.register("approval", this.buildApprovalDescriptor());
|
|
11105
|
-
}
|
|
11106
|
-
/**
|
|
11107
|
-
* Request approval for a tool call.
|
|
11108
|
-
*
|
|
11109
|
-
* 1. Checks session rules — may resolve immediately.
|
|
11110
|
-
* 2. Sends a message with approval card metadata.
|
|
11111
|
-
* 3. Waits for the owner's reply (or timeout).
|
|
11112
|
-
*/
|
|
11113
|
-
requestApproval(conversationId, toolName, toolInput, opts, runtimeOptions) {
|
|
11114
|
-
return this.request(
|
|
11115
|
-
"approval",
|
|
11116
|
-
conversationId,
|
|
11117
|
-
{ toolName, toolInput, opts },
|
|
11118
|
-
runtimeOptions
|
|
11119
|
-
);
|
|
11120
|
-
}
|
|
11121
|
-
buildApprovalDescriptor() {
|
|
11122
|
-
return {
|
|
11123
|
-
kind: "approval",
|
|
11124
|
-
generateId: /* @__PURE__ */ __name(() => generateApprovalId(), "generateId"),
|
|
11125
|
-
resolveExpiry: /* @__PURE__ */ __name(({ options }) => options.expiresAt ?? Date.now() + this.config.timeoutSeconds * 1e3, "resolveExpiry"),
|
|
11126
|
-
pollMs: /* @__PURE__ */ __name(() => 1e3, "pollMs"),
|
|
11127
|
-
preflight: /* @__PURE__ */ __name(({ conversationId, payload }) => {
|
|
11128
|
-
const { toolName, toolInput, opts } = payload;
|
|
11129
|
-
const nonOwnerResponder = Boolean(
|
|
11130
|
-
opts?.responseUserId && opts.responseUserId !== this.ctx.ownerId
|
|
11131
|
-
);
|
|
11132
|
-
const matchingRule = opts?.ignoreSessionRules || nonOwnerResponder ? null : this.checkSessionRules(toolName, conversationId);
|
|
11133
|
-
if (!matchingRule) return null;
|
|
11134
|
-
const decision = matchingRule.type === "deny-tool" ? "deny" : "allow";
|
|
11135
|
-
const rawSummary = opts?.toolSummary ?? summarizeTool(toolName, toolInput);
|
|
11136
|
-
const summary = this.config.redactPatterns.length ? redactSecrets(rawSummary, this.config.redactPatterns) : rawSummary;
|
|
11137
|
-
const logMsg = buildApprovalOutcome("", toolName, summary, decision, "session-rule");
|
|
11138
|
-
this.client.sendMessage(conversationId, logMsg, {
|
|
11139
|
-
metadata: { type: "approval_outcome", decision, reason: "session-rule" }
|
|
11140
|
-
}).catch(() => {
|
|
11141
|
-
});
|
|
11142
|
-
return { decision };
|
|
11143
|
-
}, "preflight"),
|
|
11144
|
-
create: /* @__PURE__ */ __name(async ({ conversationId, requestId, payload, expiresAt }) => {
|
|
11145
|
-
const { toolName, toolInput, opts } = payload;
|
|
11146
|
-
const approvalId = requestId;
|
|
11147
|
-
const expiresAtIso = new Date(expiresAt).toISOString();
|
|
11148
|
-
const requestedResponseUserId = opts?.responseUserId || this.ctx.ownerId || void 0;
|
|
11149
|
-
const requestedAllowSessionRule = requestedResponseUserId === this.ctx.ownerId && opts?.allowSessionRule !== false;
|
|
11150
|
-
const { metadata } = buildApprovalRequest(approvalId, toolName, toolInput, {
|
|
11151
|
-
riskLevel: opts?.riskLevel,
|
|
11152
|
-
risk: opts?.risk,
|
|
11153
|
-
category: opts?.category,
|
|
11154
|
-
responseUserId: requestedResponseUserId,
|
|
11155
|
-
runtimeId: opts?.runtimeId,
|
|
11156
|
-
turnId: opts?.turnId,
|
|
11157
|
-
native: opts?.native,
|
|
11158
|
-
toolSummary: opts?.toolSummary,
|
|
11159
|
-
details: opts?.details,
|
|
11160
|
-
diff: opts?.diff,
|
|
11161
|
-
expiresAt: expiresAtIso,
|
|
11162
|
-
redactPatterns: this.config.redactPatterns
|
|
11163
|
-
});
|
|
11164
|
-
const created = await this.client.createRuntimeApprovalRequest({
|
|
11165
|
-
conversationId,
|
|
11166
|
-
approvalId,
|
|
11167
|
-
toolName,
|
|
11168
|
-
toolSummary: metadata.toolSummary,
|
|
11169
|
-
expiresAt: Date.parse(expiresAtIso),
|
|
11170
|
-
...requestedResponseUserId ? { responseUserId: requestedResponseUserId } : {},
|
|
11171
|
-
...opts?.riskLevel ? { riskLevel: opts.riskLevel } : {},
|
|
11172
|
-
...opts?.risk ? { risk: opts.risk } : {},
|
|
11173
|
-
...opts?.category ? { category: opts.category } : {},
|
|
11174
|
-
...opts?.runtimeId ? { runtimeId: opts.runtimeId } : {},
|
|
11175
|
-
...opts?.turnId ? { turnId: opts.turnId } : {},
|
|
11176
|
-
...metadata.native ? { native: metadata.native } : {},
|
|
11177
|
-
...metadata.details ? { details: metadata.details } : {},
|
|
11178
|
-
...metadata.diff ? { diff: metadata.diff } : {},
|
|
11179
|
-
...!requestedAllowSessionRule ? { allowSessionRule: false } : {}
|
|
11180
|
-
});
|
|
11181
|
-
return {
|
|
11182
|
-
requestId: approvalId,
|
|
11183
|
-
expiresAt,
|
|
11184
|
-
state: {
|
|
11185
|
-
toolName,
|
|
11186
|
-
toolSummary: metadata.toolSummary,
|
|
11187
|
-
allowSessionRule: created.allowSessionRule ?? requestedAllowSessionRule
|
|
11188
|
-
}
|
|
11189
|
-
};
|
|
11190
|
-
}, "create"),
|
|
11191
|
-
consume: /* @__PURE__ */ __name(async ({ conversationId, requestId }) => {
|
|
11192
|
-
const response = await this.client.consumeRuntimeApprovalResponse({
|
|
11193
|
-
conversationId,
|
|
11194
|
-
approvalId: requestId
|
|
11195
|
-
});
|
|
11196
|
-
if (response.status === "allow" || response.status === "deny") {
|
|
11197
|
-
return {
|
|
11198
|
-
state: "resolved",
|
|
11199
|
-
result: {
|
|
11200
|
-
decision: response.status,
|
|
11201
|
-
...response.sessionRule ? { sessionRule: response.sessionRule } : {},
|
|
11202
|
-
...response.respondedBy ? { respondedBy: response.respondedBy } : {}
|
|
11203
|
-
}
|
|
11204
|
-
};
|
|
11205
|
-
}
|
|
11206
|
-
if (response.status === "timeout") return { state: "timeout" };
|
|
11207
|
-
return { state: "pending" };
|
|
11208
|
-
}, "consume"),
|
|
11209
|
-
cancel: /* @__PURE__ */ __name(async ({ conversationId, requestId }) => {
|
|
11210
|
-
await this.client.consumeRuntimeApprovalResponse({
|
|
11211
|
-
conversationId,
|
|
11212
|
-
approvalId: requestId,
|
|
11213
|
-
cancel: true
|
|
11214
|
-
});
|
|
11215
|
-
}, "cancel"),
|
|
11216
|
-
timeoutResult: /* @__PURE__ */ __name(() => ({ decision: "deny" }), "timeoutResult"),
|
|
11217
|
-
finalize: /* @__PURE__ */ __name(({ conversationId, requestId, state, result, reason }) => {
|
|
11218
|
-
const toolName = state?.toolName ?? "";
|
|
11219
|
-
const toolSummary = state?.toolSummary ?? "";
|
|
11220
|
-
if (reason === "timeout") {
|
|
11221
|
-
const msg = buildApprovalOutcome(requestId, toolName, toolSummary, "deny", "timeout");
|
|
11222
|
-
this.client.sendMessage(conversationId, msg, {
|
|
11223
|
-
metadata: {
|
|
11224
|
-
type: "approval_outcome",
|
|
11225
|
-
approvalId: requestId,
|
|
11226
|
-
decision: "deny",
|
|
11227
|
-
reason: "timeout"
|
|
11228
|
-
}
|
|
11229
|
-
}).catch(() => {
|
|
11230
|
-
});
|
|
11231
|
-
return { decision: "deny" };
|
|
11232
|
-
}
|
|
11233
|
-
const acceptedSessionRule = state?.allowSessionRule ? result.sessionRule : void 0;
|
|
11234
|
-
if (acceptedSessionRule) {
|
|
11235
|
-
this.addSessionRule(conversationId, acceptedSessionRule);
|
|
11236
|
-
}
|
|
11237
|
-
const outcomeMsg = buildApprovalOutcome(
|
|
11238
|
-
requestId,
|
|
11239
|
-
toolName,
|
|
11240
|
-
toolSummary,
|
|
11241
|
-
result.decision,
|
|
11242
|
-
"replied"
|
|
11243
|
-
);
|
|
11244
|
-
this.client.sendMessage(conversationId, outcomeMsg, {
|
|
11245
|
-
metadata: {
|
|
11246
|
-
type: "approval_outcome",
|
|
11247
|
-
approvalId: requestId,
|
|
11248
|
-
decision: result.decision,
|
|
11249
|
-
reason: "replied"
|
|
11250
|
-
}
|
|
11251
|
-
}).catch(() => {
|
|
11252
|
-
});
|
|
11253
|
-
if (acceptedSessionRule) {
|
|
11254
|
-
const ruleDesc = describeRule(acceptedSessionRule);
|
|
11255
|
-
this.client.sendMessage(conversationId, `Session rule set: ${ruleDesc}`, {
|
|
11256
|
-
metadata: { type: "approval_outcome", decision: result.decision, reason: "session-rule" }
|
|
11257
|
-
}).catch(() => {
|
|
11258
|
-
});
|
|
11259
|
-
}
|
|
11260
|
-
return {
|
|
11261
|
-
decision: result.decision,
|
|
11262
|
-
...acceptedSessionRule ? { sessionRule: acceptedSessionRule } : {},
|
|
11263
|
-
...result.respondedBy ? { respondedBy: result.respondedBy } : {}
|
|
11264
|
-
};
|
|
11265
|
-
}, "finalize"),
|
|
11266
|
-
matchPush: /* @__PURE__ */ __name(({ conversationId, message }) => {
|
|
11267
|
-
void conversationId;
|
|
11268
|
-
if (message.metadata?.type !== "approval_reply") return null;
|
|
11269
|
-
const parsed = parseApprovalReplyMetadata(message.metadata);
|
|
11270
|
-
if (!parsed) return null;
|
|
11271
|
-
return { requestId: parsed.approvalId };
|
|
11272
|
-
}, "matchPush")
|
|
11273
|
-
};
|
|
11274
|
-
}
|
|
11275
|
-
};
|
|
11276
|
-
function summarizeTool(toolName, toolInput) {
|
|
11277
|
-
if (toolName === "Bash" && typeof toolInput.command === "string") {
|
|
11278
|
-
return toolInput.command;
|
|
11279
|
-
}
|
|
11280
|
-
if ((toolName === "Edit" || toolName === "Write") && typeof toolInput.file_path === "string") {
|
|
11281
|
-
return toolInput.file_path;
|
|
11282
|
-
}
|
|
11283
|
-
const json = JSON.stringify(toolInput);
|
|
11284
|
-
return json.length > 100 ? json.slice(0, 100) + "..." : json;
|
|
11285
|
-
}
|
|
11286
|
-
__name(summarizeTool, "summarizeTool");
|
|
11287
|
-
function describeRule(rule) {
|
|
11288
|
-
if (rule.type === "approve-all") {
|
|
11289
|
-
if (rule.expiresAt) {
|
|
11290
|
-
const min = Math.round((new Date(rule.expiresAt).getTime() - Date.now()) / 6e4);
|
|
11291
|
-
return `auto-approving all tools for ${min}m`;
|
|
11292
|
-
}
|
|
11293
|
-
return "auto-approving all tools for this session";
|
|
11294
|
-
}
|
|
11295
|
-
if (rule.type === "approve-tool") {
|
|
11296
|
-
return `auto-approving all ${rule.toolPattern} commands`;
|
|
11297
|
-
}
|
|
11298
|
-
if (rule.type === "deny-tool") {
|
|
11299
|
-
return `auto-denying all ${rule.toolPattern} commands`;
|
|
11300
|
-
}
|
|
11301
|
-
return "unknown rule";
|
|
11302
|
-
}
|
|
11303
|
-
__name(describeRule, "describeRule");
|
|
11304
|
-
|
|
11305
|
-
// ../core/src/silent-turn.ts
|
|
11306
|
-
var NO_REPLY_REASON_SENTINEL = "given";
|
|
11307
|
-
function reportNoReplyOutcome(client, params) {
|
|
11308
|
-
try {
|
|
11309
|
-
const hasReason = Boolean(params.reason?.trim());
|
|
11310
|
-
const wire = projectVerbIntentToWire(
|
|
11311
|
-
"no_reply",
|
|
11312
|
-
{
|
|
11313
|
-
conversationId: params.conversationId,
|
|
11314
|
-
...params.messageId ? { messageId: params.messageId } : {},
|
|
11315
|
-
...hasReason ? { reason: NO_REPLY_REASON_SENTINEL } : {}
|
|
11316
|
-
},
|
|
11317
|
-
{ now: params.now ?? Date.now() }
|
|
11318
|
-
);
|
|
11319
|
-
void client.executeVerbWire(wire).catch(() => {
|
|
11320
|
-
});
|
|
11321
|
-
} catch {
|
|
11322
|
-
}
|
|
11323
|
-
}
|
|
11324
|
-
__name(reportNoReplyOutcome, "reportNoReplyOutcome");
|
|
11325
10572
|
|
|
11326
|
-
// ../core/src/
|
|
11327
|
-
var
|
|
11328
|
-
|
|
11329
|
-
group: "quiet",
|
|
11330
|
-
// Fail OPEN to today's behavior: 'unknown' is reachable whenever the
|
|
11331
|
-
// conversation fetch fails, and silence-by-accident is worse than noise.
|
|
11332
|
-
unknown: "verbose"
|
|
11333
|
-
};
|
|
11334
|
-
function normalizeTurnVerbosityConversationType(value) {
|
|
11335
|
-
const normalized = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
11336
|
-
if (normalized === "direct") return "direct";
|
|
11337
|
-
if (normalized === "group") return "group";
|
|
11338
|
-
return "unknown";
|
|
11339
|
-
}
|
|
11340
|
-
__name(normalizeTurnVerbosityConversationType, "normalizeTurnVerbosityConversationType");
|
|
11341
|
-
function resolveTurnVerbosity(input) {
|
|
11342
|
-
const configured = parseTurnVerbosityConfig(input.configured);
|
|
11343
|
-
if (configured === "verbose" || configured === "quiet") return configured;
|
|
11344
|
-
return DEFAULT_TURN_VERBOSITY_BY_CONVERSATION_TYPE[normalizeTurnVerbosityConversationType(input.conversationType)];
|
|
11345
|
-
}
|
|
11346
|
-
__name(resolveTurnVerbosity, "resolveTurnVerbosity");
|
|
11347
|
-
function parseTurnVerbosityConfig(raw) {
|
|
11348
|
-
const normalized = typeof raw === "string" ? raw.trim().toLowerCase() : "";
|
|
11349
|
-
if (normalized === "verbose" || normalized === "quiet" || normalized === "auto") {
|
|
11350
|
-
return normalized;
|
|
11351
|
-
}
|
|
11352
|
-
return null;
|
|
11353
|
-
}
|
|
11354
|
-
__name(parseTurnVerbosityConfig, "parseTurnVerbosityConfig");
|
|
10573
|
+
// ../core/src/runtime-cards.ts
|
|
10574
|
+
var FIELD_TYPE_SET = new Set(RUNTIME_CARD_FIELD_TYPES);
|
|
10575
|
+
var LINE_ITEM_COLUMN_TYPE_SET = new Set(RUNTIME_CARD_LINE_ITEM_COLUMN_TYPES);
|
|
11355
10576
|
|
|
11356
10577
|
// ../core/src/rtdb-rest.ts
|
|
11357
10578
|
var CLEARED_LOCAL_RUNTIME_FIELDS = {
|
|
@@ -11792,62 +11013,12 @@ function createRuntimeStatePublisher(options) {
|
|
|
11792
11013
|
__name(createRuntimeStatePublisher, "createRuntimeStatePublisher");
|
|
11793
11014
|
|
|
11794
11015
|
// ../core/src/retry.ts
|
|
11795
|
-
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
11796
11016
|
var CANON_MESSAGE_TEXT_MAX_BYTES = 4 * 1024;
|
|
11797
|
-
var DEFAULT_CHUNKED_MESSAGE_TEXT_MAX_BYTES = 3800;
|
|
11798
11017
|
function isPendingCanonOperation(error) {
|
|
11799
|
-
if (isChunkedSendMessageError(error)) return isPendingCanonOperation(error.cause);
|
|
11800
11018
|
return !!error && typeof error === "object" && "code" in error && ["OPERATION_PENDING", "OPERATION_UNCERTAIN", "ENDPOINT_CLOSED"].includes(String(error.code));
|
|
11801
11019
|
}
|
|
11802
11020
|
__name(isPendingCanonOperation, "isPendingCanonOperation");
|
|
11803
|
-
var ChunkedSendMessageError = class extends Error {
|
|
11804
|
-
static {
|
|
11805
|
-
__name(this, "ChunkedSendMessageError");
|
|
11806
|
-
}
|
|
11807
|
-
/** Ids of the parts that are durable in Canon, in part order. */
|
|
11808
|
-
deliveredMessageIds;
|
|
11809
|
-
/** The part the send stopped on (1-based). */
|
|
11810
|
-
failedPart;
|
|
11811
|
-
/** How many parts the text splits into in total. */
|
|
11812
|
-
totalParts;
|
|
11813
|
-
/** The underlying send failure — what callers should classify. */
|
|
11814
|
-
cause;
|
|
11815
|
-
constructor(input) {
|
|
11816
|
-
const detail = input.cause instanceof Error ? input.cause.message : String(input.cause);
|
|
11817
|
-
super(`Chunked send failed at part ${input.failedPart} of ${input.totalParts}: ${detail}`);
|
|
11818
|
-
this.name = "ChunkedSendMessageError";
|
|
11819
|
-
this.deliveredMessageIds = [...input.deliveredMessageIds];
|
|
11820
|
-
this.failedPart = input.failedPart;
|
|
11821
|
-
this.totalParts = input.totalParts;
|
|
11822
|
-
this.cause = input.cause;
|
|
11823
|
-
}
|
|
11824
|
-
/** How many parts are durable — a resume starts at the next one. */
|
|
11825
|
-
get deliveredParts() {
|
|
11826
|
-
return this.deliveredMessageIds.length;
|
|
11827
|
-
}
|
|
11828
|
-
};
|
|
11829
|
-
function isChunkedSendMessageError(error) {
|
|
11830
|
-
if (error instanceof ChunkedSendMessageError) return true;
|
|
11831
|
-
return error instanceof Error && error.name === "ChunkedSendMessageError" && Array.isArray(error.deliveredMessageIds);
|
|
11832
|
-
}
|
|
11833
|
-
__name(isChunkedSendMessageError, "isChunkedSendMessageError");
|
|
11834
11021
|
var textEncoder2 = new TextEncoder();
|
|
11835
|
-
function isRetryableCanonDeliveryError(error) {
|
|
11836
|
-
if (error instanceof CanonApiError) {
|
|
11837
|
-
return error.status === 429 || error.status >= 500;
|
|
11838
|
-
}
|
|
11839
|
-
return error instanceof Error;
|
|
11840
|
-
}
|
|
11841
|
-
__name(isRetryableCanonDeliveryError, "isRetryableCanonDeliveryError");
|
|
11842
|
-
async function sendMessageWithRetry(client, conversationId, text, options, retryOptions = {}) {
|
|
11843
|
-
try {
|
|
11844
|
-
return await (retryOptions.operationId ? client.sendMessage(conversationId, text, options, { operationId: retryOptions.operationId }) : client.sendMessage(conversationId, text, options));
|
|
11845
|
-
} catch (error) {
|
|
11846
|
-
if (!(error instanceof CanonApiError) || !error.operationId) throw error;
|
|
11847
|
-
return client.waitForOperation(error.operationId, { signal: retryOptions.signal, timeoutMs: retryOptions.timeoutMs });
|
|
11848
|
-
}
|
|
11849
|
-
}
|
|
11850
|
-
__name(sendMessageWithRetry, "sendMessageWithRetry");
|
|
11851
11022
|
function utf8ByteLength(value) {
|
|
11852
11023
|
return textEncoder2.encode(value).byteLength;
|
|
11853
11024
|
}
|
|
@@ -11946,8 +11117,7 @@ ${renderedFence.marker}` : "";
|
|
|
11946
11117
|
};
|
|
11947
11118
|
}
|
|
11948
11119
|
__name(takeChunk, "takeChunk");
|
|
11949
|
-
function
|
|
11950
|
-
const byteLimit = Math.min(maxBytes, CANON_MESSAGE_TEXT_MAX_BYTES);
|
|
11120
|
+
function splitTextWithinBytes(text, byteLimit) {
|
|
11951
11121
|
if (!Number.isFinite(byteLimit) || byteLimit < 4) {
|
|
11952
11122
|
throw new Error("maxBytes must be at least 4");
|
|
11953
11123
|
}
|
|
@@ -11972,115 +11142,7 @@ function splitTextByUtf8Bytes(text, maxBytes = DEFAULT_CHUNKED_MESSAGE_TEXT_MAX_
|
|
|
11972
11142
|
}
|
|
11973
11143
|
return chunks;
|
|
11974
11144
|
}
|
|
11975
|
-
__name(
|
|
11976
|
-
function chunkMessageId(baseMessageId, index) {
|
|
11977
|
-
if (!baseMessageId) return void 0;
|
|
11978
|
-
const suffix = `-part-${index}`;
|
|
11979
|
-
const maxBaseLength = 160 - suffix.length;
|
|
11980
|
-
return `${baseMessageId.slice(0, Math.max(0, maxBaseLength))}${suffix}`;
|
|
11981
|
-
}
|
|
11982
|
-
__name(chunkMessageId, "chunkMessageId");
|
|
11983
|
-
function stripTrailTextBlocks(trail) {
|
|
11984
|
-
if (!Array.isArray(trail)) return null;
|
|
11985
|
-
return trail.filter((block) => {
|
|
11986
|
-
if (!block || typeof block !== "object") return true;
|
|
11987
|
-
return block.kind !== "text";
|
|
11988
|
-
});
|
|
11989
|
-
}
|
|
11990
|
-
__name(stripTrailTextBlocks, "stripTrailTextBlocks");
|
|
11991
|
-
function buildChunkedMessagePartMetadata(input) {
|
|
11992
|
-
if (input.count <= 1) return { ...input.metadata ?? {} };
|
|
11993
|
-
const chunk = {
|
|
11994
|
-
type: "text",
|
|
11995
|
-
index: input.index,
|
|
11996
|
-
count: input.count,
|
|
11997
|
-
...input.groupId ? { groupId: input.groupId } : {}
|
|
11998
|
-
};
|
|
11999
|
-
if (input.index >= input.count) {
|
|
12000
|
-
const metadata = { ...input.metadata ?? {} };
|
|
12001
|
-
const trail = stripTrailTextBlocks(metadata.turnTrail);
|
|
12002
|
-
if (trail) {
|
|
12003
|
-
if (trail.length > 0) metadata.turnTrail = trail;
|
|
12004
|
-
else delete metadata.turnTrail;
|
|
12005
|
-
}
|
|
12006
|
-
return {
|
|
12007
|
-
...metadata,
|
|
12008
|
-
messageChunk: chunk
|
|
12009
|
-
};
|
|
12010
|
-
}
|
|
12011
|
-
const {
|
|
12012
|
-
turnSemantics: _turnSemantics,
|
|
12013
|
-
turnTrail: _turnTrail,
|
|
12014
|
-
...rest
|
|
12015
|
-
} = input.metadata ?? {};
|
|
12016
|
-
return {
|
|
12017
|
-
...rest,
|
|
12018
|
-
turnSemantics: "progress",
|
|
12019
|
-
replyBehavior: "suppress_auto_reply",
|
|
12020
|
-
messageChunk: chunk
|
|
12021
|
-
};
|
|
12022
|
-
}
|
|
12023
|
-
__name(buildChunkedMessagePartMetadata, "buildChunkedMessagePartMetadata");
|
|
12024
|
-
async function sendMessageWithRetryChunked(client, conversationId, text, options, retryOptions = {}, chunkingOptions = {}) {
|
|
12025
|
-
const chunks = splitTextByUtf8Bytes(
|
|
12026
|
-
text,
|
|
12027
|
-
chunkingOptions.maxTextBytes ?? DEFAULT_CHUNKED_MESSAGE_TEXT_MAX_BYTES
|
|
12028
|
-
);
|
|
12029
|
-
const alreadyDelivered = chunkingOptions.deliveredMessageIds ?? [];
|
|
12030
|
-
const resumable = chunkingOptions.resumable === true || alreadyDelivered.length > 0;
|
|
12031
|
-
if (chunks.length === 1) {
|
|
12032
|
-
if (alreadyDelivered.length > 0) {
|
|
12033
|
-
throw new ChunkedSendMessageError({
|
|
12034
|
-
cause: new Error(
|
|
12035
|
-
`Resume cursor holds ${alreadyDelivered.length} part(s) but the text now fits in one message`
|
|
12036
|
-
),
|
|
12037
|
-
deliveredMessageIds: alreadyDelivered,
|
|
12038
|
-
failedPart: 1,
|
|
12039
|
-
totalParts: 1
|
|
12040
|
-
});
|
|
12041
|
-
}
|
|
12042
|
-
const result = await sendMessageWithRetry(client, conversationId, text, options, retryOptions);
|
|
12043
|
-
return { messageIds: [result.messageId] };
|
|
12044
|
-
}
|
|
12045
|
-
const rootMessageId = options?.messageId ?? randomUUID6();
|
|
12046
|
-
const parts = chunks.map((text2, index) => ({ text: text2, options: {
|
|
12047
|
-
...options ?? {},
|
|
12048
|
-
messageId: chunkMessageId(rootMessageId, index + 1),
|
|
12049
|
-
metadata: buildChunkedMessagePartMetadata({ groupId: rootMessageId, metadata: options?.metadata, index: index + 1, count: chunks.length })
|
|
12050
|
-
} }));
|
|
12051
|
-
const group = await client.prepareMessageGroup(conversationId, rootMessageId, parts, retryOptions);
|
|
12052
|
-
const groupId = group.id;
|
|
12053
|
-
const cancel = /* @__PURE__ */ __name(() => {
|
|
12054
|
-
void client.cancelMessageGroup(groupId).catch(() => {
|
|
12055
|
-
});
|
|
12056
|
-
}, "cancel");
|
|
12057
|
-
retryOptions.signal?.addEventListener("abort", cancel, { once: true });
|
|
12058
|
-
try {
|
|
12059
|
-
const startIndex = Math.min(alreadyDelivered.length, chunks.length);
|
|
12060
|
-
const messageIds = [...alreadyDelivered.slice(0, startIndex)];
|
|
12061
|
-
for (let index = startIndex; index < chunks.length; index += 1) {
|
|
12062
|
-
const part = index + 1;
|
|
12063
|
-
try {
|
|
12064
|
-
if (retryOptions.signal?.aborted) throw new CanonApiError(409, JSON.stringify({ code: "OPERATION_PENDING", message: "Reply delivery was interrupted" }));
|
|
12065
|
-
const result = await group.sendPart(index, retryOptions);
|
|
12066
|
-
messageIds.push(result.messageId);
|
|
12067
|
-
} catch (error) {
|
|
12068
|
-
if (!resumable) throw error;
|
|
12069
|
-
throw new ChunkedSendMessageError({
|
|
12070
|
-
cause: error,
|
|
12071
|
-
deliveredMessageIds: messageIds,
|
|
12072
|
-
failedPart: part,
|
|
12073
|
-
totalParts: chunks.length
|
|
12074
|
-
});
|
|
12075
|
-
}
|
|
12076
|
-
}
|
|
12077
|
-
return { messageIds };
|
|
12078
|
-
} finally {
|
|
12079
|
-
retryOptions.signal?.removeEventListener("abort", cancel);
|
|
12080
|
-
if (retryOptions.signal?.aborted) await client.cancelMessageGroup(groupId);
|
|
12081
|
-
}
|
|
12082
|
-
}
|
|
12083
|
-
__name(sendMessageWithRetryChunked, "sendMessageWithRetryChunked");
|
|
11145
|
+
__name(splitTextWithinBytes, "splitTextWithinBytes");
|
|
12084
11146
|
|
|
12085
11147
|
// ../core/src/cli-metadata.ts
|
|
12086
11148
|
import { readFileSync as readFileSync3, realpathSync } from "node:fs";
|
|
@@ -12144,7 +11206,7 @@ function runCli(moduleUrl, main, onError, metadata) {
|
|
|
12144
11206
|
__name(runCli, "runCli");
|
|
12145
11207
|
|
|
12146
11208
|
// ../core/src/completed-output-journal.ts
|
|
12147
|
-
import { createHash as createHash4, randomUUID as
|
|
11209
|
+
import { createHash as createHash4, randomUUID as randomUUID6 } from "node:crypto";
|
|
12148
11210
|
import {
|
|
12149
11211
|
closeSync as closeSync3,
|
|
12150
11212
|
existsSync as existsSync2,
|
|
@@ -12221,7 +11283,7 @@ function createCompletedOutputJournal(directory, scope5, options) {
|
|
|
12221
11283
|
if (readFileSync4(path, "utf8") !== serialized) throw new Error(`Completed ${label} output cannot be replaced`);
|
|
12222
11284
|
return;
|
|
12223
11285
|
}
|
|
12224
|
-
const temporary = `${path.slice(0, -5)}.${process.pid}.${
|
|
11286
|
+
const temporary = `${path.slice(0, -5)}.${process.pid}.${randomUUID6()}.tmp`;
|
|
12225
11287
|
try {
|
|
12226
11288
|
const fd = openSync3(temporary, "wx", 384);
|
|
12227
11289
|
try {
|
|
@@ -12261,12 +11323,6 @@ function createCompletedOutputJournal(directory, scope5, options) {
|
|
|
12261
11323
|
};
|
|
12262
11324
|
}
|
|
12263
11325
|
__name(createCompletedOutputJournal, "createCompletedOutputJournal");
|
|
12264
|
-
function assertCompletedOutputAudience(record6, current, label) {
|
|
12265
|
-
if (!record6.audience || !current || record6.audience.membershipRevision !== void 0 && record6.audience.membershipRevision !== current.membershipRevision || JSON.stringify([...record6.audience.memberIds].sort()) !== JSON.stringify([...current.memberIds].sort())) {
|
|
12266
|
-
throw new Error(`Completed ${label} output audience changed; operator reconciliation is required`);
|
|
12267
|
-
}
|
|
12268
|
-
}
|
|
12269
|
-
__name(assertCompletedOutputAudience, "assertCompletedOutputAudience");
|
|
12270
11326
|
|
|
12271
11327
|
// src/bounded-file-read.ts
|
|
12272
11328
|
var BoundedFileReadError = class extends Error {
|
|
@@ -12545,7 +11601,7 @@ async function materializeAttachment(attachment, options) {
|
|
|
12545
11601
|
if (!response.body) {
|
|
12546
11602
|
throw new Error("Canon media response had no body");
|
|
12547
11603
|
}
|
|
12548
|
-
const tempPath = `${path}.${process.pid}.${
|
|
11604
|
+
const tempPath = `${path}.${process.pid}.${randomUUID7()}.part`;
|
|
12549
11605
|
const limiter = byteLimitTransform(maxBytes);
|
|
12550
11606
|
try {
|
|
12551
11607
|
await pipeline2(
|
|
@@ -12641,7 +11697,7 @@ async function uploadMediaFile(client, conversationId, filePath, options) {
|
|
|
12641
11697
|
const media = await client.getFileMediaPipeline(options?.fetchImpl);
|
|
12642
11698
|
const [attachment] = await media.prepare({
|
|
12643
11699
|
conversationId,
|
|
12644
|
-
attachmentId: options?.attachmentId ??
|
|
11700
|
+
attachmentId: options?.attachmentId ?? randomUUID7(),
|
|
12645
11701
|
files: [{ source: filePath, descriptor: {
|
|
12646
11702
|
mimeType,
|
|
12647
11703
|
sizeBytes: fileStat.size,
|
|
@@ -12670,7 +11726,7 @@ async function sendMediaFileMessage(client, conversationId, filePath, text = "",
|
|
|
12670
11726
|
const current = await client.getConversation(conversationId);
|
|
12671
11727
|
return !!current && originalMembers.size > 0 && current.memberIds.every((id2) => originalMembers.has(id2)) && canPublish();
|
|
12672
11728
|
} : void 0;
|
|
12673
|
-
const messageId = sendOptions.messageId ??
|
|
11729
|
+
const messageId = sendOptions.messageId ?? randomUUID7();
|
|
12674
11730
|
const pipeline3 = await client.getFileMediaPipeline(fetchImpl);
|
|
12675
11731
|
const delivered = await pipeline3.send({
|
|
12676
11732
|
conversationId,
|
|
@@ -12845,21 +11901,14 @@ export {
|
|
|
12845
11901
|
acquireLock,
|
|
12846
11902
|
clearPendingRegistration,
|
|
12847
11903
|
ensureAgentProfile,
|
|
12848
|
-
ApprovalManager,
|
|
12849
|
-
reportNoReplyOutcome,
|
|
12850
|
-
resolveTurnVerbosity,
|
|
12851
11904
|
initRTDBAuth,
|
|
12852
11905
|
renderCanonHostInboundContent,
|
|
12853
11906
|
createRuntimeStatePublisher,
|
|
12854
11907
|
isPendingCanonOperation,
|
|
12855
|
-
|
|
12856
|
-
splitTextByUtf8Bytes,
|
|
12857
|
-
buildChunkedMessagePartMetadata,
|
|
12858
|
-
sendMessageWithRetryChunked,
|
|
11908
|
+
splitTextWithinBytes,
|
|
12859
11909
|
readCliPackageVersion,
|
|
12860
11910
|
runCli,
|
|
12861
11911
|
createCompletedOutputJournal,
|
|
12862
|
-
assertCompletedOutputAudience,
|
|
12863
11912
|
BoundedFileReadError,
|
|
12864
11913
|
readBoundedRegularFileHandle,
|
|
12865
11914
|
DEFAULT_MEDIA_CACHE_DIR,
|