@softspark/ai-toolkit 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.
- package/AGENTS.md +412 -0
- package/CHANGELOG.md +68 -0
- package/LICENSE +21 -0
- package/README.md +632 -0
- package/action.yml +53 -0
- package/app/.claude-plugin/plugin.json +44 -0
- package/app/ARCHITECTURE.md +306 -0
- package/app/CLAUDE.md.template +23 -0
- package/app/agents/ai-engineer.md +128 -0
- package/app/agents/backend-specialist.md +193 -0
- package/app/agents/business-intelligence.md +54 -0
- package/app/agents/chaos-monkey.md +67 -0
- package/app/agents/chief-of-staff.md +51 -0
- package/app/agents/code-archaeologist.md +127 -0
- package/app/agents/code-reviewer.md +184 -0
- package/app/agents/command-expert.md +131 -0
- package/app/agents/data-analyst.md +205 -0
- package/app/agents/data-scientist.md +151 -0
- package/app/agents/database-architect.md +317 -0
- package/app/agents/debugger.md +238 -0
- package/app/agents/devops-implementer.md +194 -0
- package/app/agents/documenter.md +364 -0
- package/app/agents/explorer-agent.md +145 -0
- package/app/agents/fact-checker.md +172 -0
- package/app/agents/frontend-specialist.md +209 -0
- package/app/agents/game-developer.md +216 -0
- package/app/agents/incident-responder.md +226 -0
- package/app/agents/infrastructure-architect.md +127 -0
- package/app/agents/infrastructure-validator.md +247 -0
- package/app/agents/llm-ops-engineer.md +237 -0
- package/app/agents/mcp-expert.md +228 -0
- package/app/agents/mcp-server-architect.md +195 -0
- package/app/agents/mcp-testing-engineer.md +292 -0
- package/app/agents/meta-architect.md +58 -0
- package/app/agents/ml-engineer.md +136 -0
- package/app/agents/mobile-developer.md +190 -0
- package/app/agents/night-watchman.md +55 -0
- package/app/agents/nlp-engineer.md +154 -0
- package/app/agents/orchestrator.md +437 -0
- package/app/agents/performance-optimizer.md +254 -0
- package/app/agents/predictive-analyst.md +57 -0
- package/app/agents/product-manager.md +194 -0
- package/app/agents/project-planner.md +287 -0
- package/app/agents/prompt-engineer.md +103 -0
- package/app/agents/qa-automation-engineer.md +182 -0
- package/app/agents/rag-engineer.md +201 -0
- package/app/agents/research-synthesizer.md +138 -0
- package/app/agents/search-specialist.md +101 -0
- package/app/agents/security-architect.md +62 -0
- package/app/agents/security-auditor.md +293 -0
- package/app/agents/seo-specialist.md +111 -0
- package/app/agents/system-governor.md +57 -0
- package/app/agents/tech-lead.md +62 -0
- package/app/agents/technical-researcher.md +103 -0
- package/app/agents/test-engineer.md +264 -0
- package/app/constitution.md +38 -0
- package/app/hooks/_profile-check.sh +11 -0
- package/app/hooks/guard-destructive.sh +74 -0
- package/app/hooks/guard-path.sh +73 -0
- package/app/hooks/post-tool-use.sh +35 -0
- package/app/hooks/pre-compact.sh +31 -0
- package/app/hooks/quality-check.sh +22 -0
- package/app/hooks/quality-gate.sh +49 -0
- package/app/hooks/save-session.sh +24 -0
- package/app/hooks/session-end.sh +37 -0
- package/app/hooks/session-start.sh +29 -0
- package/app/hooks/subagent-start.sh +16 -0
- package/app/hooks/subagent-stop.sh +16 -0
- package/app/hooks/track-usage.sh +50 -0
- package/app/hooks/user-prompt-submit.sh +25 -0
- package/app/hooks.json +178 -0
- package/app/mcp-defaults.json +23 -0
- package/app/output-styles/golden-rules.md +43 -0
- package/app/plugins/README.md +19 -0
- package/app/plugins/csharp-pack/README.md +11 -0
- package/app/plugins/csharp-pack/plugin.json +18 -0
- package/app/plugins/enterprise-pack/README.md +16 -0
- package/app/plugins/enterprise-pack/hooks/output-style.sh +6 -0
- package/app/plugins/enterprise-pack/hooks/status-line.sh +8 -0
- package/app/plugins/enterprise-pack/plugin.json +24 -0
- package/app/plugins/frontend-pack/README.md +14 -0
- package/app/plugins/frontend-pack/plugin.json +22 -0
- package/app/plugins/java-pack/README.md +11 -0
- package/app/plugins/java-pack/plugin.json +18 -0
- package/app/plugins/kotlin-pack/README.md +11 -0
- package/app/plugins/kotlin-pack/plugin.json +18 -0
- package/app/plugins/memory-pack/README.md +24 -0
- package/app/plugins/memory-pack/hooks/observation-capture.sh +67 -0
- package/app/plugins/memory-pack/hooks/session-summary.sh +71 -0
- package/app/plugins/memory-pack/plugin.json +22 -0
- package/app/plugins/memory-pack/scripts/init_db.py +81 -0
- package/app/plugins/memory-pack/scripts/strip_private.py +22 -0
- package/app/plugins/memory-pack/skills/mem-search/SKILL.md +70 -0
- package/app/plugins/research-pack/README.md +14 -0
- package/app/plugins/research-pack/plugin.json +22 -0
- package/app/plugins/ruby-pack/README.md +11 -0
- package/app/plugins/ruby-pack/plugin.json +18 -0
- package/app/plugins/rust-pack/README.md +11 -0
- package/app/plugins/rust-pack/plugin.json +18 -0
- package/app/plugins/security-pack/README.md +15 -0
- package/app/plugins/security-pack/plugin.json +23 -0
- package/app/plugins/swift-pack/README.md +11 -0
- package/app/plugins/swift-pack/plugin.json +18 -0
- package/app/rules/claude-toolkit-rules.md +21 -0
- package/app/rules/git-conventions.md +5 -0
- package/app/rules/quality-gates.md +10 -0
- package/app/skills/_lib/__init__.py +1 -0
- package/app/skills/_lib/detect_utils.py +150 -0
- package/app/skills/agent-creator/SKILL.md +82 -0
- package/app/skills/analyze/SKILL.md +92 -0
- package/app/skills/analyze/scripts/complexity.py +165 -0
- package/app/skills/api-patterns/SKILL.md +305 -0
- package/app/skills/app-builder/SKILL.md +187 -0
- package/app/skills/architecture-audit/SKILL.md +141 -0
- package/app/skills/architecture-decision/SKILL.md +55 -0
- package/app/skills/architecture-decision/templates/adr-template.md +36 -0
- package/app/skills/biz-scan/SKILL.md +30 -0
- package/app/skills/briefing/SKILL.md +27 -0
- package/app/skills/build/SKILL.md +97 -0
- package/app/skills/build/scripts/detect-build.py +151 -0
- package/app/skills/chaos/SKILL.md +32 -0
- package/app/skills/ci/SKILL.md +77 -0
- package/app/skills/ci/scripts/ci-detect.py +135 -0
- package/app/skills/ci/templates/github-actions-node.yml +38 -0
- package/app/skills/ci/templates/github-actions-python.yml +42 -0
- package/app/skills/ci-cd-patterns/SKILL.md +299 -0
- package/app/skills/clean-code/SKILL.md +110 -0
- package/app/skills/clean-code/reference/dart.md +18 -0
- package/app/skills/clean-code/reference/go.md +23 -0
- package/app/skills/clean-code/reference/php.md +32 -0
- package/app/skills/clean-code/reference/python.md +180 -0
- package/app/skills/clean-code/reference/typescript.md +26 -0
- package/app/skills/command-creator/SKILL.md +83 -0
- package/app/skills/commit/SKILL.md +98 -0
- package/app/skills/commit/scripts/pre-commit-check.py +87 -0
- package/app/skills/commit/templates/conventional-commit.md +52 -0
- package/app/skills/csharp-patterns/SKILL.md +450 -0
- package/app/skills/database-patterns/SKILL.md +297 -0
- package/app/skills/debug/SKILL.md +154 -0
- package/app/skills/debug/scripts/error-parser.py +187 -0
- package/app/skills/debugging-tactics/SKILL.md +136 -0
- package/app/skills/deploy/SKILL.md +130 -0
- package/app/skills/deploy/scripts/pre_deploy_check.py +171 -0
- package/app/skills/deploy/templates/deployment-checklist.md +31 -0
- package/app/skills/design-an-interface/SKILL.md +105 -0
- package/app/skills/design-engineering/SKILL.md +260 -0
- package/app/skills/docker-devops/SKILL.md +303 -0
- package/app/skills/docs/SKILL.md +145 -0
- package/app/skills/docs/scripts/doc-inventory.py +176 -0
- package/app/skills/docs/templates/adr-template.md +36 -0
- package/app/skills/docs/templates/readme-template.md +67 -0
- package/app/skills/documentation-standards/SKILL.md +191 -0
- package/app/skills/ecommerce-patterns/SKILL.md +209 -0
- package/app/skills/evaluate/SKILL.md +132 -0
- package/app/skills/evolve/SKILL.md +27 -0
- package/app/skills/explain/SKILL.md +54 -0
- package/app/skills/explain/scripts/dependency-graph.py +215 -0
- package/app/skills/explore/SKILL.md +112 -0
- package/app/skills/explore/scripts/visualize.py +117 -0
- package/app/skills/fix/SKILL.md +78 -0
- package/app/skills/fix/scripts/error-classifier.py +191 -0
- package/app/skills/flutter-patterns/SKILL.md +254 -0
- package/app/skills/git-mastery/SKILL.md +70 -0
- package/app/skills/grill-me/SKILL.md +38 -0
- package/app/skills/health/SKILL.md +91 -0
- package/app/skills/health/scripts/health_check.py +162 -0
- package/app/skills/hive-mind/SKILL.md +56 -0
- package/app/skills/hook-creator/SKILL.md +107 -0
- package/app/skills/index/SKILL.md +74 -0
- package/app/skills/instinct-review/SKILL.md +77 -0
- package/app/skills/java-patterns/SKILL.md +442 -0
- package/app/skills/kotlin-patterns/SKILL.md +446 -0
- package/app/skills/lint/SKILL.md +103 -0
- package/app/skills/lint/scripts/detect-linters.py +112 -0
- package/app/skills/mcp-patterns/SKILL.md +270 -0
- package/app/skills/mem-search/SKILL.md +70 -0
- package/app/skills/migrate/SKILL.md +90 -0
- package/app/skills/migrate/scripts/migration-status.py +195 -0
- package/app/skills/migration-patterns/SKILL.md +260 -0
- package/app/skills/night-watch/SKILL.md +28 -0
- package/app/skills/observability-patterns/SKILL.md +203 -0
- package/app/skills/onboard/SKILL.md +76 -0
- package/app/skills/orchestrate/SKILL.md +86 -0
- package/app/skills/panic/SKILL.md +30 -0
- package/app/skills/performance-profiling/SKILL.md +59 -0
- package/app/skills/plan/SKILL.md +110 -0
- package/app/skills/plan/templates/plan-template.md +40 -0
- package/app/skills/plan-writing/SKILL.md +201 -0
- package/app/skills/plugin-creator/SKILL.md +78 -0
- package/app/skills/pr/SKILL.md +129 -0
- package/app/skills/pr/scripts/pr-summary.py +175 -0
- package/app/skills/prd-to-issues/SKILL.md +108 -0
- package/app/skills/prd-to-plan/SKILL.md +120 -0
- package/app/skills/predict/SKILL.md +30 -0
- package/app/skills/qa-session/SKILL.md +110 -0
- package/app/skills/rag-patterns/SKILL.md +203 -0
- package/app/skills/refactor/SKILL.md +124 -0
- package/app/skills/refactor/scripts/refactor-scan.py +210 -0
- package/app/skills/refactor-plan/SKILL.md +112 -0
- package/app/skills/repeat/SKILL.md +149 -0
- package/app/skills/research-mastery/SKILL.md +56 -0
- package/app/skills/review/SKILL.md +141 -0
- package/app/skills/review/scripts/diff-analyzer.py +170 -0
- package/app/skills/rollback/SKILL.md +87 -0
- package/app/skills/rollback/scripts/rollback_info.py +149 -0
- package/app/skills/ruby-patterns/SKILL.md +454 -0
- package/app/skills/rust-patterns/SKILL.md +446 -0
- package/app/skills/search/SKILL.md +64 -0
- package/app/skills/security-patterns/SKILL.md +91 -0
- package/app/skills/security-patterns/reference/authentication.md +37 -0
- package/app/skills/security-patterns/reference/authorization.md +22 -0
- package/app/skills/security-patterns/reference/input-validation.md +30 -0
- package/app/skills/security-patterns/reference/oauth-csrf-audit.md +131 -0
- package/app/skills/skill-creator/SKILL.md +154 -0
- package/app/skills/skill-creator/templates/dashboard/index.html +130 -0
- package/app/skills/skill-creator/templates/reasoning-engine/assets/example.json +12 -0
- package/app/skills/skill-creator/templates/reasoning-engine/search.py +110 -0
- package/app/skills/subagent-development/SKILL.md +225 -0
- package/app/skills/subagent-development/reference/code-quality-reviewer-prompt.md +145 -0
- package/app/skills/subagent-development/reference/implementer-prompt.md +118 -0
- package/app/skills/subagent-development/reference/spec-reviewer-prompt.md +100 -0
- package/app/skills/swarm/SKILL.md +81 -0
- package/app/skills/swift-patterns/SKILL.md +500 -0
- package/app/skills/tdd/SKILL.md +174 -0
- package/app/skills/tdd/reference/deep-modules.md +32 -0
- package/app/skills/tdd/reference/interface-design.md +32 -0
- package/app/skills/tdd/reference/mocking.md +52 -0
- package/app/skills/tdd/reference/refactoring.md +10 -0
- package/app/skills/tdd/reference/tests.md +59 -0
- package/app/skills/teams/SKILL.md +101 -0
- package/app/skills/test/SKILL.md +107 -0
- package/app/skills/test/scripts/detect-runner.py +113 -0
- package/app/skills/testing-patterns/SKILL.md +73 -0
- package/app/skills/testing-patterns/reference/flutter-testing.md +33 -0
- package/app/skills/testing-patterns/reference/go-testing.md +52 -0
- package/app/skills/testing-patterns/reference/php-phpunit.md +39 -0
- package/app/skills/testing-patterns/reference/python-pytest.md +228 -0
- package/app/skills/testing-patterns/reference/typescript-vitest.md +50 -0
- package/app/skills/triage-issue/SKILL.md +120 -0
- package/app/skills/typescript-patterns/SKILL.md +256 -0
- package/app/skills/ubiquitous-language/SKILL.md +74 -0
- package/app/skills/verification-before-completion/SKILL.md +108 -0
- package/app/skills/workflow/SKILL.md +250 -0
- package/app/skills/write-a-prd/SKILL.md +129 -0
- package/app/skills/write-a-prd/reference/visual-companion.md +78 -0
- package/app/skills/write-a-prd/scripts/frame-template.html +111 -0
- package/app/skills/write-a-prd/scripts/visual-server.cjs +79 -0
- package/app/templates/skill/generator/SKILL.md.template +40 -0
- package/app/templates/skill/knowledge/SKILL.md.template +52 -0
- package/app/templates/skill/linter/SKILL.md.template +34 -0
- package/app/templates/skill/reviewer/SKILL.md.template +51 -0
- package/app/templates/skill/workflow/SKILL.md.template +49 -0
- package/benchmarks/README.md +111 -0
- package/benchmarks/ecosystem-dashboard.json +148 -0
- package/benchmarks/ecosystem-harvest.json +148 -0
- package/benchmarks/results.json +38 -0
- package/benchmarks/run.py +351 -0
- package/bin/ai-toolkit.js +345 -0
- package/kb/best-practices/README.md +11 -0
- package/kb/howto/README.md +11 -0
- package/kb/procedures/maintenance-sop.md +306 -0
- package/kb/reference/agents-catalog.md +124 -0
- package/kb/reference/anti-pattern-registry-format.md +221 -0
- package/kb/reference/architecture-overview.md +232 -0
- package/kb/reference/benchmark-config.md +62 -0
- package/kb/reference/ci-integration.md +66 -0
- package/kb/reference/claude-ecosystem-benchmark-snapshot.md +80 -0
- package/kb/reference/claude-ecosystem-expansion-foundations.md +102 -0
- package/kb/reference/commands-catalog.md +21 -0
- package/kb/reference/distribution-model.md +63 -0
- package/kb/reference/global-install-model.md +56 -0
- package/kb/reference/hierarchical-override-pattern.md +200 -0
- package/kb/reference/hooks-catalog.md +306 -0
- package/kb/reference/integrations.md +88 -0
- package/kb/reference/language-packs.md +52 -0
- package/kb/reference/merge-friendly-install-model.md +58 -0
- package/kb/reference/plugin-pack-conventions.md +151 -0
- package/kb/reference/quick-wins-implementation-summary.md +70 -0
- package/kb/reference/skill-templates.md +50 -0
- package/kb/reference/skills-catalog.md +215 -0
- package/kb/reference/skills-unification.md +57 -0
- package/kb/reference/stats.md +69 -0
- package/kb/reference/sync.md +76 -0
- package/kb/troubleshooting/README.md +11 -0
- package/llms-full.txt +3068 -0
- package/llms.txt +39 -0
- package/package.json +75 -0
- package/scripts/_common.py +160 -0
- package/scripts/add_rule.py +50 -0
- package/scripts/benchmark_config.py +127 -0
- package/scripts/benchmark_ecosystem.py +288 -0
- package/scripts/check_deps.py +260 -0
- package/scripts/create_skill.py +118 -0
- package/scripts/doctor.py +504 -0
- package/scripts/eject.py +113 -0
- package/scripts/emission.py +256 -0
- package/scripts/evaluate_skills.py +260 -0
- package/scripts/frontmatter.py +58 -0
- package/scripts/generate_agents_md.py +91 -0
- package/scripts/generate_aider_conf.py +51 -0
- package/scripts/generate_cline.py +35 -0
- package/scripts/generate_copilot.py +30 -0
- package/scripts/generate_cursor_rules.py +35 -0
- package/scripts/generate_gemini.py +28 -0
- package/scripts/generate_llms_txt.py +164 -0
- package/scripts/generate_roo_modes.py +80 -0
- package/scripts/generate_windsurf.py +35 -0
- package/scripts/generator_base.py +140 -0
- package/scripts/harvest_ecosystem.py +50 -0
- package/scripts/inject_rule_cli.py +101 -0
- package/scripts/inject_section_cli.py +47 -0
- package/scripts/injection.py +180 -0
- package/scripts/install.py +236 -0
- package/scripts/install_git_hooks.py +71 -0
- package/scripts/install_steps/__init__.py +5 -0
- package/scripts/install_steps/ai_tools.py +261 -0
- package/scripts/install_steps/hooks.py +90 -0
- package/scripts/install_steps/markers.py +79 -0
- package/scripts/install_steps/symlinks.py +87 -0
- package/scripts/merge-hooks.py +192 -0
- package/scripts/plugin.py +642 -0
- package/scripts/plugin_schema.py +138 -0
- package/scripts/remove_rule.py +58 -0
- package/scripts/stats.py +81 -0
- package/scripts/sync.py +215 -0
- package/scripts/uninstall.py +292 -0
- package/scripts/validate.py +700 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# OAuth2, CSRF Protection & Audit Logging
|
|
2
|
+
|
|
3
|
+
## OAuth2 Flows
|
|
4
|
+
|
|
5
|
+
### Authorization Code Flow (FastAPI)
|
|
6
|
+
```python
|
|
7
|
+
from authlib.integrations.starlette_client import OAuth
|
|
8
|
+
from starlette.config import Config
|
|
9
|
+
|
|
10
|
+
config = Config('.env')
|
|
11
|
+
oauth = OAuth(config)
|
|
12
|
+
|
|
13
|
+
oauth.register(
|
|
14
|
+
name='google',
|
|
15
|
+
client_id=config('GOOGLE_CLIENT_ID'),
|
|
16
|
+
client_secret=config('GOOGLE_CLIENT_SECRET'),
|
|
17
|
+
authorize_url='https://accounts.google.com/o/oauth2/auth',
|
|
18
|
+
access_token_url='https://oauth2.googleapis.com/token',
|
|
19
|
+
client_kwargs={'scope': 'openid email profile'},
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
@app.get('/login')
|
|
23
|
+
async def login(request: Request):
|
|
24
|
+
redirect_uri = request.url_for('auth_callback')
|
|
25
|
+
return await oauth.google.authorize_redirect(request, redirect_uri)
|
|
26
|
+
|
|
27
|
+
@app.get('/auth/callback')
|
|
28
|
+
async def auth_callback(request: Request):
|
|
29
|
+
token = await oauth.google.authorize_access_token(request)
|
|
30
|
+
user_info = token.get('userinfo')
|
|
31
|
+
return {"email": user_info['email']}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## CSRF Protection
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from fastapi import FastAPI, Request, Depends
|
|
40
|
+
from fastapi_csrf_protect import CsrfProtect
|
|
41
|
+
from pydantic import BaseModel
|
|
42
|
+
|
|
43
|
+
class CsrfSettings(BaseModel):
|
|
44
|
+
secret_key: str = "your-secret-key-min-32-chars-long!"
|
|
45
|
+
cookie_samesite: str = "lax"
|
|
46
|
+
cookie_secure: bool = True
|
|
47
|
+
|
|
48
|
+
@CsrfProtect.load_config
|
|
49
|
+
def get_csrf_config():
|
|
50
|
+
return CsrfSettings()
|
|
51
|
+
|
|
52
|
+
@app.get("/csrf-token")
|
|
53
|
+
async def get_csrf_token(csrf_protect: CsrfProtect = Depends()):
|
|
54
|
+
token = csrf_protect.generate_csrf()
|
|
55
|
+
return {"csrf_token": token}
|
|
56
|
+
|
|
57
|
+
@app.post("/protected")
|
|
58
|
+
async def protected_route(request: Request, csrf_protect: CsrfProtect = Depends()):
|
|
59
|
+
await csrf_protect.validate_csrf(request)
|
|
60
|
+
return {"status": "ok"}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### CSRF Best Practices
|
|
64
|
+
| Technique | Implementation |
|
|
65
|
+
|-----------|---------------|
|
|
66
|
+
| SameSite Cookie | `cookie_samesite: "strict"` or `"lax"` |
|
|
67
|
+
| Double Submit | Token in cookie + header |
|
|
68
|
+
| Origin Validation | Check `Origin`/`Referer` headers |
|
|
69
|
+
| Secure Flag | `cookie_secure: True` in production |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Audit Logging
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
import structlog
|
|
77
|
+
from enum import Enum
|
|
78
|
+
from datetime import datetime
|
|
79
|
+
from typing import Any
|
|
80
|
+
|
|
81
|
+
logger = structlog.get_logger()
|
|
82
|
+
|
|
83
|
+
class AuditAction(str, Enum):
|
|
84
|
+
CREATE = "create"
|
|
85
|
+
READ = "read"
|
|
86
|
+
UPDATE = "update"
|
|
87
|
+
DELETE = "delete"
|
|
88
|
+
LOGIN = "login"
|
|
89
|
+
LOGOUT = "logout"
|
|
90
|
+
ACCESS_DENIED = "access_denied"
|
|
91
|
+
|
|
92
|
+
def audit_log(
|
|
93
|
+
action: AuditAction,
|
|
94
|
+
user_id: str,
|
|
95
|
+
resource: str,
|
|
96
|
+
resource_id: str | None = None,
|
|
97
|
+
details: dict[str, Any] | None = None,
|
|
98
|
+
ip_address: str | None = None
|
|
99
|
+
) -> None:
|
|
100
|
+
logger.info(
|
|
101
|
+
"audit_event",
|
|
102
|
+
action=action.value,
|
|
103
|
+
user_id=user_id,
|
|
104
|
+
resource=resource,
|
|
105
|
+
resource_id=resource_id,
|
|
106
|
+
details=details or {},
|
|
107
|
+
ip_address=ip_address,
|
|
108
|
+
timestamp=datetime.utcnow().isoformat()
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# Usage in FastAPI
|
|
112
|
+
@app.delete("/users/{user_id}")
|
|
113
|
+
async def delete_user(user_id: str, request: Request, current_user: User = Depends()):
|
|
114
|
+
audit_log(
|
|
115
|
+
action=AuditAction.DELETE,
|
|
116
|
+
user_id=current_user.id,
|
|
117
|
+
resource="users",
|
|
118
|
+
resource_id=user_id,
|
|
119
|
+
ip_address=request.client.host
|
|
120
|
+
)
|
|
121
|
+
# ... delete logic
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Audit Log Requirements
|
|
125
|
+
| Event | Must Log |
|
|
126
|
+
|-------|----------|
|
|
127
|
+
| Authentication | Login, logout, failed attempts |
|
|
128
|
+
| Authorization | Access denied, permission changes |
|
|
129
|
+
| Data Changes | Create, update, delete with before/after |
|
|
130
|
+
| Admin Actions | User management, config changes |
|
|
131
|
+
| Security Events | Password reset, MFA changes |
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-creator
|
|
3
|
+
description: "Create new skills from templates with guided workflow"
|
|
4
|
+
effort: high
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
argument-hint: "[skill name or description]"
|
|
7
|
+
allowed-tools: Read, Write, Edit, Bash, Grep, Glob
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Skill Creator
|
|
11
|
+
|
|
12
|
+
$ARGUMENTS
|
|
13
|
+
|
|
14
|
+
Create a new skill following the Agent Skills standard.
|
|
15
|
+
|
|
16
|
+
## Workflow
|
|
17
|
+
|
|
18
|
+
1. **Capture intent** -- ask: what should the skill do? Who invokes it?
|
|
19
|
+
2. **Classify** -- task, hybrid, or knowledge? (see Classification Guide below)
|
|
20
|
+
3. **Interview** -- gather: framework, tools, scope, output format, constraints
|
|
21
|
+
4. **Write SKILL.md** -- frontmatter + body, under 500 lines
|
|
22
|
+
5. **Create supporting files** -- reference/, templates/, scripts/ as needed
|
|
23
|
+
6. **Test and iterate** -- invoke, observe, refine
|
|
24
|
+
|
|
25
|
+
## Frontmatter Reference
|
|
26
|
+
|
|
27
|
+
| Field | Type | Required | Description |
|
|
28
|
+
|-------|------|----------|-------------|
|
|
29
|
+
| `name` | string | yes | Lowercase, hyphens only, max 64 chars |
|
|
30
|
+
| `description` | string | yes | Third person, max 1024 chars, include key terms |
|
|
31
|
+
| `effort` | low/medium/high/max | no | Controls model thinking budget |
|
|
32
|
+
| `disable-model-invocation` | bool | no | `true` = only user can trigger (task skills) |
|
|
33
|
+
| `user-invocable` | bool | no | `false` = knowledge skill, Claude auto-loads |
|
|
34
|
+
| `allowed-tools` | csv | no | Restrict tool access for safety |
|
|
35
|
+
| `model` | string | no | Override default model |
|
|
36
|
+
| `context` | string | no | `fork` to run in isolated subagent |
|
|
37
|
+
| `agent` | string | no | Agent type to use when `context: fork` |
|
|
38
|
+
| `argument-hint` | string | no | Shown in autocomplete, e.g. `"[target]"` |
|
|
39
|
+
| `hooks` | object | no | Lifecycle hooks (PreToolUse, PostToolUse, Stop) |
|
|
40
|
+
|
|
41
|
+
## Classification Guide
|
|
42
|
+
|
|
43
|
+
| Type | When to use | Key fields |
|
|
44
|
+
|------|-------------|------------|
|
|
45
|
+
| **Task** | User-triggered actions with side effects (build, deploy, commit) | `disable-model-invocation: true`, `allowed-tools` |
|
|
46
|
+
| **Hybrid** | Both user and Claude invoke (review, analyze) | defaults |
|
|
47
|
+
| **Knowledge** | Domain patterns Claude auto-loads (clean-code, api-patterns) | `user-invocable: false` |
|
|
48
|
+
|
|
49
|
+
## Writing Guidelines
|
|
50
|
+
|
|
51
|
+
- **Description**: third person ("Generates...", "Provides..."), include searchable key terms
|
|
52
|
+
- **Name**: lowercase, hyphens, max 64 chars -- match the directory name
|
|
53
|
+
- **Length**: SKILL.md under 500 lines; use `reference/` for overflow
|
|
54
|
+
- **Be concise**: Claude is smart -- give structure, not lectures
|
|
55
|
+
- **Degrees of freedom**: be specific on format/constraints, flexible on implementation
|
|
56
|
+
- **File references**: max 1 level deep (e.g., `reference/details.md`)
|
|
57
|
+
- **Use `$ARGUMENTS`**: place it early so user input is visible
|
|
58
|
+
- **Tables over prose**: for options, patterns, mappings
|
|
59
|
+
|
|
60
|
+
## Directory Structure
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
skill-name/
|
|
64
|
+
SKILL.md # Main instructions (required, <500 lines)
|
|
65
|
+
reference/ # Detailed docs (loaded on-demand)
|
|
66
|
+
templates/ # Reusable templates for output
|
|
67
|
+
scripts/ # Executable helper scripts
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Only create subdirectories when the skill needs them. Most skills are a single SKILL.md.
|
|
71
|
+
|
|
72
|
+
## SKILL.md Template
|
|
73
|
+
|
|
74
|
+
```markdown
|
|
75
|
+
---
|
|
76
|
+
name: {name}
|
|
77
|
+
description: "{Third-person description with key terms}"
|
|
78
|
+
argument-hint: "[hint]"
|
|
79
|
+
allowed-tools: Read, Grep, Glob
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
# {Title}
|
|
83
|
+
|
|
84
|
+
$ARGUMENTS
|
|
85
|
+
|
|
86
|
+
{One-line purpose statement.}
|
|
87
|
+
|
|
88
|
+
## Usage
|
|
89
|
+
|
|
90
|
+
\`\`\`
|
|
91
|
+
/{name} [arguments]
|
|
92
|
+
\`\`\`
|
|
93
|
+
|
|
94
|
+
## What This Command Does
|
|
95
|
+
|
|
96
|
+
1. **Step one**
|
|
97
|
+
2. **Step two**
|
|
98
|
+
3. **Step three**
|
|
99
|
+
|
|
100
|
+
## Output Format
|
|
101
|
+
|
|
102
|
+
{Expected output structure}
|
|
103
|
+
|
|
104
|
+
## Rules
|
|
105
|
+
|
|
106
|
+
- {Constraint 1}
|
|
107
|
+
- {Constraint 2}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Quality Checklist
|
|
111
|
+
|
|
112
|
+
Before finalizing, verify:
|
|
113
|
+
|
|
114
|
+
- [ ] Description is specific with searchable key terms
|
|
115
|
+
- [ ] SKILL.md is under 500 lines
|
|
116
|
+
- [ ] No time-sensitive information (versions, dates)
|
|
117
|
+
- [ ] Consistent terminology throughout
|
|
118
|
+
- [ ] Examples are concrete, not abstract
|
|
119
|
+
- [ ] File references max 1 level deep
|
|
120
|
+
- [ ] Workflows have numbered steps
|
|
121
|
+
- [ ] Frontmatter fields match classification type
|
|
122
|
+
- [ ] `$ARGUMENTS` is present for task/hybrid skills
|
|
123
|
+
- [ ] `allowed-tools` is minimal (principle of least privilege)
|
|
124
|
+
|
|
125
|
+
## Evaluation
|
|
126
|
+
|
|
127
|
+
After creating the skill, test it:
|
|
128
|
+
|
|
129
|
+
1. Invoke with a representative prompt
|
|
130
|
+
2. Check output matches expected structure
|
|
131
|
+
3. Verify dynamic injection (`$ARGUMENTS`) works
|
|
132
|
+
4. Test with varied argument patterns
|
|
133
|
+
5. Confirm `allowed-tools` are sufficient but not excessive
|
|
134
|
+
6. Iterate: tighten instructions where output diverges
|
|
135
|
+
|
|
136
|
+
## Installation
|
|
137
|
+
|
|
138
|
+
After creating the skill:
|
|
139
|
+
|
|
140
|
+
1. Verify the skill directory exists under `app/skills/{name}/`
|
|
141
|
+
2. Update `skills-catalog.md` if it exists
|
|
142
|
+
3. Update `ARCHITECTURE.md` skill counts if referenced
|
|
143
|
+
4. Run `validate.sh` if available
|
|
144
|
+
5. Run `evaluate-skills.sh` if available
|
|
145
|
+
|
|
146
|
+
## Common Mistakes
|
|
147
|
+
|
|
148
|
+
| Mistake | Fix |
|
|
149
|
+
|---------|-----|
|
|
150
|
+
| Description too vague | Add specific terms: "Python", "REST API", "migration" |
|
|
151
|
+
| SKILL.md too long | Move details to `reference/` subdirectory |
|
|
152
|
+
| Missing `$ARGUMENTS` | Add after the H1 heading for task/hybrid skills |
|
|
153
|
+
| Over-specifying steps | Give structure, let Claude fill details |
|
|
154
|
+
| Wrong classification | Task = side effects, Knowledge = patterns, Hybrid = both |
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>ai-toolkit Dashboard</title>
|
|
7
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"></script>
|
|
8
|
+
<style>
|
|
9
|
+
:root { --bg: #0d1117; --surface: #161b22; --border: #30363d; --text: #e6edf3; --muted: #8b949e; --accent: #58a6ff; --green: #3fb950; }
|
|
10
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
11
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; background: var(--bg); color: var(--text); min-height: 100vh; padding: 24px; }
|
|
12
|
+
h1 { font-size: 1.5rem; font-weight: 600; margin-bottom: 8px; }
|
|
13
|
+
.subtitle { color: var(--muted); margin-bottom: 24px; font-size: 0.875rem; }
|
|
14
|
+
.stats-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; margin-bottom: 24px; }
|
|
15
|
+
.stat-card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 16px; }
|
|
16
|
+
.stat-card .label { color: var(--muted); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; }
|
|
17
|
+
.stat-card .value { font-size: 2rem; font-weight: 700; color: var(--accent); margin-top: 4px; }
|
|
18
|
+
.charts { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 24px; }
|
|
19
|
+
.chart-card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 16px; }
|
|
20
|
+
.chart-card h2 { font-size: 0.875rem; color: var(--muted); margin-bottom: 12px; text-transform: uppercase; letter-spacing: 0.05em; }
|
|
21
|
+
.upload-area { background: var(--surface); border: 2px dashed var(--border); border-radius: 8px; padding: 32px; text-align: center; cursor: pointer; transition: border-color 0.2s; }
|
|
22
|
+
.upload-area:hover { border-color: var(--accent); }
|
|
23
|
+
.upload-area p { color: var(--muted); margin-top: 8px; font-size: 0.875rem; }
|
|
24
|
+
#file-input { display: none; }
|
|
25
|
+
#paste-area { width: 100%; min-height: 80px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; color: var(--text); padding: 12px; font-family: monospace; font-size: 0.8rem; margin-top: 12px; resize: vertical; }
|
|
26
|
+
button { background: var(--accent); color: var(--bg); border: none; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-weight: 600; margin-top: 8px; }
|
|
27
|
+
button:hover { opacity: 0.9; }
|
|
28
|
+
#dashboard { display: none; }
|
|
29
|
+
@media (max-width: 768px) { .charts { grid-template-columns: 1fr; } }
|
|
30
|
+
</style>
|
|
31
|
+
</head>
|
|
32
|
+
<body>
|
|
33
|
+
<h1>ai-toolkit Dashboard</h1>
|
|
34
|
+
<p class="subtitle">Load stats.json to visualize skill usage, top agents, and session metrics.</p>
|
|
35
|
+
|
|
36
|
+
<div id="loader">
|
|
37
|
+
<div class="upload-area" onclick="document.getElementById('file-input').click()">
|
|
38
|
+
<strong>Drop stats.json or click to upload</strong>
|
|
39
|
+
<p>Or paste JSON below and click Load</p>
|
|
40
|
+
</div>
|
|
41
|
+
<input type="file" id="file-input" accept=".json">
|
|
42
|
+
<textarea id="paste-area" placeholder='{"skills": {...}, "agents": {...}, "sessions": 0}'></textarea>
|
|
43
|
+
<button onclick="loadFromPaste()">Load</button>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div id="dashboard">
|
|
47
|
+
<div class="stats-row">
|
|
48
|
+
<div class="stat-card"><div class="label">Total Sessions</div><div class="value" id="total-sessions">0</div></div>
|
|
49
|
+
<div class="stat-card"><div class="label">Skills Used</div><div class="value" id="skills-used">0</div></div>
|
|
50
|
+
<div class="stat-card"><div class="label">Top Agent</div><div class="value" id="top-agent" style="font-size:1.2rem">-</div></div>
|
|
51
|
+
<div class="stat-card"><div class="label">Most Used Skill</div><div class="value" id="top-skill" style="font-size:1.2rem">-</div></div>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="charts">
|
|
54
|
+
<div class="chart-card"><h2>Skill Usage Frequency</h2><canvas id="skills-chart"></canvas></div>
|
|
55
|
+
<div class="chart-card"><h2>Top Agents</h2><canvas id="agents-chart"></canvas></div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<script>
|
|
60
|
+
let skillsChart = null, agentsChart = null;
|
|
61
|
+
|
|
62
|
+
document.getElementById('file-input').addEventListener('change', (e) => {
|
|
63
|
+
const file = e.target.files[0];
|
|
64
|
+
if (!file) return;
|
|
65
|
+
const reader = new FileReader();
|
|
66
|
+
reader.onload = (ev) => render(JSON.parse(ev.target.result));
|
|
67
|
+
reader.readAsText(file);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
function loadFromPaste() {
|
|
71
|
+
const raw = document.getElementById('paste-area').value.trim();
|
|
72
|
+
if (!raw) return;
|
|
73
|
+
try { render(JSON.parse(raw)); } catch (err) { alert('Invalid JSON: ' + err.message); }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function render(data) {
|
|
77
|
+
document.getElementById('loader').style.display = 'none';
|
|
78
|
+
document.getElementById('dashboard').style.display = 'block';
|
|
79
|
+
|
|
80
|
+
const skills = data.skills || {};
|
|
81
|
+
const agents = data.agents || {};
|
|
82
|
+
const sessions = data.sessions || 0;
|
|
83
|
+
|
|
84
|
+
document.getElementById('total-sessions').textContent = sessions;
|
|
85
|
+
document.getElementById('skills-used').textContent = Object.keys(skills).length;
|
|
86
|
+
|
|
87
|
+
const sortedSkills = Object.entries(skills).sort((a, b) => b[1] - a[1]);
|
|
88
|
+
const sortedAgents = Object.entries(agents).sort((a, b) => b[1] - a[1]);
|
|
89
|
+
|
|
90
|
+
document.getElementById('top-skill').textContent = sortedSkills[0] ? sortedSkills[0][0] : '-';
|
|
91
|
+
document.getElementById('top-agent').textContent = sortedAgents[0] ? sortedAgents[0][0] : '-';
|
|
92
|
+
|
|
93
|
+
const top15Skills = sortedSkills.slice(0, 15);
|
|
94
|
+
const top10Agents = sortedAgents.slice(0, 10);
|
|
95
|
+
|
|
96
|
+
if (skillsChart) skillsChart.destroy();
|
|
97
|
+
if (agentsChart) agentsChart.destroy();
|
|
98
|
+
|
|
99
|
+
const chartDefaults = { color: '#8b949e', borderColor: '#30363d' };
|
|
100
|
+
Chart.defaults.color = chartDefaults.color;
|
|
101
|
+
|
|
102
|
+
skillsChart = new Chart(document.getElementById('skills-chart'), {
|
|
103
|
+
type: 'bar',
|
|
104
|
+
data: {
|
|
105
|
+
labels: top15Skills.map(s => s[0]),
|
|
106
|
+
datasets: [{ label: 'Invocations', data: top15Skills.map(s => s[1]),
|
|
107
|
+
backgroundColor: '#58a6ff', borderRadius: 4, barThickness: 18 }]
|
|
108
|
+
},
|
|
109
|
+
options: {
|
|
110
|
+
indexAxis: 'y', responsive: true, plugins: { legend: { display: false } },
|
|
111
|
+
scales: { x: { grid: { color: '#21262d' } }, y: { grid: { display: false } } }
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
agentsChart = new Chart(document.getElementById('agents-chart'), {
|
|
116
|
+
type: 'bar',
|
|
117
|
+
data: {
|
|
118
|
+
labels: top10Agents.map(a => a[0]),
|
|
119
|
+
datasets: [{ label: 'Delegations', data: top10Agents.map(a => a[1]),
|
|
120
|
+
backgroundColor: '#3fb950', borderRadius: 4, barThickness: 18 }]
|
|
121
|
+
},
|
|
122
|
+
options: {
|
|
123
|
+
indexAxis: 'y', responsive: true, plugins: { legend: { display: false } },
|
|
124
|
+
scales: { x: { grid: { color: '#21262d' } }, y: { grid: { display: false } } }
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
</script>
|
|
129
|
+
</body>
|
|
130
|
+
</html>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "example-pattern-1",
|
|
4
|
+
"name": "Example Pattern",
|
|
5
|
+
"domain": "general",
|
|
6
|
+
"description": "A template entry showing the expected format",
|
|
7
|
+
"tags": ["template", "example"],
|
|
8
|
+
"anti_patterns": ["conflicting-pattern"],
|
|
9
|
+
"severity": "info",
|
|
10
|
+
"auto_fixable": false
|
|
11
|
+
}
|
|
12
|
+
]
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Generic domain reasoning engine for ai-toolkit skills.
|
|
3
|
+
|
|
4
|
+
Multi-domain search across a categorized knowledge base with anti-pattern filtering.
|
|
5
|
+
Python stdlib only, JSON to stdout, zero external deps.
|
|
6
|
+
|
|
7
|
+
Usage: python3 search.py <query> [--domain <domain>] [--limit <n>]
|
|
8
|
+
|
|
9
|
+
Threshold rule: Use this pattern when skill has >50 options across >3
|
|
10
|
+
compatibility dimensions. Below that threshold, Markdown tables suffice.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def load_catalog(assets_dir: Path) -> list[dict]:
|
|
20
|
+
"""Load all JSON asset files from the assets directory."""
|
|
21
|
+
items: list[dict] = []
|
|
22
|
+
for f in sorted(assets_dir.glob("*.json")):
|
|
23
|
+
with open(f) as fh:
|
|
24
|
+
data = json.load(fh)
|
|
25
|
+
if isinstance(data, list):
|
|
26
|
+
items.extend(data)
|
|
27
|
+
else:
|
|
28
|
+
items.append(data)
|
|
29
|
+
return items
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def match_query(
|
|
33
|
+
items: list[dict], query: str, domain: str | None = None
|
|
34
|
+
) -> list[dict]:
|
|
35
|
+
"""Score items against query using keyword matching."""
|
|
36
|
+
query_terms = query.lower().split()
|
|
37
|
+
scored: list[dict] = []
|
|
38
|
+
for item in items:
|
|
39
|
+
if domain and item.get("domain", "") != domain:
|
|
40
|
+
continue
|
|
41
|
+
searchable = " ".join(str(v) for v in item.values()).lower()
|
|
42
|
+
score = sum(1 for term in query_terms if term in searchable)
|
|
43
|
+
if score > 0:
|
|
44
|
+
scored.append({**item, "_score": score})
|
|
45
|
+
return sorted(scored, key=lambda x: x["_score"], reverse=True)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def filter_anti_patterns(
|
|
49
|
+
items: list[dict], selected: list[str]
|
|
50
|
+
) -> list[dict]:
|
|
51
|
+
"""Remove items that conflict with already-selected items."""
|
|
52
|
+
conflicts: set[str] = set()
|
|
53
|
+
for item in items:
|
|
54
|
+
if item.get("id") in selected:
|
|
55
|
+
conflicts.update(item.get("anti_patterns", []))
|
|
56
|
+
return [i for i in items if i.get("id") not in conflicts]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def main() -> None:
|
|
60
|
+
"""CLI entrypoint."""
|
|
61
|
+
if len(sys.argv) < 2:
|
|
62
|
+
print(
|
|
63
|
+
json.dumps(
|
|
64
|
+
{"error": "Usage: search.py <query> [--domain D] [--limit N]"}
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
sys.exit(1)
|
|
68
|
+
|
|
69
|
+
query = sys.argv[1]
|
|
70
|
+
domain: str | None = None
|
|
71
|
+
limit = 10
|
|
72
|
+
|
|
73
|
+
args = sys.argv[2:]
|
|
74
|
+
for i, arg in enumerate(args):
|
|
75
|
+
if arg == "--domain" and i + 1 < len(args):
|
|
76
|
+
domain = args[i + 1]
|
|
77
|
+
elif arg == "--limit" and i + 1 < len(args):
|
|
78
|
+
limit = int(args[i + 1])
|
|
79
|
+
|
|
80
|
+
assets_dir = Path(__file__).parent / "assets"
|
|
81
|
+
if not assets_dir.exists():
|
|
82
|
+
print(
|
|
83
|
+
json.dumps(
|
|
84
|
+
{"error": f"Assets directory not found: {assets_dir}"}
|
|
85
|
+
)
|
|
86
|
+
)
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
|
|
89
|
+
catalog = load_catalog(assets_dir)
|
|
90
|
+
results = match_query(catalog, query, domain)
|
|
91
|
+
results = filter_anti_patterns(results, [])[:limit]
|
|
92
|
+
|
|
93
|
+
# Remove internal score from output
|
|
94
|
+
for r in results:
|
|
95
|
+
r.pop("_score", None)
|
|
96
|
+
|
|
97
|
+
print(
|
|
98
|
+
json.dumps(
|
|
99
|
+
{
|
|
100
|
+
"query": query,
|
|
101
|
+
"domain": domain,
|
|
102
|
+
"results": results,
|
|
103
|
+
"total": len(results),
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
if __name__ == "__main__":
|
|
110
|
+
main()
|