@emaenriquez/projectmanager-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -0
- package/dist/application/ConfigManager.d.ts +73 -0
- package/dist/application/ConfigManager.d.ts.map +1 -0
- package/dist/application/ConfigManager.js +253 -0
- package/dist/application/ConfigManager.js.map +1 -0
- package/dist/application/errors/ErrorHandler.d.ts +27 -0
- package/dist/application/errors/ErrorHandler.d.ts.map +1 -0
- package/dist/application/errors/ErrorHandler.js +88 -0
- package/dist/application/errors/ErrorHandler.js.map +1 -0
- package/dist/application/state/StateManager.d.ts +26 -0
- package/dist/application/state/StateManager.d.ts.map +1 -0
- package/dist/application/state/StateManager.js +114 -0
- package/dist/application/state/StateManager.js.map +1 -0
- package/dist/application/use_cases/AddProjectUseCase.d.ts +9 -0
- package/dist/application/use_cases/AddProjectUseCase.d.ts.map +1 -0
- package/dist/application/use_cases/AddProjectUseCase.js +85 -0
- package/dist/application/use_cases/AddProjectUseCase.js.map +1 -0
- package/dist/application/use_cases/ListProjectsUseCase.d.ts +7 -0
- package/dist/application/use_cases/ListProjectsUseCase.d.ts.map +1 -0
- package/dist/application/use_cases/ListProjectsUseCase.js +14 -0
- package/dist/application/use_cases/ListProjectsUseCase.js.map +1 -0
- package/dist/application/use_cases/OpenProjectUseCase.d.ts +10 -0
- package/dist/application/use_cases/OpenProjectUseCase.d.ts.map +1 -0
- package/dist/application/use_cases/OpenProjectUseCase.js +168 -0
- package/dist/application/use_cases/OpenProjectUseCase.js.map +1 -0
- package/dist/application/use_cases/RemoveProjectUseCase.d.ts +7 -0
- package/dist/application/use_cases/RemoveProjectUseCase.d.ts.map +1 -0
- package/dist/application/use_cases/RemoveProjectUseCase.js +24 -0
- package/dist/application/use_cases/RemoveProjectUseCase.js.map +1 -0
- package/dist/application/use_cases/ScanProjectsUseCase.d.ts +13 -0
- package/dist/application/use_cases/ScanProjectsUseCase.d.ts.map +1 -0
- package/dist/application/use_cases/ScanProjectsUseCase.js +57 -0
- package/dist/application/use_cases/ScanProjectsUseCase.js.map +1 -0
- package/dist/application/use_cases/SyncProjectsUseCase.d.ts +12 -0
- package/dist/application/use_cases/SyncProjectsUseCase.d.ts.map +1 -0
- package/dist/application/use_cases/SyncProjectsUseCase.js +74 -0
- package/dist/application/use_cases/SyncProjectsUseCase.js.map +1 -0
- package/dist/application/use_cases/SystemDiagnostics.d.ts +16 -0
- package/dist/application/use_cases/SystemDiagnostics.d.ts.map +1 -0
- package/dist/application/use_cases/SystemDiagnostics.js +35 -0
- package/dist/application/use_cases/SystemDiagnostics.js.map +1 -0
- package/dist/application/use_cases/TagProjectUseCase.d.ts +9 -0
- package/dist/application/use_cases/TagProjectUseCase.d.ts.map +1 -0
- package/dist/application/use_cases/TagProjectUseCase.js +41 -0
- package/dist/application/use_cases/TagProjectUseCase.js.map +1 -0
- package/dist/domain/patterns/ProjectPatterns.d.ts +47 -0
- package/dist/domain/patterns/ProjectPatterns.d.ts.map +1 -0
- package/dist/domain/patterns/ProjectPatterns.js +200 -0
- package/dist/domain/patterns/ProjectPatterns.js.map +1 -0
- package/dist/domain/services/GitService.d.ts +23 -0
- package/dist/domain/services/GitService.d.ts.map +1 -0
- package/dist/domain/services/GitService.js +155 -0
- package/dist/domain/services/GitService.js.map +1 -0
- package/dist/domain/services/IgnoreFileParser.d.ts +55 -0
- package/dist/domain/services/IgnoreFileParser.d.ts.map +1 -0
- package/dist/domain/services/IgnoreFileParser.js +200 -0
- package/dist/domain/services/IgnoreFileParser.js.map +1 -0
- package/dist/domain/services/ProjectScanner.d.ts +65 -0
- package/dist/domain/services/ProjectScanner.d.ts.map +1 -0
- package/dist/domain/services/ProjectScanner.js +207 -0
- package/dist/domain/services/ProjectScanner.js.map +1 -0
- package/dist/domain/services/TechnologyDetector.d.ts +78 -0
- package/dist/domain/services/TechnologyDetector.d.ts.map +1 -0
- package/dist/domain/services/TechnologyDetector.js +633 -0
- package/dist/domain/services/TechnologyDetector.js.map +1 -0
- package/dist/domain/services/ToolDetector.d.ts +74 -0
- package/dist/domain/services/ToolDetector.d.ts.map +1 -0
- package/dist/domain/services/ToolDetector.js +344 -0
- package/dist/domain/services/ToolDetector.js.map +1 -0
- package/dist/domain/services/index.d.ts +5 -0
- package/dist/domain/services/index.d.ts.map +1 -0
- package/dist/domain/services/index.js +12 -0
- package/dist/domain/services/index.js.map +1 -0
- package/dist/domain/types/Config.d.ts +37 -0
- package/dist/domain/types/Config.d.ts.map +1 -0
- package/dist/domain/types/Config.js +6 -0
- package/dist/domain/types/Config.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/database/DatabaseConnection.d.ts +88 -0
- package/dist/infrastructure/database/DatabaseConnection.d.ts.map +1 -0
- package/dist/infrastructure/database/DatabaseConnection.js +318 -0
- package/dist/infrastructure/database/DatabaseConnection.js.map +1 -0
- package/dist/infrastructure/database/DatabaseValidator.d.ts +154 -0
- package/dist/infrastructure/database/DatabaseValidator.d.ts.map +1 -0
- package/dist/infrastructure/database/DatabaseValidator.js +583 -0
- package/dist/infrastructure/database/DatabaseValidator.js.map +1 -0
- package/dist/infrastructure/database/index.d.ts +8 -0
- package/dist/infrastructure/database/index.d.ts.map +1 -0
- package/dist/infrastructure/database/index.js +14 -0
- package/dist/infrastructure/database/index.js.map +1 -0
- package/dist/infrastructure/database/migrations/001_initial.d.ts +24 -0
- package/dist/infrastructure/database/migrations/001_initial.d.ts.map +1 -0
- package/dist/infrastructure/database/migrations/001_initial.js +109 -0
- package/dist/infrastructure/database/migrations/001_initial.js.map +1 -0
- package/dist/infrastructure/database/migrations/Migration.d.ts +27 -0
- package/dist/infrastructure/database/migrations/Migration.d.ts.map +1 -0
- package/dist/infrastructure/database/migrations/Migration.js +3 -0
- package/dist/infrastructure/database/migrations/Migration.js.map +1 -0
- package/dist/infrastructure/database/migrations/MigrationRunner.d.ts +52 -0
- package/dist/infrastructure/database/migrations/MigrationRunner.d.ts.map +1 -0
- package/dist/infrastructure/database/migrations/MigrationRunner.js +167 -0
- package/dist/infrastructure/database/migrations/MigrationRunner.js.map +1 -0
- package/dist/infrastructure/database/migrations/index.d.ts +10 -0
- package/dist/infrastructure/database/migrations/index.d.ts.map +1 -0
- package/dist/infrastructure/database/migrations/index.js +22 -0
- package/dist/infrastructure/database/migrations/index.js.map +1 -0
- package/dist/infrastructure/filesystem/DirectoryManager.d.ts +50 -0
- package/dist/infrastructure/filesystem/DirectoryManager.d.ts.map +1 -0
- package/dist/infrastructure/filesystem/DirectoryManager.js +143 -0
- package/dist/infrastructure/filesystem/DirectoryManager.js.map +1 -0
- package/dist/infrastructure/filesystem/index.d.ts +2 -0
- package/dist/infrastructure/filesystem/index.d.ts.map +1 -0
- package/dist/infrastructure/filesystem/index.js +6 -0
- package/dist/infrastructure/filesystem/index.js.map +1 -0
- package/dist/infrastructure/logging/LogRotator.d.ts +43 -0
- package/dist/infrastructure/logging/LogRotator.d.ts.map +1 -0
- package/dist/infrastructure/logging/LogRotator.js +172 -0
- package/dist/infrastructure/logging/LogRotator.js.map +1 -0
- package/dist/infrastructure/logging/Logger.d.ts +59 -0
- package/dist/infrastructure/logging/Logger.d.ts.map +1 -0
- package/dist/infrastructure/logging/Logger.js +182 -0
- package/dist/infrastructure/logging/Logger.js.map +1 -0
- package/dist/infrastructure/logging/index.d.ts +3 -0
- package/dist/infrastructure/logging/index.d.ts.map +1 -0
- package/dist/infrastructure/logging/index.js +8 -0
- package/dist/infrastructure/logging/index.js.map +1 -0
- package/dist/infrastructure/repositories/ProjectRepository.d.ts +20 -0
- package/dist/infrastructure/repositories/ProjectRepository.d.ts.map +1 -0
- package/dist/infrastructure/repositories/ProjectRepository.js +61 -0
- package/dist/infrastructure/repositories/ProjectRepository.js.map +1 -0
- package/dist/infrastructure/repositories/QueryBuilder.d.ts +24 -0
- package/dist/infrastructure/repositories/QueryBuilder.d.ts.map +1 -0
- package/dist/infrastructure/repositories/QueryBuilder.js +92 -0
- package/dist/infrastructure/repositories/QueryBuilder.js.map +1 -0
- package/dist/infrastructure/repositories/TagRepository.d.ts +18 -0
- package/dist/infrastructure/repositories/TagRepository.d.ts.map +1 -0
- package/dist/infrastructure/repositories/TagRepository.js +66 -0
- package/dist/infrastructure/repositories/TagRepository.js.map +1 -0
- package/dist/infrastructure/repositories/TechnologyRepository.d.ts +16 -0
- package/dist/infrastructure/repositories/TechnologyRepository.d.ts.map +1 -0
- package/dist/infrastructure/repositories/TechnologyRepository.js +46 -0
- package/dist/infrastructure/repositories/TechnologyRepository.js.map +1 -0
- package/dist/infrastructure/repositories/TransactionManager.d.ts +11 -0
- package/dist/infrastructure/repositories/TransactionManager.d.ts.map +1 -0
- package/dist/infrastructure/repositories/TransactionManager.js +21 -0
- package/dist/infrastructure/repositories/TransactionManager.js.map +1 -0
- package/dist/infrastructure/ui/ScreenManager.d.ts +11 -0
- package/dist/infrastructure/ui/ScreenManager.d.ts.map +1 -0
- package/dist/infrastructure/ui/ScreenManager.js +69 -0
- package/dist/infrastructure/ui/ScreenManager.js.map +1 -0
- package/dist/ui/cli/CLI.d.ts +9 -0
- package/dist/ui/cli/CLI.d.ts.map +1 -0
- package/dist/ui/cli/CLI.js +211 -0
- package/dist/ui/cli/CLI.js.map +1 -0
- package/dist/ui/components/DetailsPanel.d.ts +11 -0
- package/dist/ui/components/DetailsPanel.d.ts.map +1 -0
- package/dist/ui/components/DetailsPanel.js +181 -0
- package/dist/ui/components/DetailsPanel.js.map +1 -0
- package/dist/ui/components/ProjectListView.d.ts +15 -0
- package/dist/ui/components/ProjectListView.d.ts.map +1 -0
- package/dist/ui/components/ProjectListView.js +122 -0
- package/dist/ui/components/ProjectListView.js.map +1 -0
- package/dist/ui/tui/TUIApplication.d.ts +17 -0
- package/dist/ui/tui/TUIApplication.d.ts.map +1 -0
- package/dist/ui/tui/TUIApplication.js +532 -0
- package/dist/ui/tui/TUIApplication.js.map +1 -0
- package/dist/ui/tui/Theme.d.ts +25 -0
- package/dist/ui/tui/Theme.d.ts.map +1 -0
- package/dist/ui/tui/Theme.js +62 -0
- package/dist/ui/tui/Theme.js.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Project Hub
|
|
2
|
+
|
|
3
|
+
A CLI/TUI application for managing development projects across multiple technologies.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Project Scanning**: Automatically detect projects by scanning directories for config files (package.json, Cargo.toml, go.mod, etc.)
|
|
8
|
+
- **Technology Detection**: Identifies languages, frameworks, and tools used in each project
|
|
9
|
+
- **TUI Interface**: Interactive terminal UI with project list, details panel, and keyboard shortcuts
|
|
10
|
+
- **CLI Commands**: Full command-line interface for scripting and automation
|
|
11
|
+
- **Git Integration**: Shows branch, uncommitted changes, and unpushed commits
|
|
12
|
+
- **Tags & Favorites**: Organize projects with custom tags and mark favorites
|
|
13
|
+
- **Search & Filter**: Find projects quickly by name, technology, or tag
|
|
14
|
+
- **System Diagnostics**: `doctor` command to verify installed tools and database health
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Install dependencies
|
|
20
|
+
npm install
|
|
21
|
+
|
|
22
|
+
# Run in TUI mode (interactive)
|
|
23
|
+
npm run dev
|
|
24
|
+
|
|
25
|
+
# Run CLI commands
|
|
26
|
+
npm run dev -- scan C:\path\to\projects
|
|
27
|
+
npm run dev -- add C:\path\to\project
|
|
28
|
+
npm run dev -- doctor
|
|
29
|
+
npm run dev -- --help
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## CLI Commands
|
|
33
|
+
|
|
34
|
+
| Command | Description |
|
|
35
|
+
|---------|-------------|
|
|
36
|
+
| `scan [path]` | Scan a directory for projects |
|
|
37
|
+
| `add <path>` | Add a single project by path |
|
|
38
|
+
| `remove <id>` | Remove a project |
|
|
39
|
+
| `open <id> [--with <tool>]` | Open a project in an editor |
|
|
40
|
+
| `doctor` | Run system diagnostics |
|
|
41
|
+
| `sync` | Sync all projects (remove missing, update metadata) |
|
|
42
|
+
| `config list` | Show all configurations |
|
|
43
|
+
| `config get <key>` | Get a config value |
|
|
44
|
+
| `config set <key> <value>` | Set a config value |
|
|
45
|
+
| `config reset` | Reset config to defaults |
|
|
46
|
+
|
|
47
|
+
## TUI Keyboard Shortcuts
|
|
48
|
+
|
|
49
|
+
| Key | Action |
|
|
50
|
+
|-----|--------|
|
|
51
|
+
| `↑/↓` | Navigate project list |
|
|
52
|
+
| `Enter` / `D` | View project details |
|
|
53
|
+
| `A` | Add a project by path |
|
|
54
|
+
| `S` | Scan a directory |
|
|
55
|
+
| `F` | Search/filter projects |
|
|
56
|
+
| `*` | Toggle favorite |
|
|
57
|
+
| `T` | Add tag to project |
|
|
58
|
+
| `O` | Open project in editor |
|
|
59
|
+
| `X` | Delete project |
|
|
60
|
+
| `R` | Refresh list |
|
|
61
|
+
| `Q` / `Esc` | Quit |
|
|
62
|
+
|
|
63
|
+
## Architecture
|
|
64
|
+
|
|
65
|
+
The project follows **Clean Architecture** principles:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
src/
|
|
69
|
+
├── domain/ # Business entities, services (ProjectScanner, TechnologyDetector, GitService)
|
|
70
|
+
├── application/ # Use cases (ScanProjects, AddProject, etc.), state management, error handling
|
|
71
|
+
├── infrastructure/ # Database (SQLite), repositories, UI framework (Blessed)
|
|
72
|
+
└── ui/ # CLI (Commander.js), TUI components, views
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Tech Stack
|
|
76
|
+
|
|
77
|
+
- **Runtime**: Node.js + TypeScript
|
|
78
|
+
- **Database**: SQLite via better-sqlite3
|
|
79
|
+
- **CLI Framework**: Commander.js
|
|
80
|
+
- **TUI Framework**: Blessed
|
|
81
|
+
- **Testing**: Jest
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Run tests
|
|
87
|
+
npm test
|
|
88
|
+
|
|
89
|
+
# Build
|
|
90
|
+
npm run build
|
|
91
|
+
|
|
92
|
+
# Lint
|
|
93
|
+
npm run lint
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Config, DeepConfigKey } from '../domain/types/Config';
|
|
2
|
+
/**
|
|
3
|
+
* ConfigManager - Manages application configuration
|
|
4
|
+
*
|
|
5
|
+
* Responsibilities:
|
|
6
|
+
* - Load configuration from default and user-saved files
|
|
7
|
+
* - Provide get/set/reset operations
|
|
8
|
+
* - Validate configuration values
|
|
9
|
+
* - Persist configuration to disk
|
|
10
|
+
* - Merge defaults with user-saved configuration
|
|
11
|
+
*/
|
|
12
|
+
export declare class ConfigManager {
|
|
13
|
+
private config;
|
|
14
|
+
private defaultConfig;
|
|
15
|
+
private configPath;
|
|
16
|
+
private defaultConfigPath;
|
|
17
|
+
constructor(defaultConfigPath?: string, userConfigDir?: string);
|
|
18
|
+
/**
|
|
19
|
+
* Expand ~ to home directory path
|
|
20
|
+
*/
|
|
21
|
+
private expandHomePath;
|
|
22
|
+
/**
|
|
23
|
+
* Load default configuration from default.json
|
|
24
|
+
*/
|
|
25
|
+
private loadDefaultConfig;
|
|
26
|
+
/**
|
|
27
|
+
* Load user configuration or initialize with defaults
|
|
28
|
+
*/
|
|
29
|
+
private loadOrInitializeConfig;
|
|
30
|
+
/**
|
|
31
|
+
* Deep merge default and user configurations
|
|
32
|
+
*/
|
|
33
|
+
private deepMerge;
|
|
34
|
+
/**
|
|
35
|
+
* Clone configuration object deeply
|
|
36
|
+
*/
|
|
37
|
+
private cloneConfig;
|
|
38
|
+
/**
|
|
39
|
+
* Get configuration value by key
|
|
40
|
+
* Supports nested keys like "app.name"
|
|
41
|
+
*/
|
|
42
|
+
get(key: DeepConfigKey): any;
|
|
43
|
+
/**
|
|
44
|
+
* Get entire configuration
|
|
45
|
+
*/
|
|
46
|
+
getAll(): Config;
|
|
47
|
+
/**
|
|
48
|
+
* Set configuration value
|
|
49
|
+
* Supports nested keys like "app.name"
|
|
50
|
+
*/
|
|
51
|
+
set(key: DeepConfigKey, value: any): void;
|
|
52
|
+
/**
|
|
53
|
+
* Reset configuration to defaults
|
|
54
|
+
*/
|
|
55
|
+
reset(): void;
|
|
56
|
+
/**
|
|
57
|
+
* Validate configuration value before setting
|
|
58
|
+
*/
|
|
59
|
+
private validateConfigValue;
|
|
60
|
+
/**
|
|
61
|
+
* Persist configuration to disk
|
|
62
|
+
*/
|
|
63
|
+
private persist;
|
|
64
|
+
/**
|
|
65
|
+
* Get configuration file path
|
|
66
|
+
*/
|
|
67
|
+
getConfigPath(): string;
|
|
68
|
+
/**
|
|
69
|
+
* Get default configuration file path
|
|
70
|
+
*/
|
|
71
|
+
getDefaultConfigPath(): string;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=ConfigManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfigManager.d.ts","sourceRoot":"","sources":["../../src/application/ConfigManager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE/D;;;;;;;;;GASG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,iBAAiB,CAAS;gBAGhC,iBAAiB,GAAE,MAA0D,EAC7E,aAAa,GAAE,MAA8C;IAY/D;;OAEG;IACH,OAAO,CAAC,cAAc;IAUtB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASzB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAuB9B;;OAEG;IACH,OAAO,CAAC,SAAS;IAmBjB;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,aAAa,GAAG,GAAG;IAe5B;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAsBzC;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4C3B;;OAEG;IACH,OAAO,CAAC,OAAO;IAYf;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,oBAAoB,IAAI,MAAM;CAG/B"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ConfigManager = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
/**
|
|
40
|
+
* ConfigManager - Manages application configuration
|
|
41
|
+
*
|
|
42
|
+
* Responsibilities:
|
|
43
|
+
* - Load configuration from default and user-saved files
|
|
44
|
+
* - Provide get/set/reset operations
|
|
45
|
+
* - Validate configuration values
|
|
46
|
+
* - Persist configuration to disk
|
|
47
|
+
* - Merge defaults with user-saved configuration
|
|
48
|
+
*/
|
|
49
|
+
class ConfigManager {
|
|
50
|
+
constructor(defaultConfigPath = path.join(__dirname, '../../config/default.json'), userConfigDir = this.expandHomePath('~/.project-hub')) {
|
|
51
|
+
this.defaultConfigPath = defaultConfigPath;
|
|
52
|
+
this.configPath = path.join(userConfigDir, 'config.json');
|
|
53
|
+
// Load default configuration
|
|
54
|
+
this.defaultConfig = this.loadDefaultConfig();
|
|
55
|
+
// Load user configuration or use defaults
|
|
56
|
+
this.config = this.loadOrInitializeConfig();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Expand ~ to home directory path
|
|
60
|
+
*/
|
|
61
|
+
expandHomePath(filepath) {
|
|
62
|
+
if (filepath === '~') {
|
|
63
|
+
return process.env.HOME || process.env.USERPROFILE || '';
|
|
64
|
+
}
|
|
65
|
+
if (filepath.startsWith('~/')) {
|
|
66
|
+
return path.join(process.env.HOME || process.env.USERPROFILE || '', filepath.slice(2));
|
|
67
|
+
}
|
|
68
|
+
return filepath;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Load default configuration from default.json
|
|
72
|
+
*/
|
|
73
|
+
loadDefaultConfig() {
|
|
74
|
+
try {
|
|
75
|
+
const configContent = fs.readFileSync(this.defaultConfigPath, 'utf-8');
|
|
76
|
+
return JSON.parse(configContent);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
throw new Error(`Failed to load default configuration: ${error}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Load user configuration or initialize with defaults
|
|
84
|
+
*/
|
|
85
|
+
loadOrInitializeConfig() {
|
|
86
|
+
// Ensure config directory exists
|
|
87
|
+
const configDir = path.dirname(this.configPath);
|
|
88
|
+
if (!fs.existsSync(configDir)) {
|
|
89
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
90
|
+
}
|
|
91
|
+
// If user config exists, load and merge with defaults
|
|
92
|
+
if (fs.existsSync(this.configPath)) {
|
|
93
|
+
try {
|
|
94
|
+
const userConfig = JSON.parse(fs.readFileSync(this.configPath, 'utf-8'));
|
|
95
|
+
return this.deepMerge(this.defaultConfig, userConfig);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
// If loading fails, return defaults and log warning
|
|
99
|
+
console.warn(`Failed to load user config, using defaults: ${error}`);
|
|
100
|
+
return this.cloneConfig(this.defaultConfig);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Return defaults if no user config exists
|
|
104
|
+
return this.cloneConfig(this.defaultConfig);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Deep merge default and user configurations
|
|
108
|
+
*/
|
|
109
|
+
deepMerge(defaultConfig, userConfig) {
|
|
110
|
+
const result = this.cloneConfig(defaultConfig);
|
|
111
|
+
for (const key in userConfig) {
|
|
112
|
+
if (key in result) {
|
|
113
|
+
if (typeof userConfig[key] === 'object' && userConfig[key] !== null) {
|
|
114
|
+
result[key] = {
|
|
115
|
+
...result[key],
|
|
116
|
+
...userConfig[key],
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
result[key] = userConfig[key];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Clone configuration object deeply
|
|
128
|
+
*/
|
|
129
|
+
cloneConfig(config) {
|
|
130
|
+
return JSON.parse(JSON.stringify(config));
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get configuration value by key
|
|
134
|
+
* Supports nested keys like "app.name"
|
|
135
|
+
*/
|
|
136
|
+
get(key) {
|
|
137
|
+
const keys = key.split('.');
|
|
138
|
+
let value = this.config;
|
|
139
|
+
for (const k of keys) {
|
|
140
|
+
if (value && typeof value === 'object' && k in value) {
|
|
141
|
+
value = value[k];
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return value;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get entire configuration
|
|
151
|
+
*/
|
|
152
|
+
getAll() {
|
|
153
|
+
return this.cloneConfig(this.config);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Set configuration value
|
|
157
|
+
* Supports nested keys like "app.name"
|
|
158
|
+
*/
|
|
159
|
+
set(key, value) {
|
|
160
|
+
this.validateConfigValue(key, value);
|
|
161
|
+
const keys = key.split('.');
|
|
162
|
+
const lastKey = keys.pop();
|
|
163
|
+
if (!lastKey) {
|
|
164
|
+
throw new Error('Invalid configuration key');
|
|
165
|
+
}
|
|
166
|
+
let target = this.config;
|
|
167
|
+
for (const k of keys) {
|
|
168
|
+
if (!(k in target)) {
|
|
169
|
+
target[k] = {};
|
|
170
|
+
}
|
|
171
|
+
target = target[k];
|
|
172
|
+
}
|
|
173
|
+
target[lastKey] = value;
|
|
174
|
+
this.persist();
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Reset configuration to defaults
|
|
178
|
+
*/
|
|
179
|
+
reset() {
|
|
180
|
+
this.config = this.cloneConfig(this.defaultConfig);
|
|
181
|
+
this.persist();
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Validate configuration value before setting
|
|
185
|
+
*/
|
|
186
|
+
validateConfigValue(key, value) {
|
|
187
|
+
// Theme validation
|
|
188
|
+
if (key === 'ui.theme') {
|
|
189
|
+
if (!['dark', 'light'].includes(value)) {
|
|
190
|
+
throw new Error(`Invalid theme: ${value}. Must be 'dark' or 'light'.`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Logging level validation
|
|
194
|
+
if (key === 'logging.level') {
|
|
195
|
+
if (!['debug', 'info', 'warn', 'error'].includes(value)) {
|
|
196
|
+
throw new Error(`Invalid logging level: ${value}. Must be 'debug', 'info', 'warn', or 'error'.`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Scanner depth validation
|
|
200
|
+
if (key === 'scanner.depth') {
|
|
201
|
+
if (typeof value !== 'number' || value < 1) {
|
|
202
|
+
throw new Error(`Invalid scanner depth: ${value}. Must be a positive number.`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Items per page validation
|
|
206
|
+
if (key === 'ui.itemsPerPage') {
|
|
207
|
+
if (typeof value !== 'number' || value < 1) {
|
|
208
|
+
throw new Error(`Invalid itemsPerPage: ${value}. Must be a positive number.`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Patterns validation
|
|
212
|
+
if (key === 'scanner.patterns') {
|
|
213
|
+
if (!Array.isArray(value) || value.some(v => typeof v !== 'string')) {
|
|
214
|
+
throw new Error('Invalid scanner patterns. Must be an array of strings.');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Editors validation
|
|
218
|
+
if (key === 'tools.editors') {
|
|
219
|
+
if (!Array.isArray(value) || value.some(v => typeof v !== 'string')) {
|
|
220
|
+
throw new Error('Invalid editors. Must be an array of strings.');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Persist configuration to disk
|
|
226
|
+
*/
|
|
227
|
+
persist() {
|
|
228
|
+
try {
|
|
229
|
+
const configDir = path.dirname(this.configPath);
|
|
230
|
+
if (!fs.existsSync(configDir)) {
|
|
231
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
232
|
+
}
|
|
233
|
+
fs.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2), 'utf-8');
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
throw new Error(`Failed to persist configuration: ${error}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get configuration file path
|
|
241
|
+
*/
|
|
242
|
+
getConfigPath() {
|
|
243
|
+
return this.configPath;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Get default configuration file path
|
|
247
|
+
*/
|
|
248
|
+
getDefaultConfigPath() {
|
|
249
|
+
return this.defaultConfigPath;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
exports.ConfigManager = ConfigManager;
|
|
253
|
+
//# sourceMappingURL=ConfigManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfigManager.js","sourceRoot":"","sources":["../../src/application/ConfigManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare class AppError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly isTransient: boolean;
|
|
4
|
+
readonly recoverySteps: string[];
|
|
5
|
+
constructor(message: string, code: string, isTransient: boolean, recoverySteps?: string[]);
|
|
6
|
+
}
|
|
7
|
+
export declare class DatabaseError extends AppError {
|
|
8
|
+
constructor(message: string, isTransient?: boolean);
|
|
9
|
+
}
|
|
10
|
+
export declare class FileSystemError extends AppError {
|
|
11
|
+
constructor(message: string, isTransient?: boolean);
|
|
12
|
+
}
|
|
13
|
+
export declare class ErrorHandler {
|
|
14
|
+
/**
|
|
15
|
+
* Retry a function if it throws a transient error
|
|
16
|
+
*/
|
|
17
|
+
static withRetry<T>(operation: () => Promise<T> | T, maxRetries?: number, delayMs?: number): Promise<T>;
|
|
18
|
+
/**
|
|
19
|
+
* Format error for UI display
|
|
20
|
+
*/
|
|
21
|
+
static formatError(error: unknown): string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Decorator/Wrapper for use cases to handle uncaught exceptions gracefully
|
|
25
|
+
*/
|
|
26
|
+
export declare function withErrorGuard<TArgs extends any[], TResult>(fn: (...args: TArgs) => TResult): (...args: TArgs) => TResult;
|
|
27
|
+
//# sourceMappingURL=ErrorHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorHandler.d.ts","sourceRoot":"","sources":["../../../src/application/errors/ErrorHandler.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,WAAW,EAAE,OAAO,CAAC;IACrC,SAAgB,aAAa,EAAE,MAAM,EAAE,CAAC;gBAE5B,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAE,MAAM,EAAO;CAQ9F;AAED,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,OAAO,EAAE,MAAM,EAAE,WAAW,GAAE,OAAe;CAM1D;AAED,qBAAa,eAAgB,SAAQ,QAAQ;gBAC/B,OAAO,EAAE,MAAM,EAAE,WAAW,GAAE,OAAe;CAM1D;AAED,qBAAa,YAAY;IACvB;;OAEG;WACiB,SAAS,CAAC,CAAC,EAC7B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAC/B,UAAU,GAAE,MAAU,EACtB,OAAO,GAAE,MAAa,GACrB,OAAO,CAAC,CAAC,CAAC;IAuBb;;OAEG;WACW,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;CAelD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,SAAS,GAAG,EAAE,EAAE,OAAO,EACzD,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,GAC9B,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAS7B"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ErrorHandler = exports.FileSystemError = exports.DatabaseError = exports.AppError = void 0;
|
|
4
|
+
exports.withErrorGuard = withErrorGuard;
|
|
5
|
+
class AppError extends Error {
|
|
6
|
+
constructor(message, code, isTransient, recoverySteps = []) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = this.constructor.name;
|
|
9
|
+
this.code = code;
|
|
10
|
+
this.isTransient = isTransient;
|
|
11
|
+
this.recoverySteps = recoverySteps;
|
|
12
|
+
Error.captureStackTrace(this, this.constructor);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.AppError = AppError;
|
|
16
|
+
class DatabaseError extends AppError {
|
|
17
|
+
constructor(message, isTransient = false) {
|
|
18
|
+
super(message, 'DB_ERROR', isTransient, [
|
|
19
|
+
'Ensure the database file is not locked by another process.',
|
|
20
|
+
'Check if you have sufficient disk space and permissions.'
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.DatabaseError = DatabaseError;
|
|
25
|
+
class FileSystemError extends AppError {
|
|
26
|
+
constructor(message, isTransient = false) {
|
|
27
|
+
super(message, 'FS_ERROR', isTransient, [
|
|
28
|
+
'Verify the file or directory exists and you have read/write permissions.',
|
|
29
|
+
'Check if the path is correct.'
|
|
30
|
+
]);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.FileSystemError = FileSystemError;
|
|
34
|
+
class ErrorHandler {
|
|
35
|
+
/**
|
|
36
|
+
* Retry a function if it throws a transient error
|
|
37
|
+
*/
|
|
38
|
+
static async withRetry(operation, maxRetries = 3, delayMs = 1000) {
|
|
39
|
+
let lastError;
|
|
40
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
41
|
+
try {
|
|
42
|
+
return await operation();
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
lastError = error;
|
|
46
|
+
const isTransient = error instanceof AppError ? error.isTransient : false;
|
|
47
|
+
if (!isTransient || attempt === maxRetries) {
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
// Exponential backoff
|
|
51
|
+
await new Promise(resolve => setTimeout(resolve, delayMs * Math.pow(2, attempt - 1)));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
throw lastError;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Format error for UI display
|
|
58
|
+
*/
|
|
59
|
+
static formatError(error) {
|
|
60
|
+
if (error instanceof AppError) {
|
|
61
|
+
let msg = `[${error.code}] ${error.message}`;
|
|
62
|
+
if (error.recoverySteps.length > 0) {
|
|
63
|
+
msg += '\n\nRecovery Options:\n' + error.recoverySteps.map(s => `- ${s}`).join('\n');
|
|
64
|
+
}
|
|
65
|
+
return msg;
|
|
66
|
+
}
|
|
67
|
+
if (error instanceof Error) {
|
|
68
|
+
return error.message;
|
|
69
|
+
}
|
|
70
|
+
return String(error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.ErrorHandler = ErrorHandler;
|
|
74
|
+
/**
|
|
75
|
+
* Decorator/Wrapper for use cases to handle uncaught exceptions gracefully
|
|
76
|
+
*/
|
|
77
|
+
function withErrorGuard(fn) {
|
|
78
|
+
return (...args) => {
|
|
79
|
+
try {
|
|
80
|
+
return fn(...args);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error(ErrorHandler.formatError(error)); // For CLI/Logs
|
|
84
|
+
throw error; // Re-throw to be handled by UI layer
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=ErrorHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorHandler.js","sourceRoot":"","sources":["../../../src/application/errors/ErrorHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface UIState {
|
|
2
|
+
selectedProjectId: string | null;
|
|
3
|
+
sortOrder: 'name' | 'created_at' | 'last_opened';
|
|
4
|
+
sortDirection: 'ASC' | 'DESC';
|
|
5
|
+
filters: {
|
|
6
|
+
name?: string;
|
|
7
|
+
is_favorite?: boolean;
|
|
8
|
+
tags?: string[];
|
|
9
|
+
technologies?: string[];
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export type StateListener = (state: UIState) => void;
|
|
13
|
+
export declare class StateManager {
|
|
14
|
+
private state;
|
|
15
|
+
private listeners;
|
|
16
|
+
private stateFilePath;
|
|
17
|
+
constructor();
|
|
18
|
+
getState(): UIState;
|
|
19
|
+
updateState(partialState: Partial<UIState>): void;
|
|
20
|
+
resetState(): void;
|
|
21
|
+
subscribe(listener: StateListener): () => void;
|
|
22
|
+
private notifyListeners;
|
|
23
|
+
private loadState;
|
|
24
|
+
private saveState;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=StateManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StateManager.d.ts","sourceRoot":"","sources":["../../../src/application/state/StateManager.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,OAAO;IACtB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,aAAa,CAAC;IACjD,aAAa,EAAE,KAAK,GAAG,MAAM,CAAC;IAC9B,OAAO,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC;CACH;AASD,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;AAErD,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAU;IACvB,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,aAAa,CAAS;;IASvB,QAAQ,IAAI,OAAO;IAInB,WAAW,CAAC,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI;IAcjD,UAAU,IAAI,IAAI;IAMlB,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,IAAI;IAQrD,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,SAAS;IAajB,OAAO,CAAC,SAAS;CAWlB"}
|