diff --git a/src/commands/import.ts b/src/commands/import.ts index b6aad919b..d9b160a4d 100644 --- a/src/commands/import.ts +++ b/src/commands/import.ts @@ -610,7 +610,7 @@ export function collectSyncableFiles(dir: string, opts: CollectOpts = {}): strin // Descent-time prune through the canonical gate (single source of truth // in core/sync.ts) instead of a hand-maintained inline list that drifted // from it. Skips hidden dirs (`.git`, `.raw`, etc.), `node_modules`, - // `vendor`, `dist`, `build`, `ops`, and git submodules. + // `vendor`, `dist`, `build`, `venv` (#2020), `ops`, and git submodules. if (!pruneDir(entry, d)) continue; const full = join(d, entry); diff --git a/src/core/sync.ts b/src/core/sync.ts index 902280309..c2c46a2e1 100644 --- a/src/core/sync.ts +++ b/src/core/sync.ts @@ -249,6 +249,11 @@ const PRUNE_DIR_NAMES = new Set([ 'vendor', 'dist', 'build', + // Python venv: vendored dependency tree, the `node_modules` analogue (#2020). + // Like `node_modules` it lacks a leading dot so isSyncable's dot-prefix + // exclusion misses it; explicit entry keeps incremental sync consistent + // with the first-sync walker in commands/import.ts. + 'venv', '.raw', 'ops', ]);