Projects the profile snapshot into one host channel, mirroring the `install_managed_skills` `(profile_root, target, output)` contract: native-overlay targets get a rule/skill file inside the plugin root, prompt-index targets get a marked block in the prompt file. When the snapshot is empty a short placeholder is exported instead (so refreshes after new facts can find and update the channel).
(
profile_root: &Path,
target: SkillInstallTarget,
output: &Path,
)
| 685 | /// snapshot is empty a short placeholder is exported instead (so refreshes |
| 686 | /// after new facts can find and update the channel). |
| 687 | pub fn export_memory_digest( |
| 688 | profile_root: &Path, |
| 689 | target: SkillInstallTarget, |
| 690 | output: &Path, |
| 691 | ) -> Result<MemoryDigestExportSummary> { |
| 692 | if target == SkillInstallTarget::Hermes { |
| 693 | return Err(hermes_host_owned_error()); |
| 694 | } |
| 695 | if native_digest_superseded_by_host_injection(target) { |
| 696 | return Err(native_digest_superseded_error(target)); |
| 697 | } |
| 698 | let snapshot = load_memory_digest_snapshot(profile_root)?; |
| 699 | let body = compose_digest_body(&snapshot, DEFAULT_DIGEST_CHAR_BUDGET); |
| 700 | let fact_count = snapshot |
| 701 | .projects |
| 702 | .iter() |
| 703 | .map(|section| section.lines.len()) |
| 704 | .sum(); |
| 705 | let body = body.unwrap_or_else(|| EMPTY_DIGEST_NOTE.to_string()); |
| 706 | |
| 707 | let written = if target.is_native_overlay() { |
| 708 | export_native_digest(target, output, &body)? |
| 709 | } else { |
| 710 | export_prompt_digest(output, &body)?; |
| 711 | output.to_path_buf() |
| 712 | }; |
| 713 | record_digest_target(profile_root, target, output)?; |
| 714 | Ok(MemoryDigestExportSummary { |
| 715 | target, |
| 716 | output: written, |
| 717 | fact_count, |
| 718 | char_count: body.len(), |
| 719 | }) |
| 720 | } |
| 721 | |
| 722 | /// Removes the digest artifact for one host channel and forgets the recorded |
| 723 | /// export target so refreshes stop re-creating it. |