mdboard 1.3.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin.js +117 -59
- package/index.html +2161 -1579
- package/package.json +7 -5
- package/presets/kanban/api.json +91 -0
- package/presets/kanban/cli.json +69 -0
- package/presets/kanban/docs.json +29 -0
- package/presets/kanban/entities.json +128 -0
- package/presets/kanban/structure.json +15 -0
- package/presets/kanban/ui.json +86 -0
- package/presets/scrum/api.json +98 -0
- package/presets/scrum/cli.json +120 -0
- package/presets/scrum/docs.json +43 -0
- package/presets/scrum/entities.json +268 -0
- package/presets/scrum/structure.json +32 -0
- package/presets/scrum/ui.json +201 -0
- package/presets/shape-up/api.json +40 -0
- package/presets/shape-up/cli.json +44 -0
- package/presets/shape-up/docs.json +32 -0
- package/presets/shape-up/entities.json +140 -0
- package/presets/shape-up/structure.json +28 -0
- package/presets/shape-up/ui.json +114 -0
- package/src/cli/cli.js +186 -210
- package/src/cli/config.js +234 -0
- package/src/cli/init.js +128 -76
- package/src/cli/preset.js +849 -0
- package/src/cli/skill.js +417 -0
- package/src/cli/status.js +126 -96
- package/src/core/config.js +491 -38
- package/src/core/history.js +17 -1
- package/src/core/scanner.js +373 -463
- package/src/core/workspace.js +0 -15
- package/src/server/api.js +464 -741
- package/src/server/server.js +105 -130
- package/build.js +0 -44
- package/defaults.json +0 -43
- package/src/cli/sync.js +0 -194
- package/src/cli/theme.js +0 -142
- package/src/client/app.js +0 -266
- package/src/client/board.js +0 -157
- package/src/client/core.js +0 -331
- package/src/client/editor.js +0 -318
- package/src/client/history.js +0 -137
- package/src/client/metrics.js +0 -38
- package/src/client/milestones.js +0 -77
- package/src/client/notes.js +0 -183
- package/src/client/overview.js +0 -104
- package/src/client/panel.js +0 -637
- package/src/client/styles.css +0 -471
- package/src/client/table.js +0 -111
- package/src/client/template.html +0 -144
- package/src/client/themes.js +0 -261
- package/src/client/workspace.js +0 -164
- package/src/core/agent-scanner.js +0 -260
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* mdboard — Agent configuration scanner
|
|
3
|
-
*
|
|
4
|
-
* Scans projectDir for agent/AI configuration files and returns
|
|
5
|
-
* suggestions for autocomplete in the AI properties UI.
|
|
6
|
-
*
|
|
7
|
-
* Supported agents:
|
|
8
|
-
* Claude Code, Codex CLI, Gemini CLI, Cursor, VS Code Copilot,
|
|
9
|
-
* Windsurf, Cline, KiloCode, OpenClaw
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
|
|
15
|
-
function safeReadFile(filePath) {
|
|
16
|
-
try { return fs.readFileSync(filePath, 'utf-8'); } catch { return null; }
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function safeDirEntries(dir) {
|
|
20
|
-
try { return fs.readdirSync(dir).filter(e => !e.startsWith('.')); } catch { return []; }
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function safeDirEntriesRecursive(dir, prefix) {
|
|
24
|
-
const results = [];
|
|
25
|
-
for (const entry of safeDirEntries(dir)) {
|
|
26
|
-
const full = path.join(dir, entry);
|
|
27
|
-
const rel = prefix ? prefix + '/' + entry : entry;
|
|
28
|
-
try {
|
|
29
|
-
if (fs.statSync(full).isDirectory()) {
|
|
30
|
-
if (fs.existsSync(path.join(full, 'SKILL.md'))) {
|
|
31
|
-
results.push(rel);
|
|
32
|
-
}
|
|
33
|
-
results.push(...safeDirEntriesRecursive(full, rel));
|
|
34
|
-
} else if (entry.endsWith('.md')) {
|
|
35
|
-
results.push(rel);
|
|
36
|
-
}
|
|
37
|
-
} catch { /* skip */ }
|
|
38
|
-
}
|
|
39
|
-
return results;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Push value to array if not already present */
|
|
43
|
-
function pushUnique(arr, value) {
|
|
44
|
-
if (arr.indexOf(value) === -1) arr.push(value);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Collect .md files from a directory into an array (non-recursive) */
|
|
48
|
-
function collectMdFiles(dir, arr, prefix) {
|
|
49
|
-
for (const entry of safeDirEntries(dir)) {
|
|
50
|
-
if (entry.endsWith('.md') || entry.endsWith('.mdc') || entry.endsWith('.agent.md')) {
|
|
51
|
-
pushUnique(arr, prefix ? prefix + '/' + entry : entry);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Collect all files from a directory into an array (non-recursive) */
|
|
57
|
-
function collectAllFiles(dir, arr, prefix) {
|
|
58
|
-
for (const entry of safeDirEntries(dir)) {
|
|
59
|
-
const full = path.join(dir, entry);
|
|
60
|
-
try {
|
|
61
|
-
if (!fs.statSync(full).isDirectory()) {
|
|
62
|
-
pushUnique(arr, prefix ? prefix + '/' + entry : entry);
|
|
63
|
-
}
|
|
64
|
-
} catch { /* skip */ }
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** Extract mcpServers keys from a JSON file */
|
|
69
|
-
function extractMcpServersFromJson(filePath, arr) {
|
|
70
|
-
const content = safeReadFile(filePath);
|
|
71
|
-
if (!content) return;
|
|
72
|
-
try {
|
|
73
|
-
const parsed = JSON.parse(content);
|
|
74
|
-
const servers = parsed.mcpServers || parsed;
|
|
75
|
-
if (servers && typeof servers === 'object' && !Array.isArray(servers)) {
|
|
76
|
-
for (const key of Object.keys(servers)) {
|
|
77
|
-
if (key !== '$schema' && key !== 'mcpServers') pushUnique(arr, key);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
} catch { /* invalid JSON */ }
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** Check if a file exists and push to context */
|
|
84
|
-
function checkContextFile(projectDir, relativePath, arr) {
|
|
85
|
-
if (fs.existsSync(path.join(projectDir, relativePath))) {
|
|
86
|
-
pushUnique(arr, relativePath);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Scan projectDir for agent configuration files across all supported agents.
|
|
92
|
-
*
|
|
93
|
-
* @param {string} projectDir - Root of the repo
|
|
94
|
-
* @returns {{ skills: string[], agents: string[], mcps: string[], commands: string[], context: string[] }}
|
|
95
|
-
*/
|
|
96
|
-
function scanAgentConfigs(projectDir) {
|
|
97
|
-
const result = { skills: [], agents: [], mcps: [], commands: [], context: [] };
|
|
98
|
-
|
|
99
|
-
// ─── SKILLS ───────────────────────────────────────────────
|
|
100
|
-
|
|
101
|
-
// Claude Code: .claude/skills/ — .md files and subdirs with SKILL.md
|
|
102
|
-
result.skills = safeDirEntriesRecursive(path.join(projectDir, '.claude', 'skills'), '');
|
|
103
|
-
|
|
104
|
-
// Codex CLI: .codex/skills/, .agents/skills/
|
|
105
|
-
for (const dir of ['.codex/skills', '.agents/skills']) {
|
|
106
|
-
const entries = safeDirEntriesRecursive(path.join(projectDir, ...dir.split('/')), '');
|
|
107
|
-
for (const e of entries) pushUnique(result.skills, e);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// ─── AGENTS ───────────────────────────────────────────────
|
|
111
|
-
|
|
112
|
-
// Claude Code: .claude/agents/*.md
|
|
113
|
-
collectMdFiles(path.join(projectDir, '.claude', 'agents'), result.agents, '');
|
|
114
|
-
|
|
115
|
-
// Cursor: .cursor/agents/*.md
|
|
116
|
-
collectMdFiles(path.join(projectDir, '.cursor', 'agents'), result.agents, '');
|
|
117
|
-
|
|
118
|
-
// VS Code Copilot: .github/agents/*.md
|
|
119
|
-
collectMdFiles(path.join(projectDir, '.github', 'agents'), result.agents, '');
|
|
120
|
-
|
|
121
|
-
// ─── MCP SERVERS ──────────────────────────────────────────
|
|
122
|
-
|
|
123
|
-
// Claude Code: .mcp.json (project-level)
|
|
124
|
-
extractMcpServersFromJson(path.join(projectDir, '.mcp.json'), result.mcps);
|
|
125
|
-
|
|
126
|
-
// Claude Code: .claude/settings.local.json — enabledMcpjsonServers
|
|
127
|
-
const settingsJson = safeReadFile(path.join(projectDir, '.claude', 'settings.local.json'));
|
|
128
|
-
if (settingsJson) {
|
|
129
|
-
try {
|
|
130
|
-
const parsed = JSON.parse(settingsJson);
|
|
131
|
-
if (Array.isArray(parsed.enabledMcpjsonServers)) {
|
|
132
|
-
for (const srv of parsed.enabledMcpjsonServers) {
|
|
133
|
-
if (typeof srv === 'string') pushUnique(result.mcps, srv);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
} catch { /* invalid JSON */ }
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Cursor: .cursor/mcp.json
|
|
140
|
-
extractMcpServersFromJson(path.join(projectDir, '.cursor', 'mcp.json'), result.mcps);
|
|
141
|
-
|
|
142
|
-
// VS Code Copilot: .vscode/mcp.json
|
|
143
|
-
extractMcpServersFromJson(path.join(projectDir, '.vscode', 'mcp.json'), result.mcps);
|
|
144
|
-
|
|
145
|
-
// KiloCode: .kilocode/mcp.json
|
|
146
|
-
extractMcpServersFromJson(path.join(projectDir, '.kilocode', 'mcp.json'), result.mcps);
|
|
147
|
-
|
|
148
|
-
// Gemini CLI: .gemini/settings.json — mcpServers
|
|
149
|
-
const geminiSettings = safeReadFile(path.join(projectDir, '.gemini', 'settings.json'));
|
|
150
|
-
if (geminiSettings) {
|
|
151
|
-
try {
|
|
152
|
-
const parsed = JSON.parse(geminiSettings);
|
|
153
|
-
if (parsed.mcpServers && typeof parsed.mcpServers === 'object') {
|
|
154
|
-
for (const key of Object.keys(parsed.mcpServers)) {
|
|
155
|
-
pushUnique(result.mcps, key);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
} catch { /* invalid JSON */ }
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Codex CLI: .codex/config.toml — [mcp_servers.<name>]
|
|
162
|
-
const codexConfig = safeReadFile(path.join(projectDir, '.codex', 'config.toml'));
|
|
163
|
-
if (codexConfig) {
|
|
164
|
-
const mcpMatches = codexConfig.matchAll(/\[mcp_servers\.(\w[\w-]*)\]/g);
|
|
165
|
-
for (const m of mcpMatches) pushUnique(result.mcps, m[1]);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// ─── COMMANDS ─────────────────────────────────────────────
|
|
169
|
-
|
|
170
|
-
// Claude Code: .claude/commands/
|
|
171
|
-
collectAllFiles(path.join(projectDir, '.claude', 'commands'), result.commands, '');
|
|
172
|
-
|
|
173
|
-
// Gemini CLI: .gemini/commands/ (.toml files)
|
|
174
|
-
collectAllFiles(path.join(projectDir, '.gemini', 'commands'), result.commands, '');
|
|
175
|
-
|
|
176
|
-
// VS Code Copilot: .github/prompts/ (.prompt.md files)
|
|
177
|
-
collectAllFiles(path.join(projectDir, '.github', 'prompts'), result.commands, '');
|
|
178
|
-
|
|
179
|
-
// Windsurf: .windsurf/workflows/
|
|
180
|
-
collectAllFiles(path.join(projectDir, '.windsurf', 'workflows'), result.commands, '');
|
|
181
|
-
|
|
182
|
-
// CLAUDE.md — parse dev commands section
|
|
183
|
-
const claudeMd = safeReadFile(path.join(projectDir, 'CLAUDE.md'))
|
|
184
|
-
|| safeReadFile(path.join(projectDir, '.claude', 'CLAUDE.md'));
|
|
185
|
-
if (claudeMd) {
|
|
186
|
-
const lines = claudeMd.split('\n');
|
|
187
|
-
let inCommands = false;
|
|
188
|
-
for (const line of lines) {
|
|
189
|
-
if (/^#+\s*.*(command|script|dev)/i.test(line)) {
|
|
190
|
-
inCommands = true;
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
if (inCommands && /^#+\s/.test(line)) {
|
|
194
|
-
inCommands = false;
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
if (inCommands) {
|
|
198
|
-
const match = line.match(/^[-*]\s*`([^`]+)`/);
|
|
199
|
-
if (match) pushUnique(result.commands, match[1]);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// ─── CONTEXT / RULES ─────────────────────────────────────
|
|
205
|
-
|
|
206
|
-
// Claude Code
|
|
207
|
-
checkContextFile(projectDir, 'CLAUDE.md', result.context);
|
|
208
|
-
checkContextFile(projectDir, '.claude/CLAUDE.md', result.context);
|
|
209
|
-
checkContextFile(projectDir, 'CLAUDE.local.md', result.context);
|
|
210
|
-
collectMdFiles(path.join(projectDir, '.claude', 'rules'), result.context, '.claude/rules');
|
|
211
|
-
|
|
212
|
-
// Cursor
|
|
213
|
-
checkContextFile(projectDir, '.cursorrules', result.context);
|
|
214
|
-
for (const entry of safeDirEntries(path.join(projectDir, '.cursor', 'rules'))) {
|
|
215
|
-
pushUnique(result.context, '.cursor/rules/' + entry);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Codex CLI
|
|
219
|
-
checkContextFile(projectDir, 'AGENTS.md', result.context);
|
|
220
|
-
checkContextFile(projectDir, 'AGENTS.override.md', result.context);
|
|
221
|
-
|
|
222
|
-
// Gemini CLI
|
|
223
|
-
checkContextFile(projectDir, 'GEMINI.md', result.context);
|
|
224
|
-
|
|
225
|
-
// Windsurf
|
|
226
|
-
checkContextFile(projectDir, '.windsurfrules', result.context);
|
|
227
|
-
for (const entry of safeDirEntries(path.join(projectDir, '.windsurf', 'rules'))) {
|
|
228
|
-
pushUnique(result.context, '.windsurf/rules/' + entry);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Cline
|
|
232
|
-
checkContextFile(projectDir, '.clinerules', result.context);
|
|
233
|
-
// .clinerules/ as directory
|
|
234
|
-
for (const entry of safeDirEntries(path.join(projectDir, '.clinerules'))) {
|
|
235
|
-
pushUnique(result.context, '.clinerules/' + entry);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// KiloCode
|
|
239
|
-
checkContextFile(projectDir, '.kilocoderules', result.context);
|
|
240
|
-
for (const entry of safeDirEntries(path.join(projectDir, '.kilocode', 'rules'))) {
|
|
241
|
-
pushUnique(result.context, '.kilocode/rules/' + entry);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// VS Code Copilot
|
|
245
|
-
checkContextFile(projectDir, '.github/copilot-instructions.md', result.context);
|
|
246
|
-
for (const entry of safeDirEntries(path.join(projectDir, '.github', 'instructions'))) {
|
|
247
|
-
pushUnique(result.context, '.github/instructions/' + entry);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// OpenClaw
|
|
251
|
-
checkContextFile(projectDir, 'SOUL.md', result.context);
|
|
252
|
-
checkContextFile(projectDir, 'IDENTITY.md', result.context);
|
|
253
|
-
checkContextFile(projectDir, 'USER.md', result.context);
|
|
254
|
-
checkContextFile(projectDir, 'TOOLS.md', result.context);
|
|
255
|
-
checkContextFile(projectDir, 'MEMORY.md', result.context);
|
|
256
|
-
|
|
257
|
-
return result;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
module.exports = { scanAgentConfigs };
|