opencode-skills-collection 3.1.14 → 3.1.16

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 (164) hide show
  1. package/bundled-skills/.antigravity-install-manifest.json +36 -1
  2. package/bundled-skills/007/scripts/full_audit.py +34 -22
  3. package/bundled-skills/007/scripts/quick_scan.py +24 -15
  4. package/bundled-skills/007/scripts/scanners/dependency_scanner.py +31 -19
  5. package/bundled-skills/007/scripts/scanners/injection_scanner.py +24 -14
  6. package/bundled-skills/007/scripts/scanners/secrets_scanner.py +24 -14
  7. package/bundled-skills/007/scripts/score_calculator.py +25 -13
  8. package/bundled-skills/2slides-ppt-generator/scripts/download_slides_pages_voices.py +15 -1
  9. package/bundled-skills/aegisops-ai/SKILL.md +1 -1
  10. package/bundled-skills/agent-self-scheduling/SKILL.md +88 -0
  11. package/bundled-skills/alpha-vantage/SKILL.md +3 -1
  12. package/bundled-skills/anti-sleep/SKILL.md +90 -0
  13. package/bundled-skills/api-security-best-practices/SKILL.md +1 -1
  14. package/bundled-skills/app-store-optimization/SKILL.md +7 -0
  15. package/bundled-skills/audio-transcriber/scripts/transcribe.py +17 -4
  16. package/bundled-skills/azure-mgmt-botservice-py/SKILL.md +2 -1
  17. package/bundled-skills/azure-resource-manager-mysql-dotnet/SKILL.md +2 -1
  18. package/bundled-skills/azure-resource-manager-postgresql-dotnet/SKILL.md +2 -1
  19. package/bundled-skills/azure-resource-manager-sql-dotnet/SKILL.md +2 -1
  20. package/bundled-skills/biopython/SKILL.md +2 -1
  21. package/bundled-skills/brain-to-docs/SKILL.md +54 -0
  22. package/bundled-skills/browser-harness/SKILL.md +220 -0
  23. package/bundled-skills/browser-harness/references/install.md +132 -0
  24. package/bundled-skills/bumblebee/scripts/render_report.py +16 -3
  25. package/bundled-skills/bun-development/SKILL.md +1 -1
  26. package/bundled-skills/cc-skill-security-review/SKILL.md +2 -2
  27. package/bundled-skills/claude-monitor/scripts/monitor.py +15 -2
  28. package/bundled-skills/cmux/SKILL.md +250 -0
  29. package/bundled-skills/code-polish/SKILL.md +192 -0
  30. package/bundled-skills/code-review-checklist/SKILL.md +1 -1
  31. package/bundled-skills/codex-subagent/SKILL.md +117 -0
  32. package/bundled-skills/competitor-analysis/scripts/capture_screenshots.mjs +24 -3
  33. package/bundled-skills/competitor-analysis/scripts/compile_report.mjs +13 -2
  34. package/bundled-skills/competitor-analysis/scripts/extract_vs_names.mjs +23 -2
  35. package/bundled-skills/competitor-analysis/scripts/gate_candidates.mjs +21 -0
  36. package/bundled-skills/competitor-analysis/scripts/list_urls.mjs +23 -2
  37. package/bundled-skills/competitor-analysis/scripts/merge_partials.mjs +24 -3
  38. package/bundled-skills/container-security-hardening/SKILL.md +1 -1
  39. package/bundled-skills/content-creator/scripts/brand_voice_analyzer.py +15 -1
  40. package/bundled-skills/content-creator/scripts/seo_optimizer.py +15 -1
  41. package/bundled-skills/context-kit/SKILL.md +135 -0
  42. package/bundled-skills/cyber-audit/SKILL.md +138 -0
  43. package/bundled-skills/deepapi/SKILL.md +649 -0
  44. package/bundled-skills/delegating-to-agents/SKILL.md +64 -0
  45. package/bundled-skills/developer-signup-flow/SKILL.md +1 -1
  46. package/bundled-skills/diary/scripts/fetch_diaries.py +14 -1
  47. package/bundled-skills/diary/scripts/prepare_context.py +15 -2
  48. package/bundled-skills/diary/scripts/sync_to_notion.py +14 -1
  49. package/bundled-skills/dispatch/SKILL.md +19 -7
  50. package/bundled-skills/distribute-skill-to-all-agents/SKILL.md +85 -0
  51. package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
  52. package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
  53. package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
  54. package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
  55. package/bundled-skills/docs/users/bundles.md +1 -1
  56. package/bundled-skills/docs/users/claude-code-skills.md +1 -1
  57. package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
  58. package/bundled-skills/docs/users/getting-started.md +1 -1
  59. package/bundled-skills/docs/users/kiro-integration.md +1 -1
  60. package/bundled-skills/docs/users/usage.md +4 -4
  61. package/bundled-skills/docs/users/visual-guide.md +4 -4
  62. package/bundled-skills/docx-official/ooxml/scripts/pack.py +30 -3
  63. package/bundled-skills/docx-official/ooxml/scripts/unpack.py +16 -3
  64. package/bundled-skills/drizzle-migration-conflict/scripts/check_drizzle_migrations.py +27 -17
  65. package/bundled-skills/ecl-harness-engineer/agents/creator-config.md +17 -3
  66. package/bundled-skills/ecl-harness-engineer/references/environment-detection-guide.md +9 -5
  67. package/bundled-skills/effective-agent-skills/SKILL.md +333 -0
  68. package/bundled-skills/electron-development/SKILL.md +6 -2
  69. package/bundled-skills/environment-setup-guide/SKILL.md +2 -5
  70. package/bundled-skills/expo-ui/scripts/list-components.js +5 -1
  71. package/bundled-skills/fable-safe-prompt/SKILL.md +79 -0
  72. package/bundled-skills/folder-specific-claude-and-agents-md/SKILL.md +96 -0
  73. package/bundled-skills/frontend-slides/scripts/extract-pptx.py +18 -4
  74. package/bundled-skills/gcp-cloud-run/SKILL.md +2 -1
  75. package/bundled-skills/gemini-api-integration/SKILL.md +3 -1
  76. package/bundled-skills/gemini-live-api-dev/SKILL.md +2 -1
  77. package/bundled-skills/gemini-omni-flash-api/scripts/video/generate_video.py +49 -14
  78. package/bundled-skills/goal-loop/SKILL.md +175 -0
  79. package/bundled-skills/hugging-face-evaluation/SKILL.md +1 -1
  80. package/bundled-skills/hugging-face-jobs/SKILL.md +1 -1
  81. package/bundled-skills/hugging-face-jobs/scripts/finepdfs-stats.py +14 -1
  82. package/bundled-skills/hugging-face-model-trainer/scripts/convert_to_gguf.py +10 -1
  83. package/bundled-skills/hugo-to-markdown/scripts/inventory_hugo_rules.py +14 -1
  84. package/bundled-skills/image-generator/SKILL.md +3 -1
  85. package/bundled-skills/instagram/scripts/export.py +18 -7
  86. package/bundled-skills/interview-style-doc-building/SKILL.md +86 -0
  87. package/bundled-skills/junta-leiloeiros/scripts/export.py +19 -10
  88. package/bundled-skills/landing-page-generator/scripts/landing_page_scaffolder.py +15 -1
  89. package/bundled-skills/linear-claude-skill/SKILL.md +4 -2
  90. package/bundled-skills/linkedin-post-writer/SKILL.md +159 -0
  91. package/bundled-skills/linkedin-post-writer/references/hook-formulas.md +482 -0
  92. package/bundled-skills/llm-council/SKILL.md +4 -2
  93. package/bundled-skills/loki-mode/examples/todo-app-generated/backend/package-lock.json +5 -6
  94. package/bundled-skills/loki-mode/examples/todo-app-generated/backend/package.json +2 -3
  95. package/bundled-skills/markdown-rendering/SKILL.md +72 -0
  96. package/bundled-skills/matematico-tao/scripts/complexity_analyzer.py +14 -1
  97. package/bundled-skills/matematico-tao/scripts/dependency_graph.py +15 -2
  98. package/bundled-skills/mobile-design/scripts/mobile_audit.py +20 -6
  99. package/bundled-skills/monte-carlo-validation-notebook/scripts/resolve_dbt_schema.py +15 -2
  100. package/bundled-skills/multi-agent-architect/SKILL.md +1 -1
  101. package/bundled-skills/odoo-rpc-api/SKILL.md +2 -1
  102. package/bundled-skills/pci-compliance/SKILL.md +3 -1
  103. package/bundled-skills/pdf-official/scripts/create_validation_image.py +17 -3
  104. package/bundled-skills/pdf-official/scripts/extract_form_field_info.py +1 -1
  105. package/bundled-skills/personal-tool-builder/SKILL.md +1 -1
  106. package/bundled-skills/pi-custom-model/SKILL.md +68 -0
  107. package/bundled-skills/pi-web-search/SKILL.md +74 -0
  108. package/bundled-skills/playwright-skill/run.js +19 -1
  109. package/bundled-skills/pptx-official/ooxml/scripts/pack.py +30 -3
  110. package/bundled-skills/pptx-official/ooxml/scripts/unpack.py +16 -3
  111. package/bundled-skills/pptx-official/scripts/inventory.py +17 -4
  112. package/bundled-skills/pptx-official/scripts/rearrange.py +15 -2
  113. package/bundled-skills/pptx-official/scripts/replace.py +16 -3
  114. package/bundled-skills/product-manager-toolkit/scripts/customer_interview_analyzer.py +15 -1
  115. package/bundled-skills/production-code-audit/SKILL.md +1 -1
  116. package/bundled-skills/push-skill-to-github/SKILL.md +61 -0
  117. package/bundled-skills/rclone-cli/references/commands/rclone_completion_powershell.md +3 -2
  118. package/bundled-skills/read-all-adrs/SKILL.md +35 -0
  119. package/bundled-skills/remote-gpu-trainer/scripts/verify_local.py +14 -1
  120. package/bundled-skills/research-prompt/SKILL.md +63 -0
  121. package/bundled-skills/run-deep-swe/SKILL.md +120 -0
  122. package/bundled-skills/senior-architect/scripts/architecture_diagram_generator.py +15 -2
  123. package/bundled-skills/senior-architect/scripts/dependency_analyzer.py +15 -2
  124. package/bundled-skills/senior-architect/scripts/project_architect.py +15 -2
  125. package/bundled-skills/senior-frontend/scripts/bundle_analyzer.py +14 -1
  126. package/bundled-skills/senior-frontend/scripts/frontend_scaffolder.py +14 -1
  127. package/bundled-skills/senior-fullstack/scripts/code_quality_analyzer.py +15 -2
  128. package/bundled-skills/senior-fullstack/scripts/fullstack_scaffolder.py +15 -2
  129. package/bundled-skills/senior-fullstack/scripts/project_scaffolder.py +15 -2
  130. package/bundled-skills/setup-help/SKILL.md +50 -0
  131. package/bundled-skills/shodan-reconnaissance/SKILL.md +2 -1
  132. package/bundled-skills/short/SKILL.md +28 -0
  133. package/bundled-skills/skill-creator/scripts/init_skill.py +15 -2
  134. package/bundled-skills/skill-creator/scripts/package_skill.py +29 -12
  135. package/bundled-skills/skill-creator/scripts/quick_validate.py +14 -2
  136. package/bundled-skills/skill-creator-ms/SKILL.md +1 -1
  137. package/bundled-skills/skill-installer/scripts/install_skill.py +42 -8
  138. package/bundled-skills/skill-installer/scripts/package_skill.py +29 -17
  139. package/bundled-skills/skill-installer/scripts/validate_skill.py +37 -22
  140. package/bundled-skills/stripe-integration/SKILL.md +7 -3
  141. package/bundled-skills/swiftui-expert-skill/scripts/instruments_parser/xctrace.py +7 -1
  142. package/bundled-skills/swiftui-expert-skill/scripts/instruments_parser/xml_utils.py +7 -1
  143. package/bundled-skills/taisly-social-media-posting/SKILL.md +79 -0
  144. package/bundled-skills/technical-tutorials/SKILL.md +1 -1
  145. package/bundled-skills/telegram/scripts/setup_project.py +17 -2
  146. package/bundled-skills/time-ledger/SKILL.md +118 -0
  147. package/bundled-skills/trading-ledger/SKILL.md +121 -0
  148. package/bundled-skills/videodb/scripts/ws_listener.py +17 -4
  149. package/bundled-skills/voice-ai-development/SKILL.md +2 -1
  150. package/bundled-skills/vps-server-management/SKILL.md +72 -0
  151. package/bundled-skills/weaviate/scripts/weaviate_conn.py +20 -18
  152. package/bundled-skills/wgm/SKILL.md +137 -0
  153. package/bundled-skills/whatsapp-cloud-api/scripts/setup_project.py +16 -1
  154. package/bundled-skills/workorai/SKILL.md +137 -0
  155. package/bundled-skills/wp-site-health-auditor/SKILL.md +341 -0
  156. package/bundled-skills/wp-site-health-auditor/references/catalog.md +135 -0
  157. package/bundled-skills/writing-skills/render-graphs.js +13 -2
  158. package/bundled-skills/x-twitter-scraper/SKILL.md +3 -1
  159. package/bundled-skills/youtube-notetaker/scripts/serve.py +41 -31
  160. package/bundled-skills/youtube-notetaker/scripts/vtt_to_transcript.py +16 -2
  161. package/bundled-skills/youtube-notetaker/scripts/write_library_item.py +15 -1
  162. package/bundled-skills/youtube-transcript/SKILL.md +120 -0
  163. package/package.json +5 -1
  164. package/skills_index.json +786 -6
