opencode-skills-collection 3.1.13 → 3.1.14

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.
Files changed (28) hide show
  1. package/README.md +4 -6
  2. package/bundled-skills/.antigravity-install-manifest.json +4 -1
  3. package/bundled-skills/before-you-build/SKILL.md +111 -0
  4. package/bundled-skills/cron-doctor/scripts/cron-engine.js +10 -7
  5. package/bundled-skills/dispatch/SKILL.md +130 -0
  6. package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
  7. package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
  8. package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
  9. package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
  10. package/bundled-skills/docs/users/bundles.md +1 -1
  11. package/bundled-skills/docs/users/claude-code-skills.md +1 -1
  12. package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
  13. package/bundled-skills/docs/users/getting-started.md +1 -1
  14. package/bundled-skills/docs/users/kiro-integration.md +1 -1
  15. package/bundled-skills/docs/users/usage.md +4 -4
  16. package/bundled-skills/docs/users/visual-guide.md +4 -4
  17. package/bundled-skills/gh-image/SKILL.md +10 -2
  18. package/bundled-skills/hugging-face-model-trainer/SKILL.md +6 -1
  19. package/bundled-skills/hugging-face-model-trainer/references/gguf_conversion.md +5 -0
  20. package/bundled-skills/hugging-face-model-trainer/scripts/convert_to_gguf.py +30 -2
  21. package/bundled-skills/mdpr-skill/SKILL.md +233 -0
  22. package/bundled-skills/riffkit/SKILL.md +2 -2
  23. package/bundled-skills/sql-sentinel/SKILL.md +12 -3
  24. package/bundled-skills/weaviate/references/environment_requirements.md +4 -1
  25. package/bundled-skills/weaviate/scripts/weaviate_conn.py +35 -11
  26. package/bundled-skills/youtube-notetaker/scripts/serve.py +20 -11
  27. package/package.json +1 -1
  28. package/skills_index.json +85 -15
@@ -34,11 +34,13 @@ Usage:
34
34
  - BASE_MODEL: Base model used for fine-tuning (e.g., "Qwen/Qwen2.5-0.5B")
35
35
  - OUTPUT_REPO: Where to upload GGUF files (e.g., "username/my-model-gguf")
36
36
  - HF_USERNAME: Your Hugging Face username (optional, for README)
37
+ - TRUST_REMOTE_CODE: Set to "1" only for reviewed model repositories that require custom code
37
38
 
38
39
  Dependencies: All required packages are declared in PEP 723 header above.
