skillager 0.1.0__py3-none-any.whl
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.
- skillager/__init__.py +3 -0
- skillager/__main__.py +9 -0
- skillager/audience.py +133 -0
- skillager/cli.py +2639 -0
- skillager/collections.py +261 -0
- skillager/compatibility.py +158 -0
- skillager/discovery.py +233 -0
- skillager/index.py +91 -0
- skillager/lookback.py +310 -0
- skillager/materialize.py +769 -0
- skillager/onboard.py +22 -0
- skillager/paths.py +108 -0
- skillager/render.py +18 -0
- skillager/review.py +222 -0
- skillager/scan.py +292 -0
- skillager/schema.py +268 -0
- skillager/search.py +70 -0
- skillager/session.py +465 -0
- skillager/simple_yaml.py +34 -0
- skillager/trust.py +112 -0
- skillager-0.1.0.dist-info/LICENSE +21 -0
- skillager-0.1.0.dist-info/METADATA +166 -0
- skillager-0.1.0.dist-info/RECORD +25 -0
- skillager-0.1.0.dist-info/WHEEL +4 -0
- skillager-0.1.0.dist-info/entry_points.txt +2 -0
skillager/__init__.py
ADDED
skillager/__main__.py
ADDED
skillager/audience.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class AudienceSignal:
|
|
9
|
+
audience: str
|
|
10
|
+
weight: int
|
|
11
|
+
reason: str
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
DEV_SIGNALS = [
|
|
15
|
+
("commit", 3, "mentions commit workflow"),
|
|
16
|
+
("pre-land", 3, "mentions pre-land workflow"),
|
|
17
|
+
("land this", 3, "mentions landing workflow"),
|
|
18
|
+
("ship it", 2, "mentions shipping workflow"),
|
|
19
|
+
("review gate", 3, "mentions review gate"),
|
|
20
|
+
("code-review", 3, "mentions code review"),
|
|
21
|
+
("code review", 3, "mentions code review"),
|
|
22
|
+
("maintainer", 3, "mentions maintainer work"),
|
|
23
|
+
("kernel", 2, "mentions kernel work"),
|
|
24
|
+
("cuda", 2, "mentions CUDA development"),
|
|
25
|
+
("dispatch", 2, "mentions internal dispatch"),
|
|
26
|
+
("wiring", 2, "mentions internal wiring"),
|
|
27
|
+
("autonomous-execution", 2, "mentions agent execution workflow"),
|
|
28
|
+
("intake-router", 2, "mentions internal routing"),
|
|
29
|
+
("precision-compliance", 2, "mentions precision/compliance workflow"),
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
USER_SIGNALS = [
|
|
33
|
+
("gis-domain", 3, "mentions GIS domain guidance"),
|
|
34
|
+
("domain", 2, "mentions domain guidance"),
|
|
35
|
+
("concept", 2, "mentions conceptual guidance"),
|
|
36
|
+
("library usage", 3, "mentions library usage"),
|
|
37
|
+
("how to use", 3, "mentions usage guidance"),
|
|
38
|
+
("api", 2, "mentions API usage"),
|
|
39
|
+
("example", 1, "mentions examples"),
|
|
40
|
+
("tutorial", 2, "mentions tutorial guidance"),
|
|
41
|
+
("dataframe", 2, "mentions dataframe usage"),
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def classify_audience(skill: Any) -> dict[str, Any]:
|
|
46
|
+
"""Classify intended audience using only inert metadata and path-derived signals."""
|
|
47
|
+
text = _classification_text(skill)
|
|
48
|
+
signals = _signals(text)
|
|
49
|
+
declared = _declared_audiences(skill)
|
|
50
|
+
for audience in declared:
|
|
51
|
+
signals.append(AudienceSignal(audience, 2, f"declared audience: {audience}"))
|
|
52
|
+
|
|
53
|
+
scores: dict[str, int] = {"user": 0, "dev": 0}
|
|
54
|
+
reasons: dict[str, list[str]] = {"user": [], "dev": []}
|
|
55
|
+
for signal in signals:
|
|
56
|
+
if signal.audience not in scores:
|
|
57
|
+
continue
|
|
58
|
+
scores[signal.audience] += signal.weight
|
|
59
|
+
if signal.reason not in reasons[signal.audience]:
|
|
60
|
+
reasons[signal.audience].append(signal.reason)
|
|
61
|
+
|
|
62
|
+
audience = "unknown"
|
|
63
|
+
confidence = "low"
|
|
64
|
+
selected_reasons: list[str] = []
|
|
65
|
+
if scores["dev"] > scores["user"] and scores["dev"] >= 2:
|
|
66
|
+
audience = "dev"
|
|
67
|
+
confidence = _confidence(scores["dev"], scores["user"])
|
|
68
|
+
selected_reasons = reasons["dev"][:3]
|
|
69
|
+
elif scores["user"] > scores["dev"] and scores["user"] >= 2:
|
|
70
|
+
audience = "user"
|
|
71
|
+
confidence = _confidence(scores["user"], scores["dev"])
|
|
72
|
+
selected_reasons = reasons["user"][:3]
|
|
73
|
+
elif declared:
|
|
74
|
+
audience = "unknown"
|
|
75
|
+
selected_reasons = [f"conflicting or weak declared audience: {', '.join(declared)}"]
|
|
76
|
+
else:
|
|
77
|
+
selected_reasons = ["no strong audience signals in metadata"]
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
"audience": audience,
|
|
81
|
+
"confidence": confidence,
|
|
82
|
+
"reasons": selected_reasons,
|
|
83
|
+
"scores": scores,
|
|
84
|
+
"method": "metadata-heuristic",
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _classification_text(skill: Any) -> str:
|
|
89
|
+
parts = [
|
|
90
|
+
getattr(skill, "id", ""),
|
|
91
|
+
getattr(skill, "name", ""),
|
|
92
|
+
getattr(skill, "summary", ""),
|
|
93
|
+
str(getattr(skill, "entrypoint", "")),
|
|
94
|
+
str(getattr(skill, "root", "")),
|
|
95
|
+
str(getattr(skill, "package", "") or ""),
|
|
96
|
+
]
|
|
97
|
+
source = getattr(skill, "source", {}) or {}
|
|
98
|
+
if isinstance(source, dict):
|
|
99
|
+
parts.extend(str(value) for value in source.values())
|
|
100
|
+
return " ".join(parts).lower().replace("_", "-")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _declared_audiences(skill: Any) -> list[str]:
|
|
104
|
+
if getattr(skill, "inferred", False):
|
|
105
|
+
return []
|
|
106
|
+
result = []
|
|
107
|
+
for item in getattr(skill, "audience", []) or []:
|
|
108
|
+
value = item.lower()
|
|
109
|
+
if value in {"developer", "maintainer", "maintainers"}:
|
|
110
|
+
value = "dev"
|
|
111
|
+
if value in {"user", "dev"} and value not in result:
|
|
112
|
+
result.append(value)
|
|
113
|
+
return result
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _signals(text: str) -> list[AudienceSignal]:
|
|
117
|
+
result: list[AudienceSignal] = []
|
|
118
|
+
for needle, weight, reason in DEV_SIGNALS:
|
|
119
|
+
if needle in text:
|
|
120
|
+
result.append(AudienceSignal("dev", weight, reason))
|
|
121
|
+
for needle, weight, reason in USER_SIGNALS:
|
|
122
|
+
if needle in text:
|
|
123
|
+
result.append(AudienceSignal("user", weight, reason))
|
|
124
|
+
return result
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _confidence(score: int, other_score: int) -> str:
|
|
128
|
+
margin = score - other_score
|
|
129
|
+
if score >= 5 and margin >= 3:
|
|
130
|
+
return "high"
|
|
131
|
+
if score >= 3 and margin >= 2:
|
|
132
|
+
return "medium"
|
|
133
|
+
return "low"
|