@@ -437,8 +437,9 @@ shodan search 'ssl.cert.issuer.cn:self-signed'
437
437
  #!/usr/bin/env python3
438
438
  import shodan
439
439
  import json
440
+ import os
440
441
 
441
- API_KEY = 'YOUR_API_KEY'
442
+ API_KEY = os.environ["SHODAN_API_KEY"]
442
443
  api = shodan.Shodan(API_KEY)
443
444
 
444
445
  def recon_organization(org_name):
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: short
3
+ description: "Rewrite the previous response more briefly while preserving the substance."
4
+ category: writing
5
+ risk: safe
6
+ source: community
7
+ source_repo: davidondrej/skills
8
+ source_type: community
9
+ date_added: "2026-07-07"
10
+ author: davidondrej
11
+ tags: [writing, editing, concise]
12
+ tools: [claude, codex]
13
+ license: "MIT"
14
+ license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
15
+ disable-model-invocation: true
16
+ ---
17
+
18
+ rewrite your last response to be simpler & shorter. do not do anything else.
19
+
20
+ ## When to Use
21
+
22
+ - Use when the user asks for a shorter, simpler, or TLDR version of the previous response.
23
+ - Use when the current answer should be compressed without changing the substance.
24
+
25
+ ## Limitations
26
+
27
+ - Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
28
+ - For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -15,6 +15,19 @@ import sys
15
15
  from pathlib import Path
