@iamnishankhan/opencode-kit-grok 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/bin/cli.js +46 -0
  2. package/kit/.opencode/AGENTS.md +392 -0
  3. package/kit/.opencode/README.md +71 -0
  4. package/kit/.opencode/USAGE.md +405 -0
  5. package/kit/.opencode/agents/backend-specialist.md +278 -0
  6. package/kit/.opencode/agents/code-archaeologist.md +114 -0
  7. package/kit/.opencode/agents/database-architect.md +233 -0
  8. package/kit/.opencode/agents/debugger.md +234 -0
  9. package/kit/.opencode/agents/devops-engineer.md +252 -0
  10. package/kit/.opencode/agents/documentation-writer.md +111 -0
  11. package/kit/.opencode/agents/explorer-agent.md +83 -0
  12. package/kit/.opencode/agents/frontend-specialist.md +606 -0
  13. package/kit/.opencode/agents/game-developer.md +169 -0
  14. package/kit/.opencode/agents/mobile-developer.md +385 -0
  15. package/kit/.opencode/agents/orchestrator.md +213 -0
  16. package/kit/.opencode/agents/penetration-tester.md +197 -0
  17. package/kit/.opencode/agents/performance-optimizer.md +194 -0
  18. package/kit/.opencode/agents/product-manager.md +120 -0
  19. package/kit/.opencode/agents/product-owner.md +103 -0
  20. package/kit/.opencode/agents/project-planner.md +418 -0
  21. package/kit/.opencode/agents/qa-automation-engineer.md +113 -0
  22. package/kit/.opencode/agents/security-auditor.md +179 -0
  23. package/kit/.opencode/agents/seo-specialist.md +119 -0
  24. package/kit/.opencode/agents/test-engineer.md +169 -0
  25. package/kit/.opencode/commands/brainstorm.md +113 -0
  26. package/kit/.opencode/commands/coordinate.md +72 -0
  27. package/kit/.opencode/commands/create.md +63 -0
  28. package/kit/.opencode/commands/debug.md +102 -0
  29. package/kit/.opencode/commands/deploy.md +175 -0
  30. package/kit/.opencode/commands/enhance.md +62 -0
  31. package/kit/.opencode/commands/orchestrate.md +241 -0
  32. package/kit/.opencode/commands/plan.md +89 -0
  33. package/kit/.opencode/commands/preview.md +80 -0
  34. package/kit/.opencode/commands/remember.md +67 -0
  35. package/kit/.opencode/commands/status.md +86 -0
  36. package/kit/.opencode/commands/test.md +143 -0
  37. package/kit/.opencode/commands/verify.md +71 -0
  38. package/kit/.opencode/memory/MEMORY.md +6 -0
  39. package/kit/.opencode/memory/feedback-history.md +9 -0
  40. package/kit/.opencode/memory/project-conventions.md +16 -0
  41. package/kit/.opencode/memory/tech-decisions.md +10 -0
  42. package/kit/.opencode/memory/user-preferences.md +9 -0
  43. package/kit/.opencode/opencode.json +15 -0
  44. package/kit/.opencode/scripts/README.md +95 -0
  45. package/kit/.opencode/scripts/auto_preview.py +149 -0
  46. package/kit/.opencode/scripts/checklist.py +75 -0
  47. package/kit/.opencode/scripts/component_registry.py +238 -0
  48. package/kit/.opencode/scripts/dependency_graph.py +73 -0
  49. package/kit/.opencode/scripts/generate_manifest.py +44 -0
  50. package/kit/.opencode/scripts/session_manager.py +120 -0
  51. package/kit/.opencode/scripts/tests/test_toolkit.py +238 -0
  52. package/kit/.opencode/scripts/validate_kit.py +397 -0
  53. package/kit/.opencode/scripts/validation_runner.py +216 -0
  54. package/kit/.opencode/scripts/verify_all.py +85 -0
  55. package/kit/.opencode/skills/api-patterns/SKILL.md +83 -0
  56. package/kit/.opencode/skills/api-patterns/api-style.md +42 -0
  57. package/kit/.opencode/skills/api-patterns/auth.md +24 -0
  58. package/kit/.opencode/skills/api-patterns/documentation.md +26 -0
  59. package/kit/.opencode/skills/api-patterns/graphql.md +41 -0
  60. package/kit/.opencode/skills/api-patterns/rate-limiting.md +31 -0
  61. package/kit/.opencode/skills/api-patterns/response.md +37 -0
  62. package/kit/.opencode/skills/api-patterns/rest.md +40 -0
  63. package/kit/.opencode/skills/api-patterns/scripts/api_validator.py +211 -0
  64. package/kit/.opencode/skills/api-patterns/security-testing.md +122 -0
  65. package/kit/.opencode/skills/api-patterns/trpc.md +41 -0
  66. package/kit/.opencode/skills/api-patterns/versioning.md +22 -0
  67. package/kit/.opencode/skills/app-builder/SKILL.md +78 -0
  68. package/kit/.opencode/skills/app-builder/agent-coordination.md +71 -0
  69. package/kit/.opencode/skills/app-builder/feature-building.md +53 -0
  70. package/kit/.opencode/skills/app-builder/project-detection.md +45 -0
  71. package/kit/.opencode/skills/app-builder/scaffolding.md +110 -0
  72. package/kit/.opencode/skills/app-builder/tech-stack.md +41 -0
  73. package/kit/.opencode/skills/app-builder/templates/SKILL.md +39 -0
  74. package/kit/.opencode/skills/app-builder/templates/astro-static/TEMPLATE.md +78 -0
  75. package/kit/.opencode/skills/app-builder/templates/chrome-extension/TEMPLATE.md +96 -0
  76. package/kit/.opencode/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  77. package/kit/.opencode/skills/app-builder/templates/electron-desktop/TEMPLATE.md +97 -0
  78. package/kit/.opencode/skills/app-builder/templates/express-api/TEMPLATE.md +89 -0
  79. package/kit/.opencode/skills/app-builder/templates/flutter-app/TEMPLATE.md +93 -0
  80. package/kit/.opencode/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +97 -0
  81. package/kit/.opencode/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +126 -0
  82. package/kit/.opencode/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +125 -0
  83. package/kit/.opencode/skills/app-builder/templates/nextjs-static/TEMPLATE.md +174 -0
  84. package/kit/.opencode/skills/app-builder/templates/nuxt-app/TEMPLATE.md +127 -0
  85. package/kit/.opencode/skills/app-builder/templates/python-fastapi/TEMPLATE.md +94 -0
  86. package/kit/.opencode/skills/app-builder/templates/react-native-app/TEMPLATE.md +121 -0
  87. package/kit/.opencode/skills/architecture/SKILL.md +57 -0
  88. package/kit/.opencode/skills/architecture/context-discovery.md +43 -0
  89. package/kit/.opencode/skills/architecture/examples.md +94 -0
  90. package/kit/.opencode/skills/architecture/pattern-selection.md +68 -0
  91. package/kit/.opencode/skills/architecture/patterns-reference.md +50 -0
  92. package/kit/.opencode/skills/architecture/trade-off-analysis.md +77 -0
  93. package/kit/.opencode/skills/bash-linux/SKILL.md +201 -0
  94. package/kit/.opencode/skills/batch-operations/SKILL.md +105 -0
  95. package/kit/.opencode/skills/behavioral-modes/SKILL.md +253 -0
  96. package/kit/.opencode/skills/brainstorming/SKILL.md +178 -0
  97. package/kit/.opencode/skills/brainstorming/dynamic-questioning.md +350 -0
  98. package/kit/.opencode/skills/clean-code/SKILL.md +201 -0
  99. package/kit/.opencode/skills/code-review-checklist/SKILL.md +111 -0
  100. package/kit/.opencode/skills/code-review-graph/SKILL.md +305 -0
  101. package/kit/.opencode/skills/context-compression/SKILL.md +145 -0
  102. package/kit/.opencode/skills/coordinator-mode/SKILL.md +208 -0
  103. package/kit/.opencode/skills/database-design/SKILL.md +54 -0
  104. package/kit/.opencode/skills/database-design/database-selection.md +43 -0
  105. package/kit/.opencode/skills/database-design/indexing.md +39 -0
  106. package/kit/.opencode/skills/database-design/migrations.md +48 -0
  107. package/kit/.opencode/skills/database-design/optimization.md +36 -0
  108. package/kit/.opencode/skills/database-design/orm-selection.md +30 -0
  109. package/kit/.opencode/skills/database-design/schema-design.md +56 -0
  110. package/kit/.opencode/skills/database-design/scripts/schema_validator.py +172 -0
  111. package/kit/.opencode/skills/deployment-procedures/SKILL.md +243 -0
  112. package/kit/.opencode/skills/design-spec/SKILL.md +185 -0
  113. package/kit/.opencode/skills/design-spec/collection.md +106 -0
  114. package/kit/.opencode/skills/documentation-templates/SKILL.md +196 -0
  115. package/kit/.opencode/skills/frontend-architecture/SKILL.md +245 -0
  116. package/kit/.opencode/skills/frontend-design/SKILL.md +1222 -0
  117. package/kit/.opencode/skills/frontend-design/redesign.md +178 -0
  118. package/kit/.opencode/skills/frontend-design/scripts/accessibility_checker.py +145 -0
  119. package/kit/.opencode/skills/frontend-design/scripts/ux_audit.py +722 -0
  120. package/kit/.opencode/skills/frontend-design/style-brutalist.md +92 -0
  121. package/kit/.opencode/skills/frontend-design/style-minimalist.md +85 -0
  122. package/kit/.opencode/skills/game-development/2d-games/SKILL.md +118 -0
  123. package/kit/.opencode/skills/game-development/3d-games/SKILL.md +134 -0
  124. package/kit/.opencode/skills/game-development/SKILL.md +169 -0
  125. package/kit/.opencode/skills/game-development/game-art/SKILL.md +184 -0
  126. package/kit/.opencode/skills/game-development/game-audio/SKILL.md +189 -0
  127. package/kit/.opencode/skills/game-development/game-design/SKILL.md +128 -0
  128. package/kit/.opencode/skills/game-development/mobile-games/SKILL.md +107 -0
  129. package/kit/.opencode/skills/game-development/multiplayer/SKILL.md +131 -0
  130. package/kit/.opencode/skills/game-development/pc-games/SKILL.md +143 -0
  131. package/kit/.opencode/skills/game-development/vr-ar/SKILL.md +122 -0
  132. package/kit/.opencode/skills/game-development/web-games/SKILL.md +149 -0
  133. package/kit/.opencode/skills/geo-fundamentals/SKILL.md +158 -0
  134. package/kit/.opencode/skills/geo-fundamentals/scripts/geo_checker.py +273 -0
  135. package/kit/.opencode/skills/i18n-localization/SKILL.md +156 -0
  136. package/kit/.opencode/skills/i18n-localization/scripts/i18n_checker.py +223 -0
  137. package/kit/.opencode/skills/intelligent-routing/SKILL.md +337 -0
  138. package/kit/.opencode/skills/lint-and-validate/SKILL.md +47 -0
  139. package/kit/.opencode/skills/lint-and-validate/scripts/lint_runner.py +184 -0
  140. package/kit/.opencode/skills/lint-and-validate/scripts/type_coverage.py +245 -0
  141. package/kit/.opencode/skills/mcp-builder/SKILL.md +205 -0
  142. package/kit/.opencode/skills/memory-system/SKILL.md +181 -0
  143. package/kit/.opencode/skills/mobile-design/SKILL.md +396 -0
  144. package/kit/.opencode/skills/mobile-design/decision-trees.md +516 -0
  145. package/kit/.opencode/skills/mobile-design/mobile-backend.md +491 -0
  146. package/kit/.opencode/skills/mobile-design/mobile-color-system.md +420 -0
  147. package/kit/.opencode/skills/mobile-design/mobile-debugging.md +122 -0
  148. package/kit/.opencode/skills/mobile-design/mobile-design-thinking.md +357 -0
  149. package/kit/.opencode/skills/mobile-design/mobile-navigation.md +458 -0
  150. package/kit/.opencode/skills/mobile-design/mobile-performance.md +767 -0
  151. package/kit/.opencode/skills/mobile-design/mobile-testing.md +356 -0
  152. package/kit/.opencode/skills/mobile-design/mobile-typography.md +433 -0
  153. package/kit/.opencode/skills/mobile-design/platform-android.md +666 -0
  154. package/kit/.opencode/skills/mobile-design/platform-ios.md +561 -0
  155. package/kit/.opencode/skills/mobile-design/scripts/mobile_audit.py +670 -0
  156. package/kit/.opencode/skills/mobile-design/touch-psychology.md +537 -0
  157. package/kit/.opencode/skills/nextjs-react-expert/1-async-eliminating-waterfalls.md +351 -0
  158. package/kit/.opencode/skills/nextjs-react-expert/2-bundle-bundle-size-optimization.md +240 -0
  159. package/kit/.opencode/skills/nextjs-react-expert/3-server-server-side-performance.md +490 -0
  160. package/kit/.opencode/skills/nextjs-react-expert/4-client-client-side-data-fetching.md +264 -0
  161. package/kit/.opencode/skills/nextjs-react-expert/5-rerender-re-render-optimization.md +581 -0
  162. package/kit/.opencode/skills/nextjs-react-expert/6-rendering-rendering-performance.md +432 -0
  163. package/kit/.opencode/skills/nextjs-react-expert/7-js-javascript-performance.md +684 -0
  164. package/kit/.opencode/skills/nextjs-react-expert/8-advanced-advanced-patterns.md +150 -0
  165. package/kit/.opencode/skills/nextjs-react-expert/9-cache-components.md +103 -0
  166. package/kit/.opencode/skills/nextjs-react-expert/SKILL.md +293 -0
  167. package/kit/.opencode/skills/nextjs-react-expert/scripts/convert_rules.py +222 -0
  168. package/kit/.opencode/skills/nextjs-react-expert/scripts/react_performance_checker.py +281 -0
  169. package/kit/.opencode/skills/nodejs-best-practices/SKILL.md +336 -0
  170. package/kit/.opencode/skills/parallel-agents/SKILL.md +192 -0
  171. package/kit/.opencode/skills/performance-profiling/SKILL.md +145 -0
  172. package/kit/.opencode/skills/performance-profiling/scripts/bundle_analyzer.py +120 -0
  173. package/kit/.opencode/skills/performance-profiling/scripts/lighthouse_audit.py +108 -0
  174. package/kit/.opencode/skills/plan-writing/SKILL.md +153 -0
  175. package/kit/.opencode/skills/powershell-windows/SKILL.md +169 -0
  176. package/kit/.opencode/skills/python-patterns/SKILL.md +443 -0
  177. package/kit/.opencode/skills/red-team-tactics/SKILL.md +201 -0
  178. package/kit/.opencode/skills/rust-pro/SKILL.md +177 -0
  179. package/kit/.opencode/skills/seo-fundamentals/SKILL.md +131 -0
  180. package/kit/.opencode/skills/seo-fundamentals/scripts/seo_checker.py +219 -0
  181. package/kit/.opencode/skills/server-management/SKILL.md +163 -0
  182. package/kit/.opencode/skills/simplify-code/SKILL.md +131 -0
  183. package/kit/.opencode/skills/skillify/SKILL.md +115 -0
  184. package/kit/.opencode/skills/systematic-debugging/SKILL.md +111 -0
  185. package/kit/.opencode/skills/tailwind-patterns/SKILL.md +271 -0
  186. package/kit/.opencode/skills/tdd-workflow/SKILL.md +151 -0
  187. package/kit/.opencode/skills/testing-patterns/SKILL.md +180 -0
  188. package/kit/.opencode/skills/testing-patterns/scripts/test_runner.py +219 -0
  189. package/kit/.opencode/skills/verify-changes/SKILL.md +127 -0
  190. package/kit/.opencode/skills/vulnerability-scanner/SKILL.md +278 -0
  191. package/kit/.opencode/skills/vulnerability-scanner/checklists.md +124 -0
  192. package/kit/.opencode/skills/vulnerability-scanner/scripts/dependency_analyzer.py +144 -0
  193. package/kit/.opencode/skills/vulnerability-scanner/scripts/security_scan.py +410 -0
  194. package/kit/.opencode/skills/web-design-guidelines/SKILL.md +56 -0
  195. package/kit/.opencode/skills/webapp-testing/SKILL.md +189 -0
  196. package/kit/.opencode/skills/webapp-testing/scripts/playwright_runner.py +123 -0
  197. package/lib/init.js +61 -0
  198. package/package.json +21 -0
