(folder, maxDepth = 2)
| 806 | // Returns true if `folder` has any *unlocked* descendant within maxDepth. |
| 807 | // Uses listChildren’s locked flag; depth defaults to 2 (fast). |
| 808 | async function hasUnlockedDescendant(folder, maxDepth = 2) { |
| 809 | try { |
| 810 | if (maxDepth <= 0) return false; |
| 811 | const { items = [] } = await fetchChildrenOnce(folder); |
| 812 | // Any direct unlocked child? |
| 813 | for (const it of items) { |
| 814 | const name = typeof it === 'string' ? it : it?.name; |
| 815 | const locked = typeof it === 'object' ? !!it.locked : false; |
| 816 | if (!name) continue; |
| 817 | if (!locked) return true; // found an unlocked child |
| 818 | } |
| 819 | // Otherwise, go one level deeper (light, bounded) |
| 820 | if (maxDepth > 1) { |
| 821 | for (const it of items) { |
| 822 | const name = typeof it === 'string' ? it : it?.name; |
| 823 | if (!name) continue; |
| 824 | const child = folder === 'root' ? name : `${folder}/${name}`; |
| 825 | // Skip known non-folders, but listChildren only returns dirs for us |
| 826 | if (await hasUnlockedDescendant(child, maxDepth - 1)) return true; |
| 827 | } |
| 828 | } |
| 829 | } catch (e) {} |
| 830 | return false; |
| 831 | } |
| 832 | |
| 833 | async function chooseInitialFolder(effectiveRoot, selectedFolder) { |
| 834 | // 1) explicit selection |
no test coverage detected