39
40
  """
40
41
 
41
42
  import os
43
+ import re
42
44
  import sys
43
45
  import torch
44
46
  from transformers import AutoModelForCausalLM, AutoTokenizer
@@ -99,6 +101,23 @@ def run_command(cmd, description):
99
101
  return False
100
102
 
101
103
 
104
+ HF_REPO_ID_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,95}/[A-Za-z0-9][A-Za-z0-9._-]{0,95}$")
105
+
106
+
107
+ def require_hf_repo_id(value, name):
108
+ """Reject local paths, URLs, and shell-like values before loading models."""
109
+ if not HF_REPO_ID_RE.fullmatch(value):
110
+ print(
111
+ f" Invalid {name}: {value!r}. Use a Hugging Face repo id like owner/model.",
112
+ file=sys.stderr,
113
+ )
114
+ sys.exit(1)
115
+
116
+
117
+ def env_flag(name):
118
+ return os.environ.get(name, "").strip().lower() in {"1", "true", "yes", "on"}
119
+
120
+
102
121
  print("šŸ”„ GGUF Conversion Script")
103
122
  print("=" * 60)
104
123
 
@@ -112,11 +131,17 @@ ADAPTER_MODEL = os.environ.get("ADAPTER_MODEL", "evalstate/qwen-capybara-medium"
112
131
  BASE_MODEL = os.environ.get("BASE_MODEL", "Qwen/Qwen2.5-0.5B")
113
132
  OUTPUT_REPO = os.environ.get("OUTPUT_REPO", "evalstate/qwen-capybara-medium-gguf")
114
133
  username = os.environ.get("HF_USERNAME", ADAPTER_MODEL.split('/')[0])
134
+ TRUST_REMOTE_CODE = env_flag("TRUST_REMOTE_CODE")
135
+
136
+ require_hf_repo_id(ADAPTER_MODEL, "ADAPTER_MODEL")
137
+ require_hf_repo_id(BASE_MODEL, "BASE_MODEL")
138
+ require_hf_repo_id(OUTPUT_REPO, "OUTPUT_REPO")
115
139
 
116
140
  print(f"\nšŸ“¦ Configuration:")
117
141
  print(f" Base model: {BASE_MODEL}")
118
142
  print(f" Adapter model: {ADAPTER_MODEL}")
119
143
  print(f" Output repo: {OUTPUT_REPO}")
144
+ print(f" Trust remote code: {TRUST_REMOTE_CODE}")
120
145
 
121
146
  # Step 1: Load base model and adapter
122
147
  print("\nšŸ”§ Step 1: Loading base model and LoRA adapter...")
@@ -127,7 +152,7 @@ try:
127
152
  BASE_MODEL,
128
153
  dtype=torch.float16,
129
154
  device_map="auto",
130
- trust_remote_code=True,
155
+ trust_remote_code=TRUST_REMOTE_CODE,
131
156
  )
132
157
  print(" āœ… Base model loaded")
133
158
  except Exception as e:
@@ -149,7 +174,10 @@ except Exception as e:
149
174
 
150
175
  try:
151
176
  # Load tokenizer
152
- tokenizer = AutoTokenizer.from_pretrained(ADAPTER_MODEL, trust_remote_code=True)
177
+ tokenizer = AutoTokenizer.from_pretrained(
178
+ ADAPTER_MODEL,
179
+ trust_remote_code=TRUST_REMOTE_CODE,
180
+ )
153
181
  print(" āœ… Tokenizer loaded")
154
182
  except Exception as e:
155
183
  print(f" āŒ Failed to load tokenizer: {e}")
@@ -0,0 +1,233 @@
1
+ ---
2
+ name: mdpr-skill
3
+ description: "Review MDPR Markdown presentation workflows with semantic hints, visual checks, and deterministic renderer boundaries."
4
+ category: productivity
5
+ risk: safe
6
+ source: community
7
+ source_repo: ch040602/mdpr-skill
8
+ source_type: community
9
+ date_added: "2026-07-01"
10
+ author: ch040602
11
+ tags: [mdpr, presentations, markdown, powerpoint, codex, visual-review, agent-hints]
12
+ tools: [claude, cursor, gemini, codex, antigravity]
13
+ license: "MIT"
14
+ license_source: "https://github.com/ch040602/mdpr-skill/blob/main/LICENSE"
15
+ ---
16
+
17
+ # mdpr-skill
18
+
19
+ ## Overview
20
+
21
+ Use this skill as the optional agent companion for
22
+ [MDPR](https://github.com/ch040602/MdPr), a deterministic
23
+ Markdown-to-presentation runtime. MDPR owns parsing, layout, theming,
24
+ validation, and final PPTX/HTML/PDF rendering. This skill helps an agent review
25
+ MDPR workflows, propose weak semantic hints, and explain visual findings without
26
+ taking control of slide geometry.
27
+
28
+ The upstream skill source is
29
+ [`ch040602/mdpr-skill`](https://github.com/ch040602/mdpr-skill), which includes
30
+ schemas, review commands, compatibility artifacts, visual evidence examples, and
31
+ MDPR boundary documentation.
32
+
33
+ ## When to Use This Skill
34
+
35
+ - Use when the user asks about MDPR, `mdpresent`, Markdown-to-PPTX, or
36
+ Markdown presentation review.
37
+ - Use when generated MDPR artifacts need semantic, narrative, accessibility, or
38
+ visual review notes.
39
+ - Use when the user wants Codex-style presentation workflow hints while keeping
40
+ MDPR as the deterministic renderer.
41
+ - Use when comparing MDPR output against image-only deck generators such as a
42
+ codex-ppt style workflow.
43
+ - Use when a reusable theme or style-pack proposal should be expressed as an
44
+ approval-bound MDPR candidate instead of direct final slide edits.
45
+
46
+ ## Core Boundary
47
+
48
+ - Let MDPR own parsing, slide splitting, recipes, layout, coordinates,
49
+ geometry, typography, colors, z-order, arrows, effects, exact icon assets,
50
+ renderer object IDs, and final PPTX objects.
51
+ - Keep agent output semantic, evidence-based, and schema-valid.
52
+ - Express fixes as Markdown cleanup, MDPR rulebook changes, config changes,
53
+ deterministic policy changes, or approval-bound proposals.
54
+ - Preserve the ability to build the same deck with all agent hints disabled.
55
+ - Do not mutate source Markdown unless the user explicitly asks for a cleaned
56
+ source draft.
57
+
58
+ ## How It Works
59
+
60
+ ### Step 1: Identify the MDPR Surface
61
+
62
+ Classify the user's request before producing advice:
63
+
64
+ - `semantic hints`: compact intent, grouping, importance, and icon-keyword
65
+ suggestions.
66
+ - `review report`: visual or narrative concerns grounded in rendered evidence,
67
+ manifests, or validation reports.
68
+ - `layout intent`: high-level layout goals from a summarized template catalog,
69
+ never concrete placeholder coordinates.
70
+ - `theme candidate`: reusable token and style-pack proposal for later MDPR
71
+ approval/import gates.
72
+ - `codex-ppt compatibility`: feature mapping and comparison notes only; do not
73
+ turn MDPR into a full-slide image renderer.
74
+
75
+ ### Step 2: Ground Every Finding
76
+
77
+ Reference available evidence such as:
78
+
79
+ - source Markdown path or heading text
80
+ - MDPR manifest summaries
81
+ - rendered preview image paths
82
+ - validation report IDs
83
+ - source notes or citation metadata
84
+ - schema names such as `agent-hint.json`, `review-report.json`, or
85
+ `mdpr-theme-candidate-v1`
86
+
87
+ If evidence is missing, say what artifact is needed instead of inventing a
88
+ pass/fail result.
89
+
90
+ ### Step 3: Keep Hints Weak
91
+
92
+ Allowed hints:
93
+
94
+ - slide or section intent
95
+ - content grouping
96
+ - relative importance
97
+ - icon-search keywords
98
+ - accessibility or citation review notes
99
+ - generated-image candidate briefs when an icon would be too small or too
100
+ semantically ambiguous
101
+
102
+ Disallowed hints:
103
+
104
+ - final coordinates, sizes, z-order, geometry, or object IDs
105
+ - exact colors, typography, arrows, effects, or icon asset choices
106
+ - final layout IDs or placeholder IDs
107
+ - pass/fail validation decisions not backed by MDPR validation
108
+
109
+ ### Step 4: Route Fixes to MDPR-Owned Changes
110
+
111
+ When repeated issues appear, recommend a deterministic follow-up surface:
112
+
113
+ - Markdown cleanup
114
+ - MDPR rulebook change
115
+ - MDPR config/profile change
116
+ - MDPR theme-pack registration
117
+ - MDPR validation improvement
118
+ - approval-bound deck-local override or style-pack candidate
119
+
120
+ ## Useful Local Commands
121
+
122
+ Run these only when the upstream `mdpr-skill` CLI is available in the current
123
+ workspace and the referenced input files exist.
124
+
125
+ ```bash
126
+ node bin/mdpr-skill.js hint --source-sha256 <64hex> --out .mdpresent/proposals/agent-hint.json
127
+ node bin/mdpr-skill.js review --manifest dist/mdpresent-manifest.json --out .mdpresent/review/review-report.json
128
+ node bin/mdpr-skill.js narrative --markdown deck.md --manifest dist/mdpresent-manifest.json --out .mdpresent/review/narrative-review.json
129
+ node bin/mdpr-skill.js layout-intent --layout-catalog template-layout-catalog.json --out .mdpresent/review/layout-intent.json
130
+ node bin/mdpr-skill.js accessibility --markdown deck.md --audience "executive review" --out .mdpresent/review/accessibility-review.json
131
+ ```
132
+
133
+ ## Examples
134
+
135
+ ### Review a Rendered MDPR Deck
136
+
137
+ 1. Read the source Markdown, manifest summary, rendered image list, and any
138
+ validation report.
139
+ 2. Separate source-content problems from renderer/rulebook problems.
140
+ 3. Report only evidence-backed visual concerns.
141
+ 4. Recommend deterministic MDPR fixes when the same issue repeats.
142
+
143
+ ```markdown
144
+ Finding: Slide 4 has weak visual hierarchy between the metric and explanation.
145
+ Evidence: rendered/slide-04.png, manifest slide id `s4`, heading "Revenue Mix".
146
+ MDPR-owned fix: adjust the metric-card recipe spacing rule or choose a
147
+ deterministic layout profile with stronger numeric emphasis.
148
+ ```
149
+
150
+ ### Propose a Theme Candidate
151
+
152
+ 1. Treat the source design as a visual system, not content to copy.
153
+ 2. Extract reusable tokens, semantic layout blueprints, decoration grammar, and
154
+ best-fit scenarios.
155
+ 3. Emit an approval-bound `mdpr-theme-candidate-v1`.
156
+ 4. Keep `mdprOwnsFinalLayout`, `mdprOwnsFinalThemeBinding`, and
157
+ `noRawUseInAgentHints` true.
158
+
159
+ ```json
160
+ {
161
+ "schema": "mdpr-theme-candidate-v1",
162
+ "source": "rendered reference set approved by user",
163
+ "useCases": ["executive review", "research update"],
164
+ "constraints": {
165
+ "mdprOwnsFinalLayout": true,
166
+ "mdprOwnsFinalThemeBinding": true,
167
+ "noRawUseInAgentHints": true
168
+ }
169
+ }
170
+ ```
171
+
172
+ ### Compare with codex-ppt Style Workflows
173
+
174
+ Use codex-ppt only as a capability reference or image-only baseline. Preserve
175
+ the output-model distinction: codex-ppt style workflows may produce full-slide
176
+ images, while MDPR defaults to editable PPTX/HTML/PDF with deterministic
177
+ validation.
178
+
179
+ ```markdown
180
+ Comparison note: codex-ppt style output may optimize for a single rasterized
181
+ slide image. MDPR should instead preserve editable slide objects and route
182
+ visual improvements through recipes, themes, and validation policies.
183
+ ```
184
+
185
+ ## Best Practices
186
+
187
+ - Do: Prefer concise semantic hints over restating the source.
188
+ - Do: Keep review notes actionable for MDPR maintainers.
189
+ - Do: Call out missing evidence before making quality claims.
190
+ - Do: Treat LLM judgment as triage only; MDPR validation remains the release
191
+ gate.
192
+ - Avoid: Turning generated asset prompts into final asset selections.
193
+ - Avoid: Recommending raw colors, coordinates, or renderer object IDs from
194
+ agent judgment alone.
195
+
196
+ ## Limitations
197
+
198
+ - This skill does not replace MDPR runtime validation.
199
+ - This skill does not generate final slide coordinates or final PPTX objects.
200
+ - This skill does not make MDPR depend on an LLM.
201
+ - This skill should not be used to copy private deck designs or proprietary
202
+ slide content.
203
+
204
+ ## Common Pitfalls
205
+
206
+ - **Problem:** Treating mdpr-skill output as final slide layout.
207
+ **Solution:** Keep hints semantic and let MDPR choose final layout, geometry,
208
+ and renderer objects.
209
+
210
+ - **Problem:** Reporting visual issues without evidence.
211
+ **Solution:** Link each finding to source Markdown, a manifest entry, rendered
212
+ previews, validation reports, or another concrete artifact.
213
+
214
+ - **Problem:** Copying codex-ppt image-only behavior into MDPR.
215
+ **Solution:** Use image-only generators as comparison baselines while
216
+ preserving MDPR's editable PPTX/HTML/PDF output model.
217
+
218
+ ## Security & Safety Notes
219
+
220
+ - Review only files the user has provided or authorized.
221
+ - Do not fetch private references, credentials, or paid assets without explicit
222
+ permission.
223
+ - Do not include secrets, API keys, or private source content in generated
224
+ review reports or theme candidates.
225
+ - Treat all CLI commands as local workspace commands; confirm input paths exist
226
+ before running them.
227
+
228
+ ## Related Skills
229
+
230
+ - `@frontend-slides` - Use for browser-native HTML presentation generation.
231
+ - `@2slides-ppt-generator` - Use for hosted API-based presentation generation.
232
+ - `@office-productivity` - Use for broader document, spreadsheet, and slide
233
+ workflow coordination.
@@ -2,7 +2,7 @@
2
2
  name: riffkit
3
3
  description: "Riff a winning TikTok into your own short video — study a proven video's emotion formula and regenerate it with your product, character, and language (EN/ES). Also makes UGC ad creative."
4
4
  category: api-integration
5
- risk: safe
5
+ risk: critical
6
6
  source: community
7
7
  source_repo: riffkit/skill
8
8
  source_type: community
@@ -115,7 +115,7 @@ riff https://www.tiktok.com/@user/video/123 into my product video, in Spanish
115
115
 
116
116
  Riffkit is a hosted service — generating videos requires a Riffkit account (billed by the second of finished video). No local GPU or models. Create an account at https://riffkit.ai.
117
117
 
118
- **On the `risk: safe` label:** the skill performs no destructive or privileged actions — it only reads account data and submits render jobs a normal authenticated user can make. It *does* trigger a paid render, but that spend is gated behind an explicit, per-run user confirmation (see the workflow's Step 4 and the Security & Safety Notes) — it never spends autonomously. This matches other billed-API skills already in the catalog (e.g. `2slides-ppt-generator`).
118
+ **On the `risk: critical` label:** the skill handles a live account session token and `POST /api/riffs` starts a paid render. The workflow requires explicit, per-run confirmation before submitting, but the catalog risk label must still reflect token handling and billable mutation.
119
119
 
120
120
  ## Related Skills
121
121
 
@@ -2,7 +2,7 @@
2
2
  name: sql-sentinel
3
3
  description: "Audit SQL for the cost & performance anti-patterns that burn warehouse credits. Scores warehouse health 0-100 and outputs a prioritized cost-reduction plan for BigQuery, Snowflake, Redshift, and Postgres."
4
4
  category: data
5
- risk: safe
5
+ risk: critical
6
6
  source: community
7
7
  source_repo: takeaseatventure/sql-sentinel
8
8
  source_type: community
@@ -10,6 +10,14 @@ date_added: "2026-06-26"
10
10
  author: takeaseat
11
11
  tags: [sql, bigquery, snowflake, redshift, postgres, data-warehouse, cost-optimization, performance, audit, finops]
12
12
  tools: [claude, cursor, codex, gemini]
13
+ plugin:
14
+ targets:
15
+ codex: blocked
16
+ claude: blocked
17
+ setup:
18
+ type: manual
19
+ summary: "Clone the upstream analyzer only after pinning or reviewing the exact commit to run."
20
+ docs: SKILL.md
13
21
  license: "MIT"
14
22
  license_source: "https://github.com/takeaseatventure/sql-sentinel/blob/main/LICENSE"
15
23
  ---
@@ -22,7 +30,7 @@ A static-analysis skill that audits SQL for the cost & performance anti-patterns
22
30
 
23
31
  Built for analytics engineers (dbt, Looker), data platform teams running FinOps / "reduce cloud spend" initiatives, and anyone reviewing a SQL pull request before it hits production. Works across BigQuery, Snowflake, Redshift, and Postgres. Zero dependencies, MIT licensed.
24
32
 
25
- The executable engine and full rule set live in the source repository: https://github.com/takeaseatventure/sql-sentinel
33
+ The executable engine and full rule set live in the source repository: https://github.com/takeaseatventure/sql-sentinel. Treat that repository as third-party executable code.
26
34
 
27
35
  ## When to Use This Skill
28
36
 
@@ -38,11 +46,12 @@ The engine splits a SQL script into statements (honoring quotes and comments), r
38
46
 
39
47
  ### Step 1: Run the audit
40
48
 
41
- Install or clone the source repository, then run the zero-dependency engine:
49
+ Install or clone the source repository only after choosing a reviewed commit, tag, or release to trust. Do not run code from a mutable default branch just because this skill links to it:
42
50
 
43
51
  ```bash
44
52
  git clone https://github.com/takeaseatventure/sql-sentinel.git
45
53
  cd sql-sentinel
54
+ git checkout <reviewed-commit-or-tag>
46
55
  node scripts/sql-sentinel.js path/to/query.sql
47
56
  ```
48
57
 
@@ -30,5 +30,8 @@ Use this reference when building apps that connect to Weaviate and require exter
30
30
 
31
31
  ## Usage Notes
32
32
 
33
+ - Provider keys are not forwarded automatically. Set `WEAVIATE_PROVIDER_KEYS`
34
+ to a comma-separated allowlist, for example `OPENAI_API_KEY,COHERE_API_KEY`.
33
35
  - Set only the provider keys your collection configuration actually uses.
34
- - If multiple providers are configured, include all corresponding headers.
36
+ - If multiple providers are configured, include only those corresponding
37
+ headers.
@@ -3,8 +3,8 @@ Shared Weaviate connection utilities.
3
3
 
4
4
  This module handles:
5
5
  - Environment variable validation
6
- - API key to header mapping for all supported providers
7
- - Client connection with automatic header configuration
6
+ - Explicit API key to header mapping for selected providers
7
+ - Client connection with caller-controlled header configuration
8
8
 
9
9
  Usage in scripts:
10
10
  import sys
@@ -23,7 +23,11 @@ from weaviate.classes.init import Auth
23
23
  from weaviate.client import WeaviateClient
24
24
  from weaviate.classes.init import AdditionalConfig, Timeout
25
25
 
26
- # Canonical environment variable to Weaviate header mapping
26
+ # Canonical environment variable to Weaviate header mapping.
27
+ #
28
+ # These values are never forwarded implicitly. Set WEAVIATE_PROVIDER_KEYS to a
29
+ # comma-separated allowlist such as "OPENAI_API_KEY,COHERE_API_KEY" when a
30
+ # specific vectorizer/integration requires a provider key.
27
31
  API_KEY_MAP = {
28
32
  "ANTHROPIC_API_KEY": "X-Anthropic-Api-Key",
29
33
  "ANYSCALE_API_KEY": "X-Anyscale-Api-Key",
@@ -45,17 +49,37 @@ API_KEY_MAP = {
45
49
  }
46
50
 
47
51
 
52
+ def _selected_provider_keys() -> set[str]:
53
+ raw = os.environ.get("WEAVIATE_PROVIDER_KEYS", "").strip()
54
+ if not raw:
55
+ return set()
56
+
57
+ selected = {item.strip() for item in raw.split(",") if item.strip()}
58
+ unknown = sorted(selected - set(API_KEY_MAP))
59
+ if unknown:
60
+ print(
61
+ "Error: WEAVIATE_PROVIDER_KEYS contains unsupported key(s): "
62
+ + ", ".join(unknown),
63
+ file=sys.stderr,
64
+ )
65
+ sys.exit(1)
66
+ return selected
67
+
68
+
48
69
  def _collect_headers_and_providers() -> tuple[dict[str, str], list[str]]:
49
70
  """