@@ -0,0 +1,410 @@
1
+ #!/usr/bin/env python3
2
+ """AG Kit security scanner.
3
+
4
+ Performs lightweight, local checks for dependency hygiene, hard-coded secrets,
5
+ dangerous code patterns, and common security misconfiguration.
6
+
7
+ The scanner is intentionally dependency-free. It is a guardrail, not a
8
+ replacement for a full SAST/SCA product.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import argparse
13
+ import io
14
+ import json
15
+ import os
16
+ import re
17
+ import subprocess
18
+ import sys
19
+ import tokenize
20
+ from datetime import datetime, timezone
21
+ from pathlib import Path
22
+ from typing import Any, Callable
23
+
24
+ try:
25
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
26
+ sys.stderr.reconfigure(encoding="utf-8", errors="replace")
27
+ except AttributeError:
28
+ pass
29
+
30
+ SECRET_PATTERNS: tuple[tuple[str, str, str], ...] = (
31
+ (r"api[_-]?key\s*[=:]\s*[\"'][^\"']{10,}[\"']", "API Key", "high"),
32
+ (r"token\s*[=:]\s*[\"'][^\"']{10,}[\"']", "Token", "high"),
33
+ (r"bearer\s+[a-zA-Z0-9\-_.]{16,}", "Bearer Token", "critical"),
34
+ (r"AKIA[0-9A-Z]{16}", "AWS Access Key", "critical"),
35
+ (r"aws[_-]?secret[_-]?access[_-]?key\s*[=:]\s*[\"'][^\"']+[\"']", "AWS Secret", "critical"),
36
+ (r"AZURE[_-]?[A-Z_]+\s*[=:]\s*[\"'][^\"']+[\"']", "Azure Credential", "critical"),
37
+ (r"GOOGLE[_-]?[A-Z_]+\s*[=:]\s*[\"'][^\"']+[\"']", "GCP Credential", "critical"),
38
+ (r"password\s*[=:]\s*[\"'][^\"']{6,}[\"']", "Password", "high"),
39
+ (r"(?:mongodb|postgres(?:ql)?|mysql|redis):\/\/[^\s\"']+", "Database Connection String", "critical"),
40
+ (r"-----BEGIN\s+(?:RSA|PRIVATE|EC|OPENSSH)\s+KEY-----", "Private Key", "critical"),
41
+ (r"ssh-rsa\s+[A-Za-z0-9+/]{80,}", "SSH Key", "critical"),
42
+ (r"eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+", "JWT Token", "high"),
43
+ )
44
+
45
+ DANGEROUS_PATTERNS: tuple[tuple[str, str, str, str], ...] = (
46
+ (r"\beval\s*\(", "eval() usage", "critical", "Code injection risk"),
47
+ (r"\bexec\s*\(", "exec() usage", "critical", "Code injection risk"),
48
+ (r"new\s+Function\s*\(", "Function constructor", "high", "Code injection risk"),
49
+ (r"child_process\.exec\s*\(", "child_process.exec", "high", "Command injection risk"),
50
+ (r"subprocess\.(?:call|run|Popen)\s*\([^\n]*shell\s*=\s*True", "subprocess shell=True", "high", "Command injection risk"),
51
+ (r"dangerouslySetInnerHTML", "dangerouslySetInnerHTML", "high", "XSS risk"),
52
+ (r"\.innerHTML\s*=", "innerHTML assignment", "medium", "XSS risk"),
53
+ (r"document\.write\s*\(", "document.write", "medium", "XSS risk"),
54
+ (r"[\"'][^\"']*\+\s*[a-zA-Z_]\w*\s*\+\s*[\"'][^\n]*(?:SELECT|INSERT|UPDATE|DELETE)", "SQL string concatenation", "critical", "SQL injection risk"),
55
+ (r"f[\"'][^\"']*(?:SELECT|INSERT|UPDATE|DELETE)[^\"']*\{", "SQL f-string", "critical", "SQL injection risk"),
56
+ (r"verify\s*=\s*False", "SSL verification disabled", "high", "MITM risk"),
57
+ (r"--insecure\b", "Insecure flag", "medium", "Security disabled"),
58
+ (r"disable[_-]?ssl", "SSL disabled", "high", "MITM risk"),
59
+ (r"pickle\.loads?\s*\(", "pickle usage", "high", "Unsafe deserialization risk"),
60
+ (r"yaml\.load\s*\(", "yaml.load usage", "high", "Unsafe deserialization risk"),
61
+ )
62
+
63
+ SEVERITY_RANK = {"none": 99, "low": 1, "medium": 2, "high": 3, "critical": 4}
64
+ SKIP_DIRS = {
65
+ "node_modules", ".git", "dist", "build", "__pycache__", ".venv", "venv",
66
+ ".next", ".agents", ".agent", ".tox", ".mypy_cache", ".pytest_cache",
67
+ "coverage", ".coverage", "vendor",
68
+ }
69
+ CODE_EXTENSIONS = {".js", ".mjs", ".cjs", ".ts", ".tsx", ".jsx", ".py", ".go", ".java", ".rb", ".php"}
70
+ CONFIG_EXTENSIONS = {".json", ".yaml", ".yml", ".toml", ".env", ".ini", ".conf"}
71
+ PLACEHOLDER_MARKERS = (
72
+ "YOUR_", "EXAMPLE", "CHANGEME", "CHANGE_ME", "REPLACE_ME", "PLACEHOLDER",
73
+ "DUMMY", "SAMPLE", "FAKE_", "TEST_TOKEN", "TEST_KEY",
74
+ )
75
+ SELF_PATH = Path(__file__).resolve()
76
+
77
+
78
+ def _new_result(tool: str, status: str) -> dict[str, Any]:
79
+ return {"tool": tool, "findings": [], "status": status, "scanned_files": 0}
80
+
81
+
82
+ def _iter_files(project: Path, extensions: set[str]):
83
+ for root, dirs, files in os.walk(project):
84
+ dirs[:] = [d for d in dirs if d not in SKIP_DIRS]
85
+ for filename in files:
86
+ path = Path(root) / filename
87
+ if path.resolve() == SELF_PATH:
88
+ continue
89
+ if path.suffix.lower() in extensions or filename.startswith(".env"):
90
+ yield path
91
+
92
+
93
+ def _relative(path: Path, project: Path) -> str:
94
+ try:
95
+ return path.relative_to(project).as_posix()
96
+ except ValueError:
97
+ return path.as_posix()
98
+
99
+
100
+ def _is_placeholder(value: str) -> bool:
101
+ upper = value.upper()
102
+ return any(marker in upper for marker in PLACEHOLDER_MARKERS)
103
+
104
+
105
+ def _redact(value: str) -> str:
106
+ value = value.strip().replace("\n", " ")
107
+ if len(value) <= 12:
108
+ return "<redacted>"
109
+ return f"{value[:4]}…{value[-4:]}"
110
+
111
+
112
+ def _python_code_without_strings(text: str) -> list[str]:
113
+ lines = [list(line) for line in text.splitlines(keepends=True)]
114
+ try:
115
+ tokens = tokenize.generate_tokens(io.StringIO(text).readline)
116
+ for tok in tokens:
117
+ if tok.type not in {tokenize.STRING, tokenize.COMMENT}:
118
+ continue
119
+ (srow, scol), (erow, ecol) = tok.start, tok.end
120
+ for row in range(srow, erow + 1):
121
+ if not (1 <= row <= len(lines)):
122
+ continue
123
+ start = scol if row == srow else 0
124
+ end = ecol if row == erow else len(lines[row - 1])
125
+ for col in range(start, min(end, len(lines[row - 1]))):
126
+ if lines[row - 1][col] not in "\r\n":
127
+ lines[row - 1][col] = " "
128
+ except (tokenize.TokenError, IndentationError):
129
+ pass
130
+ return ["".join(line) for line in lines]
131
+
132
+
133
+ def _generic_code_without_strings(text: str) -> list[str]:
134
+ cleaned = re.sub(r"/\*.*?\*/", lambda m: "\n" * m.group(0).count("\n"), text, flags=re.DOTALL)
135
+ output: list[str] = []
136
+ string_re = re.compile(r"(?:\"(?:\\.|[^\"\\])*\"|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`)")
137
+ for line in cleaned.splitlines(keepends=True):
138
+ no_comment = re.sub(r"//.*$", "", line)
139
+ output.append(string_re.sub("", no_comment))
140
+ return output
141
+
142
+
143
+ def scan_dependencies(project_path: str) -> dict[str, Any]:
144
+ project = Path(project_path)
145
+ result = _new_result("dependency_scanner", "[OK] Supply chain checks passed")
146
+
147
+ ecosystems = {
148
+ "node": (["package.json"], ["package-lock.json", "npm-shrinkwrap.json", "yarn.lock", "pnpm-lock.yaml", "bun.lock", "bun.lockb"]),
149
+ "python": (["pyproject.toml", "setup.py", "setup.cfg", "requirements.in"], ["poetry.lock", "Pipfile.lock", "uv.lock", "requirements.txt"]),
150
+ "ruby": (["Gemfile"], ["Gemfile.lock"]),
151
+ "rust": (["Cargo.toml"], ["Cargo.lock"]),
152
+ "go": (["go.mod"], ["go.sum"]),
153
+ }
154
+ for name, (manifests, locks) in ecosystems.items():
155
+ if any((project / f).exists() for f in manifests) and not any((project / f).exists() for f in locks):
156
+ result["findings"].append({
157
+ "type": "Missing lock file",
158
+ "severity": "high",
159
+ "ecosystem": name,
160
+ "message": f"{name}: manifest found but no supported lock file is present.",
161
+ })
162
+
163
+ if (project / "package.json").exists():
164
+ try:
165
+ proc = subprocess.run(
166
+ ["npm", "audit", "--json"], cwd=project, capture_output=True,
167
+ text=True, timeout=90, check=False,
168
+ )
169
+ raw = proc.stdout.strip() or proc.stderr.strip()
170
+ if raw:
171
+ data = json.loads(raw)
172
+ metadata = data.get("metadata", {}).get("vulnerabilities", {})
173
+ counts = {key: int(metadata.get(key, 0) or 0) for key in ("critical", "high", "moderate", "low")}
174
+ result["npm_audit"] = counts
175
+ for severity in ("critical", "high"):
176
+ if counts[severity]:
177
+ result["findings"].append({
178
+ "type": "npm audit", "severity": severity,
179
+ "message": f"{counts[severity]} {severity} dependency vulnerabilities.",
180
+ })
181
+ except FileNotFoundError:
182
+ result["notes"] = ["npm is unavailable; npm audit was skipped."]
183
+ except subprocess.TimeoutExpired:
184
+ result["notes"] = ["npm audit timed out."]
185
+ except (json.JSONDecodeError, OSError) as exc:
186
+ result["notes"] = [f"npm audit output could not be parsed: {exc}"]
187
+
188
+ if result["findings"]:
189
+ result["status"] = "[!] Dependency risks found"
190
+ return result
191
+
192
+
193
+ def scan_secrets(project_path: str) -> dict[str, Any]:
194
+ project = Path(project_path).resolve()
195
+ result = _new_result("secret_scanner", "[OK] No secrets detected")
196
+ counts = {"critical": 0, "high": 0, "medium": 0, "low": 0}
197
+
198
+ for path in _iter_files(project, CODE_EXTENSIONS | CONFIG_EXTENSIONS):
199
+ result["scanned_files"] += 1
200
+ try:
201
+ content = path.read_text("utf-8", errors="ignore")
202
+ except OSError:
203
+ continue
204
+ for pattern, secret_type, severity in SECRET_PATTERNS:
205
+ for match in re.finditer(pattern, content, re.IGNORECASE):
206
+ matched = match.group(0)
207
+ line = content.count("\n", 0, match.start()) + 1
208
+ source_line = content.splitlines()[line - 1] if content.splitlines() else ""
209
+ if _is_placeholder(matched) or "agkit: allow-secret" in source_line.lower() or "# nosec" in source_line.lower():
210
+ continue
211
+ result["findings"].append({
212
+ "file": _relative(path, project), "line": line, "type": secret_type,
213
+ "severity": severity, "preview": _redact(matched),
214
+ })
215
+ counts[severity] += 1
216
+
217
+ result["by_severity"] = counts
218
+ if counts["critical"]:
219
+ result["status"] = "[!!] CRITICAL: Potential secrets exposed"
220
+ elif counts["high"]:
221
+ result["status"] = "[!] HIGH: Potential secrets found"
222
+ elif sum(counts.values()):
223
+ result["status"] = "[?] Potential secrets need review"
224
+ return result
225
+
226
+
227
+ def scan_code_patterns(project_path: str) -> dict[str, Any]:
228
+ project = Path(project_path).resolve()
229
+ result = _new_result("pattern_scanner", "[OK] No dangerous patterns")
230
+ by_category: dict[str, int] = {}
231
+
232
+ for path in _iter_files(project, CODE_EXTENSIONS):
233
+ result["scanned_files"] += 1
234
+ try:
235
+ text = path.read_text("utf-8", errors="ignore")
236
+ except OSError:
237
+ continue
238
+ lines = _python_code_without_strings(text) if path.suffix.lower() == ".py" else _generic_code_without_strings(text)
239
+ original = text.splitlines()
240
+ for line_number, code_line in enumerate(lines, 1):
241
+ for pattern, name, severity, category in DANGEROUS_PATTERNS:
242
+ if re.search(pattern, code_line, re.IGNORECASE):
243
+ snippet = original[line_number - 1].strip()[:120] if line_number <= len(original) else ""
244
+ result["findings"].append({
245
+ "file": _relative(path, project), "line": line_number,
246
+ "pattern": name, "severity": severity, "category": category,
247
+ "snippet": snippet,
248
+ })
249
+ by_category[category] = by_category.get(category, 0) + 1
250
+ result["by_category"] = by_category
251
+ critical = sum(f["severity"] == "critical" for f in result["findings"])
252
+ high = sum(f["severity"] == "high" for f in result["findings"])
253
+ if critical:
254
+ result["status"] = f"[!!] CRITICAL: {critical} dangerous pattern(s)"
255
+ elif high:
256
+ result["status"] = f"[!] HIGH: {high} risky pattern(s)"
257
+ elif result["findings"]:
258
+ result["status"] = "[?] Patterns need review"
259
+ return result
260
+
261
+
262
+ def _looks_like_web_project(project: Path) -> bool:
263
+ indicators = (
264
+ "package.json", "next.config.js", "next.config.mjs", "vite.config.ts",
265
+ "vite.config.js", "nuxt.config.ts", "angular.json", "nginx.conf",
266
+ )
267
+ return any((project / name).exists() for name in indicators)
268
+
269
+
270
+ def scan_configuration(project_path: str) -> dict[str, Any]:
271
+ project = Path(project_path).resolve()
272
+ result = _new_result("config_scanner", "[OK] Configuration checks passed")
273
+ checks: dict[str, Any] = {}
274
+ patterns = (
275
+ (r'"DEBUG"\s*:\s*true', "Debug mode enabled", "high"),
276
+ (r"\bdebug\s*=\s*True", "Debug mode enabled", "high"),
277
+ (r'"CORS_ALLOW_ALL"\s*:\s*true', "CORS allows every origin", "high"),
278
+ (r'Access-Control-Allow-Origin[^\n]*[\"\']\*[\"\']', "CORS wildcard", "high"),
279
+ (r"allowCredentials[^\n]*true[^\n]*origin[^\n]*\*", "Credentials with wildcard CORS", "critical"),
280
+ )
281
+
282
+ extra_names = {"next.config.js", "next.config.mjs", "next.config.ts", "webpack.config.js", ".eslintrc.js", "nginx.conf"}
283
+ header_files = {"next.config.js", "next.config.mjs", "next.config.ts", "middleware.ts", "middleware.js", "nginx.conf", "vercel.json"}
284
+ header_pattern = re.compile(
285
+ r"Content-Security-Policy|Strict-Transport-Security|X-Frame-Options|frame-ancestors|Referrer-Policy",
286
+ re.IGNORECASE,
287
+ )
288
+ has_security_headers = False
289
+ for root, dirs, files in os.walk(project):
290
+ dirs[:] = [d for d in dirs if d not in SKIP_DIRS]
291
+ for filename in files:
292
+ path = Path(root) / filename
293
+ if path.resolve() == SELF_PATH:
294
+ continue
295
+ if path.suffix.lower() not in CONFIG_EXTENSIONS and filename not in extra_names and not filename.startswith(".env"):
296
+ continue
297
+ result["scanned_files"] += 1
298
+ try:
299
+ content = path.read_text("utf-8", errors="ignore")
300
+ except OSError:
301
+ continue
302
+ if filename in header_files and header_pattern.search(content):
303
+ has_security_headers = True
304
+ for pattern, issue, severity in patterns:
305
+ if re.search(pattern, content, re.IGNORECASE):
306
+ result["findings"].append({"file": _relative(path, project), "issue": issue, "severity": severity})
307
+
308
+ if _looks_like_web_project(project):
309
+ checks["security_headers_config"] = has_security_headers
310
+ if not checks["security_headers_config"]:
311
+ result["findings"].append({
312
+ "issue": "No obvious security-header configuration found",
313
+ "severity": "medium",
314
+ "recommendation": "Configure CSP, HSTS, frame-ancestors/X-Frame-Options, and Referrer-Policy as appropriate.",
315
+ })
316
+ else:
317
+ checks["security_headers_config"] = "not_applicable"
318
+ result["checks"] = checks
319
+
320
+ if any(f["severity"] == "critical" for f in result["findings"]):
321
+ result["status"] = "[!!] CRITICAL: Configuration issues"
322
+ elif any(f["severity"] == "high" for f in result["findings"]):
323
+ result["status"] = "[!] HIGH: Configuration review needed"
324
+ elif result["findings"]:
325
+ result["status"] = "[?] Configuration review recommended"
326
+ return result
327
+
328
+
329
+ def run_full_scan(project_path: str, scan_type: str = "all") -> dict[str, Any]:
330
+ project = str(Path(project_path).resolve())
331
+ report: dict[str, Any] = {
332
+ "project": project,
333
+ "timestamp": datetime.now(timezone.utc).isoformat(),
334
+ "scan_type": scan_type,
335
+ "scans": {},
336
+ "summary": {"total_findings": 0, "critical": 0, "high": 0, "medium": 0, "low": 0, "overall_status": "[OK] SECURE"},
337
+ }
338
+ scanners: dict[str, tuple[str, Callable[[str], dict[str, Any]]]] = {
339
+ "deps": ("dependencies", scan_dependencies),
340
+ "secrets": ("secrets", scan_secrets),
341
+ "patterns": ("code_patterns", scan_code_patterns),
342
+ "config": ("configuration", scan_configuration),
343
+ }
344
+ for key, (name, scanner) in scanners.items():
345
+ if scan_type not in {"all", key}:
346
+ continue
347
+ scan_result = scanner(project)
348
+ report["scans"][name] = scan_result
349
+ findings = scan_result.get("findings", [])
350
+ report["summary"]["total_findings"] += len(findings)
351
+ for finding in findings:
352
+ severity = finding.get("severity", "low")
353
+ if severity in {"critical", "high", "medium", "low"}:
354
+ report["summary"][severity] += 1
355
+
356
+ summary = report["summary"]
357
+ if summary["critical"]:
358
+ summary["overall_status"] = "[!!] CRITICAL ISSUES FOUND"
359
+ elif summary["high"]:
360
+ summary["overall_status"] = "[!] HIGH RISK ISSUES"
361
+ elif summary["total_findings"]:
362
+ summary["overall_status"] = "[?] REVIEW RECOMMENDED"
363
+ return report
364
+
365
+
366
+ def _should_fail(report: dict[str, Any], threshold: str) -> bool:
367
+ if threshold == "none":
368
+ return False
369
+ required_rank = SEVERITY_RANK[threshold]
370
+ return any(
371
+ report["summary"].get(severity, 0) > 0 and rank >= required_rank
372
+ for severity, rank in SEVERITY_RANK.items()
373
+ if severity != "none"
374
+ )
375
+
376
+
377
+ def main() -> int:
378
+ parser = argparse.ArgumentParser(description="Run lightweight AG Kit security checks")
379
+ parser.add_argument("project_path", nargs="?", default=".", help="Project directory to scan")
380
+ parser.add_argument("--scan-type", choices=["all", "deps", "secrets", "patterns", "config"], default="all")
381
+ parser.add_argument("--output", choices=["json", "summary"], default="json")
382
+ parser.add_argument(
383
+ "--fail-on", choices=["none", "low", "medium", "high", "critical"], default="high",
384
+ help="Return exit code 1 when a finding at or above this severity exists (default: high)",
385
+ )
386
+ args = parser.parse_args()
387
+ project = Path(args.project_path).resolve()
388
+ if not project.is_dir():
389
+ print(json.dumps({"error": f"Directory not found: {project}"}))
390
+ return 2
391
+
392
+ report = run_full_scan(str(project), args.scan_type)
393
+ if args.output == "summary":
394
+ summary = report["summary"]
395
+ print(f"\n{'=' * 60}\nSecurity Scan: {report['project']}\n{'=' * 60}")
396
+ print(f"Status: {summary['overall_status']}")
397
+ print(f"Total Findings: {summary['total_findings']}")
398
+ print(f" Critical: {summary['critical']}\n High: {summary['high']}\n Medium: {summary['medium']}\n Low: {summary['low']}")
399
+ print("=" * 60)
400
+ for name, scan in report["scans"].items():
401
+ print(f"\n{name.upper()}: {scan['status']}")
402
+ for finding in scan.get("findings", [])[:10]:
403
+ print(f" - {finding}")
404
+ else:
405
+ print(json.dumps(report, indent=2, ensure_ascii=False))
406
+ return 1 if _should_fail(report, args.fail_on) else 0
407
+
408
+
409
+ if __name__ == "__main__":
410
+ raise SystemExit(main())
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: web-design-guidelines
3
+ description: Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
4
+ compatibility: opencode
5
+ metadata:
6
+ when_to_use: "\"When auditing web UI for best practices, checking accessibility, or reviewing design against Web Interface Guidelines.\""
7
+ version: "1.0.0"
8
+ ---
9
+ # Web Interface Guidelines
10
+
11
+ Review files for compliance with Web Interface Guidelines.
12
+
13
+ ## How It Works
14
+
15
+ 1. Fetch the latest guidelines from the source URL below
16
+ 2. Read the specified files (or prompt user for files/pattern)
17
+ 3. Check against all rules in the fetched guidelines
18
+ 4. Output findings in the terse `file:line` format
19
+
20
+ ## Guidelines Source
21
+
22
+ Fetch fresh guidelines before each review:
23
+
24
+ ```
25
+ https://raw.githubusercontent.com/vercel-labs/web-interface-guidelines/main/command.md
26
+ ```
27
+
28
+ Use WebFetch to retrieve the latest rules. The fetched content contains all the rules and output format instructions.
29
+
30
+ ## Usage
31
+
32
+ When a user provides a file or pattern argument:
33
+ 1. Fetch guidelines from the source URL above
34
+ 2. Read the specified files
35
+ 3. Apply all rules from the fetched guidelines
36
+ 4. Output findings using the format specified in the guidelines
37
+
38
+ If no files specified, ask the user which files to review.
39
+
40
+ ---
41
+
42
+ ## Related Skills
43
+
44
+ | Skill | When to Use |
45
+ |-------|-------------|
46
+ | **[frontend-design](../frontend-design/SKILL.md)** | Before coding - Learn design principles (color, typography, UX psychology) |
47
+ | **web-design-guidelines** (this) | After coding - Audit for accessibility, performance, and best practices |
48
+
49
+ ## Design Workflow
50
+
51
+ ```
52
+ 1. DESIGN → Read frontend-design principles
53
+ 2. CODE → Implement the design
54
+ 3. AUDIT → Run web-design-guidelines review ← YOU ARE HERE
55
+ 4. FIX → Address findings from audit
56
+ ```
@@ -0,0 +1,189 @@
1
+ ---
2
+ name: webapp-testing
3
+ description: Web application testing principles. E2E, Playwright, deep audit strategies.
4
+ compatibility: opencode
5
+ metadata:
6
+ when_to_use: "\"When writing E2E tests with Playwright, performing deep web app audits, or testing user flows. Use with /test workflow.\""
7
+ version: "1.0.0"
8
+ ---
9
+ # Web App Testing
10
+
11
+ > Discover and test everything. Leave no route untested.
12
+
13
+ ## 🔧 Runtime Scripts
14
+
15
+ **Execute these for automated browser testing:**
16
+
17
+ | Script | Purpose | Usage |
18
+ |--------|---------|-------|
19
+ | `.opencode/scripts/playwright_runner.py` | Basic browser test | `python .opencode/scripts/playwright_runner.py https://example.com` |
20
+ | | With screenshot | `python .opencode/scripts/playwright_runner.py <url> --screenshot` |
21
+ | | Accessibility check | `python .opencode/scripts/playwright_runner.py <url> --a11y` |
22
+
23
+ **Requires:** `pip install playwright && playwright install chromium`
24
+
25
+ ---
26
+
27
+ ## 1. Deep Audit Approach
28
+
29
+ ### Discovery First
30
+
31
+ | Target | How to Find |
32
+ |--------|-------------|
33
+ | Routes | Scan app/, pages/, router files |
34
+ | API endpoints | Grep for HTTP methods |
35
+ | Components | Find component directories |
36
+ | Features | Read documentation |
37
+
38
+ ### Systematic Testing
39
+
40
+ 1. **Map** - List all routes/APIs
41
+ 2. **Scan** - Verify they respond
42
+ 3. **Test** - Cover critical paths
43
+
44
+ ---
45
+
46
+ ## 2. Testing Pyramid for Web
47
+
48
+ ```
49
+ /\ E2E (Few)
50
+ / \ Critical user flows
51
+ /----\
52
+ / \ Integration (Some)
53
+ /--------\ API, data flow
54
+ / \
55
+ /------------\ Component (Many)
56
+ Individual UI pieces
57
+ ```
58
+
59
+ ---
60
+
61
+ ## 3. E2E Test Principles
62
+
63
+ ### What to Test
64
+
65
+ | Priority | Tests |
66
+ |----------|-------|
67
+ | 1 | Happy path user flows |
68
+ | 2 | Authentication flows |
69
+ | 3 | Critical business actions |
70
+ | 4 | Error handling |
71
+
72
+ ### E2E Best Practices
73
+
74
+ | Practice | Why |
75
+ |----------|-----|
76
+ | Use data-testid | Stable selectors |
77
+ | Wait for elements | Avoid flaky tests |
78
+ | Clean state | Independent tests |
79
+ | Avoid implementation details | Test user behavior |
80
+
81
+ ---
82
+
83
+ ## 4. Playwright Principles
84
+
85
+ ### Core Concepts
86
+
87
+ | Concept | Use |
88
+ |---------|-----|
89
+ | Page Object Model | Encapsulate page logic |
90
+ | Fixtures | Reusable test setup |
91
+ | Assertions | Built-in auto-wait |
92
+ | Trace Viewer | Debug failures |
93
+
94
+ ### Configuration
95
+
96
+ | Setting | Recommendation |
97
+ |---------|----------------|
98
+ | Retries | 2 on CI |
99
+ | Trace | on-first-retry |
100
+ | Screenshots | on-failure |
101
+ | Video | retain-on-failure |
102
+
103
+ ---
104
+
105
+ ## 5. Visual Testing
106
+
107
+ ### When to Use
108
+
109
+ | Scenario | Value |
110
+ |----------|-------|
111
+ | Design system | High |
112
+ | Marketing pages | High |
113
+ | Component library | Medium |
114
+ | Dynamic content | Lower |
115
+
116
+ ### Strategy
117
+
118
+ - Baseline screenshots
119
+ - Compare on changes
120
+ - Review visual diffs
121
+ - Update intentional changes
122
+
123
+ ---
124
+
125
+ ## 6. API Testing Principles
126
+
127
+ ### Coverage Areas
128
+
129
+ | Area | Tests |
130
+ |------|-------|
131
+ | Status codes | 200, 400, 404, 500 |
132
+ | Response shape | Matches schema |
133
+ | Error messages | User-friendly |
134
+ | Edge cases | Empty, large, special chars |
135
+
136
+ ---
137
+
138
+ ## 7. Test Organization
139
+
140
+ ### File Structure
141
+
142
+ ```
143
+ tests/
144
+ ├── e2e/ # Full user flows
145
+ ├── integration/ # API, data
146
+ ├── component/ # UI units
147
+ └── fixtures/ # Shared data
148
+ ```
149
+
150
+ ### Naming Convention
151
+
152
+ | Pattern | Example |
153
+ |---------|---------|
154
+ | Feature-based | `login.spec.ts` |
155
+ | Descriptive | `user-can-checkout.spec.ts` |
156
+
157
+ ---
158
+
159
+ ## 8. CI Integration
160
+
161
+ ### Pipeline Steps
162
+
163
+ 1. Install dependencies
164
+ 2. Install browsers
165
+ 3. Run tests
166
+ 4. Upload artifacts (traces, screenshots)
167
+
168
+ ### Parallelization
169
+
170
+ | Strategy | Use |
171
+ |----------|-----|
172
+ | Per file | Playwright default |
173
+ | Sharding | Large suites |
174
+ | Workers | Multiple browsers |
175
+
176
+ ---
177
+
178
+ ## 9. Anti-Patterns
179
+
180
+ | ❌ Don't | ✅ Do |
181
+ |----------|-------|
182
+ | Test implementation | Test behavior |
183
+ | Hardcode waits | Use auto-wait |
184
+ | Skip cleanup | Isolate tests |
185
+ | Ignore flaky tests | Fix root cause |
186
+
187
+ ---
188
+
189
+ > **Remember:** E2E tests are expensive. Use them for critical paths only.