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.
Files changed (162) hide show
  1. package/README.md +523 -0
  2. package/dist/cli/commands/approve.d.ts +27 -0
  3. package/dist/cli/commands/approve.d.ts.map +1 -0
  4. package/dist/cli/commands/approve.js +119 -0
  5. package/dist/cli/commands/approve.js.map +1 -0
  6. package/dist/cli/commands/batch.d.ts +15 -0
  7. package/dist/cli/commands/batch.d.ts.map +1 -0
  8. package/dist/cli/commands/batch.js +521 -0
  9. package/dist/cli/commands/batch.js.map +1 -0
  10. package/dist/cli/commands/create.d.ts +9 -0
  11. package/dist/cli/commands/create.d.ts.map +1 -0
  12. package/dist/cli/commands/create.js +321 -0
  13. package/dist/cli/commands/create.js.map +1 -0
  14. package/dist/cli/commands/delete.d.ts +9 -0
  15. package/dist/cli/commands/delete.d.ts.map +1 -0
  16. package/dist/cli/commands/delete.js +143 -0
  17. package/dist/cli/commands/delete.js.map +1 -0
  18. package/dist/cli/commands/export.d.ts +9 -0
  19. package/dist/cli/commands/export.d.ts.map +1 -0
  20. package/dist/cli/commands/export.js +66 -0
  21. package/dist/cli/commands/export.js.map +1 -0
  22. package/dist/cli/commands/find.d.ts +16 -0
  23. package/dist/cli/commands/find.d.ts.map +1 -0
  24. package/dist/cli/commands/find.js +252 -0
  25. package/dist/cli/commands/find.js.map +1 -0
  26. package/dist/cli/commands/get.d.ts +9 -0
  27. package/dist/cli/commands/get.d.ts.map +1 -0
  28. package/dist/cli/commands/get.js +74 -0
  29. package/dist/cli/commands/get.js.map +1 -0
  30. package/dist/cli/commands/graph.d.ts +9 -0
  31. package/dist/cli/commands/graph.d.ts.map +1 -0
  32. package/dist/cli/commands/graph.js +200 -0
  33. package/dist/cli/commands/graph.js.map +1 -0
  34. package/dist/cli/commands/import.d.ts +9 -0
  35. package/dist/cli/commands/import.d.ts.map +1 -0
  36. package/dist/cli/commands/import.js +807 -0
  37. package/dist/cli/commands/import.js.map +1 -0
  38. package/dist/cli/commands/init.d.ts +9 -0
  39. package/dist/cli/commands/init.d.ts.map +1 -0
  40. package/dist/cli/commands/init.js +57 -0
  41. package/dist/cli/commands/init.js.map +1 -0
  42. package/dist/cli/commands/list.d.ts +9 -0
  43. package/dist/cli/commands/list.d.ts.map +1 -0
  44. package/dist/cli/commands/list.js +175 -0
  45. package/dist/cli/commands/list.js.map +1 -0
  46. package/dist/cli/commands/merge.d.ts +9 -0
  47. package/dist/cli/commands/merge.d.ts.map +1 -0
  48. package/dist/cli/commands/merge.js +113 -0
  49. package/dist/cli/commands/merge.js.map +1 -0
  50. package/dist/cli/commands/serve.d.ts +9 -0
  51. package/dist/cli/commands/serve.d.ts.map +1 -0
  52. package/dist/cli/commands/serve.js +94 -0
  53. package/dist/cli/commands/serve.js.map +1 -0
  54. package/dist/cli/commands/update.d.ts +9 -0
  55. package/dist/cli/commands/update.d.ts.map +1 -0
  56. package/dist/cli/commands/update.js +423 -0
  57. package/dist/cli/commands/update.js.map +1 -0
  58. package/dist/cli/commands/wire.d.ts +15 -0
  59. package/dist/cli/commands/wire.d.ts.map +1 -0
  60. package/dist/cli/commands/wire.js +164 -0
  61. package/dist/cli/commands/wire.js.map +1 -0
  62. package/dist/cli/index.d.ts +7 -0
  63. package/dist/cli/index.d.ts.map +1 -0
  64. package/dist/cli/index.js +100 -0
  65. package/dist/cli/index.js.map +1 -0
  66. package/dist/cli/output/json.d.ts +16 -0
  67. package/dist/cli/output/json.d.ts.map +1 -0
  68. package/dist/cli/output/json.js +29 -0
  69. package/dist/cli/output/json.js.map +1 -0
  70. package/dist/cli/output/markdown.d.ts +15 -0
  71. package/dist/cli/output/markdown.d.ts.map +1 -0
  72. package/dist/cli/output/markdown.js +206 -0
  73. package/dist/cli/output/markdown.js.map +1 -0
  74. package/dist/cli/output/table.d.ts +23 -0
  75. package/dist/cli/output/table.d.ts.map +1 -0
  76. package/dist/cli/output/table.js +150 -0
  77. package/dist/cli/output/table.js.map +1 -0
  78. package/dist/cli/utils/helpers.d.ts +126 -0
  79. package/dist/cli/utils/helpers.d.ts.map +1 -0
  80. package/dist/cli/utils/helpers.js +325 -0
  81. package/dist/cli/utils/helpers.js.map +1 -0
  82. package/dist/core/graph/algorithms.d.ts +11 -0
  83. package/dist/core/graph/algorithms.d.ts.map +1 -0
  84. package/dist/core/graph/algorithms.js +14 -0
  85. package/dist/core/graph/algorithms.js.map +1 -0
  86. package/dist/core/graph/cycle.d.ts +155 -0
  87. package/dist/core/graph/cycle.d.ts.map +1 -0
  88. package/dist/core/graph/cycle.js +297 -0
  89. package/dist/core/graph/cycle.js.map +1 -0
  90. package/dist/core/graph/index.d.ts +223 -0
  91. package/dist/core/graph/index.d.ts.map +1 -0
  92. package/dist/core/graph/index.js +475 -0
  93. package/dist/core/graph/index.js.map +1 -0
  94. package/dist/core/graph/operations.d.ts +240 -0
  95. package/dist/core/graph/operations.d.ts.map +1 -0
  96. package/dist/core/graph/operations.js +503 -0
  97. package/dist/core/graph/operations.js.map +1 -0
  98. package/dist/core/graph/sort.d.ts +76 -0
  99. package/dist/core/graph/sort.d.ts.map +1 -0
  100. package/dist/core/graph/sort.js +254 -0
  101. package/dist/core/graph/sort.js.map +1 -0
  102. package/dist/core/graph/traversal.d.ts +122 -0
  103. package/dist/core/graph/traversal.d.ts.map +1 -0
  104. package/dist/core/graph/traversal.js +336 -0
  105. package/dist/core/graph/traversal.js.map +1 -0
  106. package/dist/core/models/task-node.d.ts +328 -0
  107. package/dist/core/models/task-node.d.ts.map +1 -0
  108. package/dist/core/models/task-node.js +1090 -0
  109. package/dist/core/models/task-node.js.map +1 -0
  110. package/dist/core/registry/index.d.ts +102 -0
  111. package/dist/core/registry/index.d.ts.map +1 -0
  112. package/dist/core/registry/index.js +249 -0
  113. package/dist/core/registry/index.js.map +1 -0
  114. package/dist/core/registry/root-guard.d.ts +19 -0
  115. package/dist/core/registry/root-guard.d.ts.map +1 -0
  116. package/dist/core/registry/root-guard.js +28 -0
  117. package/dist/core/registry/root-guard.js.map +1 -0
  118. package/dist/core/storage/atomic-write.d.ts +181 -0
  119. package/dist/core/storage/atomic-write.d.ts.map +1 -0
  120. package/dist/core/storage/atomic-write.js +379 -0
  121. package/dist/core/storage/atomic-write.js.map +1 -0
  122. package/dist/core/storage/file-store.d.ts +148 -0
  123. package/dist/core/storage/file-store.d.ts.map +1 -0
  124. package/dist/core/storage/file-store.js +423 -0
  125. package/dist/core/storage/file-store.js.map +1 -0
  126. package/dist/core/storage/indexer.d.ts +138 -0
  127. package/dist/core/storage/indexer.d.ts.map +1 -0
  128. package/dist/core/storage/indexer.js +350 -0
  129. package/dist/core/storage/indexer.js.map +1 -0
  130. package/dist/core/utils/status-helpers.d.ts +59 -0
  131. package/dist/core/utils/status-helpers.d.ts.map +1 -0
  132. package/dist/core/utils/status-helpers.js +149 -0
  133. package/dist/core/utils/status-helpers.js.map +1 -0
  134. package/dist/index.d.ts +10 -0
  135. package/dist/index.d.ts.map +1 -0
  136. package/dist/index.js +10 -0
  137. package/dist/index.js.map +1 -0
  138. package/dist/types/index.d.ts +504 -0
  139. package/dist/types/index.d.ts.map +1 -0
  140. package/dist/types/index.js +182 -0
  141. package/dist/types/index.js.map +1 -0
  142. package/dist/web/routes/graph.d.ts +17 -0
  143. package/dist/web/routes/graph.d.ts.map +1 -0
  144. package/dist/web/routes/graph.js +277 -0
  145. package/dist/web/routes/graph.js.map +1 -0
  146. package/dist/web/routes/projects.d.ts +14 -0
  147. package/dist/web/routes/projects.d.ts.map +1 -0
  148. package/dist/web/routes/projects.js +102 -0
  149. package/dist/web/routes/projects.js.map +1 -0
  150. package/dist/web/routes/tasks.d.ts +17 -0
  151. package/dist/web/routes/tasks.d.ts.map +1 -0
  152. package/dist/web/routes/tasks.js +538 -0
  153. package/dist/web/routes/tasks.js.map +1 -0
  154. package/dist/web/server.d.ts +121 -0
  155. package/dist/web/server.d.ts.map +1 -0
  156. package/dist/web/server.js +389 -0
  157. package/dist/web/server.js.map +1 -0
  158. package/dist/web-ui/assets/index-BB0qvF1y.css +1 -0
  159. package/dist/web-ui/assets/index-Vmm72oKY.js +34 -0
  160. package/dist/web-ui/index.html +14 -0
  161. package/dist/web-ui/vite.svg +1 -0
  162. package/package.json +94 -0
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Core type definitions for Octie task management system
3
+ *
4
+ * This module defines all TypeScript interfaces and types used throughout the system.
5
+ * @module types
6
+ */
7
+ /**
8
+ * Error code to HTTP status code mapping
9
+ * Used by API error handler to return appropriate status codes
10
+ */
11
+ export const ERROR_STATUS_MAP = {
12
+ // Client errors (4xx)
13
+ TASK_NOT_FOUND: 404,
14
+ PROJECT_NOT_FOUND: 404,
15
+ VALIDATION_ERROR: 400,
16
+ ATOMIC_TASK_VIOLATION: 400,
17
+ INVALID_ARGUMENT: 400,
18
+ INVALID_TASK_ID: 400,
19
+ CIRCULAR_DEPENDENCY: 400,
20
+ DUPLICATE_TASK: 409,
21
+ // Server errors (5xx)
22
+ FILE_OPERATION_ERROR: 500,
23
+ STORAGE_ERROR: 500,
24
+ INTERNAL_ERROR: 500,
25
+ };
26
+ /**
27
+ * Error code to suggestion mapping
28
+ * Provides actionable recovery steps for each error type
29
+ */
30
+ export const ERROR_SUGGESTIONS = {
31
+ TASK_NOT_FOUND: 'Use `octie list` to see all available tasks and their IDs.',
32
+ PROJECT_NOT_FOUND: 'Run `octie init` to create a new project or use `--project <path>` to specify the project directory.',
33
+ VALIDATION_ERROR: 'Check the input format and ensure all required fields are provided.',
34
+ ATOMIC_TASK_VIOLATION: 'Split the task into smaller, focused tasks with specific deliverables.',
35
+ INVALID_ARGUMENT: 'Check the command syntax with `octie <command> --help`.',
36
+ INVALID_TASK_ID: 'Task IDs must be valid UUIDs. Use `octie list` to find the correct task ID.',
37
+ CIRCULAR_DEPENDENCY: 'Remove one of the edges in the cycle using `octie update <id> --unblock <blocker_id>`.',
38
+ DUPLICATE_TASK: 'Use `octie list --search <query>` to find existing similar tasks.',
39
+ FILE_OPERATION_ERROR: 'Check file permissions and ensure the .octie directory is writable.',
40
+ STORAGE_ERROR: 'Try restoring from backup with `octie import --file .octie/project.json.bak`.',
41
+ INTERNAL_ERROR: 'Run with --verbose flag for more details or check the logs.',
42
+ };
43
+ /**
44
+ * Custom error base class
45
+ * All Octie-specific errors extend this class
46
+ */
47
+ export class OctieError extends Error {
48
+ code;
49
+ /** Optional suggestion for how to resolve the error */
50
+ suggestion;
51
+ /** HTTP status code for API responses */
52
+ statusCode;
53
+ constructor(message, code, suggestion) {
54
+ super(message);
55
+ this.code = code;
56
+ this.name = 'OctieError';
57
+ this.suggestion = suggestion ?? ERROR_SUGGESTIONS[code];
58
+ this.statusCode = ERROR_STATUS_MAP[code] ?? 500;
59
+ }
60
+ }
61
+ /**
62
+ * Error thrown when a task is not found
63
+ */
64
+ export class TaskNotFoundError extends OctieError {
65
+ constructor(taskId) {
66
+ super(`Task with ID '${taskId}' not found`, 'TASK_NOT_FOUND', `Use \`octie list\` to see all available tasks. The ID '${taskId}' may be incorrect or the task may have been deleted.`);
67
+ this.name = 'TaskNotFoundError';
68
+ }
69
+ }
70
+ /**
71
+ * Error thrown when a short UUID prefix matches multiple tasks
72
+ */
73
+ export class AmbiguousIdError extends OctieError {
74
+ constructor(prefix, matchingIds) {
75
+ super(`ID prefix '${prefix}' matches multiple tasks: ${matchingIds.map(id => id.substring(0, 7)).join(', ')}. Please provide more characters.`, 'AMBIGUOUS_ID', `The ID prefix '${prefix}' is too short and matches ${matchingIds.length} tasks. Provide more characters (up to the full UUID) to uniquely identify a task.`);
76
+ this.name = 'AmbiguousIdError';
77
+ }
78
+ }
79
+ /**
80
+ * Error thrown when a project is not found
81
+ */
82
+ export class ProjectNotFoundError extends OctieError {
83
+ constructor(path) {
84
+ super(path ? `No Octie project found at '${path}'` : 'No Octie project found', 'PROJECT_NOT_FOUND', 'Run `octie init` to create a new project in the current directory, or use `--project <path>` to specify a different project directory.');
85
+ this.name = 'ProjectNotFoundError';
86
+ }
87
+ }
88
+ /**
89
+ * Error thrown when a circular dependency is detected
90
+ */
91
+ export class CircularDependencyError extends OctieError {
92
+ cycleNodes;
93
+ constructor(cycleNodes) {
94
+ super(`Circular dependency detected: ${cycleNodes.join(' -> ')}`, 'CIRCULAR_DEPENDENCY', `Break the cycle by removing one of the dependencies. Use \`octie update ${cycleNodes[0]} --unblock ${cycleNodes[cycleNodes.length - 1]}\` or restructure your task graph.`);
95
+ this.cycleNodes = cycleNodes;
96
+ this.name = 'CircularDependencyError';
97
+ }
98
+ }
99
+ /**
100
+ * Error thrown when file operations fail
101
+ */
102
+ export class FileOperationError extends OctieError {
103
+ filePath;
104
+ constructor(message, filePath) {
105
+ super(`${message}: ${filePath}`, 'FILE_OPERATION_ERROR', `Check file permissions and ensure the path is correct. If the file is corrupted, try restoring from backup: \`octie import --file .octie/project.json.bak\``);
106
+ this.filePath = filePath;
107
+ this.name = 'FileOperationError';
108
+ }
109
+ }
110
+ /**
111
+ * Error thrown when validation fails
112
+ */
113
+ export class ValidationError extends OctieError {
114
+ field;
115
+ constructor(message, field) {
116
+ super(message, 'VALIDATION_ERROR', field ? `Check the '${field}' field and ensure it meets the requirements.` : 'Check the input format and ensure all required fields are provided.');
117
+ this.field = field;
118
+ this.name = 'ValidationError';
119
+ }
120
+ }
121
+ /**
122
+ * Error thrown when atomic task validation fails
123
+ */
124
+ export class AtomicTaskViolationError extends ValidationError {
125
+ violations;
126
+ constructor(message, violations) {
127
+ super(message, 'ATOMIC_TASK_VIOLATION');
128
+ this.violations = violations;
129
+ this.name = 'AtomicTaskViolationError';
130
+ // Override suggestion with specific violations
131
+ this.suggestion = `Task violates atomic task requirements:\n${violations.map(v => ` • ${v}`).join('\n')}\n\nSplit into smaller tasks or make the task more specific.`;
132
+ }
133
+ }
134
+ /**
135
+ * Error thrown when an invalid argument is provided
136
+ */
137
+ export class InvalidArgumentError extends OctieError {
138
+ constructor(message, suggestion) {
139
+ super(message, 'INVALID_ARGUMENT', suggestion ?? 'Check the command syntax with `octie <command> --help`.');
140
+ this.name = 'InvalidArgumentError';
141
+ }
142
+ }
143
+ /**
144
+ * Error thrown when a duplicate is detected
145
+ */
146
+ export class DuplicateTaskError extends OctieError {
147
+ constructor(identifier) {
148
+ super(`Task already exists: ${identifier}`, 'DUPLICATE_TASK', 'Use `octie list --search <query>` to find the existing task, or use a different identifier.');
149
+ this.name = 'DuplicateTaskError';
150
+ }
151
+ }
152
+ /**
153
+ * Error thrown when storage operations fail
154
+ */
155
+ export class StorageError extends OctieError {
156
+ constructor(message, suggestion) {
157
+ super(message, 'STORAGE_ERROR', suggestion ?? 'Try restoring from backup or re-initialize the project.');
158
+ this.name = 'StorageError';
159
+ }
160
+ }
161
+ /**
162
+ * Immutability violation error
163
+ * Thrown when attempting to modify completed items that are immutable
164
+ *
165
+ * Per the status refactor spec:
166
+ * - success_criteria items: Cannot be unchecked or deleted once completed
167
+ * - deliverables items: Cannot be unchecked or deleted once completed
168
+ * - need_fix items: Cannot be deleted or unmarked once completed
169
+ */
170
+ export class ImmutabilityViolationError extends ValidationError {
171
+ /** ID of the item that cannot be modified */
172
+ itemId;
173
+ /** Type of the item (success_criterion, deliverable, need_fix) */
174
+ itemType;
175
+ constructor(message, itemId, itemType) {
176
+ super(message, itemType);
177
+ this.name = 'ImmutabilityViolationError';
178
+ this.itemId = itemId;
179
+ this.itemType = itemType;
180
+ }
181
+ }
182
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Graph Routes - Graph analysis and validation endpoints
3
+ *
4
+ * Provides endpoints for graph structure analysis, topological sorting,
5
+ * cycle detection, critical path analysis, and project statistics.
6
+ *
7
+ * @module web/routes/graph
8
+ */
9
+ import type { Router } from 'express';
10
+ import type { TaskGraphStore } from '../../core/graph/index.js';
11
+ /**
12
+ * Register graph routes
13
+ * @param router - Express Router instance
14
+ * @param getGraph - Function to get the current graph instance
15
+ */
16
+ export declare function registerGraphRoutes(router: Router, getGraph: () => TaskGraphStore | null): void;
17
+ //# sourceMappingURL=graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../../src/web/routes/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAqB,MAAM,EAAE,MAAM,SAAS,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAmDhE;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,cAAc,GAAG,IAAI,GACpC,IAAI,CAoQN"}
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Graph Routes - Graph analysis and validation endpoints
3
+ *
4
+ * Provides endpoints for graph structure analysis, topological sorting,
5
+ * cycle detection, critical path analysis, and project statistics.
6
+ *
7
+ * @module web/routes/graph
8
+ */
9
+ import { topologicalSort, findCriticalPath, isValidDAG } from '../../core/graph/sort.js';
10
+ import { detectCycle, hasCycle, getCycleStatistics } from '../../core/graph/cycle.js';
11
+ import { TaskStorage } from '../../core/storage/file-store.js';
12
+ import { ERROR_SUGGESTIONS } from '../../types/index.js';
13
+ /**
14
+ * Async error handler wrapper
15
+ * Catches async errors and passes them to Express error handling
16
+ */
17
+ function asyncHandler(fn) {
18
+ return (req, res, next) => {
19
+ Promise.resolve(fn(req, res)).catch(next);
20
+ };
21
+ }
22
+ /**
23
+ * Send successful API response
24
+ */
25
+ function sendSuccess(res, data, status = 200) {
26
+ res.status(status).json({
27
+ success: true,
28
+ data,
29
+ timestamp: new Date().toISOString(),
30
+ });
31
+ }
32
+ /**
33
+ * Send error API response
34
+ */
35
+ function sendError(res, code, message, status = 400, details, suggestion) {
36
+ res.status(status).json({
37
+ success: false,
38
+ error: {
39
+ code,
40
+ message,
41
+ suggestion: suggestion ?? ERROR_SUGGESTIONS[code],
42
+ details,
43
+ },
44
+ timestamp: new Date().toISOString(),
45
+ });
46
+ }
47
+ /**
48
+ * Register graph routes
49
+ * @param router - Express Router instance
50
+ * @param getGraph - Function to get the current graph instance
51
+ */
52
+ export function registerGraphRoutes(router, getGraph) {
53
+ // Cache for loaded project graphs
54
+ const graphCache = new Map();
55
+ /**
56
+ * Get graph for a specific project path, using cache when possible
57
+ */
58
+ async function getProjectGraph(projectPath) {
59
+ if (!projectPath) {
60
+ return getGraph();
61
+ }
62
+ // Check cache first
63
+ const cached = graphCache.get(projectPath);
64
+ if (cached) {
65
+ return cached;
66
+ }
67
+ // Load the project
68
+ try {
69
+ const storage = new TaskStorage({ projectDir: projectPath });
70
+ const graph = await storage.load();
71
+ graphCache.set(projectPath, graph);
72
+ return graph;
73
+ }
74
+ catch {
75
+ return null;
76
+ }
77
+ }
78
+ /**
79
+ * Extract project path from query params
80
+ */
81
+ function getProjectPath(req) {
82
+ const project = req.query.project;
83
+ return typeof project === 'string' ? project : undefined;
84
+ }
85
+ /**
86
+ * GET /api/graph
87
+ * Get full graph structure including all tasks and edges
88
+ */
89
+ router.get('/api/graph', asyncHandler(async (req, res) => {
90
+ const projectPath = getProjectPath(req);
91
+ const graph = await getProjectGraph(projectPath);
92
+ if (!graph) {
93
+ return sendError(res, 'GRAPH_NOT_LOADED', projectPath ? `Project not found: ${projectPath}` : 'Graph not loaded', 500);
94
+ }
95
+ // Serialize graph to JSON format
96
+ const graphData = graph.toJSON();
97
+ // Convert nodes from object (keyed by ID) to array for frontend
98
+ const nodesArray = Object.values(graphData.nodes);
99
+ // Get valid node IDs
100
+ const validNodeIds = new Set(nodesArray.map(n => n.id));
101
+ // Filter edges to only include valid node references
102
+ const filterEdges = (edges) => {
103
+ const filtered = {};
104
+ for (const [sourceId, targetIds] of Object.entries(edges)) {
105
+ // Skip if source is invalid
106
+ if (!sourceId || sourceId === 'null' || sourceId === 'undefined' || !validNodeIds.has(sourceId)) {
107
+ continue;
108
+ }
109
+ // Filter targets to only valid nodes
110
+ const validTargets = (targetIds || []).filter(targetId => targetId && targetId !== 'null' && targetId !== 'undefined' && validNodeIds.has(targetId));
111
+ if (validTargets.length > 0) {
112
+ filtered[sourceId] = validTargets;
113
+ }
114
+ }
115
+ return filtered;
116
+ };
117
+ return sendSuccess(res, {
118
+ metadata: graphData.metadata,
119
+ nodes: nodesArray,
120
+ outgoingEdges: filterEdges(graphData.outgoingEdges),
121
+ incomingEdges: filterEdges(graphData.incomingEdges),
122
+ });
123
+ }));
124
+ /**
125
+ * GET /api/graph/topology
126
+ * Get topological order of tasks
127
+ */
128
+ router.get('/api/graph/topology', asyncHandler(async (req, res) => {
129
+ const projectPath = getProjectPath(req);
130
+ const graph = await getProjectGraph(projectPath);
131
+ if (!graph) {
132
+ return sendError(res, 'GRAPH_NOT_LOADED', projectPath ? `Project not found: ${projectPath}` : 'Graph not loaded', 500);
133
+ }
134
+ const result = topologicalSort(graph);
135
+ if (result.hasCycle) {
136
+ return sendSuccess(res, {
137
+ hasCycle: true,
138
+ cycleNodes: result.cycleNodes,
139
+ message: 'Graph contains cycles, topological sort is not valid for cyclic graphs',
140
+ });
141
+ }
142
+ return sendSuccess(res, {
143
+ hasCycle: false,
144
+ sorted: result.sorted,
145
+ taskCount: result.sorted.length,
146
+ });
147
+ }));
148
+ /**
149
+ * POST /api/graph/validate
150
+ * Validate graph structure and check for cycles
151
+ */
152
+ router.post('/api/graph/validate', asyncHandler(async (req, res) => {
153
+ const projectPath = getProjectPath(req);
154
+ const graph = await getProjectGraph(projectPath);
155
+ if (!graph) {
156
+ return sendError(res, 'GRAPH_NOT_LOADED', projectPath ? `Project not found: ${projectPath}` : 'Graph not loaded', 500);
157
+ }
158
+ // Check if graph is valid (acyclic)
159
+ const isValid = isValidDAG(graph);
160
+ // Get cycle statistics if graph has cycles
161
+ let cycleStats = null;
162
+ if (!isValid) {
163
+ cycleStats = getCycleStatistics(graph);
164
+ }
165
+ return sendSuccess(res, {
166
+ isValid,
167
+ hasCycle: !isValid,
168
+ cycleStats,
169
+ message: isValid
170
+ ? 'Graph structure is valid (acyclic)'
171
+ : 'Graph contains cycles and is not a valid DAG',
172
+ });
173
+ }));
174
+ /**
175
+ * GET /api/graph/cycles
176
+ * Detect and return all cycles in the graph
177
+ */
178
+ router.get('/api/graph/cycles', asyncHandler(async (req, res) => {
179
+ const projectPath = getProjectPath(req);
180
+ const graph = await getProjectGraph(projectPath);
181
+ if (!graph) {
182
+ return sendError(res, 'GRAPH_NOT_LOADED', projectPath ? `Project not found: ${projectPath}` : 'Graph not loaded', 500);
183
+ }
184
+ const result = detectCycle(graph);
185
+ if (!result.hasCycle) {
186
+ return sendSuccess(res, {
187
+ hasCycle: false,
188
+ cycles: [],
189
+ message: 'No cycles detected in graph',
190
+ });
191
+ }
192
+ return sendSuccess(res, {
193
+ hasCycle: true,
194
+ cycles: result.cycles,
195
+ cycleCount: result.cycles.length,
196
+ message: `Found ${result.cycles.length} cycle(s) in graph`,
197
+ });
198
+ }));
199
+ /**
200
+ * GET /api/graph/critical-path
201
+ * Get the critical path (longest path) through the graph
202
+ */
203
+ router.get('/api/graph/critical-path', asyncHandler(async (req, res) => {
204
+ const projectPath = getProjectPath(req);
205
+ const graph = await getProjectGraph(projectPath);
206
+ if (!graph) {
207
+ return sendError(res, 'GRAPH_NOT_LOADED', projectPath ? `Project not found: ${projectPath}` : 'Graph not loaded', 500);
208
+ }
209
+ // First check if graph has cycles
210
+ if (hasCycle(graph)) {
211
+ return sendError(res, 'GRAPH_HAS_CYCLE', 'Cannot calculate critical path for cyclic graph', 400);
212
+ }
213
+ const result = findCriticalPath(graph);
214
+ return sendSuccess(res, {
215
+ path: result.path,
216
+ duration: result.duration,
217
+ taskCount: result.path.length,
218
+ });
219
+ }));
220
+ /**
221
+ * GET /api/stats
222
+ * Get project statistics
223
+ */
224
+ router.get('/api/stats', asyncHandler(async (req, res) => {
225
+ const projectPath = getProjectPath(req);
226
+ const graph = await getProjectGraph(projectPath);
227
+ if (!graph) {
228
+ return sendError(res, 'GRAPH_NOT_LOADED', projectPath ? `Project not found: ${projectPath}` : 'Graph not loaded', 500);
229
+ }
230
+ // Get basic graph stats
231
+ const totalTasks = graph.size;
232
+ const rootTasks = graph.getRootTasks();
233
+ const orphanTasks = graph.getOrphanTasks();
234
+ // Calculate status and priority counts by iterating through tasks
235
+ const statusCounts = new Map();
236
+ statusCounts.set('ready', 0);
237
+ statusCounts.set('in_progress', 0);
238
+ statusCounts.set('in_review', 0);
239
+ statusCounts.set('completed', 0);
240
+ statusCounts.set('blocked', 0);
241
+ const priorityCounts = new Map();
242
+ priorityCounts.set('top', 0);
243
+ priorityCounts.set('second', 0);
244
+ priorityCounts.set('later', 0);
245
+ for (const task of graph.getAllTasks()) {
246
+ const currentStatus = statusCounts.get(task.status) ?? 0;
247
+ statusCounts.set(task.status, currentStatus + 1);
248
+ const currentPriority = priorityCounts.get(task.priority) ?? 0;
249
+ priorityCounts.set(task.priority, currentPriority + 1);
250
+ }
251
+ // Convert Maps to plain objects for JSON response
252
+ const statusCountsObj = {};
253
+ statusCounts.forEach((value, key) => { statusCountsObj[key] = value; });
254
+ const priorityCountsObj = {};
255
+ priorityCounts.forEach((value, key) => { priorityCountsObj[key] = value; });
256
+ // Build response
257
+ const stats = {
258
+ project: {
259
+ name: graph.metadata.project_name,
260
+ version: graph.metadata.version,
261
+ created: graph.metadata.created_at,
262
+ updated: graph.metadata.updated_at,
263
+ },
264
+ tasks: {
265
+ total: totalTasks,
266
+ root: rootTasks.length,
267
+ orphan: orphanTasks.length,
268
+ rootTaskIds: rootTasks,
269
+ orphanTaskIds: orphanTasks,
270
+ statusCounts: statusCountsObj,
271
+ priorityCounts: priorityCountsObj,
272
+ },
273
+ };
274
+ return sendSuccess(res, stats);
275
+ }));
276
+ }
277
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../../src/web/routes/graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Projects Routes - Global project registry endpoints
3
+ *
4
+ * Provides endpoints for listing and managing registered Octie projects.
5
+ *
6
+ * @module web/routes/projects
7
+ */
8
+ import type { Router } from 'express';
9
+ /**
10
+ * Register project routes
11
+ * @param router - Express Router instance
12
+ */
13
+ export declare function registerProjectsRoutes(router: Router): void;
14
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../../src/web/routes/projects.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAqB,MAAM,EAAE,MAAM,SAAS,CAAC;AA6DzD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAgE3D"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Projects Routes - Global project registry endpoints
3
+ *
4
+ * Provides endpoints for listing and managing registered Octie projects.
5
+ *
6
+ * @module web/routes/projects
7
+ */
8
+ import { getAllProjects, verifyProjectExists, loadRegistry, saveRegistry, } from '../../core/registry/index.js';
9
+ import { ERROR_SUGGESTIONS } from '../../types/index.js';
10
+ /**
11
+ * Async error handler wrapper
12
+ */
13
+ function asyncHandler(fn) {
14
+ return (req, res, next) => {
15
+ Promise.resolve(fn(req, res)).catch(next);
16
+ };
17
+ }
18
+ /**
19
+ * Send successful API response
20
+ */
21
+ function sendSuccess(res, data, status = 200) {
22
+ res.status(status).json({
23
+ success: true,
24
+ data,
25
+ timestamp: new Date().toISOString(),
26
+ });
27
+ }
28
+ /**
29
+ * Send error API response
30
+ */
31
+ function sendError(res, code, message, status = 400, details, suggestion) {
32
+ res.status(status).json({
33
+ success: false,
34
+ error: {
35
+ code,
36
+ message,
37
+ suggestion: suggestion ?? ERROR_SUGGESTIONS[code],
38
+ details,
39
+ },
40
+ timestamp: new Date().toISOString(),
41
+ });
42
+ }
43
+ /**
44
+ * Register project routes
45
+ * @param router - Express Router instance
46
+ */
47
+ export function registerProjectsRoutes(router) {
48
+ /**
49
+ * GET /api/projects
50
+ * List all registered projects with existence status
51
+ */
52
+ router.get('/api/projects', asyncHandler(async (_req, res) => {
53
+ const projects = getAllProjects();
54
+ // Add existence status to each project
55
+ const projectsWithStatus = projects.map(project => ({
56
+ ...project,
57
+ exists: verifyProjectExists(project),
58
+ }));
59
+ return sendSuccess(res, {
60
+ projects: projectsWithStatus,
61
+ count: projectsWithStatus.length,
62
+ });
63
+ }));
64
+ /**
65
+ * DELETE /api/projects/:path
66
+ * Remove a project from the registry (by encoded path)
67
+ */
68
+ router.delete('/api/projects/*', asyncHandler(async (req, res) => {
69
+ // Decode the path from URL
70
+ const encodedPath = req.params[0] ?? '';
71
+ const projectPath = decodeURIComponent(encodedPath);
72
+ const registry = loadRegistry();
73
+ let found = false;
74
+ for (const [key, project] of Object.entries(registry.projects)) {
75
+ if (project.path === projectPath) {
76
+ delete registry.projects[key];
77
+ found = true;
78
+ break;
79
+ }
80
+ }
81
+ if (!found) {
82
+ return sendError(res, 'PROJECT_NOT_FOUND', 'Project not found in registry', 404);
83
+ }
84
+ saveRegistry(registry);
85
+ return sendSuccess(res, {
86
+ removed: true,
87
+ path: projectPath,
88
+ });
89
+ }));
90
+ /**
91
+ * GET /api/registry/path
92
+ * Get the global registry file path
93
+ */
94
+ router.get('/api/registry/path', asyncHandler(async (_req, res) => {
95
+ const { getGlobalRegistryPath } = await import('../../core/registry/index.js');
96
+ const registryPath = getGlobalRegistryPath();
97
+ return sendSuccess(res, {
98
+ path: registryPath,
99
+ });
100
+ }));
101
+ }
102
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../../src/web/routes/projects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Task Routes - RESTful CRUD endpoints for task management
3
+ *
4
+ * Provides complete CRUD operations for tasks via REST API.
5
+ * All endpoints use Zod validation and proper HTTP status codes.
6
+ *
7
+ * @module web/routes/tasks
8
+ */
9
+ import type { Router } from 'express';
10
+ import type { TaskGraphStore } from '../../core/graph/index.js';
11
+ /**
12
+ * Register task routes
13
+ * @param router - Express Router instance
14
+ * @param getGraph - Function to get the current graph instance
15
+ */
16
+ export declare function registerTaskRoutes(router: Router, getGraph: () => TaskGraphStore | null): void;
17
+ //# sourceMappingURL=tasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../../src/web/routes/tasks.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAqB,MAAM,EAAE,MAAM,SAAS,CAAC;AAEzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAwIhE;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,cAAc,GAAG,IAAI,GACpC,IAAI,CAwcN"}