@geanatz/cortex-mcp 5.0.1
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/LICENSE +21 -0
- package/README.md +281 -0
- package/dist/errors/errors.d.ts +109 -0
- package/dist/errors/errors.js +199 -0
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.js +4 -0
- package/dist/features/task-management/models/artifact.d.ts +169 -0
- package/dist/features/task-management/models/artifact.js +155 -0
- package/dist/features/task-management/models/config.d.ts +54 -0
- package/dist/features/task-management/models/config.js +54 -0
- package/dist/features/task-management/models/index.d.ts +6 -0
- package/dist/features/task-management/models/index.js +6 -0
- package/dist/features/task-management/models/task.d.ts +173 -0
- package/dist/features/task-management/models/task.js +84 -0
- package/dist/features/task-management/storage/file-storage.d.ts +130 -0
- package/dist/features/task-management/storage/file-storage.js +575 -0
- package/dist/features/task-management/storage/index.d.ts +5 -0
- package/dist/features/task-management/storage/index.js +5 -0
- package/dist/features/task-management/storage/storage.d.ts +159 -0
- package/dist/features/task-management/storage/storage.js +37 -0
- package/dist/features/task-management/tools/artifacts/index.d.ts +6 -0
- package/dist/features/task-management/tools/artifacts/index.js +174 -0
- package/dist/features/task-management/tools/base/handlers.d.ts +7 -0
- package/dist/features/task-management/tools/base/handlers.js +15 -0
- package/dist/features/task-management/tools/base/index.d.ts +3 -0
- package/dist/features/task-management/tools/base/index.js +3 -0
- package/dist/features/task-management/tools/base/schemas.d.ts +3 -0
- package/dist/features/task-management/tools/base/schemas.js +6 -0
- package/dist/features/task-management/tools/base/types.d.ts +13 -0
- package/dist/features/task-management/tools/base/types.js +1 -0
- package/dist/features/task-management/tools/tasks/index.d.ts +10 -0
- package/dist/features/task-management/tools/tasks/index.js +500 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +57 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.js +61 -0
- package/dist/types/common.d.ts +10 -0
- package/dist/types/common.js +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +5 -0
- package/dist/utils/cache.d.ts +104 -0
- package/dist/utils/cache.js +196 -0
- package/dist/utils/file-utils.d.ts +101 -0
- package/dist/utils/file-utils.js +270 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.js +12 -0
- package/dist/utils/logger.d.ts +77 -0
- package/dist/utils/logger.js +173 -0
- package/dist/utils/response-builder.d.ts +4 -0
- package/dist/utils/response-builder.js +19 -0
- package/dist/utils/storage-config.d.ts +29 -0
- package/dist/utils/storage-config.js +51 -0
- package/dist/utils/string-utils.d.ts +2 -0
- package/dist/utils/string-utils.js +16 -0
- package/dist/utils/validation.d.ts +9 -0
- package/dist/utils/validation.js +9 -0
- package/dist/utils/version.d.ts +9 -0
- package/dist/utils/version.js +41 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Geanatz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Cortex MCP - Task-Based Orchestration for AI Workflows
|
|
2
|
+
|
|
3
|
+
An MCP (Model Context Protocol) server for managing task-based workflows with artifact support across five orchestration phases: Explore, Search, Plan, Build, and Test.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Simplified Task Management** - Parent tasks with inline subtasks, no separate folders
|
|
8
|
+
- **Phase-Aware Artifacts** - Store and manage artifacts for each orchestration phase (explore, search, plan, build, test)
|
|
9
|
+
- **File-Based Storage** - All data stored in `.cortex/` directory with no database required
|
|
10
|
+
- **In-Memory Caching** - High-performance caching layer with TTL for frequently accessed tasks
|
|
11
|
+
- **Structured Logging** - Comprehensive logging with configurable levels
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
### Using npx (Recommended)
|
|
16
|
+
|
|
17
|
+
Run the latest version without installing:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx -y @geanatz/cortex-mcp@latest
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Global Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install -g @geanatz/cortex-mcp
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Local Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install @geanatz/cortex-mcp
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
### Starting the Server
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Project-specific mode (stores in .cortex/ )
|
|
41
|
+
cortex-mcp
|
|
42
|
+
|
|
43
|
+
# Global mode (stores in ~/.cortex/)
|
|
44
|
+
cortex-mcp --claude
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### MCP Configuration
|
|
48
|
+
|
|
49
|
+
Add to your MCP settings (e.g., Claude Desktop, Cursor, etc.):
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"cortex": {
|
|
54
|
+
"type": "local",
|
|
55
|
+
"enabled": true,
|
|
56
|
+
"command": [
|
|
57
|
+
"npx",
|
|
58
|
+
"-y",
|
|
59
|
+
"@geanatz/cortex-mcp@latest"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Or for global mode:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"cortex": {
|
|
70
|
+
"type": "local",
|
|
71
|
+
"enabled": true,
|
|
72
|
+
"command": [
|
|
73
|
+
"npx",
|
|
74
|
+
"-y",
|
|
75
|
+
"@geanatz/cortex-mcp@latest",
|
|
76
|
+
"--claude"
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Creating Tasks
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
Tool: create_task
|
|
86
|
+
Parameters:
|
|
87
|
+
- workingDirectory: path where tasks are stored
|
|
88
|
+
- details: task description (generates task ID)
|
|
89
|
+
- status (optional): pending | in_progress | done
|
|
90
|
+
- tags (optional): categorization tags
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Managing Subtasks
|
|
94
|
+
|
|
95
|
+
Subtasks are created using `update_task` with the `addSubtask` parameter:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
Tool: update_task
|
|
99
|
+
Parameters:
|
|
100
|
+
- id: parent task ID
|
|
101
|
+
- addSubtask: { details: "Subtask description", status: "pending" }
|
|
102
|
+
- updateSubtask: { id: "1", status: "done" }
|
|
103
|
+
- removeSubtaskId: "1"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Managing Artifacts
|
|
107
|
+
|
|
108
|
+
Each task can have artifacts for 5 phases:
|
|
109
|
+
- **explore**: Codebase analysis and discovery findings
|
|
110
|
+
- **search**: External research and documentation findings
|
|
111
|
+
- **plan**: Implementation approach and step-by-step plan
|
|
112
|
+
- **build**: Implementation changes and modifications made
|
|
113
|
+
- **test**: Test execution results and verification status
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
Tools: create_{phase}, update_{phase}, delete_{phase}
|
|
117
|
+
Parameters:
|
|
118
|
+
- workingDirectory: project directory
|
|
119
|
+
- taskId: which task to attach artifact to
|
|
120
|
+
- content: markdown content
|
|
121
|
+
- status: pending | in-progress | completed | failed | skipped
|
|
122
|
+
- retries, error: optional metadata
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Storage Format
|
|
126
|
+
|
|
127
|
+
Tasks are stored in `.cortex/tasks/{number}-{slug}/` directories:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
.cortex/
|
|
131
|
+
└── tasks/
|
|
132
|
+
├── 001-implement-auth/
|
|
133
|
+
│ ├── .task.json (parent task + subtasks array)
|
|
134
|
+
│ ├── explore.md (explore phase artifact)
|
|
135
|
+
│ ├── search.md (search phase artifact)
|
|
136
|
+
│ ├── plan.md (plan phase artifact)
|
|
137
|
+
│ ├── build.md (build phase artifact)
|
|
138
|
+
│ └── test.md (test phase artifact)
|
|
139
|
+
└── 002-setup-database/
|
|
140
|
+
├── .task.json
|
|
141
|
+
└── ... (optional artifacts)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Task JSON Structure
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"id": "001-implement-auth",
|
|
149
|
+
"details": "Implement authentication system",
|
|
150
|
+
"status": "in_progress",
|
|
151
|
+
"tags": ["auth", "backend"],
|
|
152
|
+
"createdAt": "2024-01-01T00:00:00Z",
|
|
153
|
+
"updatedAt": "2024-01-01T00:00:00Z",
|
|
154
|
+
"actualHours": 2.5,
|
|
155
|
+
"subtasks": [
|
|
156
|
+
{ "id": "1", "details": "Setup JWT library", "status": "done" },
|
|
157
|
+
{ "id": "2", "details": "Create login endpoint", "status": "in_progress" },
|
|
158
|
+
{ "id": "3", "details": "Add middleware", "status": "pending" }
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Data Model
|
|
164
|
+
|
|
165
|
+
### Task (Parent)
|
|
166
|
+
```typescript
|
|
167
|
+
interface Task {
|
|
168
|
+
id: string; // Task ID (e.g., "001-implement-auth")
|
|
169
|
+
details: string; // Full task description
|
|
170
|
+
status: 'pending' | 'in_progress' | 'done';
|
|
171
|
+
createdAt: string; // ISO 8601 timestamp
|
|
172
|
+
updatedAt: string; // Last modification timestamp
|
|
173
|
+
tags?: string[]; // Categorization tags
|
|
174
|
+
actualHours?: number; // Time tracking
|
|
175
|
+
subtasks: Subtask[]; // Array of subtasks
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Subtask
|
|
180
|
+
```typescript
|
|
181
|
+
interface Subtask {
|
|
182
|
+
id: string; // Simple ID ("1", "2", etc.)
|
|
183
|
+
details: string; // Subtask description
|
|
184
|
+
status: 'pending' | 'in_progress' | 'done';
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Artifact
|
|
189
|
+
```typescript
|
|
190
|
+
interface Artifact {
|
|
191
|
+
metadata: {
|
|
192
|
+
phase: 'explore' | 'search' | 'plan' | 'build' | 'test';
|
|
193
|
+
status: 'pending' | 'in-progress' | 'completed' | 'failed' | 'skipped';
|
|
194
|
+
createdAt: string; // ISO 8601
|
|
195
|
+
updatedAt: string; // ISO 8601
|
|
196
|
+
retries?: number; // Attempt count
|
|
197
|
+
error?: string; // Error message if status=failed
|
|
198
|
+
}
|
|
199
|
+
content: string; // Markdown content
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Available Tools
|
|
204
|
+
|
|
205
|
+
### Task Management
|
|
206
|
+
- `create_task` - Create a new parent task
|
|
207
|
+
- `list_tasks` - List all tasks with subtasks
|
|
208
|
+
- `get_task` - Get task details including subtasks and artifacts
|
|
209
|
+
- `update_task` - Update task and manage subtasks
|
|
210
|
+
- `delete_task` - Delete task and all its subtasks
|
|
211
|
+
|
|
212
|
+
### Artifact Management
|
|
213
|
+
- `create_explore` - Create explore phase artifact
|
|
214
|
+
- `update_explore` - Update explore phase artifact
|
|
215
|
+
- `delete_explore` - Delete explore phase artifact
|
|
216
|
+
- `create_search` - Create search phase artifact
|
|
217
|
+
- `update_search` - Update search phase artifact
|
|
218
|
+
- `delete_search` - Delete search phase artifact
|
|
219
|
+
- `create_plan` - Create plan phase artifact
|
|
220
|
+
- `update_plan` - Update plan phase artifact
|
|
221
|
+
- `delete_plan` - Delete plan phase artifact
|
|
222
|
+
- `create_build` - Create build phase artifact
|
|
223
|
+
- `update_build` - Update build phase artifact
|
|
224
|
+
- `delete_build` - Delete build phase artifact
|
|
225
|
+
- `create_test` - Create test phase artifact
|
|
226
|
+
- `update_test` - Update test phase artifact
|
|
227
|
+
- `delete_test` - Delete test phase artifact
|
|
228
|
+
|
|
229
|
+
## Configuration
|
|
230
|
+
|
|
231
|
+
### Environment Variables
|
|
232
|
+
- `DEBUG=true` - Enable debug logging
|
|
233
|
+
|
|
234
|
+
### Command-Line Flags
|
|
235
|
+
- `--claude` - Use global directory mode (~/.cortex/)
|
|
236
|
+
|
|
237
|
+
## Development
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
# Build TypeScript
|
|
241
|
+
npm run build
|
|
242
|
+
|
|
243
|
+
# Watch mode
|
|
244
|
+
npm run dev
|
|
245
|
+
|
|
246
|
+
# Start server
|
|
247
|
+
npm start
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Build Optimization
|
|
251
|
+
- Uses TypeScript with incremental builds
|
|
252
|
+
- Optimized for <5s build times with ~800MB memory usage
|
|
253
|
+
- Proper closure elimination for fast type inference
|
|
254
|
+
|
|
255
|
+
## Architecture
|
|
256
|
+
|
|
257
|
+
- **Clean layering** - Types → Utilities → Storage → Tools → Server
|
|
258
|
+
- **No circular dependencies** - Easy to understand data flow
|
|
259
|
+
- **Abstract storage** - File-based implementation, easily extensible
|
|
260
|
+
- **MCP-compliant** - Full compliance with Model Context Protocol specification
|
|
261
|
+
|
|
262
|
+
## Version
|
|
263
|
+
|
|
264
|
+
Current version: **5.0.0**
|
|
265
|
+
|
|
266
|
+
- v5.0.0: Simplified model - subtasks stored inline, removed dependencies, removed move_task
|
|
267
|
+
- v4.0.0: Complete refactor with artifact support and optimized build
|
|
268
|
+
- v3.x: Legacy memory features (deprecated)
|
|
269
|
+
- v1.x: Initial implementation
|
|
270
|
+
|
|
271
|
+
## License
|
|
272
|
+
|
|
273
|
+
MIT - See LICENSE file for details
|
|
274
|
+
|
|
275
|
+
## Author
|
|
276
|
+
|
|
277
|
+
Geanatz
|
|
278
|
+
|
|
279
|
+
## Contributing
|
|
280
|
+
|
|
281
|
+
Contributions welcome!
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for the application
|
|
3
|
+
* Provides typed, hierarchical error handling
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Base application error class
|
|
7
|
+
* All custom errors should extend this
|
|
8
|
+
*/
|
|
9
|
+
export declare abstract class AppError extends Error {
|
|
10
|
+
readonly code: string;
|
|
11
|
+
readonly timestamp: Date;
|
|
12
|
+
readonly context?: Record<string, unknown>;
|
|
13
|
+
constructor(message: string, code: string, context?: Record<string, unknown>);
|
|
14
|
+
/**
|
|
15
|
+
* Convert error to JSON-serializable object
|
|
16
|
+
*/
|
|
17
|
+
toJSON(): Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Error codes enum for type-safe error handling
|
|
21
|
+
*/
|
|
22
|
+
export declare const ErrorCodes: {
|
|
23
|
+
readonly VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
24
|
+
readonly INVALID_INPUT: "INVALID_INPUT";
|
|
25
|
+
readonly REQUIRED_FIELD_MISSING: "REQUIRED_FIELD_MISSING";
|
|
26
|
+
readonly INVALID_FORMAT: "INVALID_FORMAT";
|
|
27
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
28
|
+
readonly TASK_NOT_FOUND: "TASK_NOT_FOUND";
|
|
29
|
+
readonly ARTIFACT_NOT_FOUND: "ARTIFACT_NOT_FOUND";
|
|
30
|
+
readonly PARENT_NOT_FOUND: "PARENT_NOT_FOUND";
|
|
31
|
+
readonly DEPENDENCY_NOT_FOUND: "DEPENDENCY_NOT_FOUND";
|
|
32
|
+
readonly ALREADY_EXISTS: "ALREADY_EXISTS";
|
|
33
|
+
readonly CIRCULAR_REFERENCE: "CIRCULAR_REFERENCE";
|
|
34
|
+
readonly SELF_REFERENCE: "SELF_REFERENCE";
|
|
35
|
+
readonly STORAGE_ERROR: "STORAGE_ERROR";
|
|
36
|
+
readonly FILE_READ_ERROR: "FILE_READ_ERROR";
|
|
37
|
+
readonly FILE_WRITE_ERROR: "FILE_WRITE_ERROR";
|
|
38
|
+
readonly DIRECTORY_ERROR: "DIRECTORY_ERROR";
|
|
39
|
+
readonly PARSE_ERROR: "PARSE_ERROR";
|
|
40
|
+
readonly INITIALIZATION_ERROR: "INITIALIZATION_ERROR";
|
|
41
|
+
readonly CONFIGURATION_ERROR: "CONFIGURATION_ERROR";
|
|
42
|
+
readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
|
|
43
|
+
};
|
|
44
|
+
export type ErrorCode = typeof ErrorCodes[keyof typeof ErrorCodes];
|
|
45
|
+
/**
|
|
46
|
+
* Validation error for input validation failures
|
|
47
|
+
*/
|
|
48
|
+
export declare class ValidationError extends AppError {
|
|
49
|
+
readonly field?: string;
|
|
50
|
+
readonly value?: unknown;
|
|
51
|
+
constructor(message: string, field?: string, value?: unknown, context?: Record<string, unknown>);
|
|
52
|
+
static requiredField(field: string): ValidationError;
|
|
53
|
+
static invalidFormat(field: string, expected: string, received?: unknown): ValidationError;
|
|
54
|
+
static maxLength(field: string, max: number, actual: number): ValidationError;
|
|
55
|
+
static minLength(field: string, min: number, actual: number): ValidationError;
|
|
56
|
+
static emptyString(field: string): ValidationError;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Not found error for missing resources
|
|
60
|
+
*/
|
|
61
|
+
export declare class NotFoundError extends AppError {
|
|
62
|
+
readonly resourceType: string;
|
|
63
|
+
readonly resourceId: string;
|
|
64
|
+
constructor(resourceType: string, resourceId: string, context?: Record<string, unknown>);
|
|
65
|
+
static task(taskId: string): NotFoundError;
|
|
66
|
+
static artifact(taskId: string, phase: string): NotFoundError;
|
|
67
|
+
static parent(parentId: string): NotFoundError;
|
|
68
|
+
static dependency(depId: string): NotFoundError;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Conflict error for operations that would create invalid states
|
|
72
|
+
*/
|
|
73
|
+
export declare class ConflictError extends AppError {
|
|
74
|
+
constructor(message: string, code?: ErrorCode, context?: Record<string, unknown>);
|
|
75
|
+
static circularReference(taskId: string, targetId: string): ConflictError;
|
|
76
|
+
static selfReference(taskId: string, operation: string): ConflictError;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Storage error for file system operations
|
|
80
|
+
*/
|
|
81
|
+
export declare class StorageError extends AppError {
|
|
82
|
+
readonly path?: string;
|
|
83
|
+
readonly operation?: string;
|
|
84
|
+
constructor(message: string, code?: ErrorCode, path?: string, operation?: string, context?: Record<string, unknown>);
|
|
85
|
+
static readError(path: string, originalError?: Error): StorageError;
|
|
86
|
+
static writeError(path: string, originalError?: Error): StorageError;
|
|
87
|
+
static directoryError(path: string, originalError?: Error): StorageError;
|
|
88
|
+
static parseError(path: string, format: string, originalError?: Error): StorageError;
|
|
89
|
+
static initializationError(path: string, message: string): StorageError;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Type guard to check if an error is an AppError
|
|
93
|
+
*/
|
|
94
|
+
export declare function isAppError(error: unknown): error is AppError;
|
|
95
|
+
/**
|
|
96
|
+
* Type guard for specific error types
|
|
97
|
+
*/
|
|
98
|
+
export declare function isValidationError(error: unknown): error is ValidationError;
|
|
99
|
+
export declare function isNotFoundError(error: unknown): error is NotFoundError;
|
|
100
|
+
export declare function isConflictError(error: unknown): error is ConflictError;
|
|
101
|
+
export declare function isStorageError(error: unknown): error is StorageError;
|
|
102
|
+
/**
|
|
103
|
+
* Extract error message from unknown error
|
|
104
|
+
*/
|
|
105
|
+
export declare function getErrorMessage(error: unknown): string;
|
|
106
|
+
/**
|
|
107
|
+
* Wrap unknown errors in AppError
|
|
108
|
+
*/
|
|
109
|
+
export declare function wrapError(error: unknown, fallbackMessage?: string): AppError;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for the application
|
|
3
|
+
* Provides typed, hierarchical error handling
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Base application error class
|
|
7
|
+
* All custom errors should extend this
|
|
8
|
+
*/
|
|
9
|
+
export class AppError extends Error {
|
|
10
|
+
code;
|
|
11
|
+
timestamp;
|
|
12
|
+
context;
|
|
13
|
+
constructor(message, code, context) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = this.constructor.name;
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.timestamp = new Date();
|
|
18
|
+
this.context = context;
|
|
19
|
+
// Maintains proper stack trace for where error was thrown
|
|
20
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Convert error to JSON-serializable object
|
|
24
|
+
*/
|
|
25
|
+
toJSON() {
|
|
26
|
+
return {
|
|
27
|
+
name: this.name,
|
|
28
|
+
message: this.message,
|
|
29
|
+
code: this.code,
|
|
30
|
+
timestamp: this.timestamp.toISOString(),
|
|
31
|
+
context: this.context,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Error codes enum for type-safe error handling
|
|
37
|
+
*/
|
|
38
|
+
export const ErrorCodes = {
|
|
39
|
+
// Validation errors (4xx equivalent)
|
|
40
|
+
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
41
|
+
INVALID_INPUT: 'INVALID_INPUT',
|
|
42
|
+
REQUIRED_FIELD_MISSING: 'REQUIRED_FIELD_MISSING',
|
|
43
|
+
INVALID_FORMAT: 'INVALID_FORMAT',
|
|
44
|
+
// Resource errors
|
|
45
|
+
NOT_FOUND: 'NOT_FOUND',
|
|
46
|
+
TASK_NOT_FOUND: 'TASK_NOT_FOUND',
|
|
47
|
+
ARTIFACT_NOT_FOUND: 'ARTIFACT_NOT_FOUND',
|
|
48
|
+
PARENT_NOT_FOUND: 'PARENT_NOT_FOUND',
|
|
49
|
+
DEPENDENCY_NOT_FOUND: 'DEPENDENCY_NOT_FOUND',
|
|
50
|
+
// Conflict errors
|
|
51
|
+
ALREADY_EXISTS: 'ALREADY_EXISTS',
|
|
52
|
+
CIRCULAR_REFERENCE: 'CIRCULAR_REFERENCE',
|
|
53
|
+
SELF_REFERENCE: 'SELF_REFERENCE',
|
|
54
|
+
// Storage errors
|
|
55
|
+
STORAGE_ERROR: 'STORAGE_ERROR',
|
|
56
|
+
FILE_READ_ERROR: 'FILE_READ_ERROR',
|
|
57
|
+
FILE_WRITE_ERROR: 'FILE_WRITE_ERROR',
|
|
58
|
+
DIRECTORY_ERROR: 'DIRECTORY_ERROR',
|
|
59
|
+
PARSE_ERROR: 'PARSE_ERROR',
|
|
60
|
+
// System errors
|
|
61
|
+
INITIALIZATION_ERROR: 'INITIALIZATION_ERROR',
|
|
62
|
+
CONFIGURATION_ERROR: 'CONFIGURATION_ERROR',
|
|
63
|
+
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Validation error for input validation failures
|
|
67
|
+
*/
|
|
68
|
+
export class ValidationError extends AppError {
|
|
69
|
+
field;
|
|
70
|
+
value;
|
|
71
|
+
constructor(message, field, value, context) {
|
|
72
|
+
super(message, ErrorCodes.VALIDATION_ERROR, { ...context, field, value });
|
|
73
|
+
this.field = field;
|
|
74
|
+
this.value = value;
|
|
75
|
+
}
|
|
76
|
+
static requiredField(field) {
|
|
77
|
+
return new ValidationError(`${field} is required.`, field, undefined, { code: ErrorCodes.REQUIRED_FIELD_MISSING });
|
|
78
|
+
}
|
|
79
|
+
static invalidFormat(field, expected, received) {
|
|
80
|
+
return new ValidationError(`Invalid format for ${field}. Expected ${expected}.`, field, received, { code: ErrorCodes.INVALID_FORMAT, expected });
|
|
81
|
+
}
|
|
82
|
+
static maxLength(field, max, actual) {
|
|
83
|
+
return new ValidationError(`${field} must be ${max} characters or less (got ${actual}).`, field, undefined, { code: ErrorCodes.INVALID_INPUT, max, actual });
|
|
84
|
+
}
|
|
85
|
+
static minLength(field, min, actual) {
|
|
86
|
+
return new ValidationError(`${field} must be at least ${min} characters (got ${actual}).`, field, undefined, { code: ErrorCodes.INVALID_INPUT, min, actual });
|
|
87
|
+
}
|
|
88
|
+
static emptyString(field) {
|
|
89
|
+
return new ValidationError(`${field} must not be empty.`, field, '', { code: ErrorCodes.INVALID_INPUT });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Not found error for missing resources
|
|
94
|
+
*/
|
|
95
|
+
export class NotFoundError extends AppError {
|
|
96
|
+
resourceType;
|
|
97
|
+
resourceId;
|
|
98
|
+
constructor(resourceType, resourceId, context) {
|
|
99
|
+
super(`${resourceType} with ID "${resourceId}" not found.`, ErrorCodes.NOT_FOUND, { ...context, resourceType, resourceId });
|
|
100
|
+
this.resourceType = resourceType;
|
|
101
|
+
this.resourceId = resourceId;
|
|
102
|
+
}
|
|
103
|
+
static task(taskId) {
|
|
104
|
+
return new NotFoundError('Task', taskId, { code: ErrorCodes.TASK_NOT_FOUND });
|
|
105
|
+
}
|
|
106
|
+
static artifact(taskId, phase) {
|
|
107
|
+
return new NotFoundError(`${phase} artifact`, taskId, { code: ErrorCodes.ARTIFACT_NOT_FOUND, phase });
|
|
108
|
+
}
|
|
109
|
+
static parent(parentId) {
|
|
110
|
+
return new NotFoundError('Parent task', parentId, { code: ErrorCodes.PARENT_NOT_FOUND });
|
|
111
|
+
}
|
|
112
|
+
static dependency(depId) {
|
|
113
|
+
return new NotFoundError('Dependency task', depId, { code: ErrorCodes.DEPENDENCY_NOT_FOUND });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Conflict error for operations that would create invalid states
|
|
118
|
+
*/
|
|
119
|
+
export class ConflictError extends AppError {
|
|
120
|
+
constructor(message, code = ErrorCodes.CIRCULAR_REFERENCE, context) {
|
|
121
|
+
super(message, code, context);
|
|
122
|
+
}
|
|
123
|
+
static circularReference(taskId, targetId) {
|
|
124
|
+
return new ConflictError(`Moving task would create a circular reference.`, ErrorCodes.CIRCULAR_REFERENCE, { taskId, targetId });
|
|
125
|
+
}
|
|
126
|
+
static selfReference(taskId, operation) {
|
|
127
|
+
return new ConflictError(`Task cannot ${operation} itself.`, ErrorCodes.SELF_REFERENCE, { taskId, operation });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Storage error for file system operations
|
|
132
|
+
*/
|
|
133
|
+
export class StorageError extends AppError {
|
|
134
|
+
path;
|
|
135
|
+
operation;
|
|
136
|
+
constructor(message, code = ErrorCodes.STORAGE_ERROR, path, operation, context) {
|
|
137
|
+
super(message, code, { ...context, path, operation });
|
|
138
|
+
this.path = path;
|
|
139
|
+
this.operation = operation;
|
|
140
|
+
}
|
|
141
|
+
static readError(path, originalError) {
|
|
142
|
+
return new StorageError(`Failed to read file: ${path}`, ErrorCodes.FILE_READ_ERROR, path, 'read', { originalError: originalError?.message });
|
|
143
|
+
}
|
|
144
|
+
static writeError(path, originalError) {
|
|
145
|
+
return new StorageError(`Failed to write file: ${path}`, ErrorCodes.FILE_WRITE_ERROR, path, 'write', { originalError: originalError?.message });
|
|
146
|
+
}
|
|
147
|
+
static directoryError(path, originalError) {
|
|
148
|
+
return new StorageError(`Directory operation failed: ${path}`, ErrorCodes.DIRECTORY_ERROR, path, 'directory', { originalError: originalError?.message });
|
|
149
|
+
}
|
|
150
|
+
static parseError(path, format, originalError) {
|
|
151
|
+
return new StorageError(`Failed to parse ${format} file: ${path}`, ErrorCodes.PARSE_ERROR, path, 'parse', { format, originalError: originalError?.message });
|
|
152
|
+
}
|
|
153
|
+
static initializationError(path, message) {
|
|
154
|
+
return new StorageError(message, ErrorCodes.INITIALIZATION_ERROR, path, 'initialize');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Type guard to check if an error is an AppError
|
|
159
|
+
*/
|
|
160
|
+
export function isAppError(error) {
|
|
161
|
+
return error instanceof AppError;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Type guard for specific error types
|
|
165
|
+
*/
|
|
166
|
+
export function isValidationError(error) {
|
|
167
|
+
return error instanceof ValidationError;
|
|
168
|
+
}
|
|
169
|
+
export function isNotFoundError(error) {
|
|
170
|
+
return error instanceof NotFoundError;
|
|
171
|
+
}
|
|
172
|
+
export function isConflictError(error) {
|
|
173
|
+
return error instanceof ConflictError;
|
|
174
|
+
}
|
|
175
|
+
export function isStorageError(error) {
|
|
176
|
+
return error instanceof StorageError;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Extract error message from unknown error
|
|
180
|
+
*/
|
|
181
|
+
export function getErrorMessage(error) {
|
|
182
|
+
if (error instanceof Error) {
|
|
183
|
+
return error.message;
|
|
184
|
+
}
|
|
185
|
+
if (typeof error === 'string') {
|
|
186
|
+
return error;
|
|
187
|
+
}
|
|
188
|
+
return 'An unknown error occurred';
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Wrap unknown errors in AppError
|
|
192
|
+
*/
|
|
193
|
+
export function wrapError(error, fallbackMessage) {
|
|
194
|
+
if (isAppError(error)) {
|
|
195
|
+
return error;
|
|
196
|
+
}
|
|
197
|
+
const message = getErrorMessage(error) || fallbackMessage || 'Unknown error';
|
|
198
|
+
return new StorageError(message, ErrorCodes.UNKNOWN_ERROR);
|
|
199
|
+
}
|