1import { relative } from 'path' 17type Section = 'movements' | 'info' 18const cmd = (run: () => Promise<unknown>, section: Section, args: string, desc?: string) => Object.assign(run, { section, args, desc }) 21 mv: cmd(() => import('./ptmvMainF.mts').then(m => m.ptmvMain()), 22 'movements', '<from> <to>', 'mv/rn & update imports & importers (auto-commits)'), 23 commit: cmd(() => import('./ptmCommitMainF.mts').then(m => m.ptmCommitMain()), 24 'movements', '--msg= [--files=...] [--amend]', 'pt_commit CLI equivalent (for worktree delegation)'), 25 extract: cmd(() => import('./ptextractMainF.mts').then(m => m.ptextractMain()), 26 'movements', '<exports...> [dest]', 'extract exports to dest or new file'), 27 rntok: cmd(() => import('./ptrntokMainF.mts').then(m => m.ptrntokMain()), 28 'movements', '<from> <to>', 'rn word codebase-wide (auto-commits)'), 29 subst: cmd(() => import('./ptsubstMainAI.mts').then(m => m.ptsubstMain()), 30 'movements', '<pattern> <name>', 'replace pattern, auto-add import if nec'), 31 resolveimport: cmd(async () => { 32 const [fromFile, toFile] = process.argv.slice(2, 4) 33 if (!fromFile || !toFile) throPtErr('usage: ptm resolveimport <fromFile> <toFile>') 34 const { resolveImportPath } = await import('../../deployF/jsImportsF/resolveImportPathF.mts') 35 console.log(resolveImportPath(fromFile, toFile)) 36 }, 'info', '<fromFile> <toFile>', 'compute correct relative import path (avoids depth/extension errors)'), 37 importers: cmd(async () => { 39 const positionalArgs = process.argv.slice(2).filter(a => !a.startsWith('--')) 40 const [importeePath, importerPath] = positionalArgs 43 if (!result) return console.log('No importers found') 44 const lines = result.split('\n') 45 const filtered = epDir ? lines.filter(l => l.startsWith(epDir)) : lines 46 console.log(filtered.join('\n') || 'No importers found') 47 }, 'info', '<file> [<importer>] [--epDir]', 'ls files that directly import tgt'), 48 howimports: cmd(async () => { 50 const epDirArg = process.argv.find(a => a.startsWith('--epDir=')) 51 const epDir = epDirArg?.split('=')[1] 52 const srcPath = process.argv[3] && !process.argv[3].startsWith('--') ? process.argv[3] : undefined 54 }, 'info', '<file> [<srcFile|package>] [--epDir]', 'ls eps that transitively import tgt (or chain from srcFile/pkg)'), 55 lseps: cmd(async () => { 56 const epDirArg = process.argv.find(a => a.startsWith('--epDir=')) 57 const epDir = epDirArg?.split('=')[1] 59 const inclTokens = process.argv.includes('--inclTokens') 60 const inclNpm = process.argv.includes('--inclNpm') 65 const maxPathLen = Math.max(...epPathsA.map(ep => ep.length)) 66 for (const ep of epPathsA) console.log(`${ep.padEnd(maxPathLen + 2)}${getEpType(ep) || '?'}`) 70 const countTokensFn = inclTokens ? (await import('../../sharedF/countTokensF.mts')).countTokens : undefined 71 const epTypesA = epPathsA.map((p: string) => getEpType(p)) 72 const fmtN = (n: number) => n >= 1000 ? (n / 1000).toFixed(1) + 'k' : String(n) 75 for (const s of statsA) { 76 const epTypeStr = s.epType ? ` # ${s.epType}` : '' 77 const epTypeLoc = s.epTypeLocCnt != null ? ` (${fmtN(s.epTypeLocCnt)} epType)` : '' 80 tokStr = ` ${fmtN(s.appTokenCnt!)} tok` 81 if (s.epTypeTokenCnt != null) tokStr += ` (${fmtN(s.epTypeTokenCnt!)} epType tok)` 83 console.log(`\n${s.epPath}${epTypeStr} ${fmtN(s.appLocCnt)} loc${epTypeLoc}${tokStr}`) 84 if (inclNpm && s.appPkgNamesA.length) console.log(` ${jsObjStringify({deps: s.appPkgNamesA})}`) 85 if (inclNpm && s.devPkgNamesA.length) console.log(` ${jsObjStringify({devDeps: s.devPkgNamesA})}`) 87 if (!inclNpm) console.log('\n' + chalkGray('--inclNpm')) 88 }, 'info', '[--epDir=<dir>] [--inclTokens] [--inclNpm]', 'eps & stats'), 89 bisect: cmd(() => import('./ptmBisectAI.mts').then(m => m.ptmBisect()), 90 'info', '<ep> --good=<sha> [--autorun]', 'bisect importtree in isolated worktree'), 91 wt: cmd(() => import('./ptmWorktreeAI.mts').then(m => m.ptmWt()), 92 'info', 'start <name>|--sha=<sha> | done <name> [--discard]', 'isolated worktree (to dev or checkout SHA)'), 93 check: cmd(async () => { 94 const args = process.argv.slice(2) 95 if (!args.length) throPtErr('usage: ptm check <file|dir> [file2|dir2 ...]') 98 }, 'info', '<files|dirs...>', 'check syntax + TS types + boundaries (componentsF can\'t import serverF etc)'), 99 epsearch: cmd(() => import('./ptmEpsearchAI.mts').then(m => m.ptmEpsearchMain()), 100 'info', '<ep> <pattern> [rg-flags...]', 'search within ep import tree (uses rg)'), 101 gitlog: cmd(() => import('./ptmGitlogAI.mts').then(m => m.ptmGitlog()), 102 'info', '<file> [git-log-flags...]', 'git log limited to file import tree'), 103 ocsearch: cmd(() => import('./ptmOcsearchAI.mts').then(m => m.ptmOcsearch()), 104 'info', '<query> [--since=Nd]', 'search past oc sessions & commits by keyword'), 105 exceptions: cmd(() => import('./ptmExceptionsAI.mts').then(m => m.ptmExceptions()), 106 'info', '[--show=<errHash>] [--test]', 'exceptions across all eps from IMAP'), 109const mvEmojiA = ['🙏', '💎', '🤲', '👐', '🫶'] 111const showHelp = () => { 112 const entries = Object.entries(subcommandH) 113 const printSection = (section: Section, header: string) => { 114 console.log(` # ${header}`) 115 const sectionEntries = entries.filter(([_, h]) => h.section === section) 116 if (section === 'movements') { 117 const mvCount = sectionEntries.length 118 throwIf(() => mvCount !== mvEmojiA.length, {mvCount, mvEmojiA}) 120 sectionEntries.forEach(([name, h], i) => { 121 const emoji = section === 'movements' ? `${mvEmojiA[i]} ` : ' ' 123 console.log(` ${name.padEnd(11)}${emoji}${h.args.padEnd(30)}${desc}`) 126 console.log(`$ ${ptmBin} <action> [args]`) 127 printSection('movements', 'movements') 129 printSection('info', 'info/debug') 132export const ptmMain = async () => { 133 const [subcommand, ...restArgs] = process.argv.slice(2) 135 if (!subcommand || subcommand === 'help') { 140 const handler = subcommandH[subcommand as keyof typeof subcommandH] 142 console.error(`Unknown command: ${subcommand}\n`) 147 process.argv = [process.argv[0], process.argv[1], ...restArgs] 149 if (handler.section === 'movements' && relative(ptDir, process.cwd()).startsWith('..')) { 150 console.error(`ERROR: ptm ${subcommand} operates on ptDir (${ptDir}) but you're in a worktree (${process.cwd()}).\nUse: ${process.cwd()}/pt0/path_bin/ptm ${subcommand} ...`)