mdan-cli 2.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/README.md +223 -0
- package/agents/AGENTS-REGISTRY.md +215 -0
- package/agents/architect.md +160 -0
- package/agents/dev.md +166 -0
- package/agents/devops.md +230 -0
- package/agents/doc.md +189 -0
- package/agents/learn.md +377 -0
- package/agents/product.md +124 -0
- package/agents/security.md +168 -0
- package/agents/test.md +151 -0
- package/agents/ux.md +207 -0
- package/cli/mdan.js +505 -0
- package/cli/mdan.py +259 -0
- package/cli/mdan.sh +724 -0
- package/cli/postinstall.js +4 -0
- package/core/orchestrator.md +238 -0
- package/core/universal-envelope.md +160 -0
- package/install.sh +228 -0
- package/integrations/all-integrations.md +300 -0
- package/integrations/claude.md +46 -0
- package/integrations/cursor.md +74 -0
- package/integrations/windsurf.md +48 -0
- package/memory/MDAN-STATE.template.json +44 -0
- package/memory/MEMORY-SYSTEM.md +197 -0
- package/package.json +48 -0
- package/phases/01-discover.md +136 -0
- package/phases/02-design.md +147 -0
- package/phases/03-build.md +113 -0
- package/phases/04-verify.md +101 -0
- package/phases/05-ship.md +156 -0
- package/skills/find-skills/skill.md +133 -0
- package/templates/ARCHITECTURE.md +186 -0
- package/templates/CHANGELOG.md +41 -0
- package/templates/MDAN-KNOWLEDGE.md +73 -0
- package/templates/PRD.md +120 -0
- package/templates/SECURITY-REVIEW.md +99 -0
- package/templates/TEST-PLAN.md +97 -0
package/cli/mdan.js
ADDED
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
const { intro, text, select, isCancel, cancel, outro, spinner } = require('@clack/prompts');
|
|
7
|
+
const pc = require('picocolors');
|
|
8
|
+
|
|
9
|
+
const VERSION = '2.2.0';
|
|
10
|
+
const MDAN_DIR = path.resolve(__dirname, '..');
|
|
11
|
+
|
|
12
|
+
// Colors
|
|
13
|
+
const colors = {
|
|
14
|
+
red: '\x1b[0;31m',
|
|
15
|
+
green: '\x1b[0;32m',
|
|
16
|
+
yellow: '\x1b[1;33m',
|
|
17
|
+
cyan: '\x1b[0;36m',
|
|
18
|
+
magenta: '\x1b[0;35m',
|
|
19
|
+
bold: '\x1b[1m',
|
|
20
|
+
nc: '\x1b[0m'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function banner() {
|
|
24
|
+
console.log(`${colors.cyan}
|
|
25
|
+
███╗ ███╗██████╗ █████╗ ███╗ ██╗
|
|
26
|
+
████╗ ████║██╔══██╗██╔══██╗████╗ ██║
|
|
27
|
+
██╔████╔██║██║ ██║███████║██╔██╗ ██║
|
|
28
|
+
██║╚██╔╝██║██║ ██║██╔══██║██║╚██╗██║
|
|
29
|
+
██║ ╚═╝ ██║██████╔╝██║ ██║██║ ╚████║
|
|
30
|
+
╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝
|
|
31
|
+
${colors.nc}
|
|
32
|
+
${colors.bold}Multi-Agent Development Agentic Network${colors.nc} v${VERSION}
|
|
33
|
+
`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function showHelp() {
|
|
37
|
+
banner();
|
|
38
|
+
console.log(`${colors.bold}USAGE${colors.nc}
|
|
39
|
+
mdan <command> [options]
|
|
40
|
+
|
|
41
|
+
${colors.bold}COMMANDS${colors.nc}
|
|
42
|
+
init [name] Create a new project
|
|
43
|
+
attach [--rebuild] Add MDAN to existing project
|
|
44
|
+
status Show project status
|
|
45
|
+
phase [1-5] Show phase guide
|
|
46
|
+
workflow [name] Show granular workflow
|
|
47
|
+
module add [name] Install a domain module (e.g., agile-scrum)
|
|
48
|
+
agent [name] Show agent prompt
|
|
49
|
+
oc Copy orchestrator prompt to clipboard
|
|
50
|
+
skills List available skills
|
|
51
|
+
version Show version
|
|
52
|
+
|
|
53
|
+
${colors.bold}EXAMPLES${colors.nc}
|
|
54
|
+
mdan init my-app # New project
|
|
55
|
+
cd my-project && mdan attach # Existing project
|
|
56
|
+
mdan attach --rebuild # Rebuild from scratch
|
|
57
|
+
|
|
58
|
+
${colors.bold}AGENTS${colors.nc}
|
|
59
|
+
product, architect, ux, dev, test, security, devops, doc
|
|
60
|
+
`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function cmdInit(initialName) {
|
|
64
|
+
intro(pc.bgCyan(pc.black(' MDAN v' + VERSION + ' - Initialization Wizard ')));
|
|
65
|
+
|
|
66
|
+
let name = initialName;
|
|
67
|
+
|
|
68
|
+
if (!name) {
|
|
69
|
+
const namePrompt = await text({
|
|
70
|
+
message: 'What is your project name?',
|
|
71
|
+
initialValue: 'my-project',
|
|
72
|
+
validate(value) {
|
|
73
|
+
if (value.length === 0) return 'Name is required!';
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (isCancel(namePrompt)) {
|
|
78
|
+
cancel('Operation cancelled.');
|
|
79
|
+
return process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
name = namePrompt;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const setupType = await select({
|
|
85
|
+
message: 'What kind of project are you building?',
|
|
86
|
+
options: [
|
|
87
|
+
{ value: 'standard', label: 'Standard Web/Mobile App', hint: 'Default 5-phase workflow' },
|
|
88
|
+
{ value: 'micro', label: 'Micro Project', hint: 'Solo dev, single feature, simple' },
|
|
89
|
+
{ value: 'api', label: 'API / SDK', hint: 'No UI, dev-focused' },
|
|
90
|
+
{ value: 'product', label: 'Scale-up Product', hint: 'Multi-month, stakeholders' }
|
|
91
|
+
]
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (isCancel(setupType)) {
|
|
95
|
+
cancel('Operation cancelled.');
|
|
96
|
+
return process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const s = spinner();
|
|
100
|
+
s.start(`Creating ${name} project structure...`);
|
|
101
|
+
|
|
102
|
+
const dirs = [
|
|
103
|
+
`${name}/.mdan/agents`,
|
|
104
|
+
`${name}/.mdan/skills`,
|
|
105
|
+
`${name}/mdan_output`,
|
|
106
|
+
`${name}/.claude/skills`,
|
|
107
|
+
`${name}/.github`
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
dirs.forEach(dir => fs.mkdirSync(dir, { recursive: true }));
|
|
111
|
+
|
|
112
|
+
fs.copyFileSync(`${MDAN_DIR}/core/orchestrator.md`, `${name}/.mdan/orchestrator.md`);
|
|
113
|
+
fs.copyFileSync(`${MDAN_DIR}/core/universal-envelope.md`, `${name}/.mdan/universal-envelope.md`);
|
|
114
|
+
|
|
115
|
+
fs.readdirSync(`${MDAN_DIR}/agents`).filter(f => f.endsWith('.md')).forEach(f => {
|
|
116
|
+
fs.copyFileSync(`${MDAN_DIR}/agents/${f}`, `${name}/.mdan/agents/${f}`);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
fs.readdirSync(`${MDAN_DIR}/templates`).filter(f => f.endsWith('.md')).forEach(f => {
|
|
120
|
+
fs.copyFileSync(`${MDAN_DIR}/templates/${f}`, `${name}/mdan_output/${f}`);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Copy skills
|
|
124
|
+
const skillsDir = `${MDAN_DIR}/skills`;
|
|
125
|
+
if (fs.existsSync(skillsDir)) {
|
|
126
|
+
fs.readdirSync(skillsDir).forEach(skill => {
|
|
127
|
+
const src = `${skillsDir}/${skill}`;
|
|
128
|
+
const dest1 = `${name}/.mdan/skills/${skill}`;
|
|
129
|
+
const dest2 = `${name}/.claude/skills/${skill}`;
|
|
130
|
+
if (fs.statSync(src).isDirectory()) {
|
|
131
|
+
fs.cpSync(src, dest1, { recursive: true });
|
|
132
|
+
fs.cpSync(src, dest2, { recursive: true });
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Create .cursorrules
|
|
138
|
+
let cursorrules = fs.readFileSync(`${MDAN_DIR}/core/orchestrator.md`, 'utf8');
|
|
139
|
+
cursorrules += '\n\n## CURSOR INSTRUCTIONS\nAgent files are in .mdan/agents/\nSkills are in .mdan/skills/';
|
|
140
|
+
fs.writeFileSync(`${name}/.cursorrules`, cursorrules);
|
|
141
|
+
fs.copyFileSync(`${name}/.cursorrules`, `${name}/.windsurfrules`);
|
|
142
|
+
fs.copyFileSync(`${MDAN_DIR}/core/orchestrator.md`, `${name}/.github/copilot-instructions.md`);
|
|
143
|
+
|
|
144
|
+
fs.writeFileSync(`${name}/README.md`, `# ${name}\n\n> Built with MDAN (${setupType} profile)\n`);
|
|
145
|
+
|
|
146
|
+
s.stop(pc.green(`Project ${name} initialized successfully!`));
|
|
147
|
+
|
|
148
|
+
outro(
|
|
149
|
+
pc.bold('Next steps:\n') +
|
|
150
|
+
`1. ${pc.cyan(`cd ${name}`)}\n` +
|
|
151
|
+
`2. Open the folder in your IDE (Cursor, Windsurf, etc.)\n` +
|
|
152
|
+
`3. Or run ${pc.cyan('mdan oc')} and paste into your favorite LLM chat.`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function cmdAttach(rebuildMode) {
|
|
157
|
+
intro(pc.bgMagenta(pc.black(' MDAN v' + VERSION + ' - Attach Wizard ')));
|
|
158
|
+
|
|
159
|
+
const projectName = path.basename(process.cwd());
|
|
160
|
+
let isRebuild = rebuildMode === '--rebuild';
|
|
161
|
+
|
|
162
|
+
if (!rebuildMode) {
|
|
163
|
+
const action = await select({
|
|
164
|
+
message: `How do you want to attach MDAN to ${pc.bold(projectName)}?`,
|
|
165
|
+
options: [
|
|
166
|
+
{ value: 'attach', label: 'Attach normally', hint: 'Analyze existing codebase and add features' },
|
|
167
|
+
{ value: 'rebuild', label: 'Rebuild Mode', hint: 'Analyze then rewrite EVERYTHING from scratch' }
|
|
168
|
+
]
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
if (isCancel(action)) {
|
|
172
|
+
cancel('Operation cancelled.');
|
|
173
|
+
return process.exit(0);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
isRebuild = action === 'rebuild';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const s = spinner();
|
|
180
|
+
s.start(isRebuild
|
|
181
|
+
? `Preparing REBUILD environment for ${projectName}...`
|
|
182
|
+
: `Attaching MDAN to ${projectName}...`);
|
|
183
|
+
|
|
184
|
+
fs.mkdirSync('.mdan/agents', { recursive: true });
|
|
185
|
+
fs.mkdirSync('.mdan/skills', { recursive: true });
|
|
186
|
+
fs.mkdirSync('.claude/skills', { recursive: true });
|
|
187
|
+
fs.mkdirSync('.github', { recursive: true });
|
|
188
|
+
|
|
189
|
+
fs.copyFileSync(`${MDAN_DIR}/core/orchestrator.md`, '.mdan/orchestrator.md');
|
|
190
|
+
fs.copyFileSync(`${MDAN_DIR}/core/universal-envelope.md`, '.mdan/universal-envelope.md');
|
|
191
|
+
|
|
192
|
+
fs.readdirSync(`${MDAN_DIR}/agents`).filter(f => f.endsWith('.md')).forEach(f => {
|
|
193
|
+
fs.copyFileSync(`${MDAN_DIR}/agents/${f}`, `.mdan/agents/${f}`);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Copy skills
|
|
197
|
+
const skillsDir = `${MDAN_DIR}/skills`;
|
|
198
|
+
if (fs.existsSync(skillsDir)) {
|
|
199
|
+
fs.readdirSync(skillsDir).forEach(skill => {
|
|
200
|
+
const src = `${skillsDir}/${skill}`;
|
|
201
|
+
if (fs.statSync(src).isDirectory()) {
|
|
202
|
+
fs.cpSync(src, `.mdan/skills/${skill}`, { recursive: true });
|
|
203
|
+
fs.cpSync(src, `.claude/skills/${skill}`, { recursive: true });
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Create .cursorrules
|
|
209
|
+
let cursorrules = fs.readFileSync(`${MDAN_DIR}/core/orchestrator.md`, 'utf8');
|
|
210
|
+
if (isRebuild) {
|
|
211
|
+
cursorrules += '\n\n## REBUILD MODE\nAnalyze existing code then rewrite from scratch.';
|
|
212
|
+
} else {
|
|
213
|
+
cursorrules += '\n\n## EXISTING PROJECT\nAnalyze codebase before making changes.';
|
|
214
|
+
}
|
|
215
|
+
fs.writeFileSync('.cursorrules', cursorrules);
|
|
216
|
+
fs.copyFileSync('.cursorrules', '.windsurfrules');
|
|
217
|
+
fs.copyFileSync(`${MDAN_DIR}/core/orchestrator.md`, '.github/copilot-instructions.md');
|
|
218
|
+
|
|
219
|
+
s.stop(pc.green(`MDAN attached successfully!`));
|
|
220
|
+
|
|
221
|
+
outro(
|
|
222
|
+
pc.bold('Next steps:\n') +
|
|
223
|
+
`1. Open this folder in your IDE (Cursor, Windsurf, etc.)\n` +
|
|
224
|
+
`2. Or run ${pc.cyan('mdan oc')} and paste the prompt into Claude/ChatGPT\n\n` +
|
|
225
|
+
(isRebuild
|
|
226
|
+
? pc.magenta(`Start prompt: "MDAN REBUILD: Analyze and rewrite this project"`)
|
|
227
|
+
: pc.cyan(`Start prompt: "MDAN: Analyze this project and help me [your goal]"`))
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function cmdOc() {
|
|
232
|
+
let orchFile = '.mdan/orchestrator.md';
|
|
233
|
+
if (!fs.existsSync(orchFile)) {
|
|
234
|
+
orchFile = `${MDAN_DIR}/core/orchestrator.md`;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (fs.existsSync(orchFile)) {
|
|
238
|
+
const content = fs.readFileSync(orchFile, 'utf8');
|
|
239
|
+
try {
|
|
240
|
+
if (process.platform === 'darwin') {
|
|
241
|
+
execSync('pbcopy', { input: content });
|
|
242
|
+
} else if (process.platform === 'win32') {
|
|
243
|
+
execSync('clip', { input: content });
|
|
244
|
+
} else if (process.platform === 'linux') {
|
|
245
|
+
try {
|
|
246
|
+
execSync('xclip -selection clipboard', { input: content });
|
|
247
|
+
} catch (e) {
|
|
248
|
+
execSync('wl-copy', { input: content });
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
throw new Error('Unsupported platform');
|
|
252
|
+
}
|
|
253
|
+
console.log(`${colors.green}✅ Orchestrator prompt copied to clipboard!${colors.nc}`);
|
|
254
|
+
console.log(' Paste it into Claude, ChatGPT, or your favorite LLM.');
|
|
255
|
+
} catch (e) {
|
|
256
|
+
console.log(content);
|
|
257
|
+
console.log(`\n${colors.yellow}⚠️ Could not copy to clipboard automatically. Please copy the text above.${colors.nc}`);
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
console.log(`${colors.red}Orchestrator file not found.${colors.nc}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function cmdStatus() {
|
|
265
|
+
if (fs.existsSync('.mdan/orchestrator.md')) {
|
|
266
|
+
console.log(`${colors.green}✅ MDAN is active in this project${colors.nc}`);
|
|
267
|
+
if (fs.existsSync('.mdan/STATUS.md')) {
|
|
268
|
+
console.log(fs.readFileSync('.mdan/STATUS.md', 'utf8'));
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
console.log(`${colors.yellow}No MDAN project here.${colors.nc}`);
|
|
272
|
+
console.log(' Run: mdan init [name] or mdan attach');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function cmdPhase(num, action) {
|
|
277
|
+
const phases = {
|
|
278
|
+
'1': ['01-discover.md', 'DISCOVER'],
|
|
279
|
+
'discover': ['01-discover.md', 'DISCOVER'],
|
|
280
|
+
'2': ['02-design.md', 'DESIGN'],
|
|
281
|
+
'design': ['02-design.md', 'DESIGN'],
|
|
282
|
+
'3': ['03-build.md', 'BUILD'],
|
|
283
|
+
'build': ['03-build.md', 'BUILD'],
|
|
284
|
+
'4': ['04-verify.md', 'VERIFY'],
|
|
285
|
+
'verify': ['04-verify.md', 'VERIFY'],
|
|
286
|
+
'5': ['05-ship.md', 'SHIP'],
|
|
287
|
+
'ship': ['05-ship.md', 'SHIP']
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
if (!phases[num]) {
|
|
291
|
+
console.log('Usage: mdan phase [1-5|name] [copy]');
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const [file, name] = phases[num];
|
|
296
|
+
const phaseFile = `${MDAN_DIR}/phases/${file}`;
|
|
297
|
+
|
|
298
|
+
if (fs.existsSync(phaseFile)) {
|
|
299
|
+
const content = fs.readFileSync(phaseFile, 'utf8');
|
|
300
|
+
|
|
301
|
+
if (action === 'copy' || action === '-c') {
|
|
302
|
+
try {
|
|
303
|
+
if (process.platform === 'darwin') {
|
|
304
|
+
execSync('pbcopy', { input: content });
|
|
305
|
+
} else if (process.platform === 'win32') {
|
|
306
|
+
execSync('clip', { input: content });
|
|
307
|
+
} else if (process.platform === 'linux') {
|
|
308
|
+
try {
|
|
309
|
+
execSync('xclip -selection clipboard', { input: content });
|
|
310
|
+
} catch (e) {
|
|
311
|
+
execSync('wl-copy', { input: content });
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
throw new Error('Unsupported platform');
|
|
315
|
+
}
|
|
316
|
+
console.log(`${colors.green}✅ Phase ${name} prompt copied to clipboard!${colors.nc}`);
|
|
317
|
+
console.log(' Paste it into your LLM to start the phase.');
|
|
318
|
+
} catch (e) {
|
|
319
|
+
console.log(content);
|
|
320
|
+
console.log(`\n${colors.yellow}⚠️ Could not copy automatically. Please copy the text above.${colors.nc}`);
|
|
321
|
+
}
|
|
322
|
+
} else {
|
|
323
|
+
console.log(`${colors.cyan}${colors.bold}Phase ${name}${colors.nc}`);
|
|
324
|
+
console.log(content);
|
|
325
|
+
console.log(`\n${colors.yellow}Tip: Run '${colors.cyan}mdan phase ${num} copy${colors.yellow}' to copy this content to clipboard.${colors.nc}`);
|
|
326
|
+
}
|
|
327
|
+
} else {
|
|
328
|
+
console.log(`${colors.red}Phase file not found: ${file}${colors.nc}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function cmdModule(action, name) {
|
|
333
|
+
if (action !== 'add' || !name) {
|
|
334
|
+
console.log('Usage: mdan module add [name]');
|
|
335
|
+
console.log('Available modules:');
|
|
336
|
+
if (fs.existsSync(`${MDAN_DIR}/modules`)) {
|
|
337
|
+
fs.readdirSync(`${MDAN_DIR}/modules`).forEach(m => {
|
|
338
|
+
const stat = fs.statSync(`${MDAN_DIR}/modules/${m}`);
|
|
339
|
+
if (stat.isDirectory()) console.log(` ${m}`);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const moduleDir = `${MDAN_DIR}/modules/${name}`;
|
|
346
|
+
if (!fs.existsSync(moduleDir)) {
|
|
347
|
+
console.log(`${colors.red}Module not found: ${name}${colors.nc}`);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
console.log(`${colors.cyan}📦 Installing module: ${colors.bold}${name}${colors.nc}`);
|
|
352
|
+
|
|
353
|
+
if (!fs.existsSync('.mdan')) {
|
|
354
|
+
console.log(`${colors.yellow}⚠️ No .mdan folder found. Are you in an MDAN project?${colors.nc}`);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Copy agents
|
|
359
|
+
if (fs.existsSync(`${moduleDir}/agents`)) {
|
|
360
|
+
fs.readdirSync(`${moduleDir}/agents`).forEach(f => {
|
|
361
|
+
fs.copyFileSync(`${moduleDir}/agents/${f}`, `.mdan/agents/${f}`);
|
|
362
|
+
console.log(`${colors.green} Added agent:${colors.nc} ${f}`);
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
console.log(`\n${colors.green}✅ Module ${name} installed!${colors.nc}`);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function cmdWorkflow(name, action) {
|
|
370
|
+
if (!name) {
|
|
371
|
+
console.log('Usage: mdan workflow [name] [copy]');
|
|
372
|
+
console.log('Available workflows:');
|
|
373
|
+
if (fs.existsSync(`${MDAN_DIR}/workflows`)) {
|
|
374
|
+
fs.readdirSync(`${MDAN_DIR}/workflows`).forEach(f => {
|
|
375
|
+
if (f.endsWith('.md')) console.log(` ${f.replace('.md', '')}`);
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const workflowFile = `${MDAN_DIR}/workflows/${name}.md`;
|
|
382
|
+
|
|
383
|
+
if (fs.existsSync(workflowFile)) {
|
|
384
|
+
const content = fs.readFileSync(workflowFile, 'utf8');
|
|
385
|
+
|
|
386
|
+
if (action === 'copy' || action === '-c') {
|
|
387
|
+
try {
|
|
388
|
+
if (process.platform === 'darwin') {
|
|
389
|
+
execSync('pbcopy', { input: content });
|
|
390
|
+
} else if (process.platform === 'win32') {
|
|
391
|
+
execSync('clip', { input: content });
|
|
392
|
+
} else if (process.platform === 'linux') {
|
|
393
|
+
try {
|
|
394
|
+
execSync('xclip -selection clipboard', { input: content });
|
|
395
|
+
} catch (e) {
|
|
396
|
+
execSync('wl-copy', { input: content });
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
console.log(`${colors.green}✅ Workflow ${name} prompt copied to clipboard!${colors.nc}`);
|
|
400
|
+
} catch (e) {
|
|
401
|
+
console.log(content);
|
|
402
|
+
console.log(`\n${colors.yellow}⚠️ Could not copy automatically. Please copy the text above.${colors.nc}`);
|
|
403
|
+
}
|
|
404
|
+
} else {
|
|
405
|
+
console.log(`${colors.cyan}${colors.bold}Workflow: ${name}${colors.nc}`);
|
|
406
|
+
console.log(content);
|
|
407
|
+
console.log(`\n${colors.yellow}Tip: Run '${colors.cyan}mdan workflow ${name} copy${colors.yellow}' to copy this content to clipboard.${colors.nc}`);
|
|
408
|
+
}
|
|
409
|
+
} else {
|
|
410
|
+
console.log(`${colors.red}Workflow not found: ${name}${colors.nc}`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function cmdAgent(name) {
|
|
415
|
+
const file = `${MDAN_DIR}/agents/${name}.md`;
|
|
416
|
+
if (fs.existsSync(file)) {
|
|
417
|
+
console.log(fs.readFileSync(file, 'utf8'));
|
|
418
|
+
} else {
|
|
419
|
+
console.log('Agents: product, architect, ux, dev, test, security, devops, doc');
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function cmdSkills() {
|
|
424
|
+
console.log(`${colors.cyan}Skills:${colors.nc}`);
|
|
425
|
+
const skillsDir = `${MDAN_DIR}/skills`;
|
|
426
|
+
if (fs.existsSync(skillsDir)) {
|
|
427
|
+
fs.readdirSync(skillsDir).forEach(s => console.log(` ${s}`));
|
|
428
|
+
} else {
|
|
429
|
+
console.log(' No skills installed');
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Main
|
|
434
|
+
const [,, cmd, ...args] = process.argv;
|
|
435
|
+
|
|
436
|
+
async function main() {
|
|
437
|
+
if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
|
|
438
|
+
if (!cmd) {
|
|
439
|
+
// Interactive Wizard Default
|
|
440
|
+
intro(pc.bgCyan(pc.black(' MDAN v' + VERSION + ' ')));
|
|
441
|
+
const action = await select({
|
|
442
|
+
message: 'What would you like to do?',
|
|
443
|
+
options: [
|
|
444
|
+
{ value: 'init', label: 'Create a new project', hint: 'Start fresh' },
|
|
445
|
+
{ value: 'attach', label: 'Attach to existing project', hint: 'Add MDAN to this folder' },
|
|
446
|
+
{ value: 'help', label: 'Show Help', hint: 'See all commands' }
|
|
447
|
+
]
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
if (isCancel(action)) {
|
|
451
|
+
cancel('Operation cancelled.');
|
|
452
|
+
return process.exit(0);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (action === 'init') {
|
|
456
|
+
return cmdInit();
|
|
457
|
+
} else if (action === 'attach') {
|
|
458
|
+
return cmdAttach();
|
|
459
|
+
} else if (action === 'help') {
|
|
460
|
+
showHelp();
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
} else {
|
|
464
|
+
showHelp();
|
|
465
|
+
}
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
switch (cmd) {
|
|
470
|
+
case 'init':
|
|
471
|
+
await cmdInit(args[0]);
|
|
472
|
+
break;
|
|
473
|
+
case 'attach':
|
|
474
|
+
await cmdAttach(args[0]);
|
|
475
|
+
break;
|
|
476
|
+
case 'oc':
|
|
477
|
+
cmdOc();
|
|
478
|
+
break;
|
|
479
|
+
case 'status':
|
|
480
|
+
cmdStatus();
|
|
481
|
+
break;
|
|
482
|
+
case 'phase':
|
|
483
|
+
cmdPhase(args[0], args[1]);
|
|
484
|
+
break;
|
|
485
|
+
case 'module':
|
|
486
|
+
cmdModule(args[0], args[1]);
|
|
487
|
+
break;
|
|
488
|
+
case 'workflow':
|
|
489
|
+
cmdWorkflow(args[0], args[1]);
|
|
490
|
+
break;
|
|
491
|
+
case 'agent':
|
|
492
|
+
cmdAgent(args[0]);
|
|
493
|
+
break;
|
|
494
|
+
case 'skills':
|
|
495
|
+
cmdSkills();
|
|
496
|
+
break;
|
|
497
|
+
case 'version':
|
|
498
|
+
case '-v':
|
|
499
|
+
console.log(`MDAN v${VERSION}`);
|
|
500
|
+
break;
|
|
501
|
+
default:
|
|
502
|
+
console.log(`Unknown: ${cmd}. Run: mdan help`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
main().catch(console.error);
|