obsidian-dev-skills 1.2.0 → 1.2.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.
@@ -134,6 +134,62 @@ Then cut releases by pushing a tag (e.g. `git tag 0.1.0 && git push origin 0.1.0
134
134
 
135
135
  **Fix**: merge the two rule blocks. If they target the same selector and have non-overlapping properties, combine into one block. If they target the same selector and one is meant to override the other (e.g. inside a media query), wrap the override in a more specific selector or use a CSS variable.
136
136
 
137
+ ### `!important` declarations
138
+
139
+ > Avoid `!important`. Override styles by increasing selector specificity or using CSS variables instead.
140
+
141
+ The fix is almost never to keep `!important` and hope the scorecard ignores it. Instead, scope the rule with a parent class so it wins the cascade naturally.
142
+
143
+ ```css
144
+ /* Wrong: leans on !important to beat Obsidian's defaults */
145
+ .my-plugin-btn {
146
+ border: none !important;
147
+ background: none !important;
148
+ }
149
+
150
+ /* Right: parent class boosts specificity, no !important needed */
151
+ .my-plugin-panel .my-plugin-btn {
152
+ border: none;
153
+ background: none;
154
+ }
155
+ ```
156
+
157
+ The parent class is whatever wrapper the plugin's UI lives inside (e.g. the panel root, settings container). For toggle classes that need to beat an element's natural display, chain the toggle class with the base class for the same specificity boost: `.my-plugin-panel .my-toggle-hidden { display: none; }`.
158
+
159
+ ### `:has()` selector
160
+
161
+ > Avoid `:has()`. It can cause significant performance issues due to broad selector invalidation.
162
+
163
+ Most uses of `:has()` are stylistic preferences that can be rewritten as descendant selectors targeting the child element directly.
164
+
165
+ ```css
166
+ /* Wrong: re-styles the parent based on a descendant */
167
+ .result:has(a[href*="http"]) {
168
+ word-break: break-all;
169
+ }
170
+
171
+ /* Right: targets the child directly */
172
+ .result a[href*="http"] {
173
+ word-break: break-all;
174
+ }
175
+ ```
176
+
177
+ If the rule genuinely needs to style a parent based on a child's presence, fall back to adding a marker class via TypeScript when the child is appended (e.g. `parentEl.addClass('has-external-link')`).
178
+
179
+ ### Don't override global Obsidian UI selectors
180
+
181
+ A plugin's `styles.css` is loaded globally. Rules targeting Obsidian's built-in classes affect every other plugin and Obsidian itself, not just yours.
182
+
183
+ ```css
184
+ /* Wrong: forces flex layout on every menu in Obsidian, not just this plugin's */
185
+ .menu .menu-item {
186
+ display: flex !important;
187
+ justify-content: space-between !important;
188
+ }
189
+ ```
190
+
191
+ **Fix**: either remove the rule and accept Obsidian's default styling, or scope it. Menus appended outside your plugin's panel (via `new Menu()`) can't be scoped via parent class, so the rule has to be removed, or a marker class added when the menu is opened. The scorecard does not specifically flag this leak, but it's a hygiene rule that prevents conflicts with other plugins.
192
+
137
193
  ### `obsidianmd` ESLint rules (Warnings and Risks)
138
194
 
139
195
  `eslint-plugin-obsidianmd` enforces Obsidian-idiomatic patterns. Common signals and fixes:
@@ -154,6 +210,18 @@ this.countEl.setText('0 Selected');
154
210
 
155
211
  **Never disable this rule.** The scorecard explicitly flags `eslint-disable-next-line obsidianmd/ui/sentence-case` as a Risk and counts each occurrence. If a string genuinely cannot be sentence case (e.g. it embeds a proper noun or product name), fix the casing instead of disabling.
156
212
 
213
+ **Configure the rule for domain-specific acronyms.** The rule accepts `acronyms`, `brands`, `ignoreWords`, and `ignoreRegex` options. Use these when your plugin legitimately uses acronyms or quoted button names that the rule otherwise rejects.
214
+
215
+ ```js
216
+ // eslint.config.mjs
217
+ "obsidianmd/ui/sentence-case": ["error", {
218
+ acronyms: ["SEO", "MDX", "URL", "CSV", "H1", "H2", "H3", "H4", "H5", "H6"],
219
+ ignoreRegex: ['"[^"]+"'], // ignore content inside double quotes (referenced button/control names)
220
+ }]
221
+ ```
222
+
223
+ This is the right answer when the autofix expected output is something like `'Open seo audit panel'` (downcased acronym) but the string genuinely should read `'Open SEO audit panel'`. Configuring the rule is preferred over per-line disables, which are forbidden, or awkward rephrasing.
224
+
157
225
  #### `obsidianmd/prefer-create-el-shorthand` (Warning)
158
226
 
159
227
  Use `createDiv()` and `createSpan()` instead of `createEl('div')` and `createEl('span')`.
@@ -69,6 +69,42 @@ Cut releases by pushing a tag (`git tag 0.1.0 && git push origin 0.1.0`). The wo
69
69
 
70
70
  For the full set of scorecard signals and their fixes, see [scorecard-compliance.md](scorecard-compliance.md).
71
71
 
72
+ ### Pushing tags so the workflow actually fires
73
+
74
+ Push order matters. Push commits to the default branch **first**, in a separate command, then push the tag. If you push both in a single batch (`git push --tags --follow-tags` or some GUIs), GitHub occasionally processes the tag webhook before indexing the workflow file at that ref, and the trigger silently drops.
75
+
76
+ ```bash
77
+ git push origin master # commits first
78
+ # pause a few seconds
79
+ git push origin 0.1.0 # tag in a separate command
80
+ ```
81
+
82
+ If the workflow does not fire on a tag push, diagnose with:
83
+
84
+ ```bash
85
+ gh api repos/:owner/:repo/actions/runs --jq '.workflow_runs[0:5] | .[] | {id, event, status, conclusion, head_branch, created_at}'
86
+ gh workflow list
87
+ gh api repos/:owner/:repo/actions/permissions/workflow
88
+ ```
89
+
90
+ If `gh api .../runs` is empty for the tag, the trigger was dropped. Recovery options:
91
+
92
+ - **Add `workflow_dispatch:` to the trigger** so you can re-run from the Actions tab without a re-push.
93
+ - **Re-push the tag**: `git push origin :refs/tags/0.1.0 && git push origin 0.1.0`.
94
+ - **Manually create the release** in the GitHub UI. The release will exist but it will not have the build provenance attestation, which costs scorecard points until the next release.
95
+
96
+ ### Recovery trigger
97
+
98
+ It is worth adding a manual trigger alongside the tag-push trigger so future "the workflow didn't fire" situations have a one-click fix:
99
+
100
+ ```yaml
101
+ on:
102
+ push:
103
+ tags:
104
+ - "*"
105
+ workflow_dispatch:
106
+ ```
107
+
72
108
  > [!NOTE]
73
109
  > Themes and plugins have different asset requirements and submission paths. Ensure you follow the correct flow for your project type.
74
110
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "obsidian-dev-skills",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Agent skills for Obsidian plugin and theme development, including community scorecard compliance, release workflow attestation, and dependency vulnerability hygiene.",
5
5
  "keywords": [
6
6
  "obsidian",