msl 0.1.0__tar.gz

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 (47) hide show
  1. msl-0.1.0/LICENSE +21 -0
  2. msl-0.1.0/MANIFEST.in +3 -0
  3. msl-0.1.0/PKG-INFO +130 -0
  4. msl-0.1.0/README.md +99 -0
  5. msl-0.1.0/pyproject.toml +55 -0
  6. msl-0.1.0/setup.cfg +4 -0
  7. msl-0.1.0/src/msl/__init__.py +3 -0
  8. msl-0.1.0/src/msl/cli.py +51 -0
  9. msl-0.1.0/src/msl/detection.py +97 -0
  10. msl-0.1.0/src/msl/models.py +80 -0
  11. msl-0.1.0/src/msl/path_rules.py +28 -0
  12. msl-0.1.0/src/msl/scanner.py +376 -0
  13. msl-0.1.0/src/msl/skills/flutter/industry_standard.md +87 -0
  14. msl-0.1.0/src/msl/skills/flutter/intermediate.md +46 -0
  15. msl-0.1.0/src/msl/skills/flutter/simple.md +20 -0
  16. msl-0.1.0/src/msl/skills/go-server/industry_standard.md +89 -0
  17. msl-0.1.0/src/msl/skills/go-server/intermediate.md +53 -0
  18. msl-0.1.0/src/msl/skills/go-server/simple.md +19 -0
  19. msl-0.1.0/src/msl/skills/nextjs/industry_standard.md +88 -0
  20. msl-0.1.0/src/msl/skills/nextjs/intermediate.md +46 -0
  21. msl-0.1.0/src/msl/skills/nextjs/simple.md +21 -0
  22. msl-0.1.0/src/msl/skills/nodejs-server/industry_standard.md +91 -0
  23. msl-0.1.0/src/msl/skills/nodejs-server/intermediate.md +49 -0
  24. msl-0.1.0/src/msl/skills/nodejs-server/simple.md +20 -0
  25. msl-0.1.0/src/msl/skills/python/industry_standard.md +86 -0
  26. msl-0.1.0/src/msl/skills/python/intermediate.md +48 -0
  27. msl-0.1.0/src/msl/skills/python/simple.md +20 -0
  28. msl-0.1.0/src/msl/skills/react-vite/industry_standard.md +80 -0
  29. msl-0.1.0/src/msl/skills/react-vite/intermediate.md +44 -0
  30. msl-0.1.0/src/msl/skills/react-vite/simple.md +19 -0
  31. msl-0.1.0/src/msl/skills/rust-server/industry_standard.md +87 -0
  32. msl-0.1.0/src/msl/skills/rust-server/intermediate.md +45 -0
  33. msl-0.1.0/src/msl/skills/rust-server/simple.md +19 -0
  34. msl-0.1.0/src/msl/templates.py +40 -0
  35. msl-0.1.0/src/msl/ui.py +314 -0
  36. msl-0.1.0/src/msl/writer.py +63 -0
  37. msl-0.1.0/src/msl.egg-info/PKG-INFO +130 -0
  38. msl-0.1.0/src/msl.egg-info/SOURCES.txt +45 -0
  39. msl-0.1.0/src/msl.egg-info/dependency_links.txt +1 -0
  40. msl-0.1.0/src/msl.egg-info/entry_points.txt +2 -0
  41. msl-0.1.0/src/msl.egg-info/requires.txt +2 -0
  42. msl-0.1.0/src/msl.egg-info/top_level.txt +1 -0
  43. msl-0.1.0/tests/test_detection.py +101 -0
  44. msl-0.1.0/tests/test_path_rules.py +32 -0
  45. msl-0.1.0/tests/test_scanner.py +156 -0
  46. msl-0.1.0/tests/test_templates.py +51 -0
  47. msl-0.1.0/tests/test_writer.py +73 -0
