@@ -452,6 +452,29 @@ def add_single_file(
452452 return _add_single_file_locked (file_path , kb_dir , stage = stage , bundle = bundle )
453453
454454
455+ def _delete_if_auto_cleanup_enabled (
456+ file_path : Path , status : Literal ["added" , "skipped" , "failed" ], config : dict
457+ ) -> bool :
458+ """Delete file if addition succeeded and auto_delete_added_files is enabled.
459+
460+ Args:
461+ file_path: Path to the file to potentially delete.
462+ status: Result status from add_single_file ("added", "skipped", or "failed").
463+ config: Configuration dict (typically from resolve_effective_config).
464+
465+ Returns:
466+ True if file was deleted, False otherwise.
467+ """
468+ if status == "added" and config .get ("auto_delete_added_files" , False ):
469+ try :
470+ file_path .unlink (missing_ok = True )
471+ return True
472+ except Exception as exc :
473+ logger .warning (f"Failed to delete { file_path .name } : { exc } " )
474+ return False
475+ return False
476+
477+
455478def _add_single_file_locked (
456479 file_path : Path , kb_dir : Path , * , stage : bool = True , bundle = None
457480) -> Literal ["added" , "skipped" , "failed" ]:
@@ -1086,6 +1109,9 @@ def add(ctx, path, from_pageindex_cloud):
10861109 Alternatively, pass --from-pageindex-cloud <DOC_ID> to import a document
10871110 that is already indexed in PageIndex Cloud, with no local file. Requires
10881111 the PAGEINDEX_API_KEY environment variable.
1112+
1113+ If ``auto_delete_added_files`` is enabled in config.yaml, successfully
1114+ added files are automatically deleted after ingestion.
10891115 """
10901116 kb_dir = _find_kb_dir (ctx .obj .get ("kb_dir_override" ))
10911117 if kb_dir is None :
@@ -1106,6 +1132,8 @@ def add(ctx, path, from_pageindex_cloud):
11061132 click .echo ("Provide a PATH or use --from-pageindex-cloud <DOC_ID>." )
11071133 return
11081134
1135+ config = resolve_effective_config (kb_dir )[0 ]
1136+
11091137 # URL ingest: download into raw/ first, then call add_single_file explicitly.
11101138 # Keep staged conversion enabled so converted source artifacts do not touch
11111139 # the live KB before the mutation snapshot exists. The tri-state outcome
@@ -1123,6 +1151,8 @@ def add(ctx, path, from_pageindex_cloud):
11231151 # indexing has already succeeded but compilation didn't.
11241152 if outcome == "skipped" :
11251153 fetched .unlink (missing_ok = True )
1154+ else :
1155+ _delete_if_auto_cleanup_enabled (fetched , outcome , config )
11261156 return
11271157
11281158 target = Path (path )
@@ -1143,15 +1173,71 @@ def add(ctx, path, from_pageindex_cloud):
11431173 click .echo (f"Found { total } supported file(s) in { path } ." )
11441174 for i , f in enumerate (files , 1 ):
11451175 click .echo (f"\n [{ i } /{ total } ] " , nl = False )
1146- add_single_file (f , kb_dir )
1176+ outcome = add_single_file (f , kb_dir )
1177+ _delete_if_auto_cleanup_enabled (f , outcome , config )
11471178 else :
11481179 if target .suffix .lower () not in SUPPORTED_EXTENSIONS :
11491180 click .echo (
11501181 f"Unsupported file type: { target .suffix } . "
11511182 f"Supported: { ', ' .join (sorted (SUPPORTED_EXTENSIONS ))} "
11521183 )
11531184 return
1154- add_single_file (target , kb_dir )
1185+ outcome = add_single_file (target , kb_dir )
1186+ _delete_if_auto_cleanup_enabled (target , outcome , config )
1187+
1188+
1189+ @cli .command ()
1190+ @click .pass_context
1191+ @_with_kb_lock (exclusive = True )
1192+ def add_all (ctx ):
1193+ """Process all files in the ``raw/`` directory and add them to the knowledge base.
1194+
1195+ This command walks the ``raw/`` directory recursively for all supported
1196+ document types and ingests them into the KB. If ``auto_delete_added_files``
1197+ is enabled in config.yaml, successfully added files are automatically deleted
1198+ after ingestion.
1199+
1200+ Returns a summary of the operation (added, skipped, failed, deleted counts).
1201+ """
1202+ kb_dir = _find_kb_dir (ctx .obj .get ("kb_dir_override" ))
1203+ if kb_dir is None :
1204+ click .echo ("No knowledge base found. Run `openkb init` first." )
1205+ return
1206+
1207+ raw_dir = kb_dir / "raw"
1208+ if not raw_dir .is_dir ():
1209+ click .echo (f"No raw/ directory found at { raw_dir } " )
1210+ return
1211+
1212+ files = [
1213+ f
1214+ for f in sorted (raw_dir .rglob ("*" ))
1215+ if f .is_file () and f .suffix .lower () in SUPPORTED_EXTENSIONS
1216+ ]
1217+ if not files :
1218+ click .echo ("No supported files found in raw/ directory." )
1219+ return
1220+
1221+ config = resolve_effective_config (kb_dir )[0 ]
1222+ total = len (files )
1223+ added = skipped = failed = deleted = 0
1224+
1225+ click .echo (f"Processing { total } file(s) from raw/ directory..." )
1226+ for i , f in enumerate (files , 1 ):
1227+ click .echo (f"\n [{ i } /{ total } ] " , nl = False )
1228+ outcome = add_single_file (f , kb_dir )
1229+ if outcome == "added" :
1230+ added += 1
1231+ elif outcome == "skipped" :
1232+ skipped += 1
1233+ else :
1234+ failed += 1
1235+ if _delete_if_auto_cleanup_enabled (f , outcome , config ):
1236+ deleted += 1
1237+
1238+ click .echo (
1239+ f"\n \n Summary: Added: { added } , Skipped: { skipped } , Failed: { failed } , Deleted: { deleted } "
1240+ )
11551241
11561242
11571243def _stream_to_tty () -> bool :
0 commit comments