* When an `init`/`index` produced an EMPTY graph and the reason is that the * project's own `.gitignore` excludes nested git repositories — the "super-repo * gitignores its child repos" layout (#1156), where `init` at the parent * correctly indexes ~nothing while `init` inside each child works —
(
clack: typeof import('@clack/prompts'),
projectPath: string,
reindex: () => Promise<IndexResult>,
opts: { interactive: boolean },
)
| 463 | * (#970, #1065). Best-effort throughout: detection never breaks the command. |
| 464 | */ |
| 465 | async function offerIndexIgnoredRepos( |
| 466 | clack: typeof import('@clack/prompts'), |
| 467 | projectPath: string, |
| 468 | reindex: () => Promise<IndexResult>, |
| 469 | opts: { interactive: boolean }, |
| 470 | ): Promise<IndexResult | undefined> { |
| 471 | let repos: string[]; |
| 472 | try { |
| 473 | const { findUnindexedIgnoredRepos } = await import('../extraction'); |
| 474 | repos = findUnindexedIgnoredRepos(projectPath); |
| 475 | } catch { |
| 476 | return; // detection is advisory — never let it break the command |
| 477 | } |
| 478 | if (repos.length === 0) return; |
| 479 | |
| 480 | const { PROJECT_CONFIG_FILENAME } = await import('../project-config'); |
| 481 | const isOne = repos.length === 1; |
| 482 | const SHOWN = 6; |
| 483 | const names = repos.slice(0, SHOWN).map((r) => r.replace(/\/$/, '')); |
| 484 | const extra = repos.length > SHOWN ? ` (+${formatNumber(repos.length - SHOWN)} more)` : ''; |
| 485 | const snippet = `{ "includeIgnored": [${repos.map((p) => JSON.stringify(p)).join(', ')}] }`; |
| 486 | |
| 487 | clack.log.warn( |
| 488 | `Your .gitignore excludes ${isOne ? 'a nested git repository' : `${formatNumber(repos.length)} nested git repositories`} here, ` + |
| 489 | `so ${isOne ? 'it was' : 'they were'} not indexed: ${names.join(', ')}${extra}.`, |
| 490 | ); |
| 491 | |
| 492 | const manualHint = () => { |
| 493 | clack.log.info( |
| 494 | `If ${isOne ? "it's" : "they're"} your code, add ${isOne ? 'it' : 'them'} to ${PROJECT_CONFIG_FILENAME} and re-index:`, |
| 495 | ); |
| 496 | clack.log.info(` ${snippet}`); |
| 497 | }; |
| 498 | |
| 499 | if (!opts.interactive || !process.stdin.isTTY) { |
| 500 | manualHint(); |
| 501 | return; |
| 502 | } |
| 503 | |
| 504 | const yes = await clack.confirm({ |
| 505 | message: `Index ${isOne ? 'it' : `these ${formatNumber(repos.length)}`} now? Adds ${isOne ? 'it' : 'them'} to ${PROJECT_CONFIG_FILENAME}.`, |
| 506 | initialValue: true, |
| 507 | }); |
| 508 | if (clack.isCancel(yes) || !yes) { |
| 509 | manualHint(); |
| 510 | return; |
| 511 | } |
| 512 | |
| 513 | let added: number; |
| 514 | try { |
| 515 | const { addIncludeIgnoredPatterns } = await import('../project-config'); |
| 516 | added = addIncludeIgnoredPatterns(projectPath, repos); |
| 517 | } catch (err) { |
| 518 | clack.log.error(`Could not update ${PROJECT_CONFIG_FILENAME}: ${err instanceof Error ? err.message : String(err)}`); |
| 519 | manualHint(); |
| 520 | return; |
| 521 | } |
| 522 | clack.log.success(`Added ${formatNumber(added)} ${added === 1 ? 'entry' : 'entries'} to ${PROJECT_CONFIG_FILENAME} ${getGlyphs().dash} re-indexing…`); |
no test coverage detected