fd958671ca
- Design doc with full spec (dense markdown format, hybrid AST+LLM pipeline, consumption model, stale data mitigation) - Implementation plan with 6 milestones and rollout strategy - TypeScript package structure with all source stubs - CLI entry point, formatter, discover, init, patch, validate, extract, merge - Pi SKILL.md with tool definitions and format documentation
57 lines
1.4 KiB
TypeScript
57 lines
1.4 KiB
TypeScript
import { readdirSync, statSync } from 'fs';
|
|
import { join, relative } from 'path';
|
|
import ignore from 'ignore';
|
|
|
|
const DEFAULT_IGNORE = [
|
|
'node_modules', '.git', 'dist', 'build', 'coverage',
|
|
'.next', '.venv', '__pycache__', '.DS_Store', '*.log'
|
|
];
|
|
|
|
export interface DirectoryEntry {
|
|
dirPath: string;
|
|
relativePath: string;
|
|
files: string[];
|
|
}
|
|
|
|
export function discoverProject(rootPath: string): DirectoryEntry[] {
|
|
const ig = ignore().add(DEFAULT_IGNORE);
|
|
const gitignorePath = join(rootPath, '.gitignore');
|
|
try {
|
|
const gitignoreContent = require('fs').readFileSync(gitignorePath, 'utf8');
|
|
ig.add(gitignoreContent);
|
|
} catch { /* no .gitignore */ }
|
|
|
|
const entries: DirectoryEntry[] = [];
|
|
|
|
function walk(dir: string) {
|
|
const relDir = relative(rootPath, dir) || '.';
|
|
if (ig.ignores(relDir)) return;
|
|
|
|
const items = readdirSync(dir);
|
|
const files: string[] = [];
|
|
const subdirs: string[] = [];
|
|
|
|
for (const item of items) {
|
|
const relPath = join(relDir, item);
|
|
if (ig.ignores(relPath)) continue;
|
|
|
|
const fullPath = join(dir, item);
|
|
const st = statSync(fullPath);
|
|
if (st.isDirectory()) {
|
|
subdirs.push(fullPath);
|
|
} else {
|
|
files.push(item);
|
|
}
|
|
}
|
|
|
|
entries.push({ dirPath: dir, relativePath: relDir, files });
|
|
|
|
for (const subdir of subdirs) {
|
|
walk(subdir);
|
|
}
|
|
}
|
|
|
|
walk(rootPath);
|
|
return entries;
|
|
}
|