Initial commit: pi-project-map skill scaffolding

- 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
This commit is contained in:
2026-06-09 17:45:19 +02:00
commit fd958671ca
20 changed files with 4667 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
import { dirname, join } from 'path';
import { existsSync, readFileSync, writeFileSync } from 'fs';
import { parsePackageMap, renderPackageMap } from './format.js';
import { extractFileLLM } from './llm-extract.js';
import { extractFileAST } from './ast-extract.js';
import { mergeFileData } from './merge.js';
import { readdirSync } from 'fs';
const SMALL_PACKAGE_THRESHOLD = 10;
export async function patchFile(filePath: string): Promise<void> {
const dirPath = dirname(filePath);
const mapPath = join(dirPath, '.pi-map.md');
if (!existsSync(mapPath)) {
// No map exists yet — would need to generate from scratch
console.warn(`No .pi-map.md found in ${dirPath}`);
return;
}
const allFiles = readdirSync(dirPath).filter((f: string) => !f.startsWith('.') && !f.endsWith('.md'));
const isSmallPackage = allFiles.length < SMALL_PACKAGE_THRESHOLD;
if (isSmallPackage) {
// Full rewrite for small packages
// TODO: import and reuse init logic for a single directory
console.log(`Full rewrite of ${mapPath} (small package: ${allFiles.length} files)`);
} else {
// Section-level patch
const existing = parsePackageMap(readFileSync(mapPath, 'utf8'));
const llmData = await extractFileLLM(filePath);
const astData = await extractFileAST(filePath);
const fileName = filePath.split('/').pop()!;
const updatedFile = mergeFileData(fileName, llmData, astData);
// Replace the matching file entry
const idx = existing.files.findIndex(f => f.name === updatedFile.name);
if (idx >= 0) {
existing.files[idx] = updatedFile;
} else {
existing.files.push(updatedFile);
}
existing.dirty = `${new Date().toISOString()}: ${fileName} patched (section-level)`;
writeFileSync(mapPath, renderPackageMap(existing));
console.log(`Patched ${mapPath}`);
}
}