@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.
- package/LICENSE +21 -0
- package/README.md +190 -0
- package/dist/agent-parser.d.ts +146 -0
- package/dist/agent-parser.d.ts.map +1 -0
- package/dist/agent-parser.js +448 -0
- package/dist/agent-parser.js.map +1 -0
- package/dist/config.d.ts +54 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +146 -0
- package/dist/config.js.map +1 -0
- package/dist/coordination.d.ts +102 -0
- package/dist/coordination.d.ts.map +1 -0
- package/dist/coordination.js +157 -0
- package/dist/coordination.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +256 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer.d.ts +83 -0
- package/dist/indexer.d.ts.map +1 -0
- package/dist/indexer.js +467 -0
- package/dist/indexer.js.map +1 -0
- package/dist/resources/agents-status.d.ts +32 -0
- package/dist/resources/agents-status.d.ts.map +1 -0
- package/dist/resources/agents-status.js +73 -0
- package/dist/resources/agents-status.js.map +1 -0
- package/dist/resources/decisions-log.d.ts +21 -0
- package/dist/resources/decisions-log.d.ts.map +1 -0
- package/dist/resources/decisions-log.js +146 -0
- package/dist/resources/decisions-log.js.map +1 -0
- package/dist/resources/index.d.ts +10 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +74 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/plans-full.d.ts +11 -0
- package/dist/resources/plans-full.d.ts.map +1 -0
- package/dist/resources/plans-full.js +71 -0
- package/dist/resources/plans-full.js.map +1 -0
- package/dist/resources/plans-index.d.ts +30 -0
- package/dist/resources/plans-index.d.ts.map +1 -0
- package/dist/resources/plans-index.js +177 -0
- package/dist/resources/plans-index.js.map +1 -0
- package/dist/resources/plans-summary.d.ts +33 -0
- package/dist/resources/plans-summary.d.ts.map +1 -0
- package/dist/resources/plans-summary.js +238 -0
- package/dist/resources/plans-summary.js.map +1 -0
- package/dist/rlm/extractors.d.ts +39 -0
- package/dist/rlm/extractors.d.ts.map +1 -0
- package/dist/rlm/extractors.js +291 -0
- package/dist/rlm/extractors.js.map +1 -0
- package/dist/rlm/helpers-inject.d.ts +13 -0
- package/dist/rlm/helpers-inject.d.ts.map +1 -0
- package/dist/rlm/helpers-inject.js +586 -0
- package/dist/rlm/helpers-inject.js.map +1 -0
- package/dist/rlm/helpers.d.ts +124 -0
- package/dist/rlm/helpers.d.ts.map +1 -0
- package/dist/rlm/helpers.js +381 -0
- package/dist/rlm/helpers.js.map +1 -0
- package/dist/rlm/index.d.ts +12 -0
- package/dist/rlm/index.d.ts.map +1 -0
- package/dist/rlm/index.js +19 -0
- package/dist/rlm/index.js.map +1 -0
- package/dist/rlm/parallel.d.ts +45 -0
- package/dist/rlm/parallel.d.ts.map +1 -0
- package/dist/rlm/parallel.js +76 -0
- package/dist/rlm/parallel.js.map +1 -0
- package/dist/rlm/recursion.d.ts +96 -0
- package/dist/rlm/recursion.d.ts.map +1 -0
- package/dist/rlm/recursion.js +113 -0
- package/dist/rlm/recursion.js.map +1 -0
- package/dist/rlm/sampling.d.ts +100 -0
- package/dist/rlm/sampling.d.ts.map +1 -0
- package/dist/rlm/sampling.js +96 -0
- package/dist/rlm/sampling.js.map +1 -0
- package/dist/rlm/sandbox.d.ts +73 -0
- package/dist/rlm/sandbox.d.ts.map +1 -0
- package/dist/rlm/sandbox.js +160 -0
- package/dist/rlm/sandbox.js.map +1 -0
- package/dist/rlm/security.d.ts +28 -0
- package/dist/rlm/security.d.ts.map +1 -0
- package/dist/rlm/security.js +154 -0
- package/dist/rlm/security.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +107 -0
- package/dist/server.js.map +1 -0
- package/dist/task-parser.d.ts +47 -0
- package/dist/task-parser.d.ts.map +1 -0
- package/dist/task-parser.js +112 -0
- package/dist/task-parser.js.map +1 -0
- package/dist/test-setup.d.ts +6 -0
- package/dist/test-setup.d.ts.map +1 -0
- package/dist/test-setup.js +37 -0
- package/dist/test-setup.js.map +1 -0
- package/dist/tools/claim-task.d.ts +28 -0
- package/dist/tools/claim-task.d.ts.map +1 -0
- package/dist/tools/claim-task.js +288 -0
- package/dist/tools/claim-task.js.map +1 -0
- package/dist/tools/create-doc.d.ts +47 -0
- package/dist/tools/create-doc.d.ts.map +1 -0
- package/dist/tools/create-doc.js +137 -0
- package/dist/tools/create-doc.js.map +1 -0
- package/dist/tools/create-plan.d.ts +25 -0
- package/dist/tools/create-plan.d.ts.map +1 -0
- package/dist/tools/create-plan.js +179 -0
- package/dist/tools/create-plan.js.map +1 -0
- package/dist/tools/delete-doc.d.ts +51 -0
- package/dist/tools/delete-doc.d.ts.map +1 -0
- package/dist/tools/delete-doc.js +194 -0
- package/dist/tools/delete-doc.js.map +1 -0
- package/dist/tools/get-next-task.d.ts +49 -0
- package/dist/tools/get-next-task.d.ts.map +1 -0
- package/dist/tools/get-next-task.js +204 -0
- package/dist/tools/get-next-task.js.map +1 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +122 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list-docs.d.ts +53 -0
- package/dist/tools/list-docs.d.ts.map +1 -0
- package/dist/tools/list-docs.js +236 -0
- package/dist/tools/list-docs.js.map +1 -0
- package/dist/tools/open-document-in-cursor.d.ts +62 -0
- package/dist/tools/open-document-in-cursor.d.ts.map +1 -0
- package/dist/tools/open-document-in-cursor.js +211 -0
- package/dist/tools/open-document-in-cursor.js.map +1 -0
- package/dist/tools/read-doc.d.ts +44 -0
- package/dist/tools/read-doc.d.ts.map +1 -0
- package/dist/tools/read-doc.js +174 -0
- package/dist/tools/read-doc.js.map +1 -0
- package/dist/tools/release-task.d.ts +28 -0
- package/dist/tools/release-task.d.ts.map +1 -0
- package/dist/tools/release-task.js +154 -0
- package/dist/tools/release-task.js.map +1 -0
- package/dist/tools/rlm-multi-query.d.ts +110 -0
- package/dist/tools/rlm-multi-query.d.ts.map +1 -0
- package/dist/tools/rlm-multi-query.js +348 -0
- package/dist/tools/rlm-multi-query.js.map +1 -0
- package/dist/tools/rlm-query.d.ts +56 -0
- package/dist/tools/rlm-query.d.ts.map +1 -0
- package/dist/tools/rlm-query.js +228 -0
- package/dist/tools/rlm-query.js.map +1 -0
- package/dist/tools/search-docs.d.ts +34 -0
- package/dist/tools/search-docs.d.ts.map +1 -0
- package/dist/tools/search-docs.js +292 -0
- package/dist/tools/search-docs.js.map +1 -0
- package/dist/tools/update-doc.d.ts +149 -0
- package/dist/tools/update-doc.d.ts.map +1 -0
- package/dist/tools/update-doc.js +195 -0
- package/dist/tools/update-doc.js.map +1 -0
- package/dist/tools/update-task-status.d.ts +31 -0
- package/dist/tools/update-task-status.d.ts.map +1 -0
- package/dist/tools/update-task-status.js +303 -0
- package/dist/tools/update-task-status.js.map +1 -0
- package/dist/types.d.ts +50 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/backup.d.ts +76 -0
- package/dist/utils/backup.d.ts.map +1 -0
- package/dist/utils/backup.js +172 -0
- package/dist/utils/backup.js.map +1 -0
- package/dist/utils/errors.d.ts +93 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +125 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/os-paths.d.ts +45 -0
- package/dist/utils/os-paths.d.ts.map +1 -0
- package/dist/utils/os-paths.js +81 -0
- package/dist/utils/os-paths.js.map +1 -0
- package/dist/utils/paths.d.ts +71 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +165 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/watcher.d.ts +19 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +109 -0
- package/dist/watcher.js.map +1 -0
- 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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"}
|
package/dist/config.d.ts
ADDED
|
@@ -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":"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"}
|