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.py
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""MDAN CLI - Multi-Agent Development Agentic Network"""
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
import shutil
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
VERSION = "2.2.0"
|
|
11
|
+
MDAN_DIR = Path(__file__).parent.parent
|
|
12
|
+
|
|
13
|
+
# Colors
|
|
14
|
+
RED = "\033[0;31m"
|
|
15
|
+
GREEN = "\033[0;32m"
|
|
16
|
+
YELLOW = "\033[1;33m"
|
|
17
|
+
CYAN = "\033[0;36m"
|
|
18
|
+
MAGENTA = "\033[0;35m"
|
|
19
|
+
BOLD = "\033[1m"
|
|
20
|
+
NC = "\033[0m"
|
|
21
|
+
|
|
22
|
+
def banner():
|
|
23
|
+
print(f"{CYAN}")
|
|
24
|
+
print(" ███╗ ███╗██████╗ █████╗ ███╗ ██╗")
|
|
25
|
+
print(" ████╗ ████║██╔══██╗██╔══██╗████╗ ██║")
|
|
26
|
+
print(" ██╔████╔██║██║ ██║███████║██╔██╗ ██║")
|
|
27
|
+
print(" ██║╚██╔╝██║██║ ██║██╔══██║██║╚██╗██║")
|
|
28
|
+
print(" ██║ ╚═╝ ██║██████╔╝██║ ██║██║ ╚████║")
|
|
29
|
+
print(" ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝")
|
|
30
|
+
print(f"{NC}")
|
|
31
|
+
print(f" {BOLD}Multi-Agent Development Agentic Network{NC} v{VERSION}\n")
|
|
32
|
+
|
|
33
|
+
def show_help():
|
|
34
|
+
banner()
|
|
35
|
+
print(f"{BOLD}USAGE{NC}")
|
|
36
|
+
print(" mdan <command> [options]\n")
|
|
37
|
+
print(f"{BOLD}COMMANDS{NC}")
|
|
38
|
+
print(" init [name] Create a new project")
|
|
39
|
+
print(" attach [--rebuild] Add MDAN to existing project")
|
|
40
|
+
print(" status Show project status")
|
|
41
|
+
print(" phase [1-5] Show phase guide")
|
|
42
|
+
print(" agent [name] Show agent prompt")
|
|
43
|
+
print(" oc Copy orchestrator prompt to clipboard")
|
|
44
|
+
print(" skills List available skills")
|
|
45
|
+
print(" version Show version\n")
|
|
46
|
+
print(f"{BOLD}EXAMPLES{NC}")
|
|
47
|
+
print(" mdan init my-app # New project")
|
|
48
|
+
print(" cd my-project && mdan attach # Existing project")
|
|
49
|
+
print(" mdan attach --rebuild # Rebuild from scratch\n")
|
|
50
|
+
print(f"{BOLD}AGENTS{NC}")
|
|
51
|
+
print(" product, architect, ux, dev, test, security, devops, doc")
|
|
52
|
+
|
|
53
|
+
def cmd_init(name="my-project"):
|
|
54
|
+
print(f"{CYAN}🚀 Creating: {BOLD}{name}{NC}")
|
|
55
|
+
|
|
56
|
+
dirs = [
|
|
57
|
+
f"{name}/.mdan/agents", f"{name}/.mdan/skills", f"{name}/mdan_output",
|
|
58
|
+
f"{name}/.claude/skills", f"{name}/.github"
|
|
59
|
+
]
|
|
60
|
+
for d in dirs:
|
|
61
|
+
Path(d).mkdir(parents=True, exist_ok=True)
|
|
62
|
+
|
|
63
|
+
shutil.copy(f"{MDAN_DIR}/core/orchestrator.md", f"{name}/.mdan/")
|
|
64
|
+
shutil.copy(f"{MDAN_DIR}/core/universal-envelope.md", f"{name}/.mdan/")
|
|
65
|
+
|
|
66
|
+
for f in Path(f"{MDAN_DIR}/agents").glob("*.md"):
|
|
67
|
+
shutil.copy(f, f"{name}/.mdan/agents/")
|
|
68
|
+
|
|
69
|
+
for f in Path(f"{MDAN_DIR}/templates").glob("*.md"):
|
|
70
|
+
shutil.copy(f, f"{name}/mdan_output/")
|
|
71
|
+
|
|
72
|
+
skills_dir = Path(f"{MDAN_DIR}/skills")
|
|
73
|
+
if skills_dir.exists():
|
|
74
|
+
for s in skills_dir.iterdir():
|
|
75
|
+
if s.is_dir():
|
|
76
|
+
shutil.copytree(s, f"{name}/.mdan/skills/{s.name}", dirs_exist_ok=True)
|
|
77
|
+
shutil.copytree(s, f"{name}/.claude/skills/{s.name}", dirs_exist_ok=True)
|
|
78
|
+
|
|
79
|
+
cursorrules = Path(f"{MDAN_DIR}/core/orchestrator.md").read_text()
|
|
80
|
+
cursorrules += "\n\n## CURSOR INSTRUCTIONS\nAgent files in .mdan/agents/\nSkills in .mdan/skills/"
|
|
81
|
+
Path(f"{name}/.cursorrules").write_text(cursorrules)
|
|
82
|
+
shutil.copy(f"{name}/.cursorrules", f"{name}/.windsurfrules")
|
|
83
|
+
shutil.copy(f"{MDAN_DIR}/core/orchestrator.md", f"{name}/.github/copilot-instructions.md")
|
|
84
|
+
Path(f"{name}/README.md").write_text(f"# {name}\n\n> Built with MDAN\n")
|
|
85
|
+
|
|
86
|
+
print(f"{GREEN}✅ Created {name}/{NC}\n")
|
|
87
|
+
print(f" {BOLD}Next:{NC} cursor {name}")
|
|
88
|
+
|
|
89
|
+
def cmd_attach(rebuild=None):
|
|
90
|
+
project = Path.cwd().name
|
|
91
|
+
|
|
92
|
+
if rebuild == "--rebuild":
|
|
93
|
+
print(f"{MAGENTA}🔄 REBUILD MODE: {BOLD}{project}{NC}")
|
|
94
|
+
else:
|
|
95
|
+
print(f"{CYAN}🔗 Attaching to: {BOLD}{project}{NC}")
|
|
96
|
+
|
|
97
|
+
Path(".mdan/agents").mkdir(parents=True, exist_ok=True)
|
|
98
|
+
Path(".mdan/skills").mkdir(parents=True, exist_ok=True)
|
|
99
|
+
Path(".claude/skills").mkdir(parents=True, exist_ok=True)
|
|
100
|
+
Path(".github").mkdir(parents=True, exist_ok=True)
|
|
101
|
+
|
|
102
|
+
shutil.copy(f"{MDAN_DIR}/core/orchestrator.md", ".mdan/")
|
|
103
|
+
shutil.copy(f"{MDAN_DIR}/core/universal-envelope.md", ".mdan/")
|
|
104
|
+
|
|
105
|
+
for f in Path(f"{MDAN_DIR}/agents").glob("*.md"):
|
|
106
|
+
shutil.copy(f, ".mdan/agents/")
|
|
107
|
+
|
|
108
|
+
skills_dir = Path(f"{MDAN_DIR}/skills")
|
|
109
|
+
if skills_dir.exists():
|
|
110
|
+
for s in skills_dir.iterdir():
|
|
111
|
+
if s.is_dir():
|
|
112
|
+
shutil.copytree(s, f".mdan/skills/{s.name}", dirs_exist_ok=True)
|
|
113
|
+
shutil.copytree(s, f".claude/skills/{s.name}", dirs_exist_ok=True)
|
|
114
|
+
|
|
115
|
+
cursorrules = Path(f"{MDAN_DIR}/core/orchestrator.md").read_text()
|
|
116
|
+
if rebuild == "--rebuild":
|
|
117
|
+
cursorrules += "\n\n## REBUILD MODE\nAnalyze existing code then rewrite from scratch."
|
|
118
|
+
else:
|
|
119
|
+
cursorrules += "\n\n## EXISTING PROJECT\nAnalyze codebase before making changes."
|
|
120
|
+
Path(".cursorrules").write_text(cursorrules)
|
|
121
|
+
shutil.copy(".cursorrules", ".windsurfrules")
|
|
122
|
+
shutil.copy(f"{MDAN_DIR}/core/orchestrator.md", ".github/copilot-instructions.md")
|
|
123
|
+
|
|
124
|
+
print(f"{GREEN}✅ MDAN ready!{NC}\n")
|
|
125
|
+
print(f" {BOLD}Next:{NC} Run {CYAN}mdan oc{NC} to copy prompt")
|
|
126
|
+
if rebuild == "--rebuild":
|
|
127
|
+
print(f" Start: {CYAN}MDAN REBUILD: Analyze and rewrite this project{NC}")
|
|
128
|
+
else:
|
|
129
|
+
print(f" Start: {CYAN}MDAN: Analyze this project{NC}")
|
|
130
|
+
|
|
131
|
+
def cmd_oc():
|
|
132
|
+
import subprocess
|
|
133
|
+
orch_file = Path(".mdan/orchestrator.md")
|
|
134
|
+
if not orch_file.exists():
|
|
135
|
+
orch_file = Path(f"{MDAN_DIR}/core/orchestrator.md")
|
|
136
|
+
|
|
137
|
+
if orch_file.exists():
|
|
138
|
+
content = orch_file.read_text()
|
|
139
|
+
try:
|
|
140
|
+
if sys.platform == "darwin":
|
|
141
|
+
subprocess.run("pbcopy", universal_newlines=True, input=content, check=True)
|
|
142
|
+
elif sys.platform == "win32":
|
|
143
|
+
subprocess.run("clip", universal_newlines=True, input=content, check=True)
|
|
144
|
+
elif sys.platform == "linux":
|
|
145
|
+
if shutil.which("xclip"):
|
|
146
|
+
subprocess.run(["xclip", "-selection", "clipboard"], universal_newlines=True, input=content, check=True)
|
|
147
|
+
elif shutil.which("wl-copy"):
|
|
148
|
+
subprocess.run(["wl-copy"], universal_newlines=True, input=content, check=True)
|
|
149
|
+
else:
|
|
150
|
+
raise Exception("No clipboard tool found")
|
|
151
|
+
print(f"{GREEN}✅ Orchestrator prompt copied to clipboard!{NC}")
|
|
152
|
+
print(" Paste it into Claude, ChatGPT, or your favorite LLM.")
|
|
153
|
+
except Exception:
|
|
154
|
+
print(content)
|
|
155
|
+
print(f"\n{YELLOW}⚠️ Could not copy to clipboard automatically. Please copy the text above.{NC}")
|
|
156
|
+
else:
|
|
157
|
+
print(f"{RED}Orchestrator file not found.{NC}")
|
|
158
|
+
|
|
159
|
+
def cmd_status():
|
|
160
|
+
if Path(".mdan/orchestrator.md").exists():
|
|
161
|
+
print(f"{GREEN}✅ MDAN is active in this project{NC}")
|
|
162
|
+
if Path(".mdan/STATUS.md").exists():
|
|
163
|
+
print(Path(".mdan/STATUS.md").read_text())
|
|
164
|
+
else:
|
|
165
|
+
print(f"{YELLOW}No MDAN project here.{NC}")
|
|
166
|
+
print(" Run: mdan init [name] or mdan attach")
|
|
167
|
+
|
|
168
|
+
def cmd_phase(num, action=None):
|
|
169
|
+
import subprocess
|
|
170
|
+
phases = {
|
|
171
|
+
"1": ("01-discover.md", "DISCOVER"),
|
|
172
|
+
"discover": ("01-discover.md", "DISCOVER"),
|
|
173
|
+
"2": ("02-design.md", "DESIGN"),
|
|
174
|
+
"design": ("02-design.md", "DESIGN"),
|
|
175
|
+
"3": ("03-build.md", "BUILD"),
|
|
176
|
+
"build": ("03-build.md", "BUILD"),
|
|
177
|
+
"4": ("04-verify.md", "VERIFY"),
|
|
178
|
+
"verify": ("04-verify.md", "VERIFY"),
|
|
179
|
+
"5": ("05-ship.md", "SHIP"),
|
|
180
|
+
"ship": ("05-ship.md", "SHIP")
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if num not in phases:
|
|
184
|
+
print("Usage: mdan phase [1-5|name] [copy]")
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
file, name = phases[num]
|
|
188
|
+
phase_file = Path(f"{MDAN_DIR}/phases/{file}")
|
|
189
|
+
|
|
190
|
+
if phase_file.exists():
|
|
191
|
+
content = phase_file.read_text()
|
|
192
|
+
if action in ["copy", "-c"]:
|
|
193
|
+
try:
|
|
194
|
+
if sys.platform == "darwin":
|
|
195
|
+
subprocess.run("pbcopy", universal_newlines=True, input=content, check=True)
|
|
196
|
+
elif sys.platform == "win32":
|
|
197
|
+
subprocess.run("clip", universal_newlines=True, input=content, check=True)
|
|
198
|
+
elif sys.platform == "linux":
|
|
199
|
+
if shutil.which("xclip"):
|
|
200
|
+
subprocess.run(["xclip", "-selection", "clipboard"], universal_newlines=True, input=content, check=True)
|
|
201
|
+
elif shutil.which("wl-copy"):
|
|
202
|
+
subprocess.run(["wl-copy"], universal_newlines=True, input=content, check=True)
|
|
203
|
+
else:
|
|
204
|
+
raise Exception("No clipboard tool found")
|
|
205
|
+
print(f"{GREEN}✅ Phase {name} prompt copied to clipboard!{NC}")
|
|
206
|
+
print(" Paste it into your LLM to start the phase.")
|
|
207
|
+
except Exception:
|
|
208
|
+
print(content)
|
|
209
|
+
print(f"\n{YELLOW}⚠️ Could not copy automatically. Please copy the text above.{NC}")
|
|
210
|
+
else:
|
|
211
|
+
print(f"{CYAN}{BOLD}Phase {name}{NC}")
|
|
212
|
+
print(content)
|
|
213
|
+
print(f"\n{YELLOW}Tip: Run '{CYAN}mdan phase {num} copy{YELLOW}' to copy this content to clipboard.{NC}")
|
|
214
|
+
else:
|
|
215
|
+
print(f"Phase file not found: {file}")
|
|
216
|
+
|
|
217
|
+
def cmd_agent(name):
|
|
218
|
+
file = Path(f"{MDAN_DIR}/agents/{name}.md")
|
|
219
|
+
if file.exists():
|
|
220
|
+
print(file.read_text())
|
|
221
|
+
else:
|
|
222
|
+
print("Agents: product, architect, ux, dev, test, security, devops, doc")
|
|
223
|
+
|
|
224
|
+
def cmd_skills():
|
|
225
|
+
print(f"{CYAN}Skills:{NC}")
|
|
226
|
+
skills_dir = Path(f"{MDAN_DIR}/skills")
|
|
227
|
+
if skills_dir.exists():
|
|
228
|
+
for s in skills_dir.iterdir():
|
|
229
|
+
print(f" {s.name}")
|
|
230
|
+
else:
|
|
231
|
+
print(" No skills installed")
|
|
232
|
+
|
|
233
|
+
def main():
|
|
234
|
+
args = sys.argv[1:]
|
|
235
|
+
cmd = args[0] if args else "help"
|
|
236
|
+
|
|
237
|
+
if cmd in ["help", "--help", "-h", None]:
|
|
238
|
+
show_help()
|
|
239
|
+
elif cmd == "init":
|
|
240
|
+
cmd_init(args[1] if len(args) > 1 else "my-project")
|
|
241
|
+
elif cmd == "attach":
|
|
242
|
+
cmd_attach(args[1] if len(args) > 1 else None)
|
|
243
|
+
elif cmd == "oc":
|
|
244
|
+
cmd_oc()
|
|
245
|
+
elif cmd == "status":
|
|
246
|
+
cmd_status()
|
|
247
|
+
elif cmd == "phase":
|
|
248
|
+
cmd_phase(args[1] if len(args) > 1 else None, args[2] if len(args) > 2 else None)
|
|
249
|
+
elif cmd == "agent":
|
|
250
|
+
cmd_agent(args[1] if len(args) > 1 else None)
|
|
251
|
+
elif cmd == "skills":
|
|
252
|
+
cmd_skills()
|
|
253
|
+
elif cmd in ["version", "-v"]:
|
|
254
|
+
print(f"MDAN v{VERSION}")
|
|
255
|
+
else:
|
|
256
|
+
print(f"Unknown: {cmd}. Run: mdan help")
|
|
257
|
+
|
|
258
|
+
if __name__ == "__main__":
|
|
259
|
+
main()
|