surshar / claude-code
Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.
Built by Anthropic · github.com/anthropics
| 1 | import Limits from '../../../limits' |
| 2 | import Argv from '../../argv' |
| 3 | import GitParse from '../../parse' |
| 4 | import type Types from '../../types' |
| 5 | import { datingsOf } from '../datings-of' |
| 6 | import type { UntrackedPlace } from '../untracked-place' |
| 7 | |
| 8 | /** |
| 9 | * The untracked, unignored files as 0/0 rows: the session's own first, |
| 10 | * then, when the scope asks, the tagged pre-session ones, up to the slots. |
| 11 | * |
| 12 | * At most MAX_UNTRACKED_PROBES are dated; a file past that or past the |
| 13 | * listing budget reads as pre-session, an undatable one as the session's |
| 14 | * (the built-in panel's rule). A listing not given whole: no answer. |
| 15 | * |
| 16 | * @param context the fetch: its pinned git, stamp probe and session start |
| 17 | * @param place the free row slots and the scope |
| 18 | * @returns the rows to merge after the tracked ones, or null when the |
| 19 | * `-z` listing failed, timed out or was cut |
| 20 | */ |
| 21 | export async function untrackedFiles( |
| 22 | context: Pick<Types.FetchContext, 'run' | 'deps' | 'stamps'>, |
| 23 | place: UntrackedPlace, |
| 24 | ): Promise<readonly Types.FileStat[] | null> { |
| 25 | if (place.slots <= 0) { |
| 26 | return [] |
| 27 | } |
| 28 | |
| 29 | const listing = await context.run([ |
| 30 | Argv.NO_OPTIONAL_LOCKS, |
| 31 | 'ls-files', |
| 32 | '-z', |
| 33 | '--others', |
| 34 | '--exclude-standard', |
| 35 | '--full-name', |
| 36 | ]) |
| 37 | |
| 38 | if (!GitParse.isWholeAnswer(listing)) { |
| 39 | return null |
| 40 | } |
| 41 | |
| 42 | const paths = listing.stdout.split('\0').filter(path => path !== '') |
| 43 | const probedPaths = paths.slice(0, Limits.MAX_UNTRACKED_PROBES) |
| 44 | const datings = await datingsOf( |
| 45 | context.stamps, |
| 46 | context.deps.sessionStartMs, |
| 47 | probedPaths, |
| 48 | ) |
| 49 | const probed = probedPaths.map(path => ({ |
| 50 | path, |
| 51 | isPreSession: datings.get(path) !== 'session', |
| 52 | })) |
| 53 | const isWithPreSession = place.scope === 'with-pre-session' |
| 54 | const earlier = isWithPreSession |
| 55 | ? [ |
| 56 | ...probed.filter(file => file.isPreSession), |
| 57 | ...paths |
| 58 | .slice(Limits.MAX_UNTRACKED_PROBES) |
| 59 | .map(path => ({ path, isPreSession: true })), |
| 60 | ] |
| 61 | : [] |
| 62 | const ordered = [...probed.filter(file => !file.isPreSession), ...earlier] |
| 63 | |
| 64 | return ordered.slice(0, place.slots).map(file => ({ |
| 65 | path: file.path, |
| 66 | renamedFrom: null, |
| 67 | added: 0, |
| 68 | removed: 0, |
| 69 | isBinary: false, |
| 70 | isUntracked: true, |
| 71 | isPreSession: file.isPreSession, |
| 72 | })) |
| 73 | } |