octie-cli 1.0.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 +523 -0
- package/dist/cli/commands/approve.d.ts +27 -0
- package/dist/cli/commands/approve.d.ts.map +1 -0
- package/dist/cli/commands/approve.js +119 -0
- package/dist/cli/commands/approve.js.map +1 -0
- package/dist/cli/commands/batch.d.ts +15 -0
- package/dist/cli/commands/batch.d.ts.map +1 -0
- package/dist/cli/commands/batch.js +521 -0
- package/dist/cli/commands/batch.js.map +1 -0
- package/dist/cli/commands/create.d.ts +9 -0
- package/dist/cli/commands/create.d.ts.map +1 -0
- package/dist/cli/commands/create.js +321 -0
- package/dist/cli/commands/create.js.map +1 -0
- package/dist/cli/commands/delete.d.ts +9 -0
- package/dist/cli/commands/delete.d.ts.map +1 -0
- package/dist/cli/commands/delete.js +143 -0
- package/dist/cli/commands/delete.js.map +1 -0
- package/dist/cli/commands/export.d.ts +9 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +66 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/find.d.ts +16 -0
- package/dist/cli/commands/find.d.ts.map +1 -0
- package/dist/cli/commands/find.js +252 -0
- package/dist/cli/commands/find.js.map +1 -0
- package/dist/cli/commands/get.d.ts +9 -0
- package/dist/cli/commands/get.d.ts.map +1 -0
- package/dist/cli/commands/get.js +74 -0
- package/dist/cli/commands/get.js.map +1 -0
- package/dist/cli/commands/graph.d.ts +9 -0
- package/dist/cli/commands/graph.d.ts.map +1 -0
- package/dist/cli/commands/graph.js +200 -0
- package/dist/cli/commands/graph.js.map +1 -0
- package/dist/cli/commands/import.d.ts +9 -0
- package/dist/cli/commands/import.d.ts.map +1 -0
- package/dist/cli/commands/import.js +807 -0
- package/dist/cli/commands/import.js.map +1 -0
- package/dist/cli/commands/init.d.ts +9 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +57 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/list.d.ts +9 -0
- package/dist/cli/commands/list.d.ts.map +1 -0
- package/dist/cli/commands/list.js +175 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/merge.d.ts +9 -0
- package/dist/cli/commands/merge.d.ts.map +1 -0
- package/dist/cli/commands/merge.js +113 -0
- package/dist/cli/commands/merge.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +9 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +94 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/update.d.ts +9 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +423 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/commands/wire.d.ts +15 -0
- package/dist/cli/commands/wire.d.ts.map +1 -0
- package/dist/cli/commands/wire.js +164 -0
- package/dist/cli/commands/wire.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +100 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output/json.d.ts +16 -0
- package/dist/cli/output/json.d.ts.map +1 -0
- package/dist/cli/output/json.js +29 -0
- package/dist/cli/output/json.js.map +1 -0
- package/dist/cli/output/markdown.d.ts +15 -0
- package/dist/cli/output/markdown.d.ts.map +1 -0
- package/dist/cli/output/markdown.js +206 -0
- package/dist/cli/output/markdown.js.map +1 -0
- package/dist/cli/output/table.d.ts +23 -0
- package/dist/cli/output/table.d.ts.map +1 -0
- package/dist/cli/output/table.js +150 -0
- package/dist/cli/output/table.js.map +1 -0
- package/dist/cli/utils/helpers.d.ts +126 -0
- package/dist/cli/utils/helpers.d.ts.map +1 -0
- package/dist/cli/utils/helpers.js +325 -0
- package/dist/cli/utils/helpers.js.map +1 -0
- package/dist/core/graph/algorithms.d.ts +11 -0
- package/dist/core/graph/algorithms.d.ts.map +1 -0
- package/dist/core/graph/algorithms.js +14 -0
- package/dist/core/graph/algorithms.js.map +1 -0
- package/dist/core/graph/cycle.d.ts +155 -0
- package/dist/core/graph/cycle.d.ts.map +1 -0
- package/dist/core/graph/cycle.js +297 -0
- package/dist/core/graph/cycle.js.map +1 -0
- package/dist/core/graph/index.d.ts +223 -0
- package/dist/core/graph/index.d.ts.map +1 -0
- package/dist/core/graph/index.js +475 -0
- package/dist/core/graph/index.js.map +1 -0
- package/dist/core/graph/operations.d.ts +240 -0
- package/dist/core/graph/operations.d.ts.map +1 -0
- package/dist/core/graph/operations.js +503 -0
- package/dist/core/graph/operations.js.map +1 -0
- package/dist/core/graph/sort.d.ts +76 -0
- package/dist/core/graph/sort.d.ts.map +1 -0
- package/dist/core/graph/sort.js +254 -0
- package/dist/core/graph/sort.js.map +1 -0
- package/dist/core/graph/traversal.d.ts +122 -0
- package/dist/core/graph/traversal.d.ts.map +1 -0
- package/dist/core/graph/traversal.js +336 -0
- package/dist/core/graph/traversal.js.map +1 -0
- package/dist/core/models/task-node.d.ts +328 -0
- package/dist/core/models/task-node.d.ts.map +1 -0
- package/dist/core/models/task-node.js +1090 -0
- package/dist/core/models/task-node.js.map +1 -0
- package/dist/core/registry/index.d.ts +102 -0
- package/dist/core/registry/index.d.ts.map +1 -0
- package/dist/core/registry/index.js +249 -0
- package/dist/core/registry/index.js.map +1 -0
- package/dist/core/registry/root-guard.d.ts +19 -0
- package/dist/core/registry/root-guard.d.ts.map +1 -0
- package/dist/core/registry/root-guard.js +28 -0
- package/dist/core/registry/root-guard.js.map +1 -0
- package/dist/core/storage/atomic-write.d.ts +181 -0
- package/dist/core/storage/atomic-write.d.ts.map +1 -0
- package/dist/core/storage/atomic-write.js +379 -0
- package/dist/core/storage/atomic-write.js.map +1 -0
- package/dist/core/storage/file-store.d.ts +148 -0
- package/dist/core/storage/file-store.d.ts.map +1 -0
- package/dist/core/storage/file-store.js +423 -0
- package/dist/core/storage/file-store.js.map +1 -0
- package/dist/core/storage/indexer.d.ts +138 -0
- package/dist/core/storage/indexer.d.ts.map +1 -0
- package/dist/core/storage/indexer.js +350 -0
- package/dist/core/storage/indexer.js.map +1 -0
- package/dist/core/utils/status-helpers.d.ts +59 -0
- package/dist/core/utils/status-helpers.d.ts.map +1 -0
- package/dist/core/utils/status-helpers.js +149 -0
- package/dist/core/utils/status-helpers.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +504 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +182 -0
- package/dist/types/index.js.map +1 -0
- package/dist/web/routes/graph.d.ts +17 -0
- package/dist/web/routes/graph.d.ts.map +1 -0
- package/dist/web/routes/graph.js +277 -0
- package/dist/web/routes/graph.js.map +1 -0
- package/dist/web/routes/projects.d.ts +14 -0
- package/dist/web/routes/projects.d.ts.map +1 -0
- package/dist/web/routes/projects.js +102 -0
- package/dist/web/routes/projects.js.map +1 -0
- package/dist/web/routes/tasks.d.ts +17 -0
- package/dist/web/routes/tasks.d.ts.map +1 -0
- package/dist/web/routes/tasks.js +538 -0
- package/dist/web/routes/tasks.js.map +1 -0
- package/dist/web/server.d.ts +121 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +389 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web-ui/assets/index-BB0qvF1y.css +1 -0
- package/dist/web-ui/assets/index-Vmm72oKY.js +34 -0
- package/dist/web-ui/index.html +14 -0
- package/dist/web-ui/vite.svg +1 -0
- package/package.json +94 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Storage for file operations
|
|
3
|
+
*
|
|
4
|
+
* Manages persistent storage of task graphs using atomic file operations.
|
|
5
|
+
* Handles project.json, backups, and .octie directory structure.
|
|
6
|
+
*
|
|
7
|
+
* Directory Structure:
|
|
8
|
+
* .octie/
|
|
9
|
+
* ├── project.json # Main task storage
|
|
10
|
+
* ├── project.json.bak # Latest backup
|
|
11
|
+
* ├── project.json.bak.{ts} # Rotated backups
|
|
12
|
+
* ├── indexes/ # Pre-computed indexes
|
|
13
|
+
* ├── cache/ # Serialized graph cache
|
|
14
|
+
* └── config.json # Project configuration
|
|
15
|
+
*
|
|
16
|
+
* @module core/storage
|
|
17
|
+
*/
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import { FileOperationError, ValidationError } from '../../types/index.js';
|
|
20
|
+
import { AtomicFileWriter } from './atomic-write.js';
|
|
21
|
+
import { TaskGraphStore } from '../graph/index.js';
|
|
22
|
+
import { TaskNode } from '../models/task-node.js';
|
|
23
|
+
/**
|
|
24
|
+
* Default project file name
|
|
25
|
+
*/
|
|
26
|
+
const DEFAULT_PROJECT_FILE = 'project.json';
|
|
27
|
+
/**
|
|
28
|
+
* Default .octie directory name
|
|
29
|
+
*/
|
|
30
|
+
const OCTIE_DIR_NAME = '.octie';
|
|
31
|
+
/**
|
|
32
|
+
* Task Storage class
|
|
33
|
+
*
|
|
34
|
+
* Manages persistent storage of task graphs with atomic operations.
|
|
35
|
+
*/
|
|
36
|
+
export class TaskStorage {
|
|
37
|
+
_projectDir;
|
|
38
|
+
_octieDirName;
|
|
39
|
+
_projectFileName;
|
|
40
|
+
_autoBackup;
|
|
41
|
+
_backupCount;
|
|
42
|
+
_writer;
|
|
43
|
+
/**
|
|
44
|
+
* Create a new TaskStorage instance
|
|
45
|
+
* @param config - Storage configuration
|
|
46
|
+
*/
|
|
47
|
+
constructor(config = {}) {
|
|
48
|
+
this._projectDir = config.projectDir || process.cwd();
|
|
49
|
+
this._octieDirName = config.octieDirName || OCTIE_DIR_NAME;
|
|
50
|
+
this._projectFileName = config.projectFileName || DEFAULT_PROJECT_FILE;
|
|
51
|
+
this._autoBackup = config.autoBackup ?? true;
|
|
52
|
+
this._backupCount = config.backupCount ?? 5;
|
|
53
|
+
this._writer = new AtomicFileWriter({
|
|
54
|
+
backupCount: this._backupCount,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get the Octie directory path
|
|
59
|
+
*/
|
|
60
|
+
get octieDirPath() {
|
|
61
|
+
return join(this._projectDir, this._octieDirName);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get the project file path
|
|
65
|
+
*/
|
|
66
|
+
get projectFilePath() {
|
|
67
|
+
return join(this.octieDirPath, this._projectFileName);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get the backup file path
|
|
71
|
+
*/
|
|
72
|
+
get backupFilePath() {
|
|
73
|
+
return `${this.projectFilePath}.bak`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get the indexes directory path
|
|
77
|
+
*/
|
|
78
|
+
get indexesDirPath() {
|
|
79
|
+
return join(this.octieDirPath, 'indexes');
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get the cache directory path
|
|
83
|
+
*/
|
|
84
|
+
get cacheDirPath() {
|
|
85
|
+
return join(this.octieDirPath, 'cache');
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get the config file path
|
|
89
|
+
*/
|
|
90
|
+
get configFilePath() {
|
|
91
|
+
return join(this.octieDirPath, 'config.json');
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Initialize the Octie directory structure
|
|
95
|
+
* Creates .octie directory with subdirectories if they don't exist
|
|
96
|
+
*/
|
|
97
|
+
async init() {
|
|
98
|
+
// Ensure .octie directory exists
|
|
99
|
+
await this._writer.ensureDir(this.octieDirPath);
|
|
100
|
+
// Ensure subdirectories exist
|
|
101
|
+
await this._writer.ensureDir(this.indexesDirPath);
|
|
102
|
+
await this._writer.ensureDir(this.cacheDirPath);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check if Octie directory exists
|
|
106
|
+
* @returns True if .octie directory exists
|
|
107
|
+
*/
|
|
108
|
+
async exists() {
|
|
109
|
+
return await this._writer.exists(this.projectFilePath);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Load project from file
|
|
113
|
+
* @returns TaskGraphStore instance
|
|
114
|
+
* @throws {FileOperationError} If file doesn't exist or is invalid
|
|
115
|
+
*/
|
|
116
|
+
async load() {
|
|
117
|
+
// Check if project exists
|
|
118
|
+
if (!await this.exists()) {
|
|
119
|
+
throw new FileOperationError('Octie project not found. Run `octie init` to create a new project.', this.projectFilePath);
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
// Read and parse project file
|
|
123
|
+
const projectFile = await this._writer.readJSON(this.projectFilePath);
|
|
124
|
+
// Validate project file structure
|
|
125
|
+
this._validateProjectFile(projectFile);
|
|
126
|
+
// Create graph from loaded data
|
|
127
|
+
const graph = new TaskGraphStore(projectFile.metadata);
|
|
128
|
+
for (const [, taskData] of Object.entries(projectFile.tasks)) {
|
|
129
|
+
// Convert plain object to TaskNode class instance
|
|
130
|
+
const node = TaskNode.fromJSON(taskData);
|
|
131
|
+
graph.addNode(node);
|
|
132
|
+
}
|
|
133
|
+
// Note: Edges are automatically restored when nodes are added
|
|
134
|
+
// via the TaskNode.edges field, so we don't need to restore them again
|
|
135
|
+
return graph;
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
if (error instanceof FileOperationError) {
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
throw new FileOperationError(`Failed to load project: ${error instanceof Error ? error.message : String(error)}`, this.projectFilePath);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Save project to file
|
|
146
|
+
* @param graph - TaskGraphStore to save
|
|
147
|
+
* @param options - Save options
|
|
148
|
+
*/
|
|
149
|
+
async save(graph, options = {}) {
|
|
150
|
+
const createBackup = options.createBackup ?? this._autoBackup;
|
|
151
|
+
// Ensure directory exists
|
|
152
|
+
await this.init();
|
|
153
|
+
try {
|
|
154
|
+
// Convert graph to JSON-serializable format
|
|
155
|
+
const json = graph.toJSON();
|
|
156
|
+
// Convert edges to GraphEdge[] format
|
|
157
|
+
const edges = [];
|
|
158
|
+
for (const [fromId, targets] of Object.entries(json.outgoingEdges)) {
|
|
159
|
+
for (const toId of targets) {
|
|
160
|
+
edges.push({
|
|
161
|
+
from: fromId,
|
|
162
|
+
to: toId,
|
|
163
|
+
type: 'blocks', // Default edge type for now
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Build project file structure
|
|
168
|
+
const projectFile = {
|
|
169
|
+
$schema: 'https://octie.dev/schemas/project-v1.json',
|
|
170
|
+
version: '1.0.0',
|
|
171
|
+
format: 'octie-project',
|
|
172
|
+
metadata: json.metadata,
|
|
173
|
+
tasks: json.nodes,
|
|
174
|
+
edges,
|
|
175
|
+
indexes: await this._buildIndexes(graph),
|
|
176
|
+
};
|
|
177
|
+
// Write atomically
|
|
178
|
+
await this._writer.write(this.projectFilePath, projectFile, {
|
|
179
|
+
createBackup,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
throw new FileOperationError(`Failed to save project: ${error instanceof Error ? error.message : String(error)}`, this.projectFilePath);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Build indexes for fast lookups
|
|
188
|
+
* @param graph - TaskGraphStore to index
|
|
189
|
+
* @returns ProjectIndexes
|
|
190
|
+
* @private
|
|
191
|
+
*/
|
|
192
|
+
async _buildIndexes(graph) {
|
|
193
|
+
const byStatus = {
|
|
194
|
+
ready: [],
|
|
195
|
+
in_progress: [],
|
|
196
|
+
in_review: [],
|
|
197
|
+
completed: [],
|
|
198
|
+
blocked: [],
|
|
199
|
+
};
|
|
200
|
+
const byPriority = {
|
|
201
|
+
top: [],
|
|
202
|
+
second: [],
|
|
203
|
+
later: [],
|
|
204
|
+
};
|
|
205
|
+
// Use Object.create(null) to avoid prototype pollution
|
|
206
|
+
// (e.g., token "constructor" would conflict with Object.prototype.constructor)
|
|
207
|
+
const searchText = Object.create(null);
|
|
208
|
+
const files = Object.create(null);
|
|
209
|
+
// Build indexes from all tasks
|
|
210
|
+
for (const task of graph.getAllTasks()) {
|
|
211
|
+
// Status index
|
|
212
|
+
byStatus[task.status]?.push(task.id);
|
|
213
|
+
// Priority index
|
|
214
|
+
byPriority[task.priority]?.push(task.id);
|
|
215
|
+
// Full-text search index (tokenize and index)
|
|
216
|
+
const text = `${task.title} ${task.description} ${task.notes}`.toLowerCase();
|
|
217
|
+
const tokens = text.match(/\b\w+\b/g) || [];
|
|
218
|
+
for (const token of tokens) {
|
|
219
|
+
if (!searchText[token]) {
|
|
220
|
+
searchText[token] = [];
|
|
221
|
+
}
|
|
222
|
+
if (!searchText[token].includes(task.id)) {
|
|
223
|
+
searchText[token].push(task.id);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// File reference index
|
|
227
|
+
for (const filePath of task.related_files) {
|
|
228
|
+
if (!files[filePath]) {
|
|
229
|
+
files[filePath] = [];
|
|
230
|
+
}
|
|
231
|
+
if (!files[filePath].includes(task.id)) {
|
|
232
|
+
files[filePath].push(task.id);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Get root and orphan tasks
|
|
237
|
+
const rootTasks = graph.getRootTasks();
|
|
238
|
+
const orphanTasks = graph.getOrphanTasks();
|
|
239
|
+
return {
|
|
240
|
+
byStatus: byStatus,
|
|
241
|
+
byPriority: byPriority,
|
|
242
|
+
rootTasks,
|
|
243
|
+
orphanTasks,
|
|
244
|
+
searchText,
|
|
245
|
+
files,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Validate project file structure
|
|
250
|
+
* @param projectFile - Project file to validate
|
|
251
|
+
* @throws {ValidationError} If structure is invalid
|
|
252
|
+
* @private
|
|
253
|
+
*/
|
|
254
|
+
_validateProjectFile(projectFile) {
|
|
255
|
+
if (!projectFile.tasks || typeof projectFile.tasks !== 'object') {
|
|
256
|
+
throw new ValidationError('Invalid project file: missing or invalid tasks', 'tasks');
|
|
257
|
+
}
|
|
258
|
+
if (!projectFile.metadata || typeof projectFile.metadata !== 'object') {
|
|
259
|
+
throw new ValidationError('Invalid project file: missing or invalid metadata', 'metadata');
|
|
260
|
+
}
|
|
261
|
+
// Validate metadata fields
|
|
262
|
+
const { metadata } = projectFile;
|
|
263
|
+
if (!metadata.project_name || typeof metadata.project_name !== 'string') {
|
|
264
|
+
throw new ValidationError('Invalid metadata: missing project_name', 'metadata.project_name');
|
|
265
|
+
}
|
|
266
|
+
if (!metadata.created_at || typeof metadata.created_at !== 'string') {
|
|
267
|
+
throw new ValidationError('Invalid metadata: missing created_at', 'metadata.created_at');
|
|
268
|
+
}
|
|
269
|
+
if (!metadata.updated_at || typeof metadata.updated_at !== 'string') {
|
|
270
|
+
throw new ValidationError('Invalid metadata: missing updated_at', 'metadata.updated_at');
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Get project metadata only (faster than full load)
|
|
275
|
+
* @returns Project metadata
|
|
276
|
+
* @throws {FileOperationError} If file doesn't exist
|
|
277
|
+
*/
|
|
278
|
+
async getMetadata() {
|
|
279
|
+
if (!await this.exists()) {
|
|
280
|
+
throw new FileOperationError('Octie project not found. Run `octie init` to create a new project.', this.projectFilePath);
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
const projectFile = await this._writer.readJSON(this.projectFilePath);
|
|
284
|
+
return projectFile.metadata;
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
throw new FileOperationError(`Failed to load metadata: ${error instanceof Error ? error.message : String(error)}`, this.projectFilePath);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Delete project file and backups
|
|
292
|
+
* Use with caution - this is destructive
|
|
293
|
+
*/
|
|
294
|
+
async delete() {
|
|
295
|
+
try {
|
|
296
|
+
// Delete project file
|
|
297
|
+
await this._writer.delete(this.projectFilePath);
|
|
298
|
+
// Delete backup files
|
|
299
|
+
await this._writer.delete(this.backupFilePath);
|
|
300
|
+
// Note: We don't delete the entire .octie directory
|
|
301
|
+
// as it may contain other data (indexes, cache, config)
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
throw new FileOperationError(`Failed to delete project: ${error instanceof Error ? error.message : String(error)}`, this.projectFilePath);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Create a new project with default metadata
|
|
309
|
+
* @param projectName - Project name
|
|
310
|
+
* @param description - Optional project description
|
|
311
|
+
*/
|
|
312
|
+
async createProject(projectName, description) {
|
|
313
|
+
await this.init();
|
|
314
|
+
const metadata = {
|
|
315
|
+
project_name: projectName,
|
|
316
|
+
version: '1.0.0',
|
|
317
|
+
created_at: new Date().toISOString(),
|
|
318
|
+
updated_at: new Date().toISOString(),
|
|
319
|
+
description,
|
|
320
|
+
};
|
|
321
|
+
const projectFile = {
|
|
322
|
+
$schema: 'https://octie.dev/schemas/project-v1.json',
|
|
323
|
+
version: '1.0.0',
|
|
324
|
+
format: 'octie-project',
|
|
325
|
+
metadata,
|
|
326
|
+
tasks: {},
|
|
327
|
+
edges: [],
|
|
328
|
+
indexes: {
|
|
329
|
+
byStatus: {
|
|
330
|
+
ready: [],
|
|
331
|
+
in_progress: [],
|
|
332
|
+
in_review: [],
|
|
333
|
+
completed: [],
|
|
334
|
+
blocked: [],
|
|
335
|
+
},
|
|
336
|
+
byPriority: {
|
|
337
|
+
top: [],
|
|
338
|
+
second: [],
|
|
339
|
+
later: [],
|
|
340
|
+
},
|
|
341
|
+
rootTasks: [],
|
|
342
|
+
orphanTasks: [],
|
|
343
|
+
searchText: {},
|
|
344
|
+
files: {},
|
|
345
|
+
},
|
|
346
|
+
};
|
|
347
|
+
await this._writer.write(this.projectFilePath, projectFile, {
|
|
348
|
+
createBackup: false, // No backup on initial create
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* List backup files
|
|
353
|
+
* @returns Array of backup file paths
|
|
354
|
+
*/
|
|
355
|
+
async listBackups() {
|
|
356
|
+
const { promises: fs } = await import('node:fs');
|
|
357
|
+
const backups = [];
|
|
358
|
+
try {
|
|
359
|
+
const files = await fs.readdir(this.octieDirPath);
|
|
360
|
+
for (const file of files) {
|
|
361
|
+
if (file.startsWith(`${this._projectFileName}.bak`)) {
|
|
362
|
+
backups.push(join(this.octieDirPath, file));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
// Directory might not exist yet
|
|
368
|
+
}
|
|
369
|
+
return backups.sort().reverse(); // Newest first
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Restore from latest backup
|
|
373
|
+
* @throws {FileOperationError} If no backup exists
|
|
374
|
+
*/
|
|
375
|
+
async restoreFromBackup() {
|
|
376
|
+
const backups = await this.listBackups();
|
|
377
|
+
if (backups.length === 0) {
|
|
378
|
+
throw new FileOperationError('No backup files found', this.backupFilePath);
|
|
379
|
+
}
|
|
380
|
+
const latestBackup = backups[0];
|
|
381
|
+
if (!latestBackup) {
|
|
382
|
+
throw new FileOperationError('No backup files found', this.backupFilePath);
|
|
383
|
+
}
|
|
384
|
+
try {
|
|
385
|
+
// Copy backup to main file
|
|
386
|
+
const { promises: fs } = await import('node:fs');
|
|
387
|
+
await fs.copyFile(latestBackup, this.projectFilePath);
|
|
388
|
+
}
|
|
389
|
+
catch (error) {
|
|
390
|
+
throw new FileOperationError(`Failed to restore from backup: ${error instanceof Error ? error.message : String(error)}`, latestBackup);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Get project path for current directory
|
|
396
|
+
* Searches upward from current directory for .octie folder
|
|
397
|
+
* @returns Project directory path or undefined if not found
|
|
398
|
+
*/
|
|
399
|
+
export async function findProjectPath(startDir = process.cwd()) {
|
|
400
|
+
const { resolve } = await import('node:path');
|
|
401
|
+
const { promises: fs } = await import('node:fs');
|
|
402
|
+
let currentDir = resolve(startDir);
|
|
403
|
+
// Search upward until root directory
|
|
404
|
+
while (true) {
|
|
405
|
+
const octieDir = join(currentDir, OCTIE_DIR_NAME);
|
|
406
|
+
const projectFile = join(octieDir, DEFAULT_PROJECT_FILE);
|
|
407
|
+
try {
|
|
408
|
+
await fs.access(projectFile);
|
|
409
|
+
return currentDir;
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
// Not found, continue searching
|
|
413
|
+
}
|
|
414
|
+
// Move to parent directory
|
|
415
|
+
const parentDir = resolve(currentDir, '..');
|
|
416
|
+
// Check if we've reached the root
|
|
417
|
+
if (parentDir === currentDir) {
|
|
418
|
+
return undefined;
|
|
419
|
+
}
|
|
420
|
+
currentDir = parentDir;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
//# sourceMappingURL=file-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-store.js","sourceRoot":"","sources":["../../../src/core/storage/file-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index Manager for fast task lookups
|
|
3
|
+
*
|
|
4
|
+
* Maintains pre-computed indexes for efficient queries:
|
|
5
|
+
* - Status-based grouping (byStatus)
|
|
6
|
+
* - Priority-based grouping (byPriority)
|
|
7
|
+
* - Root tasks (no incoming edges)
|
|
8
|
+
* - Orphan tasks (no edges)
|
|
9
|
+
* - Full-text search index (inverted index)
|
|
10
|
+
* - File reference index
|
|
11
|
+
*
|
|
12
|
+
* Provides O(1) incremental updates and O(n) full rebuild.
|
|
13
|
+
*
|
|
14
|
+
* @module core/storage
|
|
15
|
+
*/
|
|
16
|
+
import type { TaskNode, TaskStatus, TaskPriority, ProjectIndexes } from '../../types/index.js';
|
|
17
|
+
import { TaskGraphStore } from '../graph/index.js';
|
|
18
|
+
/**
|
|
19
|
+
* Index Manager class
|
|
20
|
+
*
|
|
21
|
+
* Maintains indexes for fast task queries and filtering.
|
|
22
|
+
*/
|
|
23
|
+
export declare class IndexManager {
|
|
24
|
+
/** Tasks grouped by status */
|
|
25
|
+
private _byStatus;
|
|
26
|
+
/** Tasks grouped by priority */
|
|
27
|
+
private _byPriority;
|
|
28
|
+
/** Full-text search index (term -> task IDs) */
|
|
29
|
+
private _searchText;
|
|
30
|
+
/** File reference index (file path -> task IDs) */
|
|
31
|
+
private _files;
|
|
32
|
+
/** Root tasks (no incoming edges) - cached */
|
|
33
|
+
private _rootTasks;
|
|
34
|
+
/** Orphan tasks (no edges) - cached */
|
|
35
|
+
private _orphanTasks;
|
|
36
|
+
/** Cached result object */
|
|
37
|
+
private _cachedIndexes;
|
|
38
|
+
/**
|
|
39
|
+
* Create a new IndexManager
|
|
40
|
+
*/
|
|
41
|
+
constructor();
|
|
42
|
+
/**
|
|
43
|
+
* Incremental update for a single task
|
|
44
|
+
* Removes old task from indexes and adds new version
|
|
45
|
+
* O(1) operation for most cases
|
|
46
|
+
*
|
|
47
|
+
* @param task - New or updated task
|
|
48
|
+
* @param oldTask - Previous task state (for removal from old indexes)
|
|
49
|
+
* @param graph - TaskGraphStore for edge information
|
|
50
|
+
*/
|
|
51
|
+
updateTask(task: TaskNode, oldTask: TaskNode | null, graph: TaskGraphStore): void;
|
|
52
|
+
/**
|
|
53
|
+
* Remove task from indexes
|
|
54
|
+
* @param task - Task to remove
|
|
55
|
+
* @private
|
|
56
|
+
*/
|
|
57
|
+
private _removeTask;
|
|
58
|
+
/**
|
|
59
|
+
* Add task to indexes
|
|
60
|
+
* @param task - Task to add
|
|
61
|
+
* @param graph - TaskGraphStore for edge information
|
|
62
|
+
* @private
|
|
63
|
+
*/
|
|
64
|
+
private _addTask;
|
|
65
|
+
/**
|
|
66
|
+
* Update root/orphan status for a task
|
|
67
|
+
* @param taskId - Task ID to check
|
|
68
|
+
* @param graph - TaskGraphStore for edge information
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
private _updateRootOrphanStatus;
|
|
72
|
+
/**
|
|
73
|
+
* Rebuild all indexes from scratch
|
|
74
|
+
* O(n) operation where n is the number of tasks
|
|
75
|
+
*
|
|
76
|
+
* @param tasks - Map of all tasks
|
|
77
|
+
* @param graph - TaskGraphStore for edge information
|
|
78
|
+
*/
|
|
79
|
+
rebuildIndexes(tasks: Map<string, TaskNode>, graph: TaskGraphStore): void;
|
|
80
|
+
/**
|
|
81
|
+
* Get task IDs by status
|
|
82
|
+
* @param status - Task status to filter by
|
|
83
|
+
* @returns Array of task IDs
|
|
84
|
+
*/
|
|
85
|
+
getByStatus(status: TaskStatus): string[];
|
|
86
|
+
/**
|
|
87
|
+
* Get task IDs by priority
|
|
88
|
+
* @param priority - Task priority to filter by
|
|
89
|
+
* @returns Array of task IDs
|
|
90
|
+
*/
|
|
91
|
+
getByPriority(priority: TaskPriority): string[];
|
|
92
|
+
/**
|
|
93
|
+
* Search tasks by text query
|
|
94
|
+
* @param query - Search query (will be tokenized)
|
|
95
|
+
* @returns Array of task IDs matching any token
|
|
96
|
+
*/
|
|
97
|
+
search(query: string): string[];
|
|
98
|
+
/**
|
|
99
|
+
* Get task IDs by related file
|
|
100
|
+
* @param filePath - File path to search for
|
|
101
|
+
* @returns Array of task IDs
|
|
102
|
+
*/
|
|
103
|
+
getByFile(filePath: string): string[];
|
|
104
|
+
/**
|
|
105
|
+
* Get root tasks (no incoming edges)
|
|
106
|
+
* @returns Array of task IDs
|
|
107
|
+
*/
|
|
108
|
+
getRootTasks(): string[];
|
|
109
|
+
/**
|
|
110
|
+
* Get orphan tasks (no edges)
|
|
111
|
+
* @returns Array of task IDs
|
|
112
|
+
*/
|
|
113
|
+
getOrphanTasks(): string[];
|
|
114
|
+
/**
|
|
115
|
+
* Get all indexes as a ProjectIndexes object
|
|
116
|
+
* Cached result - only recomputed if indexes changed
|
|
117
|
+
*
|
|
118
|
+
* @returns ProjectIndexes interface
|
|
119
|
+
*/
|
|
120
|
+
getIndexes(): ProjectIndexes;
|
|
121
|
+
/**
|
|
122
|
+
* Clear all indexes
|
|
123
|
+
*/
|
|
124
|
+
clear(): void;
|
|
125
|
+
/**
|
|
126
|
+
* Get index statistics (for debugging)
|
|
127
|
+
* @returns Statistics about the indexes
|
|
128
|
+
*/
|
|
129
|
+
getStats(): {
|
|
130
|
+
statusCounts: Record<TaskStatus, number>;
|
|
131
|
+
priorityCounts: Record<TaskPriority, number>;
|
|
132
|
+
searchTermsCount: number;
|
|
133
|
+
fileRefCount: number;
|
|
134
|
+
rootTasksCount: number;
|
|
135
|
+
orphanTasksCount: number;
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=indexer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexer.d.ts","sourceRoot":"","sources":["../../../src/core/storage/indexer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC/F,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD;;;;GAIG;AACH,qBAAa,YAAY;IACvB,8BAA8B;IAC9B,OAAO,CAAC,SAAS,CAA+B;IAEhD,gCAAgC;IAChC,OAAO,CAAC,WAAW,CAAiC;IAEpD,gDAAgD;IAChD,OAAO,CAAC,WAAW,CAA2B;IAE9C,mDAAmD;IACnD,OAAO,CAAC,MAAM,CAA2B;IAEzC,8CAA8C;IAC9C,OAAO,CAAC,UAAU,CAAc;IAEhC,uCAAuC;IACvC,OAAO,CAAC,YAAY,CAAc;IAElC,2BAA2B;IAC3B,OAAO,CAAC,cAAc,CAAwB;IAE9C;;OAEG;;IAuBH;;;;;;;;OAQG;IACH,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI;IAajF;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAgCnB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;IAmChB;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IAmB/B;;;;;;OAMG;IACH,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI;IA6BzE;;;;OAIG;IACH,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE;IAIzC;;;;OAIG;IACH,aAAa,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,EAAE;IAI/C;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAgB/B;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;IAIrC;;;OAGG;IACH,YAAY,IAAI,MAAM,EAAE;IAIxB;;;OAGG;IACH,cAAc,IAAI,MAAM,EAAE;IAI1B;;;;;OAKG;IACH,UAAU,IAAI,cAAc;IAwC5B;;OAEG;IACH,KAAK,IAAI,IAAI;IAqBb;;;OAGG;IACH,QAAQ,IAAI;QACV,YAAY,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACzC,cAAc,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAC7C,gBAAgB,EAAE,MAAM,CAAC;QACzB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;KAC1B;CAgCF"}
|