16
16
 
17
17
 
18
+ def safe_user_path(path_value, base_dir="."):
19
+ """Resolve a CLI path under the current workspace."""
20
+ if base_dir != ".":
21
+ raise ValueError("Custom base directories are not supported for CLI paths")
22
+ base_path = Path.cwd().resolve()
23
+ resolved_path = Path(path_value).expanduser().resolve()
24
+ try:
25
+ resolved_path.relative_to(base_path)
26
+ except ValueError as exc:
27
+ raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
28
+ return resolved_path
29
+
30
+
18
31
  SKILL_TEMPLATE = """---
19
32
  name: {skill_name}
20
33
  description: [TODO: Complete and informative explanation of what the skill does and when to use it. Include WHEN to use this skill - specific scenarios, file types, or tasks that trigger it.]
@@ -203,7 +216,7 @@ def init_skill(skill_name, path):
203
216
  Path to created skill directory, or None if error
204
217
  """
205
218
  # Determine skill directory path
206
- skill_dir = Path(path).resolve() / skill_name
219
+ skill_dir = safe_user_path(path).resolve() / skill_name
207
220
 
208
221
  # Check if directory already exists
209
222
  if skill_dir.exists():
@@ -285,7 +298,7 @@ def main():
285
298
  sys.exit(1)
