@softspark/ai-toolkit 1.2.0 → 1.3.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 (142) hide show
  1. package/AGENTS.md +5 -29
  2. package/CHANGELOG.md +39 -0
  3. package/README.md +170 -27
  4. package/app/.claude-plugin/plugin.json +2 -2
  5. package/app/ARCHITECTURE.md +35 -19
  6. package/app/agents/ai-engineer.md +47 -5
  7. package/app/agents/fact-checker.md +1 -1
  8. package/app/agents/llm-ops-engineer.md +2 -2
  9. package/app/agents/{mcp-server-architect.md → mcp-specialist.md} +124 -18
  10. package/app/agents/mcp-testing-engineer.md +2 -2
  11. package/app/agents/nlp-engineer.md +1 -1
  12. package/app/agents/orchestrator.md +3 -4
  13. package/app/agents/project-planner.md +1 -1
  14. package/app/agents/technical-researcher.md +71 -21
  15. package/app/hooks/commit-quality.sh +53 -0
  16. package/app/hooks/governance-capture.sh +77 -0
  17. package/app/hooks/guard-config.sh +46 -0
  18. package/app/hooks/mcp-health.sh +53 -0
  19. package/app/hooks/pre-compact-save.sh +34 -0
  20. package/app/hooks/session-context.sh +60 -0
  21. package/app/hooks.json +60 -0
  22. package/app/mcp-templates/README.md +105 -0
  23. package/app/mcp-templates/brave-search.json +13 -0
  24. package/app/mcp-templates/cloudflare.json +14 -0
  25. package/app/mcp-templates/context7.json +10 -0
  26. package/app/mcp-templates/custom-template.json +13 -0
  27. package/app/mcp-templates/datadog.json +15 -0
  28. package/app/mcp-templates/docker.json +10 -0
  29. package/app/mcp-templates/fetch.json +10 -0
  30. package/app/mcp-templates/filesystem.json +10 -0
  31. package/app/mcp-templates/git.json +10 -0
  32. package/app/mcp-templates/github.json +13 -0
  33. package/app/mcp-templates/google-drive.json +15 -0
  34. package/app/mcp-templates/google-maps.json +13 -0
  35. package/app/mcp-templates/grafana.json +14 -0
  36. package/app/mcp-templates/linear.json +13 -0
  37. package/app/mcp-templates/memory.json +10 -0
  38. package/app/mcp-templates/notion.json +13 -0
  39. package/app/mcp-templates/postgres.json +10 -0
  40. package/app/mcp-templates/puppeteer.json +10 -0
  41. package/app/mcp-templates/redis.json +13 -0
  42. package/app/mcp-templates/sentry.json +14 -0
  43. package/app/mcp-templates/sequential-thinking.json +10 -0
  44. package/app/mcp-templates/slack.json +14 -0
  45. package/app/mcp-templates/sqlite.json +10 -0
  46. package/app/mcp-templates/supabase.json +14 -0
  47. package/app/mcp-templates/vercel.json +13 -0
  48. package/app/plugins/research-pack/README.md +1 -1
  49. package/app/plugins/research-pack/plugin.json +1 -1
  50. package/app/rules/claude-toolkit-rules.md +1 -1
  51. package/app/rules/common/coding-style.md +52 -0
  52. package/app/rules/common/git-workflow.md +45 -0
  53. package/app/rules/common/performance.md +49 -0
  54. package/app/rules/common/security.md +59 -0
  55. package/app/rules/common/testing.md +53 -0
  56. package/app/rules/cpp/coding-style.md +55 -0
  57. package/app/rules/cpp/frameworks.md +55 -0
  58. package/app/rules/cpp/patterns.md +57 -0
  59. package/app/rules/cpp/security.md +61 -0
  60. package/app/rules/cpp/testing.md +58 -0
  61. package/app/rules/csharp/coding-style.md +54 -0
  62. package/app/rules/csharp/frameworks.md +60 -0
  63. package/app/rules/csharp/patterns.md +61 -0
  64. package/app/rules/csharp/security.md +60 -0
  65. package/app/rules/csharp/testing.md +58 -0
  66. package/app/rules/dart/coding-style.md +61 -0
  67. package/app/rules/dart/frameworks.md +59 -0
  68. package/app/rules/dart/patterns.md +62 -0
  69. package/app/rules/dart/security.md +60 -0
  70. package/app/rules/dart/testing.md +60 -0
  71. package/app/rules/golang/coding-style.md +50 -0
  72. package/app/rules/golang/frameworks.md +56 -0
  73. package/app/rules/golang/patterns.md +52 -0
  74. package/app/rules/golang/security.md +61 -0
  75. package/app/rules/golang/testing.md +54 -0
  76. package/app/rules/java/coding-style.md +56 -0
  77. package/app/rules/java/frameworks.md +54 -0
  78. package/app/rules/java/patterns.md +59 -0
  79. package/app/rules/java/security.md +60 -0
  80. package/app/rules/java/testing.md +55 -0
  81. package/app/rules/kotlin/coding-style.md +56 -0
  82. package/app/rules/kotlin/frameworks.md +54 -0
  83. package/app/rules/kotlin/patterns.md +54 -0
  84. package/app/rules/kotlin/security.md +62 -0
  85. package/app/rules/kotlin/testing.md +56 -0
  86. package/app/rules/php/coding-style.md +53 -0
  87. package/app/rules/php/frameworks.md +57 -0
  88. package/app/rules/php/patterns.md +63 -0
  89. package/app/rules/php/security.md +61 -0
  90. package/app/rules/php/testing.md +60 -0
  91. package/app/rules/python/coding-style.md +52 -0
  92. package/app/rules/python/frameworks.md +53 -0
  93. package/app/rules/python/patterns.md +53 -0
  94. package/app/rules/python/security.md +58 -0
  95. package/app/rules/python/testing.md +52 -0
  96. package/app/rules/ruby/coding-style.md +56 -0
  97. package/app/rules/ruby/frameworks.md +56 -0
  98. package/app/rules/ruby/patterns.md +61 -0
  99. package/app/rules/ruby/security.md +61 -0
  100. package/app/rules/ruby/testing.md +63 -0
  101. package/app/rules/rust/coding-style.md +52 -0
  102. package/app/rules/rust/frameworks.md +59 -0
  103. package/app/rules/rust/patterns.md +58 -0
  104. package/app/rules/rust/security.md +64 -0
  105. package/app/rules/rust/testing.md +54 -0
  106. package/app/rules/swift/coding-style.md +55 -0
  107. package/app/rules/swift/frameworks.md +63 -0
  108. package/app/rules/swift/patterns.md +63 -0
  109. package/app/rules/swift/security.md +63 -0
  110. package/app/rules/swift/testing.md +60 -0
  111. package/app/rules/typescript/coding-style.md +51 -0
  112. package/app/rules/typescript/frameworks.md +51 -0
  113. package/app/rules/typescript/patterns.md +51 -0
  114. package/app/rules/typescript/security.md +55 -0
  115. package/app/rules/typescript/testing.md +52 -0
  116. package/app/skills/app-builder/SKILL.md +1 -1
  117. package/app/skills/brand-voice/SKILL.md +92 -0
  118. package/app/skills/council/SKILL.md +133 -0
  119. package/app/skills/introspect/SKILL.md +125 -0
  120. package/bin/ai-toolkit.js +103 -2
  121. package/kb/reference/agents-catalog.md +10 -13
  122. package/kb/reference/architecture-overview.md +29 -6
  123. package/kb/reference/commands-catalog.md +4 -4
  124. package/kb/reference/competitive-features-implementation.md +677 -0
  125. package/kb/reference/extension-api.md +175 -0
  126. package/kb/reference/hooks-catalog.md +90 -14
  127. package/kb/reference/language-rules.md +167 -0
  128. package/kb/reference/manifest-install.md +165 -0
  129. package/kb/reference/mcp-templates.md +110 -0
  130. package/kb/reference/skills-catalog.md +9 -6
  131. package/llms-full.txt +1511 -59
  132. package/llms.txt +8 -3
  133. package/package.json +2 -2
  134. package/scripts/inject_hook_cli.py +330 -0
  135. package/scripts/install.py +241 -7
  136. package/scripts/install_steps/ai_tools.py +63 -1
  137. package/scripts/install_steps/detect_language.py +50 -0
  138. package/scripts/install_steps/install_state.py +117 -0
  139. package/scripts/mcp_manager.py +206 -0
  140. package/app/agents/mcp-expert.md +0 -228
  141. package/app/agents/rag-engineer.md +0 -201
  142. package/app/agents/research-synthesizer.md +0 -138