50
- Scan env once to build Weaviate headers and detected key names.
71
+ Build Weaviate headers only for explicitly selected provider env vars.
51
72
 
52
73
  Returns:
53
74
  Tuple of (headers, detected_env_var_names)
54
75
  """
55
76
  headers: dict[str, str] = {}
56
77
  detected_providers: list[str] = []
78
+ selected = _selected_provider_keys()
57
79
 
58
80
  for env_var, header_name in API_KEY_MAP.items():
81
+ if env_var not in selected:
82
+ continue
59
83
  value = os.environ.get(env_var, "").strip()
60
84
  if not value:
61
85
  continue
@@ -97,13 +121,13 @@ def validate_env(require_weaviate: bool = True) -> tuple[str, str]:
97
121
 
98
122
  def get_headers() -> dict[str, str] | None:
99
123
  """
100
- Build headers dict from all available API keys in environment.
124
+ Build headers dict from the WEAVIATE_PROVIDER_KEYS allowlist.
101
125
 
102
- Scans environment for all known API key variables and builds
103
- the appropriate headers dict for Weaviate client connection.
126
+ Provider keys are sensitive and often unrelated to the current Weaviate
127
+ operation, so this helper never scans and forwards every matching key.
104
128
 
105
129
  Returns:
106
- Dict of headers if any API keys found, None otherwise
130
+ Dict of headers if selected API keys are present, None otherwise
107
131
  """
108
132
  headers, _ = _collect_headers_and_providers()
109
133
  return headers if headers else None
@@ -111,7 +135,7 @@ def get_headers() -> dict[str, str] | None:
111
135
 
112
136
  def get_detected_providers() -> list[str]:
113
137
  """