msl-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Murad
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
msl-0.1.0/MANIFEST.in ADDED
@@ -0,0 +1,3 @@
1
+ recursive-include src/msl/skills *.md
2
+ include LICENSE
3
+ include README.md
msl-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,130 @@
1
+ Metadata-Version: 2.4
2
+ Name: msl
3
+ Version: 0.1.0
4
+ Summary: MSL — Muradian Skill Languages: Generate platform-specific skill files for AI coding assistants
5
+ Author: Murad
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/mozaddedalfeshani/msl
8
+ Project-URL: Repository, https://github.com/mozaddedalfeshani/msl
9
+ Project-URL: Issues, https://github.com/mozaddedalfeshani/msl/issues
10
+ Keywords: ai,coding-assistant,cursor,vscode,claude,codex,skill,rules,developer-tools,cli
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development
23
+ Classifier: Topic :: Software Development :: Code Generators
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: rich>=13.0
29
+ Requires-Dist: questionary>=2.0
30
+ Dynamic: license-file
31
+
32
+ # MSL — Muradian Skill Languages
33
+
34
+ Generate platform-specific skill/rule files for AI coding assistants with one command. No need to remember which file goes where — `msl` handles the structure for you.
35
+
36
+ ## Install
37
+
38
+ ```bash
39
+ pip install msl
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ ```bash
45
+ msl
46
+ ```
47
+
48
+ The wizard will:
49
+
50
+ 1. **Detect** your environment (Node.js, Cursor, VS Code, Claude Code, Codex)
51
+ 2. **Scan** your project to auto-detect frameworks, languages, package manager
52
+ 3. **Ask** which platform to target
53
+ 4. **Ask** your project path (current directory or custom)
54
+ 5. **Ask** your project type (auto-suggested from scan)
55
+ 6. **Ask** your preference level (Simple → Industry Standard)
56
+ 7. **Generate** the correct file in the right location with project-aware content
57
+
58
+ ```
59
+ ╭──────────────────────────────────────╮
60
+ │ MSL — Muradian Skill Languages │
61
+ ╰──────────────────────────────────────╯
62
+
63
+ Environment Check
64
+ ✓ Node.js v20.11.0
65
+ ✓ Cursor 0.45.0
66
+ ✓ VS Code 1.89.1
67
+ ✓ Claude 2.1.0
68
+ ✓ Codex 0.72.0
69
+
70
+ Project Scan
71
+ Name: my-saas-app
72
+ Languages: TypeScript
73
+ Detected: Next.js, App Router, tailwindcss, prisma
74
+ Type: Web (Next.js) (95% confidence)
75
+ ```
76
+
77
+ ## Supported Platforms
78
+
79
+ | Platform | Output Path |
80
+ | ----------- | --------------------------------- |
81
+ | Cursor | `.cursor/rules.md` |
82
+ | VS Code | `.github/copilot-instructions.md` |
83
+ | Claude Code | `CLAUDE.md` |
84
+ | Codex | `AGENTS.md` |
85
+
86
+ ## Supported Project Types
87
+
88
+ - **Flutter** — Dart, widgets, state management, routing
89
+ - **Web (Next.js)** — App Router, Server Components, data fetching
90
+ - **Web (React/Vite)** — SPA, hooks, React Router, Zustand
91
+ - **Rust (Server)** — Axum/Actix, async, sqlx, error handling
92
+ - **Node.js (Server)** — Express/Fastify, TypeScript, Prisma
93
+ - **Python** — FastAPI/Flask, typed Python, pytest
94
+ - **Go (Server)** — Chi/Gin, structured logging, sqlx
95
+
96
+ ## Preference Levels
97
+
98
+ | Level | What it includes |
99
+ | ----------------- | ------------------------------------------------- |
100
+ | Simple | Clean code basics, modular structure |
101
+ | Intermediate | Patterns, testing, conventions, data layer |
102
+ | Industry Standard | Full architecture, CI/CD, security, observability |
103
+
104
+ ## Smart Features
105
+
106
+ - **Auto-detection**: Scans `package.json`, `Cargo.toml`, `pubspec.yaml`, `pyproject.toml`, `go.mod` to identify your stack
107
+ - **Context injection**: Appends detected project name, frameworks, and package manager to the generated file
108
+ - **Correct conventions**: Uses each platform's real config file path — not a generic filename
109
+ - **Safe writes**: Always asks before overwriting existing files
110
+
111
+ ## CLI Options
112
+
113
+ ```bash
114
+ msl # Run the interactive wizard
115
+ msl --version # Show version
116
+ msl --help # Show help
117
+ ```
118
+
119
+ ## Development
120
+
121
+ ```bash
122
+ git clone https://github.com/murad/msl.git
123
+ cd msl
124
+ pip install -e .
125
+ msl
126
+ ```
127
+
128
+ ## License
129
+
130
+ MIT
msl-0.1.0/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # MSL — Muradian Skill Languages
2
+
3
+ Generate platform-specific skill/rule files for AI coding assistants with one command. No need to remember which file goes where — `msl` handles the structure for you.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install msl
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ msl
15
+ ```
16
+
17
+ The wizard will:
18
+
19
+ 1. **Detect** your environment (Node.js, Cursor, VS Code, Claude Code, Codex)
20
+ 2. **Scan** your project to auto-detect frameworks, languages, package manager
21
+ 3. **Ask** which platform to target
22
+ 4. **Ask** your project path (current directory or custom)
23
+ 5. **Ask** your project type (auto-suggested from scan)
24
+ 6. **Ask** your preference level (Simple → Industry Standard)
25
+ 7. **Generate** the correct file in the right location with project-aware content
26
+
27
+ ```
28
+ ╭──────────────────────────────────────╮
29
+ │ MSL — Muradian Skill Languages │
30
+ ╰──────────────────────────────────────╯
31
+
32
+ Environment Check
33
+ ✓ Node.js v20.11.0
34
+ ✓ Cursor 0.45.0
35
+ ✓ VS Code 1.89.1
36
+ ✓ Claude 2.1.0
37
+ ✓ Codex 0.72.0
38
+
39
+ Project Scan
40
+ Name: my-saas-app
41
+ Languages: TypeScript
42
+ Detected: Next.js, App Router, tailwindcss, prisma
43
+ Type: Web (Next.js) (95% confidence)
44
+ ```
45
+
46
+ ## Supported Platforms
47
+
48
+ | Platform | Output Path |
49
+ | ----------- | --------------------------------- |
50
+ | Cursor | `.cursor/rules.md` |
51
+ | VS Code | `.github/copilot-instructions.md` |
52
+ | Claude Code | `CLAUDE.md` |
53
+ | Codex | `AGENTS.md` |
54
+
55
+ ## Supported Project Types
56
+
57
+ - **Flutter** — Dart, widgets, state management, routing
58
+ - **Web (Next.js)** — App Router, Server Components, data fetching
59
+ - **Web (React/Vite)** — SPA, hooks, React Router, Zustand
60
+ - **Rust (Server)** — Axum/Actix, async, sqlx, error handling
61
+ - **Node.js (Server)** — Express/Fastify, TypeScript, Prisma
62
+ - **Python** — FastAPI/Flask, typed Python, pytest
63
+ - **Go (Server)** — Chi/Gin, structured logging, sqlx
64
+
65
+ ## Preference Levels
66
+
67
+ | Level | What it includes |
68
+ | ----------------- | ------------------------------------------------- |
69
+ | Simple | Clean code basics, modular structure |
70
+ | Intermediate | Patterns, testing, conventions, data layer |
71
+ | Industry Standard | Full architecture, CI/CD, security, observability |
72
+
73
+ ## Smart Features
74
+
75
+ - **Auto-detection**: Scans `package.json`, `Cargo.toml`, `pubspec.yaml`, `pyproject.toml`, `go.mod` to identify your stack
76
+ - **Context injection**: Appends detected project name, frameworks, and package manager to the generated file
77
+ - **Correct conventions**: Uses each platform's real config file path — not a generic filename
78
+ - **Safe writes**: Always asks before overwriting existing files
79
+
80
+ ## CLI Options
81
+
82
+ ```bash
83
+ msl # Run the interactive wizard
84
+ msl --version # Show version
85
+ msl --help # Show help
86
+ ```
87
+
88
+ ## Development
89
+
90
+ ```bash
91
+ git clone https://github.com/murad/msl.git
92
+ cd msl
93
+ pip install -e .
94
+ msl
95
+ ```
96
+
97
+ ## License
98
+
99
+ MIT
@@ -0,0 +1,55 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "msl"
7
+ version = "0.1.0"
8
+ description = "MSL — Muradian Skill Languages: Generate platform-specific skill files for AI coding assistants"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ {name = "Murad"},
14
+ ]
15
+ keywords = [
16
+ "ai", "coding-assistant", "cursor", "vscode", "claude", "codex",
17
+ "skill", "rules", "developer-tools", "cli",
18
+ ]
19
+ classifiers = [
20
+ "Development Status :: 4 - Beta",
21
+ "Environment :: Console",
22
+ "Intended Audience :: Developers",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Operating System :: OS Independent",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3.9",
27
+ "Programming Language :: Python :: 3.10",
28
+ "Programming Language :: Python :: 3.11",
29
+ "Programming Language :: Python :: 3.12",
30
+ "Programming Language :: Python :: 3.13",
31
+ "Topic :: Software Development",
32
+ "Topic :: Software Development :: Code Generators",
33
+ "Typing :: Typed",
34
+ ]
35
+ dependencies = [
36
+ "rich>=13.0",
37
+ "questionary>=2.0",
38
+ ]
39
+
40
+ [project.scripts]
41
+ msl = "msl.cli:main"
42
+
43
+ [project.urls]
44
+ Homepage = "https://github.com/mozaddedalfeshani/msl"
45
+ Repository = "https://github.com/mozaddedalfeshani/msl"
46
+ Issues = "https://github.com/mozaddedalfeshani/msl/issues"
47
+
48
+ [tool.setuptools.packages.find]
49
+ where = ["src"]
50
+
51
+ [tool.setuptools.package-data]
52
+ msl = ["skills/**/*.md"]
53
+
54
+ [tool.pytest.ini_options]
55
+ testpaths = ["tests"]
msl-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """MSL — Muradian Skill Languages CLI."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+
5
+
6
+ def main() -> None:
7
+ # Handle --version / --help before importing heavy dependencies
8
+ if len(sys.argv) > 1:
9
+ arg = sys.argv[1]
10
+ if arg in ("--version", "-V"):
11
+ from . import __version__
12
+ print(f"msl {__version__}")
13
+ return
14
+ if arg in ("--help", "-h"):
15
+ print(
16
+ "Usage: msl [options]\n"
17
+ "\n"
18
+ " Interactive wizard that generates platform-specific skill\n"
19
+ " files for AI coding assistants (Cursor, VS Code, Claude Code, Codex).\n"
20
+ "\n"
21
+ "Options:\n"
22
+ " -h, --help Show this help message\n"
23
+ " -V, --version Show version number\n"
24
+ )
25
+ return
26
+
27
+ from .ui import console, run_wizard, show_cancelled, show_success
28
+ from .writer import generate_skill_file
29
+
30
+ try:
31
+ result = run_wizard()
32
+ if result is None:
33
+ sys.exit(0)
34
+
35
+ ctx, scan = result
36
+ output_path = generate_skill_file(ctx, scan)
37
+ show_success(output_path)
38
+
39
+ except KeyboardInterrupt:
40
+ show_cancelled()
41
+ sys.exit(0)
42
+ except FileExistsError as exc:
43
+ console.print(f"\n[yellow]{exc}[/yellow]")
44
+ sys.exit(0)
45
+ except Exception as exc:
46
+ console.print(f"\n[red]Error: {exc}[/red]")
47
+ sys.exit(1)
48
+
49
+
50
+ if __name__ == "__main__":
51
+ main()
@@ -0,0 +1,97 @@
1
+ from __future__ import annotations
2
+
3
+ import platform as platform_mod
4
+ import shutil
5
+ import subprocess
6
+ from pathlib import Path
7
+
8
+ from .models import DetectedTool
9
+
10
+
11
+ def _run_version_cmd(cmd: str) -> str | None:
12
+ try:
13
+ result = subprocess.run(
14
+ [cmd, "--version"],
15
+ capture_output=True,
16
+ text=True,
17
+ timeout=5,
18
+ )
19
+ if result.returncode == 0:
20
+ return (result.stdout.strip() or result.stderr.strip()) or None
21
+ except (FileNotFoundError, subprocess.TimeoutExpired, OSError):
22
+ pass
23
+ return None
24
+
25
+
26
+ def _check_macos_app(app_name: str) -> bool:
27
+ return Path(f"/Applications/{app_name}.app").exists()
28
+
29
+
30
+ def detect_nodejs() -> DetectedTool:
31
+ version = _run_version_cmd("node")
32
+ return DetectedTool(
33
+ name="Node.js",
34
+ installed=version is not None,
35
+ version=version,
36
+ path=shutil.which("node"),
37
+ )
38
+
39
+
40
+ def detect_cursor() -> DetectedTool:
41
+ cursor_path = shutil.which("cursor")
42
+ if cursor_path:
43
+ version = _run_version_cmd("cursor")
44
+ return DetectedTool(
45
+ name="Cursor", installed=True, version=version, path=cursor_path
46
+ )
47
+ if platform_mod.system() == "Darwin" and _check_macos_app("Cursor"):
48
+ return DetectedTool(
49
+ name="Cursor", installed=True, path="/Applications/Cursor.app"
50
+ )
51
+ return DetectedTool(name="Cursor", installed=False)
52
+
53
+
54
+ def detect_vscode() -> DetectedTool:
55
+ code_path = shutil.which("code")
56
+ if code_path:
57
+ version = _run_version_cmd("code")
58
+ return DetectedTool(
59
+ name="VS Code", installed=True, version=version, path=code_path
60
+ )
61
+ if platform_mod.system() == "Darwin" and _check_macos_app("Visual Studio Code"):
62
+ return DetectedTool(
63
+ name="VS Code",
64
+ installed=True,
65
+ path="/Applications/Visual Studio Code.app",
66
+ )
67
+ return DetectedTool(name="VS Code", installed=False)
68
+
69
+
70
+ def detect_claude_code() -> DetectedTool:
71
+ claude_path = shutil.which("claude")
72
+ if claude_path:
73
+ version = _run_version_cmd("claude")
74
+ return DetectedTool(
75
+ name="Claude Code", installed=True, version=version, path=claude_path
76
+ )
77
+ return DetectedTool(name="Claude Code", installed=False)
78
+
79
+
80
+ def detect_codex() -> DetectedTool:
81
+ codex_path = shutil.which("codex")
82
+ if codex_path:
83
+ version = _run_version_cmd("codex")
84
+ return DetectedTool(
85
+ name="Codex", installed=True, version=version, path=codex_path
86
+ )
87
+ return DetectedTool(name="Codex", installed=False)
88
+
89
+
90
+ def detect_all() -> dict[str, DetectedTool]:
91
+ return {
92
+ "nodejs": detect_nodejs(),
93
+ "cursor": detect_cursor(),
94
+ "vscode": detect_vscode(),
95
+ "claude-code": detect_claude_code(),
96
+ "codex": detect_codex(),
97
+ }
@@ -0,0 +1,80 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from enum import Enum
5
+ from pathlib import Path
6
+
7
+
8
+ class Platform(Enum):
9
+ CURSOR = "cursor"
10
+ VSCODE = "vscode"
11
+ CLAUDE_CODE = "claude-code"
12
+ CODEX = "codex"
13
+
14
+ @property
15
+ def display_name(self) -> str:
16
+ return {
17
+ Platform.CURSOR: "Cursor",
18
+ Platform.VSCODE: "VS Code",
19
+ Platform.CLAUDE_CODE: "Claude Code",
20
+ Platform.CODEX: "Codex",
21
+ }[self]
22
+
23
+
24
+ class ProjectType(Enum):
25
+ FLUTTER = "flutter"
26
+ NEXTJS = "nextjs"
27
+ REACT_VITE = "react-vite"
28
+ RUST_SERVER = "rust-server"
29
+ NODEJS_SERVER = "nodejs-server"
30
+ PYTHON = "python"
31
+ GO_SERVER = "go-server"
32
+
33
+ @property
34
+ def display_name(self) -> str:
35
+ return {
36
+ ProjectType.FLUTTER: "Flutter",
37
+ ProjectType.NEXTJS: "Web (Next.js)",
38
+ ProjectType.REACT_VITE: "Web (React/Vite)",
39
+ ProjectType.RUST_SERVER: "Rust (Server)",
40
+ ProjectType.NODEJS_SERVER: "Node.js (Server)",
41
+ ProjectType.PYTHON: "Python",
42
+ ProjectType.GO_SERVER: "Go (Server)",
43
+ }[self]
44
+
45
+
46
+ class PreferenceTier(Enum):
47
+ SIMPLE = "simple"
48
+ INTERMEDIATE = "intermediate"
49
+ INDUSTRY_STANDARD = "industry_standard"
50
+
51
+ @property
52
+ def display_name(self) -> str:
53
+ return {
54
+ PreferenceTier.SIMPLE: "Simple — modular, clean code basics",
55
+ PreferenceTier.INTERMEDIATE: "Intermediate — patterns, testing, conventions",
56
+ PreferenceTier.INDUSTRY_STANDARD: "Industry Standard — full architecture & delivery rules",
57
+ }[self]
58
+
59
+
60
+ @dataclass
61
+ class DetectedTool:
62
+ name: str
63
+ installed: bool
64
+ version: str | None = None
65
+ path: str | None = None
66
+
67
+
68
+ @dataclass
69
+ class SkillGenContext:
70
+ target_platform: Platform
71
+ project_path: Path
72
+ project_type: ProjectType
73
+ preference_tier: PreferenceTier
74
+ detected_tools: dict[str, DetectedTool] = field(default_factory=dict)
75
+
76
+ @property
77
+ def output_path(self) -> Path:
78
+ from .path_rules import get_output_path
79
+
80
+ return get_output_path(self.target_platform, self.project_path)
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from .models import Platform
6
+
7
+ # Platform → (hidden directory name | None, filename)
8
+ # Based on each tool's ACTUAL config-file convention.
9
+ PLATFORM_PATHS: dict[str, tuple[str | None, str]] = {
10
+ Platform.CURSOR.value: (".cursor", "rules.md"), # .cursor/rules.md
11
+ Platform.VSCODE.value: (".github", "copilot-instructions.md"), # .github/copilot-instructions.md
12
+ Platform.CLAUDE_CODE.value: (None, "CLAUDE.md"), # CLAUDE.md at project root
13
+ Platform.CODEX.value: (None, "AGENTS.md"), # AGENTS.md at project root
14
+ }
15
+
16
+
17
+ def get_output_path(platform: Platform, project_root: Path) -> Path:
18
+ directory, filename = PLATFORM_PATHS[platform.value]
19
+ if directory:
20
+ return project_root / directory / filename
21
+ return project_root / filename
22
+
23
+
24
+ def get_output_dir(platform: Platform, project_root: Path) -> Path:
25
+ directory, _ = PLATFORM_PATHS[platform.value]
26
+ if directory:
27
+ return project_root / directory
28
+ return project_root