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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "updatedAt": "2026-07-03T01:46:50.032Z",
3
+ "updatedAt": "2026-07-07T07:43:09.313Z",
4
4
  "entries": [
5
5
  "00-andruia-consultant",
6
6
  "007",
@@ -38,6 +38,7 @@
38
38
  "agent-orchestration-improve-agent",
39
39
  "agent-orchestration-multi-agent-optimize",
40
40
  "agent-orchestrator",
41
+ "agent-self-scheduling",
41
42
  "agent-squad",
42
43
  "agent-squad/alex",
43
44
  "agent-squad/aria",
@@ -97,6 +98,7 @@
97
98
  "animejs-animation",
98
99
  "anti-deception",
99
100
  "anti-reversing-techniques",
101
+ "anti-sleep",
100
102
  "anti-sycophancy",
101
103
  "antigravity-agent-manager",
102
104
  "antigravity-design-expert",
@@ -335,6 +337,7 @@
335
337
  "blog-writing-guide",
336
338
  "blueprint",
337
339
  "box-automation",
340
+ "brain-to-docs",
338
341
  "brainstorming",
339
342
  "brand-guidelines",
340
343
  "brand-guidelines-anthropic",
@@ -352,6 +355,7 @@
352
355
  "brooks-test",
353
356
  "browser-automation",
354
357
  "browser-extension-builder",
358
+ "browser-harness",
355
359
  "browser-testing-with-devtools",
356
360
  "bug-hunt-swarm",
357
361
  "bug-hunter",
@@ -422,10 +426,12 @@
422
426
  "cloud-penetration-testing",
423
427
  "cloudflare-workers-expert",
424
428
  "cloudformation-best-practices",
429
+ "cmux",
425
430
  "co-marketing",
426
431
  "coda-automation",
427
432
  "code-documentation-code-explain",
428
433
  "code-documentation-doc-generate",
434
+ "code-polish",
429
435
  "code-refactoring-context-restore",
430
436
  "code-refactoring-refactor-clean",
431
437
  "code-refactoring-tech-debt",
@@ -448,6 +454,7 @@
448
454
  "codebase-to-wordpress-converter",
449
455
  "codex-fable5",
450
456
  "codex-review",
457
+ "codex-subagent",
451
458
  "cold-email",
452
459
  "comfyui-gateway",
453
460
  "commit",
@@ -484,6 +491,7 @@
484
491
  "context-engineering",
485
492
  "context-fundamentals",
486
493
  "context-guardian",
494
+ "context-kit",
487
495
  "context-management-context-restore",
488
496
  "context-management-context-save",
489
497
  "context-manager",
@@ -528,6 +536,7 @@
528
536
  "customer-support",
529
537
  "customs-trade-compliance",
530
538
  "cv-generator",
539
+ "cyber-audit",
531
540
  "cypress-skill",
532
541
  "daily",
533
542
  "daily-gift",
@@ -565,8 +574,10 @@
565
574
  "debugging-toolkit-smart-debug",
566
575
  "decision-navigator",
567
576
  "deep-research",
577
+ "deepapi",
568
578
  "defi-protocol-templates",
569
579
  "defuddle",
580
+ "delegating-to-agents",
570
581
  "dependency-management-deps-audit",
571
582
  "dependency-upgrade",
572
583
  "deploy-to-vercel",
@@ -656,6 +667,7 @@
656
667
  "discord-bot-architect",
657
668
  "dispatch",
658
669
  "dispatching-parallel-agents",
670
+ "distribute-skill-to-all-agents",
659
671
  "distributed-debugging-debug-trace",
660
672
  "distributed-tracing",
661
673
  "django-access-review",
@@ -690,6 +702,7 @@
690
702
  "earllm-build",
691
703
  "eas-update-insights",
692
704
  "ecl-harness-engineer",
705
+ "effective-agent-skills",
693
706
  "efficient-web-research",
694
707
  "ejentum-reasoning-harness",
695
708
  "electron-development",
@@ -737,6 +750,7 @@
737
750
  "expo-ui",
738
751
  "expo-ui-jetpack-compose",
739
752
  "expo-ui-swift-ui",
753
+ "fable-safe-prompt",
740
754
  "faf-context",
741
755
  "faf-expert",
742
756
  "faf-go",
@@ -773,6 +787,7 @@
773
787
  "fixing-motion-performance",
774
788
  "flowhunt-skill",
775
789
  "flutter-expert",
790
+ "folder-specific-claude-and-agents-md",
776
791
  "food-database-query",
777
792
  "form-cro",
778
793
  "formik-patterns",
@@ -868,6 +883,7 @@
868
883
  "go-playwright",
869
884
  "go-rod-master",
870
885
  "goal-analyzer",
886
+ "goal-loop",
871
887
  "godot-4-migration",
872
888
  "godot-gdscript-patterns",
873
889
  "golang-pro",
@@ -980,6 +996,7 @@
980
996
  "internal-comms-anthropic",
981
997
  "internal-comms-community",
982
998
  "interview-coach",
999
+ "interview-style-doc-building",
983
1000
  "invariant-guard",
984
1001
  "inventory-demand-planning",
985
1002
  "ios-debugger-agent",
@@ -1053,6 +1070,7 @@
1053
1070
  "linkedin-automation",
1054
1071
  "linkedin-cli",
1055
1072
  "linkedin-content-generator",
1073
+ "linkedin-post-writer",
1056
1074
  "linkedin-profile-optimizer",
1057
1075
  "linkerd-patterns",
1058
1076
  "lint-and-validate",
@@ -1119,6 +1137,7 @@
1119
1137
  "malware-analyst",
1120
1138
  "manage-skills",
1121
1139
  "manifest",
1140
+ "markdown-rendering",
1122
1141
  "market-sizing-analysis",
1123
1142
  "marketing-ideas",
1124
1143
  "marketing-plan",
@@ -1308,6 +1327,8 @@
1308
1327
  "phase-gated-debugging",
1309
1328
  "photopea-embedded-editor",
1310
1329
  "php-pro",
1330
+ "pi-custom-model",
1331
+ "pi-web-search",
1311
1332
  "pipecat-friday-agent",
1312
1333
  "pipedrive-automation",
1313
1334
  "pitch-psychologist",
@@ -1376,6 +1397,7 @@
1376
1397
  "public-relations",
1377
1398
  "pubmed-database",
1378
1399
  "puppeteer-skill",
1400
+ "push-skill-to-github",
1379
1401
  "puzzle-activity-planner",
1380
1402
  "pydantic-ai",
1381
1403
  "pydantic-models-py",
@@ -1411,6 +1433,7 @@
1411
1433
  "react-patterns",
1412
1434
  "react-state-management",
1413
1435
  "react-ui-patterns",
1436
+ "read-all-adrs",
1414
1437
  "readme",
1415
1438
  "recallmax",
1416
1439
  "receiving-code-review",
@@ -1430,6 +1453,7 @@
1430
1453
  "render-automation",
1431
1454
  "repo-maintainer",
1432
1455
  "requesting-code-review",
1456
+ "research-prompt",
1433
1457
  "resolving-merge-conflicts",
1434
1458
  "returns-reverse-logistics",
1435
1459
  "reverse-engineer",
@@ -1448,6 +1472,7 @@
1448
1472
  "robius-widget-patterns",
1449
1473
  "robot-framework-skill",
1450
1474
  "ruby-pro",
1475
+ "run-deep-swe",
1451
1476
  "runapi-cli",
1452
1477
  "runaway-guard",
1453
1478
  "rust-async-patterns",
@@ -1546,6 +1571,7 @@
1546
1571
  "server-management",
1547
1572
  "service-mesh-expert",
1548
1573
  "service-mesh-observability",
1574
+ "setup-help",
1549
1575
  "setup-matt-pocock-skills",
1550
1576
  "sexual-health-analyzer",
1551
1577
  "shadcn",
@@ -1558,6 +1584,7 @@
1558
1584
  "shopify-apps",
1559
1585
  "shopify-automation",
1560
1586
  "shopify-development",
1587
+ "short",
1561
1588
  "signup-flow-cro",
1562
1589
  "similarity-search-patterns",
1563
1590
  "simplify-code",
@@ -1668,6 +1695,7 @@
1668
1695
  "systems-programming-rust-project",
1669
1696
  "tailwind-design-system",
1670
1697
  "tailwind-patterns",
1698
+ "taisly-social-media-posting",
1671
1699
  "tanstack-query-expert",
1672
1700
  "task-intelligence",
1673
1701
  "tavily-web",
@@ -1721,6 +1749,7 @@
1721
1749
  "threejs-skills",
1722
1750
  "threejs-textures",
1723
1751
  "tiktok-automation",
1752
+ "time-ledger",
1724
1753
  "tmux",
1725
1754
  "to-issues",
1726
1755
  "to-prd",
@@ -1731,6 +1760,7 @@
1731
1760
  "tools-page-seo-optimizer",
1732
1761
  "top-web-vulnerabilities",
1733
1762
  "track-management",
1763
+ "trading-ledger",
1734
1764
  "train-sentence-transformers",
1735
1765
  "transformers-js",
1736
1766
  "travel-health-analyzer",
@@ -1822,6 +1852,7 @@
1822
1852
  "voice-agents",
1823
1853
  "voice-ai-development",
1824
1854
  "voice-ai-engine-development",
1855
+ "vps-server-management",
1825
1856
  "vscode-extension-guide-en",
1826
1857
  "vulnerability-scanner",
1827
1858
  "warren-buffett",
@@ -1842,6 +1873,7 @@
1842
1873
  "wechat-official-account-strategist",
1843
1874
  "weightloss-analyzer",
1844
1875
  "wellally-tech",
1876
+ "wgm",
1845
1877
  "whatsapp-automation",
1846
1878
  "whatsapp-cloud-api",
1847
1879
  "wiki-architect",
@@ -1866,6 +1898,8 @@
1866
1898
  "workflow-automation",
1867
1899
  "workflow-orchestration-patterns",
1868
1900
  "workflow-patterns",
1901
+ "workorai",
1902
+ "wp-site-health-auditor",
1869
1903
  "wrike-automation",
1870
1904
  "writing-great-skills",
1871
1905
  "writing-plans",
@@ -1889,6 +1923,7 @@
1889
1923
  "youtube-notetaker",
1890
1924
  "youtube-seo-optimizer",
1891
1925
  "youtube-summarizer",
1926
+ "youtube-transcript",
1892
1927
  "zapier-make-patterns",
1893
1928
  "zendesk-automation",
1894
1929
  "zeroize-audit",
@@ -27,6 +27,19 @@ import time
27
27
  from datetime import datetime, timezone
28
28
  from pathlib import Path
29
29
 
30
+
31
+ def safe_user_path(path_value, base_dir="."):
32
+ """Resolve a CLI path under the current workspace."""
33
+ if base_dir != ".":
34
+ raise ValueError("Custom base directories are not supported for CLI paths")
35
+ base_path = Path.cwd().resolve()
36
+ resolved_path = Path(path_value).expanduser().resolve()
37
+ try:
38
+ resolved_path.relative_to(base_path)
39
+ except ValueError as exc:
40
+ raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
41
+ return resolved_path
42
+
30
43
  # ---------------------------------------------------------------------------
31
44
  # Imports from the 007 config hub (same directory)
32
45
  # ---------------------------------------------------------------------------
@@ -397,31 +410,30 @@ def _phase1_surface_mapping(target: Path, verbose: bool = False) -> dict:
397
410
 
398
411
  _config_extensions = {".json", ".yaml", ".yml", ".toml", ".ini", ".cfg", ".conf", ".env"}
399
412
 
400
- for root, dirs, filenames in os.walk(target):
401
- dirs[:] = [d for d in dirs if d not in SKIP_DIRECTORIES]
402
-
403
- for fname in filenames:
404
- total_files += 1
405
- fpath = Path(root) / fname
406
- suffix = fpath.suffix.lower()
413
+ for fpath in safe_user_path(target).rglob("*"):
414
+ if not fpath.is_file() or any(part in SKIP_DIRECTORIES for part in fpath.parts):
415
+ continue
416
+ fname = fpath.name
417
+ total_files += 1
418
+ suffix = fpath.suffix.lower()
407
419
 
408
- # Categorize by extension
409
- ext_key = suffix if suffix else "(no extension)"
410
- files_by_type[ext_key] = files_by_type.get(ext_key, 0) + 1
420
+ # Categorize by extension
421
+ ext_key = suffix if suffix else "(no extension)"
422
+ files_by_type[ext_key] = files_by_type.get(ext_key, 0) + 1
411
423
 
412
- # Detect entry points
413
- for pat in _entry_point_patterns:
414
- if pat.search(fname) or pat.search(str(fpath)):
415
- entry_points.append(str(fpath))
416
- break
424
+ # Detect entry points
425
+ for pat in _entry_point_patterns:
426
+ if pat.search(fname) or pat.search(str(fpath)):
427
+ entry_points.append(str(fpath))
428
+ break
417
429
 
418
- # Detect dependency files
419
- if fname.lower() in _dep_file_names:
420
- dependency_files.append(str(fpath))
430
+ # Detect dependency files
431
+ if fname.lower() in _dep_file_names:
432
+ dependency_files.append(str(fpath))
421
433
 
422
- # Detect config files
423
- if suffix in _config_extensions or fname.lower().startswith(".env"):
424
- config_files.append(str(fpath))
434
+ # Detect config files
435
+ if suffix in _config_extensions or fname.lower().startswith(".env"):
436
+ config_files.append(str(fpath))
425
437
 
426
438
  # Sort by count descending
427
439
  sorted_types = sorted(files_by_type.items(), key=lambda x: x[1], reverse=True)
@@ -1053,7 +1065,7 @@ def run_audit(
1053
1065
 
1054
1066
  ensure_directories()
1055
1067
 
1056
- target = Path(target_path).resolve()
1068
+ target = safe_user_path(target_path).resolve()
1057
1069
  if not target.exists():
1058
1070
  logger.error("Target path does not exist: %s", target)
1059
1071
  sys.exit(1)
@@ -17,6 +17,19 @@ import sys
17
17
  import time
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
  # ---------------------------------------------------------------------------
21
34
  # Imports from the 007 config hub (same directory)
22
35
  # ---------------------------------------------------------------------------
@@ -134,20 +147,16 @@ def collect_files(target: Path, logger) -> list[Path]:
134
147
  files: list[Path] = []
135
148
  max_files = LIMITS["max_files_per_scan"]
136
149
 
137
- for root, dirs, filenames in os.walk(target):
138
- # Prune skipped directories in-place so os.walk does not descend
139
- dirs[:] = [d for d in dirs if not _should_skip_dir(d)]
140
-
141
- for fname in filenames:
142
- if len(files) >= max_files:
143
- logger.warning(
144
- "Reached max_files_per_scan limit (%d). Stopping collection.", max_files
145
- )
146
- return files
147
-
148
- fpath = Path(root) / fname
149
- if _is_scannable(fpath):
150
- files.append(fpath)
150
+ for fpath in safe_user_path(target).rglob("*"):
151
+ if not fpath.is_file() or any(_should_skip_dir(part) for part in fpath.parts):
152
+ continue
153
+ if len(files) >= max_files:
154
+ logger.warning(
155
+ "Reached max_files_per_scan limit (%d). Stopping collection.", max_files
156
+ )
157
+ return files
158
+ if _is_scannable(fpath):
159
+ files.append(fpath)
151
160
 
152
161
  return files
153
162
 
@@ -368,7 +377,7 @@ def run_scan(target_path: str, output_format: str = "text", verbose: bool = Fals
368
377
  logger = setup_logging("007-quick-scan")
369
378
  ensure_directories()
370
379
 
371
- target = Path(target_path).resolve()
380
+ target = safe_user_path(target_path).resolve()
372
381
  if not target.exists():
373
382
  logger.error("Target path does not exist: %s", target)
374
383
  sys.exit(1)
@@ -17,6 +17,19 @@ import sys
17
17
  import time
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
  # ---------------------------------------------------------------------------
21
34
  # Import from the 007 config hub (parent directory)
22
35
  # ---------------------------------------------------------------------------
@@ -850,27 +863,26 @@ def discover_dependency_files(target: Path) -> list[Path]:
850
863
  """
851
864
  found: list[Path] = []
852
865
 
853
- for root, dirs, filenames in os.walk(target):
854
- dirs[:] = [d for d in dirs if d not in config.SKIP_DIRECTORIES]
855
-
856
- for fname in filenames:
857
- fpath = Path(root) / fname
858
- fname_lower = fname.lower()
866
+ for fpath in safe_user_path(target).rglob("*"):
867
+ if not fpath.is_file() or any(part in config.SKIP_DIRECTORIES for part in fpath.parts):
868
+ continue
869
+ fname = fpath.name
870
+ fname_lower = fname.lower()
859
871
 
860
- # Exact name matches
861
- if fname in ALL_DEP_FILES:
862
- found.append(fpath)
863
- continue
872
+ # Exact name matches
873
+ if fname in ALL_DEP_FILES:
874
+ found.append(fpath)
875
+ continue
864
876
 
865
- # requirements*.txt variants
866
- if _REQUIREMENTS_RE.match(fname):
867
- found.append(fpath)
868
- continue
877
+ # requirements*.txt variants
878
+ if _REQUIREMENTS_RE.match(fname):
879
+ found.append(fpath)
880
+ continue
869
881
 
870
- # Docker files (prefix match)
871
- if any(fname_lower.startswith(prefix.lower()) for prefix in DOCKER_PREFIXES):
872
- found.append(fpath)
873
- continue
882
+ # Docker files (prefix match)
883
+ if any(fname_lower.startswith(prefix.lower()) for prefix in DOCKER_PREFIXES):
884
+ found.append(fpath)
885
+ continue
874
886
 
875
887
  return found
876
888
 
@@ -1158,7 +1170,7 @@ def run_scan(
1158
1170
 
1159
1171
  config.ensure_directories()
1160
1172
 
1161
- target = Path(target_path).resolve()
1173
+ target = safe_user_path(target_path).resolve()
1162
1174
  if not target.exists():
1163
1175
  logger.error("Target path does not exist: %s", target)
1164
1176
  sys.exit(1)
@@ -20,6 +20,19 @@ import sys
20
20
  import time
21
21
  from pathlib import Path
22
22
 
23
+
24
+ def safe_user_path(path_value, base_dir="."):
25
+ """Resolve a CLI path under the current workspace."""
26
+ if base_dir != ".":
27
+ raise ValueError("Custom base directories are not supported for CLI paths")
28
+ base_path = Path.cwd().resolve()
29
+ resolved_path = Path(path_value).expanduser().resolve()
30
+ try:
31
+ resolved_path.relative_to(base_path)
32
+ except ValueError as exc:
33
+ raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
34
+ return resolved_path
35
+
23
36
  # ---------------------------------------------------------------------------
24
37
  # Import from the 007 config hub (parent directory)
25
38
  # ---------------------------------------------------------------------------
@@ -546,19 +559,16 @@ def collect_files(target: Path) -> list[Path]:
546
559
  files: list[Path] = []
547
560
  max_files = config.LIMITS["max_files_per_scan"]
548
561
 
549
- for root, dirs, filenames in os.walk(target):
550
- dirs[:] = [d for d in dirs if d not in config.SKIP_DIRECTORIES]
551
-
552
- for fname in filenames:
553
- if len(files) >= max_files:
554
- logger.warning(
555
- "Reached max_files_per_scan limit (%d). Stopping.", max_files
556
- )
557
- return files
558
-
559
- fpath = Path(root) / fname
560
- if _should_scan_file(fpath):
561
- files.append(fpath)
562
+ for fpath in safe_user_path(target).rglob("*"):
563
+ if not fpath.is_file() or any(part in config.SKIP_DIRECTORIES for part in fpath.parts):
564
+ continue
565
+ if len(files) >= max_files:
566
+ logger.warning(
567
+ "Reached max_files_per_scan limit (%d). Stopping.", max_files
568
+ )
569
+ return files
570
+ if _should_scan_file(fpath):
571
+ files.append(fpath)
562
572
 
563
573
  return files
564
574
 
@@ -961,7 +971,7 @@ def run_scan(
961
971
 
962
972
  config.ensure_directories()
963
973
 
964
- target = Path(target_path).resolve()
974
+ target = safe_user_path(target_path).resolve()
965
975
  if not target.exists():
966
976
  logger.error("Target path does not exist: %s", target)
967
977
  sys.exit(1)
@@ -20,6 +20,19 @@ import sys
20
20
  import time
21
21
  from pathlib import Path
22
22
 
23
+
24
+ def safe_user_path(path_value, base_dir="."):
25
+ """Resolve a CLI path under the current workspace."""
26
+ if base_dir != ".":
27
+ raise ValueError("Custom base directories are not supported for CLI paths")
28
+ base_path = Path.cwd().resolve()
29
+ resolved_path = Path(path_value).expanduser().resolve()
30
+ try:
31
+ resolved_path.relative_to(base_path)
32
+ except ValueError as exc:
33
+ raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
34
+ return resolved_path
35
+
23
36
  # ---------------------------------------------------------------------------
24
37
  # Import from the 007 config hub (parent directory)
25
38
  # ---------------------------------------------------------------------------
@@ -375,19 +388,16 @@ def collect_files(target: Path) -> list[Path]:
375
388
  files: list[Path] = []
376
389
  max_files = config.LIMITS["max_files_per_scan"]
377
390
 
378
- for root, dirs, filenames in os.walk(target):
379
- dirs[:] = [d for d in dirs if d not in config.SKIP_DIRECTORIES]
380
-
381
- for fname in filenames:
382
- if len(files) >= max_files:
383
- logger.warning(
384
- "Reached max_files_per_scan limit (%d). Stopping.", max_files
385
- )
386
- return files
387
-
388
- fpath = Path(root) / fname
389
- if _should_scan_file(fpath):
390
- files.append(fpath)
391
+ for fpath in safe_user_path(target).rglob("*"):
392
+ if not fpath.is_file() or any(part in config.SKIP_DIRECTORIES for part in fpath.parts):
393
+ continue
394
+ if len(files) >= max_files:
395
+ logger.warning(
396
+ "Reached max_files_per_scan limit (%d). Stopping.", max_files
397
+ )
398
+ return files
399
+ if _should_scan_file(fpath):
400
+ files.append(fpath)
391
401
 
392
402
  return files
393
403
 
@@ -869,7 +879,7 @@ def run_scan(
869
879
 
870
880
  config.ensure_directories()
871
881
 
872
- target = Path(target_path).resolve()
882
+ target = safe_user_path(target_path).resolve()
873
883
  if not target.exists():
874
884
  logger.error("Target path does not exist: %s", target)
875
885
  sys.exit(1)
@@ -24,6 +24,19 @@ import sys
24
24
  import time
25
25
  from pathlib import Path
26
26
 
27
+
28
+ def safe_user_path(path_value, base_dir="."):
29
+ """Resolve a CLI path under the current workspace."""
30
+ if base_dir != ".":
31
+ raise ValueError("Custom base directories are not supported for CLI paths")
32
+ base_path = Path.cwd().resolve()
33
+ resolved_path = Path(path_value).expanduser().resolve()
34
+ try:
35
+ resolved_path.relative_to(base_path)
36
+ except ValueError as exc:
37
+ raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
38
+ return resolved_path
39
+
27
40
  # ---------------------------------------------------------------------------
28
41
  # Imports from the 007 config hub (same directory)
29
42
  # ---------------------------------------------------------------------------
@@ -141,18 +154,17 @@ def _collect_source_files(target: Path) -> list[Path]:
141
154
  files: list[Path] = []
142
155
  max_files = LIMITS["max_files_per_scan"]
143
156
 
144
- for root, dirs, filenames in os.walk(target):
145
- dirs[:] = [d for d in dirs if d not in SKIP_DIRECTORIES]
146
- for fname in filenames:
147
- if len(files) >= max_files:
148
- return files
149
- fpath = Path(root) / fname
150
- suffix = fpath.suffix.lower()
151
- name = fpath.name.lower()
152
- for ext in SCANNABLE_EXTENSIONS:
153
- if name.endswith(ext) or suffix == ext:
154
- files.append(fpath)
155
- break
157
+ for fpath in safe_user_path(target).rglob("*"):
158
+ if not fpath.is_file() or any(part in SKIP_DIRECTORIES for part in fpath.parts):
159
+ continue
160
+ if len(files) >= max_files:
161
+ return files
162
+ suffix = fpath.suffix.lower()
163
+ name = fpath.name.lower()
164
+ for ext in SCANNABLE_EXTENSIONS:
165
+ if name.endswith(ext) or suffix == ext:
166
+ files.append(fpath)
167
+ break
156
168
 
157
169
  return files
158
170
 
@@ -529,7 +541,7 @@ def run_score(
529
541
 
530
542
  ensure_directories()
531
543
 
532
- target = Path(target_path).resolve()
544
+ target = safe_user_path(target_path).resolve()
533
545
  if not target.exists():
534
546
  logger.error("Target path does not exist: %s", target)
535
547
  sys.exit(1)
@@ -14,6 +14,20 @@ import socket
14
14
  import requests
15
15
  from urllib.parse import urlparse
16
16
  from typing import Optional, Dict, Any
17
+ from pathlib import Path
18
+
19
+
20
+ def safe_user_path(path_value, base_dir="."):
21
+ """Resolve a CLI path under the current workspace."""
22
+ if base_dir != ".":
23
+ raise ValueError("Custom base directories are not supported for CLI paths")
24
+ base_path = Path.cwd().resolve()
25
+ resolved_path = Path(path_value).expanduser().resolve()
26
+ try:
27
+ resolved_path.relative_to(base_path)
28
+ except ValueError as exc:
29
+ raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
30
+ return resolved_path
17
31
 
18
32
 
19
33
  API_BASE_URL = "https://2slides.com/api/v1"
@@ -124,7 +138,7 @@ def download_slides_pages_voices(
124
138
  zip_response.raise_for_status()
125
139
 
126
140
  # Save to file
127
- with open(output_path, 'wb') as f:
141
+ with safe_user_path(output_path).open('wb') as f:
128
142
  for chunk in zip_response.iter_content(chunk_size=8192):
129
143
  f.write(chunk)
130
144