@sudosandwich/limps 0.2.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 (183) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +190 -0
  3. package/dist/agent-parser.d.ts +146 -0
  4. package/dist/agent-parser.d.ts.map +1 -0
  5. package/dist/agent-parser.js +448 -0
  6. package/dist/agent-parser.js.map +1 -0
  7. package/dist/config.d.ts +54 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +146 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/coordination.d.ts +102 -0
  12. package/dist/coordination.d.ts.map +1 -0
  13. package/dist/coordination.js +157 -0
  14. package/dist/coordination.js.map +1 -0
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +256 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/indexer.d.ts +83 -0
  20. package/dist/indexer.d.ts.map +1 -0
  21. package/dist/indexer.js +467 -0
  22. package/dist/indexer.js.map +1 -0
  23. package/dist/resources/agents-status.d.ts +32 -0
  24. package/dist/resources/agents-status.d.ts.map +1 -0
  25. package/dist/resources/agents-status.js +73 -0
  26. package/dist/resources/agents-status.js.map +1 -0
  27. package/dist/resources/decisions-log.d.ts +21 -0
  28. package/dist/resources/decisions-log.d.ts.map +1 -0
  29. package/dist/resources/decisions-log.js +146 -0
  30. package/dist/resources/decisions-log.js.map +1 -0
  31. package/dist/resources/index.d.ts +10 -0
  32. package/dist/resources/index.d.ts.map +1 -0
  33. package/dist/resources/index.js +74 -0
  34. package/dist/resources/index.js.map +1 -0
  35. package/dist/resources/plans-full.d.ts +11 -0
  36. package/dist/resources/plans-full.d.ts.map +1 -0
  37. package/dist/resources/plans-full.js +71 -0
  38. package/dist/resources/plans-full.js.map +1 -0
  39. package/dist/resources/plans-index.d.ts +30 -0
  40. package/dist/resources/plans-index.d.ts.map +1 -0
  41. package/dist/resources/plans-index.js +177 -0
  42. package/dist/resources/plans-index.js.map +1 -0
  43. package/dist/resources/plans-summary.d.ts +33 -0
  44. package/dist/resources/plans-summary.d.ts.map +1 -0
  45. package/dist/resources/plans-summary.js +238 -0
  46. package/dist/resources/plans-summary.js.map +1 -0
  47. package/dist/rlm/extractors.d.ts +39 -0
  48. package/dist/rlm/extractors.d.ts.map +1 -0
  49. package/dist/rlm/extractors.js +291 -0
  50. package/dist/rlm/extractors.js.map +1 -0
  51. package/dist/rlm/helpers-inject.d.ts +13 -0
  52. package/dist/rlm/helpers-inject.d.ts.map +1 -0
  53. package/dist/rlm/helpers-inject.js +586 -0
  54. package/dist/rlm/helpers-inject.js.map +1 -0
  55. package/dist/rlm/helpers.d.ts +124 -0
  56. package/dist/rlm/helpers.d.ts.map +1 -0
  57. package/dist/rlm/helpers.js +381 -0
  58. package/dist/rlm/helpers.js.map +1 -0
  59. package/dist/rlm/index.d.ts +12 -0
  60. package/dist/rlm/index.d.ts.map +1 -0
  61. package/dist/rlm/index.js +19 -0
  62. package/dist/rlm/index.js.map +1 -0
  63. package/dist/rlm/parallel.d.ts +45 -0
  64. package/dist/rlm/parallel.d.ts.map +1 -0
  65. package/dist/rlm/parallel.js +76 -0
  66. package/dist/rlm/parallel.js.map +1 -0
  67. package/dist/rlm/recursion.d.ts +96 -0
  68. package/dist/rlm/recursion.d.ts.map +1 -0
  69. package/dist/rlm/recursion.js +113 -0
  70. package/dist/rlm/recursion.js.map +1 -0
  71. package/dist/rlm/sampling.d.ts +100 -0
  72. package/dist/rlm/sampling.d.ts.map +1 -0
  73. package/dist/rlm/sampling.js +96 -0
  74. package/dist/rlm/sampling.js.map +1 -0
  75. package/dist/rlm/sandbox.d.ts +73 -0
  76. package/dist/rlm/sandbox.d.ts.map +1 -0
  77. package/dist/rlm/sandbox.js +160 -0
  78. package/dist/rlm/sandbox.js.map +1 -0
  79. package/dist/rlm/security.d.ts +28 -0
  80. package/dist/rlm/security.d.ts.map +1 -0
  81. package/dist/rlm/security.js +154 -0
  82. package/dist/rlm/security.js.map +1 -0
  83. package/dist/server.d.ts +21 -0
  84. package/dist/server.d.ts.map +1 -0
  85. package/dist/server.js +107 -0
  86. package/dist/server.js.map +1 -0
  87. package/dist/task-parser.d.ts +47 -0
  88. package/dist/task-parser.d.ts.map +1 -0
  89. package/dist/task-parser.js +112 -0
  90. package/dist/task-parser.js.map +1 -0
  91. package/dist/test-setup.d.ts +6 -0
  92. package/dist/test-setup.d.ts.map +1 -0
  93. package/dist/test-setup.js +37 -0
  94. package/dist/test-setup.js.map +1 -0
  95. package/dist/tools/claim-task.d.ts +28 -0
  96. package/dist/tools/claim-task.d.ts.map +1 -0
  97. package/dist/tools/claim-task.js +288 -0
  98. package/dist/tools/claim-task.js.map +1 -0
  99. package/dist/tools/create-doc.d.ts +47 -0
  100. package/dist/tools/create-doc.d.ts.map +1 -0
  101. package/dist/tools/create-doc.js +137 -0
  102. package/dist/tools/create-doc.js.map +1 -0
  103. package/dist/tools/create-plan.d.ts +25 -0
  104. package/dist/tools/create-plan.d.ts.map +1 -0
  105. package/dist/tools/create-plan.js +179 -0
  106. package/dist/tools/create-plan.js.map +1 -0
  107. package/dist/tools/delete-doc.d.ts +51 -0
  108. package/dist/tools/delete-doc.d.ts.map +1 -0
  109. package/dist/tools/delete-doc.js +194 -0
  110. package/dist/tools/delete-doc.js.map +1 -0
  111. package/dist/tools/get-next-task.d.ts +49 -0
  112. package/dist/tools/get-next-task.d.ts.map +1 -0
  113. package/dist/tools/get-next-task.js +204 -0
  114. package/dist/tools/get-next-task.js.map +1 -0
  115. package/dist/tools/index.d.ts +10 -0
  116. package/dist/tools/index.d.ts.map +1 -0
  117. package/dist/tools/index.js +122 -0
  118. package/dist/tools/index.js.map +1 -0
  119. package/dist/tools/list-docs.d.ts +53 -0
  120. package/dist/tools/list-docs.d.ts.map +1 -0
  121. package/dist/tools/list-docs.js +236 -0
  122. package/dist/tools/list-docs.js.map +1 -0
  123. package/dist/tools/open-document-in-cursor.d.ts +62 -0
  124. package/dist/tools/open-document-in-cursor.d.ts.map +1 -0
  125. package/dist/tools/open-document-in-cursor.js +211 -0
  126. package/dist/tools/open-document-in-cursor.js.map +1 -0
  127. package/dist/tools/read-doc.d.ts +44 -0
  128. package/dist/tools/read-doc.d.ts.map +1 -0
  129. package/dist/tools/read-doc.js +174 -0
  130. package/dist/tools/read-doc.js.map +1 -0
  131. package/dist/tools/release-task.d.ts +28 -0
  132. package/dist/tools/release-task.d.ts.map +1 -0
  133. package/dist/tools/release-task.js +154 -0
  134. package/dist/tools/release-task.js.map +1 -0
  135. package/dist/tools/rlm-multi-query.d.ts +110 -0
  136. package/dist/tools/rlm-multi-query.d.ts.map +1 -0
  137. package/dist/tools/rlm-multi-query.js +348 -0
  138. package/dist/tools/rlm-multi-query.js.map +1 -0
  139. package/dist/tools/rlm-query.d.ts +56 -0
  140. package/dist/tools/rlm-query.d.ts.map +1 -0
  141. package/dist/tools/rlm-query.js +228 -0
  142. package/dist/tools/rlm-query.js.map +1 -0
  143. package/dist/tools/search-docs.d.ts +34 -0
  144. package/dist/tools/search-docs.d.ts.map +1 -0
  145. package/dist/tools/search-docs.js +292 -0
  146. package/dist/tools/search-docs.js.map +1 -0
  147. package/dist/tools/update-doc.d.ts +149 -0
  148. package/dist/tools/update-doc.d.ts.map +1 -0
  149. package/dist/tools/update-doc.js +195 -0
  150. package/dist/tools/update-doc.js.map +1 -0
  151. package/dist/tools/update-task-status.d.ts +31 -0
  152. package/dist/tools/update-task-status.d.ts.map +1 -0
  153. package/dist/tools/update-task-status.js +303 -0
  154. package/dist/tools/update-task-status.js.map +1 -0
  155. package/dist/types.d.ts +50 -0
  156. package/dist/types.d.ts.map +1 -0
  157. package/dist/types.js +2 -0
  158. package/dist/types.js.map +1 -0
  159. package/dist/utils/backup.d.ts +76 -0
  160. package/dist/utils/backup.d.ts.map +1 -0
  161. package/dist/utils/backup.js +172 -0
  162. package/dist/utils/backup.js.map +1 -0
  163. package/dist/utils/errors.d.ts +93 -0
  164. package/dist/utils/errors.d.ts.map +1 -0
  165. package/dist/utils/errors.js +125 -0
  166. package/dist/utils/errors.js.map +1 -0
  167. package/dist/utils/index.d.ts +8 -0
  168. package/dist/utils/index.d.ts.map +1 -0
  169. package/dist/utils/index.js +9 -0
  170. package/dist/utils/index.js.map +1 -0
  171. package/dist/utils/os-paths.d.ts +45 -0
  172. package/dist/utils/os-paths.d.ts.map +1 -0
  173. package/dist/utils/os-paths.js +81 -0
  174. package/dist/utils/os-paths.js.map +1 -0
  175. package/dist/utils/paths.d.ts +71 -0
  176. package/dist/utils/paths.d.ts.map +1 -0
  177. package/dist/utils/paths.js +165 -0
  178. package/dist/utils/paths.js.map +1 -0
  179. package/dist/watcher.d.ts +19 -0
  180. package/dist/watcher.d.ts.map +1 -0
  181. package/dist/watcher.js +109 -0
  182. package/dist/watcher.js.map +1 -0
  183. package/package.json +85 -0
