Skip to content

Commit 2cabb0f

Browse files
authored
fix(plugins): deduplicate code and fix cross-plugin imports (#1)
* fix(hooks): correct beads directory detection for worktrees - Add find_beads_dir() that searches up directory tree matching bd CLI behavior - Fix session_context.py, flow_check.py, pretool-beads-guard.py to use new function - Remove wildcard PreToolUse matcher (tmux-emoji-ops on every tool call) - Fix memory_validator.py to use session_output for proper hook formatting - Update go-dev agent skill path reference - Improve init-project.py to detect beads in parent directories * refactor(plugins): fix outdated path references and clean up hooks - Fix skill path references in ansible-scaffold.md, flux-refactor.md, harness commands, and workflow-scaffold.md - Move golangci-guard.py and pretool-go-get-check.py to go-dev plugin - Add plugin-specific hooks.json to go-dev and tdd plugins - Remove deprecated scripts: memory_validator.sh, skill_suggester.py - Update SKILL.md references to use new plugin structure * docs(flux): clarify Context7 version lookup limitations Context7 returns documentation examples which may contain older versions. Added alternative methods: helm repo search and GitHub releases. Updated cert-manager Context7 ID to correct /cert-manager/website. * refactor(hooks): remove duplicate beads check, fix command reference - flow_check.py: Remove beads check (session_context.py handles it better) - session_bootstrap.py: Fix `/init-workflow` → `/workflow-init` * refactor(hooks): move Go-specific hooks to go-dev plugin Move pretool-serializable-check.py from workflow to go-dev plugin since it's Go-specific (checks pgx.Serializable usage). Also activate golangci-guard.py which existed but was not registered. Improves plugin separation: domain-specific hooks belong in their respective plugins, not the general workflow plugin. * fix(checkpoint): reduce memory pollution with 10min granularity PreCompact hook was creating a new checkpoint every minute, causing 30+ empty memory files. Now uses 10-minute buckets and auto-cleans old empty checkpoints (> 2 hours) that were never filled in. Changes: - Timestamp uses 10-min granularity (HHMM → HH[00|10|20|30|40|50]) - Reuses existing checkpoint within same bucket - Auto-cleanup removes empty templates older than 2 hours * perf(hooks): optimize prompt-guard with project type check - Skip prompt-guard early for non-Helm/GitOps projects - Avoids unnecessary processing on every user prompt - Fix harness-init.md path to use sibling plugin reference * fix(hooks): simplify beads task check with explicit cwd The previous implementation tried to manually find the beads database path which failed in complex worktree scenarios. Now relies on bd's auto-discovery which properly handles daemon connections and worktrees. Tested with writing to external projects - hook correctly allows writes when an active task exists in the main project. * fix(tdd): use recursive glob for test file detection Test files in subdirectories (e.g., internal/services/task_test.go) were not detected because has_tests() used non-recursive glob patterns like *_test.go instead of **/*_test.go. Changes: - Use recursive glob patterns (**/*_test.go, etc.) - Use next() with default for early exit on first match - Add sync notes between duplicate implementations * docs: add sync notes for duplicate detect_tdd_mode functions Both TDD and workflow plugins have detect_tdd_mode implementations. Since plugins may be installed independently, we keep both but add cross-reference comments to help maintainers keep them in sync. * fix(hooks): add JSON error handling to version-guard The version-guard hook was missing try/except for json.load(sys.stdin). If the input was invalid JSON, the hook would crash instead of allowing the operation to proceed. * fix(harness): correct regex for beads task ID parsing The beads CLI outputs "Created issue: <id>" not "Created: <id>". Updated regex to match actual output format. * fix(plugins): deduplicate code and fix cross-plugin imports Fixes discovered during Ralph Loop testing (iterations 7-10): workflow (1.2.0 → 1.2.1): - fix: use CamelCase for Python pytest verification patterns - fix: use relative import for notifier with fallback tdd (1.1.0 → 1.1.1): - refactor: import detect_tdd_mode from workflow instead of duplicating go-dev (1.1.0 → 1.1.1): - refactor: import response utilities from workflow - remove: duplicate lib/response.py and empty lib/ directory Benefits: - Single source of truth for shared utilities - No more "Keep in sync" comments - Easier maintenance
1 parent 40f0be0 commit 2cabb0f

35 files changed

Lines changed: 390 additions & 273 deletions

plugins/ansible/commands/ansible-scaffold.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ Create the following structure:
5353

5454
### Step 3: Generate Configuration Files
5555

56-
1. **ansible.cfg** - Copy from `skills/infra/ansible-automation/examples/project-layout/ansible.cfg`
57-
2. **requirements.yml** - Copy from `skills/infra/ansible-automation/examples/project-layout/requirements.yml`
56+
1. **ansible.cfg** - Copy from `plugins/ansible/skills/ansible/examples/project-layout/ansible.cfg`
57+
2. **requirements.yml** - Copy from `plugins/ansible/skills/ansible/examples/project-layout/requirements.yml`
5858

5959
3. **.ansible-lint**:
6060
```yaml
@@ -99,17 +99,17 @@ For each environment, create:
9999
1. **hosts.yml** - Basic inventory structure
100100
2. **group_vars/all.yml** - Environment-specific variables
101101

102-
Use `skills/infra/ansible-automation/examples/project-layout/inventories/` as templates.
102+
Use `plugins/ansible/skills/ansible/examples/project-layout/inventories/` as templates.
103103

104104
### Step 5: Create Main Playbook
105105

106-
Create `playbooks/site.yml` from `skills/infra/ansible-automation/examples/playbooks/site.yml`.
106+
Create `playbooks/site.yml` from `plugins/ansible/skills/ansible/examples/playbooks/site.yml`.
107107

108108
### Step 6: Add Baseline Role (if requested)
109109

110110
If user selected baseline role:
111111

112-
1. Copy entire `skills/infra/ansible-automation/examples/baseline-role/` to `roles/baseline/`
112+
1. Copy entire `plugins/ansible/skills/ansible/examples/baseline-role/` to `roles/baseline/`
113113
2. Update variable prefix if project has specific naming
114114

115115
### Step 7: Add CI Pipeline (if requested)

plugins/flux/commands/flux-refactor.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Use AskUserQuestion to confirm:
2828
Execute the analysis script:
2929

3030
```bash
31-
python plugins/skillbox/skills/k8s/flux-gitops-refactor/scripts/analyze-structure.py /path/to/repo --format=markdown
31+
python ${CLAUDE_PLUGIN_ROOT}/skills/refactor/scripts/analyze-structure.py /path/to/repo --format=markdown
3232
```
3333

3434
Present analysis results to user showing:
@@ -125,5 +125,5 @@ configMapGenerator:
125125
126126
## References
127127
128-
- Load `skills/k8s/flux-gitops-refactor/references/refactoring-patterns.md` for detailed patterns
129-
- Load `skills/k8s/flux-gitops-scaffold/references/project-structure.md` for target structure
128+
- See `skills/refactor/references/refactoring-patterns.md` for detailed patterns
129+
- See `skills/scaffold/references/project-structure.md` for target structure

plugins/flux/skills/scaffold/references/version-matrix.md

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,41 @@
66
1. SessionStart hook — reminds about Context7 for k8s projects
77
2. PreToolUse hook — checks versions in HelmRelease files
88

9-
## Using Context7 for Latest Versions (REQUIRED)
9+
## Getting Chart Versions
1010

11-
**Mandatory workflow**fetch latest versions via Context7 before scaffolding:
11+
**Recommended workflow**verify versions before scaffolding:
1212

13-
### Step 1: Resolve Library ID
13+
### Option 1: Context7 (Documentation)
1414

1515
```
1616
Tool: resolve-library-id
1717
Parameter: libraryName="cert-manager"
18-
```
19-
20-
### Step 2: Query Documentation for Version
2118
22-
```
2319
Tool: query-docs
2420
Parameters:
25-
libraryId: "/jetstack/cert-manager"
26-
topic: "helm chart installation version"
21+
libraryId: "/cert-manager/website"
22+
topic: "helm chart install version"
2723
```
2824

25+
**Note:** Context7 returns documentation examples which may contain older versions.
26+
Use as reference but verify current release.
27+
28+
### Option 2: Helm Repo (Authoritative)
29+
30+
```bash
31+
helm repo add jetstack https://charts.jetstack.io
32+
helm search repo jetstack/cert-manager --versions | head -5
33+
```
34+
35+
### Option 3: GitHub Releases
36+
37+
Check the project's GitHub releases page for latest stable version.
38+
2939
## Component Library IDs
3040

3141
| Component | Library Name | Context7 ID |
3242
|-----------|--------------|-------------|
33-
| cert-manager | cert-manager | /jetstack/cert-manager |
43+
| cert-manager | cert-manager | /cert-manager/website |
3444
| ingress-nginx | ingress-nginx | /kubernetes/ingress-nginx |
3545
| external-secrets | external-secrets | /external-secrets/external-secrets |
3646
| external-dns | external-dns | /kubernetes-sigs/external-dns |

plugins/go-dev/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "go-dev",
33
"description": "Go development toolkit: project structure, services, repositories, handlers, OpenAPI code generation",
4-
"version": "1.0.0",
4+
"version": "1.1.1",
55
"author": {
66
"name": "11me"
77
}

plugins/go-dev/agents/project-init.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ This agent uses patterns from `go-development` skill:
143143
- **Errors**: Typed errors (EntityNotFound, ValidationFailed, StateConflict)
144144
- **Logging**: slog (default) or zap (for large projects)
145145

146-
See skill: `plugins/skillbox/skills/go/go-development/SKILL.md`
146+
See skill: `plugins/go-dev/skills/go-development/SKILL.md`
147147

148148
## Scaffolding Process
149149

plugins/go-dev/hooks/hooks.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"hooks": {
3+
"SessionStart": [
4+
{
5+
"once": true,
6+
"hooks": [
7+
{
8+
"type": "command",
9+
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/hooks/session_context.py"
10+
}
11+
]
12+
}
13+
],
14+
"PreToolUse": [
15+
{
16+
"matcher": "Bash",
17+
"hooks": [
18+
{
19+
"type": "command",
20+
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/hooks/pretool-go-get-check.py"
21+
}
22+
]
23+
},
24+
{
25+
"matcher": "Write|Edit",
26+
"hooks": [
27+
{
28+
"type": "command",
29+
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/hooks/golangci-guard.py"
30+
},
31+
{
32+
"type": "command",
33+
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/hooks/pretool-serializable-check.py"
34+
}
35+
]
36+
}
37+
]
38+
}
39+
}

plugins/workflow/scripts/hooks/golangci-guard.py renamed to plugins/go-dev/scripts/hooks/golangci-guard.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,32 @@
66
import sys
77
from pathlib import Path
88

9-
sys.path.insert(0, str(Path(__file__).parent))
10-
from lib.response import allow, ask
9+
# Import response utilities from workflow plugin (avoid duplication)
10+
_workflow_lib = Path(__file__).parent.parent.parent.parent / "workflow/scripts/hooks/lib"
11+
if _workflow_lib.exists():
12+
sys.path.insert(0, str(_workflow_lib))
13+
from response import allow, ask
14+
else:
15+
# Minimal fallback
16+
def allow(event: str | None = None) -> None:
17+
if event:
18+
print(json.dumps({"hookSpecificOutput": {"hookEventName": event}}))
19+
20+
def ask(reason: str, event: str = "PreToolUse", context: str | None = None) -> None:
21+
output: dict = {
22+
"hookSpecificOutput": {
23+
"hookEventName": event,
24+
"permissionDecision": "ask",
25+
"permissionDecisionReason": reason,
26+
}
27+
}
28+
if context:
29+
output["hookSpecificOutput"]["additionalContext"] = context
30+
print(json.dumps(output))
1131

1232

1333
def is_inside_plugin_dir(file_path: str) -> bool:
14-
"""Check if file is inside the skillbox plugin directory.
15-
16-
Uses CLAUDE_PLUGIN_ROOT env var provided by Claude Code.
17-
"""
34+
"""Check if file is inside the skillbox plugin directory."""
1835
plugin_root = os.environ.get("CLAUDE_PLUGIN_ROOT", "")
1936
if not plugin_root:
2037
return False
File renamed without changes.

plugins/workflow/scripts/hooks/pretool-serializable-check.py renamed to plugins/go-dev/scripts/hooks/pretool-serializable-check.py

File renamed without changes.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env python3
2+
"""SessionStart hook: inject Go-specific guidelines.
3+
4+
Only activates if go.mod exists in current directory.
5+
"""
6+
7+
import json
8+
from pathlib import Path
9+
10+
11+
def main() -> None:
12+
cwd = Path.cwd()
13+
14+
# Only activate for Go projects
15+
if not (cwd / "go.mod").exists():
16+
return
17+
18+
output_lines: list[str] = []
19+
20+
# Try to load GO-GUIDELINES.md from plugin
21+
guidelines_path = Path(__file__).parent.parent.parent / "skills/go-development/GO-GUIDELINES.md"
22+
if guidelines_path.exists():
23+
guidelines = guidelines_path.read_text().strip()
24+
output_lines.append("## Go Guidelines")
25+
output_lines.append("")
26+
output_lines.append(guidelines)
27+
output_lines.append("")
28+
else:
29+
# Fallback
30+
output_lines.append("**Go Linter enforces:**")
31+
output_lines.append("- `userID` not `userId` (var-naming)")
32+
output_lines.append("- `any` not `interface{}` (use-any)")
33+
output_lines.append("- No `common/helpers/utils/shared/misc` packages")
34+
output_lines.append("")
35+
output_lines.append("→ Run `golangci-lint run` after completing Go tasks")
36+
output_lines.append("")
37+
38+
output_lines.append("- Dependencies: always use `@latest` (hook enforces)")
39+
output_lines.append(
40+
"- Repository queries: use Filter pattern (`XxxFilter` + `getXxxCondition()`)"
41+
)
42+
43+
if output_lines:
44+
print(
45+
json.dumps(
46+
{
47+
"hookSpecificOutput": {
48+
"hookEventName": "SessionStart",
49+
"additionalContext": "\n".join(output_lines),
50+
}
51+
}
52+
)
53+
)
54+
55+
56+
if __name__ == "__main__":
57+
main()

0 commit comments

Comments
 (0)