@ouro.bot/cli 0.1.0-alpha.730 → 0.1.0-alpha.731

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.
@@ -8,7 +8,6 @@ exports.renderCachedMessageSummary = renderCachedMessageSummary;
8
8
  exports.mergeCachedMailSearchDocuments = mergeCachedMailSearchDocuments;
9
9
  exports.searchSuccessfulImportArchives = searchSuccessfulImportArchives;
10
10
  const node_fs_1 = __importDefault(require("node:fs"));
11
- const node_crypto_1 = require("node:crypto");
12
11
  const friends_1 = require("@ouro.bot/friends");
13
12
  const file_store_1 = require("../mailroom/file-store");
14
13
  const reader_1 = require("../mailroom/reader");
@@ -25,8 +24,8 @@ const credential_access_1 = require("./credential-access");
25
24
  const background_operations_1 = require("../heart/background-operations");
26
25
  const mail_import_discovery_1 = require("../heart/mail-import-discovery");
27
26
  const identity_1 = require("../heart/identity");
28
- const MAIL_SEARCH_INDEX_FETCH_CONCURRENCY = 80;
29
- const MAIL_SEARCH_INDEX_BATCH_SIZE = 500;
27
+ const blob_store_1 = require("../mailroom/blob-store");
28
+ const hosted_cache_sync_1 = require("../mailroom/hosted-cache-sync");
30
29
  function trustAllowsMailRead(ctx) {
31
30
  const trustLevel = ctx?.context?.friend?.trustLevel;
32
31
  const allowed = trustLevel === undefined || (0, friends_1.isTrustedLevel)(trustLevel);
@@ -300,24 +299,6 @@ function appendDelegatedSearchCoverage(body, input) {
300
299
  ].filter(Boolean).join(" "),
301
300
  ].join("\n\n");
302
301
  }
