@remnic/core 9.12.0 → 9.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Orchestrator
3
- } from "./chunk-3VBXP5HS.js";
3
+ } from "./chunk-5RZHHANR.js";
4
4
  import "./chunk-5SB7SC2G.js";
5
5
  import "./chunk-3332THSR.js";
6
6
  import "./chunk-I74SUMNI.js";
@@ -2835,8 +2835,8 @@ function utcDateKeysForLocalDay(date, timeZone) {
2835
2835
  const hourMs = 36e5;
2836
2836
  const scanStart = date.getTime() - 48 * hourMs;
2837
2837
  const scanEnd = date.getTime() + 48 * hourMs;
2838
- for (let ms = scanStart; ms <= scanEnd; ms += hourMs) {
2839
- const candidate = new Date(ms);
2838
+ for (let ms2 = scanStart; ms2 <= scanEnd; ms2 += hourMs) {
2839
+ const candidate = new Date(ms2);
2840
2840
  if (formatDateInTimeZone(candidate, timeZone) === targetLocalDate) {
2841
2841
  keys.add(utcDateKey(candidate));
2842
2842
  }
@@ -22206,8 +22206,8 @@ function isProcessAlive(pid) {
22206
22206
  return true;
22207
22207
  }
22208
22208
  }
22209
- function sleepSync(ms) {
22210
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
22209
+ function sleepSync(ms2) {
22210
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms2);
22211
22211
  }
22212
22212
  function createPersonalSpace(baseDir, memoryDirOverride) {
22213
22213
  const homeDir = baseDir ?? resolveHomeDir();
@@ -23295,18 +23295,18 @@ function computeDwell(snapshots) {
23295
23295
  }
23296
23296
  return dwell;
23297
23297
  }
23298
- function formatDurationMinutes(ms) {
23299
- return `${Math.round(ms / 6e4)}m`;
23298
+ function formatDurationMinutes(ms2) {
23299
+ return `${Math.round(ms2 / 6e4)}m`;
23300
23300
  }
23301
23301
  function clockHhMm(iso, timezone) {
23302
- const ms = Date.parse(iso);
23303
- if (!Number.isFinite(ms)) return "??:??";
23302
+ const ms2 = Date.parse(iso);
23303
+ if (!Number.isFinite(ms2)) return "??:??";
23304
23304
  const parts = new Intl.DateTimeFormat("en-GB", {
23305
23305
  timeZone: timezone,
23306
23306
  hour: "2-digit",
23307
23307
  minute: "2-digit",
23308
23308
  hour12: false
23309
- }).formatToParts(new Date(ms));
23309
+ }).formatToParts(new Date(ms2));
23310
23310
  const hour = parts.find((p) => p.type === "hour")?.value ?? "00";
23311
23311
  const minute = parts.find((p) => p.type === "minute")?.value ?? "00";
23312
23312
  return `${hour}:${minute}`;
@@ -23329,8 +23329,8 @@ function perAppSection(ordered, dwell) {
23329
23329
  if (rows.length === 0) {
23330
23330
  lines.push("_No activity recorded._");
23331
23331
  } else {
23332
- for (const [app, ms] of rows) {
23333
- lines.push(`- ${app}: ${formatDurationMinutes(ms)}`);
23332
+ for (const [app, ms2] of rows) {
23333
+ lines.push(`- ${app}: ${formatDurationMinutes(ms2)}`);
23334
23334
  }
23335
23335
  }
23336
23336
  return lines.join("\n");
@@ -23485,8 +23485,185 @@ function parseMachinesList(raw) {
23485
23485
  return raw.replace(/^\[/, "").replace(/\]$/, "").split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
23486
23486
  }
23487
23487
 
23488
- // src/session-summaries/index.ts
23488
+ // src/meetings/detect.ts
23489
23489
  import { createHash as createHash10 } from "crypto";
23490
+ var DEFAULT_MEETING_APP_PATTERNS = [
23491
+ "zoom.us",
23492
+ "Zoom",
23493
+ "Microsoft Teams",
23494
+ "teams.microsoft.com",
23495
+ "meet.google.com",
23496
+ "Webex",
23497
+ "Slack",
23498
+ // huddle windows
23499
+ "FaceTime"
23500
+ ];
23501
+ var DEFAULT_MEETINGS_DETECTION_CONFIG = {
23502
+ appPatterns: [...DEFAULT_MEETING_APP_PATTERNS],
23503
+ minOverlapMinutes: 2,
23504
+ audioOnlyMinMinutes: 15,
23505
+ mergeGapMinutes: 2
23506
+ };
23507
+ function ms(iso) {
23508
+ if (typeof iso !== "string") return Number.NaN;
23509
+ if (!Number.isFinite(Date.parse(iso))) return Number.NaN;
23510
+ const m = iso.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|[+-](?:0\d:[0-5]\d|1[0-3]:[0-5]\d|14:00))$/);
23511
+ if (m === null) return Number.NaN;
23512
+ const [year, month, day, hour, minute, second] = m.slice(1).map(Number);
23513
+ const daysInMonth = month >= 1 && month <= 12 ? new Date(Date.UTC(year, month, 0)).getUTCDate() : 0;
23514
+ if (day < 1 || day > daysInMonth || hour > 23 || minute > 59 || second > 59) return Number.NaN;
23515
+ return Date.parse(iso);
23516
+ }
23517
+ function overlapMs(aStart, aEnd, bStart, bEnd) {
23518
+ const start = Math.max(aStart, bStart);
23519
+ const end = Math.min(aEnd, bEnd);
23520
+ return end > start ? end - start : 0;
23521
+ }
23522
+ function meetingId(date, startUtc) {
23523
+ if (!isValidDay(date)) {
23524
+ throw new RangeError(`meetings: invalid day "${date}" for a meeting id; expected a real YYYY-MM-DD.`);
23525
+ }
23526
+ const startMs = ms(startUtc);
23527
+ if (Number.isNaN(startMs)) {
23528
+ throw new RangeError(`meetings: invalid meeting start "${startUtc}" for a meeting id.`);
23529
+ }
23530
+ const anchor = new Date(startMs).toISOString();
23531
+ const hash = createHash10("sha256").update(`${date}|${anchor}`, "utf8").digest("hex").slice(0, 8);
23532
+ return `mtg-${date}-${hash}`;
23533
+ }
23534
+ function isFinitePair(a, b) {
23535
+ return Number.isFinite(a) && Number.isFinite(b) && b > a;
23536
+ }
23537
+ function combineDetection(a, b) {
23538
+ if (a === "app+audio" || b === "app+audio") return "app+audio";
23539
+ if (a === "provider" || b === "provider") return "provider";
23540
+ return "audio";
23541
+ }
23542
+ function buildCandidates(audioWindows, appSpans, config) {
23543
+ const minOverlapMs = config.minOverlapMinutes * 6e4;
23544
+ const audioOnlyMs = config.audioOnlyMinMinutes * 6e4;
23545
+ const candidates = [];
23546
+ for (const window of audioWindows) {
23547
+ const startMs = ms(window.startUtc);
23548
+ const endMs = ms(window.endUtc);
23549
+ if (!isFinitePair(startMs, endMs)) continue;
23550
+ if (window.providerMeeting === true) {
23551
+ candidates.push({
23552
+ startMs,
23553
+ endMs,
23554
+ detectionSource: "provider",
23555
+ sources: [window.source],
23556
+ ...window.title !== void 0 ? { title: window.title } : {}
23557
+ });
23558
+ continue;
23559
+ }
23560
+ let bestApp;
23561
+ for (const span of appSpans) {
23562
+ const spanStart = ms(span.startUtc);
23563
+ const spanEnd = ms(span.endUtc);
23564
+ if (!isFinitePair(spanStart, spanEnd)) continue;
23565
+ const overlap = overlapMs(startMs, endMs, spanStart, spanEnd);
23566
+ if (overlap <= 0 || overlap < minOverlapMs) continue;
23567
+ if (bestApp === void 0 || overlap > bestApp.overlap) {
23568
+ bestApp = { span, overlap };
23569
+ } else if (overlap === bestApp.overlap) {
23570
+ const bestStart = ms(bestApp.span.startUtc);
23571
+ const better = spanStart < bestStart || spanStart === bestStart && (span.app < bestApp.span.app || span.app === bestApp.span.app && spanEnd < ms(bestApp.span.endUtc));
23572
+ if (better) bestApp = { span, overlap };
23573
+ }
23574
+ }
23575
+ if (bestApp !== void 0) {
23576
+ candidates.push({
23577
+ startMs,
23578
+ endMs,
23579
+ app: bestApp.span.app,
23580
+ detectionSource: "app+audio",
23581
+ sources: [window.source],
23582
+ ...window.title !== void 0 ? { title: window.title } : {}
23583
+ });
23584
+ continue;
23585
+ }
23586
+ if (endMs - startMs >= audioOnlyMs && Number.isInteger(window.distinctNonWearerSpeakers) && window.distinctNonWearerSpeakers >= 2) {
23587
+ candidates.push({
23588
+ startMs,
23589
+ endMs,
23590
+ detectionSource: "audio",
23591
+ sources: [window.source],
23592
+ ...window.title !== void 0 ? { title: window.title } : {}
23593
+ });
23594
+ }
23595
+ }
23596
+ return candidates;
23597
+ }
23598
+ var DETECTION_RANK = {
23599
+ "app+audio": 0,
23600
+ provider: 1,
23601
+ audio: 2
23602
+ };
23603
+ function candidateOrder(a, b) {
23604
+ return a.startMs - b.startMs || a.endMs - b.endMs || DETECTION_RANK[a.detectionSource] - DETECTION_RANK[b.detectionSource] || (a.app ?? "").localeCompare(b.app ?? "") || (a.title ?? "").localeCompare(b.title ?? "") || (a.sources[0] ?? "").localeCompare(b.sources[0] ?? "");
23605
+ }
23606
+ function mergeCandidates(candidates, mergeGapMs) {
23607
+ const sorted = [...candidates].sort(candidateOrder);
23608
+ const merged = [];
23609
+ for (const candidate of sorted) {
23610
+ const prev = merged[merged.length - 1];
23611
+ const overlaps = prev !== void 0 && candidate.startMs < prev.endMs;
23612
+ const sameAppAdjacent = prev !== void 0 && prev.app !== void 0 && prev.app === candidate.app && candidate.startMs - prev.endMs <= mergeGapMs;
23613
+ if (prev !== void 0 && (overlaps || sameAppAdjacent)) {
23614
+ prev.endMs = Math.max(prev.endMs, candidate.endMs);
23615
+ prev.app = prev.app ?? candidate.app;
23616
+ prev.detectionSource = combineDetection(prev.detectionSource, candidate.detectionSource);
23617
+ prev.sources = [.../* @__PURE__ */ new Set([...prev.sources, ...candidate.sources])];
23618
+ prev.title = prev.title ?? candidate.title;
23619
+ continue;
23620
+ }
23621
+ merged.push({ ...candidate, sources: [...candidate.sources] });
23622
+ }
23623
+ return merged;
23624
+ }
23625
+ function assertFiniteNonNegative(name, value) {
23626
+ if (!Number.isFinite(value) || value < 0) {
23627
+ throw new RangeError(`meetings config "${name}" must be a finite, non-negative number (got ${value}).`);
23628
+ }
23629
+ }
23630
+ function isValidDay(date) {
23631
+ const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(date);
23632
+ if (m === null) return false;
23633
+ const [, year, month, day] = m.map(Number);
23634
+ const daysInMonth = month >= 1 && month <= 12 ? new Date(Date.UTC(year, month, 0)).getUTCDate() : 0;
23635
+ return day >= 1 && day <= daysInMonth;
23636
+ }
23637
+ function validateConfig(config) {
23638
+ assertFiniteNonNegative("minOverlapMinutes", config.minOverlapMinutes);
23639
+ assertFiniteNonNegative("audioOnlyMinMinutes", config.audioOnlyMinMinutes);
23640
+ assertFiniteNonNegative("mergeGapMinutes", config.mergeGapMinutes);
23641
+ }
23642
+ function detectMeetings(input, config = DEFAULT_MEETINGS_DETECTION_CONFIG) {
23643
+ validateConfig(config);
23644
+ if (!isValidDay(input.date)) {
23645
+ throw new RangeError(`meetings: invalid day "${input.date}"; expected a real YYYY-MM-DD.`);
23646
+ }
23647
+ const candidates = buildCandidates(input.audioWindows, input.appSpans, config);
23648
+ const merged = mergeCandidates(candidates, config.mergeGapMinutes * 6e4);
23649
+ return merged.map((candidate) => {
23650
+ const startUtc = new Date(candidate.startMs).toISOString();
23651
+ const endUtc = new Date(candidate.endMs).toISOString();
23652
+ return {
23653
+ id: meetingId(input.date, startUtc),
23654
+ date: input.date,
23655
+ startUtc,
23656
+ endUtc,
23657
+ ...candidate.app !== void 0 ? { app: candidate.app } : {},
23658
+ detectionSource: candidate.detectionSource,
23659
+ sources: [...candidate.sources].sort((a, b) => a < b ? -1 : a > b ? 1 : 0),
23660
+ ...candidate.title !== void 0 ? { title: candidate.title } : {}
23661
+ };
23662
+ });
23663
+ }
23664
+
23665
+ // src/session-summaries/index.ts
23666
+ import { createHash as createHash11 } from "crypto";
23490
23667
  import { lstat as lstat2, mkdir as mkdir8, readFile as readFile6, readdir as readdir4, rename, rm, stat as stat4, writeFile as writeFile7 } from "fs/promises";
23491
23668
  import path31 from "path";
23492
23669
 
@@ -23988,7 +24165,7 @@ var DEFAULT_MAX_FILES = 5e3;
23988
24165
  var DEFAULT_MAX_SESSIONS = 500;
23989
24166
  var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".jsonl"]);
23990
24167
  function shortHash(value, length = 16) {
23991
- return createHash10("sha256").update(value).digest("hex").slice(0, length);
24168
+ return createHash11("sha256").update(value).digest("hex").slice(0, length);
23992
24169
  }
23993
24170
  async function listTranscriptFiles(root, maxFiles) {
23994
24171
  const out = [];
@@ -24577,6 +24754,10 @@ export {
24577
24754
  composeActivityDigestMeta,
24578
24755
  serializeActivityDigest,
24579
24756
  parseActivityDigest,
24757
+ DEFAULT_MEETING_APP_PATTERNS,
24758
+ DEFAULT_MEETINGS_DETECTION_CONFIG,
24759
+ meetingId,
24760
+ detectMeetings,
24580
24761
  registerLocalSessionSourceAdapter,
24581
24762
  getLocalSessionSourceAdapter,
24582
24763
  listLocalSessionSourceAdapters,
@@ -24592,4 +24773,4 @@ export {
24592
24773
  blendGraphExpandedRecallScore,
24593
24774
  Orchestrator
24594
24775
  };
24595
- //# sourceMappingURL=chunk-3VBXP5HS.js.map
24776
+ //# sourceMappingURL=chunk-5RZHHANR.js.map