@@ -0,0 +1,448 @@
1
+ /**
2
+ * Agent file parser for MCP planning tools.
3
+ *
4
+ * Agent files use YAML frontmatter as the single source of truth for task state.
5
+ * This module provides functions to parse, update, and query agent files.
6
+ *
7
+ * Task ID Format: `<plan-folder>#<agent-number>` (e.g., "0022-datagrid-stories#000")
8
+ */
9
+ import { readFileSync, writeFileSync, statSync, readdirSync } from 'fs';
10
+ import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
11
+ /**
12
+ * Default frontmatter for agent files without frontmatter.
13
+ */
14
+ const DEFAULT_FRONTMATTER = {
15
+ status: 'GAP',
16
+ persona: 'coder',
17
+ claimedBy: null,
18
+ dependencies: [],
19
+ blocks: [],
20
+ files: [],
21
+ };
22
+ /**
23
+ * Extract agent number from filename.
24
+ *
25
+ * @example
26
+ * extractAgentNumber("000_agent_sticky_header.agent.md") // "000"
27
+ * extractAgentNumber("001_agent_navigation.agent.md") // "001"
28
+ * extractAgentNumber("signalbadge.agent.md") // null (no number prefix)
29
+ *
30
+ * @param filename - Agent filename (not full path)
31
+ * @returns Agent number or null if not found
32
+ */
33
+ export function extractAgentNumber(filename) {
34
+ // Match leading digits in filename (e.g., "000", "001", "012")
35
+ const match = filename.match(/^(\d+)/);
36
+ return match ? match[1] : null;
37
+ }
38
+ /**
39
+ * Extract plan folder from agent file path.
40
+ *
41
+ * @example
42
+ * extractPlanFolder("/path/to/plans/0022-datagrid-stories/agents/000_agent.agent.md")
43
+ * // "0022-datagrid-stories"
44
+ *
45
+ * @param path - Full path to agent file
46
+ * @returns Plan folder name or null if not found
47
+ */
48
+ export function extractPlanFolder(path) {
49
+ // Match plans/<folder>/agents/
50
+ const match = path.match(/plans[/\\]([^/\\]+)[/\\]agents[/\\]/);
51
+ return match ? match[1] : null;
52
+ }
53
+ /**
54
+ * Build task ID from plan folder and agent number.
55
+ *
56
+ * @example
57
+ * buildTaskId("0022-datagrid-stories", "000") // "0022-datagrid-stories#000"
58
+ *
59
+ * @param planFolder - Plan folder name
60
+ * @param agentNumber - Agent number
61
+ * @returns Task ID in format planFolder#agentNumber
62
+ */
63
+ export function buildTaskId(planFolder, agentNumber) {
64
+ return `${planFolder}#${agentNumber}`;
65
+ }
66
+ /**
67
+ * Parse task ID to extract plan folder and agent number.
68
+ *
69
+ * @example
70
+ * parseTaskId("0022-datagrid-stories#000")
71
+ * // { planFolder: "0022-datagrid-stories", agentNumber: "000" }
72
+ *
73
+ * @param taskId - Task ID
74
+ * @returns Parsed components or null if invalid format
75
+ */
76
+ export function parseTaskId(taskId) {
77
+ const match = taskId.match(/^(.+)#(\d+)$/);
78
+ if (!match) {
79
+ return null;
80
+ }
81
+ return {
82
+ planFolder: match[1],
83
+ agentNumber: match[2],
84
+ };
85
+ }
86
+ /**
87
+ * Parse YAML frontmatter from content.
88
+ * Returns null if no frontmatter found.
89
+ *
90
+ * @param content - File content
91
+ * @returns Parsed frontmatter and remaining content, or null if no frontmatter
92
+ */
93
+ function parseFrontmatter(content) {
94
+ // Frontmatter must start at the beginning of the file
95
+ if (!content.startsWith('---')) {
96
+ return null;
97
+ }
98
+ // Find the closing ---
99
+ const endIndex = content.indexOf('\n---', 3);
100
+ if (endIndex === -1) {
101
+ return null;
102
+ }
103
+ const yamlContent = content.slice(4, endIndex);
104
+ const body = content.slice(endIndex + 4).trim();
105
+ try {
106
+ const frontmatter = parseYaml(yamlContent);
107
+ return { frontmatter: frontmatter || {}, body };
108
+ }
109
+ catch {
110
+ // Invalid YAML - treat as no frontmatter
111
+ return null;
112
+ }
113
+ }
114
+ /**
115
+ * Extract title from agent file content.
116
+ * Looks for first # heading.
117
+ *
118
+ * @param content - File content (after frontmatter)
119
+ * @returns Title or empty string if not found
120
+ */
121
+ function extractTitle(content) {
122
+ const match = content.match(/^#\s+(?:Agent\s+\d+:\s*)?(.+)$/m);
123
+ return match ? match[1].trim() : '';
124
+ }
125
+ /**
126
+ * Extract status from legacy agent file content (for migration).
127
+ * Looks for Status: `GAP` pattern in content.
128
+ *
129
+ * @param content - File content
130
+ * @returns Status or 'GAP' if not found
131
+ */
132
+ function extractLegacyStatus(content) {
133
+ const match = content.match(/Status:\s*`?(\w+)`?/i);
134
+ if (match) {
135
+ const status = match[1].toUpperCase();
136
+ if (['GAP', 'WIP', 'PASS', 'BLOCKED'].includes(status)) {
137
+ return status;
138
+ }
139
+ }
140
+ return 'GAP';
141
+ }
142
+ /**
143
+ * Extract persona from legacy agent file content (for migration).
144
+ *
145
+ * @param content - File content
146
+ * @returns Persona or 'coder' if not found
147
+ */
148
+ function extractLegacyPersona(content) {
149
+ const match = content.match(/persona[:\s]+(coder|reviewer|pm|customer)/i);
150
+ if (match) {
151
+ return match[1].toLowerCase();
152
+ }
153
+ return 'coder';
154
+ }
155
+ /**
156
+ * Extract files from legacy agent file content (for migration).
157
+ * Looks for Own: or Files: patterns.
158
+ *
159
+ * @param content - File content
160
+ * @returns Array of file paths
161
+ */
162
+ function extractLegacyFiles(content) {
163
+ const files = [];
164
+ // Look for Own: pattern
165
+ const ownMatch = content.match(/Own:\s*(.+?)(?:\n|$)/i);
166
+ if (ownMatch) {
167
+ const fileMatches = ownMatch[1].matchAll(/`([^`]+)`/g);
168
+ for (const match of fileMatches) {
169
+ files.push(match[1]);
170
+ }
171
+ }
172
+ // Look for Files: patterns in feature sections
173
+ const filesMatches = content.matchAll(/Files:\s*(.+?)(?:\n|$)/gi);
174
+ for (const match of filesMatches) {
175
+ const fileRefs = match[1].matchAll(/`([^`]+)`/g);
176
+ for (const fileRef of fileRefs) {
177
+ if (!files.includes(fileRef[1])) {
178
+ files.push(fileRef[1]);
179
+ }
180
+ }
181
+ }
182
+ return files;
183
+ }
184
+ /**
185
+ * Extract dependencies from legacy agent file content (for migration).
186
+ * Looks for Depend on: Agent XXX patterns.
187
+ *
188
+ * @param content - File content
189
+ * @returns Array of agent numbers
190
+ */
191
+ function extractLegacyDependencies(content) {
192
+ const deps = [];
193
+ const match = content.match(/Depend on:\s*(.+?)(?:\n|$)/i);
194
+ if (match && match[1].toLowerCase() !== 'none') {
195
+ // Look for Agent XXX patterns
196
+ const agentMatches = match[1].matchAll(/Agent\s+(\d+)/gi);
197
+ for (const agentMatch of agentMatches) {
198
+ deps.push(agentMatch[1].padStart(3, '0'));
199
+ }
200
+ }
201
+ return deps;
202
+ }
203
+ /**
204
+ * Extract blocks from legacy agent file content (for migration).
205
+ * Looks for Block: Agent XXX patterns.
206
+ *
207
+ * @param content - File content
208
+ * @returns Array of agent numbers
209
+ */
210
+ function extractLegacyBlocks(content) {
211
+ const blocks = [];
212
+ const match = content.match(/Block:\s*(.+?)(?:\n|$)/i);
213
+ if (match) {
214
+ // Look for Agent XXX patterns
215
+ const agentMatches = match[1].matchAll(/Agent\s+(\d+)/gi);
216
+ for (const agentMatch of agentMatches) {
217
+ blocks.push(agentMatch[1].padStart(3, '0'));
218
+ }
219
+ }
220
+ return blocks;
221
+ }
222
+ /**
223
+ * Parse an agent file and extract frontmatter and metadata.
224
+ *
225
+ * @param path - Full path to agent file
226
+ * @param content - File content
227
+ * @returns Parsed agent file or null if not a valid agent file
228
+ */
229
+ export function parseAgentFile(path, content) {
230
+ // Extract plan folder and agent number from path
231
+ const planFolder = extractPlanFolder(path);
232
+ if (!planFolder) {
233
+ return null;
234
+ }
235
+ // Extract agent number from filename
236
+ const filename = path.split(/[/\\]/).pop() || '';
237
+ const agentNumber = extractAgentNumber(filename);
238
+ if (!agentNumber) {
239
+ return null;
240
+ }
241
+ // Get file mtime
242
+ let mtime;
243
+ try {
244
+ const stats = statSync(path);
245
+ mtime = stats.mtime;
246
+ }
247
+ catch {
248
+ mtime = new Date();
249
+ }
250
+ // Parse frontmatter
251
+ const parsed = parseFrontmatter(content);
252
+ let frontmatter;
253
+ let body;
254
+ if (parsed) {
255
+ // Merge with defaults
256
+ frontmatter = {
257
+ ...DEFAULT_FRONTMATTER,
258
+ ...parsed.frontmatter,
259
+ };
260
+ body = parsed.body;
261
+ }
262
+ else {
263
+ // No frontmatter - extract from legacy format
264
+ frontmatter = {
265
+ status: extractLegacyStatus(content),
266
+ persona: extractLegacyPersona(content),
267
+ claimedBy: null,
268
+ dependencies: extractLegacyDependencies(content),
269
+ blocks: extractLegacyBlocks(content),
270
+ files: extractLegacyFiles(content),
271
+ };
272
+ body = content;
273
+ }
274
+ const taskId = buildTaskId(planFolder, agentNumber);
275
+ const title = extractTitle(body);
276
+ return {
277
+ taskId,
278
+ planFolder,
279
+ agentNumber,
280
+ path,
281
+ frontmatter,
282
+ content: body,
283
+ mtime,
284
+ title,
285
+ };
286
+ }
287
+ /**
288
+ * Read and parse an agent file from disk.
289
+ *
290
+ * @param path - Full path to agent file
291
+ * @returns Parsed agent file or null if not found or invalid
292
+ */
293
+ export function readAgentFile(path) {
294
+ try {
295
+ const content = readFileSync(path, 'utf-8');
296
+ return parseAgentFile(path, content);
297
+ }
298
+ catch {
299
+ return null;
300
+ }
301
+ }
302
+ /**
303
+ * Update agent file frontmatter on disk.
304
+ *
305
+ * @param path - Full path to agent file
306
+ * @param updates - Partial frontmatter updates
307
+ * @returns Updated parsed agent file or null on error
308
+ */
309
+ export function updateAgentFrontmatter(path, updates) {
310
+ // Read current file
311
+ let content;
312
+ try {
313
+ content = readFileSync(path, 'utf-8');
314
+ }
315
+ catch {
316
+ return null;
317
+ }
318
+ // Parse current state
319
+ const parsed = parseAgentFile(path, content);
320
+ if (!parsed) {
321
+ return null;
322
+ }
323
+ // Merge updates
324
+ const newFrontmatter = {
325
+ ...parsed.frontmatter,
326
+ ...updates,
327
+ };
328
+ // Build new content with frontmatter
329
+ const yamlContent = stringifyYaml(newFrontmatter, { lineWidth: 0 }).trim();
330
+ const newContent = `---\n${yamlContent}\n---\n\n${parsed.content}`;
331
+ // Write back
332
+ try {
333
+ writeFileSync(path, newContent, 'utf-8');
334
+ }
335
+ catch {
336
+ return null;
337
+ }
338
+ // Re-parse and return
339
+ return parseAgentFile(path, newContent);
340
+ }
341
+ /**
342
+ * Add frontmatter to a legacy agent file (migration helper).
343
+ * Extracts state from content and adds proper YAML frontmatter.
344
+ *
345
+ * @param path - Full path to agent file
346
+ * @returns Updated parsed agent file or null on error
347
+ */
348
+ export function migrateAgentFile(path) {
349
+ // Read current file
350
+ let content;
351
+ try {
352
+ content = readFileSync(path, 'utf-8');
353
+ }
354
+ catch {
355
+ return null;
356
+ }
357
+ // Check if already has frontmatter
358
+ if (content.startsWith('---')) {
359
+ // Already migrated
360
+ return parseAgentFile(path, content);
361
+ }
362
+ // Extract legacy data
363
+ const frontmatter = {
364
+ status: extractLegacyStatus(content),
365
+ persona: extractLegacyPersona(content),
366
+ claimedBy: null,
367
+ dependencies: extractLegacyDependencies(content),
368
+ blocks: extractLegacyBlocks(content),
369
+ files: extractLegacyFiles(content),
370
+ };
371
+ // Build new content with frontmatter
372
+ const yamlContent = stringifyYaml(frontmatter, { lineWidth: 0 }).trim();
373
+ const newContent = `---\n${yamlContent}\n---\n\n${content}`;
374
+ // Write back
375
+ try {
376
+ writeFileSync(path, newContent, 'utf-8');
377
+ }
378
+ catch {
379
+ return null;
380
+ }
381
+ // Re-parse and return
382
+ return parseAgentFile(path, newContent);
383
+ }
384
+ /**
385
+ * Check if an agent is stale (WIP status but mtime > threshold).
386
+ *
387
+ * @param agent - Parsed agent file
388
+ * @param thresholdMinutes - Stale threshold in minutes (default 10)
389
+ * @returns true if agent is stale
390
+ */
391
+ export function isAgentStale(agent, thresholdMinutes = 10) {
392
+ if (agent.frontmatter.status !== 'WIP') {
393
+ return false;
394
+ }
395
+ const now = new Date();
396
+ const ageMs = now.getTime() - agent.mtime.getTime();
397
+ const ageMinutes = ageMs / (1000 * 60);
398
+ return ageMinutes > thresholdMinutes;
399
+ }
400
+ /**
401
+ * Find agent file path by task ID.
402
+ *
403
+ * @param plansPath - Base path to plans directory
404
+ * @param taskId - Task ID in format planFolder#agentNumber
405
+ * @returns Full path to agent file or null if not found
406
+ */
407
+ export function findAgentFilePath(plansPath, taskId) {
408
+ const parsed = parseTaskId(taskId);
409
+ if (!parsed) {
410
+ return null;
411
+ }
412
+ const { planFolder, agentNumber } = parsed;
413
+ // Build path pattern: plans/<planFolder>/agents/<agentNumber>*.agent.md
414
+ const agentsDir = `${plansPath}/${planFolder}/agents`;
415
+ // Try to find matching file
416
+ try {
417
+ const files = readdirSync(agentsDir);
418
+ for (const file of files) {
419
+ if (file.endsWith('.agent.md') && file.startsWith(agentNumber)) {
420
+ return `${agentsDir}/${file}`;
421
+ }
422
+ }
423
+ }
424
+ catch {
425
+ // Directory doesn't exist or can't be read
426
+ }
427
+ return null;
428
+ }
429
+ /**
430
+ * Resolve a dependency reference to a full task ID.
431
+ * Handles both agent numbers ("000") and full task IDs ("0022-plan#000").
432
+ *
433
+ * @param dep - Dependency reference
434
+ * @param currentPlanFolder - Current plan folder for relative references
435
+ * @returns Full task ID or null if invalid
436
+ */
437
+ export function resolveDependency(dep, currentPlanFolder) {
438
+ // If already a full task ID (contains #), return as-is
439
+ if (dep.includes('#')) {
440
+ return dep;
441
+ }
442
+ // If it's just an agent number, prepend current plan folder
443
+ if (/^\d+$/.test(dep)) {
444
+ return buildTaskId(currentPlanFolder, dep);
445
+ }
446
+ return null;
447
+ }
448
+ //# sourceMappingURL=agent-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-parser.js","sourceRoot":"","sources":["../src/agent-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Server configuration interface.
3
+ */
4
+ export interface ServerConfig {
5
+ plansPath: string;
6
+ docsPaths?: string[];
7
+ fileExtensions?: string[];
8
+ dataPath: string;
9
+ coordinationPath: string;
10
+ heartbeatTimeout: number;
11
+ debounceDelay: number;
12
+ maxHandoffIterations: number;
13
+ }
14
+ /**
15
+ * Expand tilde (~) to home directory in a path.
16
+ *
17
+ * @param path - Path that may contain ~ prefix
18
+ * @returns Path with ~ expanded to home directory
19
+ */
20
+ export declare function expandTilde(path: string): string;
21
+ /**
22
+ * Load configuration from file.
23
+ * Creates default configuration file if it doesn't exist.
24
+ * Paths are resolved relative to the config file location.
25
+ *
26
+ * @param configPath - Path to config.json file
27
+ * @returns Server configuration
28
+ */
29
+ export declare function loadConfig(configPath: string): ServerConfig;
30
+ /**
31
+ * Validate configuration object.
32
+ * Uses type checking to ensure all required fields are present and correct types.
33
+ *
34
+ * @param config - Configuration object to validate
35
+ * @returns true if valid, false otherwise
36
+ */
37
+ export declare function validateConfig(config: unknown): config is ServerConfig;
38
+ /**
39
+ * Get all documentation paths to index.
40
+ * Combines plansPath with any additional docsPaths, deduplicating.
41
+ *
42
+ * @param config - Server configuration
43
+ * @returns Array of unique paths to index
44
+ */
45
+ export declare function getAllDocsPaths(config: ServerConfig): string[];
46
+ /**
47
+ * Get file extensions to index.
48
+ * Returns configured extensions or default ['.md'].
49
+ *
50
+ * @param config - Server configuration
51
+ * @returns Array of file extensions (e.g., ['.md', '.jsx', '.tsx'])
52
+ */
53
+ export declare function getFileExtensions(config: ServerConfig): string[];
54
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAqBD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CA6C3D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,YAAY,CAuCtE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,CAS9D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,CAEhE"}
package/dist/config.js ADDED
@@ -0,0 +1,146 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
2
+ import { resolve, dirname } from 'path';
3
+ import { homedir } from 'os';
4
+ /**
5
+ * Default file extensions to index.
6
+ */
7
+ const DEFAULT_FILE_EXTENSIONS = ['.md'];
8
+ /**
9
+ * Default server configuration.
10
+ */
11
+ const DEFAULT_CONFIG = {
12
+ plansPath: './plans',
13
+ docsPaths: undefined,
14
+ fileExtensions: undefined,
15
+ dataPath: './data',
16
+ coordinationPath: './coordination.json',
17
+ heartbeatTimeout: 300000, // 5 minutes
18
+ debounceDelay: 200, // 200ms
19
+ maxHandoffIterations: 3,
20
+ };
21
+ /**
22
+ * Expand tilde (~) to home directory in a path.
23
+ *
24
+ * @param path - Path that may contain ~ prefix
25
+ * @returns Path with ~ expanded to home directory
26
+ */
27
+ export function expandTilde(path) {
28
+ if (path.startsWith('~/') || path === '~') {
29
+ return path.replace(/^~/, homedir());
30
+ }
31
+ return path;
32
+ }
33
+ /**
34
+ * Load configuration from file.
35
+ * Creates default configuration file if it doesn't exist.
36
+ * Paths are resolved relative to the config file location.
37
+ *
38
+ * @param configPath - Path to config.json file
39
+ * @returns Server configuration
40
+ */
41
+ export function loadConfig(configPath) {
42
+ const configDir = dirname(configPath);
43
+ if (!existsSync(configPath)) {
44
+ // Create default config file
45
+ const defaultConfig = { ...DEFAULT_CONFIG };
46
+ // Resolve paths relative to config file
47
+ defaultConfig.plansPath = resolve(configDir, DEFAULT_CONFIG.plansPath);
48
+ defaultConfig.dataPath = resolve(configDir, DEFAULT_CONFIG.dataPath);
49
+ defaultConfig.coordinationPath = resolve(configDir, DEFAULT_CONFIG.coordinationPath);
50
+ mkdirSync(configDir, { recursive: true });
51
+ writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2), 'utf-8');
52
+ return defaultConfig;
53
+ }
54
+ const content = readFileSync(configPath, 'utf-8');
55
+ const config = JSON.parse(content);
56
+ // Helper to resolve path with tilde expansion
57
+ const resolvePath = (p) => {
58
+ const expanded = expandTilde(p);
59
+ // If path starts with ~ it's now absolute, otherwise resolve relative to configDir
60
+ if (p.startsWith('~')) {
61
+ return expanded;
62
+ }
63
+ return resolve(configDir, expanded);
64
+ };
65
+ // Resolve docsPaths relative to config file (with tilde expansion)
66
+ const resolvedDocsPaths = config.docsPaths ? config.docsPaths.map(resolvePath) : undefined;
67
+ // Merge with defaults and resolve paths (with tilde expansion)
68
+ const mergedConfig = {
69
+ plansPath: resolvePath(config.plansPath || DEFAULT_CONFIG.plansPath),
70
+ docsPaths: resolvedDocsPaths,
71
+ fileExtensions: config.fileExtensions,
72
+ dataPath: resolvePath(config.dataPath || DEFAULT_CONFIG.dataPath),
73
+ coordinationPath: resolvePath(config.coordinationPath || DEFAULT_CONFIG.coordinationPath),
74
+ heartbeatTimeout: config.heartbeatTimeout ?? DEFAULT_CONFIG.heartbeatTimeout,
75
+ debounceDelay: config.debounceDelay ?? DEFAULT_CONFIG.debounceDelay,
76
+ maxHandoffIterations: config.maxHandoffIterations ?? DEFAULT_CONFIG.maxHandoffIterations,
77
+ };
78
+ return mergedConfig;
79
+ }
80
+ /**
81
+ * Validate configuration object.
82
+ * Uses type checking to ensure all required fields are present and correct types.
83
+ *
84
+ * @param config - Configuration object to validate
85
+ * @returns true if valid, false otherwise
86
+ */
87
+ export function validateConfig(config) {
88
+ if (!config || typeof config !== 'object') {
89
+ return false;
90
+ }
91
+ const c = config;
92
+ // Check required fields
93
+ if (typeof c.plansPath !== 'string' ||
94
+ typeof c.dataPath !== 'string' ||
95
+ typeof c.coordinationPath !== 'string' ||
96
+ typeof c.heartbeatTimeout !== 'number' ||
97
+ typeof c.debounceDelay !== 'number' ||
98
+ typeof c.maxHandoffIterations !== 'number') {
99
+ return false;
100
+ }
101
+ // Check optional docsPaths (must be string array if present)
102
+ if (c.docsPaths !== undefined) {
103
+ if (!Array.isArray(c.docsPaths) || !c.docsPaths.every((p) => typeof p === 'string')) {
104
+ return false;
105
+ }
106
+ }
107
+ // Check optional fileExtensions (must be string array if present)
108
+ if (c.fileExtensions !== undefined) {
109
+ if (!Array.isArray(c.fileExtensions) || !c.fileExtensions.every((e) => typeof e === 'string')) {
110
+ return false;
111
+ }
112
+ }
113
+ // Check positive values
114
+ if (c.heartbeatTimeout < 0 || c.debounceDelay < 0 || c.maxHandoffIterations < 0) {
115
+ return false;
116
+ }
117
+ return true;
118
+ }
119
+ /**
120
+ * Get all documentation paths to index.
121
+ * Combines plansPath with any additional docsPaths, deduplicating.
122
+ *
123
+ * @param config - Server configuration
124
+ * @returns Array of unique paths to index
125
+ */
126
+ export function getAllDocsPaths(config) {
127
+ const paths = new Set();
128
+ paths.add(config.plansPath);
129
+ if (config.docsPaths) {
130
+ for (const p of config.docsPaths) {
131
+ paths.add(p);
132
+ }
133
+ }
134
+ return Array.from(paths);
135
+ }
136
+ /**
137
+ * Get file extensions to index.
138
+ * Returns configured extensions or default ['.md'].
139
+ *
140
+ * @param config - Server configuration
141
+ * @returns Array of file extensions (e.g., ['.md', '.jsx', '.tsx'])
142
+ */
143
+ export function getFileExtensions(config) {
144
+ return config.fileExtensions || DEFAULT_FILE_EXTENSIONS;
145
+ }
146
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAgB7B;;GAEG;AACH,MAAM,uBAAuB,GAAG,CAAC,KAAK,CAAC,CAAC;AAExC;;GAEG;AACH,MAAM,cAAc,GAAiB;IACnC,SAAS,EAAE,SAAS;IACpB,SAAS,EAAE,SAAS;IACpB,cAAc,EAAE,SAAS;IACzB,QAAQ,EAAE,QAAQ;IAClB,gBAAgB,EAAE,qBAAqB;IACvC,gBAAgB,EAAE,MAAM,EAAE,YAAY;IACtC,aAAa,EAAE,GAAG,EAAE,QAAQ;IAC5B,oBAAoB,EAAE,CAAC;CACxB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,UAAkB;IAC3C,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAEtC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,6BAA6B;QAC7B,MAAM,aAAa,GAAG,EAAE,GAAG,cAAc,EAAE,CAAC;QAC5C,wCAAwC;QACxC,aAAa,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;QACvE,aAAa,CAAC,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;QACrE,aAAa,CAAC,gBAAgB,GAAG,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,gBAAgB,CAAC,CAAC;QAErF,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAC3E,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA0B,CAAC;IAE5D,8CAA8C;IAC9C,MAAM,WAAW,GAAG,CAAC,CAAS,EAAU,EAAE;QACxC,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAChC,mFAAmF;QACnF,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,OAAO,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACtC,CAAC,CAAC;IAEF,mEAAmE;IACnE,MAAM,iBAAiB,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE3F,+DAA+D;IAC/D,MAAM,YAAY,GAAiB;QACjC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,SAAS,IAAI,cAAc,CAAC,SAAS,CAAC;QACpE,SAAS,EAAE,iBAAiB;QAC5B,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,QAAQ,IAAI,cAAc,CAAC,QAAQ,CAAC;QACjE,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAAC,gBAAgB,IAAI,cAAc,CAAC,gBAAgB,CAAC;QACzF,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,IAAI,cAAc,CAAC,gBAAgB;QAC5E,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,cAAc,CAAC,aAAa;QACnE,oBAAoB,EAAE,MAAM,CAAC,oBAAoB,IAAI,cAAc,CAAC,oBAAoB;KACzF,CAAC;IAEF,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,MAAe;IAC5C,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,CAAC,GAAG,MAA+B,CAAC;IAE1C,wBAAwB;IACxB,IACE,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;QAC/B,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ;QAC9B,OAAO,CAAC,CAAC,gBAAgB,KAAK,QAAQ;QACtC,OAAO,CAAC,CAAC,gBAAgB,KAAK,QAAQ;QACtC,OAAO,CAAC,CAAC,aAAa,KAAK,QAAQ;QACnC,OAAO,CAAC,CAAC,oBAAoB,KAAK,QAAQ,EAC1C,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,6DAA6D;IAC7D,IAAI,CAAC,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAC9B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;YACpF,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,kEAAkE;IAClE,IAAI,CAAC,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;YAC9F,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,wBAAwB;IACxB,IAAI,CAAC,CAAC,gBAAgB,GAAG,CAAC,IAAI,CAAC,CAAC,aAAa,GAAG,CAAC,IAAI,CAAC,CAAC,oBAAoB,GAAG,CAAC,EAAE,CAAC;QAChF,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC5B,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACjC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAoB;IACpD,OAAO,MAAM,CAAC,cAAc,IAAI,uBAAuB,CAAC;AAC1D,CAAC"}