303
- async function mapWithConcurrency(items, concurrency, worker) {
304
- /* v8 ignore next -- refresh callers pass only non-empty slices into the worker pool. @preserve */
305
- if (items.length === 0)
306
- return [];
307
- const results = new Array(items.length);
308
- let nextIndex = 0;
309
- const workerLoop = async () => {
310
- while (true) {
311
- const current = nextIndex;
312
- nextIndex += 1;
313
- if (current >= items.length)
314
- return;
315
- results[current] = await worker(items[current], current);
316
- }
317
- };
318
- await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, async () => workerLoop()));
319
- return results;
320
- }
321
302
  function mailListFilters(input) {
322
303
  return {
323
304
  agentId: input.agentId,
@@ -338,28 +319,6 @@ function mailSearchCoverageKey(input) {
338
319
  ...(input.source ? { source: input.source } : {}),
339
320
  };
340
321
  }
341
- function mailSearchCacheDocumentNeedsProjectionRefresh(document) {
342
- if (document.textProjectionVersion === search_cache_1.MAIL_SEARCH_TEXT_PROJECTION_VERSION)
343
- return false;
344
- return document.textExcerpt.trim().length === 0;
345
- }
346
- function mailSearchCoverageSnapshot(records) {
347
- const normalizedRecords = records
348
- .map((record) => ({
349
- id: record.id,
350
- receivedAt: record.receivedAt,
351
- placement: record.placement,
352
- compartmentKind: record.compartmentKind,
353
- source: record.source?.toLowerCase() ?? null,
354
- }))
355
- .sort((left, right) => left.id.localeCompare(right.id));
356
- return {
357
- visibleMessageCount: records.length,
358
- messageIndexFingerprint: (0, node_crypto_1.createHash)("sha256").update(JSON.stringify(normalizedRecords)).digest("hex"),
359
- ...(oldestReceivedAt(records) ? { oldestReceivedAt: oldestReceivedAt(records) } : {}),
360
- ...(newestReceivedAt(records) ? { newestReceivedAt: newestReceivedAt(records) } : {}),
361
- };
362
- }
363
322
  function mailSearchCoverageStalenessReason(record, currentSnapshot) {
364
323
  if (!record)
365
324
  return "hosted search index incomplete";
@@ -389,113 +348,6 @@ function mailSearchCoverageUnsearchableReason(record) {
389
348
  const noun = unsearchableCount === 1 ? "message was" : "messages were";
390
349
  return `${unsearchableCount} visible ${noun} not searchable because the index skipped missing/decryption-key mail`;
391
350
  }
392
- function newestReceivedAt(records) {
393
- return records.reduce((newest, record) => {
394
- if (!newest || Date.parse(record.receivedAt) > Date.parse(newest))
395
- return record.receivedAt;
396
- return newest;
397
- }, undefined);
398
- }
399
- function oldestReceivedAt(records) {
400
- return records.reduce((oldest, record) => {
401
- if (!oldest || Date.parse(record.receivedAt) < Date.parse(oldest))
402
- return record.receivedAt;
403
- return oldest;
404
- }, undefined);
405
- }
406
- async function refreshMailSearchIndex(input) {
407
- const filters = mailListFilters(input);
408
- const indexedRecords = await input.store.listMessageIndexRecords?.(filters);
409
- const visibleRecords = indexedRecords ?? (await input.store.listMessages(filters)).map((message) => ({
410
- schemaVersion: 1,
411
- id: message.id,
412
- agentId: message.agentId,
413
- compartmentKind: message.compartmentKind,
414
- placement: message.placement,
415
- ...(message.source ? { source: message.source } : {}),
416
- receivedAt: message.receivedAt,
417
- }));
418
- const visibleIds = new Set(visibleRecords.map((record) => record.id));
419
- const coverageSnapshot = mailSearchCoverageSnapshot(visibleRecords);
420
- const cachedForScope = (0, search_cache_1.searchMailSearchCache)({
421
- agentId: input.agentId,
422
- placement: input.placement,
423
- compartmentKind: input.scope,
424
- source: input.source,
425
- }, input.cacheOptions);
426
- const cachedVisibleIds = new Set(cachedForScope
427
- .filter((document) => visibleIds.has(document.messageId))
428
- .filter((document) => !mailSearchCacheDocumentNeedsProjectionRefresh(document))
429
- .map((document) => document.messageId));
430
- const idsToFetch = visibleRecords
431
- .filter((record) => !cachedVisibleIds.has(record.id))
432
- .map((record) => record.id);
433
- const failures = [];
434
- let fetchedCount = 0;
435
- let skippedCount = 0;
436
- for (let start = 0; start < idsToFetch.length; start += MAIL_SEARCH_INDEX_BATCH_SIZE) {
437
- const batchIds = idsToFetch.slice(start, start + MAIL_SEARCH_INDEX_BATCH_SIZE);
438
- const fetchedMessages = await mapWithConcurrency(batchIds, MAIL_SEARCH_INDEX_FETCH_CONCURRENCY, async (id) => {
439
- try {
440
- const message = input.store.getIndexedMessageById
441
- ? await input.store.getIndexedMessageById(id)
442
- : await input.store.getMessage(id);
443
- return { id, message, error: message ? null : "indexed message was not retrievable" };
444
- }
445
- catch (error) {
446
- return { id, message: null, error: error instanceof Error ? error.message : String(error) };
447
- }
448
- });
449
- failures.push(...fetchedMessages.filter((entry) => entry.error !== null));
450
- const fetchedStored = fetchedMessages
451
- .map((entry) => entry.message)
452
- .filter((message) => message !== null);
453
- const result = decryptVisibleMessages(fetchedStored, input.privateKeys);
454
- cacheDecryptedMessages(result.decrypted, input.cacheOptions);
455
- fetchedCount += fetchedStored.length;
456
- skippedCount += result.skipped.length;
457
- (0, runtime_1.emitNervesEvent)({
458
- component: "repertoire",
459
- event: "repertoire.mail_search_index_refresh_progress",
460
- message: "mail search index refresh cached a batch",
461
- meta: {
462
- agentId: input.agentId,
463
- fetched: fetchedCount,
464
- totalToFetch: idsToFetch.length,
465
- alreadyCached: cachedVisibleIds.size,
466
- failures: failures.length,
467
- },
468
- });
469
- }
470
- const refreshedCachedForScope = (0, search_cache_1.searchMailSearchCache)({
471
- agentId: input.agentId,
472
- placement: input.placement,
473
- compartmentKind: input.scope,
474
- source: input.source,
475
- }, input.cacheOptions).filter((document) => visibleIds.has(document.messageId));
476
- if (failures.length > 0) {
477
- const sample = failures.slice(0, 3).map((entry) => `${entry.id}: ${entry.error}`).join("; ");
478
- throw new Error(`mail search index refresh incomplete after fetching ${fetchedCount}/${idsToFetch.length} missing message(s); ${failures.length} fetch failed. first failure(s): ${sample}`);
479
- }
480
- const coverage = (0, search_cache_1.writeMailSearchCoverageRecord)({
481
- schemaVersion: 1,
482
- ...mailSearchCoverageKey(input),
483
- indexedAt: new Date().toISOString(),
484
- visibleMessageCount: visibleRecords.length,
485
- cachedMessageCount: refreshedCachedForScope.length,
486
- decryptableMessageCount: refreshedCachedForScope.length,
487
- skippedMessageCount: skippedCount,
488
- messageIndexFingerprint: coverageSnapshot.messageIndexFingerprint,
489
- textProjectionVersion: search_cache_1.MAIL_SEARCH_TEXT_PROJECTION_VERSION,
490
- ...(coverageSnapshot.oldestReceivedAt ? { oldestReceivedAt: coverageSnapshot.oldestReceivedAt } : {}),
491
- ...(coverageSnapshot.newestReceivedAt ? { newestReceivedAt: coverageSnapshot.newestReceivedAt } : {}),
492
- }, input.cacheOptions);
493
- return {
494
- coverage,
495
- fetched: fetchedCount,
496
- alreadyCached: cachedVisibleIds.size,
497
- };
498
- }
499
351
  function accessProvenance(message) {
500
352
  const provenance = (0, core_1.describeMailProvenance)(message);
501
353
  return {
@@ -1390,7 +1242,7 @@ exports.mailToolDefinitions = [
1390
1242
  }
1391
1243
  if (hostedDelegatedSearch && storedCoverageRecord) {
1392
1244
  if (currentIndexRecordsLoaded) {
1393
- currentCoverageSnapshot = mailSearchCoverageSnapshot(currentIndexRecords);
1245
+ currentCoverageSnapshot = (0, blob_store_1.canonicalMailIndexRecordSnapshot)(currentIndexRecords);
1394
1246
  }
1395
1247
  else if (!coverageValidationError) {
1396
1248
  coverageValidationError = "hosted store does not expose message index records";
@@ -1575,8 +1427,9 @@ exports.mailToolDefinitions = [
1575
1427
  : requestedScope ?? (args.source ? "delegated" : (familyOrAgentSelf(ctx) ? undefined : "native"));
1576
1428
  try {
1577
1429
  const cacheOptions = mailSearchCacheOptionsForStore(resolved.store);
1578
- const refreshed = await refreshMailSearchIndex({
1430
+ const refreshed = await (0, hosted_cache_sync_1.syncHostedMailSearchCache)({
1579
1431
  agentId: resolved.agentName,
1432
+ mode: "scoped-upsert",
1580
1433
  store: resolved.store,
1581
1434
  privateKeys: resolved.config.privateKeys,
1582
1435
  storeKind: resolved.storeKind,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.730",
3
+ "version": "0.1.0-alpha.731",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },