maestro-skills 0.1.1
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/.github/workflows/ci.yml +26 -0
- package/.github/workflows/publish-npm.yml +30 -0
- package/CONTRIBUTING.md +31 -0
- package/LICENSE +21 -0
- package/README.md +300 -0
- package/SECURITY.md +33 -0
- package/docs/github-workflow.md +96 -0
- package/docs/maestro-skills-cli.md +113 -0
- package/package.json +35 -0
- package/packages/maestro-skills/README.md +37 -0
- package/packages/maestro-skills/agents.json +36 -0
- package/packages/maestro-skills/bin/cli.js +37 -0
- package/packages/maestro-skills/lib/detect-agents.js +28 -0
- package/packages/maestro-skills/lib/install.js +58 -0
- package/packages/maestro-skills/lib/paths.js +42 -0
- package/packages/maestro-skills/lib/remove.js +71 -0
- package/packages/maestro-skills/lib/run-manifest.js +92 -0
- package/packages/maestro-skills/lib/setup.js +115 -0
- package/packages/maestro-skills/package.json +47 -0
- package/packages/maestro-skills/test/agents.test.js +17 -0
- package/packages/rodovalhofs-maestro/agents.json +36 -0
- package/packages/rodovalhofs-maestro/bin/cli.js +10 -0
- package/packages/rodovalhofs-maestro/lib/detect-agents.js +28 -0
- package/packages/rodovalhofs-maestro/lib/install.js +58 -0
- package/packages/rodovalhofs-maestro/lib/paths.js +42 -0
- package/packages/rodovalhofs-maestro/lib/remove.js +71 -0
- package/packages/rodovalhofs-maestro/lib/run-manifest.js +92 -0
- package/packages/rodovalhofs-maestro/lib/setup.js +115 -0
- package/packages/rodovalhofs-maestro/package.json +33 -0
- package/scripts/sync-skill-to-cli.mjs +75 -0
- package/scripts/sync-templates.ps1 +22 -0
- package/skills/maestro/SKILL.md +272 -0
- package/skills/maestro/maestro-exclude.example.txt +6 -0
- package/skills/maestro/scripts/bm25.py +70 -0
- package/skills/maestro/scripts/build_manifest.py +183 -0
- package/skills/maestro/scripts/concept_gaps.py +196 -0
- package/skills/maestro/scripts/domains.py +148 -0
- package/skills/maestro/scripts/intents.py +167 -0
- package/skills/maestro/scripts/maestro_paths.py +41 -0
- package/skills/maestro/scripts/route_tasks.py +101 -0
- package/skills/maestro/scripts/routing.py +106 -0
- package/skills/maestro/scripts/search_skills.py +287 -0
- package/skills/maestro/scripts/synonyms.py +47 -0
- package/templates/.github/ISSUE_TEMPLATE/bug_report.yml +34 -0
- package/templates/.github/ISSUE_TEMPLATE/chore.yml +17 -0
- package/templates/.github/ISSUE_TEMPLATE/config.yml +1 -0
- package/templates/.github/ISSUE_TEMPLATE/feature_request.yml +27 -0
- package/templates/.github/workflows/ci-failure-to-issue.yml +47 -0
- package/templates/.github/workflows/ci.yml +27 -0
- package/templates/CONTRIBUTING.md +22 -0
- package/templates/labels.json +12 -0
- package/templates/pull_request_template.md +18 -0
- package/tests/fixtures/sample-manifest.json +76 -0
- package/tests/test_concept_gaps.py +63 -0
- package/tests/test_maestro_paths.py +29 -0
- package/tests/test_search_routing.py +161 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 2,
|
|
3
|
+
"skill_count": 7,
|
|
4
|
+
"skills": [
|
|
5
|
+
{
|
|
6
|
+
"name": "superdesign",
|
|
7
|
+
"folder": "superdesign",
|
|
8
|
+
"description": "Frontend UI/UX design agent for superdesign canvas drafts",
|
|
9
|
+
"tags": ["design", "ui", "ux"],
|
|
10
|
+
"domain": "design",
|
|
11
|
+
"path": "/tmp/skills/superdesign/SKILL.md",
|
|
12
|
+
"scope": "agents",
|
|
13
|
+
"installed": true
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "systematic-debugging",
|
|
17
|
+
"folder": "systematic-debugging",
|
|
18
|
+
"description": "Structured root cause debugging for failing tests",
|
|
19
|
+
"tags": ["debug", "troubleshooting"],
|
|
20
|
+
"domain": "web",
|
|
21
|
+
"path": "/tmp/skills/systematic-debugging/SKILL.md",
|
|
22
|
+
"scope": "personal",
|
|
23
|
+
"installed": true
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "gh-fix-ci",
|
|
27
|
+
"folder": "gh-fix-ci",
|
|
28
|
+
"description": "Fix failing GitHub Actions CI checks on pull requests",
|
|
29
|
+
"tags": ["github", "ci"],
|
|
30
|
+
"domain": "devops-git",
|
|
31
|
+
"path": "/tmp/skills/gh-fix-ci/SKILL.md",
|
|
32
|
+
"scope": "personal",
|
|
33
|
+
"installed": true
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "performing-memory-forensics-with-volatility3",
|
|
37
|
+
"folder": "performing-memory-forensics-with-volatility3",
|
|
38
|
+
"description": "Analyze memory dumps with Volatility 3 for credential theft",
|
|
39
|
+
"tags": ["forensics", "volatility", "memory-forensics"],
|
|
40
|
+
"domain": "security",
|
|
41
|
+
"path": "/tmp/skills/performing-memory-forensics-with-volatility3/SKILL.md",
|
|
42
|
+
"scope": "agents",
|
|
43
|
+
"installed": true
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "react-best-practices",
|
|
47
|
+
"folder": "react-best-practices",
|
|
48
|
+
"description": "React component patterns and performance",
|
|
49
|
+
"tags": ["react", "frontend"],
|
|
50
|
+
"domain": "web",
|
|
51
|
+
"path": "/tmp/skills/react-best-practices/SKILL.md",
|
|
52
|
+
"scope": "personal",
|
|
53
|
+
"installed": true
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "find-skills",
|
|
57
|
+
"folder": "find-skills",
|
|
58
|
+
"description": "Discover and install agent skills from the open skills ecosystem via npx skills",
|
|
59
|
+
"tags": ["skills", "discover", "install"],
|
|
60
|
+
"domain": "meta",
|
|
61
|
+
"path": "/tmp/skills/find-skills/SKILL.md",
|
|
62
|
+
"scope": "agents",
|
|
63
|
+
"installed": true
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "maestro",
|
|
67
|
+
"folder": "maestro",
|
|
68
|
+
"description": "Meta orchestrator",
|
|
69
|
+
"tags": ["meta"],
|
|
70
|
+
"domain": "meta",
|
|
71
|
+
"path": "/tmp/skills/maestro/SKILL.md",
|
|
72
|
+
"scope": "personal",
|
|
73
|
+
"installed": true
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Unit tests for concept gap detection."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
import unittest
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
SCRIPTS = Path(__file__).resolve().parents[1] / "skills" / "maestro" / "scripts"
|
|
10
|
+
sys.path.insert(0, str(SCRIPTS))
|
|
11
|
+
|
|
12
|
+
from concept_gaps import ( # noqa: E402
|
|
13
|
+
MAX_DISCOVER_GAPS,
|
|
14
|
+
build_discover_queries,
|
|
15
|
+
extract_concept_candidates,
|
|
16
|
+
find_concept_gaps,
|
|
17
|
+
)
|
|
18
|
+
from search_skills import skill_document # noqa: E402
|
|
19
|
+
from synonyms import expand_query # noqa: E402
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TestConceptGapLimits(unittest.TestCase):
|
|
23
|
+
def test_max_two_gaps_with_notes(self) -> None:
|
|
24
|
+
query = (
|
|
25
|
+
"colocar skeleton-loader e react-query e tanstack-table na ui"
|
|
26
|
+
)
|
|
27
|
+
candidates = extract_concept_candidates(query)
|
|
28
|
+
self.assertGreater(len(candidates), MAX_DISCOVER_GAPS)
|
|
29
|
+
|
|
30
|
+
pool = [
|
|
31
|
+
{
|
|
32
|
+
"name": "react-best-practices",
|
|
33
|
+
"folder": "react-best-practices",
|
|
34
|
+
"description": "React patterns",
|
|
35
|
+
"tags": ["react"],
|
|
36
|
+
"domain": "web",
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
results = [
|
|
40
|
+
{
|
|
41
|
+
"name": "react-best-practices",
|
|
42
|
+
"description": "React patterns",
|
|
43
|
+
"tags": ["react"],
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
gaps, notes = find_concept_gaps(
|
|
47
|
+
query, results, pool, skill_document, expand_query
|
|
48
|
+
)
|
|
49
|
+
self.assertLessEqual(len(gaps), MAX_DISCOVER_GAPS)
|
|
50
|
+
self.assertTrue(notes)
|
|
51
|
+
|
|
52
|
+
def test_build_discover_queries_includes_gap(self) -> None:
|
|
53
|
+
queries = build_discover_queries(
|
|
54
|
+
["skeleton-loader"],
|
|
55
|
+
"vamos colocar skeleton-loader na ui",
|
|
56
|
+
"web",
|
|
57
|
+
)
|
|
58
|
+
self.assertEqual(len(queries), 1)
|
|
59
|
+
self.assertIn("skeleton-loader", queries[0])
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
unittest.main()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Tests for multi-agent skill roots."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
import unittest
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
SCRIPTS = Path(__file__).resolve().parents[1] / "skills" / "maestro" / "scripts"
|
|
10
|
+
sys.path.insert(0, str(SCRIPTS))
|
|
11
|
+
|
|
12
|
+
from maestro_paths import GLOBAL_SKILL_ROOTS, project_skill_roots # noqa: E402
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestMaestroPaths(unittest.TestCase):
|
|
16
|
+
def test_global_roots_include_codex(self) -> None:
|
|
17
|
+
scopes = [scope for _, scope in GLOBAL_SKILL_ROOTS]
|
|
18
|
+
self.assertIn("codex", scopes)
|
|
19
|
+
codex_path = next(path for path, scope in GLOBAL_SKILL_ROOTS if scope == "codex")
|
|
20
|
+
self.assertTrue(str(codex_path).replace("\\", "/").endswith("/.codex/skills"))
|
|
21
|
+
|
|
22
|
+
def test_project_roots_include_codex(self) -> None:
|
|
23
|
+
roots = project_skill_roots(Path("/tmp/project"))
|
|
24
|
+
scopes = [scope for _, scope in roots]
|
|
25
|
+
self.assertIn("project-codex", scopes)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == "__main__":
|
|
29
|
+
unittest.main()
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""Tests for maestro hybrid skill routing."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
import unittest
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
11
|
+
SCRIPTS = ROOT / "skills" / "maestro" / "scripts"
|
|
12
|
+
sys.path.insert(0, str(SCRIPTS))
|
|
13
|
+
|
|
14
|
+
from concept_gaps import extract_concept_candidates, find_concept_gaps # noqa: E402
|
|
15
|
+
from intents import is_bypass_task, is_force_discover, task_intents # noqa: E402
|
|
16
|
+
from routing import build_routing, is_high_risk, select_mode # noqa: E402
|
|
17
|
+
from route_tasks import route_batch # noqa: E402
|
|
18
|
+
from search_skills import search_skills, skill_document # noqa: E402
|
|
19
|
+
from synonyms import expand_query # noqa: E402
|
|
20
|
+
|
|
21
|
+
FIXTURE_MANIFEST = Path(__file__).parent / "fixtures" / "sample-manifest.json"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def load_fixture() -> dict:
|
|
25
|
+
return json.loads(FIXTURE_MANIFEST.read_text(encoding="utf-8"))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TestSynonyms(unittest.TestCase):
|
|
29
|
+
def test_portuguese_debug_expansion(self) -> None:
|
|
30
|
+
expanded = expand_query("depurar teste falhando")
|
|
31
|
+
self.assertIn("debug", expanded)
|
|
32
|
+
self.assertIn("test", expanded)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TestIntents(unittest.TestCase):
|
|
36
|
+
def test_debug_intent_detected(self) -> None:
|
|
37
|
+
intents = task_intents("inspect failing test and find root cause")
|
|
38
|
+
names = [i["name"] for i in intents]
|
|
39
|
+
self.assertIn("root-cause-debugging", names)
|
|
40
|
+
|
|
41
|
+
def test_bypass_greeting(self) -> None:
|
|
42
|
+
self.assertTrue(is_bypass_task("oi"))
|
|
43
|
+
|
|
44
|
+
def test_force_discover_intent(self) -> None:
|
|
45
|
+
self.assertTrue(is_force_discover("find a skill for changelog"))
|
|
46
|
+
self.assertTrue(is_force_discover("tem skill para deploy"))
|
|
47
|
+
self.assertFalse(is_force_discover("corrigir CI no PR"))
|
|
48
|
+
|
|
49
|
+
def test_skill_discovery_intent_profile(self) -> None:
|
|
50
|
+
intents = task_intents("npx skills find react")
|
|
51
|
+
names = [i["name"] for i in intents]
|
|
52
|
+
self.assertIn("skill-discovery", names)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class TestRouting(unittest.TestCase):
|
|
56
|
+
def test_high_risk_forces_recommend(self) -> None:
|
|
57
|
+
self.assertTrue(is_high_risk("deploy to production with token"))
|
|
58
|
+
mode = select_mode(0.9, high_risk=True)
|
|
59
|
+
self.assertEqual(mode, "recommend")
|
|
60
|
+
|
|
61
|
+
def test_p1_auto_load(self) -> None:
|
|
62
|
+
matches = [{"confidence": 0.4, "mode": "auto-load"}]
|
|
63
|
+
routing = build_routing("design dashboard ui", matches, high_risk=False)
|
|
64
|
+
self.assertEqual(routing["priority"], "P1")
|
|
65
|
+
self.assertEqual(routing["decision"], "auto-load")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class TestConceptGaps(unittest.TestCase):
|
|
69
|
+
def test_extract_skeleton_loader(self) -> None:
|
|
70
|
+
query = "vamos fazer uma alteração na ui e vamos colocar skeleton-loader"
|
|
71
|
+
candidates = extract_concept_candidates(query)
|
|
72
|
+
self.assertIn("skeleton-loader", candidates)
|
|
73
|
+
|
|
74
|
+
def test_ui_is_stopword(self) -> None:
|
|
75
|
+
query = "melhorar a ui do app"
|
|
76
|
+
candidates = extract_concept_candidates(query)
|
|
77
|
+
self.assertNotIn("ui", candidates)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class TestSearchSkills(unittest.TestCase):
|
|
81
|
+
def setUp(self) -> None:
|
|
82
|
+
self.manifest = load_fixture()
|
|
83
|
+
|
|
84
|
+
def test_superdesign_ranks_for_design_query(self) -> None:
|
|
85
|
+
result = search_skills(
|
|
86
|
+
"design landing page UI with superdesign",
|
|
87
|
+
self.manifest,
|
|
88
|
+
domain="design",
|
|
89
|
+
)
|
|
90
|
+
self.assertTrue(result["results"])
|
|
91
|
+
self.assertEqual(result["results"][0]["name"], "superdesign")
|
|
92
|
+
self.assertIn("routing", result)
|
|
93
|
+
self.assertIn(result["routing"]["priority"], {"P1", "P2"})
|
|
94
|
+
|
|
95
|
+
def test_forensics_intent_boost(self) -> None:
|
|
96
|
+
result = search_skills(
|
|
97
|
+
"memory forensics credential dumping volatility",
|
|
98
|
+
self.manifest,
|
|
99
|
+
domain="security",
|
|
100
|
+
)
|
|
101
|
+
self.assertTrue(result["results"])
|
|
102
|
+
self.assertEqual(
|
|
103
|
+
result["results"][0]["name"],
|
|
104
|
+
"performing-memory-forensics-with-volatility3",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
def test_concept_gap_triggers_discover(self) -> None:
|
|
108
|
+
result = search_skills(
|
|
109
|
+
"vamos fazer uma alteração na ui e vamos colocar skeleton-loader",
|
|
110
|
+
self.manifest,
|
|
111
|
+
domain="web",
|
|
112
|
+
)
|
|
113
|
+
discover = result["discover"]
|
|
114
|
+
self.assertTrue(discover["triggered"])
|
|
115
|
+
self.assertIn("concept_gap", discover["reasons"])
|
|
116
|
+
self.assertIn("skeleton-loader", discover["gaps"])
|
|
117
|
+
self.assertTrue(discover["queries"])
|
|
118
|
+
self.assertFalse(result.get("missing_skills"))
|
|
119
|
+
|
|
120
|
+
def test_force_discover_triggers_even_with_strong_local(self) -> None:
|
|
121
|
+
result = search_skills(
|
|
122
|
+
"find a skill for react performance",
|
|
123
|
+
self.manifest,
|
|
124
|
+
domain="web",
|
|
125
|
+
)
|
|
126
|
+
discover = result["discover"]
|
|
127
|
+
self.assertTrue(discover["triggered"])
|
|
128
|
+
self.assertTrue(discover["force_discover"])
|
|
129
|
+
self.assertIn("force_discover", discover["reasons"])
|
|
130
|
+
|
|
131
|
+
def test_ci_query_no_discover(self) -> None:
|
|
132
|
+
result = search_skills(
|
|
133
|
+
"corrigir CI quebrado no pull request",
|
|
134
|
+
self.manifest,
|
|
135
|
+
domain="devops-git",
|
|
136
|
+
)
|
|
137
|
+
self.assertEqual(result["results"][0]["name"], "gh-fix-ci")
|
|
138
|
+
self.assertFalse(result["discover"]["triggered"])
|
|
139
|
+
|
|
140
|
+
def test_bypass_routing(self) -> None:
|
|
141
|
+
result = search_skills("oi", self.manifest)
|
|
142
|
+
self.assertEqual(result["routing"]["priority"], "P3")
|
|
143
|
+
self.assertEqual(result["routing"]["decision"], "bypass")
|
|
144
|
+
self.assertFalse(result["discover"]["triggered"])
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class TestRouteBatch(unittest.TestCase):
|
|
148
|
+
def test_batch_returns_per_task_results(self) -> None:
|
|
149
|
+
payload = route_batch(
|
|
150
|
+
["design dashboard ui", "fix failing CI on PR"],
|
|
151
|
+
FIXTURE_MANIFEST,
|
|
152
|
+
)
|
|
153
|
+
self.assertTrue(payload["batch"])
|
|
154
|
+
self.assertEqual(payload["task_count"], 2)
|
|
155
|
+
self.assertEqual(len(payload["results"]), 2)
|
|
156
|
+
self.assertIn("routing", payload)
|
|
157
|
+
self.assertIn("discover", payload)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
if __name__ == "__main__":
|
|
161
|
+
unittest.main()
|