nexus-dev-toolkit 3.0.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.
- nexus_dev_toolkit-3.0.0/LICENSE +21 -0
- nexus_dev_toolkit-3.0.0/PKG-INFO +170 -0
- nexus_dev_toolkit-3.0.0/README.md +150 -0
- nexus_dev_toolkit-3.0.0/nexus_cli.py +292 -0
- nexus_dev_toolkit-3.0.0/nexus_dev_toolkit.egg-info/PKG-INFO +170 -0
- nexus_dev_toolkit-3.0.0/nexus_dev_toolkit.egg-info/SOURCES.txt +24 -0
- nexus_dev_toolkit-3.0.0/nexus_dev_toolkit.egg-info/dependency_links.txt +1 -0
- nexus_dev_toolkit-3.0.0/nexus_dev_toolkit.egg-info/entry_points.txt +3 -0
- nexus_dev_toolkit-3.0.0/nexus_dev_toolkit.egg-info/requires.txt +7 -0
- nexus_dev_toolkit-3.0.0/nexus_dev_toolkit.egg-info/top_level.txt +3 -0
- nexus_dev_toolkit-3.0.0/nexus_server.py +16 -0
- nexus_dev_toolkit-3.0.0/pyproject.toml +48 -0
- nexus_dev_toolkit-3.0.0/setup.cfg +4 -0
- nexus_dev_toolkit-3.0.0/tools/__init__.py +0 -0
- nexus_dev_toolkit-3.0.0/tools/epav/__init__.py +14 -0
- nexus_dev_toolkit-3.0.0/tools/epav/arch_ingest.py +124 -0
- nexus_dev_toolkit-3.0.0/tools/epav/package_resolver.py +271 -0
- nexus_dev_toolkit-3.0.0/tools/epav/project_rules.py +208 -0
- nexus_dev_toolkit-3.0.0/tools/epav/skills/__init__.py +0 -0
- nexus_dev_toolkit-3.0.0/tools/epav/skills/apply.md +41 -0
- nexus_dev_toolkit-3.0.0/tools/epav/skills/epav.md +46 -0
- nexus_dev_toolkit-3.0.0/tools/epav/skills/evaluate.md +42 -0
- nexus_dev_toolkit-3.0.0/tools/epav/skills/plan.md +46 -0
- nexus_dev_toolkit-3.0.0/tools/epav/skills/scaffold.md +249 -0
- nexus_dev_toolkit-3.0.0/tools/epav/skills/validate.md +57 -0
- nexus_dev_toolkit-3.0.0/tools/epav/task_loader.py +140 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ronald dela Cruz
|
|
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.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nexus-dev-toolkit
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: LLM-agnostic developer workflow toolkit — Day 0 scaffold + Day 1 EPAV
|
|
5
|
+
Author-email: Ronald dela Cruz <rcdelacruz@users.noreply.github.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://nexus.coderstudio.co
|
|
8
|
+
Project-URL: Repository, https://github.com/rcdelacruz/nexus-dev-toolkit
|
|
9
|
+
Project-URL: Issues, https://github.com/rcdelacruz/nexus-dev-toolkit/issues
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: mcp[cli]>=1.0.0
|
|
14
|
+
Requires-Dist: typer>=0.12.0
|
|
15
|
+
Requires-Dist: rich>=13.0.0
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
18
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# nexus-dev-toolkit
|
|
22
|
+
|
|
23
|
+
[](https://pypi.org/project/nexus-dev-toolkit/)
|
|
24
|
+
[](https://pypi.org/project/nexus-dev-toolkit/)
|
|
25
|
+
[](LICENSE)
|
|
26
|
+
|
|
27
|
+
Developer workflow toolkit for AI-assisted development. Gives any team a structured Day 0 scaffold and repeatable Day 1 feature cycle via the EPAV methodology.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Why
|
|
32
|
+
|
|
33
|
+
Ad-hoc AI prompting doesn't scale. Every dev prompts differently, context drifts, and nobody knows what the AI was told last sprint.
|
|
34
|
+
|
|
35
|
+
`nexus-dev-toolkit` gives your team a single workflow:
|
|
36
|
+
|
|
37
|
+
- **Day 0** — scaffold the project once, production-grade, zero credentials needed
|
|
38
|
+
- **Day 1** — every feature follows the same four steps: evaluate → plan → apply → validate
|
|
39
|
+
|
|
40
|
+
Every skill, every rule, every pattern lives in the project repo — versioned, shared, and enforced.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## The Workflow
|
|
45
|
+
|
|
46
|
+
### Day 0 — `/scaffold` (once per project)
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
nexus init <project-dir>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Sets up `.claude/commands/`, `.claude/settings.json`, and `knowledge/`. Then in Claude Code:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
/scaffold
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
EVALUATE → PLAN → APPLY → VALIDATE. Produces a production-grade project: correct stack from your arch doc, mock auth, mock data, design system, AGENTS.md — all from your architecture document. Runs with `npm install && npm run dev` (or equivalent) from commit one.
|
|
59
|
+
|
|
60
|
+
### Day 1 — EPAV (every feature, every sprint)
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
/evaluate → /plan → /apply → /validate
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Each step is a built-in skill in `.claude/commands/`. Every task starts with a row from the dev tasks CSV. Every task ends with acceptance criteria verified.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Install
|
|
71
|
+
|
|
72
|
+
**Requirements:** Python 3.10+, `uv` (recommended) or `pip`
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Recommended
|
|
76
|
+
uv tool install nexus-dev-toolkit
|
|
77
|
+
|
|
78
|
+
# Or via pip
|
|
79
|
+
pip install nexus-dev-toolkit
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Quick Start
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
cd my-project
|
|
88
|
+
nexus init .
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Then open the project in Claude Code and type `/scaffold`.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Commands
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
nexus init . # set up .claude/commands/ + knowledge/ + .mcp.json
|
|
99
|
+
nexus skill add code-review # create a custom skill in .claude/commands/
|
|
100
|
+
nexus skill list # list all skills
|
|
101
|
+
nexus rule add api-standards # create a rule in knowledge/rules/
|
|
102
|
+
nexus rule list # list all rules
|
|
103
|
+
nexus update # update to latest version
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## What `nexus init` Creates
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
.claude/
|
|
112
|
+
├── commands/
|
|
113
|
+
│ ├── scaffold.md ← /scaffold — Day 0 one-time setup
|
|
114
|
+
│ ├── evaluate.md ← /evaluate — orient on a task
|
|
115
|
+
│ ├── plan.md ← /plan — blueprint, no code
|
|
116
|
+
│ ├── apply.md ← /apply — implement the plan
|
|
117
|
+
│ ├── validate.md ← /validate — verify acceptance criteria
|
|
118
|
+
│ └── epav.md ← /epav — full cycle guide
|
|
119
|
+
└── settings.json ← PostToolUse hook: graphify auto-updates after every file edit
|
|
120
|
+
knowledge/
|
|
121
|
+
├── rules/ ← coding standards, arch decisions
|
|
122
|
+
├── patterns/ ← reusable implementation patterns
|
|
123
|
+
├── prompts/dev/ ← task prompt templates
|
|
124
|
+
└── retros/ ← retrospective notes
|
|
125
|
+
.mcp.json ← MCP server config
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## MCP Server
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"mcpServers": {
|
|
135
|
+
"nexus": {
|
|
136
|
+
"command": "uvx",
|
|
137
|
+
"args": ["--refresh", "--from", "nexus-dev-toolkit", "nexus-mcp"]
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`nexus init` writes `.mcp.json` automatically.
|
|
144
|
+
|
|
145
|
+
### MCP Tools
|
|
146
|
+
|
|
147
|
+
| Tool | Purpose |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `ingest_architecture_doc` | Load arch doc → `knowledge/rules/arch-summary.md` |
|
|
150
|
+
| `load_task` | Load a CSV task row into context |
|
|
151
|
+
| `generate_project_rules` | Generate `AGENTS.md` from arch doc |
|
|
152
|
+
| `resolve_package_versions` | Resolve exact package versions via real package manager |
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Custom Skills
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
nexus skill add my-code-review
|
|
160
|
+
# Edit .claude/commands/my-code-review.md
|
|
161
|
+
# Type /my-code-review in Claude Code
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Custom skills live alongside built-in skills in `.claude/commands/` — versioned in your repo, shared across the team.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# nexus-dev-toolkit
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/nexus-dev-toolkit/)
|
|
4
|
+
[](https://pypi.org/project/nexus-dev-toolkit/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
Developer workflow toolkit for AI-assisted development. Gives any team a structured Day 0 scaffold and repeatable Day 1 feature cycle via the EPAV methodology.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Why
|
|
12
|
+
|
|
13
|
+
Ad-hoc AI prompting doesn't scale. Every dev prompts differently, context drifts, and nobody knows what the AI was told last sprint.
|
|
14
|
+
|
|
15
|
+
`nexus-dev-toolkit` gives your team a single workflow:
|
|
16
|
+
|
|
17
|
+
- **Day 0** — scaffold the project once, production-grade, zero credentials needed
|
|
18
|
+
- **Day 1** — every feature follows the same four steps: evaluate → plan → apply → validate
|
|
19
|
+
|
|
20
|
+
Every skill, every rule, every pattern lives in the project repo — versioned, shared, and enforced.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## The Workflow
|
|
25
|
+
|
|
26
|
+
### Day 0 — `/scaffold` (once per project)
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
nexus init <project-dir>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Sets up `.claude/commands/`, `.claude/settings.json`, and `knowledge/`. Then in Claude Code:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
/scaffold
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
EVALUATE → PLAN → APPLY → VALIDATE. Produces a production-grade project: correct stack from your arch doc, mock auth, mock data, design system, AGENTS.md — all from your architecture document. Runs with `npm install && npm run dev` (or equivalent) from commit one.
|
|
39
|
+
|
|
40
|
+
### Day 1 — EPAV (every feature, every sprint)
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
/evaluate → /plan → /apply → /validate
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Each step is a built-in skill in `.claude/commands/`. Every task starts with a row from the dev tasks CSV. Every task ends with acceptance criteria verified.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
**Requirements:** Python 3.10+, `uv` (recommended) or `pip`
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Recommended
|
|
56
|
+
uv tool install nexus-dev-toolkit
|
|
57
|
+
|
|
58
|
+
# Or via pip
|
|
59
|
+
pip install nexus-dev-toolkit
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Quick Start
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
cd my-project
|
|
68
|
+
nexus init .
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Then open the project in Claude Code and type `/scaffold`.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Commands
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
nexus init . # set up .claude/commands/ + knowledge/ + .mcp.json
|
|
79
|
+
nexus skill add code-review # create a custom skill in .claude/commands/
|
|
80
|
+
nexus skill list # list all skills
|
|
81
|
+
nexus rule add api-standards # create a rule in knowledge/rules/
|
|
82
|
+
nexus rule list # list all rules
|
|
83
|
+
nexus update # update to latest version
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## What `nexus init` Creates
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
.claude/
|
|
92
|
+
├── commands/
|
|
93
|
+
│ ├── scaffold.md ← /scaffold — Day 0 one-time setup
|
|
94
|
+
│ ├── evaluate.md ← /evaluate — orient on a task
|
|
95
|
+
│ ├── plan.md ← /plan — blueprint, no code
|
|
96
|
+
│ ├── apply.md ← /apply — implement the plan
|
|
97
|
+
│ ├── validate.md ← /validate — verify acceptance criteria
|
|
98
|
+
│ └── epav.md ← /epav — full cycle guide
|
|
99
|
+
└── settings.json ← PostToolUse hook: graphify auto-updates after every file edit
|
|
100
|
+
knowledge/
|
|
101
|
+
├── rules/ ← coding standards, arch decisions
|
|
102
|
+
├── patterns/ ← reusable implementation patterns
|
|
103
|
+
├── prompts/dev/ ← task prompt templates
|
|
104
|
+
└── retros/ ← retrospective notes
|
|
105
|
+
.mcp.json ← MCP server config
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## MCP Server
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"mcpServers": {
|
|
115
|
+
"nexus": {
|
|
116
|
+
"command": "uvx",
|
|
117
|
+
"args": ["--refresh", "--from", "nexus-dev-toolkit", "nexus-mcp"]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`nexus init` writes `.mcp.json` automatically.
|
|
124
|
+
|
|
125
|
+
### MCP Tools
|
|
126
|
+
|
|
127
|
+
| Tool | Purpose |
|
|
128
|
+
|---|---|
|
|
129
|
+
| `ingest_architecture_doc` | Load arch doc → `knowledge/rules/arch-summary.md` |
|
|
130
|
+
| `load_task` | Load a CSV task row into context |
|
|
131
|
+
| `generate_project_rules` | Generate `AGENTS.md` from arch doc |
|
|
132
|
+
| `resolve_package_versions` | Resolve exact package versions via real package manager |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Custom Skills
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
nexus skill add my-code-review
|
|
140
|
+
# Edit .claude/commands/my-code-review.md
|
|
141
|
+
# Type /my-code-review in Claude Code
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Custom skills live alongside built-in skills in `.claude/commands/` — versioned in your repo, shared across the team.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import shutil
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.table import Table
|
|
10
|
+
|
|
11
|
+
app = typer.Typer(name="nexus", no_args_is_help=True, help="nexus-dev-toolkit — LLM-agnostic developer workflow toolkit")
|
|
12
|
+
skill_app = typer.Typer(name="skill", no_args_is_help=True, help="Manage skills in .claude/commands/")
|
|
13
|
+
rule_app = typer.Typer(name="rule", no_args_is_help=True, help="Manage rules in knowledge/rules/")
|
|
14
|
+
app.add_typer(skill_app, name="skill")
|
|
15
|
+
app.add_typer(rule_app, name="rule")
|
|
16
|
+
|
|
17
|
+
console = Console()
|
|
18
|
+
|
|
19
|
+
# ── Built-in skills shipped with the package ──────────────────────────────────
|
|
20
|
+
|
|
21
|
+
_SKILLS_SRC = Path(__file__).parent / "tools" / "epav" / "skills"
|
|
22
|
+
|
|
23
|
+
_BUILTIN_SKILLS = [
|
|
24
|
+
"scaffold.md",
|
|
25
|
+
"evaluate.md",
|
|
26
|
+
"plan.md",
|
|
27
|
+
"apply.md",
|
|
28
|
+
"validate.md",
|
|
29
|
+
"epav.md",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
# ── .claude/settings.json ────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
_CLAUDE_SETTINGS = {
|
|
35
|
+
"hooks": {
|
|
36
|
+
"PostToolUse": [
|
|
37
|
+
{
|
|
38
|
+
"matcher": ".*",
|
|
39
|
+
"hooks": [
|
|
40
|
+
{
|
|
41
|
+
"type": "command",
|
|
42
|
+
"command": "graphify update . --force 2>/dev/null || true"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# ── knowledge/ scaffold ───────────────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
_KNOWLEDGE_DIRS = [
|
|
53
|
+
"knowledge/rules",
|
|
54
|
+
"knowledge/patterns",
|
|
55
|
+
"knowledge/prompts/dev",
|
|
56
|
+
"knowledge/retros",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
# ── MCP config ────────────────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
_MCP_BLOCK = {
|
|
62
|
+
"nexus": {
|
|
63
|
+
"command": "uvx",
|
|
64
|
+
"args": ["--refresh", "--from", "nexus-dev-toolkit", "nexus-mcp"],
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _init_project(project_dir: Path) -> list[str]:
|
|
70
|
+
"""
|
|
71
|
+
nexus init — sets up:
|
|
72
|
+
.claude/commands/ ← built-in skills
|
|
73
|
+
.claude/settings.json ← PostToolUse graphify hook
|
|
74
|
+
knowledge/ ← empty scaffold
|
|
75
|
+
"""
|
|
76
|
+
created = []
|
|
77
|
+
|
|
78
|
+
# .claude/commands/ — copy built-in skills
|
|
79
|
+
commands_dir = project_dir / ".claude" / "commands"
|
|
80
|
+
commands_dir.mkdir(parents=True, exist_ok=True)
|
|
81
|
+
|
|
82
|
+
for skill_name in _BUILTIN_SKILLS:
|
|
83
|
+
src = _SKILLS_SRC / skill_name
|
|
84
|
+
dest = commands_dir / skill_name
|
|
85
|
+
if src.exists() and not dest.exists():
|
|
86
|
+
shutil.copy2(src, dest)
|
|
87
|
+
created.append(f".claude/commands/{skill_name}")
|
|
88
|
+
|
|
89
|
+
# .claude/settings.json — PostToolUse graphify hook
|
|
90
|
+
settings_path = project_dir / ".claude" / "settings.json"
|
|
91
|
+
if not settings_path.exists():
|
|
92
|
+
settings_path.write_text(json.dumps(_CLAUDE_SETTINGS, indent=2))
|
|
93
|
+
created.append(".claude/settings.json")
|
|
94
|
+
|
|
95
|
+
# knowledge/ scaffold
|
|
96
|
+
for d in _KNOWLEDGE_DIRS:
|
|
97
|
+
target = project_dir / d
|
|
98
|
+
target.mkdir(parents=True, exist_ok=True)
|
|
99
|
+
|
|
100
|
+
return created
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _write_mcp_config(project_dir: Path) -> str:
|
|
104
|
+
mcp_path = project_dir / ".mcp.json"
|
|
105
|
+
existing: dict = {}
|
|
106
|
+
if mcp_path.exists():
|
|
107
|
+
try:
|
|
108
|
+
existing = json.loads(mcp_path.read_text())
|
|
109
|
+
except Exception:
|
|
110
|
+
pass
|
|
111
|
+
existing.setdefault("mcpServers", {}).update(_MCP_BLOCK)
|
|
112
|
+
mcp_path.write_text(json.dumps(existing, indent=2))
|
|
113
|
+
return ".mcp.json"
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# ── Commands ──────────────────────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
@app.command()
|
|
119
|
+
def init(
|
|
120
|
+
project_dir: str = typer.Argument(".", help="Project directory to initialize"),
|
|
121
|
+
) -> None:
|
|
122
|
+
"""Initialize .claude/commands/, .claude/settings.json, and knowledge/ in a project."""
|
|
123
|
+
root = Path(project_dir).resolve()
|
|
124
|
+
console.print(f"\n [cyan]▶[/cyan] Initializing nexus in [bold]{root}[/bold]\n")
|
|
125
|
+
|
|
126
|
+
created = _init_project(root)
|
|
127
|
+
for f in created:
|
|
128
|
+
console.print(f" [green]✓[/green] {f}")
|
|
129
|
+
|
|
130
|
+
if not created:
|
|
131
|
+
console.print(" [yellow]·[/yellow] Already initialized — nothing to do")
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
mcp = _write_mcp_config(root)
|
|
135
|
+
console.print(f" [green]✓[/green] {mcp}")
|
|
136
|
+
|
|
137
|
+
console.print(f"\n [bold green]Done.[/bold green] Open [bold]{root}[/bold] in Claude Code and type [cyan]/scaffold[/cyan]\n")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@app.command()
|
|
141
|
+
def update() -> None:
|
|
142
|
+
"""Update nexus-dev-toolkit to the latest version."""
|
|
143
|
+
console.print("\n [cyan]▶[/cyan] Updating nexus-dev-toolkit…\n")
|
|
144
|
+
if shutil.which("uv"):
|
|
145
|
+
subprocess.run(["uv", "tool", "upgrade", "nexus-dev-toolkit"])
|
|
146
|
+
else:
|
|
147
|
+
subprocess.run([sys.executable, "-m", "pip", "install", "--upgrade", "nexus-dev-toolkit"])
|
|
148
|
+
console.print("\n [green]✓[/green] Done.\n")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# ── skill subcommands ─────────────────────────────────────────────────────────
|
|
152
|
+
|
|
153
|
+
_SKILL_TEMPLATE = """\
|
|
154
|
+
# /{name}
|
|
155
|
+
|
|
156
|
+
**{name}** — describe what this skill does.
|
|
157
|
+
|
|
158
|
+
## When to use
|
|
159
|
+
|
|
160
|
+
Describe the trigger or context.
|
|
161
|
+
|
|
162
|
+
## Steps
|
|
163
|
+
|
|
164
|
+
### 1 — First step
|
|
165
|
+
|
|
166
|
+
What to do.
|
|
167
|
+
|
|
168
|
+
### 2 — Second step
|
|
169
|
+
|
|
170
|
+
What to do next.
|
|
171
|
+
|
|
172
|
+
### 3 — Output
|
|
173
|
+
|
|
174
|
+
What the AI should produce when done.
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@skill_app.command("add")
|
|
179
|
+
def skill_add(
|
|
180
|
+
name: str = typer.Argument(..., help="Skill name (e.g. 'code-review')"),
|
|
181
|
+
project_dir: str = typer.Option(".", "--dir", "-d"),
|
|
182
|
+
) -> None:
|
|
183
|
+
"""Create a new skill in .claude/commands/."""
|
|
184
|
+
root = Path(project_dir).resolve()
|
|
185
|
+
dest = root / ".claude" / "commands" / f"{name}.md"
|
|
186
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
187
|
+
|
|
188
|
+
if dest.exists():
|
|
189
|
+
console.print(f" [yellow]·[/yellow] .claude/commands/{name}.md already exists")
|
|
190
|
+
return
|
|
191
|
+
|
|
192
|
+
dest.write_text(_SKILL_TEMPLATE.format(name=name), encoding="utf-8")
|
|
193
|
+
console.print(f" [green]✓[/green] Created .claude/commands/{name}.md")
|
|
194
|
+
console.print(f" [dim]Edit it and type [cyan]/{name}[/cyan] in Claude Code.[/dim]")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@skill_app.command("list")
|
|
198
|
+
def skill_list(
|
|
199
|
+
project_dir: str = typer.Option(".", "--dir", "-d"),
|
|
200
|
+
) -> None:
|
|
201
|
+
"""List all skills in .claude/commands/."""
|
|
202
|
+
root = Path(project_dir).resolve()
|
|
203
|
+
commands_dir = root / ".claude" / "commands"
|
|
204
|
+
|
|
205
|
+
if not commands_dir.exists():
|
|
206
|
+
console.print(" [yellow]·[/yellow] No .claude/commands/ found. Run [cyan]nexus init[/cyan] first.")
|
|
207
|
+
return
|
|
208
|
+
|
|
209
|
+
skills = sorted(commands_dir.glob("*.md"))
|
|
210
|
+
if not skills:
|
|
211
|
+
console.print(" [yellow]·[/yellow] No skills yet. Run [cyan]nexus skill add <name>[/cyan]")
|
|
212
|
+
return
|
|
213
|
+
|
|
214
|
+
table = Table(show_header=True, header_style="dim")
|
|
215
|
+
table.add_column("Skill", style="cyan")
|
|
216
|
+
table.add_column("Source")
|
|
217
|
+
|
|
218
|
+
builtins = set(_BUILTIN_SKILLS)
|
|
219
|
+
for s in skills:
|
|
220
|
+
source = "built-in" if s.name in builtins else "custom"
|
|
221
|
+
table.add_row(f"/{s.stem}", source)
|
|
222
|
+
|
|
223
|
+
console.print(table)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
# ── rule subcommands ──────────────────────────────────────────────────────────
|
|
227
|
+
|
|
228
|
+
_RULE_TEMPLATE = """\
|
|
229
|
+
# {name}
|
|
230
|
+
|
|
231
|
+
_Project rule — read by AI tools via AGENTS.md._
|
|
232
|
+
|
|
233
|
+
## Rules
|
|
234
|
+
|
|
235
|
+
- Rule one
|
|
236
|
+
- Rule two
|
|
237
|
+
- Rule three
|
|
238
|
+
|
|
239
|
+
## Rationale
|
|
240
|
+
|
|
241
|
+
Why these rules exist.
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
@rule_app.command("add")
|
|
246
|
+
def rule_add(
|
|
247
|
+
name: str = typer.Argument(..., help="Rule name (e.g. 'api-standards')"),
|
|
248
|
+
project_dir: str = typer.Option(".", "--dir", "-d"),
|
|
249
|
+
) -> None:
|
|
250
|
+
"""Create a new rule in knowledge/rules/."""
|
|
251
|
+
root = Path(project_dir).resolve()
|
|
252
|
+
dest = root / "knowledge" / "rules" / f"{name}.md"
|
|
253
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
254
|
+
|
|
255
|
+
if dest.exists():
|
|
256
|
+
console.print(f" [yellow]·[/yellow] knowledge/rules/{name}.md already exists")
|
|
257
|
+
return
|
|
258
|
+
|
|
259
|
+
dest.write_text(_RULE_TEMPLATE.format(name=name), encoding="utf-8")
|
|
260
|
+
console.print(f" [green]✓[/green] Created knowledge/rules/{name}.md")
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
@rule_app.command("list")
|
|
264
|
+
def rule_list(
|
|
265
|
+
project_dir: str = typer.Option(".", "--dir", "-d"),
|
|
266
|
+
) -> None:
|
|
267
|
+
"""List all rules in knowledge/rules/."""
|
|
268
|
+
root = Path(project_dir).resolve()
|
|
269
|
+
rules_dir = root / "knowledge" / "rules"
|
|
270
|
+
|
|
271
|
+
if not rules_dir.exists():
|
|
272
|
+
console.print(" [yellow]·[/yellow] No knowledge/rules/ found. Run [cyan]nexus init[/cyan] first.")
|
|
273
|
+
return
|
|
274
|
+
|
|
275
|
+
rules = sorted(rules_dir.glob("*.md"))
|
|
276
|
+
if not rules:
|
|
277
|
+
console.print(" [yellow]·[/yellow] No rules yet. Run [cyan]nexus rule add <name>[/cyan]")
|
|
278
|
+
return
|
|
279
|
+
|
|
280
|
+
table = Table(show_header=True, header_style="dim")
|
|
281
|
+
table.add_column("Rule", style="cyan")
|
|
282
|
+
for r in rules:
|
|
283
|
+
table.add_row(r.stem)
|
|
284
|
+
console.print(table)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def main() -> None:
|
|
288
|
+
app()
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
if __name__ == "__main__":
|
|
292
|
+
main()
|