@ouro.bot/cli 0.1.0-alpha.450 → 0.1.0-alpha.451
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/changelog.json +8 -0
- package/dist/heart/daemon/cli-exec.js +222 -1
- package/dist/heart/daemon/cli-help.js +19 -2
- package/dist/heart/daemon/cli-parse.js +44 -3
- package/dist/heart/daemon/doctor.js +1 -1
- package/dist/heart/daemon/sense-manager.js +29 -2
- package/dist/heart/identity.js +4 -1
- package/dist/heart/outlook/outlook-http-hooks.js +2 -0
- package/dist/heart/outlook/outlook-http-routes.js +14 -2
- package/dist/heart/outlook/outlook-read.js +4 -1
- package/dist/heart/outlook/readers/mail.js +203 -0
- package/dist/heart/sense-truth.js +8 -4
- package/dist/heart/turn-context.js +14 -4
- package/dist/mailroom/blob-store.js +154 -0
- package/dist/mailroom/core.js +387 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +230 -0
- package/dist/mailroom/mbox-import.js +105 -0
- package/dist/mailroom/reader.js +150 -0
- package/dist/mailroom/smtp-ingress.js +176 -0
- package/dist/mind/friends/channel.js +9 -0
- package/dist/mind/friends/types.js +1 -1
- package/dist/mind/prompt.js +16 -4
- package/dist/outlook-ui/assets/index-BXw3xmUo.js +61 -0
- package/dist/outlook-ui/assets/index-D4Wg-o8Z.css +1 -0
- package/dist/outlook-ui/index.html +2 -2
- package/dist/repertoire/tools-mail.js +209 -0
- package/dist/senses/commands.js +1 -1
- package/package.json +6 -1
- package/dist/outlook-ui/assets/index-BAcU08c-.css +0 -1
- package/dist/outlook-ui/assets/index-D7l3l4vY.js +0 -61
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readMailView = readMailView;
|
|
4
|
+
exports.readMailMessageView = readMailMessageView;
|
|
5
|
+
const runtime_1 = require("../../../nerves/runtime");
|
|
6
|
+
const file_store_1 = require("../../../mailroom/file-store");
|
|
7
|
+
const reader_1 = require("../../../mailroom/reader");
|
|
8
|
+
const OUTLOOK_MAIL_LIST_LIMIT = 50;
|
|
9
|
+
const OUTLOOK_MAIL_COUNT_LIMIT = 500;
|
|
10
|
+
const OUTLOOK_MAIL_BODY_LIMIT = 12_000;
|
|
11
|
+
function emptyFolders() {
|
|
12
|
+
return [
|
|
13
|
+
{ id: "imbox", label: "Imbox", count: 0 },
|
|
14
|
+
{ id: "screener", label: "Screener", count: 0 },
|
|
15
|
+
{ id: "delegated", label: "Delegated", count: 0 },
|
|
16
|
+
{ id: "native", label: "Native", count: 0 },
|
|
17
|
+
];
|
|
18
|
+
}
|
|
19
|
+
function unavailableMailView(agentName, status, error) {
|
|
20
|
+
return {
|
|
21
|
+
status,
|
|
22
|
+
agentName,
|
|
23
|
+
mailboxAddress: null,
|
|
24
|
+
generatedAt: new Date().toISOString(),
|
|
25
|
+
store: null,
|
|
26
|
+
folders: emptyFolders(),
|
|
27
|
+
messages: [],
|
|
28
|
+
accessLog: [],
|
|
29
|
+
error,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function unavailableMessageView(agentName, status, error) {
|
|
33
|
+
return {
|
|
34
|
+
status,
|
|
35
|
+
agentName,
|
|
36
|
+
mailboxAddress: null,
|
|
37
|
+
generatedAt: new Date().toISOString(),
|
|
38
|
+
message: null,
|
|
39
|
+
accessLog: [],
|
|
40
|
+
error,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function mailSummary(message) {
|
|
44
|
+
return {
|
|
45
|
+
id: message.id,
|
|
46
|
+
subject: message.private.subject,
|
|
47
|
+
from: message.private.from,
|
|
48
|
+
to: message.private.to,
|
|
49
|
+
cc: message.private.cc,
|
|
50
|
+
date: message.private.date ?? null,
|
|
51
|
+
receivedAt: message.receivedAt,
|
|
52
|
+
snippet: message.private.snippet,
|
|
53
|
+
placement: message.placement,
|
|
54
|
+
compartmentKind: message.compartmentKind,
|
|
55
|
+
ownerEmail: message.ownerEmail ?? null,
|
|
56
|
+
source: message.source ?? null,
|
|
57
|
+
recipient: message.recipient,
|
|
58
|
+
attachmentCount: message.private.attachments.length,
|
|
59
|
+
untrustedContentWarning: message.private.untrustedContentWarning,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function buildFolders(messages) {
|
|
63
|
+
const folders = [
|
|
64
|
+
{ id: "imbox", label: "Imbox", count: messages.filter((message) => message.placement === "imbox").length },
|
|
65
|
+
{ id: "screener", label: "Screener", count: messages.filter((message) => message.placement === "screener").length },
|
|
66
|
+
{ id: "delegated", label: "Delegated", count: messages.filter((message) => message.compartmentKind === "delegated").length },
|
|
67
|
+
{ id: "native", label: "Native", count: messages.filter((message) => message.compartmentKind === "native").length },
|
|
68
|
+
];
|
|
69
|
+
const sourceCounts = new Map();
|
|
70
|
+
for (const message of messages) {
|
|
71
|
+
if (!message.source)
|
|
72
|
+
continue;
|
|
73
|
+
sourceCounts.set(message.source, (sourceCounts.get(message.source) ?? 0) + 1);
|
|
74
|
+
}
|
|
75
|
+
for (const [source, count] of [...sourceCounts.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
76
|
+
folders.push({ id: `source:${source}`, label: source.toUpperCase(), count });
|
|
77
|
+
}
|
|
78
|
+
return folders;
|
|
79
|
+
}
|
|
80
|
+
function accessEntries(entries) {
|
|
81
|
+
return entries
|
|
82
|
+
.slice()
|
|
83
|
+
.sort((left, right) => right.accessedAt.localeCompare(left.accessedAt))
|
|
84
|
+
.slice(0, 20)
|
|
85
|
+
.map((entry) => ({
|
|
86
|
+
id: entry.id,
|
|
87
|
+
messageId: entry.messageId ?? null,
|
|
88
|
+
threadId: entry.threadId ?? null,
|
|
89
|
+
tool: entry.tool,
|
|
90
|
+
reason: entry.reason,
|
|
91
|
+
accessedAt: entry.accessedAt,
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
function emitMailRead(agentName, mode, status) {
|
|
95
|
+
(0, runtime_1.emitNervesEvent)({
|
|
96
|
+
component: "heart",
|
|
97
|
+
event: "heart.outlook_mail_read",
|
|
98
|
+
message: "reading Outlook mail surface",
|
|
99
|
+
meta: { agentName, mode, status },
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
function statusFromReaderFailure(reason) {
|
|
103
|
+
return reason;
|
|
104
|
+
}
|
|
105
|
+
async function readMailView(agentName) {
|
|
106
|
+
const resolved = (0, reader_1.resolveMailroomReader)(agentName);
|
|
107
|
+
if (!resolved.ok) {
|
|
108
|
+
const status = statusFromReaderFailure(resolved.reason);
|
|
109
|
+
emitMailRead(agentName, "list", status);
|
|
110
|
+
return unavailableMailView(agentName, status, resolved.error);
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const stored = await resolved.store.listMessages({ agentId: agentName, limit: OUTLOOK_MAIL_COUNT_LIMIT });
|
|
114
|
+
const decrypted = (0, file_store_1.decryptMessages)(stored, resolved.config.privateKeys);
|
|
115
|
+
const summaries = decrypted.map(mailSummary);
|
|
116
|
+
await resolved.store.recordAccess({
|
|
117
|
+
agentId: agentName,
|
|
118
|
+
tool: "outlook_mail_list",
|
|
119
|
+
reason: "outlook read-only mailbox",
|
|
120
|
+
});
|
|
121
|
+
const accessLog = accessEntries(await resolved.store.listAccessLog(agentName));
|
|
122
|
+
emitMailRead(agentName, "list", "ready");
|
|
123
|
+
return {
|
|
124
|
+
status: "ready",
|
|
125
|
+
agentName,
|
|
126
|
+
mailboxAddress: resolved.config.mailboxAddress,
|
|
127
|
+
generatedAt: new Date().toISOString(),
|
|
128
|
+
store: {
|
|
129
|
+
kind: resolved.storeKind,
|
|
130
|
+
label: resolved.storeLabel,
|
|
131
|
+
},
|
|
132
|
+
folders: buildFolders(summaries),
|
|
133
|
+
messages: summaries.slice(0, OUTLOOK_MAIL_LIST_LIMIT),
|
|
134
|
+
accessLog,
|
|
135
|
+
error: null,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
140
|
+
emitMailRead(agentName, "list", "error");
|
|
141
|
+
return unavailableMailView(agentName, "error", message);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async function readMailMessageView(agentName, messageId) {
|
|
145
|
+
const resolved = (0, reader_1.resolveMailroomReader)(agentName);
|
|
146
|
+
if (!resolved.ok) {
|
|
147
|
+
const status = statusFromReaderFailure(resolved.reason);
|
|
148
|
+
emitMailRead(agentName, "message", status);
|
|
149
|
+
return unavailableMessageView(agentName, status, resolved.error);
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
const stored = await resolved.store.getMessage(messageId);
|
|
153
|
+
if (!stored || stored.agentId !== agentName) {
|
|
154
|
+
emitMailRead(agentName, "message", "not-found");
|
|
155
|
+
return {
|
|
156
|
+
status: "not-found",
|
|
157
|
+
agentName,
|
|
158
|
+
mailboxAddress: resolved.config.mailboxAddress,
|
|
159
|
+
generatedAt: new Date().toISOString(),
|
|
160
|
+
message: null,
|
|
161
|
+
accessLog: accessEntries(await resolved.store.listAccessLog(agentName)),
|
|
162
|
+
error: `No visible mail message found for ${messageId}.`,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
const decrypted = (0, file_store_1.decryptMessages)([stored], resolved.config.privateKeys)[0];
|
|
166
|
+
const access = await resolved.store.recordAccess({
|
|
167
|
+
agentId: agentName,
|
|
168
|
+
messageId,
|
|
169
|
+
tool: "outlook_mail_message",
|
|
170
|
+
reason: "outlook read-only message body",
|
|
171
|
+
});
|
|
172
|
+
const body = decrypted.private.text.length > OUTLOOK_MAIL_BODY_LIMIT
|
|
173
|
+
? decrypted.private.text.slice(0, OUTLOOK_MAIL_BODY_LIMIT)
|
|
174
|
+
: decrypted.private.text;
|
|
175
|
+
const detail = {
|
|
176
|
+
...mailSummary(decrypted),
|
|
177
|
+
text: body,
|
|
178
|
+
htmlAvailable: typeof decrypted.private.html === "string" && decrypted.private.html.length > 0,
|
|
179
|
+
bodyTruncated: decrypted.private.text.length > OUTLOOK_MAIL_BODY_LIMIT,
|
|
180
|
+
attachments: decrypted.private.attachments,
|
|
181
|
+
access: {
|
|
182
|
+
tool: access.tool,
|
|
183
|
+
reason: access.reason,
|
|
184
|
+
accessedAt: access.accessedAt,
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
emitMailRead(agentName, "message", "ready");
|
|
188
|
+
return {
|
|
189
|
+
status: "ready",
|
|
190
|
+
agentName,
|
|
191
|
+
mailboxAddress: resolved.config.mailboxAddress,
|
|
192
|
+
generatedAt: new Date().toISOString(),
|
|
193
|
+
message: detail,
|
|
194
|
+
accessLog: accessEntries(await resolved.store.listAccessLog(agentName)),
|
|
195
|
+
error: null,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
200
|
+
emitMailRead(agentName, "message", "error");
|
|
201
|
+
return unavailableMessageView(agentName, "error", message);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -7,12 +7,16 @@ const SENSES = [
|
|
|
7
7
|
{ sense: "cli", label: "CLI", daemonManaged: false },
|
|
8
8
|
{ sense: "teams", label: "Teams", daemonManaged: true },
|
|
9
9
|
{ sense: "bluebubbles", label: "BlueBubbles", daemonManaged: true },
|
|
10
|
+
{ sense: "mail", label: "Mail", daemonManaged: true },
|
|
10
11
|
];
|
|
11
12
|
function configuredSenses(senses) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const configured = senses ?? {};
|
|
14
|
+
return {
|
|
15
|
+
...configured,
|
|
16
|
+
cli: configured.cli ?? { ...identity_1.DEFAULT_AGENT_SENSES.cli },
|
|
17
|
+
teams: configured.teams ?? { ...identity_1.DEFAULT_AGENT_SENSES.teams },
|
|
18
|
+
bluebubbles: configured.bluebubbles ?? { ...identity_1.DEFAULT_AGENT_SENSES.bluebubbles },
|
|
19
|
+
mail: configured.mail ?? { ...identity_1.DEFAULT_AGENT_SENSES.mail },
|
|
16
20
|
};
|
|
17
21
|
}
|
|
18
22
|
function resolveStatus(enabled, daemonManaged, runtimeInfo) {
|
|
@@ -141,18 +141,24 @@ function hasTextField(record, key) {
|
|
|
141
141
|
}
|
|
142
142
|
function readSenseStatusLines() {
|
|
143
143
|
const config = (0, identity_1.loadAgentConfig)();
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
const configuredSenses = config.senses ?? {};
|
|
145
|
+
const senses = {
|
|
146
|
+
...configuredSenses,
|
|
147
|
+
cli: configuredSenses.cli ?? { enabled: true },
|
|
148
|
+
teams: configuredSenses.teams ?? { enabled: false },
|
|
149
|
+
bluebubbles: configuredSenses.bluebubbles ?? { enabled: false },
|
|
150
|
+
mail: configuredSenses.mail ?? { enabled: false },
|
|
148
151
|
};
|
|
149
152
|
const payload = (0, config_1.loadConfig)();
|
|
150
153
|
const teams = payload.teams;
|
|
151
154
|
const bluebubbles = payload.bluebubbles;
|
|
155
|
+
const mailroom = payload.mailroom;
|
|
156
|
+
const privateKeys = mailroom?.privateKeys;
|
|
152
157
|
const configured = {
|
|
153
158
|
cli: true,
|
|
154
159
|
teams: hasTextField(teams, "clientId") && hasTextField(teams, "clientSecret") && hasTextField(teams, "tenantId"),
|
|
155
160
|
bluebubbles: hasTextField(bluebubbles, "serverUrl") && hasTextField(bluebubbles, "password"),
|
|
161
|
+
mail: hasTextField(mailroom, "mailboxAddress") && !!privateKeys && typeof privateKeys === "object" && !Array.isArray(privateKeys),
|
|
156
162
|
};
|
|
157
163
|
const rows = [
|
|
158
164
|
{ label: "CLI", status: "interactive" },
|
|
@@ -164,6 +170,10 @@ function readSenseStatusLines() {
|
|
|
164
170
|
label: "BlueBubbles",
|
|
165
171
|
status: !senses.bluebubbles.enabled ? "disabled" : configured.bluebubbles ? "ready" : "not_attached",
|
|
166
172
|
},
|
|
173
|
+
{
|
|
174
|
+
label: "Mail",
|
|
175
|
+
status: !senses.mail.enabled ? "disabled" : configured.mail ? "ready" : "needs_config",
|
|
176
|
+
},
|
|
167
177
|
];
|
|
168
178
|
return rows.map((row) => `- ${row.label}: ${row.status}`);
|
|
169
179
|
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AzureBlobMailroomStore = void 0;
|
|
4
|
+
exports.decryptBlobMessages = decryptBlobMessages;
|
|
5
|
+
const runtime_1 = require("../nerves/runtime");
|
|
6
|
+
const core_1 = require("./core");
|
|
7
|
+
function compareNewestFirst(left, right) {
|
|
8
|
+
return Date.parse(right.receivedAt) - Date.parse(left.receivedAt);
|
|
9
|
+
}
|
|
10
|
+
function blobText(value) {
|
|
11
|
+
return Buffer.from(`${JSON.stringify(value, null, 2)}\n`, "utf-8");
|
|
12
|
+
}
|
|
13
|
+
async function downloadJson(blob) {
|
|
14
|
+
if (!await blob.exists())
|
|
15
|
+
return null;
|
|
16
|
+
return JSON.parse((await blob.downloadToBuffer()).toString("utf-8"));
|
|
17
|
+
}
|
|
18
|
+
class AzureBlobMailroomStore {
|
|
19
|
+
serviceClient;
|
|
20
|
+
containerName;
|
|
21
|
+
containerReady = null;
|
|
22
|
+
constructor(options) {
|
|
23
|
+
this.serviceClient = options.serviceClient;
|
|
24
|
+
this.containerName = options.containerName;
|
|
25
|
+
(0, runtime_1.emitNervesEvent)({
|
|
26
|
+
component: "senses",
|
|
27
|
+
event: "senses.mail_blob_store_init",
|
|
28
|
+
message: "azure blob mailroom store initialized",
|
|
29
|
+
meta: { containerName: this.containerName },
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
get container() {
|
|
33
|
+
return this.serviceClient.getContainerClient(this.containerName);
|
|
34
|
+
}
|
|
35
|
+
async ensureContainer() {
|
|
36
|
+
if (!this.containerReady) {
|
|
37
|
+
this.containerReady = this.container.createIfNotExists().then(() => undefined);
|
|
38
|
+
}
|
|
39
|
+
await this.containerReady;
|
|
40
|
+
}
|
|
41
|
+
messageBlob(id) {
|
|
42
|
+
return this.container.getBlockBlobClient(`messages/${id}.json`);
|
|
43
|
+
}
|
|
44
|
+
rawBlob(objectName) {
|
|
45
|
+
return this.container.getBlockBlobClient(objectName);
|
|
46
|
+
}
|
|
47
|
+
accessLogBlob(agentId) {
|
|
48
|
+
return this.container.getBlockBlobClient(`access-log/${agentId}.jsonl`);
|
|
49
|
+
}
|
|
50
|
+
async putRawMessage(input) {
|
|
51
|
+
await this.ensureContainer();
|
|
52
|
+
const { message, rawPayload } = await (0, core_1.buildStoredMailMessage)(input);
|
|
53
|
+
const existing = await downloadJson(this.messageBlob(message.id));
|
|
54
|
+
if (existing) {
|
|
55
|
+
(0, runtime_1.emitNervesEvent)({
|
|
56
|
+
component: "senses",
|
|
57
|
+
event: "senses.mail_blob_store_dedupe",
|
|
58
|
+
message: "azure blob mailroom store deduped existing message",
|
|
59
|
+
meta: { id: message.id, agentId: message.agentId },
|
|
60
|
+
});
|
|
61
|
+
return { created: false, message: existing };
|
|
62
|
+
}
|
|
63
|
+
await this.rawBlob(message.rawObject).uploadData(blobText(rawPayload));
|
|
64
|
+
await this.messageBlob(message.id).uploadData(blobText(message));
|
|
65
|
+
(0, runtime_1.emitNervesEvent)({
|
|
66
|
+
component: "senses",
|
|
67
|
+
event: "senses.mail_blob_store_message_written",
|
|
68
|
+
message: "azure blob mailroom store wrote message",
|
|
69
|
+
meta: { id: message.id, agentId: message.agentId },
|
|
70
|
+
});
|
|
71
|
+
return { created: true, message };
|
|
72
|
+
}
|
|
73
|
+
async getMessage(id) {
|
|
74
|
+
await this.ensureContainer();
|
|
75
|
+
const message = await downloadJson(this.messageBlob(id));
|
|
76
|
+
(0, runtime_1.emitNervesEvent)({
|
|
77
|
+
component: "senses",
|
|
78
|
+
event: "senses.mail_blob_store_message_read",
|
|
79
|
+
message: "azure blob mailroom store read message",
|
|
80
|
+
meta: { id, found: message !== null },
|
|
81
|
+
});
|
|
82
|
+
return message;
|
|
83
|
+
}
|
|
84
|
+
async listMessages(filters) {
|
|
85
|
+
await this.ensureContainer();
|
|
86
|
+
const messages = [];
|
|
87
|
+
for await (const item of this.container.listBlobsFlat({ prefix: "messages/" })) {
|
|
88
|
+
const message = await downloadJson(this.container.getBlockBlobClient(item.name));
|
|
89
|
+
if (message)
|
|
90
|
+
messages.push(message);
|
|
91
|
+
}
|
|
92
|
+
const filtered = messages
|
|
93
|
+
.filter((message) => message.agentId === filters.agentId)
|
|
94
|
+
.filter((message) => filters.placement ? message.placement === filters.placement : true)
|
|
95
|
+
.filter((message) => filters.compartmentKind ? message.compartmentKind === filters.compartmentKind : true)
|
|
96
|
+
.filter((message) => filters.source ? message.source === filters.source : true)
|
|
97
|
+
.sort(compareNewestFirst)
|
|
98
|
+
.slice(0, filters.limit ?? 20);
|
|
99
|
+
(0, runtime_1.emitNervesEvent)({
|
|
100
|
+
component: "senses",
|
|
101
|
+
event: "senses.mail_blob_store_messages_listed",
|
|
102
|
+
message: "azure blob mailroom store listed messages",
|
|
103
|
+
meta: { agentId: filters.agentId, count: filtered.length },
|
|
104
|
+
});
|
|
105
|
+
return filtered;
|
|
106
|
+
}
|
|
107
|
+
async readRawPayload(objectName) {
|
|
108
|
+
await this.ensureContainer();
|
|
109
|
+
const payload = await downloadJson(this.rawBlob(objectName));
|
|
110
|
+
(0, runtime_1.emitNervesEvent)({
|
|
111
|
+
component: "senses",
|
|
112
|
+
event: "senses.mail_blob_store_raw_read",
|
|
113
|
+
message: "azure blob mailroom store read raw payload",
|
|
114
|
+
meta: { objectName, found: payload !== null },
|
|
115
|
+
});
|
|
116
|
+
return payload;
|
|
117
|
+
}
|
|
118
|
+
async recordAccess(entry) {
|
|
119
|
+
await this.ensureContainer();
|
|
120
|
+
const complete = {
|
|
121
|
+
...entry,
|
|
122
|
+
id: `access_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
123
|
+
accessedAt: new Date().toISOString(),
|
|
124
|
+
};
|
|
125
|
+
const blob = this.accessLogBlob(entry.agentId);
|
|
126
|
+
const existing = await downloadJson(blob).catch(() => null);
|
|
127
|
+
const entries = Array.isArray(existing) ? existing : [];
|
|
128
|
+
entries.push(complete);
|
|
129
|
+
await blob.uploadData(blobText(entries));
|
|
130
|
+
(0, runtime_1.emitNervesEvent)({
|
|
131
|
+
component: "senses",
|
|
132
|
+
event: "senses.mail_blob_access_recorded",
|
|
133
|
+
message: "azure blob mail access recorded",
|
|
134
|
+
meta: { agentId: entry.agentId, messageId: entry.messageId ?? null, tool: entry.tool },
|
|
135
|
+
});
|
|
136
|
+
return complete;
|
|
137
|
+
}
|
|
138
|
+
async listAccessLog(agentId) {
|
|
139
|
+
await this.ensureContainer();
|
|
140
|
+
const entries = await downloadJson(this.accessLogBlob(agentId));
|
|
141
|
+
const safeEntries = Array.isArray(entries) ? entries : [];
|
|
142
|
+
(0, runtime_1.emitNervesEvent)({
|
|
143
|
+
component: "senses",
|
|
144
|
+
event: "senses.mail_blob_access_log_listed",
|
|
145
|
+
message: "azure blob mail access log listed",
|
|
146
|
+
meta: { agentId, count: safeEntries.length },
|
|
147
|
+
});
|
|
148
|
+
return safeEntries;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.AzureBlobMailroomStore = AzureBlobMailroomStore;
|
|
152
|
+
function decryptBlobMessages(messages, privateKeys) {
|
|
153
|
+
return messages.map((message) => (0, core_1.decryptStoredMailMessage)(message, privateKeys));
|
|
154
|
+
}
|