package/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # ai-toolkit
2
2
 
3
- > Professional-grade Claude Code toolkit: 87 skills, 47 agents, machine-enforced constitution, quality hooks.
3
+ > Professional-grade Claude Code toolkit: 90 skills, 44 agents, machine-enforced constitution, quality hooks.
4
4
 
5
5
  ## Documentation
6
6
 
@@ -14,7 +14,7 @@
14
14
  - [Best Practices](kb/best-practices/README.md)
15
15
  - [How-To Guides](kb/howto/README.md)
16
16
  - [SOP: Claude Toolkit Maintenance](kb/procedures/maintenance-sop.md)
17
- - [Agents Catalog (47 agents)](kb/reference/agents-catalog.md)
17
+ - [Agents Catalog (44 agents)](kb/reference/agents-catalog.md)
18
18
  - [Anti-Pattern Registry Format](kb/reference/anti-pattern-registry-format.md)
19
19
  - [AI Toolkit Architecture](kb/reference/architecture-overview.md)
20
20
  - [Config Benchmark](kb/reference/benchmark-config.md)
@@ -22,17 +22,22 @@
22
22
  - [Claude Ecosystem Benchmark Snapshot](kb/reference/claude-ecosystem-benchmark-snapshot.md)
23
23
  - [Claude Ecosystem Expansion Foundations](kb/reference/claude-ecosystem-expansion-foundations.md)
