dasa-sradha-kit 5.0.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 (54) hide show
  1. package/.agent/.shared/infinite-memory.md +19 -0
  2. package/.agent/.shared/max-power-core.md +27 -0
  3. package/.agent/ARCHITECTURE.md +104 -0
  4. package/.agent/agents/dasa-dharma.md +21 -0
  5. package/.agent/agents/dasa-dwipa.md +21 -0
  6. package/.agent/agents/dasa-indra.md +21 -0
  7. package/.agent/agents/dasa-kala.md +21 -0
  8. package/.agent/agents/dasa-mpu.md +21 -0
  9. package/.agent/agents/dasa-nala.md +21 -0
  10. package/.agent/agents/dasa-patih.md +21 -0
  11. package/.agent/agents/dasa-rsi.md +25 -0
  12. package/.agent/agents/dasa-sastra.md +21 -0
  13. package/.agent/agents/dasa-widya.md +21 -0
  14. package/.agent/rules/GEMINI.md +183 -0
  15. package/.agent/scripts/api_validator.py +70 -0
  16. package/.agent/scripts/arch_mapper.py +101 -0
  17. package/.agent/scripts/compact_memory.py +68 -0
  18. package/.agent/scripts/complexity_scorer.py +82 -0
  19. package/.agent/scripts/context_mapper.py +91 -0
  20. package/.agent/scripts/design_engine.py +108 -0
  21. package/.agent/scripts/design_memory_sync.py +87 -0
  22. package/.agent/scripts/lint_fixer.py +79 -0
  23. package/.agent/scripts/qa_gate.py +84 -0
  24. package/.agent/scripts/security_scan.py +82 -0
  25. package/.agent/scripts/semantic-scan.py +56 -0
  26. package/.agent/scripts/skill_search.py +91 -0
  27. package/.agent/scripts/status_parser.py +78 -0
  28. package/.agent/scripts/test_runner.py +98 -0
  29. package/.agent/scripts/validate_env.py +71 -0
  30. package/.agent/scripts/web_scraper.py +86 -0
  31. package/.agent/scripts/workspace-mapper.py +58 -0
  32. package/.agent/skills/.gitkeep +0 -0
  33. package/.agent/workflows/dasa-api.md +42 -0
  34. package/.agent/workflows/dasa-assimilate.md +44 -0
  35. package/.agent/workflows/dasa-commit.md +46 -0
  36. package/.agent/workflows/dasa-docs.md +46 -0
  37. package/.agent/workflows/dasa-e2e.md +41 -0
  38. package/.agent/workflows/dasa-feature.md +46 -0
  39. package/.agent/workflows/dasa-fix.md +37 -0
  40. package/.agent/workflows/dasa-init.md +29 -0
  41. package/.agent/workflows/dasa-plan.md +56 -0
  42. package/.agent/workflows/dasa-pr.md +47 -0
  43. package/.agent/workflows/dasa-refactor.md +44 -0
  44. package/.agent/workflows/dasa-seed.md +44 -0
  45. package/.agent/workflows/dasa-start-work.md +51 -0
  46. package/.agent/workflows/dasa-status.md +58 -0
  47. package/.agent/workflows/dasa-sync.md +39 -0
  48. package/.agent/workflows/dasa-uninstall.md +30 -0
  49. package/CHANGELOG.md +94 -0
  50. package/LICENSE +21 -0
  51. package/README.md +135 -0
  52. package/bin/cli.js +218 -0
  53. package/bin/dasa-cli.js +100 -0
  54. package/package.json +37 -0
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Dasa Mpu: The Cartographer (arch_mapper.py)
4
+ Parses structural and dependency files (package.json, go.mod, requirements.txt)
5
+ and outputs a highly compressed TOON map of the backend architecture.
6
+ Saves Mpu from spending tokens reading massive dependency files line-by-line.
7
+ """
8
+
9
+ import os
10
+ import sys
11
+ import json
12
+
13
+ def parse_package_json():
14
+ """Extract dependencies and scripts from package.json."""
15
+ if not os.path.exists("package.json"):
16
+ return None
17
+
18
+ try:
19
+ with open("package.json", "r") as f:
20
+ data = json.load(f)
21
+
22
+ deps = list(data.get("dependencies", {}).keys())
23
+ scripts = list(data.get("scripts", {}).keys())
24
+
25
+ return {
26
+ "type": "Node/JS",
27
+ "name": data.get("name", "Unknown"),
28
+ "core_deps": deps[:15], # Only take top 15 to save tokens
29
+ "total_deps": len(deps),
30
+ "scripts": scripts
31
+ }
32
+ except Exception:
33
+ return None
34
+
35
+ def parse_go_mod():
36
+ """Extract module info from go.mod."""
37
+ if not os.path.exists("go.mod"):
38
+ return None
39
+
40
+ try:
41
+ with open("go.mod", "r") as f:
42
+ lines = f.readlines()
43
+
44
+ mod_name = "Unknown"
45
+ deps = []
46
+ for line in lines:
47
+ line = line.strip()
48
+ if line.startswith("module "):
49
+ mod_name = line.split()[1]
50
+ elif line and not line.startswith("go ") and not line.startswith("require") and not line.startswith(")"):
51
+ # Rough extraction of dependency names
52
+ parts = line.split()
53
+ if len(parts) > 0 and "." in parts[0]:
54
+ deps.append(parts[0])
55
+
56
+ return {
57
+ "type": "Go Module",
58
+ "name": mod_name,
59
+ "core_deps": deps[:15],
60
+ "total_deps": len(deps)
61
+ }
62
+ except Exception:
63
+ return None
64
+
65
+ def main():
66
+ print("🛡️ [Dasa Mpu] Initializing Architectural Cartographer...")
67
+
68
+ arch_data = {}
69
+
70
+ node_data = parse_package_json()
71
+ if node_data:
72
+ arch_data["Node"] = node_data
73
+
74
+ go_data = parse_go_mod()
75
+ if go_data:
76
+ arch_data["Go"] = go_data
77
+
78
+ if not arch_data:
79
+ print("🟡 [Mpu Cartographer] No recognized architecture definitions found. Pass.")
80
+ sys.exit(0)
81
+
82
+ # Generate the highly compressed TOON map
83
+ toon_map = "# Architectural Map\n"
84
+ for ecosystem, data in arch_data.items():
85
+ toon_map += f"\n## {ecosystem}: {data.get('name')}\n"
86
+ toon_map += f"- **Total Dependencies:** {data.get('total_deps')}\n"
87
+ toon_map += f"- **Core Tools:** {', '.join(data.get('core_deps', []))}\n"
88
+ if "scripts" in data:
89
+ toon_map += f"- **Available Scripts:** {', '.join(data.get('scripts', []))}\n"
90
+
91
+ os.makedirs(".artifacts", exist_ok=True)
92
+ out_path = ".artifacts/architecture_map.toon"
93
+
94
+ with open(out_path, "w") as f:
95
+ f.write(toon_map)
96
+
97
+ print(f"🟢 [Mpu Cartographer] Architecture successfully compressed into {out_path}.")
98
+ sys.exit(0)
99
+
100
+ if __name__ == "__main__":
101
+ main()
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Dasa Patih: Temporal Knowledge Graph Compactor (compact_memory.py)
4
+ Imitates the 5-sector cognitive engine from `OpenMemory`.
5
+ Compresses sprawling chat histories into specific TOON memory sectors.
6
+ """
7
+
8
+ import os
9
+ import sys
10
+ import json
11
+ import datetime
12
+
13
+ def init_memory_vault():
14
+ return {
15
+ "episodic": [], # Events (e.g., "User asked for a login page")
16
+ "semantic": [], # Facts (e.g., "The API is hosted on port 8080")
17
+ "procedural": [], # Skills (e.g., "How to deploy to Railway")
18
+ "emotional": [], # Preferences (e.g., "User hates Tailwind")
19
+ "reflective": [] # Insights (e.g., "We should use Postgres instead of MySQL next time")
20
+ }
21
+
22
+ def add_memory(vault, sector, content, context_id="system"):
23
+ """Adds a memory to the designated sector with temporal metadata."""
24
+ if sector not in vault:
25
+ print(f"Error: Unknown memory sector '{sector}'")
26
+ return
27
+
28
+ memory_node = {
29
+ "content": content,
30
+ "valid_from": datetime.datetime.now().isoformat(),
31
+ "context": context_id
32
+ }
33
+
34
+ vault[sector].append(memory_node)
35
+ return memory_node
36
+
37
+ def main():
38
+ vault_path = ".artifacts/dasa_memory.toon"
39
+ os.makedirs(".artifacts", exist_ok=True)
40
+
41
+ # Load existing vault or create new
42
+ if os.path.exists(vault_path):
43
+ with open(vault_path, "r") as f:
44
+ try:
45
+ vault = json.load(f)
46
+ except json.JSONDecodeError:
47
+ vault = init_memory_vault()
48
+ else:
49
+ vault = init_memory_vault()
50
+
51
+ if len(sys.argv) < 3:
52
+ print("Usage: python3 compact_memory.py <sector> <memory_content>")
53
+ print("Sectors: episodic, semantic, procedural, emotional, reflective")
54
+ sys.exit(1)
55
+
56
+ sector = sys.argv[1]
57
+ content = " ".join(sys.argv[2:])
58
+
59
+ print(f"🧠 [Dasa Patih] Integrating memory into {sector.upper()} sector...")
60
+ add_memory(vault, sector, content)
61
+
62
+ with open(vault_path, "w") as f:
63
+ json.dump(vault, f, indent=2)
64
+
65
+ print(f"✅ Memory firmly consolidated in {vault_path}. Temporal Graph updated.")
66
+
67
+ if __name__ == "__main__":
68
+ main()
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Dasa Rsi: The Oracle's Lens (complexity_scorer.py)
4
+ Performs static analysis on source code files to calculate cyclomatic complexity.
5
+ Outputs only the specific 'hotspot' functions and line numbers, preventing Rsi
6
+ from having to read the entire file line-by-line.
7
+ """
8
+
9
+ import sys
10
+ import os
11
+ import re
12
+
13
+ def compute_complexity(code_chunk):
14
+ """
15
+ Very naive cyclomatic complexity estimator wrapper.
16
+ Counts branching keywords as a rough heuristics.
17
+ """
18
+ keywords = [
19
+ r'\bif\b', r'\belse\b', r'\bfor\b', r'\bwhile\b',
20
+ r'\bswitch\b', r'\bcase\b', r'\bcatch\b', r'\b\?\b', r'&&', r'\|\|'
21
+ ]
22
+ complexity = 1
23
+ for kw in keywords:
24
+ complexity += len(re.findall(kw, code_chunk))
25
+ return complexity
26
+
27
+ def analyze_file(filepath):
28
+ """Roughly chunks a file into blocks and scores them."""
29
+ if not os.path.exists(filepath):
30
+ return None
31
+
32
+ with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
33
+ lines = f.readlines()
34
+
35
+ hotspots = []
36
+ chunk_size = 20 # Lines
37
+
38
+ for i in range(0, len(lines), chunk_size):
39
+ chunk = "".join(lines[i:i+chunk_size])
40
+ score = compute_complexity(chunk)
41
+
42
+ # Arbitrary threshold to define a "hotspot" (high branching logic)
43
+ if score >= 10:
44
+ hotspots.append({
45
+ "line_start": i + 1,
46
+ "line_end": min(i + chunk_size, len(lines)),
47
+ "score": score,
48
+ "preview": lines[i].strip()
49
+ })
50
+
51
+ return hotspots
52
+
53
+ def main():
54
+ if len(sys.argv) < 2:
55
+ print("Usage: python3 complexity_scorer.py <file_path>")
56
+ sys.exit(1)
57
+
58
+ target_file = sys.argv[1]
59
+ print(f"🛡️ [Dasa Rsi] Analyzing structural complexity of {target_file}...")
60
+
61
+ hotspots = analyze_file(target_file)
62
+
63
+ if hotspots is None:
64
+ print(f"🔴 [Rsi Lens] File {target_file} not found.")
65
+ sys.exit(1)
66
+
67
+ if not hotspots:
68
+ print(f"🟢 [Rsi Lens] No significant structural hotspots detected in {os.path.basename(target_file)}.")
69
+ sys.exit(0)
70
+
71
+ # Sort by highest complexity
72
+ hotspots.sort(key=lambda x: x["score"], reverse=True)
73
+
74
+ print("\n🔍 HIGH COMPLEXITY HOTSPOTS DETECTED:")
75
+ for h in hotspots[:5]: # Only show top 5 worst offenders
76
+ print(f" - Lines {h['line_start']}-{h['line_end']} | Complexity Score: {h['score']} | Context: `{h['preview'][:40]}...`")
77
+
78
+ print("\n[Rsi Lens] Recommend running `view_file` exclusively on these line ranges.")
79
+ sys.exit(0)
80
+
81
+ if __name__ == "__main__":
82
+ main()
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Dasa Patih: Zero-Dependency Context Mapper (context_mapper.py)
4
+ Replicates the focused vector mapping of `amdb` and `osgrep` but runs 100% natively.
5
+ Extracts class and function signatures from Python/JS/TS/Go/Rust codebases
6
+ to build highly compressed `.artifacts/context.toon` snippets for the LLM.
7
+ """
8
+
9
+ import sys
10
+ import os
11
+ import re
12
+ import ast
13
+ from pathlib import Path
14
+
15
+ def parse_python(filepath: Path):
16
+ signatures = []
17
+ try:
18
+ content = filepath.read_text(encoding="utf-8")
19
+ tree = ast.parse(content)
20
+ for node in ast.walk(tree):
21
+ if isinstance(node, ast.FunctionDef) or isinstance(node, ast.AsyncFunctionDef):
22
+ signatures.append(f"def {node.name}(...)")
23
+ elif isinstance(node, ast.ClassDef):
24
+ signatures.append(f"class {node.name}")
25
+ except Exception:
26
+ pass
27
+ return signatures
28
+
29
+ def parse_regex(filepath: Path, class_pattern, func_pattern):
30
+ signatures = []
31
+ try:
32
+ content = filepath.read_text(encoding="utf-8")
33
+ lines = content.splitlines()
34
+ for line in lines:
35
+ if re.search(class_pattern, line):
36
+ signatures.append(line.strip().rstrip('{'))
37
+ elif re.search(func_pattern, line):
38
+ signatures.append(line.strip().rstrip('{'))
39
+ except Exception:
40
+ pass
41
+ return signatures
42
+
43
+ def parse_file(filepath: Path):
44
+ ext = filepath.suffix
45
+ if ext == ".py":
46
+ return parse_python(filepath)
47
+ elif ext in [".js", ".ts", ".jsx", ".tsx"]:
48
+ return parse_regex(filepath, r"^\s*(export\s+)?class\s+\w+", r"^\s*(export\s+)?(async\s+)?function\s+\w+|^\s*(export\s+)?const\s+\w+\s*=\s*\(.*\)\s*=>")
49
+ elif ext == ".go":
50
+ return parse_regex(filepath, r"^\s*type\s+\w+\s+struct", r"^\s*func\s+")
51
+ elif ext == ".rs":
52
+ return parse_regex(filepath, r"^\s*(pub\s+)?(struct|enum|trait)\s+\w+", r"^\s*(pub\s+)?(async\s+)?fn\s+\w+")
53
+ return []
54
+
55
+ def main():
56
+ if len(sys.argv) < 2:
57
+ print("Usage: context_mapper.py <directory>")
58
+ sys.exit(1)
59
+
60
+ target_dir = Path(sys.argv[1])
61
+ if not target_dir.exists() or not target_dir.is_dir():
62
+ print(f"Directory {target_dir} not found.")
63
+ sys.exit(1)
64
+
65
+ print(f"🗺️ Dasa Patih: Mapping codebase context for {target_dir}...")
66
+
67
+ context_lines = [f"# Codebase Context: {target_dir.name}\n"]
68
+
69
+ for root, dirs, files in os.walk(target_dir):
70
+ # Exclude typical noise
71
+ dirs[:] = [d for d in dirs if d not in [".git", "node_modules", "target", "dist", ".gemini", ".artifacts"]]
72
+ for file in files:
73
+ ext = Path(file).suffix
74
+ if ext in [".py", ".js", ".ts", ".jsx", ".tsx", ".go", ".rs"]:
75
+ filepath = Path(root) / file
76
+ sigs = parse_file(filepath)
77
+ if sigs:
78
+ rel_path = filepath.relative_to(target_dir)
79
+ context_lines.append(f"\n## {rel_path}")
80
+ for sig in sigs:
81
+ context_lines.append(f"- {sig}")
82
+
83
+ artifacts_dir = target_dir / ".artifacts"
84
+ artifacts_dir.mkdir(exist_ok=True)
85
+ out_file = artifacts_dir / "context.toon"
86
+
87
+ out_file.write_text("\n".join(context_lines), encoding="utf-8")
88
+ print(f"✅ Context successfully compressed into {out_file}")
89
+
90
+ if __name__ == "__main__":
91
+ main()
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Dasa Mpu / Dasa Nala: The Design Engine (design_engine.py)
4
+ Assimilates logic from `ui-ux-pro-max` and `design-rules-ai`.
5
+ Prevents AI hallucination by programmatically generating a strict `MASTER.md`
6
+ design system with hardcoded spacing, radiuses, and industry-specific palettes.
7
+ """
8
+
9
+ import os
10
+ import sys
11
+ import json
12
+
13
+ # Statically enforce design-rules-ai constraints
14
+ ANTI_AI_CONSTRAINTS = [
15
+ "NEVER use generic placeholder names like 'Acme Corp' or 'John Doe'. Use realistic data.",
16
+ "NEVER generate raw SVG code. You MUST use standard libraries like Lucide or Heroicons.",
17
+ "NEVER use random spacing like 7px or 13px. You MUST adhere to the [4, 8, 12, 16, 24, 32, 48, 64] scale.",
18
+ "NEVER use random border-radiuses. 4px for inputs, 8px for cards, 12px for modals, 9999px for pills.",
19
+ "NEVER use rainbow colors. Limit to 1 primary, 1 secondary, and neutral grays."
20
+ ]
21
+
22
+ # Basic industry reasoning matrix (inspired by ui-ux-pro-max)
23
+ INDUSTRY_MATRIX = {
24
+ "saas": {
25
+ "style": "Glassmorphism / Minimal",
26
+ "colors": {"primary": "#0F172A", "secondary": "#3B82F6", "accent": "#10B981"},
27
+ "fonts": "Inter / Roboto Mono",
28
+ "radius": "8px cards, 4px inputs"
29
+ },
30
+ "fintech": {
31
+ "style": "High-Contrast / Trust-focused",
32
+ "colors": {"primary": "#000000", "secondary": "#111827", "accent": "#059669"},
33
+ "fonts": "Plus Jakarta Sans",
34
+ "radius": "4px universal"
35
+ },
36
+ "healthcare": {
37
+ "style": "Clean / Accessible (WCAG AA)",
38
+ "colors": {"primary": "#FFFFFF", "secondary": "#0284C7", "accent": "#14B8A6"},
39
+ "fonts": "Open Sans",
40
+ "radius": "12px soft"
41
+ },
42
+ "ecommerce": {
43
+ "style": "Hero-Centric / Conversion Focused",
44
+ "colors": {"primary": "#18181B", "secondary": "#F43F5E", "accent": "#F59E0B"},
45
+ "fonts": "Outfit / Playfair Display",
46
+ "radius": "0px sharp or 9999px pills"
47
+ }
48
+ }
49
+
50
+ def generate_design_system(industry):
51
+ """Generate a highly constrained MASTER.md design TOON."""
52
+ target = industry.lower()
53
+
54
+ # Default to SaaS if unknown
55
+ if target not in INDUSTRY_MATRIX:
56
+ target = "saas"
57
+
58
+ specs = INDUSTRY_MATRIX[target]
59
+
60
+ toon = f"""# MASTER DESIGN SYSTEM: {industry.upper()}
61
+
62
+ > **CRITICAL**: This document overrides all LLM design instincts. Do not hallucinate styles outside of this spec.
63
+
64
+ ## 1. Visual Identity
65
+ - **Design Style:** {specs['style']}
66
+ - **Primary Font:** {specs['fonts']}
67
+ - **Border Radius Rule:** {specs['radius']}
68
+
69
+ ## 2. Color Palette (Strict Limit)
70
+ - **Primary:** `{specs['colors']['primary']}`
71
+ - **Secondary:** `{specs['colors']['secondary']}`
72
+ - **Accent/CTA:** `{specs['colors']['accent']}`
73
+
74
+ ## 3. The 'Anti-AI' Constraints (MANDATORY)
75
+ """
76
+ for rule in ANTI_AI_CONSTRAINTS:
77
+ toon += f"- {rule}\n"
78
+
79
+ toon += "\n## 4. Spacing Scale (Strict)\n"
80
+ toon += "You are ONLY allowed to use these sizing steps (rem/px):\n"
81
+ toon += "`[0.25rem/4px, 0.5rem/8px, 0.75rem/12px, 1rem/16px, 1.5rem/24px, 2rem/32px, 3rem/48px, 4rem/64px]`\n"
82
+
83
+ return toon
84
+
85
+ def main():
86
+ if len(sys.argv) < 2:
87
+ print("Usage: python3 design_engine.py <industry_type>")
88
+ print("Options: saas, fintech, healthcare, ecommerce")
89
+ sys.exit(1)
90
+
91
+ industry = sys.argv[1]
92
+
93
+ print(f"🛡️ [Dasa Mpu] Booting Design Engine for industry: {industry}...")
94
+
95
+ toon_content = generate_design_system(industry)
96
+
97
+ os.makedirs(".design-memory", exist_ok=True)
98
+ out_path = ".design-memory/MASTER.md"
99
+
100
+ with open(out_path, "w") as f:
101
+ f.write(toon_content)
102
+
103
+ print(f"🟢 [Mpu Architect] Strict Design System generated at {out_path}.")
104
+ print("Dasa Nala is now bound by these cognitive constraints.")
105
+ sys.exit(0)
106
+
107
+ if __name__ == "__main__":
108
+ main()
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Dasa Nala: The Vision Bridge (design_memory_sync.py)
4
+ Natively integrates with the `memvid/design-memory` architecture.
5
+ Reads the highly semantic markdown files generated by design-memory OCR
6
+ and compiles them into a single, token-compressed TOON block for Dasa Nala.
7
+ Prevents "vision blowout" by substituting 40 PNG mockups with pure semantic text.
8
+ """
9
+
10
+ import os
11
+ import sys
12
+
13
+ def check_design_memory():
14
+ """Verify that the user actually has a populated .design-memory folder."""
15
+ base_path = ".design-memory"
16
+ if not os.path.exists(base_path):
17
+ return False
18
+
19
+ # It needs to have at least one of the core files
20
+ core_files = ["style.md", "layout.md", "components.md", "reference.md"]
21
+ return any(os.path.exists(os.path.join(base_path, f)) for f in core_files)
22
+
23
+ def read_and_compress(filepath, max_lines=150):
24
+ """Read a markdown file and truncate if it's insanely long to protect context."""
25
+ if not os.path.exists(filepath):
26
+ return ""
27
+
28
+ try:
29
+ with open(filepath, "r", encoding='utf-8') as f:
30
+ lines = f.readlines()
31
+
32
+ if len(lines) > max_lines:
33
+ # Take front matter and trailing summary, drop the middle
34
+ head = "".join(lines[:max_lines//2])
35
+ tail = "".join(lines[-(max_lines//2):])
36
+ return head + "\n\n... [CONTENT COMPRESSED TO SAVE TOKENS] ...\n\n" + tail
37
+ return "".join(lines)
38
+ except Exception as e:
39
+ return f"Error reading {filepath}: {e}"
40
+
41
+ def main():
42
+ print("🛡️ [Dasa Nala] Analyzing `.design-memory/` Vision Bridge...")
43
+
44
+ if not check_design_memory():
45
+ print("🟡 [Nala Vision Bridge] No `.design-memory/` output detected. Skipping Vision Bridge.")
46
+ sys.exit(0)
47
+
48
+ print("⚡ [Nala Vision Bridge] `memvid/design-memory` artifacts detected. Compressing UI semantics...")
49
+
50
+ # We prioritize the files that actually tell the AI how to build the UI
51
+ files_to_sync = {
52
+ "Global Styles": ".design-memory/style.md",
53
+ "Layout Spec": ".design-memory/layout.md",
54
+ "Component Recipes": ".design-memory/components.md"
55
+ }
56
+
57
+ bridge_output = "# Vision Bridge: Compiled Design Memory\n\n"
58
+ bridge_output += "> Automatically generated from `memvid/design-memory`. This replaces the need to analyze raw PNGs.\n\n"
59
+
60
+ for section_name, path in files_to_sync.items():
61
+ if os.path.exists(path):
62
+ content = read_and_compress(path)
63
+ bridge_output += f"## {section_name}\n\n{content}\n\n---\n\n"
64
+
65
+ # Also grab UI Skills if they exist
66
+ skills_dir = ".design-memory/skills"
67
+ if os.path.isdir(skills_dir):
68
+ bridge_output += "## UI Implementation Skills\n\n"
69
+ for root, _, files in os.walk(skills_dir):
70
+ for file in files:
71
+ if file.endswith(".md"):
72
+ skill_path = os.path.join(root, file)
73
+ skill_content = read_and_compress(skill_path, max_lines=50)
74
+ bridge_output += f"### {file}\n{skill_content}\n\n"
75
+
76
+ os.makedirs(".artifacts", exist_ok=True)
77
+ out_path = ".artifacts/vision_bridge.toon"
78
+
79
+ with open(out_path, "w", encoding='utf-8') as f:
80
+ f.write(bridge_output)
81
+
82
+ print(f"🟢 [Nala Vision Bridge] Successfully compressed UI Mockups into semantic text.")
83
+ print(f"Context saved to {out_path}.")
84
+ sys.exit(0)
85
+
86
+ if __name__ == "__main__":
87
+ main()
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Dasa Nala: Auto-Formatter (lint_fixer.py)
4
+ Detects installed linting/formatting tools and automatically fixes fixable syntax.
5
+ Prevents the AI from wasting LLM tokens manually inserting missing semicolons or spaces.
6
+ """
7
+
8
+ import os
9
+ import sys
10
+ import subprocess
11
+
12
+ def detect_and_run_formatters():
13
+ """Detect formatters in the project and run their auto-fix commands."""
14
+ fixed_something = False
15
+
16
+ # 1. Javascript / Typescript (Prettier/ESLint)
17
+ if os.path.exists("package.json"):
18
+ with open("package.json", "r") as f:
19
+ content = f.read()
20
+
21
+ if '"prettier"' in content or '"prettier:' in content:
22
+ print("⚡ [Nala Formatter] Prettier detected. Running `npx prettier --write .`")
23
+ try:
24
+ subprocess.run(["npx", "prettier", "--write", "."], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
25
+ fixed_something = True
26
+ except Exception:
27
+ pass
28
+
29
+ if '"eslint"' in content:
30
+ print("⚡ [Nala Formatter] ESLint detected. Running `npx eslint --fix .`")
31
+ try:
32
+ subprocess.run(["npx", "eslint", "--fix", "."], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
33
+ fixed_something = True
34
+ except Exception:
35
+ pass
36
+
37
+ # 2. Python (Ruff / Black)
38
+ if os.path.exists("pyproject.toml") or os.path.exists("requirements.txt"):
39
+ try:
40
+ # Check if ruff is available
41
+ subprocess.run(["ruff", "--version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
42
+ print("⚡ [Nala Formatter] Ruff detected. Running `ruff check --fix .` and `ruff format .`")
43
+ subprocess.run(["ruff", "check", "--fix", "."], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
44
+ subprocess.run(["ruff", "format", "."], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
45
+ fixed_something = True
46
+ except (subprocess.CalledProcessError, FileNotFoundError):
47
+ try:
48
+ subprocess.run(["black", "--version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
49
+ print("⚡ [Nala Formatter] Black detected. Running `black .`")
50
+ subprocess.run(["black", "."], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
51
+ fixed_something = True
52
+ except (subprocess.CalledProcessError, FileNotFoundError):
53
+ pass
54
+
55
+ # 3. Go (gofmt)
56
+ if os.path.exists("go.mod"):
57
+ print("⚡ [Nala Formatter] Go module detected. Running `gofmt -w .`")
58
+ try:
59
+ subprocess.run(["gofmt", "-w", "."], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
60
+ fixed_something = True
61
+ except Exception:
62
+ pass
63
+
64
+ return fixed_something
65
+
66
+ def main():
67
+ print("🛡️ [Dasa Nala] Initializing Auto-Formatter...")
68
+
69
+ ran_formatters = detect_and_run_formatters()
70
+
71
+ if ran_formatters:
72
+ print("🟢 [Nala Formatter] Code styling automatically fixed where possible. AI tokens saved.")
73
+ else:
74
+ print("🟡 [Nala Formatter] No supported formatters detected in project root. Skipping.")
75
+
76
+ sys.exit(0)
77
+
78
+ if __name__ == "__main__":
79
+ main()