@olegkoval/agent-skills 1.38.3 → 1.40.0
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/copilot-instructions.md +1 -0
- package/.github/prompts/veto-routing.prompt.md +65 -0
- package/.kiro/steering/veto-routing.md +64 -0
- package/.windsurf/rules/veto-routing.md +63 -0
- package/README.md +3 -2
- package/adapters/claude/olko-skill-meta/skills/veto-routing/SKILL.md +76 -0
- package/adapters/codex/olko-skill-meta/README.md +1 -0
- package/adapters/cursor/olko-skill-meta/skills/veto-routing/SKILL.md +76 -0
- package/adapters/grok/olko-skill-meta/skills/veto-routing/SKILL.md +76 -0
- package/catalog/skills.json +23 -0
- package/package.json +1 -1
- package/plugins/olko-apple-kit/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-creative/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-garmin-kit/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-git-tools/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-github-pr/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-obsidian/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-product/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-reflection/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-release/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-skill-meta/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-skill-meta/skills/veto-routing/SKILL.md +75 -0
- package/plugins/olko-web-ops/.claude-plugin/plugin.json +1 -1
- package/scripts/lib/catalog.mjs +1 -1
- package/site/assets/catalog.css +1064 -0
- package/site/assets/catalog.js +232 -0
- package/site/build.mjs +218 -166
- package/site/assets/paperbag.css +0 -707
- package/site/assets/paperbag.js +0 -218
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const CONSENT_KEY = "skills-analytics-consent-v1";
|
|
5
|
+
const DATA_LAYER = "skillsDataLayer";
|
|
6
|
+
const SITE_AREA = "skills";
|
|
7
|
+
const PRODUCTION_HOST = "skills.olegkoval.com";
|
|
8
|
+
const measurementId = document.body.dataset.gaMeasurementId;
|
|
9
|
+
let analyticsEnabled = false;
|
|
10
|
+
let analyticsLoaded = false;
|
|
11
|
+
|
|
12
|
+
const getConsent = () => {
|
|
13
|
+
try {
|
|
14
|
+
return window.localStorage.getItem(CONSENT_KEY);
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const setConsent = (value) => {
|
|
21
|
+
try {
|
|
22
|
+
window.localStorage.setItem(CONSENT_KEY, value);
|
|
23
|
+
} catch {
|
|
24
|
+
// Analytics remains session-only if storage is unavailable.
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const skillsGtag = function () {
|
|
29
|
+
window[DATA_LAYER] = window[DATA_LAYER] || [];
|
|
30
|
+
window[DATA_LAYER].push(arguments);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const loadAnalytics = () => {
|
|
34
|
+
analyticsEnabled = true;
|
|
35
|
+
if (analyticsLoaded || !measurementId) return;
|
|
36
|
+
analyticsLoaded = true;
|
|
37
|
+
|
|
38
|
+
window[DATA_LAYER] = window[DATA_LAYER] || [];
|
|
39
|
+
window.skillsGtag = skillsGtag;
|
|
40
|
+
skillsGtag("js", new Date());
|
|
41
|
+
skillsGtag("config", measurementId, {
|
|
42
|
+
cookie_flags: "SameSite=None;Secure",
|
|
43
|
+
page_location: `${window.location.origin}${window.location.pathname}`,
|
|
44
|
+
page_path: window.location.pathname,
|
|
45
|
+
site_area: SITE_AREA,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Keep local previews and CI from polluting the production GA4 property.
|
|
49
|
+
if (window.location.hostname !== PRODUCTION_HOST) return;
|
|
50
|
+
|
|
51
|
+
const script = document.createElement("script");
|
|
52
|
+
script.async = true;
|
|
53
|
+
script.dataset.skillsAnalytics = "true";
|
|
54
|
+
script.src = `https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(measurementId)}&l=${DATA_LAYER}`;
|
|
55
|
+
document.head.appendChild(script);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const track = (name, params = {}) => {
|
|
59
|
+
if (!analyticsEnabled || !analyticsLoaded) return;
|
|
60
|
+
skillsGtag("event", name, {
|
|
61
|
+
...params,
|
|
62
|
+
site_area: SITE_AREA,
|
|
63
|
+
transport_type: "beacon",
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const banner = document.querySelector("[data-consent-banner]");
|
|
68
|
+
|
|
69
|
+
const showConsent = () => {
|
|
70
|
+
if (banner) banner.hidden = false;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const hideConsent = () => {
|
|
74
|
+
if (banner) banner.hidden = true;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
if (getConsent() === "accepted") loadAnalytics();
|
|
78
|
+
else if (getConsent() !== "declined") window.setTimeout(showConsent, 700);
|
|
79
|
+
|
|
80
|
+
document.querySelector("[data-consent-accept]")?.addEventListener("click", () => {
|
|
81
|
+
setConsent("accepted");
|
|
82
|
+
loadAnalytics();
|
|
83
|
+
track("analytics_consent_update", { consent_choice: "accepted" });
|
|
84
|
+
hideConsent();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
document.querySelector("[data-consent-decline]")?.addEventListener("click", () => {
|
|
88
|
+
if (analyticsLoaded) {
|
|
89
|
+
skillsGtag("consent", "update", { analytics_storage: "denied" });
|
|
90
|
+
}
|
|
91
|
+
analyticsEnabled = false;
|
|
92
|
+
setConsent("declined");
|
|
93
|
+
hideConsent();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
document.querySelector("[data-consent-open]")?.addEventListener("click", showConsent);
|
|
97
|
+
|
|
98
|
+
const selectText = (element) => {
|
|
99
|
+
const range = document.createRange();
|
|
100
|
+
range.selectNodeContents(element);
|
|
101
|
+
const selection = window.getSelection();
|
|
102
|
+
selection.removeAllRanges();
|
|
103
|
+
selection.addRange(range);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
document.querySelectorAll("[data-copy]").forEach((button) => {
|
|
107
|
+
const idle = button.textContent;
|
|
108
|
+
let resetTimer = 0;
|
|
109
|
+
|
|
110
|
+
button.addEventListener("click", async () => {
|
|
111
|
+
const container = button.closest(".command, .install-line");
|
|
112
|
+
const source = container?.querySelector("pre, code");
|
|
113
|
+
if (!source) return;
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
await navigator.clipboard.writeText(source.textContent.trim());
|
|
117
|
+
button.textContent = "Copied";
|
|
118
|
+
} catch {
|
|
119
|
+
selectText(source);
|
|
120
|
+
button.textContent = "Selected";
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
clearTimeout(resetTimer);
|
|
124
|
+
resetTimer = window.setTimeout(() => {
|
|
125
|
+
button.textContent = idle;
|
|
126
|
+
}, 1500);
|
|
127
|
+
|
|
128
|
+
const params = {};
|
|
129
|
+
for (const [key, value] of Object.entries(button.dataset)) {
|
|
130
|
+
if (!key.startsWith("analytics") || key === "analyticsEvent") continue;
|
|
131
|
+
const param = key
|
|
132
|
+
.replace(/^analytics/, "")
|
|
133
|
+
.replace(/^[A-Z]/, (letter) => letter.toLowerCase())
|
|
134
|
+
.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
135
|
+
params[param] = value;
|
|
136
|
+
}
|
|
137
|
+
track(button.dataset.analyticsEvent || "command_copy", params);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const search = document.getElementById("q");
|
|
142
|
+
const grid = document.getElementById("grid");
|
|
143
|
+
|
|
144
|
+
if (search && grid) {
|
|
145
|
+
const cards = Array.from(grid.querySelectorAll(".skill-card"));
|
|
146
|
+
const chips = Array.from(document.querySelectorAll(".chip"));
|
|
147
|
+
const count = document.getElementById("count");
|
|
148
|
+
const empty = document.getElementById("empty");
|
|
149
|
+
const active = { category: null, adapter: null };
|
|
150
|
+
let searchTimer = 0;
|
|
151
|
+
|
|
152
|
+
const apply = () => {
|
|
153
|
+
const needle = search.value.trim().toLowerCase();
|
|
154
|
+
let shown = 0;
|
|
155
|
+
|
|
156
|
+
for (const card of cards) {
|
|
157
|
+
const matchesText = !needle || card.dataset.search.includes(needle);
|
|
158
|
+
const matchesCategory = !active.category || card.dataset.category === active.category;
|
|
159
|
+
const matchesAdapter =
|
|
160
|
+
!active.adapter || card.dataset.adapters.split(" ").includes(active.adapter);
|
|
161
|
+
const visible = matchesText && matchesCategory && matchesAdapter;
|
|
162
|
+
card.hidden = !visible;
|
|
163
|
+
if (visible) shown += 1;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
count.textContent = shown === cards.length ? `${cards.length} skills` : `${shown} of ${cards.length} skills`;
|
|
167
|
+
empty.hidden = shown !== 0;
|
|
168
|
+
return shown;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
search.addEventListener("input", () => {
|
|
172
|
+
const shown = apply();
|
|
173
|
+
window.clearTimeout(searchTimer);
|
|
174
|
+
if (search.value.trim().length < 2) return;
|
|
175
|
+
searchTimer = window.setTimeout(() => {
|
|
176
|
+
track("catalog_search", { result_count: shown });
|
|
177
|
+
}, 600);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
for (const chip of chips) {
|
|
181
|
+
chip.addEventListener("click", () => {
|
|
182
|
+
const kind = chip.dataset.kind;
|
|
183
|
+
const value = chip.dataset.value;
|
|
184
|
+
const isActive = active[kind] === value;
|
|
185
|
+
active[kind] = isActive ? null : value;
|
|
186
|
+
|
|
187
|
+
for (const other of chips) {
|
|
188
|
+
if (other.dataset.kind !== kind) continue;
|
|
189
|
+
other.setAttribute("aria-pressed", String(!isActive && other.dataset.value === value));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const shown = apply();
|
|
193
|
+
track("catalog_filter", {
|
|
194
|
+
filter_type: kind,
|
|
195
|
+
filter_value: isActive ? "all" : value,
|
|
196
|
+
result_count: shown,
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const params = new URLSearchParams(window.location.search);
|
|
202
|
+
if (params.get("q")) search.value = params.get("q");
|
|
203
|
+
for (const kind of ["category", "adapter"]) {
|
|
204
|
+
const value = params.get(kind);
|
|
205
|
+
if (!value) continue;
|
|
206
|
+
const chip = chips.find(
|
|
207
|
+
(candidate) => candidate.dataset.kind === kind && candidate.dataset.value === value,
|
|
208
|
+
);
|
|
209
|
+
if (chip) {
|
|
210
|
+
active[kind] = value;
|
|
211
|
+
chip.setAttribute("aria-pressed", "true");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
apply();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
document.querySelectorAll("[data-analytics-event]").forEach((element) => {
|
|
218
|
+
if (element.matches("[data-copy]")) return;
|
|
219
|
+
element.addEventListener("click", () => {
|
|
220
|
+
const params = {};
|
|
221
|
+
for (const [key, value] of Object.entries(element.dataset)) {
|
|
222
|
+
if (!key.startsWith("analytics") || key === "analyticsEvent") continue;
|
|
223
|
+
const param = key
|
|
224
|
+
.replace(/^analytics/, "")
|
|
225
|
+
.replace(/^[A-Z]/, (letter) => letter.toLowerCase())
|
|
226
|
+
.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
227
|
+
params[param] = value;
|
|
228
|
+
}
|
|
229
|
+
track(element.dataset.analyticsEvent, params);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
})();
|