24
24
  - [Commands Catalog (DEPRECATED)](kb/reference/commands-catalog.md)
25
+ - [Plan: Competitive Features — ai-toolkit](kb/reference/competitive-features-implementation.md)
25
26
  - [Distribution Model](kb/reference/distribution-model.md)
27
+ - [Extension API Reference](kb/reference/extension-api.md)
26
28
  - [Global Install Model](kb/reference/global-install-model.md)
27
29
  - [Hierarchical Override Pattern](kb/reference/hierarchical-override-pattern.md)
28
30
  - [Hooks Catalog](kb/reference/hooks-catalog.md)
29
31
  - [External Integrations](kb/reference/integrations.md)
30
32
  - [Language Plugin Packs](kb/reference/language-packs.md)
33
+ - [Language Rules System](kb/reference/language-rules.md)
34
+ - [Manifest-Driven Install System](kb/reference/manifest-install.md)
35
+ - [MCP Server Templates](kb/reference/mcp-templates.md)
31
36
  - [Merge-Friendly Install Model](kb/reference/merge-friendly-install-model.md)
32
37
  - [Plugin Pack Conventions](kb/reference/plugin-pack-conventions.md)
33
38
  - [Quick Wins Implementation Summary](kb/reference/quick-wins-implementation-summary.md)
34
39
  - [Skill Templates](kb/reference/skill-templates.md)
35
- - [Skills Catalog (87 skills)](kb/reference/skills-catalog.md)
40
+ - [Skills Catalog (90 skills)](kb/reference/skills-catalog.md)
36
41
  - [Skills Unification Model](kb/reference/skills-unification.md)
37
42
  - [Usage Statistics](kb/reference/stats.md)
38
43
  - [Config Sync](kb/reference/sync.md)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@softspark/ai-toolkit",