286
299
 
287
300
  skill_name = sys.argv[1]
288
- path = sys.argv[3]
301
+ path = safe_user_path(sys.argv[3])
289
302
 
290
303
  print(f"🚀 Initializing skill: {skill_name}")
291
304
  print(f" Location: {path}")
@@ -12,7 +12,21 @@ Example:
12
12
 
13
13
  import sys
14
14
  import zipfile
15
+ import tempfile
15
16
  from pathlib import Path
17
+
18
+
19
+ def safe_user_path(path_value, base_dir="."):
20
+ """Resolve a CLI path under the current workspace."""
21
+ if base_dir != ".":
22
+ raise ValueError("Custom base directories are not supported for CLI paths")
23
+ base_path = Path.cwd().resolve()
24
+ resolved_path = Path(path_value).expanduser().resolve()
25
+ try:
26
+ resolved_path.relative_to(base_path)
27
+ except ValueError as exc:
28
+ raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
29
+ return resolved_path
16
30
  from quick_validate import validate_skill
17
31
 
18
32
 
@@ -37,7 +51,7 @@ def package_skill(skill_path, output_dir=None):
37
51
  Returns:
38
52
  Path to the created .skill file, or None if error
39
53
  """
40
- skill_path = Path(skill_path).resolve()
54
+ skill_path = safe_user_path(skill_path).resolve()
41
55
 
42
56
  # Validate skill folder exists
43
57
  if not skill_path.exists():
@@ -66,7 +80,7 @@ def package_skill(skill_path, output_dir=None):
66
80
  # Determine output location
67
81
  skill_name = skill_path.name
68
82
  if output_dir:
69
- output_path = Path(output_dir).resolve()
83
+ output_path = safe_user_path(output_dir).resolve()
70
84
  output_path.mkdir(parents=True, exist_ok=True)
71
85
  else:
72
86
  output_path = Path.cwd()
@@ -75,14 +89,17 @@ def package_skill(skill_path, output_dir=None):
75
89
 
76
90
  # Create the .skill file (zip format)
77
91
  try:
78
- with zipfile.ZipFile(skill_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
79
- # Walk through the skill directory
80
- for file_path in skill_path.rglob('*'):
81
- if should_include(file_path, skill_path):
82
- # Calculate the relative path within the zip
83
- arcname = file_path.relative_to(skill_path.parent)
84
- zipf.write(file_path, arcname)
85
- print(f" Added: {arcname}")
92
+ with tempfile.TemporaryDirectory() as temp_dir:
93
+ temp_zip_path = Path(temp_dir) / "skill.zip"
94
+ with zipfile.ZipFile(temp_zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
95
+ # Walk through the skill directory
96
+ for file_path in skill_path.rglob('*'):
97
+ if should_include(file_path, skill_path):
98
+ # Calculate the relative path within the zip
99
+ arcname = file_path.relative_to(skill_path.parent)
100
+ zipf.write(file_path, arcname)
101
+ print(f" Added: {arcname}")
102
+ skill_filename.write_bytes(temp_zip_path.read_bytes())
86
103
 
87
104
  print(f"\n✅ Successfully packaged skill to: {skill_filename}")
88
105
  return skill_filename
@@ -100,8 +117,8 @@ def main():
100
117
  print(" python utils/package_skill.py skills/public/my-skill ./dist")
101
118
  sys.exit(1)
102
119
 
103
- skill_path = sys.argv[1]
104
- output_dir = sys.argv[2] if len(sys.argv) > 2 else None
120
+ skill_path = safe_user_path(sys.argv[1])
121
+ output_dir = safe_user_path(sys.argv[2]) if len(sys.argv) > 2 else None
105
122
 
106
123
  print(f"📦 Packaging skill: {skill_path}")
107
124
  if output_dir:
@@ -9,9 +9,21 @@ import re
9
9
  import yaml
10
10
  from pathlib import Path
11
11
 
12
+ def safe_user_path(path_value, base_dir="."):
13
+ """Resolve a CLI path under the current workspace."""
14
+ if base_dir != ".":
15
+ raise ValueError("Custom base directories are not supported for CLI paths")
16
+ base_path = Path.cwd().resolve()
17
+ resolved_path = Path(path_value).expanduser().resolve()
18
+ try:
19
+ resolved_path.relative_to(base_path)
20
+ except ValueError as exc:
21
+ raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
22
+ return resolved_path
23
+
12
24
  def validate_skill(skill_path):
13
25
  """Basic validation of a skill"""
14
- skill_path = Path(skill_path)
26
+ skill_path = safe_user_path(skill_path)
15
27
 
16
28
  # Check SKILL.md exists
17
29
  skill_md = skill_path / 'SKILL.md'
@@ -92,4 +104,4 @@ if __name__ == "__main__":
92
104
 
93
105
  valid, message = validate_skill(sys.argv[1])
94
106
  print(message)
95
- sys.exit(0 if valid else 1)
107
+ sys.exit(0 if valid else 1)
@@ -412,7 +412,7 @@ client = MyClient(endpoint, credential)
412
412
 
413
413
  #### ❌ INCORRECT: Hardcoded Credentials
414
414
  \`\`\`python
415
- client = MyClient(endpoint, api_key="hardcoded") # Security risk
415
+ client = MyClient(endpoint, credential="[redacted API key]") # Security risk
416
416
  \`\`\`
417
417
  ```
418
418
 
@@ -33,6 +33,40 @@ import re
33
33
  from pathlib import Path
34
34
  from datetime import datetime
35
35
 
36
+
37
+ def safe_user_path(path_value, base_dir="."):
38
+ """Resolve a CLI path under the current workspace."""
39
+ if base_dir != ".":
40
+ raise ValueError("Custom base directories are not supported for CLI paths")
41
+ base_path = Path.cwd().resolve()
42
+ resolved_path = Path(path_value).expanduser().resolve()
43
+ try:
44
+ resolved_path.relative_to(base_path)
45
+ except ValueError as exc:
46
+ raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
47
+ return resolved_path
48
+
49
+
50
+ def copy_tree_contents(source_dir: Path, target_dir: Path, *, ignore=None) -> None:
51
+ target_dir.mkdir(parents=True, exist_ok=True)
52
+
53
+ for current_dir, dirs, files in os.walk(source_dir, followlinks=False):
54
+ current_path = Path(current_dir)
55
+ ignored_names = set(ignore(str(current_path), dirs + files)) if ignore is not None else set()
56
+ dirs[:] = [directory for directory in dirs if directory not in ignored_names]
57
+
58
+ relative_dir = current_path.relative_to(source_dir)
59
+ target_current_dir = target_dir / relative_dir
60
+ target_current_dir.mkdir(parents=True, exist_ok=True)
61
+
62
+ for file_name in files:
63
+ if file_name in ignored_names:
64
+ continue
65
+ source_path = current_path / file_name
66
+ if not source_path.is_file():
67
+ continue
68
+ (target_current_dir / file_name).write_bytes(source_path.read_bytes())
69
+
36
70
  # Add scripts directory to path for imports
37
71
  SCRIPT_DIR = Path(__file__).parent.resolve()
38
72
  sys.path.insert(0, str(SCRIPT_DIR))
@@ -147,7 +181,7 @@ def safe_skill_path(root: Path, skill_name: str) -> Path:
147
181
 
148
182
  def resolve_skill_source(source: str) -> Path:
149
183
  """Resolve and validate a local skill source directory."""
150
- source_path = Path(source).expanduser().resolve()
184
+ source_path = safe_user_path(source).expanduser().resolve()
151
185
  if not source_path.is_dir():
152
186
  raise ValueError(f"Source does not exist or is not a directory: {source_path}")
153
187
  if not (source_path / "SKILL.md").is_file():
@@ -164,7 +198,7 @@ def md5_dir(path: Path, exclude_dirs: set = None) -> str:
164
198
  if exclude_dirs is None:
165
199
  exclude_dirs = {"backups", "staging", ".git", "__pycache__", "node_modules", ".venv"}
166
200
 
167
- root_path = Path(path).resolve(strict=True)
201
+ root_path = safe_user_path(path).resolve(strict=True)
168
202
  if not root_path.is_dir():
169
203
  raise ValueError(f"Hash target must be a directory: {root_path}")
170
204
 
@@ -173,7 +207,7 @@ def md5_dir(path: Path, exclude_dirs: set = None) -> str:
173
207
  # Filter out excluded directories
174
208
  dirs[:] = [d for d in dirs if d not in exclude_dirs]
175
209
  for f in sorted(files):
176
- fp = Path(root) / f
210
+ fp = safe_user_path(root) / f
177
211
  try:
178
212
  resolved_fp = fp.resolve(strict=True)
179
213
  resolved_fp.relative_to(root_path)
@@ -370,7 +404,7 @@ def step4_check_conflicts(skill_name: str) -> dict:
370
404
  def _backup_ignore(directory, contents):
371
405
  """Ignore function for shutil.copytree to skip backup/staging dirs."""
372
406
  ignored = set()
373
- dir_path = Path(directory)
407
+ dir_path = safe_user_path(directory)
374
408
  for item in contents:
375
409
  item_path = dir_path / item
376
410
  if item_path.is_symlink():
@@ -436,7 +470,7 @@ def step6_copy_to_skills_root(source_path: Path, skill_name: str) -> dict:
436
470
 
437
471
  # Copy to staging first (skip backups/staging to prevent recursion)
438
472
  try:
439
- shutil.copytree(source_path, staging, ignore=_backup_ignore, dirs_exist_ok=True)
473
+ copy_tree_contents(source_path, staging, ignore=_backup_ignore)
440
474
  except Exception as e:
441
475
  return {"success": False, "error": f"Copy to staging failed: {e}"}
442
476
 
@@ -470,7 +504,7 @@ def step6_copy_to_skills_root(source_path: Path, skill_name: str) -> dict:
470
504
  except Exception as e:
471
505
  # Try copy + delete as fallback (cross-device moves)
472
506
  try:
473
- shutil.copytree(staging, dest, dirs_exist_ok=True)
507
+ copy_tree_contents(staging, dest)
474
508
  shutil.rmtree(staging, ignore_errors=True)
475
509
  except Exception as e2:
476
510
  shutil.rmtree(staging, ignore_errors=True)
@@ -496,7 +530,7 @@ def step7_register_claude(skill_name: str) -> dict:
496
530
 
497
531
  # Copy SKILL.md
498
532
  try:
499
- shutil.copy2(source_skill_md, claude_dest_dir / "SKILL.md")
533
+ (claude_dest_dir / "SKILL.md").write_bytes(source_skill_md.read_bytes())
500
534
  except Exception as e:
501
535
  return {"success": False, "error": f"Failed to copy SKILL.md to Claude skills: {e}"}
502
536
 
@@ -507,7 +541,7 @@ def step7_register_claude(skill_name: str) -> dict:
507
541
  try:
508
542
  if claude_refs.exists():
509
543
  shutil.rmtree(claude_refs)
510
- shutil.copytree(refs_dir, claude_refs)
544
+ copy_tree_contents(refs_dir, claude_refs)
511
545
  except Exception:
512
546
  pass # Non-critical
513
547
 
@@ -23,8 +23,22 @@ import sys
23
23
  import json
24
24
  import re
25
25
  import zipfile
26
+ import tempfile
26
27
  from pathlib import Path
27
28
 
29
+
30
+ def safe_user_path(path_value, base_dir="."):
31
+ """Resolve a CLI path under the current workspace."""
32
+ if base_dir != ".":
33
+ raise ValueError("Custom base directories are not supported for CLI paths")
34
+ base_path = Path.cwd().resolve()
35
+ resolved_path = Path(path_value).expanduser().resolve()
36
+ try:
37
+ resolved_path.relative_to(base_path)
38
+ except ValueError as exc:
39
+ raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
40
+ return resolved_path
41
+
28
42
  # ── Configuration ──────────────────────────────────────────────────────────
29
43
 
30
44
  SKILLS_ROOT = Path(r"C:\Users\renat\skills")
@@ -51,7 +65,7 @@ SAFE_ARCHIVE_NAME_RE = re.compile(r"^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$")
51
65
 
52
66
  def resolve_existing_dir(path) -> Path:
53
67
  """Resolve a user-provided directory and require it to exist."""
54
- resolved = Path(path).expanduser().resolve()
68
+ resolved = safe_user_path(path).expanduser().resolve()
55
69
  if not resolved.is_dir():
56
70
  raise ValueError(f"Directory not found: {resolved}")
57
71
  return resolved
@@ -59,7 +73,7 @@ def resolve_existing_dir(path) -> Path:
59
73
 
60
74
  def resolve_output_dir(path) -> Path:
61
75
  """Resolve a user-provided output directory."""
62
- resolved = Path(path).expanduser().resolve()
76
+ resolved = safe_user_path(path).expanduser().resolve()
63
77
  if resolved.exists() and not resolved.is_dir():
64
78
  raise ValueError(f"Output path is not a directory: {resolved}")
65
79
  return resolved
@@ -218,14 +232,9 @@ def package_skill(skill_dir: Path, output_dir: Path = None) -> dict:
218
232
 
219
233
  # Collect files
220
234
  files_to_include = []
221
- for root, dirs, files in os.walk(skill_dir):
222
- # Filter directories in-place to skip excluded ones
223
- dirs[:] = [d for d in dirs if d not in EXCLUDE_DIRS]
224
-
225
- for f in files:
226
- fp = Path(root) / f
227
- if should_include(fp, skill_dir):
228
- files_to_include.append(fp)
235
+ for fp in safe_user_path(skill_dir).rglob("*"):
236
+ if fp.is_file() and should_include(fp, skill_dir):
237
+ files_to_include.append(fp)
229
238
 
230
239
  if not files_to_include:
231
240
  return {"success": False, "error": "No files to package"}
@@ -233,13 +242,16 @@ def package_skill(skill_dir: Path, output_dir: Path = None) -> dict:
233
242
  # Create ZIP with skill folder as root
234
243
  # CRITICAL: ZIP paths MUST use forward slashes, not Windows backslashes
235
244
  try:
236
- with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
237
- for fp in sorted(files_to_include):
238
- rel_path = fp.relative_to(skill_dir)
239
- # Convert Windows backslash to forward slash for ZIP compatibility
240
- rel_posix = rel_path.as_posix()
241
- archive_path = f"{skill_name_lower}/{rel_posix}"
242
- zf.write(fp, archive_path)
245
+ with tempfile.TemporaryDirectory() as temp_dir:
246
+ temp_zip_path = Path(temp_dir) / "skill.zip"
247
+ with zipfile.ZipFile(temp_zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
248
+ for fp in sorted(files_to_include):
249
+ rel_path = fp.relative_to(skill_dir)
250
+ # Convert Windows backslash to forward slash for ZIP compatibility
251
+ rel_posix = rel_path.as_posix()
252
+ archive_path = f"{skill_name_lower}/{rel_posix}"
253
+ zf.write(fp, archive_path)
254
+ zip_path.write_bytes(temp_zip_path.read_bytes())
243
255
 
244
256
  # Verify ZIP is not empty and valid
245
257
  with zipfile.ZipFile(zip_path, "r") as zf_check:
@@ -17,6 +17,19 @@ import json
17
17
  import re
18
18
  from pathlib import Path
19
19
 
20
+
21
+ def safe_user_path(path_value, base_dir="."):
22
+ """Resolve a CLI path under the current workspace."""
23
+ if base_dir != ".":
24
+ raise ValueError("Custom base directories are not supported for CLI paths")
25
+ base_path = Path.cwd().resolve()
26
+ resolved_path = Path(path_value).expanduser().resolve()
27
+ try:
28
+ resolved_path.relative_to(base_path)
29
+ except ValueError as exc:
30
+ raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
31
+ return resolved_path
32
+
20
33
  # ── Constants ──────────────────────────────────────────────────────────────
21
34
 
22
35
  FORBIDDEN_PATTERNS = [
@@ -43,7 +56,7 @@ REGISTRY_PATH = SKILLS_ROOT / "agent-orchestrator" / "data" / "registry.json"
43
56
 
44
57
  def resolve_existing_dir(path) -> Path:
45
58
  """Resolve a user-provided directory and require it to exist."""
46
- resolved = Path(path).expanduser().resolve()
59
+ resolved = safe_user_path(path).expanduser().resolve()
47
60
  if not resolved.is_dir():
48
61
  raise ValueError(f"Directory does not exist: {resolved}")
49
62
  return resolved
@@ -222,19 +235,20 @@ def check_forbidden_files(skill_dir: Path) -> dict:
222
235
  """Check 7: No forbidden files (.env, credentials, keys, etc.)."""
223
236
  found_forbidden = []
224
237
 
225
- for root, _dirs, files in os.walk(skill_dir):
226
- for f in files:
227
- f_lower = f.lower()
228
- for pattern in FORBIDDEN_PATTERNS:
229
- if pattern.startswith("*."):
230
- ext = pattern[1:] # e.g., ".key"
231
- if f_lower.endswith(ext):
232
- found_forbidden.append(os.path.join(root, f))
233
- break
234
- else:
235
- if f_lower == pattern.lower():
236
- found_forbidden.append(os.path.join(root, f))
237
- break
238
+ for path in safe_user_path(skill_dir).rglob("*"):
239
+ if not path.is_file():
240
+ continue
241
+ f_lower = path.name.lower()
242
+ for pattern in FORBIDDEN_PATTERNS:
243
+ if pattern.startswith("*."):
244
+ ext = pattern[1:] # e.g., ".key"
245
+ if f_lower.endswith(ext):
246
+ found_forbidden.append(str(path))
247
+ break
248
+ else:
249
+ if f_lower == pattern.lower():
250
+ found_forbidden.append(str(path))
251
+ break
238
252
 
239
253
  if found_forbidden:
240
254
  return {
@@ -255,12 +269,13 @@ def check_forbidden_files(skill_dir: Path) -> dict:
255
269
  def check_total_size(skill_dir: Path) -> dict:
256
270
  """Check 8: Total size is reasonable (warn if > 50MB)."""
257
271
  total = 0
258
- for root, _dirs, files in os.walk(skill_dir):
259
- for f in files:
260
- try:
261
- total += os.path.getsize(os.path.join(root, f))
262
- except OSError:
263
- pass
272
+ for path in safe_user_path(skill_dir).rglob("*"):
273
+ if not path.is_file():
274
+ continue
275
+ try:
276
+ total += path.stat().st_size
277
+ except OSError:
278
+ pass
264
279
 
265
280
  size_mb = total / (1024 * 1024)
266
281
  ok = size_mb <= MAX_SIZE_MB
@@ -360,7 +375,7 @@ def validate(skill_dir: Path, strict: bool = False, registry_path: Path = None)
360
375
  except ValueError as e:
361
376
  return {
362
377
  "valid": False,
363
- "skill_dir": str(Path(skill_dir).expanduser()),
378
+ "skill_dir": str(safe_user_path(skill_dir).expanduser()),
364
379
  "checks": [],
365
380
  "warnings": [],
366
381
  "errors": [str(e)],
@@ -433,7 +448,7 @@ def main():
433
448
  if "--registry" in sys.argv:
434
449
  idx = sys.argv.index("--registry")
435
450
  if idx + 1 < len(sys.argv):
436
- registry_path = Path(sys.argv[idx + 1]).expanduser().resolve()
451
+ registry_path = safe_user_path(sys.argv[idx + 1]).expanduser().resolve()
437
452
 
438
453
  result = validate(skill_dir, strict=strict, registry_path=registry_path)
439
454
  print(json.dumps(result, indent=2, ensure_ascii=False))
@@ -77,9 +77,10 @@ Master Stripe payment processing integration for robust, PCI-compliant payment f
77
77
  ## Quick Start
78
78
 
79
79
  ```python
80
+ import os
80
81
  import stripe
81
82
 
82
- stripe.api_key = "sk_test_..."
83
+ stripe.api_key = os.environ["STRIPE_SECRET_KEY"]
83
84
 
84
85
  # Create a checkout session
85
86
  session = stripe.checkout.Session.create(
@@ -222,12 +223,13 @@ def create_customer_portal_session(customer_id):
222
223
 
223
224
  ### Secure Webhook Endpoint
224
225
  ```python
226
+ import os
225
227
  from flask import Flask, request
226
228
  import stripe
227
229
 
228
230
  app = Flask(__name__)
229
231
 
230
- endpoint_secret = 'whsec_...'
232
+ endpoint_secret = os.environ["STRIPE_WEBHOOK_SECRET"]
231
233
 
232
234
  @app.route('/webhook', methods=['POST'])
233
235
  def webhook():
@@ -392,7 +394,9 @@ def handle_dispute(charge_id, evidence):
392
394
 
393
395
  ```python
394
396
  # Use test mode keys
395
- stripe.api_key = "sk_test_..."
397
+ import os
398
+
399
+ stripe.api_key = os.environ["STRIPE_SECRET_KEY"]
396
400
 
397
401
  # Test card numbers
398
402
  TEST_CARDS = {
@@ -2,10 +2,14 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  import subprocess
5
- import xml.etree.ElementTree as ET
6
5
  from dataclasses import dataclass
7
6
  from pathlib import Path
8
7
 
8
+ try:
9
+ from defusedxml import ElementTree as ET
10
+ except ImportError: # pragma: no cover - guidance for direct script use
11
+ ET = None
12
+
9
13
 
10
14
  @dataclass(frozen=True)
11
15
  class RunInfo:
@@ -43,6 +47,8 @@ def toc(trace_path: Path) -> TraceInfo:
43
47
 
44
48
  The TOC is small (a few KB) so we load it fully rather than streaming.
45
49
  """
