feat(coding-agent): package deduplication and collision detection

- Package deduplication: same package in global+project, project wins
- Collision detection for skills, prompts, and themes with ResourceCollision type
- PathMetadata tracking with parent directory lookup for file paths
- Display improvements: section headers, sorted groups, accent colors for packages
- pi list shows full paths below package names
- Extension loader discovers files in directories without index.ts
- In-memory SettingsManager properly tracks project settings

fixes #645
This commit is contained in:
Mario Zechner 2026-01-24 00:35:19 +01:00
parent c5c515f560
commit 50c8323590
18 changed files with 738 additions and 389 deletions

View file

@ -120,6 +120,7 @@ export class SettingsManager {
private settingsPath: string | null;
private projectSettingsPath: string | null;
private globalSettings: Settings;
private inMemoryProjectSettings: Settings; // For in-memory mode
private settings: Settings;
private persist: boolean;
@ -133,6 +134,7 @@ export class SettingsManager {
this.projectSettingsPath = projectSettingsPath;
this.persist = persist;
this.globalSettings = initialSettings;
this.inMemoryProjectSettings = {};
const projectSettings = this.loadProjectSettings();
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
}
@ -227,6 +229,11 @@ export class SettingsManager {
}
private loadProjectSettings(): Settings {
// In-memory mode: return stored in-memory project settings
if (!this.persist) {
return structuredClone(this.inMemoryProjectSettings);
}
if (!this.projectSettingsPath || !existsSync(this.projectSettingsPath)) {
return {};
}
@ -281,7 +288,13 @@ export class SettingsManager {
}
private saveProjectSettings(settings: Settings): void {
if (!this.persist || !this.projectSettingsPath) {
// In-memory mode: store in memory
if (!this.persist) {
this.inMemoryProjectSettings = structuredClone(settings);
return;
}
if (!this.projectSettingsPath) {
return;
}
try {