3
- "version": "1.2.0",
4
- "description": "Professional-grade AI coding toolkit: 87 skills, 47 agents, multi-platform support (Claude, Cursor, Windsurf, Copilot, Gemini, Cline, Roo Code, Aider, Augment), machine-enforced safety constitution, persona presets, skill security auditor, expanded lifecycle hooks, 11 plugin packs, and benchmark tooling.",
3
+ "version": "1.3.0",
4
+ "description": "Professional-grade AI coding toolkit: 90 skills, 44 agents, multi-platform support (Claude, Cursor, Windsurf, Copilot, Gemini, Cline, Roo Code, Aider, Augment), machine-enforced safety constitution, persona presets, skill security auditor, expanded lifecycle hooks, 11 plugin packs, and benchmark tooling.",
5
5
  "keywords": [
6
6
  "claude",
7
7
  "claude-code",
@@ -0,0 +1,330 @@
1
+ #!/usr/bin/env python3
2
+ """Inject external hooks into ~/.claude/settings.json.
3
+
4
+ Allows external tools (MCP servers, plugins, etc.) to register their own
5
+ hooks alongside ai-toolkit's hooks. Each injected file is tagged with a
6
+ ``_source`` derived from the filename stem so that re-running is idempotent
7
+ and removal is safe.
8
+
9
+ Usage:
10
+ inject_hook_cli.py <hooks-file.json> [target-dir]
11
+ inject_hook_cli.py --remove <hook-source-name> [target-dir]
12
+
13
+ Arguments:
14
+ hooks-file Path to a JSON file with ``{"hooks": {"EventName": [...]}}``
15
+ target-dir Directory containing ``.claude/settings.json`` (default: $HOME)
16
+
17
+ Flags:
18
+ --remove Remove all hook entries tagged with the given source name
19
+
20
+ The source name is derived from the filename stem (e.g.,
21
+ ``rag-mcp-hooks.json`` becomes ``"rag-mcp-hooks"``). All entries are tagged
22
+ with ``"_source": "<source-name>"`` for idempotent updates. Re-running
23
+ replaces old entries with the same source name.
24
+
25
+ Entries tagged with ``_source: "ai-toolkit"`` are **never** modified -- those
26
+ are managed exclusively by the toolkit itself.
27
+
28
+ Exit codes:
29
+ 0 success
30
+ 1 usage / argument error
31
+ 2 JSON parse error
32
+ """
33
+ from __future__ import annotations
34
+
35
+ import json
36
+ import os
37
+ import sys
38
+ from pathlib import Path
39
+
40
+ # Protected source tag -- this CLI must never touch ai-toolkit's own entries.
41
+ PROTECTED_SOURCE = "ai-toolkit"
42
+
43
+
44
+ # ---------------------------------------------------------------------------
45
+ # JSON helpers (same style as merge-hooks.py)
46
+ # ---------------------------------------------------------------------------
47
+
48
+ def load_json(path: str) -> dict:
49
+ """Load and parse a JSON file.
50
+
51
+ Args:
52
+ path: Filesystem path to the JSON file.
53
+
54
+ Returns:
55
+ Parsed JSON content as a dictionary.
56
+ """
57
+ with open(path) as f:
58
+ return json.load(f)
59
+
60
+
61
+ def save_json(path: str, data: dict) -> None:
62
+ """Write a dictionary to a JSON file with 4-space indent and trailing newline.
63
+
64
+ Args:
65
+ path: Filesystem path for the output JSON file.
66
+ data: Dictionary to serialize.
67
+ """
68
+ with open(path, "w") as f:
69
+ json.dump(data, f, indent=4, ensure_ascii=False)
70
+ f.write("\n")
71
+
72
+
73
+ # ---------------------------------------------------------------------------
74
+ # Core logic
75
+ # ---------------------------------------------------------------------------
76
+
77
+ def _entry_source(entry: dict) -> str | None:
78
+ """Return the ``_source`` tag of a hook entry, checking nested hooks too.
79
+
80
+ Args:
81
+ entry: A single hook entry dict.
82
+
83
+ Returns:
84
+ The source string, or ``None`` if untagged.
85
+ """
86
+ if "_source" in entry:
87
+ return entry["_source"]
88
+ for hook in entry.get("hooks", []):
89
+ if isinstance(hook, dict) and "_source" in hook:
90
+ return hook["_source"]
91
+ return None
92
+
93
+
94
+ def strip_source(hooks: dict, source: str) -> dict:
95
+ """Remove all entries whose ``_source`` matches *source*.
96
+
97
+ Args:
98
+ hooks: Existing hooks dict (event-name -> list of entries).
99
+ source: Source tag to strip.
100
+
101
+ Returns:
102
+ New hooks dict with matching entries removed. Empty event lists
103
+ are omitted.
104
+ """
105
+ result: dict = {}
106
+ for event, entries in hooks.items():
107
+ filtered = [e for e in entries if _entry_source(e) != source]
108
+ if filtered:
109
+ result[event] = filtered
110
+ return result
111
+
112
+
113
+ def tag_entries(hooks: dict, source: str) -> dict:
114
+ """Tag every entry in *hooks* with ``"_source": source``.
115
+
116
+ Operates on top-level entries only (not nested ``hooks`` arrays) to
117
+ match the convention used in ``app/hooks.json``.
118
+
119
+ Args:
120
+ hooks: Hook entries to tag (event-name -> list of entries).
121
+ source: Source tag to apply.
122
+
123
+ Returns:
124
+ New hooks dict with all entries tagged.
125
+ """
126
+ result: dict = {}
127
+ for event, entries in hooks.items():
128
+ tagged = []
129
+ for entry in entries:
130
+ entry_copy = dict(entry)
131
+ entry_copy["_source"] = source
132
+ tagged.append(entry_copy)
133
+ result[event] = tagged
134
+ return result
135
+
136
+
137
+ def merge_hooks(new_hooks: dict, existing_hooks: dict, source: str) -> dict:
138
+ """Strip old entries for *source*, then append *new_hooks*.
139
+
140
+ Args:
141
+ new_hooks: Tagged hook entries to inject.
142
+ existing_hooks: Current hooks from the settings file.
143
+ source: Source tag being injected.
144
+
145
+ Returns:
146
+ Merged hooks dict.
147
+ """
148
+ merged = strip_source(existing_hooks, source)
149
+ for event, entries in new_hooks.items():
150
+ if event not in merged:
151
+ merged[event] = []
152
+ merged[event].extend(entries)
153
+ return merged
154
+
155
+
156
+ # ---------------------------------------------------------------------------
157
+ # CLI actions
158
+ # ---------------------------------------------------------------------------
159
+
160
+ def inject(hooks_file: str, target_dir: str) -> None:
161
+ """Inject hooks from *hooks_file* into the target settings.json.
162
+
163
+ Args:
164
+ hooks_file: Path to the external hooks JSON file.
165
+ target_dir: Directory containing ``.claude/settings.json``.
166
+ """
167
+ # Derive source name from filename stem
168
+ source = Path(hooks_file).stem
169
+ if source == PROTECTED_SOURCE:
170
+ print(
171
+ f"Error: source name '{PROTECTED_SOURCE}' is reserved. "
172
+ "Rename your hooks file.",
173
+ file=sys.stderr,
174
+ )
175
+ sys.exit(1)
176
+
177
+ # Load the hooks file
178
+ try:
179
+ hooks_data = load_json(hooks_file)
180
+ except json.JSONDecodeError as exc:
181
+ print(f"Error: malformed JSON in {hooks_file}: {exc}", file=sys.stderr)
182
+ sys.exit(2)
183
+ except OSError as exc:
184
+ print(f"Error reading hooks file: {exc}", file=sys.stderr)
185
+ sys.exit(1)
186
+
187
+ new_hooks = hooks_data.get("hooks", {})
188
+ if not new_hooks:
189
+ print(f"Warning: no 'hooks' key found in {hooks_file}", file=sys.stderr)
190
+ return
191
+
192
+ # Tag entries with source
193
+ tagged = tag_entries(new_hooks, source)
194
+
195
+ # Load existing settings
196
+ settings_dir = Path(target_dir) / ".claude"
197
+ settings_path = settings_dir / "settings.json"
198
+
199
+ settings: dict = {}
200
+ if settings_path.is_file():
201
+ try:
202
+ settings = load_json(str(settings_path))
203
+ except json.JSONDecodeError as exc:
204
+ print(
205
+ f"Error: malformed JSON in {settings_path}: {exc}",
206
+ file=sys.stderr,
207
+ )
208
+ sys.exit(2)
209
+ else:
210
+ settings_dir.mkdir(parents=True, exist_ok=True)
211
+
212
+ existing_hooks = settings.get("hooks", {})
213
+ settings["hooks"] = merge_hooks(tagged, existing_hooks, source)
214
+ save_json(str(settings_path), settings)
215
+ print(f"Injected hooks from '{source}' into {settings_path}")
216
+
217
+
218
+ def remove(source_name: str, target_dir: str) -> None:
219
+ """Remove all hook entries tagged with *source_name*.
220
+
221
+ Args:
222
+ source_name: The ``_source`` tag to remove.
223
+ target_dir: Directory containing ``.claude/settings.json``.
224
+ """
225
+ if source_name == PROTECTED_SOURCE:
226
+ print(
227
+ f"Error: cannot remove '{PROTECTED_SOURCE}' entries. "
228
+ "Use 'ai-toolkit uninstall' instead.",
229
+ file=sys.stderr,
230
+ )
231
+ sys.exit(1)
232
+
233
+ settings_path = Path(target_dir) / ".claude" / "settings.json"
234
+
235
+ if not settings_path.is_file():
236
+ print(f"No settings.json found at {settings_path}")
237
+ return
238
+
239
+ try:
240
+ settings = load_json(str(settings_path))
241
+ except json.JSONDecodeError as exc:
242
+ print(
243
+ f"Error: malformed JSON in {settings_path}: {exc}",
244
+ file=sys.stderr,
245
+ )
246
+ sys.exit(2)
247
+
248
+ existing_hooks = settings.get("hooks", {})
249
+ cleaned = strip_source(existing_hooks, source_name)
250
+
251
+ if cleaned:
252
+ settings["hooks"] = cleaned
253
+ else:
254
+ settings.pop("hooks", None)
255
+
256
+ save_json(str(settings_path), settings)
257
+ print(f"Removed hooks with source '{source_name}' from {settings_path}")
258
+
259
+
260
+ # ---------------------------------------------------------------------------
261
+ # Argument parsing
262
+ # ---------------------------------------------------------------------------
263
+
264
+ def _parse_args(argv: list[str]) -> dict:
265
+ """Parse CLI arguments.
266
+
267
+ Returns:
268
+ Dict with keys: remove_mode, remove_name, source_file, target_dir.
269
+ """
270
+ result: dict = {
271
+ "remove_mode": False,
272
+ "remove_name": "",
273
+ "source_file": "",
274
+ "target_dir": str(Path.home()),
275
+ }
276
+
277
+ i = 0
278
+ while i < len(argv):
279
+ arg = argv[i]
280
+ if arg == "--remove":
281
+ result["remove_mode"] = True
282
+ i += 1
283
+ if i >= len(argv):
284
+ print("--remove requires a hook source name", file=sys.stderr)
285
+ sys.exit(1)
286
+ result["remove_name"] = argv[i]
287
+ elif arg.startswith("-"):
288
+ print(f"Unknown option: {arg}", file=sys.stderr)
289
+ sys.exit(1)
290
+ elif not result["source_file"] and not result["remove_mode"]:
291
+ result["source_file"] = arg
292
+ else:
293
+ result["target_dir"] = arg
294
+ i += 1
295
+
296
+ return result
297
+
298
+
299
+ def main() -> None:
300
+ """Inject or remove external hooks in settings.json."""
301
+ args = _parse_args(sys.argv[1:])
302
+
303
+ # -- remove mode ---------------------------------------------------------
304
+ if args["remove_mode"]:
305
+ remove(args["remove_name"], args["target_dir"])
306
+ return
307
+
308
+ # -- inject mode ---------------------------------------------------------
309
+ source_file = args["source_file"]
310
+ if not source_file:
311
+ print(
312
+ "Usage: inject_hook_cli.py <hooks-file.json> [target-dir]",
313
+ file=sys.stderr,
314
+ )
315
+ print(
316
+ " inject_hook_cli.py --remove <hook-source-name> [target-dir]",
317
+ file=sys.stderr,
318
+ )
319
+ sys.exit(1)
320
+
321
+ source_path = Path(source_file)
322
+ if not source_path.is_file():
323
+ print(f"Hooks file not found: {source_path}", file=sys.stderr)
324
+ sys.exit(1)
325
+
326
+ inject(source_file, args["target_dir"])
327
+
328
+
329
+ if __name__ == "__main__":
330
+ main()