@@ -84,6 +84,70 @@ def _capture_compatible(trail):
8484 ]
8585
8686
87+ # --- DECANT: pour captured artifacts into one clipboard-ready payload --------
88+ # The bridge between "captured" and "paste this into any ChatBot." Small,
89+ # high-signal lenses are inlined; large ones (hydrated DOM, raw source) are
90+ # cited by their browser_cache path only, so a huge DOM never floods the
91+ # clipboard. Generic label on purpose (Stick Bug / white-label): the bundle
92+ # calls itself "Artifact Compiler," never "Pipulate."
93+ DECANT_INLINE_KEYS = (
94+ "seo_md" ,
95+ "headers" ,
96+ "accessibility_tree_summary" ,
97+ "links_md" ,
98+ "diff_hierarchy_txt" ,
99+ "optics_manifest" ,
100+ )
101+ DECANT_INLINE_CAP = 20000 # chars per inlined lens; the rest lives on disk
102+
103+
104+ def _decant (captured ):
105+ """Build one markdown capture bundle from a list of (stop, url, artifacts)."""
106+ parts = [
107+ "# Artifact Compiler -- Mother Cat capture bundle" ,
108+ "" ,
109+ "Wire-truth artifacts captured on the operator's machine. Each stop" ,
110+ "lists the files written to browser_cache; small high-signal lenses are" ,
111+ "inlined below, large ones (hydrated DOM, raw source) are cited by path." ,
112+ "" ,
113+ ]
114+ for stop_name , final_url , artifacts in captured :
115+ parts .append (f"## Stop: { stop_name } " )
116+ parts .append (f"- final_url: { final_url } " )
117+ parts .append ("- artifacts on disk:" )
118+ for key , path in sorted (artifacts .items ()):
119+ parts .append (f" - { key } : { path } " )
120+ parts .append ("" )
121+ for key in DECANT_INLINE_KEYS :
122+ path = artifacts .get (key )
123+ if not path or not os .path .exists (path ):
124+ continue
125+ try :
126+ text = Path (path ).read_text (encoding = "utf-8" , errors = "replace" )
127+ except OSError :
128+ continue
129+ if len (text ) > DECANT_INLINE_CAP :
130+ text = text [:DECANT_INLINE_CAP ] + "\n ... [truncated; full file on disk]"
131+ parts .append (f"### { stop_name } -- { key } " )
132+ parts .append ("```text" )
133+ parts .append (text )
134+ parts .append ("```" )
135+ parts .append ("" )
136+ return "\n " .join (parts )
137+
138+
139+ def _decant_to_clipboard (payload ):
140+ """Copy the bundle to the clipboard, reusing prompt_foo's cross-platform path.
141+
142+ Deferred import: prompt_foo drags tiktoken/pydot in at module load, so it is
143+ imported HERE, on a real DECANT only -- never on module import or
144+ --dry-narrate. Reuse over re-implement: copy_to_clipboard already owns the
145+ SSH-bridge and the pbcopy/xclip fallbacks.
146+ """
147+ from prompt_foo import copy_to_clipboard
148+ copy_to_clipboard (payload )
149+
150+
87151async def _ride_async (trail_path , dry_narrate = False ):
88152 trail_path = Path (trail_path )
89153 trail = walk .load_trail (trail_path )
0 commit comments