50
+ if ET is None:
51
+ raise RuntimeError("Install defusedxml before parsing xctrace XML exports.")
46
52
  xml_bytes = _run_export(trace_path, ["--toc"])
47
53
  root = ET.fromstring(xml_bytes)
48
54
 
@@ -6,10 +6,14 @@ a global id cache for later ref lookups.
6
6
  """
7
7
  from __future__ import annotations
8
8
 
9
- import xml.etree.ElementTree as ET
10
9
  from collections.abc import Iterator
11
10
  from dataclasses import dataclass
12
11
 
12
+ try:
13
+ from defusedxml import ElementTree as ET
14
+ except ImportError: # pragma: no cover - guidance for direct script use
15
+ ET = None
16
+
13
17
 
14
18
  @dataclass(frozen=True)
15
19
  class Column:
@@ -26,6 +30,8 @@ class RowStream:
26
30
  """
27
31
 
28
32
  def __init__(self, xml_bytes: bytes):
33
+ if ET is None:
34
+ raise RuntimeError("Install defusedxml before parsing xctrace XML exports.")
29
35
  self._xml = xml_bytes
30
36
  self.columns: list[Column] = []
31
37
  self._id_cache: dict[str, ET.Element] = {}
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: taisly-social-media-posting
3
+ description: "Use Taisly Agent Kit to prepare and publish approved short-form video posts across TikTok, Instagram Reels, YouTube Shorts, X, and Facebook."
4
+ category: marketing
5
+ risk: critical
6
+ source: community
7
+ source_repo: taisly/agent
8
+ source_type: community
9
+ date_added: "2026-07-07"
10
+ author: taisly
11
+ tags: [social-media, video, publishing, mcp, cli, sdk, tiktok, instagram, youtube-shorts, x, facebook]
12
+ tools: [codex, claude]
13
+ license: "MIT"
14
+ license_source: "https://github.com/taisly/agent/blob/main/LICENSE"
15
+ ---
16
+
17
+ # Taisly Social Media Posting
18
+
19
+ ## Overview
20
+
21
+ Taisly Agent Kit provides an MCP server, CLI, SDK, and agent docs for publishing
22
+ approved short-form videos to TikTok, Instagram Reels, YouTube Shorts, X, and
23
+ Facebook. Use this skill to plan a posting workflow around Taisly, verify that
24
+ the user has the required account access, and keep publishing actions behind an
25
+ explicit confirmation gate.
26
+
27
+ ## When to Use
28
+
29
+ - Use when the user wants an agent-assisted workflow for publishing short-form
30
+ videos with Taisly.
31
+ - Use when the user mentions `taisly/agent`, the Taisly MCP server, Taisly CLI,
32
+ or the Taisly SDK.
33
+ - Use when coordinating final approval, caption metadata, target platforms, and
34
+ posting status for social video distribution.
35
+
36
+ ## Workflow
37
+
38
+ 1. Confirm the exact target platforms and video asset paths or URLs.
39
+ 2. Confirm that the user has already connected the relevant social accounts in
40
+ Taisly or has provided the intended MCP/CLI setup path.
41
+ 3. Draft or review captions, hashtags, titles, descriptions, and platform
42
+ metadata before any publishing command is run.
43
+ 4. Present a final posting summary with platforms, media, captions, visibility,
44
+ and timing.
45
+ 5. Wait for explicit user approval before invoking any Taisly command, MCP tool,
46
+ SDK call, or other state-changing publishing action.
47
+
48
+ ## Examples
49
+
50
+ ```text
51
+ Use Taisly to prepare this product demo for TikTok, Reels, Shorts, X, and Facebook.
52
+ Review the caption and metadata first; do not publish until I approve.
53
+ ```
54
+
55
+ ```text
56
+ Set up a Taisly MCP publishing workflow for approved video assets in ./campaign.
57
+ ```
58
+
59
+ ## Safety Notes
60
+
61
+ - Treat publish, schedule, delete, account-linking, and metadata update actions
62
+ as state-changing operations requiring explicit user approval.
63
+ - Never request, print, or store platform passwords, OAuth secrets, API keys, or
64
+ session tokens. Use the user's existing Taisly/MCP/CLI authentication flow.
65
+ - If the requested action could violate platform policies, brand review, legal
66
+ constraints, or creator permissions, pause and ask for confirmation.
67
+
68
+ ## Limitations
69
+
70
+ - Platform availability, media requirements, and API behavior depend on the
71
+ upstream Taisly Agent Kit and connected platform accounts.
72
+ - This skill does not replace human review for legal, brand, copyright, or
73
+ platform-compliance decisions.
74
+ - Verify the current Taisly setup instructions from `taisly/agent` before
75
+ installing or running tools in a new environment.
76
+
77
+ ## Source
78
+
79
+ - GitHub: [taisly/agent](https://github.com/taisly/agent)
@@ -379,7 +379,7 @@ export API_KEY=your_key
379
379
  set API_KEY=your_key
380
380
 
381
381
  # Windows PowerShell
382
- $env:API_KEY="your_key"
382
+ $env:API_KEY = Read-Host -AsSecureString "API key"
383
383
  \`\`\`
384
384
  ```
385
385