@remnic/core 9.3.739 → 9.3.741
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-boundary.js +13 -13
- package/dist/access-cli.js +35 -35
- package/dist/access-http.js +18 -18
- package/dist/access-mcp.js +17 -17
- package/dist/access-operations-batch.js +15 -15
- package/dist/access-operations.js +16 -16
- package/dist/access-service.js +12 -12
- package/dist/active-memory-bridge.js +3 -3
- package/dist/briefing.js +2 -2
- package/dist/buffer.js +2 -2
- package/dist/capabilities.d.ts +97 -1
- package/dist/capabilities.js +7 -1
- package/dist/causal-consolidation.js +4 -3
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/{chunk-IFCM6OLK.js → chunk-3TUDKDTQ.js} +7 -7
- package/dist/{chunk-A7INTIC5.js → chunk-4J53ZVPQ.js} +3 -3
- package/dist/{chunk-XYUFGHUW.js → chunk-56F6EAQ6.js} +2 -2
- package/dist/{chunk-F6OEXJQQ.js → chunk-6XG3NQRC.js} +2 -2
- package/dist/{chunk-24ZLC5QN.js → chunk-7N7S2RKF.js} +2 -2
- package/dist/{chunk-Y5OOHER4.js → chunk-7Y5KKMIP.js} +12 -11
- package/dist/chunk-7Y5KKMIP.js.map +1 -0
- package/dist/{chunk-VRBBZH4U.js → chunk-AX4TRSRE.js} +3 -3
- package/dist/{chunk-66RZ4EIT.js → chunk-BE6NEQLF.js} +3 -3
- package/dist/{chunk-YF2MMBKA.js → chunk-BJPL5WAL.js} +3 -3
- package/dist/{chunk-EO5QWINU.js → chunk-C3Z5YJSM.js} +5 -2
- package/dist/chunk-C3Z5YJSM.js.map +1 -0
- package/dist/{chunk-GEXI357K.js → chunk-C7C5WIIF.js} +2 -2
- package/dist/{chunk-L3TYGUTH.js → chunk-CMPXLMC3.js} +3 -3
- package/dist/{chunk-W2FBVBQ4.js → chunk-DBVBV2RF.js} +4 -4
- package/dist/{chunk-JQSP7YBJ.js → chunk-ELL5VYXC.js} +5 -4
- package/dist/chunk-ELL5VYXC.js.map +1 -0
- package/dist/{chunk-IQOEW5YV.js → chunk-FCQ7ZYCQ.js} +2 -2
- package/dist/{chunk-IIBFCZA7.js → chunk-FWXLKH2H.js} +3 -3
- package/dist/{chunk-RJBW4EOU.js → chunk-G7Q4D2G3.js} +74 -2
- package/dist/{chunk-RJBW4EOU.js.map → chunk-G7Q4D2G3.js.map} +1 -1
- package/dist/{chunk-WVAEIKUY.js → chunk-GPX5E36D.js} +5 -4
- package/dist/chunk-GPX5E36D.js.map +1 -0
- package/dist/{chunk-23PLOBWT.js → chunk-H3WSZWHK.js} +22 -20
- package/dist/chunk-H3WSZWHK.js.map +1 -0
- package/dist/{chunk-Q6BAA57B.js → chunk-JFCS6PQU.js} +2 -2
- package/dist/chunk-JFCS6PQU.js.map +1 -0
- package/dist/{chunk-CKHPUOAP.js → chunk-K2N6WIZM.js} +3 -3
- package/dist/{chunk-BHJAMSVC.js → chunk-LD6A7XG5.js} +7 -7
- package/dist/{chunk-AKKFHN3I.js → chunk-M4WI23X3.js} +2 -2
- package/dist/{chunk-N2O23WYA.js → chunk-M5KLYHHI.js} +2 -2
- package/dist/{chunk-TNLXCSXV.js → chunk-O4IWVWSW.js} +5 -4
- package/dist/chunk-O4IWVWSW.js.map +1 -0
- package/dist/{chunk-OQQRWPFZ.js → chunk-OS5RKJOH.js} +2 -2
- package/dist/{chunk-MAU7DFCJ.js → chunk-OT5K26NG.js} +5 -4
- package/dist/chunk-OT5K26NG.js.map +1 -0
- package/dist/{chunk-DS3FZ7GS.js → chunk-OUSOMUFV.js} +2 -2
- package/dist/{chunk-7B7IPPN5.js → chunk-OVYBENIJ.js} +3 -3
- package/dist/{chunk-5RZOFIDL.js → chunk-PI4JHLDD.js} +6 -3
- package/dist/chunk-PI4JHLDD.js.map +1 -0
- package/dist/{chunk-EU543UDC.js → chunk-QCO2QFLZ.js} +7 -7
- package/dist/chunk-QCO2QFLZ.js.map +1 -0
- package/dist/{chunk-YXOXAQ5Y.js → chunk-TQQN64J2.js} +5 -4
- package/dist/chunk-TQQN64J2.js.map +1 -0
- package/dist/{chunk-WDJCZQB4.js → chunk-UGFPGWJB.js} +2 -2
- package/dist/{chunk-75PDC7VT.js → chunk-UOVDO6TC.js} +6 -5
- package/dist/chunk-UOVDO6TC.js.map +1 -0
- package/dist/{chunk-BVG2IZOB.js → chunk-USHVHI6J.js} +7 -6
- package/dist/chunk-USHVHI6J.js.map +1 -0
- package/dist/{chunk-56LP72AD.js → chunk-UYYSOMS2.js} +4 -4
- package/dist/{chunk-IEWUPZ75.js → chunk-VC7QELR6.js} +77 -74
- package/dist/chunk-VC7QELR6.js.map +1 -0
- package/dist/{chunk-XIQAOGAA.js → chunk-WGDE2TJP.js} +7 -6
- package/dist/chunk-WGDE2TJP.js.map +1 -0
- package/dist/{chunk-UFS7OXGL.js → chunk-WHEF76BQ.js} +5 -2
- package/dist/chunk-WHEF76BQ.js.map +1 -0
- package/dist/{chunk-QTJOORGN.js → chunk-WIMKOTNY.js} +2 -2
- package/dist/{chunk-GXTYEG7Q.js → chunk-WO22UEM3.js} +2 -2
- package/dist/{chunk-BHQQVUEQ.js → chunk-X5PMDVY4.js} +6 -5
- package/dist/{chunk-BHQQVUEQ.js.map → chunk-X5PMDVY4.js.map} +1 -1
- package/dist/{chunk-C53JDEH3.js → chunk-Y62QPRKV.js} +2 -2
- package/dist/{chunk-WFNH4UDF.js → chunk-Y6PNYJVO.js} +3 -3
- package/dist/{chunk-6YKIYQU7.js → chunk-YNHRWFAP.js} +5 -2
- package/dist/{chunk-6YKIYQU7.js.map → chunk-YNHRWFAP.js.map} +1 -1
- package/dist/cli.js +29 -29
- package/dist/compounding/engine.js +4 -4
- package/dist/connectors/codex-materialize-runner.js +2 -2
- package/dist/connectors/index.js +4 -3
- package/dist/contradiction/index.js +2 -2
- package/dist/{contradiction-scan-CWO3LIWV.js → contradiction-scan-UERKJESC.js} +3 -3
- package/dist/day-summary.js +2 -1
- package/dist/embedding-fallback.js +2 -2
- package/dist/entity-retrieval.js +3 -3
- package/dist/explicit-capture.js +2 -2
- package/dist/extraction.js +4 -4
- package/dist/{first-start-migration-5DXD3TF2.js → first-start-migration-GQ3UQNIL.js} +2 -2
- package/dist/index.js +45 -45
- package/dist/local-llm.js +2 -2
- package/dist/maintenance/memory-governance.js +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +3 -3
- package/dist/namespaces/migrate.js +7 -7
- package/dist/namespaces/principal.js +2 -2
- package/dist/namespaces/search.js +4 -4
- package/dist/namespaces/storage.js +3 -3
- package/dist/operator-toolkit.js +13 -13
- package/dist/orchestration/compression-guideline-coordinator.js +2 -2
- package/dist/orchestration/maintenance.js +7 -7
- package/dist/orchestrator.js +29 -29
- package/dist/search/embed-helper.js +2 -2
- package/dist/search/factory.js +3 -3
- package/dist/search/index.js +3 -3
- package/dist/semantic-consolidation.js +4 -3
- package/dist/semantic-rule-promotion.js +2 -2
- package/dist/semantic-rule-verifier.js +2 -2
- package/dist/shared-context/manager.js +2 -1
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +1 -1
- package/dist/summarizer.js +3 -3
- package/dist/{tier-stats-QID73BBB.js → tier-stats-CSKL7BDG.js} +2 -2
- package/dist/verified-recall.js +2 -2
- package/package.json +2 -2
- package/src/access-service.ts +2 -1
- package/src/capabilities.test.ts +166 -0
- package/src/capabilities.ts +267 -0
- package/src/cli/research-status-commands.ts +2 -1
- package/src/cli.ts +3 -2
- package/src/compounding/engine.ts +2 -1
- package/src/connectors/codex-marketplace.ts +2 -1
- package/src/day-summary.ts +2 -1
- package/src/embedding-fallback.ts +2 -1
- package/src/extraction.ts +3 -2
- package/src/local-llm.ts +2 -1
- package/src/maintenance/namespace-maintenance-fanout.ts +2 -1
- package/src/maintenance/namespace-planner.ts +2 -1
- package/src/operator-toolkit.ts +1 -0
- package/src/orchestration/semantic-consolidation-coordinator.ts +3 -2
- package/src/orchestrator.ts +50 -46
- package/src/search/embed-helper.ts +2 -1
- package/src/search/factory.ts +2 -1
- package/src/semantic-consolidation.ts +2 -1
- package/src/shared-context/manager.ts +3 -2
- package/src/storage.ts +1 -1
- package/src/summarizer.ts +3 -2
- package/dist/chunk-23PLOBWT.js.map +0 -1
- package/dist/chunk-5RZOFIDL.js.map +0 -1
- package/dist/chunk-75PDC7VT.js.map +0 -1
- package/dist/chunk-BVG2IZOB.js.map +0 -1
- package/dist/chunk-EO5QWINU.js.map +0 -1
- package/dist/chunk-EU543UDC.js.map +0 -1
- package/dist/chunk-IEWUPZ75.js.map +0 -1
- package/dist/chunk-JQSP7YBJ.js.map +0 -1
- package/dist/chunk-MAU7DFCJ.js.map +0 -1
- package/dist/chunk-Q6BAA57B.js.map +0 -1
- package/dist/chunk-TNLXCSXV.js.map +0 -1
- package/dist/chunk-UFS7OXGL.js.map +0 -1
- package/dist/chunk-WVAEIKUY.js.map +0 -1
- package/dist/chunk-XIQAOGAA.js.map +0 -1
- package/dist/chunk-Y5OOHER4.js.map +0 -1
- package/dist/chunk-YXOXAQ5Y.js.map +0 -1
- /package/dist/{chunk-IFCM6OLK.js.map → chunk-3TUDKDTQ.js.map} +0 -0
- /package/dist/{chunk-A7INTIC5.js.map → chunk-4J53ZVPQ.js.map} +0 -0
- /package/dist/{chunk-XYUFGHUW.js.map → chunk-56F6EAQ6.js.map} +0 -0
- /package/dist/{chunk-F6OEXJQQ.js.map → chunk-6XG3NQRC.js.map} +0 -0
- /package/dist/{chunk-24ZLC5QN.js.map → chunk-7N7S2RKF.js.map} +0 -0
- /package/dist/{chunk-VRBBZH4U.js.map → chunk-AX4TRSRE.js.map} +0 -0
- /package/dist/{chunk-66RZ4EIT.js.map → chunk-BE6NEQLF.js.map} +0 -0
- /package/dist/{chunk-YF2MMBKA.js.map → chunk-BJPL5WAL.js.map} +0 -0
- /package/dist/{chunk-GEXI357K.js.map → chunk-C7C5WIIF.js.map} +0 -0
- /package/dist/{chunk-L3TYGUTH.js.map → chunk-CMPXLMC3.js.map} +0 -0
- /package/dist/{chunk-W2FBVBQ4.js.map → chunk-DBVBV2RF.js.map} +0 -0
- /package/dist/{chunk-IQOEW5YV.js.map → chunk-FCQ7ZYCQ.js.map} +0 -0
- /package/dist/{chunk-IIBFCZA7.js.map → chunk-FWXLKH2H.js.map} +0 -0
- /package/dist/{chunk-CKHPUOAP.js.map → chunk-K2N6WIZM.js.map} +0 -0
- /package/dist/{chunk-BHJAMSVC.js.map → chunk-LD6A7XG5.js.map} +0 -0
- /package/dist/{chunk-AKKFHN3I.js.map → chunk-M4WI23X3.js.map} +0 -0
- /package/dist/{chunk-N2O23WYA.js.map → chunk-M5KLYHHI.js.map} +0 -0
- /package/dist/{chunk-OQQRWPFZ.js.map → chunk-OS5RKJOH.js.map} +0 -0
- /package/dist/{chunk-DS3FZ7GS.js.map → chunk-OUSOMUFV.js.map} +0 -0
- /package/dist/{chunk-7B7IPPN5.js.map → chunk-OVYBENIJ.js.map} +0 -0
- /package/dist/{chunk-WDJCZQB4.js.map → chunk-UGFPGWJB.js.map} +0 -0
- /package/dist/{chunk-56LP72AD.js.map → chunk-UYYSOMS2.js.map} +0 -0
- /package/dist/{chunk-QTJOORGN.js.map → chunk-WIMKOTNY.js.map} +0 -0
- /package/dist/{chunk-GXTYEG7Q.js.map → chunk-WO22UEM3.js.map} +0 -0
- /package/dist/{chunk-C53JDEH3.js.map → chunk-Y62QPRKV.js.map} +0 -0
- /package/dist/{chunk-WFNH4UDF.js.map → chunk-Y6PNYJVO.js.map} +0 -0
- /package/dist/{contradiction-scan-CWO3LIWV.js.map → contradiction-scan-UERKJESC.js.map} +0 -0
- /package/dist/{first-start-migration-5DXD3TF2.js.map → first-start-migration-GQ3UQNIL.js.map} +0 -0
- /package/dist/{tier-stats-QID73BBB.js.map → tier-stats-CSKL7BDG.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/maintenance/namespace-maintenance-fanout.ts"],"sourcesContent":["/**\n * Namespace maintenance fanout coordinator (issue #1500).\n *\n * Builds on the namespace-aware maintenance planner (#1499 / #1517) to fan out\n * the REMAINING background maintenance jobs — dreams, pattern reinforcement,\n * governance/lifecycle, contradiction scans, semantic/causal consolidation,\n * graph decay, fact archival, tier migration — across all maintained\n * namespaces.\n *\n * The planner (`namespace-planner.ts`) already handles namespace discovery\n * (configured + catalog), per-kind gating, cycle budgeting, per-job+namespace\n * locking, status recording, and catalog maintenance timestamps. QMD\n * maintenance was wired through it in #1517. This module standardizes the\n * per-job adapter pattern so every other maintenance job can be fanned out\n * with one call, and aggregates per-namespace health for doctor/dashboard.\n *\n * Design contract (issue #1500 compatibility requirements):\n * - Existing direct `runJob({ namespace })` calls continue to work unchanged.\n * - Namespaces disabled: fanout is a no-op (the planner returns only the\n * default namespace; jobs run exactly as before).\n * - `maintenanceNamespaceFanoutEnabled: false`: fanout is a no-op.\n * - A failure in one namespace must not abort other namespaces (the planner\n * already isolates per-namespace failures).\n * - Per-namespace locks prevent duplicate concurrent runs (planner-provided).\n */\n\nimport { resolveNamespaceCapabilities } from \"../capabilities.js\";\nimport type { NamespaceCatalog } from \"../namespaces/catalog.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport {\n planNamespaceMaintenance,\n readNamespaceMaintenanceLastRanStatuses,\n readNamespaceMaintenanceStatuses,\n runNamespaceMaintenancePlan,\n type NamespaceMaintenanceCandidate,\n type NamespaceMaintenanceRunStatus,\n type NamespaceMaintenanceSummary,\n} from \"./namespace-planner.js\";\n\n/**\n * Standard maintenance job names fanned out across namespaces.\n *\n * These strings are used as the `jobName` key in:\n * - per-namespace status files (`state/namespace-maintenance-status/<job>/...`)\n * - catalog `lastMaintenanceAt[jobName]` timestamps\n * - per-job+namespace lock files (`state/maintenance-locks/<job>/...`)\n *\n * Keeping them centralized ensures the doctor, CLI, and dashboard all report\n * against the same keys.\n */\nexport const NAMESPACE_MAINTENANCE_JOBS = [\n \"qmd\",\n \"pattern-reinforcement\",\n \"contradiction-scan\",\n \"semantic-consolidation\",\n \"governance\",\n \"lifecycle\",\n \"graph-decay\",\n \"fact-archival\",\n \"tier-migration\",\n] as const;\n\nexport type NamespaceMaintenanceStandardJob =\n (typeof NAMESPACE_MAINTENANCE_JOBS)[number];\n\n/**\n * Context passed to a fanout job runner. The runner receives the per-namespace\n * candidate (namespace name, kind, storage dir) and a storage resolver that\n * the orchestrator wires to `storageRouter.storageFor(namespace)`.\n *\n * The storage resolver is intentionally typed as `unknown` here so this module\n * does not depend on the `StorageManager` class — the orchestrator provides the\n * typed resolver. This keeps the fanout module free of orchestrator/storage\n * imports and unit-testable with a stub.\n */\nexport interface NamespaceMaintenanceFanoutRunnerContext {\n config: PluginConfig;\n candidate: NamespaceMaintenanceCandidate;\n resolveStorage: (namespace: string) => Promise<unknown>;\n}\n\n/**\n * Result returned by a fanout job runner. `itemCount` is optional and\n * domain-specific (e.g. memories scanned, edges decayed, embeddings updated).\n *\n * `skipped`/`skipReason`: when a runner performs no work for a namespace\n * (e.g. the job's own cadence gate throttled it), set `skipped: true`. The\n * planner records the namespace as `state: \"skipped\"` and does NOT touch\n * the catalog's `lastMaintenanceAt`, so a throttled namespace is not\n * falsely reported as maintained.\n */\nexport interface NamespaceMaintenanceFanoutRunnerResult {\n itemCount?: number;\n skipped?: boolean;\n skipReason?: string;\n}\n\nexport type NamespaceMaintenanceFanoutRunner = (\n ctx: NamespaceMaintenanceFanoutRunnerContext,\n) => Promise<NamespaceMaintenanceFanoutRunnerResult | undefined>;\n\nexport interface RunNamespaceMaintenanceFanoutOptions {\n config: PluginConfig;\n catalog?: NamespaceCatalog;\n jobName: string;\n runner: NamespaceMaintenanceFanoutRunner;\n resolveStorage: (namespace: string) => Promise<unknown>;\n /**\n * When `false`, skip fanout entirely and return a zero-summary without\n * touching the planner or locks. This lets callers gate fanout on\n * per-job config (e.g. `semanticConsolidationEnabled`) without repeating\n * the namespace-discovery logic.\n */\n enabled?: boolean;\n}\n\n/**\n * Fan out a single maintenance job across all maintained namespaces.\n *\n * This is the primary entry point for wiring a maintenance job through the\n * namespace-aware planner. It:\n * 1. Plans which namespaces should be maintained (configured + catalog,\n * budgeted, kind-gated).\n * 2. Runs the job per-namespace through `runNamespaceMaintenancePlan`, which\n * acquires per-job+namespace locks, records status files, and touches the\n * catalog's `lastMaintenanceAt`.\n *\n * When namespaces are disabled or fanout is off, the planner returns only the\n * default namespace, so the job runs exactly once against default storage —\n * preserving single-user behavior.\n */\nexport async function runNamespaceMaintenanceFanout(\n options: RunNamespaceMaintenanceFanoutOptions,\n): Promise<NamespaceMaintenanceSummary> {\n if (options.enabled === false) {\n return {\n jobName: options.jobName,\n generatedAt: new Date().toISOString(),\n ran: 0,\n skipped: 0,\n failed: 0,\n statuses: [],\n };\n }\n\n const plan = await planNamespaceMaintenance(options.config, {\n jobName: options.jobName,\n catalog: options.catalog,\n });\n\n return runNamespaceMaintenancePlan(\n options.config,\n plan,\n async (candidate) => {\n return options.runner({\n config: options.config,\n candidate,\n resolveStorage: options.resolveStorage,\n });\n },\n options.catalog,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Health summary for doctor / dashboard / CLI\n// ---------------------------------------------------------------------------\n\nexport interface NamespaceMaintenanceJobHealth {\n jobName: string;\n ran: number;\n skipped: number;\n failed: number;\n lastRunAt: string | null;\n namespaces: NamespaceMaintenanceRunStatus[];\n}\n\nexport interface NamespaceMaintenanceHealthSummary {\n generatedAt: string;\n fanoutEnabled: boolean;\n namespacesEnabled: boolean;\n maxNamespacesPerCycle: number;\n jobs: NamespaceMaintenanceJobHealth[];\n totalRan: number;\n totalSkipped: number;\n totalFailed: number;\n}\n\n/**\n * Read all per-namespace maintenance status files and aggregate them into a\n * health summary suitable for `remnic doctor` and the admin dashboard.\n *\n * This is a pure read operation — it never runs maintenance or acquires locks.\n */\nexport async function summarizeNamespaceMaintenanceHealth(\n config: PluginConfig,\n): Promise<NamespaceMaintenanceHealthSummary> {\n const generatedAt = new Date().toISOString();\n const statuses = await readNamespaceMaintenanceStatuses(config);\n // Merge last-successful-run records so lastRunAt reflects the most recent\n // successful maintenance, not just the latest (possibly skipped/failed)\n // outcome. The latest status file is overwritten on every run; without\n // this merge a namespace that ran then got budget-skipped shows ran=0 /\n // lastRunAt=null (review #1622: preserve last successful run).\n const lastRanStatuses = await readNamespaceMaintenanceLastRanStatuses(config);\n const lastRanByJobNs = new Map<string, NamespaceMaintenanceRunStatus>();\n for (const lr of lastRanStatuses) {\n lastRanByJobNs.set(`${lr.jobName}\\u0000${lr.namespace}`, lr);\n }\n\n const byJob = new Map<string, NamespaceMaintenanceRunStatus[]>();\n for (const status of statuses) {\n const bucket = byJob.get(status.jobName);\n if (bucket) {\n bucket.push(status);\n } else {\n byJob.set(status.jobName, [status]);\n }\n }\n\n const knownJobs = new Set<string>(NAMESPACE_MAINTENANCE_JOBS);\n // Include any job names seen in status files that are not in the standard\n // set (e.g. custom jobs registered by the orchestrator) so the doctor does\n // not silently hide them.\n for (const jobName of byJob.keys()) {\n knownJobs.add(jobName);\n }\n\n const jobs: NamespaceMaintenanceJobHealth[] = [];\n let totalRan = 0;\n let totalSkipped = 0;\n let totalFailed = 0;\n\n for (const jobName of [...knownJobs].sort()) {\n const jobStatuses = byJob.get(jobName) ?? [];\n const ran = jobStatuses.filter((s) => s.state === \"ran\").length;\n const skipped = jobStatuses.filter((s) => s.state === \"skipped\").length;\n const failed = jobStatuses.filter((s) => s.state === \"failed\").length;\n // Consider BOTH the latest outcome and the last successful run so a\n // namespace that ran then was later skipped still reports lastRunAt.\n const candidates: string[] = [];\n for (const st of jobStatuses) {\n if (typeof st.completedAt === \"string\") candidates.push(st.completedAt);\n const lr = lastRanByJobNs.get(`${jobName}\\u0000${st.namespace}`);\n if (lr && typeof lr.completedAt === \"string\") candidates.push(lr.completedAt);\n }\n const lastRunAt = candidates.sort().at(-1) ?? null;\n\n totalRan += ran;\n totalSkipped += skipped;\n totalFailed += failed;\n\n jobs.push({\n jobName,\n ran,\n skipped,\n failed,\n lastRunAt,\n namespaces: jobStatuses,\n });\n }\n\n return {\n generatedAt,\n fanoutEnabled: config.maintenanceNamespaceFanoutEnabled !== false,\n namespacesEnabled: resolveNamespaceCapabilities(config).namespaces,\n maxNamespacesPerCycle: config.maintenanceMaxNamespacesPerCycle,\n jobs,\n totalRan,\n totalSkipped,\n totalFailed,\n };\n}\n\n/**\n * Format the health summary as human-readable text for the CLI.\n */\nexport function formatNamespaceMaintenanceHealthText(\n summary: NamespaceMaintenanceHealthSummary,\n): string {\n const lines: string[] = [\n \"=== Namespace Maintenance ===\",\n \"\",\n ` fanout: ${summary.fanoutEnabled ? \"enabled\" : \"disabled\"}`,\n ` namespaces: ${summary.namespacesEnabled ? \"enabled\" : \"disabled\"}`,\n ` max/cycle: ${summary.maxNamespacesPerCycle}`,\n ` total ran: ${summary.totalRan}`,\n ` total skipped: ${summary.totalSkipped}`,\n ` total failed: ${summary.totalFailed}`,\n \"\",\n ];\n\n if (summary.totalRan === 0 && summary.totalSkipped === 0 && summary.totalFailed === 0) {\n lines.push(\" (no maintenance status recorded yet)\");\n return lines.join(\"\\n\");\n }\n\n lines.push(\" Per-job breakdown:\");\n for (const job of summary.jobs) {\n const parts = [\n `ran=${job.ran}`,\n `skipped=${job.skipped}`,\n `failed=${job.failed}`,\n ];\n if (job.lastRunAt) {\n parts.push(`last=${job.lastRunAt}`);\n }\n lines.push(` ${job.jobName}: ${parts.join(\", \")}`);\n // Surface failed namespaces with their reason/error so operators know\n // WHAT to fix without rerunning with --json (review #1622).\n const failedNs = job.namespaces.filter((n) => n.state === \"failed\");\n for (const ns of failedNs) {\n const detail = ns.error ? `: ${ns.error}` : \"\";\n lines.push(` ! ${ns.namespace} failed (reason=${ns.reason ?? \"unknown\"})${detail}`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared-context/manager.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, readdir, appendFile, writeFile, stat, rename, rm } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { log } from \"../logger.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport { expandTildePath } from \"../utils/path.js\";\n\nexport const SharedFeedbackEntrySchema = z.object({\n agent: z.string().min(1),\n decision: z.enum([\"approved\", \"approved_with_feedback\", \"rejected\"]),\n reason: z.string().min(1),\n date: z.string().min(8), // ISO-ish; keep loose\n learning: z.string().optional(),\n outcome: z.string().optional(),\n severity: z.enum([\"low\", \"medium\", \"high\"]).optional(),\n confidence: z.number().min(0).max(1).optional(),\n workflow: z.string().min(1).optional(),\n tags: z.array(z.string().min(1)).optional(),\n evidenceWindowStart: z.string().min(8).optional(),\n evidenceWindowEnd: z.string().min(8).optional(),\n refs: z.array(z.string()).optional(),\n});\n\nexport type SharedFeedbackEntry = z.infer<typeof SharedFeedbackEntrySchema>;\n\nfunction safeSlug(s: string): string {\n let slug = s.toLowerCase().replace(/[^a-z0-9]+/g, \"-\");\n // Trim leading/trailing dashes without ReDoS-prone anchored quantifiers\n let start = 0;\n while (start < slug.length && slug[start] === \"-\") start++;\n let end = slug.length;\n while (end > start && slug[end - 1] === \"-\") end--;\n return slug.slice(start, end).slice(0, 80) || \"output\";\n}\n\nfunction safePathSegment(s: string, label: string): string {\n if (s.length === 0) throw new Error(`${label} must not be empty`);\n if (/[\\r\\n]/.test(s)) throw new Error(`${label} must not contain line breaks`);\n const encoded = encodeURIComponent(s);\n if (encoded === \".\" || encoded === \"..\") {\n return encoded.replace(/\\./g, \"%2E\");\n }\n return encoded;\n}\n\nfunction safeDecodePathSegment(s: string): string {\n try {\n return decodeURIComponent(s);\n } catch {\n return s;\n }\n}\n\nfunction normalizeFrontmatterScalar(value: string): string {\n if (value.length >= 2 && value.startsWith('\"') && value.endsWith('\"')) {\n try {\n const parsed = JSON.parse(value);\n if (typeof parsed === \"string\") return parsed;\n } catch {\n // Fall through to the legacy partial unescape below.\n }\n return value.slice(1, -1).replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\");\n }\n if (value.length >= 2 && value.startsWith(\"'\") && value.endsWith(\"'\")) {\n return value.slice(1, -1).replace(/''/g, \"'\");\n }\n return value;\n}\n\nfunction formatFrontmatterScalar(value: string): string {\n return JSON.stringify(value);\n}\n\nfunction readFrontmatterScalar(raw: string, key: string): string | null {\n const frontmatter = raw.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---(?:\\r?\\n|$)/)?.[1];\n if (!frontmatter) return null;\n for (const line of frontmatter.split(/\\r?\\n/)) {\n if (!line.startsWith(`${key}:`)) continue;\n const value = line.slice(key.length + 1).trim();\n return value ? normalizeFrontmatterScalar(value) : null;\n }\n return null;\n}\n\nfunction ymd(d: Date): string {\n return d.toISOString().slice(0, 10);\n}\n\nfunction safeDateSegment(date: string): string {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(date)) {\n throw new Error(`Invalid shared-context date: ${JSON.stringify(date)}; expected YYYY-MM-DD`);\n }\n const parsed = new Date(`${date}T00:00:00.000Z`);\n if (!Number.isFinite(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== date) {\n throw new Error(`Invalid shared-context date: ${JSON.stringify(date)}; expected a real calendar date`);\n }\n return date;\n}\n\nconst CROSS_SIGNAL_STOPWORDS = new Set([\n \"a\",\n \"an\",\n \"and\",\n \"are\",\n \"as\",\n \"at\",\n \"be\",\n \"by\",\n \"for\",\n \"from\",\n \"has\",\n \"have\",\n \"in\",\n \"is\",\n \"it\",\n \"of\",\n \"on\",\n \"or\",\n \"that\",\n \"the\",\n \"this\",\n \"to\",\n \"was\",\n \"were\",\n \"with\",\n \"agent\",\n \"output\",\n \"today\",\n \"daily\",\n \"notes\",\n \"note\",\n \"summary\",\n]);\n\nfunction extractTopicTokens(text: string, maxTokens: number = 12): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n const tokens = text\n .toLowerCase()\n .replace(/[^a-z0-9\\s]/g, \" \")\n .split(/\\s+/)\n .map((token) => token.trim())\n .filter((token) => token.length >= 4)\n .filter((token) => !CROSS_SIGNAL_STOPWORDS.has(token));\n\n for (const token of tokens) {\n if (seen.has(token)) continue;\n seen.add(token);\n out.push(token);\n if (out.length >= maxTokens) break;\n }\n return out;\n}\n\nfunction stripYamlFrontmatter(text: string): string {\n if (!text.startsWith(\"---\\n\")) return text;\n const closing = text.indexOf(\"\\n---\\n\", 4);\n if (closing === -1) return text;\n return text.slice(closing + 5);\n}\n\nfunction semanticRoot(token: string): string {\n let root = token.toLowerCase();\n if (root.endsWith(\"izations\") && root.length > 9) {\n root = `${root.slice(0, -8)}ize`;\n }\n else if (root.endsWith(\"ization\") && root.length > 8) {\n root = `${root.slice(0, -7)}ize`;\n } else if (root.endsWith(\"isations\") && root.length > 9) {\n root = `${root.slice(0, -8)}ise`;\n } else if (root.endsWith(\"isation\") && root.length > 8) {\n root = `${root.slice(0, -7)}ise`;\n } else {\n const suffixes = [\n \"ations\",\n \"ation\",\n \"ments\",\n \"ment\",\n \"ingly\",\n \"edly\",\n \"ings\",\n \"ing\",\n \"ers\",\n \"er\",\n \"ies\",\n \"ied\",\n \"ions\",\n \"ion\",\n \"es\",\n \"ed\",\n \"s\",\n ];\n for (const suffix of suffixes) {\n if (root.length > suffix.length + 3 && root.endsWith(suffix)) {\n root = root.slice(0, -suffix.length);\n break;\n }\n }\n }\n if (root.length > 4 && root.endsWith(\"e\")) {\n root = root.slice(0, -1);\n }\n return root;\n}\n\nfunction mergeOverlaps(\n base: SharedCrossSignalOverlap[],\n extra: SharedCrossSignalOverlap[],\n): SharedCrossSignalOverlap[] {\n const merged = new Map<string, { agents: Set<string>; sourcePaths: Set<string> }>();\n for (const entry of [...base, ...extra]) {\n const existing = merged.get(entry.token);\n if (existing) {\n for (const agent of entry.agents) existing.agents.add(agent);\n for (const sourcePath of entry.sourcePaths) existing.sourcePaths.add(sourcePath);\n } else {\n merged.set(entry.token, {\n agents: new Set(entry.agents),\n sourcePaths: new Set(entry.sourcePaths),\n });\n }\n }\n return [...merged.entries()]\n .map(([token, value]) => ({\n token,\n agents: [...value.agents].sort(),\n sourcePaths: [...value.sourcePaths].sort(),\n agentCount: value.agents.size,\n }))\n .filter((entry) => entry.agentCount >= 2)\n .sort((a, b) => b.agentCount - a.agentCount || a.token.localeCompare(b.token));\n}\n\nasync function computeSemanticOverlapCandidates(\n sources: SharedCrossSignalSource[],\n maxCandidates: number,\n timeoutAtMs: number,\n): Promise<{ overlaps: SharedCrossSignalOverlap[]; candidateCount: number; timedOut: boolean }> {\n const tokenRows: Array<{ token: string; agent: string; path: string }> = [];\n for (const source of sources) {\n for (const token of source.topics) {\n if (Date.now() >= timeoutAtMs) return { overlaps: [], candidateCount: tokenRows.length, timedOut: true };\n await new Promise<void>((resolve) => setImmediate(resolve));\n tokenRows.push({ token, agent: source.agent, path: source.path });\n if (tokenRows.length >= maxCandidates) break;\n }\n if (tokenRows.length >= maxCandidates) break;\n }\n\n const byRoot = new Map<string, Map<string, { agents: Set<string>; paths: Set<string> }>>();\n for (const row of tokenRows) {\n if (Date.now() >= timeoutAtMs) return { overlaps: [], candidateCount: tokenRows.length, timedOut: true };\n await new Promise<void>((resolve) => setImmediate(resolve));\n const root = semanticRoot(row.token);\n if (root.length < 4) continue;\n const rootGroup = byRoot.get(root) ?? new Map<string, { agents: Set<string>; paths: Set<string> }>();\n const tokenGroup = rootGroup.get(row.token) ?? { agents: new Set<string>(), paths: new Set<string>() };\n tokenGroup.agents.add(row.agent);\n tokenGroup.paths.add(row.path);\n rootGroup.set(row.token, tokenGroup);\n byRoot.set(root, rootGroup);\n }\n\n const overlaps: SharedCrossSignalOverlap[] = [];\n for (const [root, tokenMap] of byRoot.entries()) {\n if (Date.now() >= timeoutAtMs) return { overlaps: [], candidateCount: tokenRows.length, timedOut: true };\n await new Promise<void>((resolve) => setImmediate(resolve));\n if (tokenMap.size < 2) continue;\n const agents = new Set<string>();\n const sourcePaths = new Set<string>();\n for (const value of tokenMap.values()) {\n for (const agent of value.agents) agents.add(agent);\n for (const sourcePath of value.paths) sourcePaths.add(sourcePath);\n }\n if (agents.size < 2) continue;\n overlaps.push({\n token: `semantic:${root}`,\n agents: [...agents].sort(),\n sourcePaths: [...sourcePaths].sort(),\n agentCount: agents.size,\n });\n }\n\n overlaps.sort((a, b) => b.agentCount - a.agentCount || a.token.localeCompare(b.token));\n return {\n overlaps,\n candidateCount: tokenRows.length,\n timedOut: false,\n };\n}\n\nasync function computeSemanticOverlapsWithTimeout(\n sources: SharedCrossSignalSource[],\n timeoutMs: number,\n maxCandidates: number,\n): Promise<{ overlaps: SharedCrossSignalOverlap[]; candidateCount: number; timedOut: boolean }> {\n const safeTimeoutMs = Math.max(1, Math.floor(timeoutMs));\n const safeMaxCandidates = Math.max(0, Math.floor(maxCandidates));\n if (safeMaxCandidates === 0 || sources.length === 0) {\n return { overlaps: [], candidateCount: 0, timedOut: false };\n }\n const timeoutAtMs = Date.now() + safeTimeoutMs;\n return computeSemanticOverlapCandidates(sources, safeMaxCandidates, timeoutAtMs);\n}\n\ninterface SharedCrossSignalSource {\n agent: string;\n path: string;\n title: string;\n topics: string[];\n}\n\ninterface SharedCrossSignalOverlap {\n token: string;\n agents: string[];\n sourcePaths: string[];\n agentCount: number;\n}\n\ninterface SharedCrossSignalReport {\n date: string;\n generatedAt: string;\n sourceCount: number;\n feedbackCount: number;\n feedbackByDecision: Record<\"approved\" | \"approved_with_feedback\" | \"rejected\", number>;\n feedbackEntries: SharedFeedbackEntry[];\n sources: SharedCrossSignalSource[];\n overlaps: SharedCrossSignalOverlap[];\n semantic: {\n enabled: boolean;\n applied: boolean;\n timedOut: boolean;\n candidateCount: number;\n maxCandidates: number;\n addedOverlapCount: number;\n };\n}\n\nexport interface SharedCrossSignalSynthesisResult {\n date: string;\n crossSignalsPath: string;\n crossSignalsMarkdownPath: string;\n overlapCount: number;\n report: SharedCrossSignalReport;\n}\n\nexport interface SharedDailyCurationResult {\n date: string;\n roundtablePath: string;\n crossSignalsPath: string;\n crossSignalsMarkdownPath: string;\n overlapCount: number;\n}\n\nfunction feedbackDecisionPriority(decision: SharedFeedbackEntry[\"decision\"]): number {\n switch (decision) {\n case \"rejected\":\n return 3;\n case \"approved_with_feedback\":\n return 2;\n case \"approved\":\n return 1;\n }\n}\n\nfunction feedbackSeverityPriority(severity: SharedFeedbackEntry[\"severity\"]): number {\n switch (severity) {\n case \"high\":\n return 3;\n case \"medium\":\n return 2;\n case \"low\":\n return 1;\n default:\n return 0;\n }\n}\n\nfunction compareFeedbackPriority(a: SharedFeedbackEntry, b: SharedFeedbackEntry): number {\n return (\n feedbackDecisionPriority(b.decision) - feedbackDecisionPriority(a.decision)\n || feedbackSeverityPriority(b.severity) - feedbackSeverityPriority(a.severity)\n || a.date.localeCompare(b.date)\n );\n}\n\nfunction markdownLineText(value: string): string {\n return value.replace(/[\\r\\n]+/g, \" \").replace(/\\s+/g, \" \").trim();\n}\n\nfunction markdownLineList(values: readonly string[]): string {\n return values.map(markdownLineText).filter(Boolean).join(\", \");\n}\n\nfunction formatFeedbackLine(entry: SharedFeedbackEntry): string {\n const extras: string[] = [`feedback: ${markdownLineText(entry.date)}`];\n if (entry.severity) extras.push(`severity: ${markdownLineText(entry.severity)}`);\n if (entry.refs?.length) extras.push(`refs: ${markdownLineList(entry.refs)}`);\n return `- [${markdownLineText(entry.agent)}] ${entry.decision}: ${markdownLineText(entry.reason)} [${extras.join(\"; \")}]`;\n}\n\nfunction formatOverlapLine(entry: SharedCrossSignalOverlap): string {\n return `- \\`${entry.token}\\` (${entry.agentCount} agents: ${markdownLineList(entry.agents)}) [sources: ${markdownLineList(entry.sourcePaths)}]`;\n}\n\nasync function writeFileAtomic(filePath: string, content: string): Promise<void> {\n await mkdir(path.dirname(filePath), { recursive: true });\n const tempPath = path.join(\n path.dirname(filePath),\n `.${path.basename(filePath)}.${process.pid}.${randomUUID()}.tmp`,\n );\n try {\n await writeFile(tempPath, content, { encoding: \"utf-8\", flag: \"wx\" });\n await rename(tempPath, filePath);\n } catch (error) {\n await rm(tempPath, { force: true }).catch(() => undefined);\n throw error;\n }\n}\n\nexport function resolveSharedContextDir(config: PluginConfig): string {\n return typeof config.sharedContextDir === \"string\" && config.sharedContextDir.length > 0\n ? expandTildePath(config.sharedContextDir)\n : path.join(expandTildePath(config.workspaceDir), \"shared-context\");\n}\n\nexport class SharedContextManager {\n readonly dir: string;\n private readonly prioritiesPath: string;\n private readonly prioritiesInboxPath: string;\n private readonly outputsDir: string;\n private readonly roundtableDir: string;\n private readonly feedbackDir: string;\n private readonly feedbackInboxPath: string;\n private readonly crossSignalsDir: string;\n private readonly dailySynthesisChains = new Map<string, Promise<void>>();\n\n constructor(private readonly config: PluginConfig) {\n const base = resolveSharedContextDir(config);\n\n this.dir = base;\n this.prioritiesPath = path.join(base, \"priorities.md\");\n this.prioritiesInboxPath = path.join(base, \"priorities.inbox.md\");\n this.outputsDir = path.join(base, \"agent-outputs\");\n this.roundtableDir = path.join(base, \"roundtable\");\n this.feedbackDir = path.join(base, \"feedback\");\n this.feedbackInboxPath = path.join(this.feedbackDir, \"inbox.jsonl\");\n this.crossSignalsDir = path.join(base, \"cross-signals\");\n }\n\n async ensureStructure(): Promise<void> {\n await mkdir(this.dir, { recursive: true });\n await mkdir(this.outputsDir, { recursive: true });\n await mkdir(this.roundtableDir, { recursive: true });\n await mkdir(this.feedbackDir, { recursive: true });\n await mkdir(this.crossSignalsDir, { recursive: true });\n await mkdir(path.join(this.dir, \"staging\"), { recursive: true });\n await mkdir(path.join(this.dir, \"kpis\"), { recursive: true });\n await mkdir(path.join(this.dir, \"calendar\"), { recursive: true });\n await mkdir(path.join(this.dir, \"content-calendar\"), { recursive: true });\n\n // Bootstrap files if missing.\n await this.ensureFile(\n this.prioritiesPath,\n [\n \"# Priorities\",\n \"\",\n \"This is the shared priority stack. Agents should read this before acting.\",\n \"\",\n \"## Current\",\n \"- (empty)\",\n \"\",\n \"## Notes\",\n \"- (empty)\",\n \"\",\n ].join(\"\\n\"),\n );\n await this.ensureFile(\n this.prioritiesInboxPath,\n [\n \"# Priorities Inbox\",\n \"\",\n \"Append-only inbox. Curator merges into priorities.md.\",\n \"\",\n ].join(\"\\n\"),\n );\n await this.ensureFile(this.feedbackInboxPath, \"\");\n }\n\n private async ensureFile(fp: string, content: string): Promise<void> {\n try {\n await stat(fp);\n } catch {\n await writeFile(fp, content, \"utf-8\");\n }\n }\n\n async readPriorities(): Promise<string> {\n try {\n return await readFile(this.prioritiesPath, \"utf-8\");\n } catch {\n return \"\";\n }\n }\n\n async readLatestRoundtable(): Promise<string> {\n try {\n const files = (await readdir(this.roundtableDir))\n .filter((f) => f.endsWith(\".md\"))\n .sort()\n .reverse();\n const fp = files[0] ? path.join(this.roundtableDir, files[0]) : null;\n if (!fp) return \"\";\n return await readFile(fp, \"utf-8\");\n } catch {\n return \"\";\n }\n }\n\n async readLatestCrossSignals(): Promise<string> {\n try {\n const files = (await readdir(this.crossSignalsDir))\n .filter((f) => f.endsWith(\".md\"))\n .sort()\n .reverse();\n const fp = files[0] ? path.join(this.crossSignalsDir, files[0]) : null;\n if (!fp) return \"\";\n return await readFile(fp, \"utf-8\");\n } catch {\n return \"\";\n }\n }\n\n async writeAgentOutput(opts: {\n agentId: string;\n title: string;\n content: string;\n createdAt?: Date;\n }): Promise<string> {\n const createdAt = opts.createdAt ?? new Date();\n const date = ymd(createdAt);\n const time = createdAt.toISOString().slice(11, 19).replace(/:/g, \"\");\n const slug = safeSlug(opts.title);\n const agentPathSegment = safePathSegment(opts.agentId, \"agentId\");\n\n const dir = path.join(this.outputsDir, agentPathSegment, date);\n await mkdir(dir, { recursive: true });\n\n const body =\n `---\\n` +\n `kind: agent_output\\n` +\n `agent: ${formatFrontmatterScalar(opts.agentId)}\\n` +\n `createdAt: ${createdAt.toISOString()}\\n` +\n `title: ${formatFrontmatterScalar(opts.title.replace(/\\n/g, \" \").slice(0, 200))}\\n` +\n `---\\n\\n` +\n opts.content.trimEnd() +\n \"\\n\";\n\n for (let attempt = 0; attempt < 100; attempt++) {\n const suffix = attempt === 0 ? \"\" : `-${attempt + 1}`;\n const fp = path.join(dir, `${time}-${slug}${suffix}.md`);\n try {\n await writeFile(fp, body, { encoding: \"utf-8\", flag: \"wx\" });\n return fp;\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"EEXIST\") continue;\n throw error;\n }\n }\n\n throw new Error(`Unable to allocate unique shared-context output path for ${opts.agentId}`);\n }\n\n async appendFeedback(entry: SharedFeedbackEntry): Promise<void> {\n const parsed = SharedFeedbackEntrySchema.parse(entry);\n await appendFile(this.feedbackInboxPath, JSON.stringify(parsed) + \"\\n\", \"utf-8\");\n }\n\n async appendPrioritiesInbox(opts: { agentId: string; text: string }): Promise<void> {\n const stamp = new Date().toISOString();\n const lines = [\n \"\",\n `## ${stamp} (${opts.agentId})`,\n \"\",\n opts.text.trimEnd(),\n \"\",\n ].join(\"\\n\");\n await appendFile(this.prioritiesInboxPath, lines, \"utf-8\");\n }\n\n private async withDailySynthesisLock<T>(date: string, fn: () => Promise<T>): Promise<T> {\n const previous = this.dailySynthesisChains.get(date) ?? Promise.resolve();\n let releaseCurrent!: () => void;\n const current = new Promise<void>((resolve) => {\n releaseCurrent = resolve;\n });\n const queued = previous.catch(() => undefined).then(() => current);\n this.dailySynthesisChains.set(date, queued);\n await previous.catch(() => undefined);\n try {\n return await fn();\n } finally {\n releaseCurrent();\n if (this.dailySynthesisChains.get(date) === queued) {\n this.dailySynthesisChains.delete(date);\n }\n }\n }\n\n async synthesizeCrossSignals(opts: {\n date?: string;\n maxSummaryItems?: number;\n }): Promise<SharedCrossSignalSynthesisResult> {\n const date = safeDateSegment(opts.date ?? ymd(new Date()));\n return this.withDailySynthesisLock(date, () => this.synthesizeCrossSignalsUnlocked({\n date,\n maxSummaryItems: opts.maxSummaryItems,\n }));\n }\n\n private async synthesizeCrossSignalsUnlocked(opts: {\n date: string;\n maxSummaryItems?: number;\n }): Promise<SharedCrossSignalSynthesisResult> {\n const date = opts.date;\n const maxSummaryItems = Math.max(1, opts.maxSummaryItems ?? 8);\n\n // Collect outputs for the day (best-effort).\n const outputs: Array<{ agent: string; path: string; title: string; raw: string }> = [];\n try {\n const agents = (await readdir(this.outputsDir, { withFileTypes: true }))\n .sort((a, b) => a.name.localeCompare(b.name));\n for (const a of agents) {\n if (!a.isDirectory()) continue;\n const dayDir = path.join(this.outputsDir, a.name, date);\n try {\n const files = (await readdir(dayDir)).filter((f) => f.endsWith(\".md\")).sort();\n for (const f of files) {\n const p = path.join(dayDir, f);\n const raw = await readFile(p, \"utf-8\");\n const title = readFrontmatterScalar(raw, \"title\") ?? f;\n const agent = readFrontmatterScalar(raw, \"agent\") ?? safeDecodePathSegment(a.name);\n outputs.push({ agent, path: p, title, raw });\n }\n } catch {\n // no outputs for this agent/date\n }\n }\n } catch {\n // ignore\n }\n outputs.sort(\n (a, b) =>\n a.agent.localeCompare(b.agent)\n || a.path.localeCompare(b.path)\n || a.title.localeCompare(b.title),\n );\n\n // Collect feedback entries for the day.\n const feedback: SharedFeedbackEntry[] = [];\n try {\n const raw = await readFile(this.feedbackInboxPath, \"utf-8\");\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line);\n const parsed = SharedFeedbackEntrySchema.safeParse(obj);\n if (!parsed.success) continue;\n if (String(parsed.data.date).startsWith(date)) feedback.push(parsed.data);\n } catch {\n // ignore\n }\n }\n } catch {\n // ignore\n }\n\n const sources: SharedCrossSignalSource[] = outputs.map((output) => {\n const body = stripYamlFrontmatter(output.raw);\n return {\n agent: output.agent,\n path: output.path,\n title: output.title,\n topics: extractTopicTokens(`${output.title}\\n${body}`),\n };\n });\n\n const overlapMap = new Map<string, { agents: Set<string>; sourcePaths: Set<string> }>();\n for (const source of sources) {\n for (const token of source.topics) {\n const existing = overlapMap.get(token);\n if (existing) {\n existing.agents.add(source.agent);\n existing.sourcePaths.add(source.path);\n } else {\n overlapMap.set(token, {\n agents: new Set([source.agent]),\n sourcePaths: new Set([source.path]),\n });\n }\n }\n }\n\n const overlaps: SharedCrossSignalOverlap[] = [...overlapMap.entries()]\n .map(([token, v]) => ({\n token,\n agents: [...v.agents].sort(),\n sourcePaths: [...v.sourcePaths].sort(),\n agentCount: v.agents.size,\n }))\n .filter((entry) => entry.agentCount >= 2)\n .sort((a, b) => b.agentCount - a.agentCount || a.token.localeCompare(b.token));\n\n const semanticEnabled =\n this.config.sharedCrossSignalSemanticEnabled === true\n || this.config.crossSignalsSemanticEnabled === true;\n const semanticTimeoutMs =\n this.config.sharedCrossSignalSemanticTimeoutMs\n ?? this.config.crossSignalsSemanticTimeoutMs\n ?? 4000;\n const semanticMaxCandidates = this.config.sharedCrossSignalSemanticMaxCandidates ?? 120;\n let semanticApplied = false;\n let semanticTimedOut = false;\n let semanticCandidateCount = 0;\n let semanticAddedOverlapCount = 0;\n let mergedOverlaps = overlaps;\n if (semanticEnabled) {\n try {\n const semanticResult = await computeSemanticOverlapsWithTimeout(\n sources,\n semanticTimeoutMs,\n semanticMaxCandidates,\n );\n semanticTimedOut = semanticResult.timedOut;\n semanticCandidateCount = semanticResult.candidateCount;\n if (!semanticResult.timedOut && semanticResult.overlaps.length > 0) {\n mergedOverlaps = mergeOverlaps(overlaps, semanticResult.overlaps);\n semanticAddedOverlapCount = Math.max(0, mergedOverlaps.length - overlaps.length);\n semanticApplied = semanticAddedOverlapCount > 0;\n }\n } catch (err) {\n log.warn(`shared-context semantic cross-signals failed; fail-open to deterministic output: ${err}`);\n }\n }\n\n const feedbackByDecision: SharedCrossSignalReport[\"feedbackByDecision\"] = {\n approved: 0,\n approved_with_feedback: 0,\n rejected: 0,\n };\n for (const entry of feedback) {\n feedbackByDecision[entry.decision] += 1;\n }\n\n const report: SharedCrossSignalReport = {\n date,\n generatedAt: new Date().toISOString(),\n sourceCount: sources.length,\n feedbackCount: feedback.length,\n feedbackByDecision,\n feedbackEntries: [...feedback].sort(compareFeedbackPriority),\n sources,\n overlaps: mergedOverlaps,\n semantic: {\n enabled: semanticEnabled,\n applied: semanticApplied,\n timedOut: semanticTimedOut,\n candidateCount: semanticCandidateCount,\n maxCandidates: Math.max(0, Math.floor(semanticMaxCandidates)),\n addedOverlapCount: semanticAddedOverlapCount,\n },\n };\n\n const crossSignalsPath = path.join(this.crossSignalsDir, `${date}.json`);\n await writeFileAtomic(crossSignalsPath, `${JSON.stringify(report, null, 2)}\\n`);\n\n const recurringThemeLines = mergedOverlaps.length === 0\n ? [\"- No multi-agent topic overlap detected.\"]\n : mergedOverlaps.slice(0, maxSummaryItems).map((entry) => formatOverlapLine(entry));\n const riskSignals = [...feedback]\n .filter((entry) => entry.decision !== \"approved\" || entry.severity === \"high\" || entry.severity === \"medium\")\n .sort(compareFeedbackPriority)\n .slice(0, maxSummaryItems);\n const riskLines = riskSignals.length === 0\n ? [\"- No explicit blockers or elevated review risks recorded.\"]\n : riskSignals.map((entry) => formatFeedbackLine(entry));\n const promotionCandidates = mergedOverlaps\n .filter((entry) => entry.agentCount >= 3)\n .slice(0, maxSummaryItems);\n const promotionLines = promotionCandidates.length === 0\n ? [\"- No promotion candidates yet.\"]\n : promotionCandidates.map((entry) =>\n `- Consider promoting \\`${entry.token}\\` into priorities or operating rules [sources: ${markdownLineList(entry.sourcePaths)}]`\n );\n\n const crossSignalsMarkdown = [\n `# Cross-Signals — ${date}`,\n \"\",\n \"## Overview\",\n `- Source outputs analyzed: ${sources.length}`,\n `- Feedback entries analyzed: ${feedback.length}`,\n `- Decision totals: approved=${feedbackByDecision.approved}, approved_with_feedback=${feedbackByDecision.approved_with_feedback}, rejected=${feedbackByDecision.rejected}`,\n `- Semantic enhancer: ${semanticEnabled ? (semanticTimedOut ? \"enabled (timed out, fail-open)\" : semanticApplied ? \"enabled (applied)\" : \"enabled (no additional overlaps)\") : \"disabled\"}`,\n `- JSON report: ${crossSignalsPath}`,\n \"\",\n \"## Recurring Themes\",\n ...recurringThemeLines,\n \"\",\n \"## Risks And Blockers\",\n ...riskLines,\n \"\",\n \"## Potential Promotions\",\n ...promotionLines,\n \"\",\n \"## Sources\",\n ...(sources.length === 0 ? [\"- (none)\"] : sources.map((source) =>\n `- [${markdownLineText(source.agent)}] ${markdownLineText(source.title)} (${markdownLineText(source.path)})`\n )),\n \"\",\n ].join(\"\\n\");\n\n const crossSignalsMarkdownPath = path.join(this.crossSignalsDir, `${date}.md`);\n await writeFileAtomic(crossSignalsMarkdownPath, crossSignalsMarkdown);\n\n return {\n date,\n crossSignalsPath,\n crossSignalsMarkdownPath,\n overlapCount: mergedOverlaps.length,\n report,\n };\n }\n\n async curateDaily(opts: { date?: string; maxChars?: number }): Promise<SharedDailyCurationResult> {\n const date = safeDateSegment(opts.date ?? ymd(new Date()));\n return this.withDailySynthesisLock(date, () => this.curateDailyUnlocked({ ...opts, date }));\n }\n\n private async curateDailyUnlocked(opts: { date: string; maxChars?: number }): Promise<SharedDailyCurationResult> {\n const date = opts.date;\n const maxChars = Math.max(2_000, opts.maxChars ?? 20_000);\n const crossSignals = await this.synthesizeCrossSignalsUnlocked({ date });\n const feedbackLines = crossSignals.report.feedbackEntries.length === 0\n ? [\"- (none)\"]\n : crossSignals.report.feedbackEntries.map((entry) => formatFeedbackLine(entry));\n const overlapBullets = crossSignals.report.overlaps.length === 0\n ? [\"- No multi-agent topic overlap detected.\"]\n : crossSignals.report.overlaps.slice(0, 8).map((entry) => formatOverlapLine(entry));\n\n const md: string[] = [\n `# Roundtable — ${date}`,\n \"\",\n \"## Notable Agent Outputs\",\n ...(crossSignals.report.sources.length === 0\n ? [\"- (none)\"]\n : crossSignals.report.sources.map((source) => `- ${source.title} (${source.path})`)),\n \"\",\n \"## Feedback (Approve/Reject)\",\n ...feedbackLines,\n \"\",\n \"## Cross-Signals\",\n `- Source outputs analyzed: ${crossSignals.report.sourceCount}`,\n `- Feedback entries analyzed: ${crossSignals.report.feedbackCount}`,\n `- Decision totals: approved=${crossSignals.report.feedbackByDecision.approved}, approved_with_feedback=${crossSignals.report.feedbackByDecision.approved_with_feedback}, rejected=${crossSignals.report.feedbackByDecision.rejected}`,\n `- Semantic enhancer: ${crossSignals.report.semantic.enabled ? (crossSignals.report.semantic.timedOut ? \"enabled (timed out, fail-open)\" : crossSignals.report.semantic.applied ? \"enabled (applied)\" : \"enabled (no additional overlaps)\") : \"disabled\"}`,\n `- Cross-signals JSON: ${crossSignals.crossSignalsPath}`,\n `- Cross-signals markdown: ${crossSignals.crossSignalsMarkdownPath}`,\n ...overlapBullets,\n \"\",\n ];\n\n const out = md.join(\"\\n\");\n const trimmed = out.length > maxChars ? out.slice(0, maxChars) + \"\\n\\n...(trimmed)\\n\" : out;\n\n const roundtablePath = path.join(this.roundtableDir, `${date}.md`);\n await writeFileAtomic(roundtablePath, trimmed);\n\n log.info(`shared-context curated daily roundtable: ${roundtablePath}`);\n return {\n date,\n roundtablePath,\n crossSignalsPath: crossSignals.crossSignalsPath,\n crossSignalsMarkdownPath: crossSignals.crossSignalsMarkdownPath,\n overlapCount: crossSignals.overlapCount,\n };\n }\n}\n"],"mappings":";;;;;;;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,OAAO,UAAU,SAAS,YAAY,WAAW,MAAM,QAAQ,UAAU;AAClF,OAAO,UAAU;AACjB,SAAS,SAAS;AAKX,IAAM,4BAA4B,EAAE,OAAO;AAAA,EAChD,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,UAAU,EAAE,KAAK,CAAC,YAAY,0BAA0B,UAAU,CAAC;AAAA,EACnE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EACtB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,UAAU,EAAE,KAAK,CAAC,OAAO,UAAU,MAAM,CAAC,EAAE,SAAS;AAAA,EACrD,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC9C,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACrC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,SAAS;AAAA,EAC1C,qBAAqB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAChD,mBAAmB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC9C,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AACrC,CAAC;AAID,SAAS,SAAS,GAAmB;AACnC,MAAI,OAAO,EAAE,YAAY,EAAE,QAAQ,eAAe,GAAG;AAErD,MAAI,QAAQ;AACZ,SAAO,QAAQ,KAAK,UAAU,KAAK,KAAK,MAAM,IAAK;AACnD,MAAI,MAAM,KAAK;AACf,SAAO,MAAM,SAAS,KAAK,MAAM,CAAC,MAAM,IAAK;AAC7C,SAAO,KAAK,MAAM,OAAO,GAAG,EAAE,MAAM,GAAG,EAAE,KAAK;AAChD;AAEA,SAAS,gBAAgB,GAAW,OAAuB;AACzD,MAAI,EAAE,WAAW,EAAG,OAAM,IAAI,MAAM,GAAG,KAAK,oBAAoB;AAChE,MAAI,SAAS,KAAK,CAAC,EAAG,OAAM,IAAI,MAAM,GAAG,KAAK,+BAA+B;AAC7E,QAAM,UAAU,mBAAmB,CAAC;AACpC,MAAI,YAAY,OAAO,YAAY,MAAM;AACvC,WAAO,QAAQ,QAAQ,OAAO,KAAK;AAAA,EACrC;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,GAAmB;AAChD,MAAI;AACF,WAAO,mBAAmB,CAAC;AAAA,EAC7B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,2BAA2B,OAAuB;AACzD,MAAI,MAAM,UAAU,KAAK,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAAG;AACrE,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,UAAI,OAAO,WAAW,SAAU,QAAO;AAAA,IACzC,QAAQ;AAAA,IAER;AACA,WAAO,MAAM,MAAM,GAAG,EAAE,EAAE,QAAQ,QAAQ,GAAG,EAAE,QAAQ,SAAS,IAAI;AAAA,EACtE;AACA,MAAI,MAAM,UAAU,KAAK,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAAG;AACrE,WAAO,MAAM,MAAM,GAAG,EAAE,EAAE,QAAQ,OAAO,GAAG;AAAA,EAC9C;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,OAAuB;AACtD,SAAO,KAAK,UAAU,KAAK;AAC7B;AAEA,SAAS,sBAAsB,KAAa,KAA4B;AACtE,QAAM,cAAc,IAAI,MAAM,wCAAwC,IAAI,CAAC;AAC3E,MAAI,CAAC,YAAa,QAAO;AACzB,aAAW,QAAQ,YAAY,MAAM,OAAO,GAAG;AAC7C,QAAI,CAAC,KAAK,WAAW,GAAG,GAAG,GAAG,EAAG;AACjC,UAAM,QAAQ,KAAK,MAAM,IAAI,SAAS,CAAC,EAAE,KAAK;AAC9C,WAAO,QAAQ,2BAA2B,KAAK,IAAI;AAAA,EACrD;AACA,SAAO;AACT;AAEA,SAAS,IAAI,GAAiB;AAC5B,SAAO,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AACpC;AAEA,SAAS,gBAAgB,MAAsB;AAC7C,MAAI,CAAC,sBAAsB,KAAK,IAAI,GAAG;AACrC,UAAM,IAAI,MAAM,gCAAgC,KAAK,UAAU,IAAI,CAAC,uBAAuB;AAAA,EAC7F;AACA,QAAM,SAAS,oBAAI,KAAK,GAAG,IAAI,gBAAgB;AAC/C,MAAI,CAAC,OAAO,SAAS,OAAO,QAAQ,CAAC,KAAK,OAAO,YAAY,EAAE,MAAM,GAAG,EAAE,MAAM,MAAM;AACpF,UAAM,IAAI,MAAM,gCAAgC,KAAK,UAAU,IAAI,CAAC,iCAAiC;AAAA,EACvG;AACA,SAAO;AACT;AAEA,IAAM,yBAAyB,oBAAI,IAAI;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,mBAAmB,MAAc,YAAoB,IAAc;AAC1E,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,MAAgB,CAAC;AACvB,QAAM,SAAS,KACZ,YAAY,EACZ,QAAQ,gBAAgB,GAAG,EAC3B,MAAM,KAAK,EACX,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAC3B,OAAO,CAAC,UAAU,MAAM,UAAU,CAAC,EACnC,OAAO,CAAC,UAAU,CAAC,uBAAuB,IAAI,KAAK,CAAC;AAEvD,aAAW,SAAS,QAAQ;AAC1B,QAAI,KAAK,IAAI,KAAK,EAAG;AACrB,SAAK,IAAI,KAAK;AACd,QAAI,KAAK,KAAK;AACd,QAAI,IAAI,UAAU,UAAW;AAAA,EAC/B;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,MAAsB;AAClD,MAAI,CAAC,KAAK,WAAW,OAAO,EAAG,QAAO;AACtC,QAAM,UAAU,KAAK,QAAQ,WAAW,CAAC;AACzC,MAAI,YAAY,GAAI,QAAO;AAC3B,SAAO,KAAK,MAAM,UAAU,CAAC;AAC/B;AAEA,SAAS,aAAa,OAAuB;AAC3C,MAAI,OAAO,MAAM,YAAY;AAC7B,MAAI,KAAK,SAAS,UAAU,KAAK,KAAK,SAAS,GAAG;AAChD,WAAO,GAAG,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,EAC7B,WACS,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,GAAG;AACpD,WAAO,GAAG,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,EAC7B,WAAW,KAAK,SAAS,UAAU,KAAK,KAAK,SAAS,GAAG;AACvD,WAAO,GAAG,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,EAC7B,WAAW,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,GAAG;AACtD,WAAO,GAAG,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,EAC7B,OAAO;AACL,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,eAAW,UAAU,UAAU;AAC7B,UAAI,KAAK,SAAS,OAAO,SAAS,KAAK,KAAK,SAAS,MAAM,GAAG;AAC5D,eAAO,KAAK,MAAM,GAAG,CAAC,OAAO,MAAM;AACnC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,MAAI,KAAK,SAAS,KAAK,KAAK,SAAS,GAAG,GAAG;AACzC,WAAO,KAAK,MAAM,GAAG,EAAE;AAAA,EACzB;AACA,SAAO;AACT;AAEA,SAAS,cACP,MACA,OAC4B;AAC5B,QAAM,SAAS,oBAAI,IAA+D;AAClF,aAAW,SAAS,CAAC,GAAG,MAAM,GAAG,KAAK,GAAG;AACvC,UAAM,WAAW,OAAO,IAAI,MAAM,KAAK;AACvC,QAAI,UAAU;AACZ,iBAAW,SAAS,MAAM,OAAQ,UAAS,OAAO,IAAI,KAAK;AAC3D,iBAAW,cAAc,MAAM,YAAa,UAAS,YAAY,IAAI,UAAU;AAAA,IACjF,OAAO;AACL,aAAO,IAAI,MAAM,OAAO;AAAA,QACtB,QAAQ,IAAI,IAAI,MAAM,MAAM;AAAA,QAC5B,aAAa,IAAI,IAAI,MAAM,WAAW;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO,CAAC,GAAG,OAAO,QAAQ,CAAC,EACxB,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO;AAAA,IACxB;AAAA,IACA,QAAQ,CAAC,GAAG,MAAM,MAAM,EAAE,KAAK;AAAA,IAC/B,aAAa,CAAC,GAAG,MAAM,WAAW,EAAE,KAAK;AAAA,IACzC,YAAY,MAAM,OAAO;AAAA,EAC3B,EAAE,EACD,OAAO,CAAC,UAAU,MAAM,cAAc,CAAC,EACvC,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AACjF;AAEA,eAAe,iCACb,SACA,eACA,aAC8F;AAC9F,QAAM,YAAmE,CAAC;AAC1E,aAAW,UAAU,SAAS;AAC5B,eAAW,SAAS,OAAO,QAAQ;AACjC,UAAI,KAAK,IAAI,KAAK,YAAa,QAAO,EAAE,UAAU,CAAC,GAAG,gBAAgB,UAAU,QAAQ,UAAU,KAAK;AACvG,YAAM,IAAI,QAAc,CAAC,YAAY,aAAa,OAAO,CAAC;AAC1D,gBAAU,KAAK,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,OAAO,KAAK,CAAC;AAChE,UAAI,UAAU,UAAU,cAAe;AAAA,IACzC;AACA,QAAI,UAAU,UAAU,cAAe;AAAA,EACzC;AAEA,QAAM,SAAS,oBAAI,IAAsE;AACzF,aAAW,OAAO,WAAW;AAC3B,QAAI,KAAK,IAAI,KAAK,YAAa,QAAO,EAAE,UAAU,CAAC,GAAG,gBAAgB,UAAU,QAAQ,UAAU,KAAK;AACvG,UAAM,IAAI,QAAc,CAAC,YAAY,aAAa,OAAO,CAAC;AAC1D,UAAM,OAAO,aAAa,IAAI,KAAK;AACnC,QAAI,KAAK,SAAS,EAAG;AACrB,UAAM,YAAY,OAAO,IAAI,IAAI,KAAK,oBAAI,IAAyD;AACnG,UAAM,aAAa,UAAU,IAAI,IAAI,KAAK,KAAK,EAAE,QAAQ,oBAAI,IAAY,GAAG,OAAO,oBAAI,IAAY,EAAE;AACrG,eAAW,OAAO,IAAI,IAAI,KAAK;AAC/B,eAAW,MAAM,IAAI,IAAI,IAAI;AAC7B,cAAU,IAAI,IAAI,OAAO,UAAU;AACnC,WAAO,IAAI,MAAM,SAAS;AAAA,EAC5B;AAEA,QAAM,WAAuC,CAAC;AAC9C,aAAW,CAAC,MAAM,QAAQ,KAAK,OAAO,QAAQ,GAAG;AAC/C,QAAI,KAAK,IAAI,KAAK,YAAa,QAAO,EAAE,UAAU,CAAC,GAAG,gBAAgB,UAAU,QAAQ,UAAU,KAAK;AACvG,UAAM,IAAI,QAAc,CAAC,YAAY,aAAa,OAAO,CAAC;AAC1D,QAAI,SAAS,OAAO,EAAG;AACvB,UAAM,SAAS,oBAAI,IAAY;AAC/B,UAAM,cAAc,oBAAI,IAAY;AACpC,eAAW,SAAS,SAAS,OAAO,GAAG;AACrC,iBAAW,SAAS,MAAM,OAAQ,QAAO,IAAI,KAAK;AAClD,iBAAW,cAAc,MAAM,MAAO,aAAY,IAAI,UAAU;AAAA,IAClE;AACA,QAAI,OAAO,OAAO,EAAG;AACrB,aAAS,KAAK;AAAA,MACZ,OAAO,YAAY,IAAI;AAAA,MACvB,QAAQ,CAAC,GAAG,MAAM,EAAE,KAAK;AAAA,MACzB,aAAa,CAAC,GAAG,WAAW,EAAE,KAAK;AAAA,MACnC,YAAY,OAAO;AAAA,IACrB,CAAC;AAAA,EACH;AAEA,WAAS,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AACrF,SAAO;AAAA,IACL;AAAA,IACA,gBAAgB,UAAU;AAAA,IAC1B,UAAU;AAAA,EACZ;AACF;AAEA,eAAe,mCACb,SACA,WACA,eAC8F;AAC9F,QAAM,gBAAgB,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,CAAC;AACvD,QAAM,oBAAoB,KAAK,IAAI,GAAG,KAAK,MAAM,aAAa,CAAC;AAC/D,MAAI,sBAAsB,KAAK,QAAQ,WAAW,GAAG;AACnD,WAAO,EAAE,UAAU,CAAC,GAAG,gBAAgB,GAAG,UAAU,MAAM;AAAA,EAC5D;AACA,QAAM,cAAc,KAAK,IAAI,IAAI;AACjC,SAAO,iCAAiC,SAAS,mBAAmB,WAAW;AACjF;AAmDA,SAAS,yBAAyB,UAAmD;AACnF,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAEA,SAAS,yBAAyB,UAAmD;AACnF,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,wBAAwB,GAAwB,GAAgC;AACvF,SACE,yBAAyB,EAAE,QAAQ,IAAI,yBAAyB,EAAE,QAAQ,KACvE,yBAAyB,EAAE,QAAQ,IAAI,yBAAyB,EAAE,QAAQ,KAC1E,EAAE,KAAK,cAAc,EAAE,IAAI;AAElC;AAEA,SAAS,iBAAiB,OAAuB;AAC/C,SAAO,MAAM,QAAQ,YAAY,GAAG,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAClE;AAEA,SAAS,iBAAiB,QAAmC;AAC3D,SAAO,OAAO,IAAI,gBAAgB,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;AAC/D;AAEA,SAAS,mBAAmB,OAAoC;AAC9D,QAAM,SAAmB,CAAC,aAAa,iBAAiB,MAAM,IAAI,CAAC,EAAE;AACrE,MAAI,MAAM,SAAU,QAAO,KAAK,aAAa,iBAAiB,MAAM,QAAQ,CAAC,EAAE;AAC/E,MAAI,MAAM,MAAM,OAAQ,QAAO,KAAK,SAAS,iBAAiB,MAAM,IAAI,CAAC,EAAE;AAC3E,SAAO,MAAM,iBAAiB,MAAM,KAAK,CAAC,KAAK,MAAM,QAAQ,KAAK,iBAAiB,MAAM,MAAM,CAAC,KAAK,OAAO,KAAK,IAAI,CAAC;AACxH;AAEA,SAAS,kBAAkB,OAAyC;AAClE,SAAO,OAAO,MAAM,KAAK,OAAO,MAAM,UAAU,YAAY,iBAAiB,MAAM,MAAM,CAAC,eAAe,iBAAiB,MAAM,WAAW,CAAC;AAC9I;AAEA,eAAe,gBAAgB,UAAkB,SAAgC;AAC/E,QAAM,MAAM,KAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AACvD,QAAM,WAAW,KAAK;AAAA,IACpB,KAAK,QAAQ,QAAQ;AAAA,IACrB,IAAI,KAAK,SAAS,QAAQ,CAAC,IAAI,QAAQ,GAAG,IAAI,WAAW,CAAC;AAAA,EAC5D;AACA,MAAI;AACF,UAAM,UAAU,UAAU,SAAS,EAAE,UAAU,SAAS,MAAM,KAAK,CAAC;AACpE,UAAM,OAAO,UAAU,QAAQ;AAAA,EACjC,SAAS,OAAO;AACd,UAAM,GAAG,UAAU,EAAE,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM,MAAS;AACzD,UAAM;AAAA,EACR;AACF;AAEO,SAAS,wBAAwB,QAA8B;AACpE,SAAO,OAAO,OAAO,qBAAqB,YAAY,OAAO,iBAAiB,SAAS,IACnF,gBAAgB,OAAO,gBAAgB,IACvC,KAAK,KAAK,gBAAgB,OAAO,YAAY,GAAG,gBAAgB;AACtE;AAEO,IAAM,uBAAN,MAA2B;AAAA,EAWhC,YAA6B,QAAsB;AAAtB;AAC3B,UAAM,OAAO,wBAAwB,MAAM;AAE3C,SAAK,MAAM;AACX,SAAK,iBAAiB,KAAK,KAAK,MAAM,eAAe;AACrD,SAAK,sBAAsB,KAAK,KAAK,MAAM,qBAAqB;AAChE,SAAK,aAAa,KAAK,KAAK,MAAM,eAAe;AACjD,SAAK,gBAAgB,KAAK,KAAK,MAAM,YAAY;AACjD,SAAK,cAAc,KAAK,KAAK,MAAM,UAAU;AAC7C,SAAK,oBAAoB,KAAK,KAAK,KAAK,aAAa,aAAa;AAClE,SAAK,kBAAkB,KAAK,KAAK,MAAM,eAAe;AAAA,EACxD;AAAA,EAX6B;AAAA,EAVpB;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,uBAAuB,oBAAI,IAA2B;AAAA,EAevE,MAAM,kBAAiC;AACrC,UAAM,MAAM,KAAK,KAAK,EAAE,WAAW,KAAK,CAAC;AACzC,UAAM,MAAM,KAAK,YAAY,EAAE,WAAW,KAAK,CAAC;AAChD,UAAM,MAAM,KAAK,eAAe,EAAE,WAAW,KAAK,CAAC;AACnD,UAAM,MAAM,KAAK,aAAa,EAAE,WAAW,KAAK,CAAC;AACjD,UAAM,MAAM,KAAK,iBAAiB,EAAE,WAAW,KAAK,CAAC;AACrD,UAAM,MAAM,KAAK,KAAK,KAAK,KAAK,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/D,UAAM,MAAM,KAAK,KAAK,KAAK,KAAK,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5D,UAAM,MAAM,KAAK,KAAK,KAAK,KAAK,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAChE,UAAM,MAAM,KAAK,KAAK,KAAK,KAAK,kBAAkB,GAAG,EAAE,WAAW,KAAK,CAAC;AAGxE,UAAM,KAAK;AAAA,MACT,KAAK;AAAA,MACL;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,IACb;AACA,UAAM,KAAK;AAAA,MACT,KAAK;AAAA,MACL;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,IACb;AACA,UAAM,KAAK,WAAW,KAAK,mBAAmB,EAAE;AAAA,EAClD;AAAA,EAEA,MAAc,WAAW,IAAY,SAAgC;AACnE,QAAI;AACF,YAAM,KAAK,EAAE;AAAA,IACf,QAAQ;AACN,YAAM,UAAU,IAAI,SAAS,OAAO;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,MAAM,iBAAkC;AACtC,QAAI;AACF,aAAO,MAAM,SAAS,KAAK,gBAAgB,OAAO;AAAA,IACpD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,uBAAwC;AAC5C,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,KAAK,aAAa,GAC5C,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC,EAC/B,KAAK,EACL,QAAQ;AACX,YAAM,KAAK,MAAM,CAAC,IAAI,KAAK,KAAK,KAAK,eAAe,MAAM,CAAC,CAAC,IAAI;AAChE,UAAI,CAAC,GAAI,QAAO;AAChB,aAAO,MAAM,SAAS,IAAI,OAAO;AAAA,IACnC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,yBAA0C;AAC9C,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,KAAK,eAAe,GAC9C,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC,EAC/B,KAAK,EACL,QAAQ;AACX,YAAM,KAAK,MAAM,CAAC,IAAI,KAAK,KAAK,KAAK,iBAAiB,MAAM,CAAC,CAAC,IAAI;AAClE,UAAI,CAAC,GAAI,QAAO;AAChB,aAAO,MAAM,SAAS,IAAI,OAAO;AAAA,IACnC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,iBAAiB,MAKH;AAClB,UAAM,YAAY,KAAK,aAAa,oBAAI,KAAK;AAC7C,UAAM,OAAO,IAAI,SAAS;AAC1B,UAAM,OAAO,UAAU,YAAY,EAAE,MAAM,IAAI,EAAE,EAAE,QAAQ,MAAM,EAAE;AACnE,UAAM,OAAO,SAAS,KAAK,KAAK;AAChC,UAAM,mBAAmB,gBAAgB,KAAK,SAAS,SAAS;AAEhE,UAAM,MAAM,KAAK,KAAK,KAAK,YAAY,kBAAkB,IAAI;AAC7D,UAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AAEpC,UAAM,OACJ;AAAA;AAAA,SAEU,wBAAwB,KAAK,OAAO,CAAC;AAAA,aACjC,UAAU,YAAY,CAAC;AAAA,SAC3B,wBAAwB,KAAK,MAAM,QAAQ,OAAO,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,CAAC;AAAA;AAAA;AAAA,IAE/E,KAAK,QAAQ,QAAQ,IACrB;AAEF,aAAS,UAAU,GAAG,UAAU,KAAK,WAAW;AAC9C,YAAM,SAAS,YAAY,IAAI,KAAK,IAAI,UAAU,CAAC;AACnD,YAAM,KAAK,KAAK,KAAK,KAAK,GAAG,IAAI,IAAI,IAAI,GAAG,MAAM,KAAK;AACvD,UAAI;AACF,cAAM,UAAU,IAAI,MAAM,EAAE,UAAU,SAAS,MAAM,KAAK,CAAC;AAC3D,eAAO;AAAA,MACT,SAAS,OAAO;AACd,YAAI,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS,SAAU;AAC1E,cAAM;AAAA,MACR;AAAA,IACF;AAEA,UAAM,IAAI,MAAM,4DAA4D,KAAK,OAAO,EAAE;AAAA,EAC5F;AAAA,EAEA,MAAM,eAAe,OAA2C;AAC9D,UAAM,SAAS,0BAA0B,MAAM,KAAK;AACpD,UAAM,WAAW,KAAK,mBAAmB,KAAK,UAAU,MAAM,IAAI,MAAM,OAAO;AAAA,EACjF;AAAA,EAEA,MAAM,sBAAsB,MAAwD;AAClF,UAAM,SAAQ,oBAAI,KAAK,GAAE,YAAY;AACrC,UAAM,QAAQ;AAAA,MACZ;AAAA,MACA,MAAM,KAAK,KAAK,KAAK,OAAO;AAAA,MAC5B;AAAA,MACA,KAAK,KAAK,QAAQ;AAAA,MAClB;AAAA,IACF,EAAE,KAAK,IAAI;AACX,UAAM,WAAW,KAAK,qBAAqB,OAAO,OAAO;AAAA,EAC3D;AAAA,EAEA,MAAc,uBAA0B,MAAc,IAAkC;AACtF,UAAM,WAAW,KAAK,qBAAqB,IAAI,IAAI,KAAK,QAAQ,QAAQ;AACxE,QAAI;AACJ,UAAM,UAAU,IAAI,QAAc,CAAC,YAAY;AAC7C,uBAAiB;AAAA,IACnB,CAAC;AACD,UAAM,SAAS,SAAS,MAAM,MAAM,MAAS,EAAE,KAAK,MAAM,OAAO;AACjE,SAAK,qBAAqB,IAAI,MAAM,MAAM;AAC1C,UAAM,SAAS,MAAM,MAAM,MAAS;AACpC,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,UAAE;AACA,qBAAe;AACf,UAAI,KAAK,qBAAqB,IAAI,IAAI,MAAM,QAAQ;AAClD,aAAK,qBAAqB,OAAO,IAAI;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,uBAAuB,MAGiB;AAC5C,UAAM,OAAO,gBAAgB,KAAK,QAAQ,IAAI,oBAAI,KAAK,CAAC,CAAC;AACzD,WAAO,KAAK,uBAAuB,MAAM,MAAM,KAAK,+BAA+B;AAAA,MACjF;AAAA,MACA,iBAAiB,KAAK;AAAA,IACxB,CAAC,CAAC;AAAA,EACJ;AAAA,EAEA,MAAc,+BAA+B,MAGC;AAC5C,UAAM,OAAO,KAAK;AAClB,UAAM,kBAAkB,KAAK,IAAI,GAAG,KAAK,mBAAmB,CAAC;AAG7D,UAAM,UAA8E,CAAC;AACrF,QAAI;AACF,YAAM,UAAU,MAAM,QAAQ,KAAK,YAAY,EAAE,eAAe,KAAK,CAAC,GACnE,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAC9C,iBAAW,KAAK,QAAQ;AACtB,YAAI,CAAC,EAAE,YAAY,EAAG;AACtB,cAAM,SAAS,KAAK,KAAK,KAAK,YAAY,EAAE,MAAM,IAAI;AACtD,YAAI;AACF,gBAAM,SAAS,MAAM,QAAQ,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC,EAAE,KAAK;AAC5E,qBAAW,KAAK,OAAO;AACrB,kBAAM,IAAI,KAAK,KAAK,QAAQ,CAAC;AAC7B,kBAAM,MAAM,MAAM,SAAS,GAAG,OAAO;AACrC,kBAAM,QAAQ,sBAAsB,KAAK,OAAO,KAAK;AACrD,kBAAM,QAAQ,sBAAsB,KAAK,OAAO,KAAK,sBAAsB,EAAE,IAAI;AACjF,oBAAQ,KAAK,EAAE,OAAO,MAAM,GAAG,OAAO,IAAI,CAAC;AAAA,UAC7C;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AACA,YAAQ;AAAA,MACN,CAAC,GAAG,MACF,EAAE,MAAM,cAAc,EAAE,KAAK,KAC1B,EAAE,KAAK,cAAc,EAAE,IAAI,KAC3B,EAAE,MAAM,cAAc,EAAE,KAAK;AAAA,IACpC;AAGA,UAAM,WAAkC,CAAC;AACzC,QAAI;AACF,YAAM,MAAM,MAAM,SAAS,KAAK,mBAAmB,OAAO;AAC1D,iBAAW,QAAQ,IAAI,MAAM,IAAI,GAAG;AAClC,YAAI,CAAC,KAAK,KAAK,EAAG;AAClB,YAAI;AACF,gBAAM,MAAM,KAAK,MAAM,IAAI;AAC3B,gBAAM,SAAS,0BAA0B,UAAU,GAAG;AACtD,cAAI,CAAC,OAAO,QAAS;AACrB,cAAI,OAAO,OAAO,KAAK,IAAI,EAAE,WAAW,IAAI,EAAG,UAAS,KAAK,OAAO,IAAI;AAAA,QAC1E,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,UAAM,UAAqC,QAAQ,IAAI,CAAC,WAAW;AACjE,YAAM,OAAO,qBAAqB,OAAO,GAAG;AAC5C,aAAO;AAAA,QACL,OAAO,OAAO;AAAA,QACd,MAAM,OAAO;AAAA,QACb,OAAO,OAAO;AAAA,QACd,QAAQ,mBAAmB,GAAG,OAAO,KAAK;AAAA,EAAK,IAAI,EAAE;AAAA,MACvD;AAAA,IACF,CAAC;AAED,UAAM,aAAa,oBAAI,IAA+D;AACtF,eAAW,UAAU,SAAS;AAC5B,iBAAW,SAAS,OAAO,QAAQ;AACjC,cAAM,WAAW,WAAW,IAAI,KAAK;AACrC,YAAI,UAAU;AACZ,mBAAS,OAAO,IAAI,OAAO,KAAK;AAChC,mBAAS,YAAY,IAAI,OAAO,IAAI;AAAA,QACtC,OAAO;AACL,qBAAW,IAAI,OAAO;AAAA,YACpB,QAAQ,oBAAI,IAAI,CAAC,OAAO,KAAK,CAAC;AAAA,YAC9B,aAAa,oBAAI,IAAI,CAAC,OAAO,IAAI,CAAC;AAAA,UACpC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,UAAM,WAAuC,CAAC,GAAG,WAAW,QAAQ,CAAC,EAClE,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO;AAAA,MACpB;AAAA,MACA,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK;AAAA,MAC3B,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK;AAAA,MACrC,YAAY,EAAE,OAAO;AAAA,IACvB,EAAE,EACD,OAAO,CAAC,UAAU,MAAM,cAAc,CAAC,EACvC,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AAE/E,UAAM,kBACJ,KAAK,OAAO,qCAAqC,QAC9C,KAAK,OAAO,gCAAgC;AACjD,UAAM,oBACJ,KAAK,OAAO,sCACT,KAAK,OAAO,iCACZ;AACL,UAAM,wBAAwB,KAAK,OAAO,0CAA0C;AACpF,QAAI,kBAAkB;AACtB,QAAI,mBAAmB;AACvB,QAAI,yBAAyB;AAC7B,QAAI,4BAA4B;AAChC,QAAI,iBAAiB;AACrB,QAAI,iBAAiB;AACnB,UAAI;AACF,cAAM,iBAAiB,MAAM;AAAA,UAC3B;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,2BAAmB,eAAe;AAClC,iCAAyB,eAAe;AACxC,YAAI,CAAC,eAAe,YAAY,eAAe,SAAS,SAAS,GAAG;AAClE,2BAAiB,cAAc,UAAU,eAAe,QAAQ;AAChE,sCAA4B,KAAK,IAAI,GAAG,eAAe,SAAS,SAAS,MAAM;AAC/E,4BAAkB,4BAA4B;AAAA,QAChD;AAAA,MACF,SAAS,KAAK;AACZ,YAAI,KAAK,oFAAoF,GAAG,EAAE;AAAA,MACpG;AAAA,IACF;AAEA,UAAM,qBAAoE;AAAA,MACxE,UAAU;AAAA,MACV,wBAAwB;AAAA,MACxB,UAAU;AAAA,IACZ;AACA,eAAW,SAAS,UAAU;AAC5B,yBAAmB,MAAM,QAAQ,KAAK;AAAA,IACxC;AAEA,UAAM,SAAkC;AAAA,MACtC;AAAA,MACA,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,aAAa,QAAQ;AAAA,MACrB,eAAe,SAAS;AAAA,MACxB;AAAA,MACA,iBAAiB,CAAC,GAAG,QAAQ,EAAE,KAAK,uBAAuB;AAAA,MAC3D;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,QACR,SAAS;AAAA,QACT,SAAS;AAAA,QACT,UAAU;AAAA,QACV,gBAAgB;AAAA,QAChB,eAAe,KAAK,IAAI,GAAG,KAAK,MAAM,qBAAqB,CAAC;AAAA,QAC5D,mBAAmB;AAAA,MACrB;AAAA,IACF;AAEA,UAAM,mBAAmB,KAAK,KAAK,KAAK,iBAAiB,GAAG,IAAI,OAAO;AACvE,UAAM,gBAAgB,kBAAkB,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,CAAI;AAE9E,UAAM,sBAAsB,eAAe,WAAW,IAClD,CAAC,0CAA0C,IAC3C,eAAe,MAAM,GAAG,eAAe,EAAE,IAAI,CAAC,UAAU,kBAAkB,KAAK,CAAC;AACpF,UAAM,cAAc,CAAC,GAAG,QAAQ,EAC7B,OAAO,CAAC,UAAU,MAAM,aAAa,cAAc,MAAM,aAAa,UAAU,MAAM,aAAa,QAAQ,EAC3G,KAAK,uBAAuB,EAC5B,MAAM,GAAG,eAAe;AAC3B,UAAM,YAAY,YAAY,WAAW,IACrC,CAAC,2DAA2D,IAC5D,YAAY,IAAI,CAAC,UAAU,mBAAmB,KAAK,CAAC;AACxD,UAAM,sBAAsB,eACzB,OAAO,CAAC,UAAU,MAAM,cAAc,CAAC,EACvC,MAAM,GAAG,eAAe;AAC3B,UAAM,iBAAiB,oBAAoB,WAAW,IAClD,CAAC,gCAAgC,IACjC,oBAAoB;AAAA,MAAI,CAAC,UACvB,0BAA0B,MAAM,KAAK,mDAAmD,iBAAiB,MAAM,WAAW,CAAC;AAAA,IAC7H;AAEJ,UAAM,uBAAuB;AAAA,MAC3B,0BAAqB,IAAI;AAAA,MACzB;AAAA,MACA;AAAA,MACA,8BAA8B,QAAQ,MAAM;AAAA,MAC5C,gCAAgC,SAAS,MAAM;AAAA,MAC/C,+BAA+B,mBAAmB,QAAQ,4BAA4B,mBAAmB,sBAAsB,cAAc,mBAAmB,QAAQ;AAAA,MACxK,wBAAwB,kBAAmB,mBAAmB,mCAAmC,kBAAkB,sBAAsB,qCAAsC,UAAU;AAAA,MACzL,kBAAkB,gBAAgB;AAAA,MAClC;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA,GAAI,QAAQ,WAAW,IAAI,CAAC,UAAU,IAAI,QAAQ;AAAA,QAAI,CAAC,WACrD,MAAM,iBAAiB,OAAO,KAAK,CAAC,KAAK,iBAAiB,OAAO,KAAK,CAAC,KAAK,iBAAiB,OAAO,IAAI,CAAC;AAAA,MAC3G;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAEX,UAAM,2BAA2B,KAAK,KAAK,KAAK,iBAAiB,GAAG,IAAI,KAAK;AAC7E,UAAM,gBAAgB,0BAA0B,oBAAoB;AAEpE,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc,eAAe;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,MAAgF;AAChG,UAAM,OAAO,gBAAgB,KAAK,QAAQ,IAAI,oBAAI,KAAK,CAAC,CAAC;AACzD,WAAO,KAAK,uBAAuB,MAAM,MAAM,KAAK,oBAAoB,EAAE,GAAG,MAAM,KAAK,CAAC,CAAC;AAAA,EAC5F;AAAA,EAEA,MAAc,oBAAoB,MAA+E;AAC/G,UAAM,OAAO,KAAK;AAClB,UAAM,WAAW,KAAK,IAAI,KAAO,KAAK,YAAY,GAAM;AACxD,UAAM,eAAe,MAAM,KAAK,+BAA+B,EAAE,KAAK,CAAC;AACvE,UAAM,gBAAgB,aAAa,OAAO,gBAAgB,WAAW,IACjE,CAAC,UAAU,IACX,aAAa,OAAO,gBAAgB,IAAI,CAAC,UAAU,mBAAmB,KAAK,CAAC;AAChF,UAAM,iBAAiB,aAAa,OAAO,SAAS,WAAW,IAC3D,CAAC,0CAA0C,IAC3C,aAAa,OAAO,SAAS,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU,kBAAkB,KAAK,CAAC;AAEpF,UAAM,KAAe;AAAA,MACnB,uBAAkB,IAAI;AAAA,MACtB;AAAA,MACA;AAAA,MACA,GAAI,aAAa,OAAO,QAAQ,WAAW,IACvC,CAAC,UAAU,IACX,aAAa,OAAO,QAAQ,IAAI,CAAC,WAAW,KAAK,OAAO,KAAK,KAAK,OAAO,IAAI,GAAG;AAAA,MACpF;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA,8BAA8B,aAAa,OAAO,WAAW;AAAA,MAC7D,gCAAgC,aAAa,OAAO,aAAa;AAAA,MACjE,+BAA+B,aAAa,OAAO,mBAAmB,QAAQ,4BAA4B,aAAa,OAAO,mBAAmB,sBAAsB,cAAc,aAAa,OAAO,mBAAmB,QAAQ;AAAA,MACpO,wBAAwB,aAAa,OAAO,SAAS,UAAW,aAAa,OAAO,SAAS,WAAW,mCAAmC,aAAa,OAAO,SAAS,UAAU,sBAAsB,qCAAsC,UAAU;AAAA,MACxP,yBAAyB,aAAa,gBAAgB;AAAA,MACtD,6BAA6B,aAAa,wBAAwB;AAAA,MAClE,GAAG;AAAA,MACH;AAAA,IACF;AAEA,UAAM,MAAM,GAAG,KAAK,IAAI;AACxB,UAAM,UAAU,IAAI,SAAS,WAAW,IAAI,MAAM,GAAG,QAAQ,IAAI,uBAAuB;AAExF,UAAM,iBAAiB,KAAK,KAAK,KAAK,eAAe,GAAG,IAAI,KAAK;AACjE,UAAM,gBAAgB,gBAAgB,OAAO;AAE7C,QAAI,KAAK,4CAA4C,cAAc,EAAE;AACrE,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,kBAAkB,aAAa;AAAA,MAC/B,0BAA0B,aAAa;AAAA,MACvC,cAAc,aAAa;AAAA,IAC7B;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/embedding-fallback.ts"],"sourcesContent":["import path from \"node:path\";\nimport { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { log } from \"./logger.js\";\nimport {\n resolveMemoryLifecycleCapabilities,\n resolveLocalLlmCapabilities,\n} from \"./capabilities.js\";\nimport { readEnvVar } from \"./runtime/env.js\";\nimport type { PluginConfig } from \"./types.js\";\nimport {\n getHostEmbeddingProvider,\n type HostEmbeddingProvider,\n normalizeHostEmbeddingVector,\n} from \"./host-embedding-provider.js\";\n\ntype EmbeddingProviderType = \"openai\" | \"local\" | \"host\";\n\ntype ProviderConfig = {\n type: EmbeddingProviderType;\n model: string;\n endpoint?: string;\n headers?: Record<string, string>;\n hostProvider?: HostEmbeddingProvider;\n};\n\ntype EmbeddingIndexEntry = {\n vector: number[];\n path: string;\n};\n\ntype EmbeddingResult = {\n provider: ProviderConfig;\n vector: number[];\n};\n\ntype EmbeddingIndexFile = {\n version: 1;\n provider: EmbeddingProviderType;\n model: string;\n entries: Record<string, EmbeddingIndexEntry>;\n};\n\ntype EmbeddingIndexIdentity = Pick<EmbeddingIndexFile, \"provider\" | \"model\">;\ntype EmbeddingIndexComparable =\n | EmbeddingIndexIdentity\n | Pick<ProviderConfig, \"type\" | \"model\">;\n\nconst DEFAULT_OPENAI_MODEL = \"text-embedding-3-small\";\n\n/**\n * Thrown by `EmbeddingFallback.search()` (via `embed()`) when the embedding\n * backend is effectively unavailable on the lookup path — either because the\n * HTTP fetch exceeded its deadline OR because the endpoint returned a non-2xx\n * status code. Callers that need to distinguish a backend outage from \"no\n * candidates\" can `instanceof`-check against this class.\n *\n * Round 9 fix (Finding UZqB): previously a timeout returned null from embed(),\n * which caused search() to return [] silently. decideSemanticDedup then\n * classified the result as no_candidates instead of backend_unavailable, so\n * the per-batch batchBackendUnavailable short-circuit never activated and\n * batches of N facts each paid a full timeout roundtrip.\n *\n * Round 10 fix (Findings Ui1J + Ui1L): search() now only re-throws this error\n * when the caller explicitly passes `{ throwOnTimeout: true }`. Without that\n * flag search() catches it and returns [] instead, preserving fail-open\n * semantics for recall-path callers (searchEmbeddingFallback) that have no\n * try/catch. Only the semantic-dedup path (semanticDedupLookup) passes the\n * flag so it can still reach decideSemanticDedup's backend_unavailable branch.\n *\n * Round 11 fix (Finding Ur_J): `embed()` now also throws this error from the\n * lookup path when the HTTP response is non-2xx (e.g. 429, 500, 503). Without\n * this, repeated 5xx outages would each return null → [] → no_candidates and\n * subsequent facts in the same batch would all pay full roundtrips instead of\n * tripping the per-batch backend_unavailable short-circuit.\n *\n * The class name is kept for backward compatibility — `EmbeddingTimeoutError`\n * now signals \"lookup backend unavailable\" rather than strictly \"timed out\".\n */\nexport class EmbeddingTimeoutError extends Error {\n override readonly name = \"EmbeddingTimeoutError\" as const;\n constructor(message: string) {\n super(message);\n }\n}\n\nexport class EmbeddingProviderUnavailableError extends Error {\n override readonly name = \"EmbeddingProviderUnavailableError\" as const;\n constructor(message: string) {\n super(message);\n }\n}\n\nfunction isLookupBackendUnavailableError(err: unknown): boolean {\n return (\n err instanceof EmbeddingTimeoutError ||\n err instanceof EmbeddingProviderUnavailableError\n );\n}\n\n/**\n * Maximum time to wait for an embedding HTTP request on the LOOKUP/query\n * path before giving up.\n *\n * The write-time semantic dedup guard in orchestrator.persistExtraction()\n * blocks each candidate fact on an embedding lookup. If the embedding\n * endpoint hangs (degraded OpenAI, stalled local gateway, DNS timeout),\n * extraction would otherwise stall indefinitely — a single bad backend\n * could freeze the entire persist loop. Bounding the fetch here ensures\n * the decision path fails open (returns null) within a predictable window\n * and writes proceed as non-duplicates.\n *\n * Tests can override via REMNIC_EMBEDDING_FETCH_TIMEOUT_MS so they don't\n * have to wait the full default on hung-fetch assertions.\n *\n * Related: joshuaswarren/remnic#373, PR #399 P1/P2 review.\n */\nconst DEFAULT_EMBEDDING_LOOKUP_TIMEOUT_MS = 5000;\n\n/**\n * Maximum time to wait for an embedding HTTP request on the INDEX path.\n *\n * Indexing runs asynchronously after a memory has already been persisted\n * to disk. It does not block extraction or writes — it only updates the\n * embedding index used by later semantic dedup lookups. A slow local\n * CPU-backed embedding model can legitimately take tens of seconds per\n * call, so applying the short lookup timeout here silently dropped index\n * updates and caused later dedup lookups to miss recently persisted\n * memories. Use a much larger budget on this path.\n *\n * Tests can override via REMNIC_EMBEDDING_INDEX_TIMEOUT_MS.\n */\nconst DEFAULT_EMBEDDING_INDEX_TIMEOUT_MS = 120_000;\n\nfunction resolveEmbeddingLookupTimeoutMs(): number {\n const raw = readEnvVar(\"REMNIC_EMBEDDING_FETCH_TIMEOUT_MS\");\n if (raw) {\n const parsed = Number(raw);\n if (Number.isFinite(parsed) && parsed > 0) {\n return Math.floor(parsed);\n }\n }\n return DEFAULT_EMBEDDING_LOOKUP_TIMEOUT_MS;\n}\n\nfunction resolveEmbeddingIndexTimeoutMs(): number {\n const raw = readEnvVar(\"REMNIC_EMBEDDING_INDEX_TIMEOUT_MS\");\n if (raw) {\n const parsed = Number(raw);\n if (Number.isFinite(parsed) && parsed > 0) {\n return Math.floor(parsed);\n }\n }\n return DEFAULT_EMBEDDING_INDEX_TIMEOUT_MS;\n}\n\n/**\n * Options for the low-level embed() call.\n *\n * `mode` selects the timeout profile:\n * - \"lookup\" (default): bounded by the short lookup budget; fails open fast.\n * - \"index\": bounded by a much longer budget so slow backends can still\n * index newly persisted memories.\n */\nexport type EmbedMode = \"lookup\" | \"index\";\n\nexport class EmbeddingFallback {\n private readonly indexPath: string;\n private loaded: EmbeddingIndexFile | null = null;\n private mutationQueue: Promise<void> = Promise.resolve();\n\n constructor(private readonly config: PluginConfig) {\n this.indexPath = path.join(config.memoryDir, \"state\", \"embeddings.json\");\n }\n\n async isAvailable(): Promise<boolean> {\n return (await this.resolveProvider()) !== null;\n }\n\n /**\n * Embed an array of texts and return their embedding vectors.\n *\n * This is the public batch-embed interface used by semantic chunking\n * (Finding 1, PR #420 post-merge). Texts are grouped into batches of\n * `embeddingBatchSize` (from `semanticChunkingConfig`, default 32) and\n * each batch is dispatched concurrently via `Promise.all()`. This\n * preserves the semantic intent of `embeddingBatchSize` — without batching,\n * every text incurred a sequential HTTP round-trip, making the batch size\n * config ineffective. (PR #439 post-merge Finding 2.)\n *\n * If the provider is unavailable or any single embedding fails, the method\n * throws so the caller can fall back to recursive chunking.\n */\n async embedTexts(texts: string[]): Promise<number[][]> {\n const provider = await this.resolveProvider();\n if (!provider) {\n throw new Error(\"Embedding provider is not available\");\n }\n\n const batchSize = Math.max(\n 1,\n this.config.semanticChunkingConfig?.embeddingBatchSize ?? 32,\n );\n\n const vectors: number[][] = [];\n for (let i = 0; i < texts.length; i += batchSize) {\n const batch = texts.slice(i, i + batchSize);\n const batchResults = await Promise.all(\n batch.map((text) => this.embed(text, provider, { mode: \"lookup\" })),\n );\n for (const vec of batchResults) {\n if (!vec) {\n throw new Error(\"Embedding returned null for input text\");\n }\n vectors.push(vec);\n }\n }\n return vectors;\n }\n\n /**\n * Nearest-neighbor search against the embedding index.\n *\n * @param query The query string to embed and search for.\n * @param limit Max number of hits to return.\n * @param options Optional filters.\n * - `pathPrefix` Restrict candidates to entries whose indexed `path`\n * starts with this prefix (relative to `memoryDir`).\n * Used by the semantic dedup guard to scope lookups\n * to the target namespace so a high-similarity hit\n * from a different namespace can't suppress a write\n * in the target namespace. Default: no filter.\n * - `pathExcludePrefixes`\n * Exclude any entry whose indexed `path` starts with\n * any of these prefixes. Used for the default\n * namespace case: when the default namespace lives at\n * `memoryDir` root (legacy layout) we still want to\n * exclude `namespaces/<other>/…` entries.\n */\n async search(\n query: string,\n limit: number,\n options: {\n pathPrefix?: string;\n pathExcludePrefixes?: readonly string[];\n /**\n * When true, an `EmbeddingTimeoutError` from the embedding backend is\n * re-thrown to the caller. Use this on the semantic-dedup path so\n * `decideSemanticDedup`'s catch block can classify the result as\n * `reason=\"backend_unavailable\"` and activate the per-batch\n * short-circuit.\n *\n * When false (the default), a timeout is caught here and search()\n * returns [] instead — preserving fail-open semantics for the recall\n * path (`searchEmbeddingFallback`) which has no surrounding try/catch.\n * Without this gate a timed-out embedding request on the recall path\n * would propagate as an unhandled rejection and abort recall entirely.\n * (Round 10 fix, Findings Ui1J + Ui1L.)\n */\n throwOnTimeout?: boolean;\n } = {},\n ): Promise<Array<{ id: string; score: number; path: string }>> {\n const provider = await this.resolveProvider();\n if (!provider) return [];\n\n let queryResult = await this.embedForSearch(query, provider, options);\n if (!queryResult) return [];\n\n const diskIdentity = await this.readIndexIdentityFromDisk();\n if (diskIdentity && !sameIndexIdentity(diskIdentity, queryResult.provider)) {\n const diskProvider = await this.resolveFallbackProviderForIndexIdentity(diskIdentity);\n if (diskProvider) {\n const diskQueryResult = await this.embedForSearch(query, diskProvider, options);\n if (diskQueryResult && sameIndexIdentity(diskIdentity, diskQueryResult.provider)) {\n queryResult = diskQueryResult;\n } else {\n log.debug(\n `embedding fallback search skipped: preserved ${diskIdentity.provider}/${diskIdentity.model} index is unavailable for lookup`,\n );\n return [];\n }\n } else {\n log.debug(\n `embedding fallback search skipped: query provider ${queryResult.provider.type}/${queryResult.provider.model} does not match existing ${diskIdentity.provider}/${diskIdentity.model} index`,\n );\n return [];\n }\n }\n\n const index = await this.loadIndex(queryResult.provider);\n const ids = Object.keys(index.entries);\n if (ids.length === 0) return [];\n\n const includePrefix = normalizePathPrefix(options.pathPrefix);\n const excludePrefixes = (options.pathExcludePrefixes ?? [])\n .map((p) => normalizePathPrefix(p))\n .filter((p): p is string => typeof p === \"string\");\n\n const scored = ids\n .map((id) => {\n const entry = index.entries[id];\n return {\n id,\n path: entry.path,\n score: cosineSimilarity(queryResult.vector, entry.vector),\n };\n })\n .filter((r) => {\n if (!Number.isFinite(r.score)) return false;\n const normalized = normalizeEntryPath(r.path);\n if (includePrefix !== undefined && !normalized.startsWith(includePrefix)) {\n return false;\n }\n for (const excl of excludePrefixes) {\n if (normalized.startsWith(excl)) return false;\n }\n return true;\n })\n .sort((a, b) => b.score - a.score)\n .slice(0, Math.max(1, limit));\n\n return scored;\n }\n\n async indexFile(memoryId: string, content: string, filePath: string): Promise<void> {\n const provider = await this.resolveProvider();\n if (!provider) return;\n // Indexing is not on the write-critical path: a newly persisted memory\n // has already been written to disk by the time we reach this call. Use\n // the long \"index\" timeout so slow local embedding backends can still\n // add the entry to the index. Previously this used the short lookup\n // budget and silently dropped updates, leaving later dedup lookups\n // blind to the memory. Related: PR #399 P2.\n const result = await this.embedWithEffectiveProvider(content, provider, {\n mode: \"index\",\n });\n if (!result) return;\n\n await this.enqueueIndexMutation(async () => {\n const existing = await this.readIndexIdentityFromDisk();\n if (\n existing &&\n !sameIndexIdentity(existing, result.provider) &&\n !canReplaceIndexIdentity(existing, result.provider)\n ) {\n log.debug(\n `embedding fallback index update skipped: ${result.provider.type}/${result.provider.model} would replace existing ${existing.provider}/${existing.model} index`,\n );\n return;\n }\n const index = await this.loadIndex(result.provider);\n const relPath = toMemoryRelativePath(this.config.memoryDir, filePath);\n index.entries[memoryId] = {\n vector: result.vector,\n path: relPath,\n };\n await this.saveIndex(index);\n });\n }\n\n async removeFromIndex(memoryId: string): Promise<void> {\n const provider = await this.resolveProvider();\n if (!provider) return;\n\n await this.enqueueIndexMutation(async () => {\n const providers = [provider];\n const diskIdentity = await this.readIndexIdentityFromDisk();\n if (\n diskIdentity &&\n !providers.some((entry) => sameIndexIdentity(entry, diskIdentity))\n ) {\n providers.push(providerFromIndexIdentity(diskIdentity));\n }\n if (provider.type === \"host\") {\n const fallbackProvider = await this.resolveProvider({ includeHost: false });\n if (\n fallbackProvider &&\n !providers.some((entry) => sameIndexIdentity(entry, fallbackProvider))\n ) {\n providers.push(fallbackProvider);\n }\n }\n\n for (const indexProvider of providers) {\n const index = await this.loadIndex(indexProvider);\n if (!index.entries[memoryId]) continue;\n delete index.entries[memoryId];\n await this.saveIndex(index);\n }\n });\n }\n\n private enqueueIndexMutation<T>(mutation: () => Promise<T>): Promise<T> {\n const run = this.mutationQueue.catch(() => undefined).then(mutation);\n this.mutationQueue = run.then(\n () => undefined,\n () => undefined,\n );\n return run;\n }\n\n private async resolveProvider(\n options: { includeHost?: boolean } = {},\n ): Promise<ProviderConfig | null> {\n if (!resolveMemoryLifecycleCapabilities(this.config).embeddingFallback) return null;\n\n if (\n options.includeHost !== false &&\n this.config.hostEmbeddingProviderEnabled !== false\n ) {\n const hostProvider = getHostEmbeddingProvider(this.config.memoryDir);\n if (hostProvider) {\n return {\n type: \"host\",\n model: hostProvider.model || hostProvider.id,\n hostProvider,\n };\n }\n }\n\n const preferred = this.config.embeddingFallbackProvider;\n const providers = preferred === \"auto\" ? [\"openai\", \"local\"] : [preferred];\n\n for (const p of providers) {\n if (p === \"openai\") {\n const provider = this.createOpenAiProvider();\n if (provider) return provider;\n }\n\n if (p === \"local\") {\n const provider = this.createLocalProvider();\n if (provider) return provider;\n }\n }\n\n return null;\n }\n\n private async resolveFallbackProviderForIndexIdentity(\n identity: EmbeddingIndexIdentity,\n ): Promise<ProviderConfig | null> {\n if (identity.provider === \"openai\") {\n const provider = this.createOpenAiProvider();\n return provider && sameIndexIdentity(provider, identity) ? provider : null;\n }\n if (identity.provider === \"local\") {\n const provider = this.createLocalProvider();\n return provider && sameIndexIdentity(provider, identity) ? provider : null;\n }\n return null;\n }\n\n private createOpenAiProvider(): ProviderConfig | null {\n if (!this.config.openaiApiKey) return null;\n const baseUrl = this.config.openaiBaseUrl ?? \"https://api.openai.com/v1\";\n return {\n type: \"openai\",\n model: DEFAULT_OPENAI_MODEL,\n endpoint: `${baseUrl.replace(/\\/$/, \"\")}/embeddings`,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.openaiApiKey}`,\n },\n };\n }\n\n private createLocalProvider(): ProviderConfig | null {\n if (!resolveLocalLlmCapabilities(this.config).localLlm || !this.config.localLlmUrl) return null;\n const base = this.config.localLlmUrl.replace(/\\/$/, \"\");\n const endpoint = /\\/v1$/i.test(base) ? `${base}/embeddings` : `${base}/v1/embeddings`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(this.config.localLlmHeaders ?? {}),\n };\n if (this.config.localLlmApiKey && this.config.localLlmAuthHeader !== false) {\n headers.Authorization = `Bearer ${this.config.localLlmApiKey}`;\n }\n return {\n type: \"local\",\n model:\n this.config.embeddingFallbackModel ||\n this.config.localLlmModel ||\n DEFAULT_OPENAI_MODEL,\n endpoint,\n headers,\n };\n }\n\n private async embedForSearch(\n query: string,\n provider: ProviderConfig,\n options: { throwOnTimeout?: boolean } = {},\n ): Promise<EmbeddingResult | null> {\n try {\n return await this.embedWithEffectiveProvider(query, provider, {\n mode: \"lookup\",\n });\n } catch (err) {\n if (isLookupBackendUnavailableError(err)) {\n if (options.throwOnTimeout) {\n throw err;\n }\n // Fail-open: recall-path callers get an empty result rather than an\n // unhandled rejection that would abort recall entirely.\n log.debug(\"embedding fallback search: backend unavailable on lookup, returning [] (throwOnTimeout=false)\");\n return null;\n }\n throw err;\n }\n }\n\n private async embed(\n input: string,\n provider: ProviderConfig,\n options: { mode?: EmbedMode } = {},\n ): Promise<number[] | null> {\n const result = await this.embedWithEffectiveProvider(input, provider, options);\n return result?.vector ?? null;\n }\n\n private async embedWithEffectiveProvider(\n input: string,\n provider: ProviderConfig,\n options: { mode?: EmbedMode } = {},\n ): Promise<EmbeddingResult | null> {\n // Bound the fetch so a hung embedding endpoint cannot stall callers.\n // The lookup path uses a short budget (see DEFAULT_EMBEDDING_LOOKUP_TIMEOUT_MS\n // docblock) so semantic dedup fails open fast. The index path uses a\n // much longer budget because slow local backends (CPU embedding models)\n // otherwise drop index updates and blind later dedup lookups. See\n // DEFAULT_EMBEDDING_INDEX_TIMEOUT_MS docblock and PR #399 P2 review.\n const mode: EmbedMode = options.mode ?? \"lookup\";\n const timeoutMs =\n mode === \"index\"\n ? resolveEmbeddingIndexTimeoutMs()\n : resolveEmbeddingLookupTimeoutMs();\n if (provider.type === \"host\") {\n const vector = await this.embedWithHostProvider(input, provider, mode, timeoutMs);\n if (vector) return { provider, vector };\n const fallbackProvider = await this.resolveProvider({ includeHost: false });\n if (!fallbackProvider) {\n if (mode === \"lookup\") {\n throw new EmbeddingProviderUnavailableError(\n `host embedding provider unavailable (${provider.hostProvider?.id ?? provider.model})`,\n );\n }\n return null;\n }\n return this.embedWithEffectiveProvider(input, fallbackProvider, options);\n }\n if (!provider.endpoint || !provider.headers) return null;\n try {\n const res = await fetch(provider.endpoint, {\n method: \"POST\",\n headers: provider.headers,\n body: JSON.stringify({\n model: provider.model,\n input: input.slice(0, 8000),\n encoding_format: \"float\",\n }),\n signal: AbortSignal.timeout(timeoutMs),\n });\n if (!res.ok) {\n log.debug(`embedding fallback request failed: ${provider.type} ${res.status}`);\n // Round 11 fix (Finding Ur_J): on the LOOKUP path, a non-2xx response\n // means the embedding backend is effectively unavailable. Throw the\n // tagged error so search() (when called with throwOnTimeout) propagates\n // to decideSemanticDedup's backend_unavailable branch, activating the\n // per-batch short-circuit. Without this, repeated 429/5xx responses\n // would silently return [] for every fact in the batch.\n //\n // On the INDEX path a non-2xx is non-fatal (the memory is already\n // persisted; index update can be skipped) — return null there.\n if (mode === \"lookup\") {\n throw new EmbeddingTimeoutError(\n `embedding backend returned ${res.status} (${provider.type})`,\n );\n }\n return null;\n }\n const payload = (await res.json()) as any;\n const vector = payload?.data?.[0]?.embedding;\n if (!Array.isArray(vector)) return null;\n const normalized = vector\n .map((n: unknown) => Number(n))\n .filter((n: number) => Number.isFinite(n));\n return normalized.length > 0 ? { provider, vector: normalized } : null;\n } catch (err) {\n // Round 11 (Finding Ur_J): the !res.ok branch above throws\n // EmbeddingTimeoutError directly. Re-throw it here so the catch does\n // not swallow our own intentional signal back into a null return.\n if (isLookupBackendUnavailableError(err)) {\n throw err;\n }\n // AbortSignal.timeout throws a DOMException with name \"TimeoutError\";\n // surface at warn level so operators can distinguish slow backends from\n // generic errors.\n const isTimeout =\n err instanceof Error &&\n (err.name === \"TimeoutError\" || err.name === \"AbortError\");\n if (isTimeout) {\n log.warn(\n `embedding fallback fetch timed out after ${timeoutMs}ms (${provider.type}, mode=${mode})`,\n );\n // Round 9 fix (Finding UZqB): on the LOOKUP path a timeout means the\n // embedding backend is effectively unavailable — re-throw so that\n // search() propagates the error to semanticDedupLookup, which lets it\n // reach decideSemanticDedup's catch block and return\n // reason=\"backend_unavailable\". Without this, search() would silently\n // return [] and the per-batch batchBackendUnavailable flag would never\n // flip, causing subsequent facts in the same batch to each pay a full\n // timeout roundtrip (N × timeout instead of 1 × timeout).\n //\n // On the INDEX path a timeout is not fatal (the memory is already\n // persisted; index update can be skipped) — return null there so\n // indexFile() stays non-blocking.\n if (mode === \"lookup\") {\n throw new EmbeddingTimeoutError(\n `embedding backend timed out after ${timeoutMs}ms (${provider.type})`,\n );\n }\n } else {\n // Round 12 fix (PR #399 thread PRRT_kwDORJXyws56U6Gi): non-timeout\n // transport failures (ECONNREFUSED, DNS errors, TLS failures) are just\n // as fatal as timeouts on the LOOKUP path — the embedding backend is\n // effectively unreachable. Throw EmbeddingTimeoutError so that\n // search() (when called with throwOnTimeout:true) propagates the error\n // to decideSemanticDedup's backend_unavailable branch, activating the\n // per-batch short-circuit. Without this, each fact in the batch would\n // pay a full ECONNREFUSED roundtrip and return null → [] → no_candidates,\n // preventing batchBackendUnavailable from ever being set.\n //\n // On the INDEX path a transport failure is non-fatal — the memory is\n // already persisted; index update can be safely skipped.\n if (mode === \"lookup\") {\n log.warn(\n `embedding fallback transport error on lookup path (${provider.type}): ${err}`,\n );\n throw new EmbeddingTimeoutError(\n `embedding backend transport failure (${provider.type}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n log.debug(`embedding fallback error: ${err}`);\n }\n return null;\n }\n }\n\n private async embedWithHostProvider(\n input: string,\n provider: ProviderConfig,\n mode: EmbedMode,\n timeoutMs: number,\n ): Promise<number[] | null> {\n const hostProvider = provider.hostProvider;\n if (!hostProvider) return null;\n try {\n const vector = await hostProvider.embed(input.slice(0, 8000), {\n signal: AbortSignal.timeout(timeoutMs),\n inputType: mode === \"lookup\" ? \"query\" : \"document\",\n });\n return normalizeHostEmbeddingVector(vector);\n } catch (err) {\n log.debug(`host embedding provider error: ${hostProvider.id}: ${err}`);\n return null;\n }\n }\n\n private async loadIndex(provider: ProviderConfig): Promise<EmbeddingIndexFile> {\n if (this.loaded && this.loaded.provider === provider.type && this.loaded.model === provider.model) {\n return this.loaded;\n }\n\n try {\n const raw = await readFile(this.indexPath, \"utf-8\");\n const parsed = JSON.parse(raw) as EmbeddingIndexFile;\n if (\n parsed &&\n parsed.version === 1 &&\n parsed.provider === provider.type &&\n parsed.model === provider.model &&\n parsed.entries &&\n typeof parsed.entries === \"object\"\n ) {\n this.loaded = {\n version: 1,\n provider: provider.type,\n model: provider.model,\n entries: parsed.entries,\n };\n return this.loaded;\n }\n } catch {\n // ignore and create a new index\n }\n\n this.loaded = {\n version: 1,\n provider: provider.type,\n model: provider.model,\n entries: {},\n };\n return this.loaded;\n }\n\n private async readIndexIdentityFromDisk(): Promise<EmbeddingIndexIdentity | null> {\n try {\n const raw = await readFile(this.indexPath, \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<EmbeddingIndexFile> | null;\n if (\n parsed &&\n parsed.version === 1 &&\n (parsed.provider === \"openai\" ||\n parsed.provider === \"local\" ||\n parsed.provider === \"host\") &&\n typeof parsed.model === \"string\" &&\n parsed.model.length > 0\n ) {\n return {\n provider: parsed.provider,\n model: parsed.model,\n };\n }\n } catch {\n // Missing or invalid indexes are treated as absent; loadIndex() owns\n // creating a fresh file when it is safe to write.\n }\n return null;\n }\n\n private async saveIndex(index: EmbeddingIndexFile): Promise<void> {\n const dir = path.dirname(this.indexPath);\n await mkdir(dir, { recursive: true });\n const tempPath = path.join(\n dir,\n `.embeddings.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`,\n );\n try {\n await writeFile(tempPath, JSON.stringify(index), \"utf-8\");\n await rename(tempPath, this.indexPath);\n } catch (err) {\n await rm(tempPath, { force: true }).catch(() => undefined);\n throw err;\n }\n this.loaded = index;\n }\n}\n\nfunction toMemoryRelativePath(memoryDir: string, filePath: string): string {\n if (!path.isAbsolute(filePath)) return filePath;\n const rel = path.relative(memoryDir, filePath);\n return rel.startsWith(\"..\") ? filePath : rel;\n}\n\n/**\n * Normalize an index entry path to forward-slashes for stable prefix\n * comparison. Entries are stored as `path.relative(memoryDir, …)` output,\n * which on Windows uses back-slashes. Normalize both sides so prefix\n * matching is OS-independent.\n *\n * Also strip a leading `./` so this helper's output is symmetric with\n * `normalizePathPrefix` below. `toMemoryRelativePath` is a pass-through for\n * non-absolute filePath inputs, so an index entry could legitimately carry a\n * stored path like `\"./namespaces/alpha/facts/f.md\"`. Without this strip, a\n * caller-supplied prefix `\"./namespaces/alpha\"` (which `normalizePathPrefix`\n * rewrites to `\"namespaces/alpha/\"`) would silently miss that entry and\n * namespace-scoped dedup would either let a near-duplicate through or fail\n * to exclude a cross-namespace hit.\n */\nfunction normalizeEntryPath(p: string): string {\n let out = p.replace(/\\\\/g, \"/\");\n if (out.startsWith(\"./\")) out = out.slice(2);\n return out;\n}\n\n/**\n * Normalize a caller-supplied path prefix:\n * - Return `undefined` for nullish/empty input (no filter).\n * - Replace back-slashes with forward-slashes.\n * - Strip a leading `./`.\n * - Ensure a trailing `/` so `\"namespaces/a\"` doesn't accidentally match\n * `\"namespaces/another/…\"`.\n */\nfunction normalizePathPrefix(prefix: string | undefined): string | undefined {\n if (prefix === undefined || prefix === null) return undefined;\n let p = String(prefix).replace(/\\\\/g, \"/\");\n if (p.startsWith(\"./\")) p = p.slice(2);\n if (p.length === 0) return undefined;\n if (!p.endsWith(\"/\")) p = `${p}/`;\n return p;\n}\n\nfunction sameIndexIdentity(\n left: EmbeddingIndexComparable,\n right: EmbeddingIndexComparable,\n): boolean {\n return indexIdentityProvider(left) === indexIdentityProvider(right) && left.model === right.model;\n}\n\nfunction indexIdentityProvider(identity: EmbeddingIndexComparable): EmbeddingProviderType {\n return \"provider\" in identity ? identity.provider : identity.type;\n}\n\nfunction canReplaceIndexIdentity(\n existing: EmbeddingIndexIdentity,\n replacement: Pick<ProviderConfig, \"type\" | \"model\">,\n): boolean {\n return existing.provider === \"host\" && !sameIndexIdentity(existing, replacement);\n}\n\nfunction providerFromIndexIdentity(identity: EmbeddingIndexIdentity): ProviderConfig {\n return {\n type: identity.provider,\n model: identity.model,\n };\n}\n\nfunction cosineSimilarity(a: number[], b: number[]): number {\n const n = Math.min(a.length, b.length);\n if (n === 0) return 0;\n let dot = 0;\n let normA = 0;\n let normB = 0;\n for (let i = 0; i < n; i++) {\n const av = a[i] ?? 0;\n const bv = b[i] ?? 0;\n dot += av * bv;\n normA += av * av;\n normB += bv * bv;\n }\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n if (denom === 0) return 0;\n return dot / denom;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA,OAAO,UAAU;AACjB,SAAS,OAAO,UAAU,QAAQ,IAAI,iBAAiB;AA8CvD,IAAM,uBAAuB;AA+BtB,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAC7B,OAAO;AAAA,EACzB,YAAY,SAAiB;AAC3B,UAAM,OAAO;AAAA,EACf;AACF;AAEO,IAAM,oCAAN,cAAgD,MAAM;AAAA,EACzC,OAAO;AAAA,EACzB,YAAY,SAAiB;AAC3B,UAAM,OAAO;AAAA,EACf;AACF;AAEA,SAAS,gCAAgC,KAAuB;AAC9D,SACE,eAAe,yBACf,eAAe;AAEnB;AAmBA,IAAM,sCAAsC;AAe5C,IAAM,qCAAqC;AAE3C,SAAS,kCAA0C;AACjD,QAAM,MAAM,WAAW,mCAAmC;AAC1D,MAAI,KAAK;AACP,UAAM,SAAS,OAAO,GAAG;AACzB,QAAI,OAAO,SAAS,MAAM,KAAK,SAAS,GAAG;AACzC,aAAO,KAAK,MAAM,MAAM;AAAA,IAC1B;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,iCAAyC;AAChD,QAAM,MAAM,WAAW,mCAAmC;AAC1D,MAAI,KAAK;AACP,UAAM,SAAS,OAAO,GAAG;AACzB,QAAI,OAAO,SAAS,MAAM,KAAK,SAAS,GAAG;AACzC,aAAO,KAAK,MAAM,MAAM;AAAA,IAC1B;AAAA,EACF;AACA,SAAO;AACT;AAYO,IAAM,oBAAN,MAAwB;AAAA,EAK7B,YAA6B,QAAsB;AAAtB;AAC3B,SAAK,YAAY,KAAK,KAAK,OAAO,WAAW,SAAS,iBAAiB;AAAA,EACzE;AAAA,EAF6B;AAAA,EAJZ;AAAA,EACT,SAAoC;AAAA,EACpC,gBAA+B,QAAQ,QAAQ;AAAA,EAMvD,MAAM,cAAgC;AACpC,WAAQ,MAAM,KAAK,gBAAgB,MAAO;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,WAAW,OAAsC;AACrD,UAAM,WAAW,MAAM,KAAK,gBAAgB;AAC5C,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AAEA,UAAM,YAAY,KAAK;AAAA,MACrB;AAAA,MACA,KAAK,OAAO,wBAAwB,sBAAsB;AAAA,IAC5D;AAEA,UAAM,UAAsB,CAAC;AAC7B,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,WAAW;AAChD,YAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,SAAS;AAC1C,YAAM,eAAe,MAAM,QAAQ;AAAA,QACjC,MAAM,IAAI,CAAC,SAAS,KAAK,MAAM,MAAM,UAAU,EAAE,MAAM,SAAS,CAAC,CAAC;AAAA,MACpE;AACA,iBAAW,OAAO,cAAc;AAC9B,YAAI,CAAC,KAAK;AACR,gBAAM,IAAI,MAAM,wCAAwC;AAAA,QAC1D;AACA,gBAAQ,KAAK,GAAG;AAAA,MAClB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,MAAM,OACJ,OACA,OACA,UAkBI,CAAC,GACwD;AAC7D,UAAM,WAAW,MAAM,KAAK,gBAAgB;AAC5C,QAAI,CAAC,SAAU,QAAO,CAAC;AAEvB,QAAI,cAAc,MAAM,KAAK,eAAe,OAAO,UAAU,OAAO;AACpE,QAAI,CAAC,YAAa,QAAO,CAAC;AAE1B,UAAM,eAAe,MAAM,KAAK,0BAA0B;AAC1D,QAAI,gBAAgB,CAAC,kBAAkB,cAAc,YAAY,QAAQ,GAAG;AAC1E,YAAM,eAAe,MAAM,KAAK,wCAAwC,YAAY;AACpF,UAAI,cAAc;AAChB,cAAM,kBAAkB,MAAM,KAAK,eAAe,OAAO,cAAc,OAAO;AAC9E,YAAI,mBAAmB,kBAAkB,cAAc,gBAAgB,QAAQ,GAAG;AAChF,wBAAc;AAAA,QAChB,OAAO;AACL,cAAI;AAAA,YACF,gDAAgD,aAAa,QAAQ,IAAI,aAAa,KAAK;AAAA,UAC7F;AACA,iBAAO,CAAC;AAAA,QACV;AAAA,MACF,OAAO;AACL,YAAI;AAAA,UACF,qDAAqD,YAAY,SAAS,IAAI,IAAI,YAAY,SAAS,KAAK,4BAA4B,aAAa,QAAQ,IAAI,aAAa,KAAK;AAAA,QACrL;AACA,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AAEA,UAAM,QAAQ,MAAM,KAAK,UAAU,YAAY,QAAQ;AACvD,UAAM,MAAM,OAAO,KAAK,MAAM,OAAO;AACrC,QAAI,IAAI,WAAW,EAAG,QAAO,CAAC;AAE9B,UAAM,gBAAgB,oBAAoB,QAAQ,UAAU;AAC5D,UAAM,mBAAmB,QAAQ,uBAAuB,CAAC,GACtD,IAAI,CAAC,MAAM,oBAAoB,CAAC,CAAC,EACjC,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ;AAEnD,UAAM,SAAS,IACZ,IAAI,CAAC,OAAO;AACX,YAAM,QAAQ,MAAM,QAAQ,EAAE;AAC9B,aAAO;AAAA,QACL;AAAA,QACA,MAAM,MAAM;AAAA,QACZ,OAAO,iBAAiB,YAAY,QAAQ,MAAM,MAAM;AAAA,MAC1D;AAAA,IACF,CAAC,EACA,OAAO,CAAC,MAAM;AACb,UAAI,CAAC,OAAO,SAAS,EAAE,KAAK,EAAG,QAAO;AACtC,YAAM,aAAa,mBAAmB,EAAE,IAAI;AAC5C,UAAI,kBAAkB,UAAa,CAAC,WAAW,WAAW,aAAa,GAAG;AACxE,eAAO;AAAA,MACT;AACA,iBAAW,QAAQ,iBAAiB;AAClC,YAAI,WAAW,WAAW,IAAI,EAAG,QAAO;AAAA,MAC1C;AACA,aAAO;AAAA,IACT,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,MAAM,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC;AAE9B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,UAAkB,SAAiB,UAAiC;AAClF,UAAM,WAAW,MAAM,KAAK,gBAAgB;AAC5C,QAAI,CAAC,SAAU;AAOf,UAAM,SAAS,MAAM,KAAK,2BAA2B,SAAS,UAAU;AAAA,MACtE,MAAM;AAAA,IACR,CAAC;AACD,QAAI,CAAC,OAAQ;AAEb,UAAM,KAAK,qBAAqB,YAAY;AAC1C,YAAM,WAAW,MAAM,KAAK,0BAA0B;AACtD,UACE,YACA,CAAC,kBAAkB,UAAU,OAAO,QAAQ,KAC5C,CAAC,wBAAwB,UAAU,OAAO,QAAQ,GAClD;AACA,YAAI;AAAA,UACF,4CAA4C,OAAO,SAAS,IAAI,IAAI,OAAO,SAAS,KAAK,2BAA2B,SAAS,QAAQ,IAAI,SAAS,KAAK;AAAA,QACzJ;AACA;AAAA,MACF;AACA,YAAM,QAAQ,MAAM,KAAK,UAAU,OAAO,QAAQ;AAClD,YAAM,UAAU,qBAAqB,KAAK,OAAO,WAAW,QAAQ;AACpE,YAAM,QAAQ,QAAQ,IAAI;AAAA,QACxB,QAAQ,OAAO;AAAA,QACf,MAAM;AAAA,MACR;AACA,YAAM,KAAK,UAAU,KAAK;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,gBAAgB,UAAiC;AACrD,UAAM,WAAW,MAAM,KAAK,gBAAgB;AAC5C,QAAI,CAAC,SAAU;AAEf,UAAM,KAAK,qBAAqB,YAAY;AAC1C,YAAM,YAAY,CAAC,QAAQ;AAC3B,YAAM,eAAe,MAAM,KAAK,0BAA0B;AAC1D,UACE,gBACA,CAAC,UAAU,KAAK,CAAC,UAAU,kBAAkB,OAAO,YAAY,CAAC,GACjE;AACA,kBAAU,KAAK,0BAA0B,YAAY,CAAC;AAAA,MACxD;AACA,UAAI,SAAS,SAAS,QAAQ;AAC5B,cAAM,mBAAmB,MAAM,KAAK,gBAAgB,EAAE,aAAa,MAAM,CAAC;AAC1E,YACE,oBACA,CAAC,UAAU,KAAK,CAAC,UAAU,kBAAkB,OAAO,gBAAgB,CAAC,GACrE;AACA,oBAAU,KAAK,gBAAgB;AAAA,QACjC;AAAA,MACF;AAEA,iBAAW,iBAAiB,WAAW;AACrC,cAAM,QAAQ,MAAM,KAAK,UAAU,aAAa;AAChD,YAAI,CAAC,MAAM,QAAQ,QAAQ,EAAG;AAC9B,eAAO,MAAM,QAAQ,QAAQ;AAC7B,cAAM,KAAK,UAAU,KAAK;AAAA,MAC5B;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,qBAAwB,UAAwC;AACtE,UAAM,MAAM,KAAK,cAAc,MAAM,MAAM,MAAS,EAAE,KAAK,QAAQ;AACnE,SAAK,gBAAgB,IAAI;AAAA,MACvB,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,gBACZ,UAAqC,CAAC,GACN;AAChC,QAAI,CAAC,mCAAmC,KAAK,MAAM,EAAE,kBAAmB,QAAO;AAE/E,QACE,QAAQ,gBAAgB,SACxB,KAAK,OAAO,iCAAiC,OAC7C;AACA,YAAM,eAAe,yBAAyB,KAAK,OAAO,SAAS;AACnE,UAAI,cAAc;AAChB,eAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO,aAAa,SAAS,aAAa;AAAA,UAC1C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,YAAY,KAAK,OAAO;AAC9B,UAAM,YAAY,cAAc,SAAS,CAAC,UAAU,OAAO,IAAI,CAAC,SAAS;AAEzE,eAAW,KAAK,WAAW;AACzB,UAAI,MAAM,UAAU;AAClB,cAAM,WAAW,KAAK,qBAAqB;AAC3C,YAAI,SAAU,QAAO;AAAA,MACvB;AAEA,UAAI,MAAM,SAAS;AACjB,cAAM,WAAW,KAAK,oBAAoB;AAC1C,YAAI,SAAU,QAAO;AAAA,MACvB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,wCACZ,UACgC;AAChC,QAAI,SAAS,aAAa,UAAU;AAClC,YAAM,WAAW,KAAK,qBAAqB;AAC3C,aAAO,YAAY,kBAAkB,UAAU,QAAQ,IAAI,WAAW;AAAA,IACxE;AACA,QAAI,SAAS,aAAa,SAAS;AACjC,YAAM,WAAW,KAAK,oBAAoB;AAC1C,aAAO,YAAY,kBAAkB,UAAU,QAAQ,IAAI,WAAW;AAAA,IACxE;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,uBAA8C;AACpD,QAAI,CAAC,KAAK,OAAO,aAAc,QAAO;AACtC,UAAM,UAAU,KAAK,OAAO,iBAAiB;AAC7C,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,UAAU,GAAG,QAAQ,QAAQ,OAAO,EAAE,CAAC;AAAA,MACvC,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe,UAAU,KAAK,OAAO,YAAY;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,sBAA6C;AACnD,QAAI,CAAC,4BAA4B,KAAK,MAAM,EAAE,YAAY,CAAC,KAAK,OAAO,YAAa,QAAO;AAC3F,UAAM,OAAO,KAAK,OAAO,YAAY,QAAQ,OAAO,EAAE;AACtD,UAAM,WAAW,SAAS,KAAK,IAAI,IAAI,GAAG,IAAI,gBAAgB,GAAG,IAAI;AACrE,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,GAAI,KAAK,OAAO,mBAAmB,CAAC;AAAA,IACtC;AACA,QAAI,KAAK,OAAO,kBAAkB,KAAK,OAAO,uBAAuB,OAAO;AAC1E,cAAQ,gBAAgB,UAAU,KAAK,OAAO,cAAc;AAAA,IAC9D;AACA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OACE,KAAK,OAAO,0BACZ,KAAK,OAAO,iBACZ;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,eACZ,OACA,UACA,UAAwC,CAAC,GACR;AACjC,QAAI;AACF,aAAO,MAAM,KAAK,2BAA2B,OAAO,UAAU;AAAA,QAC5D,MAAM;AAAA,MACR,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,UAAI,gCAAgC,GAAG,GAAG;AACxC,YAAI,QAAQ,gBAAgB;AAC1B,gBAAM;AAAA,QACR;AAGA,YAAI,MAAM,+FAA+F;AACzG,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAc,MACZ,OACA,UACA,UAAgC,CAAC,GACP;AAC1B,UAAM,SAAS,MAAM,KAAK,2BAA2B,OAAO,UAAU,OAAO;AAC7E,WAAO,QAAQ,UAAU;AAAA,EAC3B;AAAA,EAEA,MAAc,2BACZ,OACA,UACA,UAAgC,CAAC,GACA;AAOjC,UAAM,OAAkB,QAAQ,QAAQ;AACxC,UAAM,YACJ,SAAS,UACL,+BAA+B,IAC/B,gCAAgC;AACtC,QAAI,SAAS,SAAS,QAAQ;AAC5B,YAAM,SAAS,MAAM,KAAK,sBAAsB,OAAO,UAAU,MAAM,SAAS;AAChF,UAAI,OAAQ,QAAO,EAAE,UAAU,OAAO;AACtC,YAAM,mBAAmB,MAAM,KAAK,gBAAgB,EAAE,aAAa,MAAM,CAAC;AAC1E,UAAI,CAAC,kBAAkB;AACrB,YAAI,SAAS,UAAU;AACrB,gBAAM,IAAI;AAAA,YACR,wCAAwC,SAAS,cAAc,MAAM,SAAS,KAAK;AAAA,UACrF;AAAA,QACF;AACA,eAAO;AAAA,MACT;AACA,aAAO,KAAK,2BAA2B,OAAO,kBAAkB,OAAO;AAAA,IACzE;AACA,QAAI,CAAC,SAAS,YAAY,CAAC,SAAS,QAAS,QAAO;AACpD,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,SAAS,UAAU;AAAA,QACzC,QAAQ;AAAA,QACR,SAAS,SAAS;AAAA,QAClB,MAAM,KAAK,UAAU;AAAA,UACnB,OAAO,SAAS;AAAA,UAChB,OAAO,MAAM,MAAM,GAAG,GAAI;AAAA,UAC1B,iBAAiB;AAAA,QACnB,CAAC;AAAA,QACD,QAAQ,YAAY,QAAQ,SAAS;AAAA,MACvC,CAAC;AACD,UAAI,CAAC,IAAI,IAAI;AACX,YAAI,MAAM,sCAAsC,SAAS,IAAI,IAAI,IAAI,MAAM,EAAE;AAU7E,YAAI,SAAS,UAAU;AACrB,gBAAM,IAAI;AAAA,YACR,8BAA8B,IAAI,MAAM,KAAK,SAAS,IAAI;AAAA,UAC5D;AAAA,QACF;AACA,eAAO;AAAA,MACT;AACA,YAAM,UAAW,MAAM,IAAI,KAAK;AAChC,YAAM,SAAS,SAAS,OAAO,CAAC,GAAG;AACnC,UAAI,CAAC,MAAM,QAAQ,MAAM,EAAG,QAAO;AACnC,YAAM,aAAa,OAChB,IAAI,CAAC,MAAe,OAAO,CAAC,CAAC,EAC7B,OAAO,CAAC,MAAc,OAAO,SAAS,CAAC,CAAC;AAC3C,aAAO,WAAW,SAAS,IAAI,EAAE,UAAU,QAAQ,WAAW,IAAI;AAAA,IACpE,SAAS,KAAK;AAIZ,UAAI,gCAAgC,GAAG,GAAG;AACxC,cAAM;AAAA,MACR;AAIA,YAAM,YACJ,eAAe,UACd,IAAI,SAAS,kBAAkB,IAAI,SAAS;AAC/C,UAAI,WAAW;AACb,YAAI;AAAA,UACF,4CAA4C,SAAS,OAAO,SAAS,IAAI,UAAU,IAAI;AAAA,QACzF;AAaA,YAAI,SAAS,UAAU;AACrB,gBAAM,IAAI;AAAA,YACR,qCAAqC,SAAS,OAAO,SAAS,IAAI;AAAA,UACpE;AAAA,QACF;AAAA,MACF,OAAO;AAaL,YAAI,SAAS,UAAU;AACrB,cAAI;AAAA,YACF,sDAAsD,SAAS,IAAI,MAAM,GAAG;AAAA,UAC9E;AACA,gBAAM,IAAI;AAAA,YACR,wCAAwC,SAAS,IAAI,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,UAC7G;AAAA,QACF;AACA,YAAI,MAAM,6BAA6B,GAAG,EAAE;AAAA,MAC9C;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,sBACZ,OACA,UACA,MACA,WAC0B;AAC1B,UAAM,eAAe,SAAS;AAC9B,QAAI,CAAC,aAAc,QAAO;AAC1B,QAAI;AACF,YAAM,SAAS,MAAM,aAAa,MAAM,MAAM,MAAM,GAAG,GAAI,GAAG;AAAA,QAC5D,QAAQ,YAAY,QAAQ,SAAS;AAAA,QACrC,WAAW,SAAS,WAAW,UAAU;AAAA,MAC3C,CAAC;AACD,aAAO,6BAA6B,MAAM;AAAA,IAC5C,SAAS,KAAK;AACZ,UAAI,MAAM,kCAAkC,aAAa,EAAE,KAAK,GAAG,EAAE;AACrE,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,UAAU,UAAuD;AAC7E,QAAI,KAAK,UAAU,KAAK,OAAO,aAAa,SAAS,QAAQ,KAAK,OAAO,UAAU,SAAS,OAAO;AACjG,aAAO,KAAK;AAAA,IACd;AAEA,QAAI;AACF,YAAM,MAAM,MAAM,SAAS,KAAK,WAAW,OAAO;AAClD,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,UACE,UACA,OAAO,YAAY,KACnB,OAAO,aAAa,SAAS,QAC7B,OAAO,UAAU,SAAS,SAC1B,OAAO,WACP,OAAO,OAAO,YAAY,UAC1B;AACA,aAAK,SAAS;AAAA,UACZ,SAAS;AAAA,UACT,UAAU,SAAS;AAAA,UACnB,OAAO,SAAS;AAAA,UAChB,SAAS,OAAO;AAAA,QAClB;AACA,eAAO,KAAK;AAAA,MACd;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,SAAK,SAAS;AAAA,MACZ,SAAS;AAAA,MACT,UAAU,SAAS;AAAA,MACnB,OAAO,SAAS;AAAA,MAChB,SAAS,CAAC;AAAA,IACZ;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,4BAAoE;AAChF,QAAI;AACF,YAAM,MAAM,MAAM,SAAS,KAAK,WAAW,OAAO;AAClD,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,UACE,UACA,OAAO,YAAY,MAClB,OAAO,aAAa,YACnB,OAAO,aAAa,WACpB,OAAO,aAAa,WACtB,OAAO,OAAO,UAAU,YACxB,OAAO,MAAM,SAAS,GACtB;AACA,eAAO;AAAA,UACL,UAAU,OAAO;AAAA,UACjB,OAAO,OAAO;AAAA,QAChB;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAGR;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,UAAU,OAA0C;AAChE,UAAM,MAAM,KAAK,QAAQ,KAAK,SAAS;AACvC,UAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,UAAM,WAAW,KAAK;AAAA,MACpB;AAAA,MACA,eAAe,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAAA,IACjF;AACA,QAAI;AACF,YAAM,UAAU,UAAU,KAAK,UAAU,KAAK,GAAG,OAAO;AACxD,YAAM,OAAO,UAAU,KAAK,SAAS;AAAA,IACvC,SAAS,KAAK;AACZ,YAAM,GAAG,UAAU,EAAE,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM,MAAS;AACzD,YAAM;AAAA,IACR;AACA,SAAK,SAAS;AAAA,EAChB;AACF;AAEA,SAAS,qBAAqB,WAAmB,UAA0B;AACzE,MAAI,CAAC,KAAK,WAAW,QAAQ,EAAG,QAAO;AACvC,QAAM,MAAM,KAAK,SAAS,WAAW,QAAQ;AAC7C,SAAO,IAAI,WAAW,IAAI,IAAI,WAAW;AAC3C;AAiBA,SAAS,mBAAmB,GAAmB;AAC7C,MAAI,MAAM,EAAE,QAAQ,OAAO,GAAG;AAC9B,MAAI,IAAI,WAAW,IAAI,EAAG,OAAM,IAAI,MAAM,CAAC;AAC3C,SAAO;AACT;AAUA,SAAS,oBAAoB,QAAgD;AAC3E,MAAI,WAAW,UAAa,WAAW,KAAM,QAAO;AACpD,MAAI,IAAI,OAAO,MAAM,EAAE,QAAQ,OAAO,GAAG;AACzC,MAAI,EAAE,WAAW,IAAI,EAAG,KAAI,EAAE,MAAM,CAAC;AACrC,MAAI,EAAE,WAAW,EAAG,QAAO;AAC3B,MAAI,CAAC,EAAE,SAAS,GAAG,EAAG,KAAI,GAAG,CAAC;AAC9B,SAAO;AACT;AAEA,SAAS,kBACP,MACA,OACS;AACT,SAAO,sBAAsB,IAAI,MAAM,sBAAsB,KAAK,KAAK,KAAK,UAAU,MAAM;AAC9F;AAEA,SAAS,sBAAsB,UAA2D;AACxF,SAAO,cAAc,WAAW,SAAS,WAAW,SAAS;AAC/D;AAEA,SAAS,wBACP,UACA,aACS;AACT,SAAO,SAAS,aAAa,UAAU,CAAC,kBAAkB,UAAU,WAAW;AACjF;AAEA,SAAS,0BAA0B,UAAkD;AACnF,SAAO;AAAA,IACL,MAAM,SAAS;AAAA,IACf,OAAO,SAAS;AAAA,EAClB;AACF;AAEA,SAAS,iBAAiB,GAAa,GAAqB;AAC1D,QAAM,IAAI,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;AACrC,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,MAAM;AACV,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,KAAK,EAAE,CAAC,KAAK;AACnB,UAAM,KAAK,EAAE,CAAC,KAAK;AACnB,WAAO,KAAK;AACZ,aAAS,KAAK;AACd,aAAS,KAAK;AAAA,EAChB;AACA,QAAM,QAAQ,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK;AAChD,MAAI,UAAU,EAAG,QAAO;AACxB,SAAO,MAAM;AACf;","names":[]}
|