mcp-taskflow 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/CHANGELOG.md +13 -0
- package/LICENSE.md +21 -0
- package/README.md +275 -0
- package/dist/config/pathResolver.d.ts +33 -0
- package/dist/config/pathResolver.d.ts.map +1 -0
- package/dist/config/pathResolver.js +130 -0
- package/dist/config/pathResolver.js.map +1 -0
- package/dist/data/fileOperations.d.ts +43 -0
- package/dist/data/fileOperations.d.ts.map +1 -0
- package/dist/data/fileOperations.js +248 -0
- package/dist/data/fileOperations.js.map +1 -0
- package/dist/data/memoryStore.d.ts +86 -0
- package/dist/data/memoryStore.d.ts.map +1 -0
- package/dist/data/memoryStore.js +216 -0
- package/dist/data/memoryStore.js.map +1 -0
- package/dist/data/rulesStore.d.ts +63 -0
- package/dist/data/rulesStore.d.ts.map +1 -0
- package/dist/data/rulesStore.js +196 -0
- package/dist/data/rulesStore.js.map +1 -0
- package/dist/data/schemas.d.ts +840 -0
- package/dist/data/schemas.d.ts.map +1 -0
- package/dist/data/schemas.js +265 -0
- package/dist/data/schemas.js.map +1 -0
- package/dist/data/taskSearchService.d.ts +110 -0
- package/dist/data/taskSearchService.d.ts.map +1 -0
- package/dist/data/taskSearchService.js +165 -0
- package/dist/data/taskSearchService.js.map +1 -0
- package/dist/data/taskStore.d.ts +192 -0
- package/dist/data/taskStore.d.ts.map +1 -0
- package/dist/data/taskStore.js +347 -0
- package/dist/data/taskStore.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/index.d.ts +12 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +17 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/projectPromptBuilder.d.ts +13 -0
- package/dist/prompts/projectPromptBuilder.d.ts.map +1 -0
- package/dist/prompts/projectPromptBuilder.js +29 -0
- package/dist/prompts/projectPromptBuilder.js.map +1 -0
- package/dist/prompts/researchPromptBuilder.d.ts +10 -0
- package/dist/prompts/researchPromptBuilder.d.ts.map +1 -0
- package/dist/prompts/researchPromptBuilder.js +20 -0
- package/dist/prompts/researchPromptBuilder.js.map +1 -0
- package/dist/prompts/taskPromptBuilders.d.ts +87 -0
- package/dist/prompts/taskPromptBuilders.d.ts.map +1 -0
- package/dist/prompts/taskPromptBuilders.js +529 -0
- package/dist/prompts/taskPromptBuilders.js.map +1 -0
- package/dist/prompts/templateEngine.d.ts +102 -0
- package/dist/prompts/templateEngine.d.ts.map +1 -0
- package/dist/prompts/templateEngine.js +145 -0
- package/dist/prompts/templateEngine.js.map +1 -0
- package/dist/prompts/templateLoader.d.ts +61 -0
- package/dist/prompts/templateLoader.d.ts.map +1 -0
- package/dist/prompts/templateLoader.js +129 -0
- package/dist/prompts/templateLoader.js.map +1 -0
- package/dist/prompts/templates/v1/templates_en/analyzeTask/index.md +65 -0
- package/dist/prompts/templates/v1/templates_en/analyzeTask/iteration.md +12 -0
- package/dist/prompts/templates/v1/templates_en/clearAllTasks/backupInfo.md +1 -0
- package/dist/prompts/templates/v1/templates_en/clearAllTasks/cancel.md +7 -0
- package/dist/prompts/templates/v1/templates_en/clearAllTasks/empty.md +5 -0
- package/dist/prompts/templates/v1/templates_en/clearAllTasks/index.md +5 -0
- package/dist/prompts/templates/v1/templates_en/clearAllTasks/result.md +7 -0
- package/dist/prompts/templates/v1/templates_en/clearAllTasks/success.md +5 -0
- package/dist/prompts/templates/v1/templates_en/deleteTask/completed.md +5 -0
- package/dist/prompts/templates/v1/templates_en/deleteTask/index.md +5 -0
- package/dist/prompts/templates/v1/templates_en/deleteTask/notFound.md +5 -0
- package/dist/prompts/templates/v1/templates_en/deleteTask/result.md +5 -0
- package/dist/prompts/templates/v1/templates_en/deleteTask/success.md +5 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/analysisResult.md +3 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/complexity.md +15 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/dependencies.md +3 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/dependencyTasks.md +3 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/implementationGuide.md +3 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/index.md +39 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/notes.md +1 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/relatedFilesSummary.md +5 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/verificationCriteria.md +3 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/complatedSummary.md +5 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/dependencies.md +1 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/error.md +3 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/implementationGuide.md +3 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/index.md +25 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/notFound.md +3 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/notes.md +1 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/relatedFiles.md +3 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/verificationCriteria.md +3 -0
- package/dist/prompts/templates/v1/templates_en/initProjectRules/index.md +81 -0
- package/dist/prompts/templates/v1/templates_en/listTasks/index.md +7 -0
- package/dist/prompts/templates/v1/templates_en/listTasks/notFound.md +3 -0
- package/dist/prompts/templates/v1/templates_en/listTasks/taskDetails.md +13 -0
- package/dist/prompts/templates/v1/templates_en/planTask/hasThought.md +4 -0
- package/dist/prompts/templates/v1/templates_en/planTask/index.md +96 -0
- package/dist/prompts/templates/v1/templates_en/planTask/noThought.md +4 -0
- package/dist/prompts/templates/v1/templates_en/planTask/tasks.md +17 -0
- package/dist/prompts/templates/v1/templates_en/processThought/complatedThought.md +6 -0
- package/dist/prompts/templates/v1/templates_en/processThought/index.md +13 -0
- package/dist/prompts/templates/v1/templates_en/processThought/moreThought.md +1 -0
- package/dist/prompts/templates/v1/templates_en/queryTask/index.md +24 -0
- package/dist/prompts/templates/v1/templates_en/queryTask/notFound.md +15 -0
- package/dist/prompts/templates/v1/templates_en/queryTask/taskDetails.md +5 -0
- package/dist/prompts/templates/v1/templates_en/reflectTask/index.md +57 -0
- package/dist/prompts/templates/v1/templates_en/researchMode/index.md +95 -0
- package/dist/prompts/templates/v1/templates_en/researchMode/previousState.md +9 -0
- package/dist/prompts/templates/v1/templates_en/splitTasks/index.md +34 -0
- package/dist/prompts/templates/v1/templates_en/splitTasks/taskDetails.md +12 -0
- package/dist/prompts/templates/v1/templates_en/tests/basic.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/analyzeTask.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/clearAllTasks.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/deleteTask.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/executeTask.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/getTaskDetail.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/initProjectRules.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/listTasks.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/planTask.md +3 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/processThought.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/queryTask.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/reflectTask.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/researchMode.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/splitTasks.md +83 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/updateTask.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/verifyTask.md +37 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/emptyUpdate.md +5 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/fileDetails.md +1 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/index.md +7 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/notFound.md +5 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/success.md +9 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/successDetails.md +3 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/validation.md +5 -0
- package/dist/prompts/templates/v1/templates_en/verifyTask/index.md +19 -0
- package/dist/prompts/templates/v1/templates_en/verifyTask/noPass.md +12 -0
- package/dist/prompts/thoughtPromptBuilder.d.ts +11 -0
- package/dist/prompts/thoughtPromptBuilder.d.ts.map +1 -0
- package/dist/prompts/thoughtPromptBuilder.js +30 -0
- package/dist/prompts/thoughtPromptBuilder.js.map +1 -0
- package/dist/server/container.d.ts +111 -0
- package/dist/server/container.d.ts.map +1 -0
- package/dist/server/container.js +135 -0
- package/dist/server/container.js.map +1 -0
- package/dist/server/logger.d.ts +98 -0
- package/dist/server/logger.d.ts.map +1 -0
- package/dist/server/logger.js +295 -0
- package/dist/server/logger.js.map +1 -0
- package/dist/server/mcpServer.d.ts +162 -0
- package/dist/server/mcpServer.d.ts.map +1 -0
- package/dist/server/mcpServer.js +236 -0
- package/dist/server/mcpServer.js.map +1 -0
- package/dist/tools/project/index.d.ts +7 -0
- package/dist/tools/project/index.d.ts.map +1 -0
- package/dist/tools/project/index.js +7 -0
- package/dist/tools/project/index.js.map +1 -0
- package/dist/tools/project/projectTools.d.ts +17 -0
- package/dist/tools/project/projectTools.d.ts.map +1 -0
- package/dist/tools/project/projectTools.js +73 -0
- package/dist/tools/project/projectTools.js.map +1 -0
- package/dist/tools/research/index.d.ts +7 -0
- package/dist/tools/research/index.d.ts.map +1 -0
- package/dist/tools/research/index.js +7 -0
- package/dist/tools/research/index.js.map +1 -0
- package/dist/tools/research/researchTools.d.ts +16 -0
- package/dist/tools/research/researchTools.d.ts.map +1 -0
- package/dist/tools/research/researchTools.js +41 -0
- package/dist/tools/research/researchTools.js.map +1 -0
- package/dist/tools/task/index.d.ts +8 -0
- package/dist/tools/task/index.d.ts.map +1 -0
- package/dist/tools/task/index.js +8 -0
- package/dist/tools/task/index.js.map +1 -0
- package/dist/tools/task/taskTools.d.ts +32 -0
- package/dist/tools/task/taskTools.d.ts.map +1 -0
- package/dist/tools/task/taskTools.js +542 -0
- package/dist/tools/task/taskTools.js.map +1 -0
- package/dist/tools/thought/index.d.ts +7 -0
- package/dist/tools/thought/index.d.ts.map +1 -0
- package/dist/tools/thought/index.js +7 -0
- package/dist/tools/thought/index.js.map +1 -0
- package/dist/tools/thought/thoughtTools.d.ts +16 -0
- package/dist/tools/thought/thoughtTools.d.ts.map +1 -0
- package/dist/tools/thought/thoughtTools.js +47 -0
- package/dist/tools/thought/thoughtTools.js.map +1 -0
- package/docs/API.md +32 -0
- package/docs/ARCHITECTURE.md +44 -0
- package/docs/COMPATIBILITY_REPORT.md +26 -0
- package/docs/PERFORMANCE.md +66 -0
- package/package.json +77 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomic JSON File Operations
|
|
3
|
+
*
|
|
4
|
+
* Implements atomic write using temp file + fsync + rename.
|
|
5
|
+
*/
|
|
6
|
+
import fs from 'fs/promises';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { randomUUID } from 'crypto';
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { ensureDirectory } from '../config/pathResolver.js';
|
|
11
|
+
/**
|
|
12
|
+
* Maximum number of retry attempts for file operations.
|
|
13
|
+
*/
|
|
14
|
+
const MAX_RETRIES = 5;
|
|
15
|
+
/**
|
|
16
|
+
* Base delay in milliseconds for exponential backoff.
|
|
17
|
+
*/
|
|
18
|
+
const BASE_DELAY_MS = 100;
|
|
19
|
+
/**
|
|
20
|
+
* File operation errors with detailed context
|
|
21
|
+
*/
|
|
22
|
+
export class FileOperationError extends Error {
|
|
23
|
+
filePath;
|
|
24
|
+
operation;
|
|
25
|
+
originalError;
|
|
26
|
+
constructor(message, filePath, operation, originalError) {
|
|
27
|
+
super(message);
|
|
28
|
+
this.filePath = filePath;
|
|
29
|
+
this.operation = operation;
|
|
30
|
+
this.originalError = originalError;
|
|
31
|
+
this.name = 'FileOperationError';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Parse JSON string and wrap errors
|
|
36
|
+
*/
|
|
37
|
+
function parseJson(content, filePath) {
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(content);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
throw new FileOperationError(`Invalid JSON in file: ${filePath}`, filePath, 'read', error);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Validate data with Zod schema and wrap errors
|
|
47
|
+
*/
|
|
48
|
+
function validateWithSchema(data, schema, filePath) {
|
|
49
|
+
const result = schema.safeParse(data);
|
|
50
|
+
if (!result.success) {
|
|
51
|
+
throw new FileOperationError(`Schema validation failed for ${filePath}: ${result.error.message}`, filePath, 'read', result.error);
|
|
52
|
+
}
|
|
53
|
+
return result.data;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Check if error should not be retried
|
|
57
|
+
*/
|
|
58
|
+
function isNonRetryableError(error) {
|
|
59
|
+
return (error instanceof FileOperationError ||
|
|
60
|
+
(error instanceof Error && 'code' in error && error.code === 'ENOENT'));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Read and parse JSON file with Zod schema validation.
|
|
64
|
+
*/
|
|
65
|
+
export async function readJsonFile(filePath, schema) {
|
|
66
|
+
let lastError;
|
|
67
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
68
|
+
try {
|
|
69
|
+
// Read file content
|
|
70
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
71
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
72
|
+
// Parse and validate (these throw FileOperationError on failure)
|
|
73
|
+
const parsed = parseJson(content, filePath);
|
|
74
|
+
const validated = validateWithSchema(parsed, schema, filePath);
|
|
75
|
+
return validated;
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
lastError = error;
|
|
79
|
+
// Don't retry validation errors or ENOENT (file doesn't exist)
|
|
80
|
+
if (isNonRetryableError(error)) {
|
|
81
|
+
// If it's already a FileOperationError, throw it as-is
|
|
82
|
+
if (error instanceof FileOperationError) {
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
// Wrap ENOENT in FileOperationError
|
|
86
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
87
|
+
throw new FileOperationError(`File not found: ${filePath}`, filePath, 'read', error);
|
|
88
|
+
}
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
// Retry on transient errors (EAGAIN, EBUSY, etc.)
|
|
92
|
+
if (attempt < MAX_RETRIES - 1) {
|
|
93
|
+
const delay = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
94
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// All retries exhausted
|
|
100
|
+
throw new FileOperationError(`Failed to read file after ${MAX_RETRIES} attempts: ${filePath}`, filePath, 'read', lastError);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Write JSON file atomically using temp file + rename pattern.
|
|
104
|
+
*/
|
|
105
|
+
export async function writeJsonFile(filePath, data, schema) {
|
|
106
|
+
// Validate data before any file operations
|
|
107
|
+
const validationResult = schema.safeParse(data);
|
|
108
|
+
if (!validationResult.success) {
|
|
109
|
+
throw new FileOperationError(`Schema validation failed before write: ${validationResult.error.message}`, filePath, 'write', validationResult.error);
|
|
110
|
+
}
|
|
111
|
+
// Ensure parent directory exists
|
|
112
|
+
const dirPath = path.dirname(filePath);
|
|
113
|
+
await ensureDirectory(dirPath);
|
|
114
|
+
// Generate unique temp file path
|
|
115
|
+
const tempPath = `${filePath}.tmp.${randomUUID().replace(/-/g, '')}`;
|
|
116
|
+
let lastError;
|
|
117
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
118
|
+
try {
|
|
119
|
+
// Write to temporary file
|
|
120
|
+
await writeJsonCore(tempPath, data);
|
|
121
|
+
// Atomic rename
|
|
122
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
123
|
+
await fs.rename(tempPath, filePath);
|
|
124
|
+
// Success - clean exit
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
lastError = error;
|
|
129
|
+
// Clean up temp file on failure
|
|
130
|
+
await tryDeleteFile(tempPath);
|
|
131
|
+
// Retry on transient errors
|
|
132
|
+
if (attempt < MAX_RETRIES - 1) {
|
|
133
|
+
const delay = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
134
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// All retries exhausted
|
|
140
|
+
throw new FileOperationError(`Failed to write file after ${MAX_RETRIES} attempts: ${filePath}`, filePath, 'write', lastError);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Core write operation: serialize JSON and flush to disk.
|
|
144
|
+
*/
|
|
145
|
+
async function writeJsonCore(filePath, data) {
|
|
146
|
+
// Serialize with pretty-printing (2-space indentation)
|
|
147
|
+
const json = JSON.stringify(data, null, 2);
|
|
148
|
+
// Write to file
|
|
149
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
150
|
+
const fileHandle = await fs.open(filePath, 'w');
|
|
151
|
+
try {
|
|
152
|
+
await fileHandle.writeFile(json, 'utf-8');
|
|
153
|
+
// Flush OS buffers to disk
|
|
154
|
+
await fileHandle.sync();
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
await fileHandle.close();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Safely delete a file, ignoring errors.
|
|
162
|
+
*/
|
|
163
|
+
async function tryDeleteFile(filePath) {
|
|
164
|
+
try {
|
|
165
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
166
|
+
await fs.unlink(filePath);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// Ignore all errors - this is best-effort cleanup
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Check if a file exists
|
|
174
|
+
*
|
|
175
|
+
* @param filePath - Absolute file path
|
|
176
|
+
* @returns true if file exists, false otherwise
|
|
177
|
+
*/
|
|
178
|
+
export async function fileExists(filePath) {
|
|
179
|
+
try {
|
|
180
|
+
await fs.access(filePath);
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Read JSON file or return default value if file doesn't exist.
|
|
189
|
+
*/
|
|
190
|
+
export async function readJsonFileOrDefault(filePath, schema, defaultValue) {
|
|
191
|
+
try {
|
|
192
|
+
return await readJsonFile(filePath, schema);
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
// Return default if file doesn't exist
|
|
196
|
+
if (error instanceof FileOperationError &&
|
|
197
|
+
error.originalError instanceof Error &&
|
|
198
|
+
'code' in error.originalError &&
|
|
199
|
+
error.originalError.code === 'ENOENT') {
|
|
200
|
+
return defaultValue;
|
|
201
|
+
}
|
|
202
|
+
// Re-throw other errors (validation failures, permission errors, etc.)
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* List all files in a directory.
|
|
208
|
+
*/
|
|
209
|
+
export async function listFiles(dirPath) {
|
|
210
|
+
try {
|
|
211
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
212
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
213
|
+
return entries
|
|
214
|
+
.filter(entry => entry.isFile())
|
|
215
|
+
.map(entry => entry.name);
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
throw new FileOperationError(`Failed to list files in directory: ${dirPath}`, dirPath, 'read', error);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Delete a file with retry logic.
|
|
223
|
+
*/
|
|
224
|
+
export async function deleteFile(filePath) {
|
|
225
|
+
let lastError;
|
|
226
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
227
|
+
try {
|
|
228
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
229
|
+
await fs.unlink(filePath);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
lastError = error;
|
|
234
|
+
// Don't retry if file doesn't exist (already deleted)
|
|
235
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
// Retry on transient errors
|
|
239
|
+
if (attempt < MAX_RETRIES - 1) {
|
|
240
|
+
const delay = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
241
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
throw new FileOperationError(`Failed to delete file after ${MAX_RETRIES} attempts: ${filePath}`, filePath, 'delete', lastError);
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=fileOperations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileOperations.js","sourceRoot":"","sources":["../../src/data/fileOperations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MemoryStore - Task snapshot and history management
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - Task snapshot creation and retrieval
|
|
6
|
+
* - Historical task state management
|
|
7
|
+
* - Backup functionality for task clearing
|
|
8
|
+
*
|
|
9
|
+
*/
|
|
10
|
+
import { type TaskDocument } from './schemas.js';
|
|
11
|
+
/**
|
|
12
|
+
* Snapshot metadata
|
|
13
|
+
*/
|
|
14
|
+
export interface SnapshotInfo {
|
|
15
|
+
/** Snapshot filename (without extension) */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Full file path */
|
|
18
|
+
path: string;
|
|
19
|
+
/** Snapshot creation timestamp */
|
|
20
|
+
timestamp: Date;
|
|
21
|
+
/** Number of tasks in snapshot */
|
|
22
|
+
taskCount: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* MemoryStore - Manages task snapshots and historical data
|
|
26
|
+
*/
|
|
27
|
+
export declare class MemoryStore {
|
|
28
|
+
private readonly memoryDir;
|
|
29
|
+
private readonly backupDir;
|
|
30
|
+
/**
|
|
31
|
+
* Create a new MemoryStore
|
|
32
|
+
*
|
|
33
|
+
* @param dataDir - Optional data directory override (for testing)
|
|
34
|
+
*/
|
|
35
|
+
constructor(dataDir?: string);
|
|
36
|
+
/**
|
|
37
|
+
* Save a task snapshot with a descriptive name
|
|
38
|
+
*
|
|
39
|
+
* @param name - Snapshot name (will be sanitized)
|
|
40
|
+
* @param document - Task document to snapshot
|
|
41
|
+
* @returns Path to saved snapshot
|
|
42
|
+
*/
|
|
43
|
+
saveSnapshotAsync(name: string, document: TaskDocument): Promise<string>;
|
|
44
|
+
/**
|
|
45
|
+
* Load a task snapshot by name
|
|
46
|
+
*
|
|
47
|
+
* @param name - Snapshot filename (with or without .json extension)
|
|
48
|
+
* @returns Task document from snapshot
|
|
49
|
+
*/
|
|
50
|
+
loadSnapshotAsync(name: string): Promise<TaskDocument>;
|
|
51
|
+
/**
|
|
52
|
+
* List all available snapshots
|
|
53
|
+
*
|
|
54
|
+
* @returns Array of snapshot metadata
|
|
55
|
+
*/
|
|
56
|
+
listSnapshotsAsync(): Promise<SnapshotInfo[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Delete a snapshot by name
|
|
59
|
+
*
|
|
60
|
+
* @param name - Snapshot filename (with or without .json extension)
|
|
61
|
+
* @returns True if deleted, false if not found
|
|
62
|
+
*/
|
|
63
|
+
deleteSnapshotAsync(name: string): Promise<boolean>;
|
|
64
|
+
/**
|
|
65
|
+
* Create a backup of completed tasks
|
|
66
|
+
* Used when clearing all tasks to preserve history
|
|
67
|
+
*
|
|
68
|
+
* @param document - Task document to backup
|
|
69
|
+
* @returns Path to backup file
|
|
70
|
+
*/
|
|
71
|
+
createBackupAsync(document: TaskDocument): Promise<string>;
|
|
72
|
+
/**
|
|
73
|
+
* Sanitize filename to prevent path traversal and filesystem issues
|
|
74
|
+
*
|
|
75
|
+
* Removes:
|
|
76
|
+
* - Path separators (/, \)
|
|
77
|
+
* - Null bytes
|
|
78
|
+
* - Control characters
|
|
79
|
+
* - Leading/trailing dots and spaces
|
|
80
|
+
*
|
|
81
|
+
* @param filename - Raw filename
|
|
82
|
+
* @returns Sanitized filename safe for filesystem
|
|
83
|
+
*/
|
|
84
|
+
private sanitizeFilename;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=memoryStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryStore.d.ts","sourceRoot":"","sources":["../../src/data/memoryStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,KAAK,YAAY,EAAsB,MAAM,cAAc,CAAC;AAIrE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,SAAS,EAAE,IAAI,CAAC;IAChB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB;AAsBD;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC;;;;OAIG;gBACS,OAAO,CAAC,EAAE,MAAM;IAM5B;;;;;;OAMG;IACU,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAiCrF;;;;;OAKG;IACU,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAyBnE;;;;OAIG;IACU,kBAAkB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAwC1D;;;;;OAKG;IACU,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsBhE;;;;;;OAMG;IACU,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBvE;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,gBAAgB;CAezB"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MemoryStore - Task snapshot and history management
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - Task snapshot creation and retrieval
|
|
6
|
+
* - Historical task state management
|
|
7
|
+
* - Backup functionality for task clearing
|
|
8
|
+
*
|
|
9
|
+
*/
|
|
10
|
+
import { writeJsonFile, readJsonFile, fileExists, listFiles, deleteFile } from './fileOperations.js';
|
|
11
|
+
import { TaskDocumentSchema } from './schemas.js';
|
|
12
|
+
import { getDataPath } from '../config/pathResolver.js';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
/**
|
|
15
|
+
* Maximum filename length to prevent filesystem issues
|
|
16
|
+
*/
|
|
17
|
+
const MAX_FILENAME_LENGTH = 100;
|
|
18
|
+
/**
|
|
19
|
+
* Maximum snapshot file size (10MB) to prevent DoS
|
|
20
|
+
*/
|
|
21
|
+
const MAX_SNAPSHOT_SIZE_BYTES = 10 * 1024 * 1024;
|
|
22
|
+
/**
|
|
23
|
+
* Memory subdirectory name
|
|
24
|
+
*/
|
|
25
|
+
const MEMORY_DIR = 'memory';
|
|
26
|
+
/**
|
|
27
|
+
* Backup subdirectory name
|
|
28
|
+
*/
|
|
29
|
+
const BACKUP_DIR = 'backups';
|
|
30
|
+
/**
|
|
31
|
+
* MemoryStore - Manages task snapshots and historical data
|
|
32
|
+
*/
|
|
33
|
+
export class MemoryStore {
|
|
34
|
+
memoryDir;
|
|
35
|
+
backupDir;
|
|
36
|
+
/**
|
|
37
|
+
* Create a new MemoryStore
|
|
38
|
+
*
|
|
39
|
+
* @param dataDir - Optional data directory override (for testing)
|
|
40
|
+
*/
|
|
41
|
+
constructor(dataDir) {
|
|
42
|
+
const baseDir = dataDir ?? getDataPath('', dataDir);
|
|
43
|
+
this.memoryDir = path.join(baseDir, MEMORY_DIR);
|
|
44
|
+
this.backupDir = path.join(baseDir, BACKUP_DIR);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Save a task snapshot with a descriptive name
|
|
48
|
+
*
|
|
49
|
+
* @param name - Snapshot name (will be sanitized)
|
|
50
|
+
* @param document - Task document to snapshot
|
|
51
|
+
* @returns Path to saved snapshot
|
|
52
|
+
*/
|
|
53
|
+
async saveSnapshotAsync(name, document) {
|
|
54
|
+
// Sanitize and validate filename
|
|
55
|
+
const sanitizedName = this.sanitizeFilename(name);
|
|
56
|
+
if (sanitizedName.length === 0) {
|
|
57
|
+
throw new Error('Snapshot name cannot be empty after sanitization');
|
|
58
|
+
}
|
|
59
|
+
if (sanitizedName.length > MAX_FILENAME_LENGTH) {
|
|
60
|
+
throw new Error(`Snapshot name too long (max ${MAX_FILENAME_LENGTH} characters after sanitization)`);
|
|
61
|
+
}
|
|
62
|
+
// Create snapshot filename with timestamp
|
|
63
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
64
|
+
const filename = `${sanitizedName}_${timestamp}.json`;
|
|
65
|
+
const filePath = path.join(this.memoryDir, filename);
|
|
66
|
+
// Validate file size before writing
|
|
67
|
+
const jsonSize = JSON.stringify(document).length;
|
|
68
|
+
if (jsonSize > MAX_SNAPSHOT_SIZE_BYTES) {
|
|
69
|
+
throw new Error(`Snapshot too large (${jsonSize} bytes, max ${MAX_SNAPSHOT_SIZE_BYTES})`);
|
|
70
|
+
}
|
|
71
|
+
// Write snapshot atomically
|
|
72
|
+
await writeJsonFile(filePath, document, TaskDocumentSchema);
|
|
73
|
+
return filePath;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Load a task snapshot by name
|
|
77
|
+
*
|
|
78
|
+
* @param name - Snapshot filename (with or without .json extension)
|
|
79
|
+
* @returns Task document from snapshot
|
|
80
|
+
*/
|
|
81
|
+
async loadSnapshotAsync(name) {
|
|
82
|
+
// Add .json extension if not present
|
|
83
|
+
const filename = name.endsWith('.json') ? name : `${name}.json`;
|
|
84
|
+
const filePath = path.join(this.memoryDir, filename);
|
|
85
|
+
// Validate path doesn't escape memory directory
|
|
86
|
+
const resolvedPath = path.resolve(filePath);
|
|
87
|
+
const resolvedMemoryDir = path.resolve(this.memoryDir);
|
|
88
|
+
if (!resolvedPath.startsWith(resolvedMemoryDir)) {
|
|
89
|
+
throw new Error('Invalid snapshot path: directory traversal detected');
|
|
90
|
+
}
|
|
91
|
+
// Check if file exists
|
|
92
|
+
if (!(await fileExists(filePath))) {
|
|
93
|
+
throw new Error(`Snapshot not found: ${name}`);
|
|
94
|
+
}
|
|
95
|
+
// Read and validate snapshot
|
|
96
|
+
// Zod parsing ensures all defaults are applied
|
|
97
|
+
const document = await readJsonFile(filePath, TaskDocumentSchema);
|
|
98
|
+
// Return as TaskDocument (Zod ensures schema compliance including defaults)
|
|
99
|
+
return document;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* List all available snapshots
|
|
103
|
+
*
|
|
104
|
+
* @returns Array of snapshot metadata
|
|
105
|
+
*/
|
|
106
|
+
async listSnapshotsAsync() {
|
|
107
|
+
// Ensure memory directory exists
|
|
108
|
+
if (!(await fileExists(this.memoryDir))) {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
// List all JSON files in memory directory
|
|
112
|
+
const allFiles = await listFiles(this.memoryDir);
|
|
113
|
+
const files = allFiles.filter(f => f.endsWith('.json'));
|
|
114
|
+
// Load metadata for each snapshot
|
|
115
|
+
const snapshots = [];
|
|
116
|
+
for (const file of files) {
|
|
117
|
+
try {
|
|
118
|
+
const filePath = path.join(this.memoryDir, file);
|
|
119
|
+
const document = await readJsonFile(filePath, TaskDocumentSchema);
|
|
120
|
+
// Extract timestamp from filename (format: name_YYYY-MM-DDTHH-MM-SS-sssZ.json)
|
|
121
|
+
const timestampMatch = file.match(/_(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z)\.json$/);
|
|
122
|
+
const timestamp = timestampMatch
|
|
123
|
+
? new Date(timestampMatch[1].replace(/-/g, ':').replace(/T(\d{2}):(\d{2}):(\d{2})/, 'T$1:$2:$3.'))
|
|
124
|
+
: new Date();
|
|
125
|
+
snapshots.push({
|
|
126
|
+
name: file.replace(/\.json$/, ''),
|
|
127
|
+
path: filePath,
|
|
128
|
+
timestamp,
|
|
129
|
+
taskCount: document.tasks?.length ?? 0,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
// Skip corrupted snapshots
|
|
134
|
+
console.warn(`Failed to load snapshot ${file}:`, error);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Sort by timestamp (newest first)
|
|
138
|
+
return snapshots.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Delete a snapshot by name
|
|
142
|
+
*
|
|
143
|
+
* @param name - Snapshot filename (with or without .json extension)
|
|
144
|
+
* @returns True if deleted, false if not found
|
|
145
|
+
*/
|
|
146
|
+
async deleteSnapshotAsync(name) {
|
|
147
|
+
const filename = name.endsWith('.json') ? name : `${name}.json`;
|
|
148
|
+
const filePath = path.join(this.memoryDir, filename);
|
|
149
|
+
// Validate path doesn't escape memory directory
|
|
150
|
+
const resolvedPath = path.resolve(filePath);
|
|
151
|
+
const resolvedMemoryDir = path.resolve(this.memoryDir);
|
|
152
|
+
if (!resolvedPath.startsWith(resolvedMemoryDir)) {
|
|
153
|
+
throw new Error('Invalid snapshot path: directory traversal detected');
|
|
154
|
+
}
|
|
155
|
+
// Check if file exists
|
|
156
|
+
if (!(await fileExists(filePath))) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
// Delete snapshot
|
|
160
|
+
await deleteFile(filePath);
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Create a backup of completed tasks
|
|
165
|
+
* Used when clearing all tasks to preserve history
|
|
166
|
+
*
|
|
167
|
+
* @param document - Task document to backup
|
|
168
|
+
* @returns Path to backup file
|
|
169
|
+
*/
|
|
170
|
+
async createBackupAsync(document) {
|
|
171
|
+
// Filter to only completed tasks
|
|
172
|
+
const completedTasks = document.tasks.filter(t => t.status === 'completed');
|
|
173
|
+
if (completedTasks.length === 0) {
|
|
174
|
+
throw new Error('No completed tasks to backup');
|
|
175
|
+
}
|
|
176
|
+
const backupDocument = {
|
|
177
|
+
version: document.version,
|
|
178
|
+
tasks: completedTasks,
|
|
179
|
+
};
|
|
180
|
+
// Create backup filename with timestamp
|
|
181
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
182
|
+
const filename = `backup_${timestamp}.json`;
|
|
183
|
+
const filePath = path.join(this.backupDir, filename);
|
|
184
|
+
// Write backup atomically
|
|
185
|
+
await writeJsonFile(filePath, backupDocument, TaskDocumentSchema);
|
|
186
|
+
return filePath;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Sanitize filename to prevent path traversal and filesystem issues
|
|
190
|
+
*
|
|
191
|
+
* Removes:
|
|
192
|
+
* - Path separators (/, \)
|
|
193
|
+
* - Null bytes
|
|
194
|
+
* - Control characters
|
|
195
|
+
* - Leading/trailing dots and spaces
|
|
196
|
+
*
|
|
197
|
+
* @param filename - Raw filename
|
|
198
|
+
* @returns Sanitized filename safe for filesystem
|
|
199
|
+
*/
|
|
200
|
+
sanitizeFilename(filename) {
|
|
201
|
+
return filename
|
|
202
|
+
// Remove path separators and null bytes
|
|
203
|
+
.replace(/[/\\:\0]/g, '')
|
|
204
|
+
// Remove control characters (ASCII 0-31, 127)
|
|
205
|
+
.replace(/[\x00-\x1F\x7F]/g, '')
|
|
206
|
+
// Remove characters that are problematic on Windows
|
|
207
|
+
.replace(/[<>:"|?*]/g, '')
|
|
208
|
+
// Replace spaces with underscores
|
|
209
|
+
.replace(/\s+/g, '_')
|
|
210
|
+
// Remove leading/trailing dots and spaces
|
|
211
|
+
.replace(/^[.\s]+|[.\s]+$/g, '')
|
|
212
|
+
// Collapse multiple underscores
|
|
213
|
+
.replace(/_+/g, '_');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=memoryStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryStore.js","sourceRoot":"","sources":["../../src/data/memoryStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RulesStore - Project-specific coding rules management
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - Loading and saving project coding standards
|
|
6
|
+
* - Markdown-based rules storage
|
|
7
|
+
* - Validation and size limits
|
|
8
|
+
*
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* RulesStore - Manages project-specific coding rules
|
|
12
|
+
*/
|
|
13
|
+
export declare class RulesStore {
|
|
14
|
+
private readonly rulesFilePath;
|
|
15
|
+
/**
|
|
16
|
+
* Create a new RulesStore
|
|
17
|
+
*
|
|
18
|
+
* @param dataDir - Optional data directory override (for testing)
|
|
19
|
+
*/
|
|
20
|
+
constructor(dataDir?: string);
|
|
21
|
+
/**
|
|
22
|
+
* Check if project rules exist
|
|
23
|
+
*
|
|
24
|
+
* @returns True if rules file exists
|
|
25
|
+
*/
|
|
26
|
+
rulesExistAsync(): Promise<boolean>;
|
|
27
|
+
/**
|
|
28
|
+
* Load project rules
|
|
29
|
+
*
|
|
30
|
+
* @returns Rules content as markdown string
|
|
31
|
+
*/
|
|
32
|
+
loadRulesAsync(): Promise<string>;
|
|
33
|
+
/**
|
|
34
|
+
* Save project rules
|
|
35
|
+
*
|
|
36
|
+
* Validates markdown content and size before saving
|
|
37
|
+
*
|
|
38
|
+
* @param content - Rules content as markdown string
|
|
39
|
+
*/
|
|
40
|
+
saveRulesAsync(content: string): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Initialize project rules with default template
|
|
43
|
+
*
|
|
44
|
+
* Only creates file if it doesn't already exist
|
|
45
|
+
*
|
|
46
|
+
* @returns True if created, false if already exists
|
|
47
|
+
*/
|
|
48
|
+
initializeRulesAsync(): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Update project rules (append or replace sections)
|
|
51
|
+
*
|
|
52
|
+
* @param updates - Markdown content to append or section replacements
|
|
53
|
+
* @param mode - 'append' to add to end, 'replace' to overwrite
|
|
54
|
+
*/
|
|
55
|
+
updateRulesAsync(updates: string, mode?: 'append' | 'replace'): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Delete project rules
|
|
58
|
+
*
|
|
59
|
+
* @returns True if deleted, false if didn't exist
|
|
60
|
+
*/
|
|
61
|
+
deleteRulesAsync(): Promise<boolean>;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=rulesStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rulesStore.d.ts","sourceRoot":"","sources":["../../src/data/rulesStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAuDH;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC;;;;OAIG;gBACS,OAAO,CAAC,EAAE,MAAM;IAI5B;;;;OAIG;IACU,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAIhD;;;;OAIG;IACU,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAmB9C;;;;;;OAMG;IACU,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4C3D;;;;;;OAMG;IACU,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;IASrD;;;;;OAKG;IACU,gBAAgB,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,QAAQ,GAAG,SAAoB,GACpC,OAAO,CAAC,IAAI,CAAC;IAuBhB;;;;OAIG;IACU,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;CASlD"}
|