@ikieaneh/opencode-kit 0.5.2 → 0.5.4
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/.opencode/plugins/opencode-kit.js +12 -1
- package/docs/examples/extension-skill-template.md +108 -0
- package/package.json +1 -1
- package/rules/rules.json +20 -0
- package/skills/verification-before-completion/SKILL.md +15 -12
- package/src/init.sh +5 -5
- package/src/postflight.sh +22 -7
- package/src/preflight.sh +61 -45
- package/templates/agents/orchestrator.md +1 -1
- package/templates/contract.json +1 -0
- package/templates/opencode-kit.schema.json +6 -2
- package/skills/java-developer/SKILL.md +0 -66
|
@@ -164,13 +164,24 @@ export const OpencodeKitPlugin = async ({ client, directory }) => {
|
|
|
164
164
|
fs.mkdirSync(path.join(globalConfigDir, 'rules'), { recursive: true });
|
|
165
165
|
|
|
166
166
|
return {
|
|
167
|
+
// Skill resolution order (first match wins):
|
|
168
|
+
// 1. .opencode/skills/<name>/ (user project — highest priority)
|
|
169
|
+
// 2. plugin skills/<name>/ (opencode-kit defaults — fallback)
|
|
167
170
|
config: async (config) => {
|
|
168
171
|
config.skills = config.skills || {};
|
|
169
172
|
config.skills.paths = config.skills.paths || [];
|
|
170
173
|
|
|
174
|
+
// Register user project skills FIRST (higher priority)
|
|
175
|
+
const userSkillsDir = path.join(projectDir, '.opencode/skills');
|
|
176
|
+
if (fs.existsSync(userSkillsDir) && !config.skills.paths.includes(userSkillsDir)) {
|
|
177
|
+
config.skills.paths.push(userSkillsDir);
|
|
178
|
+
log('info', `Registered user skills: ${userSkillsDir}`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Register plugin skills SECOND (fallback)
|
|
171
182
|
if (!config.skills.paths.includes(SKILLS_DIR)) {
|
|
172
183
|
config.skills.paths.push(SKILLS_DIR);
|
|
173
|
-
log('info', `Registered skills: ${SKILLS_DIR}`);
|
|
184
|
+
log('info', `Registered plugin skills: ${SKILLS_DIR}`);
|
|
174
185
|
}
|
|
175
186
|
|
|
176
187
|
// Register global config skills path
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Extension Skill Template
|
|
2
|
+
|
|
3
|
+
Create project-specific skills in `.opencode/skills/` to extend opencode-kit.
|
|
4
|
+
|
|
5
|
+
## Resolution Order
|
|
6
|
+
|
|
7
|
+
1. `.opencode/skills/<name>/SKILL.md` — user project skill (highest priority)
|
|
8
|
+
2. `node_modules/@ikieaneh/opencode-kit/skills/<name>/SKILL.md` — plugin skill (fallback)
|
|
9
|
+
|
|
10
|
+
If a user skill and plugin skill have the **same name**, the user's version takes priority.
|
|
11
|
+
|
|
12
|
+
## Example: Java/Spring Conventions
|
|
13
|
+
|
|
14
|
+
Create `.opencode/skills/java-conventions/SKILL.md`:
|
|
15
|
+
|
|
16
|
+
```markdown
|
|
17
|
+
---
|
|
18
|
+
description: Java 21 + Spring Boot 3.4 conventions for this project.
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Java Conventions
|
|
22
|
+
|
|
23
|
+
## Build & Test
|
|
24
|
+
|
|
25
|
+
| Command | Action |
|
|
26
|
+
|---------|--------|
|
|
27
|
+
| `mvn spotless:apply` | Format (Google Java Style) |
|
|
28
|
+
| `mvn test` | ArchUnit + unit tests |
|
|
29
|
+
| `mvn verify` | SpotBugs + PMD CPD |
|
|
30
|
+
|
|
31
|
+
## Hexagonal Architecture
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
application/ → domain model, ports, services (no Spring/JPA)
|
|
35
|
+
infrastructure/ → web adapters, persistence, events
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Writing Order
|
|
39
|
+
|
|
40
|
+
Port → Service → Mapper → Adapter → Constants → Events → Tests
|
|
41
|
+
|
|
42
|
+
## Naming Rules
|
|
43
|
+
|
|
44
|
+
| Concern | Suffix | Example |
|
|
45
|
+
|---------|--------|---------|
|
|
46
|
+
| API DTO | none | `Product` |
|
|
47
|
+
| Domain Model | `Domain` | `ProductDomain` |
|
|
48
|
+
| JPA Entity | `Entity` | `ProductEntity` |
|
|
49
|
+
|
|
50
|
+
## ArchUnit Rules (7)
|
|
51
|
+
|
|
52
|
+
1. domainMustNotDependOnInfrastructure
|
|
53
|
+
2. domainModelsMustNotHaveJpaAnnotations
|
|
54
|
+
3. portsMustNotReturnOptional
|
|
55
|
+
4. entitiesMustNotUseJpaRelationshipAnnotations
|
|
56
|
+
5. layeredArchitectureShouldRespectHexagonalBoundaries
|
|
57
|
+
6. domainServicesMustBeAnnotatedWithService
|
|
58
|
+
7. repositoryAdaptersMustBeAnnotatedWithComponent
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Example: Python/Django Conventions
|
|
62
|
+
|
|
63
|
+
Create `.opencode/skills/python-conventions/SKILL.md`:
|
|
64
|
+
|
|
65
|
+
```markdown
|
|
66
|
+
---
|
|
67
|
+
description: Django REST Framework conventions for this project.
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
# Python Conventions
|
|
71
|
+
|
|
72
|
+
## Build & Test
|
|
73
|
+
|
|
74
|
+
| Command | Action |
|
|
75
|
+
|---------|--------|
|
|
76
|
+
| `black .` | Format code |
|
|
77
|
+
| `ruff check .` | Lint |
|
|
78
|
+
| `pytest` | Run tests |
|
|
79
|
+
| `mypy .` | Type check |
|
|
80
|
+
|
|
81
|
+
## Architecture
|
|
82
|
+
|
|
83
|
+
Apps follow clean architecture:
|
|
84
|
+
- `models/` — domain models with business logic
|
|
85
|
+
- `serializers/` — input/output validation
|
|
86
|
+
- `views/` — HTTP handlers (thin)
|
|
87
|
+
- `services/` — business logic layer
|
|
88
|
+
- `tests/` — mirrors app structure
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## How to Load
|
|
92
|
+
|
|
93
|
+
In `opencode.json`, add to any agent's skills array:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"agent": {
|
|
98
|
+
"task-manager": {
|
|
99
|
+
"skills": [
|
|
100
|
+
"verification-before-completion",
|
|
101
|
+
"java-conventions"
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Or load it ad-hoc with: `/skill java-conventions`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ikieaneh/opencode-kit",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "Standardized OpenCode orchestration framework — contract-based, rules-enforced, zero-touch agent workflow. Install as plugin.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "RizkiRachman",
|
package/rules/rules.json
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
"strict": true,
|
|
4
4
|
"description": "Machine-enforceable rules for OpenCode agents. CRITICAL = BLOCK agent. HIGH = FLAG orchestrator. LOW = advisory.",
|
|
5
5
|
|
|
6
|
+
"required_mcps": {
|
|
7
|
+
"description": "MCPs required for the framework to function. Preflight.sh checks these dynamically.",
|
|
8
|
+
"lean-ctx": {
|
|
9
|
+
"description": "Context persistence — contract storage and retrieval",
|
|
10
|
+
"severity": "required",
|
|
11
|
+
"check_cli": "command -v lean-ctx",
|
|
12
|
+
"check_tool": "lean-ctx ctx_knowledge recall"
|
|
13
|
+
},
|
|
14
|
+
"gitnexus": {
|
|
15
|
+
"description": "Code intelligence — impact analysis before edits",
|
|
16
|
+
"severity": "required",
|
|
17
|
+
"check_cli": "npx --yes gitnexus --version"
|
|
18
|
+
},
|
|
19
|
+
"graphify": {
|
|
20
|
+
"description": "Knowledge graph — codebase exploration",
|
|
21
|
+
"severity": "optional",
|
|
22
|
+
"check_cli": "npx --yes gitnexus analyze --help"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
|
|
6
26
|
"state_machine": {
|
|
7
27
|
"transitions": [
|
|
8
28
|
{ "from": "INIT", "to": "PLAN", "require_score": null },
|
|
@@ -12,36 +12,39 @@ For any code change, run in order:
|
|
|
12
12
|
|
|
13
13
|
### 1. Formatting
|
|
14
14
|
```bash
|
|
15
|
-
|
|
15
|
+
# Format code (e.g., spotless, prettier, black, gofmt)
|
|
16
16
|
```
|
|
17
|
+
Expected: zero files changed after formatting (idempotent).
|
|
17
18
|
|
|
18
19
|
### 2. Compilation
|
|
19
20
|
```bash
|
|
20
|
-
|
|
21
|
-
#
|
|
21
|
+
# Build/tests — check for compilation errors
|
|
22
|
+
# e.g., mvn compile, npm run build, cargo check, go build ./...
|
|
22
23
|
```
|
|
24
|
+
Expected: BUILD SUCCESS.
|
|
23
25
|
|
|
24
|
-
### 3. Architecture (if
|
|
26
|
+
### 3. Architecture Rules (if applicable)
|
|
25
27
|
```bash
|
|
26
|
-
|
|
27
|
-
# Expected: all 7 ArchUnit rules pass
|
|
28
|
+
# Architecture tests — e.g., ArchUnit, layered boundary checks
|
|
28
29
|
```
|
|
30
|
+
Expected: all architecture rules pass.
|
|
29
31
|
|
|
30
32
|
### 4. Unit Tests
|
|
31
33
|
```bash
|
|
32
|
-
mvn test
|
|
33
|
-
# Expected: 0 failures, 0 errors
|
|
34
|
+
# Run unit tests — e.g., mvn test, npm test, pytest, cargo test
|
|
34
35
|
```
|
|
36
|
+
Expected: 0 failures, 0 errors.
|
|
35
37
|
|
|
36
38
|
### 5. Full Verification
|
|
37
39
|
```bash
|
|
38
|
-
mvn verify
|
|
39
|
-
# Expected: BUILD SUCCESS
|
|
40
|
+
# Full suite — e.g., mvn verify, npm test -- --all
|
|
40
41
|
```
|
|
42
|
+
Expected: BUILD SUCCESS.
|
|
41
43
|
|
|
42
44
|
### 6. Static Analysis (if configured)
|
|
43
45
|
```bash
|
|
44
|
-
#
|
|
46
|
+
# Linting, security scan, duplicate detection
|
|
47
|
+
# e.g., SpotBugs, ESLint, Clippy, bandit
|
|
45
48
|
```
|
|
46
49
|
|
|
47
50
|
## Evidence Rules
|
|
@@ -53,7 +56,7 @@ mvn verify
|
|
|
53
56
|
|
|
54
57
|
## Checklist
|
|
55
58
|
|
|
56
|
-
- [ ] Formatting passes (
|
|
59
|
+
- [ ] Formatting passes (idempotent)
|
|
57
60
|
- [ ] Compiles without errors
|
|
58
61
|
- [ ] All tests pass (0 failures, 0 errors)
|
|
59
62
|
- [ ] No new warnings (or documented)
|
package/src/init.sh
CHANGED
|
@@ -180,29 +180,29 @@ if [ "$SAMPLE" = true ]; then
|
|
|
180
180
|
else
|
|
181
181
|
cat > opencode.json << 'SAMPLEEOF'
|
|
182
182
|
{
|
|
183
|
-
"model": "
|
|
183
|
+
"model": "your-model",
|
|
184
184
|
"plugin": [
|
|
185
185
|
"@ikieaneh/opencode-kit",
|
|
186
186
|
"superpowers"
|
|
187
187
|
],
|
|
188
188
|
"agent": {
|
|
189
189
|
"orchestrator": {
|
|
190
|
-
"model": "
|
|
190
|
+
"model": "your-model",
|
|
191
191
|
"skills": ["orchestration-template", "scoring-pipeline", "verification-before-completion"],
|
|
192
192
|
"steps": 50
|
|
193
193
|
},
|
|
194
194
|
"planner": {
|
|
195
|
-
"model": "
|
|
195
|
+
"model": "your-model",
|
|
196
196
|
"skills": ["brainstorming", "writing-plans", "system-analyst"],
|
|
197
197
|
"steps": 80
|
|
198
198
|
},
|
|
199
199
|
"task-manager": {
|
|
200
|
-
"model": "
|
|
200
|
+
"model": "your-model",
|
|
201
201
|
"skills": ["subagent-driven-development", "executing-plans", "test-driven-development"],
|
|
202
202
|
"steps": 100
|
|
203
203
|
},
|
|
204
204
|
"code-reviewer": {
|
|
205
|
-
"model": "
|
|
205
|
+
"model": "your-model",
|
|
206
206
|
"skills": ["qa-expert", "security-expert"],
|
|
207
207
|
"steps": 80
|
|
208
208
|
}
|
package/src/postflight.sh
CHANGED
|
@@ -11,6 +11,9 @@ CONTRACT_FILE=".opencode/orchestration/contract.json"
|
|
|
11
11
|
STATE_FILE="STATE.md"
|
|
12
12
|
TELEMETRY_DIR=".opencode/telemetry"
|
|
13
13
|
START_TIME_FILE=".opencode/telemetry/.phase_start"
|
|
14
|
+
STATE_BACKUP_DIR=".opencode/state"
|
|
15
|
+
|
|
16
|
+
mkdir -p "$TELEMETRY_DIR" "$STATE_BACKUP_DIR"
|
|
14
17
|
|
|
15
18
|
echo "[opencode-kit] Post-flight: persisting state..."
|
|
16
19
|
|
|
@@ -34,16 +37,28 @@ print(d.get('state','UNKNOWN'))
|
|
|
34
37
|
rm -f "$START_TIME_FILE"
|
|
35
38
|
fi
|
|
36
39
|
|
|
37
|
-
# --- Step 1:
|
|
38
|
-
CURRENT_CONTRACT=$(lean-ctx ctx_knowledge recall --query "$CONTRACT_KEY" 2>/dev/null || cat "$CONTRACT_FILE")
|
|
40
|
+
# --- Step 1: Read contract (try lean-ctx first, fall back to file) ---
|
|
41
|
+
CURRENT_CONTRACT=$(lean-ctx ctx_knowledge recall --query "$CONTRACT_KEY" 2>/dev/null || cat "$CONTRACT_FILE" 2>/dev/null || echo "")
|
|
42
|
+
if [ -z "$CURRENT_CONTRACT" ]; then
|
|
43
|
+
echo " ⚠️ No contract found in lean-ctx or file. Creating new from template..."
|
|
44
|
+
if [ -f "$TEMPLATE_FILE" ]; then
|
|
45
|
+
CURRENT_CONTRACT=$(cat "$TEMPLATE_FILE")
|
|
46
|
+
fi
|
|
47
|
+
fi
|
|
39
48
|
|
|
40
|
-
# --- Step 2:
|
|
41
|
-
|
|
49
|
+
# --- Step 2: Persist (try lean-ctx first, fall back to file) ---
|
|
50
|
+
PERSISTED=false
|
|
51
|
+
if lean-ctx ctx_knowledge remember \
|
|
42
52
|
category architecture \
|
|
43
53
|
key "$CONTRACT_KEY" \
|
|
44
|
-
value "$CURRENT_CONTRACT" 2>/dev/null
|
|
45
|
-
echo " ✅ Contract persisted to lean-ctx"
|
|
46
|
-
|
|
54
|
+
value "$CURRENT_CONTRACT" 2>/dev/null; then
|
|
55
|
+
echo " ✅ Contract persisted to lean-ctx"
|
|
56
|
+
PERSISTED=true
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# File fallback: write to .opencode/state/contract.json
|
|
60
|
+
echo "$CURRENT_CONTRACT" > "$STATE_BACKUP_DIR/contract.json"
|
|
61
|
+
echo " ✅ Contract persisted to file: $STATE_BACKUP_DIR/contract.json"
|
|
47
62
|
|
|
48
63
|
# --- Step 3: Sync STATE.md ---
|
|
49
64
|
mkdir -p "$(dirname "$STATE_FILE")"
|
package/src/preflight.sh
CHANGED
|
@@ -33,55 +33,71 @@ if [ "$BRANCH" = "main" ] || [ "$BRANCH" = "master" ]; then
|
|
|
33
33
|
fi
|
|
34
34
|
echo " ✅ Branch: $BRANCH (safe)"
|
|
35
35
|
|
|
36
|
-
# --- Check 3: MCP Availability ---
|
|
36
|
+
# --- Check 3: MCP Availability (from rules.json) ---
|
|
37
37
|
echo ""
|
|
38
|
-
echo " Checking MCP availability..."
|
|
38
|
+
echo " Checking MCP availability from rules.json..."
|
|
39
39
|
|
|
40
40
|
MCP_FAIL=0
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
#
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
42
|
+
if [ -n "$PYTHON_CMD" ] && [ -f "$RULES_FILE" ]; then
|
|
43
|
+
# Parse required_mcps from rules.json
|
|
44
|
+
$PYTHON_CMD -c "
|
|
45
|
+
import json, sys, subprocess, os
|
|
46
|
+
|
|
47
|
+
with open('$RULES_FILE') as f:
|
|
48
|
+
rules = json.load(f)
|
|
49
|
+
|
|
50
|
+
mcps = rules.get('required_mcps', {})
|
|
51
|
+
if not isinstance(mcps, dict) or 'description' in mcps:
|
|
52
|
+
# Skip the meta-description field
|
|
53
|
+
mcps = {k: v for k, v in mcps.items() if k != 'description' and isinstance(v, dict)}
|
|
54
|
+
|
|
55
|
+
if not mcps:
|
|
56
|
+
print(' ℹ️ No required_mcps defined in rules.json — skipping MCP checks')
|
|
57
|
+
sys.exit(0)
|
|
58
|
+
|
|
59
|
+
failures = []
|
|
60
|
+
for name, cfg in mcps.items():
|
|
61
|
+
cli_check = cfg.get('check_cli', '')
|
|
62
|
+
tool_check = cfg.get('check_tool', '')
|
|
63
|
+
severity = cfg.get('severity', 'optional')
|
|
64
|
+
desc = cfg.get('description', name)
|
|
65
|
+
|
|
66
|
+
available = False
|
|
67
|
+
# Try CLI check first
|
|
68
|
+
if cli_check:
|
|
69
|
+
try:
|
|
70
|
+
result = subprocess.run(cli_check, shell=True, capture_output=True, timeout=5)
|
|
71
|
+
if result.returncode == 0:
|
|
72
|
+
available = True
|
|
73
|
+
except:
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
# Try tool check as fallback
|
|
77
|
+
if not available and tool_check:
|
|
78
|
+
try:
|
|
79
|
+
result = subprocess.run(tool_check, shell=True, capture_output=True, timeout=5)
|
|
80
|
+
if result.returncode == 0:
|
|
81
|
+
available = True
|
|
82
|
+
except:
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
if available:
|
|
86
|
+
print(f' ✅ {name}: available — {desc}')
|
|
87
|
+
elif severity == 'required':
|
|
88
|
+
print(f' ❌ {name}: NOT DETECTED — {desc}')
|
|
89
|
+
failures.append(name)
|
|
90
|
+
else:
|
|
91
|
+
print(f' ⚠️ {name}: not detected — {desc} (optional)')
|
|
92
|
+
|
|
93
|
+
if failures:
|
|
94
|
+
print('')
|
|
95
|
+
for name in failures:
|
|
96
|
+
print(f' → Ensure {name} is configured in opencode.json MCP servers')
|
|
97
|
+
sys.exit(1)
|
|
98
|
+
else:
|
|
99
|
+
sys.exit(0)
|
|
100
|
+
" 2>&1 || MCP_FAIL=1
|
|
85
101
|
fi
|
|
86
102
|
|
|
87
103
|
echo ""
|
|
@@ -94,7 +94,7 @@ Delegate to @code-reviewer. After return → Scoring Pipeline → update contrac
|
|
|
94
94
|
3. **Tier 3 (Verdict)**: ≥70 PASS, 50-69 RETRY, <50 BLOCKED
|
|
95
95
|
|
|
96
96
|
### 5. Verify (loop)
|
|
97
|
-
Run quality gates (
|
|
97
|
+
Run quality gates (format, compile, test, verify)
|
|
98
98
|
If CRITICAL findings → BLOCK, fix, re-review. Max 3 iterations.
|
|
99
99
|
|
|
100
100
|
### 6. Ship
|
package/templates/contract.json
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"properties": {
|
|
24
24
|
"skills": {
|
|
25
25
|
"type": "array",
|
|
26
|
-
"description": "
|
|
26
|
+
"description": "Skills to load for this agent (e.g., orchestration, scoring, quality gates)",
|
|
27
27
|
"items": { "type": "string" },
|
|
28
28
|
"default": ["orchestration-template", "scoring-pipeline", "verification-before-completion"]
|
|
29
29
|
},
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"properties": {
|
|
38
38
|
"skills": {
|
|
39
39
|
"type": "array",
|
|
40
|
-
"description": "
|
|
40
|
+
"description": "Skills for analysis, requirements gathering, plan writing",
|
|
41
41
|
"items": { "type": "string" },
|
|
42
42
|
"default": ["brainstorming", "writing-plans", "system-analyst"]
|
|
43
43
|
},
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"properties": {
|
|
52
52
|
"skills": {
|
|
53
53
|
"type": "array",
|
|
54
|
+
"description": "Skills for implementation, execution, testing",
|
|
54
55
|
"items": { "type": "string" },
|
|
55
56
|
"default": ["subagent-driven-development", "executing-plans", "test-driven-development"]
|
|
56
57
|
},
|
|
@@ -64,6 +65,7 @@
|
|
|
64
65
|
"properties": {
|
|
65
66
|
"skills": {
|
|
66
67
|
"type": "array",
|
|
68
|
+
"description": "Skills for code quality, security, performance review",
|
|
67
69
|
"items": { "type": "string" },
|
|
68
70
|
"default": ["qa-expert", "security-expert", "devops-expert"]
|
|
69
71
|
},
|
|
@@ -77,6 +79,7 @@
|
|
|
77
79
|
"properties": {
|
|
78
80
|
"skills": {
|
|
79
81
|
"type": "array",
|
|
82
|
+
"description": "Skills for verification, quality checks, post-analysis",
|
|
80
83
|
"items": { "type": "string" },
|
|
81
84
|
"default": ["verification-before-completion", "qa-expert"]
|
|
82
85
|
},
|
|
@@ -117,6 +120,7 @@
|
|
|
117
120
|
"properties": {
|
|
118
121
|
"skills": {
|
|
119
122
|
"type": "array",
|
|
123
|
+
"description": "Skills for architecture analysis, simplification, debugging",
|
|
120
124
|
"items": { "type": "string" },
|
|
121
125
|
"default": ["simplify", "systematic-debugging", "system-analyst"]
|
|
122
126
|
},
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Java/Spring Boot conventions for opencode-kit projects. Hexagonal architecture, ArchUnit, Maven build.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Java Developer
|
|
6
|
-
|
|
7
|
-
Load this skill if your project uses **Java + Spring Boot + Maven**.
|
|
8
|
-
|
|
9
|
-
## Build & Test
|
|
10
|
-
|
|
11
|
-
Replace generic `npm` commands with Maven equivalents:
|
|
12
|
-
|
|
13
|
-
| Generic | Java Equivalent |
|
|
14
|
-
|---------|-----------------|
|
|
15
|
-
| `npm test` | `mvn test` |
|
|
16
|
-
| `npm run build` | `mvn compile` |
|
|
17
|
-
| `npm run format` | `mvn spotless:apply` |
|
|
18
|
-
| `npm test -- --all` | `mvn verify` |
|
|
19
|
-
|
|
20
|
-
## Quality Gates (run in order)
|
|
21
|
-
|
|
22
|
-
```sh
|
|
23
|
-
mvn spotless:apply # Formatting (Google Java Style)
|
|
24
|
-
mvn test # ArchUnit (7 rules) + unit tests
|
|
25
|
-
mvn verify # SpotBugs + PMD CPD + full tests
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Agent Permission Overrides
|
|
29
|
-
|
|
30
|
-
In `opencode.json`, add Maven permissions to agents:
|
|
31
|
-
|
|
32
|
-
```json
|
|
33
|
-
"bash": {
|
|
34
|
-
"mvn test*": "allow",
|
|
35
|
-
"mvn compile*": "allow",
|
|
36
|
-
"mvn verify": "allow",
|
|
37
|
-
"mvn spotless:apply": "allow",
|
|
38
|
-
"git diff*": "allow",
|
|
39
|
-
"git log*": "allow"
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Conventions
|
|
44
|
-
|
|
45
|
-
### Hexagonal Architecture
|
|
46
|
-
```
|
|
47
|
-
application/ → domain model, ports, domain services
|
|
48
|
-
infrastructure/ → web adapters, persistence, event handlers
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Writing Order
|
|
52
|
-
Port → Service → Mapper → Adapter → Constants → Events → Tests
|
|
53
|
-
|
|
54
|
-
### Domain Models
|
|
55
|
-
- `@Builder @Getter @Setter` — zero JPA annotations
|
|
56
|
-
- Ports return **nullable**, never `Optional<T>`
|
|
57
|
-
- No JPA relationship annotations (`@ManyToOne`, `@OneToMany`, etc.)
|
|
58
|
-
|
|
59
|
-
### ArchUnit Rules (7)
|
|
60
|
-
1. domainMustNotDependOnInfrastructure
|
|
61
|
-
2. domainModelsMustNotHaveJpaAnnotations
|
|
62
|
-
3. portsMustNotReturnOptional
|
|
63
|
-
4. entitiesMustNotUseJpaRelationshipAnnotations
|
|
64
|
-
5. layeredArchitectureShouldRespectHexagonalBoundaries
|
|
65
|
-
6. domainServicesMustBeAnnotatedWithService
|
|
66
|
-
7. repositoryAdaptersMustBeAnnotatedWithComponent
|