114
- Get list of detected API key environment variable names.
138
+ Get list of selected API key environment variable names that are present.
115
139
 
116
140
  Returns:
117
141
  List of env var names (e.g., ["OPENAI_API_KEY", "COHERE_API_KEY"])
@@ -140,8 +164,8 @@ def get_client(
140
164
  """
141
165
  Context manager for Weaviate client connection.
142
166
 
143
- Auto-detects credentials from environment if not provided.
144
- Auto-builds headers from all available API keys if not provided.
167
+ Reads Weaviate credentials from environment if not provided.
168
+ Builds provider headers only from WEAVIATE_PROVIDER_KEYS when not provided.
145
169
 
146
170
  Args:
147
171
  url: Weaviate cluster URL (default: from WEAVIATE_URL env var)
@@ -74,23 +74,27 @@ def library_path(lib, *parts):
74
74
  def media_path(lib, filename):
75
75
  if not SAFE_MEDIA_RE.fullmatch(filename or ""):
76
76
  return None
77
- media_dir = library_path(lib, "_media")
78
- if not media_dir or not media_dir.is_dir():
77
+ root = Path(lib).resolve()
78
+ candidate = root / "_media" / filename
79
+ if candidate.is_symlink():
80
+ return None
81
+ path = library_path(lib, "_media", filename)
82
+ if not path or not path.is_file():
79
83
  return None
80
- for path in media_dir.iterdir():
81
- if path.is_file() and path.name == filename:
82
- return path
83
- return None
84
+ return path
84
85
 
85
86
 
86
87
  def item_path(lib, slug):
87
88
  if not SAFE_SLUG_RE.fullmatch(slug or ""):
88
89
  return None
89
- target = slug + ".md"
90
- for path in Path(lib).resolve().iterdir():
91
- if path.is_file() and path.name == target:
92
- return path
93
- return None
90
+ root = Path(lib).resolve()
91
+ candidate = root / (slug + ".md")
92
+ if candidate.is_symlink():
93
+ return None
94
+ path = library_path(lib, slug + ".md")
95
+ if not path or not path.is_file():
96
+ return None
97
+ return path
94
98
 
95
99
 
96
100
  def safe_content_type(ctype):
@@ -222,7 +226,12 @@ def self_test():
222
226
  (root / "video_1.md").write_text("---\ntitle: Demo\n---\nBody", encoding="utf-8")
223
227
  (root / "_media").mkdir()
224
228
  (root / "_media" / "video_1-slide-01.jpg").write_bytes(b"x")
229
+ (root / "secret.md").write_text("secret", encoding="utf-8")
230
+ (root / "linked.md").symlink_to(root / "secret.md")
231
+ (root / "_media" / "linked.jpg").symlink_to(root / "secret.md")
225
232
  assert load_item(str(root), "video_1")
233
+ assert load_item(str(root), "linked") is None
234
+ assert media_path(str(root), "linked.jpg") is None
226
235
  assert load_item(str(root), "../secret") is None
227
236
  assert library_path(str(root), "_media", "../video_1.md") is None
228
237
  assert safe_content_type("text/html; charset=utf-8") == "text/html; charset=utf-8"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-skills-collection",
3
- "version": "3.1.13",
3
+ "version": "3.1.14",
4
4
  "description": "OpenCode CLI plugin that automatically downloads and keeps skills up to date.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",