@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,270 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mcp-patterns
|
|
3
|
+
description: "Loaded when user asks about MCP servers or tool protocol design"
|
|
4
|
+
effort: medium
|
|
5
|
+
user-invocable: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# MCP Patterns Skill
|
|
9
|
+
|
|
10
|
+
## MCP Specification (2025-06-18)
|
|
11
|
+
|
|
12
|
+
### Core Concepts
|
|
13
|
+
|
|
14
|
+
| Concept | Description |
|
|
15
|
+
|---------|-------------|
|
|
16
|
+
| **Server** | Exposes tools, resources, prompts to clients |
|
|
17
|
+
| **Client** | Connects to servers, invokes tools |
|
|
18
|
+
| **Transport** | Communication layer (stdio, HTTP, SSE) |
|
|
19
|
+
| **Tool** | Executable function with JSON Schema |
|
|
20
|
+
| **Resource** | Read-only data (files, URLs) |
|
|
21
|
+
| **Prompt** | Reusable prompt template |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Tool Definition Pattern
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
// TypeScript with @modelcontextprotocol/sdk
|
|
29
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
30
|
+
tools: [{
|
|
31
|
+
name: "search_kb",
|
|
32
|
+
description: "Search the knowledge base",
|
|
33
|
+
inputSchema: {
|
|
34
|
+
type: "object",
|
|
35
|
+
properties: {
|
|
36
|
+
query: {
|
|
37
|
+
type: "string",
|
|
38
|
+
description: "Search query"
|
|
39
|
+
},
|
|
40
|
+
limit: {
|
|
41
|
+
type: "number",
|
|
42
|
+
description: "Max results",
|
|
43
|
+
default: 10
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
required: ["query"]
|
|
47
|
+
},
|
|
48
|
+
annotations: {
|
|
49
|
+
readOnlyHint: true, // Doesn't modify state
|
|
50
|
+
idempotentHint: true, // Same input = same output
|
|
51
|
+
openWorldHint: false // Bounded result set
|
|
52
|
+
}
|
|
53
|
+
}]
|
|
54
|
+
}));
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Tool Annotations
|
|
58
|
+
|
|
59
|
+
| Annotation | Meaning | Use When |
|
|
60
|
+
|------------|---------|----------|
|
|
61
|
+
| `readOnlyHint` | No side effects | Read operations |
|
|
62
|
+
| `destructiveHint` | Deletes/modifies data | Write operations |
|
|
63
|
+
| `idempotentHint` | Safe to retry | GET-like operations |
|
|
64
|
+
| `openWorldHint` | Results may change | External API calls |
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Transport Patterns
|
|
69
|
+
|
|
70
|
+
### 1. stdio (Default)
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
|
|
74
|
+
|
|
75
|
+
const transport = new StdioServerTransport();
|
|
76
|
+
await server.connect(transport);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 2. HTTP with SSE
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
# FastAPI implementation
|
|
83
|
+
from fastapi import FastAPI
|
|
84
|
+
from sse_starlette.sse import EventSourceResponse
|
|
85
|
+
|
|
86
|
+
app = FastAPI()
|
|
87
|
+
|
|
88
|
+
@app.get("/mcp/sse")
|
|
89
|
+
async def sse_endpoint():
|
|
90
|
+
async def event_generator():
|
|
91
|
+
while True:
|
|
92
|
+
# Yield MCP events
|
|
93
|
+
yield {"event": "message", "data": json.dumps(response)}
|
|
94
|
+
return EventSourceResponse(event_generator())
|
|
95
|
+
|
|
96
|
+
@app.post("/mcp")
|
|
97
|
+
async def jsonrpc_endpoint(request: Request):
|
|
98
|
+
body = await request.json()
|
|
99
|
+
response = await handle_jsonrpc(body)
|
|
100
|
+
return JSONResponse(response)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 3. Streamable HTTP (Modern)
|
|
104
|
+
|
|
105
|
+
Single `/mcp` endpoint handling GET (SSE) and POST (JSON-RPC):
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
@app.api_route("/mcp", methods=["GET", "POST"])
|
|
109
|
+
async def mcp_endpoint(request: Request):
|
|
110
|
+
if request.method == "GET":
|
|
111
|
+
# SSE streaming
|
|
112
|
+
return EventSourceResponse(stream_generator())
|
|
113
|
+
else:
|
|
114
|
+
# JSON-RPC
|
|
115
|
+
body = await request.json()
|
|
116
|
+
return JSONResponse(await handle_jsonrpc(body))
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## JSON-RPC 2.0 Pattern
|
|
122
|
+
|
|
123
|
+
### Request Format
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"jsonrpc": "2.0",
|
|
127
|
+
"id": 1,
|
|
128
|
+
"method": "tools/call",
|
|
129
|
+
"params": {
|
|
130
|
+
"name": "search_kb",
|
|
131
|
+
"arguments": {"query": "test", "limit": 5}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Response Format
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"jsonrpc": "2.0",
|
|
140
|
+
"id": 1,
|
|
141
|
+
"result": {
|
|
142
|
+
"content": [
|
|
143
|
+
{"type": "text", "text": "Search results..."}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Error Format
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"jsonrpc": "2.0",
|
|
153
|
+
"id": 1,
|
|
154
|
+
"error": {
|
|
155
|
+
"code": -32601,
|
|
156
|
+
"message": "Method not found"
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Standard Error Codes
|
|
162
|
+
| Code | Meaning |
|
|
163
|
+
|------|---------|
|
|
164
|
+
| -32700 | Parse error |
|
|
165
|
+
| -32600 | Invalid request |
|
|
166
|
+
| -32601 | Method not found |
|
|
167
|
+
| -32602 | Invalid params |
|
|
168
|
+
| -32603 | Internal error |
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Completion Support
|
|
173
|
+
|
|
174
|
+
Enable intelligent argument suggestions:
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
server.setRequestHandler(CompletionCompleteRequestSchema, async (request) => {
|
|
178
|
+
const { argument } = request.params;
|
|
179
|
+
|
|
180
|
+
if (argument.name === "service") {
|
|
181
|
+
return {
|
|
182
|
+
completion: {
|
|
183
|
+
values: ["nginx", "postgresql", "redis", "qdrant"],
|
|
184
|
+
hasMore: false
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return { completion: { values: [], hasMore: false } };
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Session Management
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// Generate secure session ID
|
|
199
|
+
const sessionId = crypto.randomUUID();
|
|
200
|
+
|
|
201
|
+
// Validate Origin header
|
|
202
|
+
const allowedOrigins = ["http://localhost:3000", "https://claude.ai"];
|
|
203
|
+
if (!allowedOrigins.includes(request.headers.origin)) {
|
|
204
|
+
throw new Error("Invalid origin");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Session storage (don't expose to client)
|
|
208
|
+
const sessions = new Map<string, SessionData>();
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Batching Support
|
|
214
|
+
|
|
215
|
+
Handle multiple requests in single HTTP call:
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
async def handle_jsonrpc(body):
|
|
219
|
+
if isinstance(body, list):
|
|
220
|
+
# Batch request
|
|
221
|
+
return [await process_single(req) for req in body]
|
|
222
|
+
else:
|
|
223
|
+
# Single request
|
|
224
|
+
return await process_single(body)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Best Practices
|
|
230
|
+
|
|
231
|
+
### Security
|
|
232
|
+
- [ ] Validate all inputs against JSON Schema
|
|
233
|
+
- [ ] Validate Origin header
|
|
234
|
+
- [ ] Implement rate limiting
|
|
235
|
+
- [ ] Use environment variables for secrets
|
|
236
|
+
- [ ] No secrets in logs or errors
|
|
237
|
+
|
|
238
|
+
### Performance
|
|
239
|
+
- [ ] Connection pooling
|
|
240
|
+
- [ ] Response caching where appropriate
|
|
241
|
+
- [ ] Streaming for large responses
|
|
242
|
+
- [ ] Batch support for efficiency
|
|
243
|
+
|
|
244
|
+
### Logging
|
|
245
|
+
- [ ] Log to stderr (never stdout)
|
|
246
|
+
- [ ] Structured JSON logs
|
|
247
|
+
- [ ] Request/response tracing
|
|
248
|
+
- [ ] Error logging with context
|
|
249
|
+
|
|
250
|
+
### Documentation
|
|
251
|
+
- [ ] Document all tools clearly
|
|
252
|
+
- [ ] Include example usage
|
|
253
|
+
- [ ] Version your API
|
|
254
|
+
- [ ] Maintain changelog
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## RAG-MCP MCP Tools
|
|
259
|
+
|
|
260
|
+
| Tool | Description |
|
|
261
|
+
|------|-------------|
|
|
262
|
+
| `smart_query` | Primary search with auto-routing |
|
|
263
|
+
| `hybrid_search_kb` | Raw vector + text search |
|
|
264
|
+
| `get_document` | Full document content |
|
|
265
|
+
| `crag_search` | Self-correcting search |
|
|
266
|
+
| `multi_hop_search` | Complex reasoning |
|
|
267
|
+
| `start_workflow` | Start agent workflow |
|
|
268
|
+
| `get_workflow_status` | Check workflow progress |
|
|
269
|
+
| `list_workflows` | List all workflows |
|
|
270
|
+
| `cancel_workflow` | Cancel workflow |
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mem-search
|
|
3
|
+
description: "Search past coding sessions using natural language. Finds relevant observations, decisions, and context from previous work."
|
|
4
|
+
effort: medium
|
|
5
|
+
argument-hint: "[search query]"
|
|
6
|
+
allowed-tools: Bash, Read
|
|
7
|
+
user-invocable: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Search Session Memory
|
|
11
|
+
|
|
12
|
+
Search the persistent memory database for past coding observations, decisions, and context.
|
|
13
|
+
|
|
14
|
+
$ARGUMENTS
|
|
15
|
+
|
|
16
|
+
## How It Works
|
|
17
|
+
|
|
18
|
+
This skill queries the SQLite FTS5 full-text search index at `~/.ai-toolkit/memory.db` to find relevant observations from past sessions.
|
|
19
|
+
|
|
20
|
+
## Instructions
|
|
21
|
+
|
|
22
|
+
1. **Parse the search query** from `$ARGUMENTS`. If empty, prompt the user for a query.
|
|
23
|
+
|
|
24
|
+
2. **Initialize the database** if it does not exist:
|
|
25
|
+
```bash
|
|
26
|
+
python3 "$HOME/.ai-toolkit/hooks/../plugins/memory-pack/scripts/init_db.py" 2>/dev/null || true
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
3. **Run the FTS5 search** against the observations table:
|
|
30
|
+
```bash
|
|
31
|
+
sqlite3 ~/.ai-toolkit/memory.db "
|
|
32
|
+
SELECT o.id, o.session_id, o.tool_name, o.content, o.created_at,
|
|
33
|
+
s.project_dir, s.summary
|
|
34
|
+
FROM observations_fts fts
|
|
35
|
+
JOIN observations o ON o.id = fts.rowid
|
|
36
|
+
LEFT JOIN sessions s ON s.session_id = o.session_id
|
|
37
|
+
WHERE observations_fts MATCH '<query>'
|
|
38
|
+
ORDER BY rank
|
|
39
|
+
LIMIT 10;
|
|
40
|
+
"
|
|
41
|
+
```
|
|
42
|
+
Replace `<query>` with the user's search terms. Escape single quotes by doubling them.
|
|
43
|
+
|
|
44
|
+
4. **Progressive disclosure** -- present results in two stages:
|
|
45
|
+
|
|
46
|
+
**Stage 1: Summary view** (show first)
|
|
47
|
+
```markdown
|
|
48
|
+
## Memory Search: "<query>"
|
|
49
|
+
|
|
50
|
+
Found N results across M sessions.
|
|
51
|
+
|
|
52
|
+
| # | Session | Project | Tool | Time | Preview |
|
|
53
|
+
|---|---------|---------|------|------|---------|
|
|
54
|
+
| 1 | abc123 | /path | Edit | 2025-01-15 | First 80 chars... |
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Stage 2: Detail view** (on request)
|
|
58
|
+
Show the full observation content, session summary, and related observations from the same session.
|
|
59
|
+
|
|
60
|
+
5. **If no results found**, suggest:
|
|
61
|
+
- Trying broader search terms
|
|
62
|
+
- Checking if memory-pack hooks are installed
|
|
63
|
+
- Running `init-db.sh` if the database is missing
|
|
64
|
+
|
|
65
|
+
## Query Tips
|
|
66
|
+
|
|
67
|
+
- Use simple keywords: `mem-search database migration`
|
|
68
|
+
- FTS5 supports prefix matching: `migrat*` matches "migration", "migrate"
|
|
69
|
+
- Boolean operators: `database AND NOT test`
|
|
70
|
+
- Column filters: `tool_name:Edit` to search only Edit tool observations
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: migrate
|
|
3
|
+
description: "Run database migrations with backup verification"
|
|
4
|
+
effort: medium
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
argument-hint: "[direction]"
|
|
7
|
+
allowed-tools: Bash, Read
|
|
8
|
+
hooks:
|
|
9
|
+
PreToolUse:
|
|
10
|
+
- matcher: "Bash"
|
|
11
|
+
hooks:
|
|
12
|
+
- type: command
|
|
13
|
+
command: "echo 'Reminder: ensure database backup exists before running migrations'"
|
|
14
|
+
scripts:
|
|
15
|
+
- scripts/migration-status.py
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# /migrate - Database Migration Workflow
|
|
19
|
+
|
|
20
|
+
$ARGUMENTS
|
|
21
|
+
|
|
22
|
+
## What This Command Does
|
|
23
|
+
|
|
24
|
+
Create, run, or manage database migrations with auto-detection of the migration tool.
|
|
25
|
+
|
|
26
|
+
## Project context
|
|
27
|
+
|
|
28
|
+
- Migration tools: !`ls alembic.ini prisma/ database/migrations/ manage.py 2>/dev/null`
|
|
29
|
+
|
|
30
|
+
## Migration Status Script
|
|
31
|
+
|
|
32
|
+
Detect migration tool and report status:
|
|
33
|
+
```bash
|
|
34
|
+
python3 scripts/migration-status.py [directory]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Returns JSON with: `tool`, `config_file`, `migrations_dir`, `total_migrations`, `latest`, `commands{}` (status/create/upgrade/downgrade).
|
|
38
|
+
|
|
39
|
+
## Auto-Detection
|
|
40
|
+
|
|
41
|
+
| File Found | Tool | Commands |
|
|
42
|
+
|------------|------|----------|
|
|
43
|
+
| `alembic.ini` | Alembic | `alembic revision`, `alembic upgrade` |
|
|
44
|
+
| `prisma/schema.prisma` | Prisma | `npx prisma migrate dev` |
|
|
45
|
+
| `database/migrations/` + `artisan` | Laravel | `php artisan migrate` |
|
|
46
|
+
| `manage.py` | Django | `python manage.py migrate` |
|
|
47
|
+
| `flyway.conf` | Flyway | `flyway migrate` |
|
|
48
|
+
| `drizzle.config.ts` | Drizzle | `npx drizzle-kit push` |
|
|
49
|
+
|
|
50
|
+
## Workflow
|
|
51
|
+
|
|
52
|
+
### Create New Migration
|
|
53
|
+
1. Detect migration tool
|
|
54
|
+
2. Generate migration from model/schema changes
|
|
55
|
+
3. Review generated SQL
|
|
56
|
+
4. Validate syntax
|
|
57
|
+
|
|
58
|
+
### Run Migrations
|
|
59
|
+
1. Show pending migrations
|
|
60
|
+
2. Dry-run if supported (`--pretend`, `--sql`)
|
|
61
|
+
3. Backup reminder
|
|
62
|
+
4. Apply with user confirmation
|
|
63
|
+
5. Verify success
|
|
64
|
+
|
|
65
|
+
### Rollback
|
|
66
|
+
1. Show last applied migration
|
|
67
|
+
2. Confirm rollback scope
|
|
68
|
+
3. Execute rollback
|
|
69
|
+
4. Verify state
|
|
70
|
+
|
|
71
|
+
## Safety Checks (MANDATORY)
|
|
72
|
+
|
|
73
|
+
- [ ] Migration tested on development/staging first
|
|
74
|
+
- [ ] Rollback path verified
|
|
75
|
+
- [ ] No data loss in forward or backward direction
|
|
76
|
+
- [ ] Large table operations use concurrent/online DDL
|
|
77
|
+
- [ ] Backup exists or reminder given
|
|
78
|
+
|
|
79
|
+
## Usage Examples
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
/migrate # Show migration status
|
|
83
|
+
/migrate create add_users # Create new migration
|
|
84
|
+
/migrate run # Apply pending migrations
|
|
85
|
+
/migrate rollback # Rollback last migration
|
|
86
|
+
/migrate status # Show applied/pending migrations
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Reference Skill
|
|
90
|
+
Use `migration-patterns` skill for zero-downtime strategies and best practices.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Detect migration tool and report status with commands reference.
|
|
3
|
+
|
|
4
|
+
Scans a project directory for well-known migration configuration files
|
|
5
|
+
(Alembic, Prisma, Laravel, Django, Drizzle) and returns a JSON object
|
|
6
|
+
describing the detected tool, config file location, migrations
|
|
7
|
+
directory, migration count, latest migration file, and command
|
|
8
|
+
references for common operations.
|
|
9
|
+
|
|
10
|
+
Usage::
|
|
11
|
+
|
|
12
|
+
python3 migration-status.py [directory]
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import os
|
|
18
|
+
import sys
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
TOOLS = {
|
|
22
|
+
"alembic": {
|
|
23
|
+
"config": "alembic.ini",
|
|
24
|
+
"migrations_dir": "alembic/versions",
|
|
25
|
+
"pattern": ".py",
|
|
26
|
+
"commands": {
|
|
27
|
+
"status": "alembic current",
|
|
28
|
+
"create": "alembic revision --autogenerate -m '<message>'",
|
|
29
|
+
"upgrade": "alembic upgrade head",
|
|
30
|
+
"downgrade": "alembic downgrade -1",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
"prisma": {
|
|
34
|
+
"config": "prisma/schema.prisma",
|
|
35
|
+
"migrations_dir": "prisma/migrations",
|
|
36
|
+
"pattern": ".sql",
|
|
37
|
+
"commands": {
|
|
38
|
+
"status": "npx prisma migrate status",
|
|
39
|
+
"create": "npx prisma migrate dev --name <name>",
|
|
40
|
+
"upgrade": "npx prisma migrate deploy",
|
|
41
|
+
"downgrade": "npx prisma migrate resolve --rolled-back <name>",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
"laravel": {
|
|
45
|
+
"config": "database/migrations",
|
|
46
|
+
"migrations_dir": "database/migrations",
|
|
47
|
+
"pattern": ".php",
|
|
48
|
+
"commands": {
|
|
49
|
+
"status": "php artisan migrate:status",
|
|
50
|
+
"create": "php artisan make:migration <name>",
|
|
51
|
+
"upgrade": "php artisan migrate",
|
|
52
|
+
"downgrade": "php artisan migrate:rollback --step=1",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
"django": {
|
|
56
|
+
"config": "manage.py",
|
|
57
|
+
"migrations_dir": None, # detected dynamically
|
|
58
|
+
"pattern": ".py",
|
|
59
|
+
"commands": {
|
|
60
|
+
"status": "python manage.py showmigrations",
|
|
61
|
+
"create": "python manage.py makemigrations",
|
|
62
|
+
"upgrade": "python manage.py migrate",
|
|
63
|
+
"downgrade": "python manage.py migrate <app> <previous>",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
"drizzle": {
|
|
67
|
+
"config": "drizzle.config.ts",
|
|
68
|
+
"migrations_dir": "drizzle",
|
|
69
|
+
"pattern": ".sql",
|
|
70
|
+
"commands": {
|
|
71
|
+
"status": "npx drizzle-kit check",
|
|
72
|
+
"create": "npx drizzle-kit generate",
|
|
73
|
+
"upgrade": "npx drizzle-kit push",
|
|
74
|
+
"downgrade": "npx drizzle-kit drop",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def find_django_migrations(project_dir: Path) -> str | None:
|
|
81
|
+
"""Find Django migration directories by looking for apps with migrations/.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
project_dir: Root directory of the Django project.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
Relative path to the first discovered migrations directory, or
|
|
88
|
+
``None`` if no Django app with migrations is found.
|
|
89
|
+
"""
|
|
90
|
+
for item in project_dir.iterdir():
|
|
91
|
+
if item.is_dir() and (item / "migrations").is_dir():
|
|
92
|
+
mig_init = item / "migrations" / "__init__.py"
|
|
93
|
+
if mig_init.exists():
|
|
94
|
+
return str(item / "migrations")
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def count_migrations(mig_dir: Path, pattern: str) -> tuple[int, str | None]:
|
|
99
|
+
"""Count migration files and find the latest one.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
mig_dir: Directory containing migration files.
|
|
103
|
+
pattern: File extension to match (e.g. ``".py"``, ``".sql"``).
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
A tuple of ``(count, latest_filename)`` where *latest_filename*
|
|
107
|
+
is the name of the most recently modified migration, or ``None``
|
|
108
|
+
if no migrations exist.
|
|
109
|
+
"""
|
|
110
|
+
if not mig_dir.is_dir():
|
|
111
|
+
return 0, None
|
|
112
|
+
files = sorted(
|
|
113
|
+
[f for f in mig_dir.iterdir() if f.suffix == pattern and f.name != "__init__.py"],
|
|
114
|
+
key=lambda p: p.stat().st_mtime,
|
|
115
|
+
)
|
|
116
|
+
return len(files), files[-1].name if files else None
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def detect(project_dir: Path) -> dict[str, object]:
|
|
120
|
+
"""Detect migration tool and gather status.
|
|
121
|
+
|
|
122
|
+
Iterates through known migration tools and checks for their
|
|
123
|
+
configuration files. Returns the first match with tool name,
|
|
124
|
+
config location, migrations directory, file counts, and
|
|
125
|
+
command references.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
project_dir: Root directory of the project to analyse.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
Dictionary with keys ``tool``, ``config_file``,
|
|
132
|
+
``migrations_dir``, ``total_migrations``, ``latest``,
|
|
133
|
+
and ``commands``.
|
|
134
|
+
"""
|
|
135
|
+
for tool_name, info in TOOLS.items():
|
|
136
|
+
config_path = project_dir / info["config"]
|
|
137
|
+
if tool_name == "laravel":
|
|
138
|
+
if not config_path.is_dir():
|
|
139
|
+
continue
|
|
140
|
+
elif tool_name == "drizzle":
|
|
141
|
+
# Also check .js variant
|
|
142
|
+
if not config_path.exists() and not (project_dir / "drizzle.config.js").exists():
|
|
143
|
+
continue
|
|
144
|
+
else:
|
|
145
|
+
if not config_path.exists():
|
|
146
|
+
continue
|
|
147
|
+
|
|
148
|
+
# Determine migrations directory
|
|
149
|
+
mig_dir_rel = info["migrations_dir"]
|
|
150
|
+
if tool_name == "django":
|
|
151
|
+
mig_dir_rel = find_django_migrations(project_dir)
|
|
152
|
+
if not mig_dir_rel:
|
|
153
|
+
mig_dir_rel = "<app>/migrations"
|
|
154
|
+
|
|
155
|
+
mig_dir = project_dir / mig_dir_rel if mig_dir_rel else None
|
|
156
|
+
total, latest = (0, None)
|
|
157
|
+
if mig_dir and mig_dir.is_dir():
|
|
158
|
+
total, latest = count_migrations(mig_dir, info["pattern"])
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
"tool": tool_name,
|
|
162
|
+
"config_file": str(config_path.relative_to(project_dir)),
|
|
163
|
+
"migrations_dir": mig_dir_rel,
|
|
164
|
+
"total_migrations": total,
|
|
165
|
+
"latest": latest,
|
|
166
|
+
"commands": info["commands"],
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
"tool": None,
|
|
171
|
+
"config_file": None,
|
|
172
|
+
"migrations_dir": None,
|
|
173
|
+
"total_migrations": 0,
|
|
174
|
+
"latest": None,
|
|
175
|
+
"commands": {},
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def main() -> None:
|
|
180
|
+
"""Entry point: detect migration tool and print JSON result to stdout."""
|
|
181
|
+
project_dir = Path(sys.argv[1]).resolve() if len(sys.argv) > 1 else Path.cwd()
|
|
182
|
+
if not project_dir.is_dir():
|
|
183
|
+
print(json.dumps({"error": f"Not a directory: {project_dir}"}))
|
|
184
|
+
sys.exit(1)
|
|
185
|
+
try:
|
|
186
|
+
result = detect(project_dir)
|
|
187
|
+
result["project_dir"] = str(project_dir)
|
|
188
|
+
print(json.dumps(result, indent=2))
|
|
189
|
+
except Exception as e:
|
|
190
|
+
print(json.dumps({"error": str(e)}))
|
|
191
|
+
sys.exit(1)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
if __name__ == "__main__":
|
|
195
|
+
main()
|