scc-universal 1.1.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 (271) hide show
  1. package/.claude-plugin/plugin.json +44 -0
  2. package/.cursor/agents/deep-researcher.md +142 -0
  3. package/.cursor/agents/doc-updater.md +219 -0
  4. package/.cursor/agents/eval-runner.md +335 -0
  5. package/.cursor/agents/learning-engine.md +210 -0
  6. package/.cursor/agents/loop-operator.md +245 -0
  7. package/.cursor/agents/refactor-cleaner.md +119 -0
  8. package/.cursor/agents/sf-admin-agent.md +127 -0
  9. package/.cursor/agents/sf-agentforce-agent.md +126 -0
  10. package/.cursor/agents/sf-apex-agent.md +117 -0
  11. package/.cursor/agents/sf-architect.md +426 -0
  12. package/.cursor/agents/sf-aura-reviewer.md +369 -0
  13. package/.cursor/agents/sf-bugfix-agent.md +101 -0
  14. package/.cursor/agents/sf-flow-agent.md +155 -0
  15. package/.cursor/agents/sf-integration-agent.md +141 -0
  16. package/.cursor/agents/sf-lwc-agent.md +123 -0
  17. package/.cursor/agents/sf-review-agent.md +357 -0
  18. package/.cursor/agents/sf-visualforce-reviewer.md +465 -0
  19. package/.cursor/hooks/adapter.js +81 -0
  20. package/.cursor/hooks/after-file-edit.js +26 -0
  21. package/.cursor/hooks/after-mcp-execution.js +12 -0
  22. package/.cursor/hooks/after-shell-execution.js +30 -0
  23. package/.cursor/hooks/after-tab-file-edit.js +12 -0
  24. package/.cursor/hooks/before-mcp-execution.js +11 -0
  25. package/.cursor/hooks/before-read-file.js +13 -0
  26. package/.cursor/hooks/before-shell-execution.js +29 -0
  27. package/.cursor/hooks/before-submit-prompt.js +23 -0
  28. package/.cursor/hooks/pre-compact.js +7 -0
  29. package/.cursor/hooks/session-end.js +10 -0
  30. package/.cursor/hooks/session-start.js +10 -0
  31. package/.cursor/hooks/stop.js +18 -0
  32. package/.cursor/hooks/subagent-start.js +10 -0
  33. package/.cursor/hooks/subagent-stop.js +10 -0
  34. package/.cursor/hooks.json +107 -0
  35. package/.cursor/skills/aside/SKILL.md +115 -0
  36. package/.cursor/skills/checkpoint/SKILL.md +50 -0
  37. package/.cursor/skills/configure-scc/SKILL.md +160 -0
  38. package/.cursor/skills/continuous-agent-loop/SKILL.md +260 -0
  39. package/.cursor/skills/mcp-server-patterns/SKILL.md +142 -0
  40. package/.cursor/skills/model-route/SKILL.md +81 -0
  41. package/.cursor/skills/prompt-optimizer/SKILL.md +366 -0
  42. package/.cursor/skills/refactor-clean/SKILL.md +133 -0
  43. package/.cursor/skills/resume-session/SKILL.md +111 -0
  44. package/.cursor/skills/save-session/SKILL.md +183 -0
  45. package/.cursor/skills/search-first/SKILL.md +140 -0
  46. package/.cursor/skills/security-scan/SKILL.md +142 -0
  47. package/.cursor/skills/sessions/SKILL.md +124 -0
  48. package/.cursor/skills/sf-agentforce-development/SKILL.md +449 -0
  49. package/.cursor/skills/sf-apex-async-patterns/SKILL.md +324 -0
  50. package/.cursor/skills/sf-apex-best-practices/SKILL.md +421 -0
  51. package/.cursor/skills/sf-apex-constraints/SKILL.md +79 -0
  52. package/.cursor/skills/sf-apex-cursor/SKILL.md +336 -0
  53. package/.cursor/skills/sf-apex-enterprise-patterns/SKILL.md +344 -0
  54. package/.cursor/skills/sf-apex-testing/SKILL.md +407 -0
  55. package/.cursor/skills/sf-api-design/SKILL.md +237 -0
  56. package/.cursor/skills/sf-approval-processes/SKILL.md +312 -0
  57. package/.cursor/skills/sf-aura-development/SKILL.md +260 -0
  58. package/.cursor/skills/sf-build-fix/SKILL.md +120 -0
  59. package/.cursor/skills/sf-data-modeling/SKILL.md +274 -0
  60. package/.cursor/skills/sf-debugging/SKILL.md +362 -0
  61. package/.cursor/skills/sf-deployment/SKILL.md +291 -0
  62. package/.cursor/skills/sf-deployment-constraints/SKILL.md +153 -0
  63. package/.cursor/skills/sf-devops-ci-cd/SKILL.md +322 -0
  64. package/.cursor/skills/sf-docs-lookup/SKILL.md +100 -0
  65. package/.cursor/skills/sf-e2e-testing/SKILL.md +321 -0
  66. package/.cursor/skills/sf-experience-cloud/SKILL.md +248 -0
  67. package/.cursor/skills/sf-flow-development/SKILL.md +376 -0
  68. package/.cursor/skills/sf-governor-limits/SKILL.md +319 -0
  69. package/.cursor/skills/sf-harness-audit/SKILL.md +139 -0
  70. package/.cursor/skills/sf-help/SKILL.md +156 -0
  71. package/.cursor/skills/sf-integration/SKILL.md +479 -0
  72. package/.cursor/skills/sf-lwc-constraints/SKILL.md +128 -0
  73. package/.cursor/skills/sf-lwc-development/SKILL.md +302 -0
  74. package/.cursor/skills/sf-lwc-testing/SKILL.md +387 -0
  75. package/.cursor/skills/sf-metadata-management/SKILL.md +285 -0
  76. package/.cursor/skills/sf-platform-events-cdc/SKILL.md +372 -0
  77. package/.cursor/skills/sf-quickstart/SKILL.md +170 -0
  78. package/.cursor/skills/sf-security/SKILL.md +330 -0
  79. package/.cursor/skills/sf-security-constraints/SKILL.md +125 -0
  80. package/.cursor/skills/sf-soql-constraints/SKILL.md +129 -0
  81. package/.cursor/skills/sf-soql-optimization/SKILL.md +353 -0
  82. package/.cursor/skills/sf-tdd-workflow/SKILL.md +332 -0
  83. package/.cursor/skills/sf-testing-constraints/SKILL.md +198 -0
  84. package/.cursor/skills/sf-trigger-constraints/SKILL.md +88 -0
  85. package/.cursor/skills/sf-trigger-frameworks/SKILL.md +343 -0
  86. package/.cursor/skills/sf-visualforce-development/SKILL.md +259 -0
  87. package/.cursor/skills/strategic-compact/SKILL.md +205 -0
  88. package/.cursor/skills/update-docs/SKILL.md +162 -0
  89. package/.cursor/skills/update-platform-docs/SKILL.md +86 -0
  90. package/.cursor-plugin/plugin.json +26 -0
  91. package/LICENSE +21 -0
  92. package/README.md +522 -0
  93. package/agents/deep-researcher.md +145 -0
  94. package/agents/doc-updater.md +222 -0
  95. package/agents/eval-runner.md +340 -0
  96. package/agents/learning-engine.md +211 -0
  97. package/agents/loop-operator.md +247 -0
  98. package/agents/refactor-cleaner.md +122 -0
  99. package/agents/sf-admin-agent.md +131 -0
  100. package/agents/sf-agentforce-agent.md +132 -0
  101. package/agents/sf-apex-agent.md +124 -0
  102. package/agents/sf-architect.md +435 -0
  103. package/agents/sf-aura-reviewer.md +372 -0
  104. package/agents/sf-bugfix-agent.md +105 -0
  105. package/agents/sf-flow-agent.md +159 -0
  106. package/agents/sf-integration-agent.md +146 -0
  107. package/agents/sf-lwc-agent.md +127 -0
  108. package/agents/sf-review-agent.md +366 -0
  109. package/agents/sf-visualforce-reviewer.md +468 -0
  110. package/assets/logo.svg +18 -0
  111. package/docs/ARCHITECTURE.md +133 -0
  112. package/docs/authoring-guide.md +373 -0
  113. package/docs/hook-development.md +578 -0
  114. package/docs/token-optimization.md +139 -0
  115. package/docs/workflow-examples.md +645 -0
  116. package/examples/agentforce-action/README.md +227 -0
  117. package/examples/apex-trigger-handler/README.md +114 -0
  118. package/examples/devops-pipeline/README.md +325 -0
  119. package/examples/flow-automation/README.md +188 -0
  120. package/examples/integration-pattern/README.md +416 -0
  121. package/examples/lwc-component/README.md +180 -0
  122. package/examples/platform-events/README.md +492 -0
  123. package/examples/scratch-org-setup/README.md +138 -0
  124. package/examples/security-audit/README.md +244 -0
  125. package/examples/visualforce-migration/README.md +314 -0
  126. package/hooks/hooks.json +338 -0
  127. package/hooks/memory-persistence/README.md +73 -0
  128. package/manifests/install-modules.json +217 -0
  129. package/manifests/install-profiles.json +17 -0
  130. package/mcp-configs/mcp-servers.json +19 -0
  131. package/package.json +89 -0
  132. package/schemas/hooks.schema.json +123 -0
  133. package/schemas/install-modules.schema.json +76 -0
  134. package/schemas/install-profiles.schema.json +28 -0
  135. package/schemas/install-state.schema.json +73 -0
  136. package/schemas/package-manager.schema.json +18 -0
  137. package/schemas/plugin.schema.json +112 -0
  138. package/schemas/scc-install-config.schema.json +29 -0
  139. package/schemas/state-store.schema.json +111 -0
  140. package/scripts/cli/install-apply.js +170 -0
  141. package/scripts/cli/uninstall.js +193 -0
  142. package/scripts/hooks/check-console-log.js +101 -0
  143. package/scripts/hooks/check-hook-enabled.js +17 -0
  144. package/scripts/hooks/check-platform-docs-age.js +48 -0
  145. package/scripts/hooks/cost-tracker.js +78 -0
  146. package/scripts/hooks/doc-file-warning.js +63 -0
  147. package/scripts/hooks/evaluate-session.js +98 -0
  148. package/scripts/hooks/governor-check.js +220 -0
  149. package/scripts/hooks/learning-observe.sh +206 -0
  150. package/scripts/hooks/mcp-health-check.js +588 -0
  151. package/scripts/hooks/post-bash-build-complete.js +34 -0
  152. package/scripts/hooks/post-bash-pr-created.js +43 -0
  153. package/scripts/hooks/post-edit-console-warn.js +61 -0
  154. package/scripts/hooks/post-edit-format.js +79 -0
  155. package/scripts/hooks/post-edit-typecheck.js +98 -0
  156. package/scripts/hooks/post-write.js +168 -0
  157. package/scripts/hooks/pre-bash-git-push-reminder.js +35 -0
  158. package/scripts/hooks/pre-bash-tmux-reminder.js +47 -0
  159. package/scripts/hooks/pre-compact.js +51 -0
  160. package/scripts/hooks/pre-tool-use.js +163 -0
  161. package/scripts/hooks/pre-write-doc-warn.js +9 -0
  162. package/scripts/hooks/quality-gate.js +251 -0
  163. package/scripts/hooks/run-with-flags-shell.sh +32 -0
  164. package/scripts/hooks/run-with-flags.js +135 -0
  165. package/scripts/hooks/session-end-marker.js +29 -0
  166. package/scripts/hooks/session-end.js +311 -0
  167. package/scripts/hooks/session-start.js +202 -0
  168. package/scripts/hooks/sfdx-scanner-check.js +142 -0
  169. package/scripts/hooks/sfdx-validate.js +119 -0
  170. package/scripts/hooks/stop-hook.js +170 -0
  171. package/scripts/hooks/suggest-compact.js +67 -0
  172. package/scripts/lib/agent-adapter.js +82 -0
  173. package/scripts/lib/apex-analysis.js +194 -0
  174. package/scripts/lib/hook-flags.js +74 -0
  175. package/scripts/lib/install-config.js +73 -0
  176. package/scripts/lib/install-executor.js +363 -0
  177. package/scripts/lib/install-state.js +121 -0
  178. package/scripts/lib/orchestration-session.js +299 -0
  179. package/scripts/lib/package-manager.js +124 -0
  180. package/scripts/lib/project-detect.js +228 -0
  181. package/scripts/lib/schema-validator.js +190 -0
  182. package/scripts/lib/skill-adapter.js +100 -0
  183. package/scripts/lib/state-store.js +376 -0
  184. package/scripts/lib/tmux-worktree-orchestrator.js +598 -0
  185. package/scripts/lib/utils.js +313 -0
  186. package/scripts/scc.js +164 -0
  187. package/skills/_reference/AGENTFORCE_PATTERNS.md +112 -0
  188. package/skills/_reference/APEX_CURSOR.md +159 -0
  189. package/skills/_reference/API_VERSIONS.md +78 -0
  190. package/skills/_reference/APPROVAL_PROCESSES.md +105 -0
  191. package/skills/_reference/ASYNC_PATTERNS.md +163 -0
  192. package/skills/_reference/AURA_COMPONENTS.md +146 -0
  193. package/skills/_reference/DATA_MIGRATION_PATTERNS.md +151 -0
  194. package/skills/_reference/DATA_MODELING.md +124 -0
  195. package/skills/_reference/DEBUGGING_TOOLS.md +140 -0
  196. package/skills/_reference/DEPLOYMENT_CHECKLIST.md +87 -0
  197. package/skills/_reference/DEPRECATIONS.md +79 -0
  198. package/skills/_reference/DOCKER_CI_PATTERNS.md +138 -0
  199. package/skills/_reference/ENTERPRISE_PATTERNS.md +122 -0
  200. package/skills/_reference/EXPERIENCE_CLOUD.md +143 -0
  201. package/skills/_reference/FLOW_PATTERNS.md +113 -0
  202. package/skills/_reference/GOVERNOR_LIMITS.md +77 -0
  203. package/skills/_reference/INTEGRATION_PATTERNS.md +105 -0
  204. package/skills/_reference/LWC_PATTERNS.md +79 -0
  205. package/skills/_reference/METADATA_TYPES.md +115 -0
  206. package/skills/_reference/NAMING_CONVENTIONS.md +84 -0
  207. package/skills/_reference/PACKAGE_DEVELOPMENT.md +150 -0
  208. package/skills/_reference/PLATFORM_EVENTS.md +121 -0
  209. package/skills/_reference/REPORTING_API.md +143 -0
  210. package/skills/_reference/SCRATCH_ORG_PATTERNS.md +126 -0
  211. package/skills/_reference/SECURITY_PATTERNS.md +127 -0
  212. package/skills/_reference/SHARING_MODEL.md +120 -0
  213. package/skills/_reference/SOQL_PATTERNS.md +119 -0
  214. package/skills/_reference/TESTING_STANDARDS.md +96 -0
  215. package/skills/_reference/TRIGGER_PATTERNS.md +114 -0
  216. package/skills/_reference/VISUALFORCE_PATTERNS.md +121 -0
  217. package/skills/aside/SKILL.md +118 -0
  218. package/skills/checkpoint/SKILL.md +53 -0
  219. package/skills/configure-scc/SKILL.md +163 -0
  220. package/skills/continuous-agent-loop/SKILL.md +264 -0
  221. package/skills/mcp-server-patterns/SKILL.md +146 -0
  222. package/skills/model-route/SKILL.md +84 -0
  223. package/skills/prompt-optimizer/SKILL.md +369 -0
  224. package/skills/refactor-clean/SKILL.md +136 -0
  225. package/skills/resume-session/SKILL.md +114 -0
  226. package/skills/save-session/SKILL.md +186 -0
  227. package/skills/search-first/SKILL.md +144 -0
  228. package/skills/security-scan/SKILL.md +146 -0
  229. package/skills/sessions/SKILL.md +127 -0
  230. package/skills/sf-agentforce-development/SKILL.md +450 -0
  231. package/skills/sf-apex-async-patterns/SKILL.md +326 -0
  232. package/skills/sf-apex-best-practices/SKILL.md +425 -0
  233. package/skills/sf-apex-constraints/SKILL.md +81 -0
  234. package/skills/sf-apex-cursor/SKILL.md +338 -0
  235. package/skills/sf-apex-enterprise-patterns/SKILL.md +348 -0
  236. package/skills/sf-apex-testing/SKILL.md +409 -0
  237. package/skills/sf-api-design/SKILL.md +238 -0
  238. package/skills/sf-approval-processes/SKILL.md +315 -0
  239. package/skills/sf-aura-development/SKILL.md +263 -0
  240. package/skills/sf-build-fix/SKILL.md +121 -0
  241. package/skills/sf-data-modeling/SKILL.md +278 -0
  242. package/skills/sf-debugging/SKILL.md +363 -0
  243. package/skills/sf-deployment/SKILL.md +295 -0
  244. package/skills/sf-deployment-constraints/SKILL.md +155 -0
  245. package/skills/sf-devops-ci-cd/SKILL.md +325 -0
  246. package/skills/sf-docs-lookup/SKILL.md +103 -0
  247. package/skills/sf-e2e-testing/SKILL.md +324 -0
  248. package/skills/sf-experience-cloud/SKILL.md +249 -0
  249. package/skills/sf-flow-development/SKILL.md +377 -0
  250. package/skills/sf-governor-limits/SKILL.md +323 -0
  251. package/skills/sf-harness-audit/SKILL.md +142 -0
  252. package/skills/sf-help/SKILL.md +159 -0
  253. package/skills/sf-integration/SKILL.md +483 -0
  254. package/skills/sf-lwc-constraints/SKILL.md +130 -0
  255. package/skills/sf-lwc-development/SKILL.md +303 -0
  256. package/skills/sf-lwc-testing/SKILL.md +388 -0
  257. package/skills/sf-metadata-management/SKILL.md +288 -0
  258. package/skills/sf-platform-events-cdc/SKILL.md +375 -0
  259. package/skills/sf-quickstart/SKILL.md +173 -0
  260. package/skills/sf-security/SKILL.md +334 -0
  261. package/skills/sf-security-constraints/SKILL.md +127 -0
  262. package/skills/sf-soql-constraints/SKILL.md +131 -0
  263. package/skills/sf-soql-optimization/SKILL.md +354 -0
  264. package/skills/sf-tdd-workflow/SKILL.md +336 -0
  265. package/skills/sf-testing-constraints/SKILL.md +200 -0
  266. package/skills/sf-trigger-constraints/SKILL.md +90 -0
  267. package/skills/sf-trigger-frameworks/SKILL.md +347 -0
  268. package/skills/sf-visualforce-development/SKILL.md +260 -0
  269. package/skills/strategic-compact/SKILL.md +208 -0
  270. package/skills/update-docs/SKILL.md +165 -0
  271. package/skills/update-platform-docs/SKILL.md +90 -0
@@ -0,0 +1,578 @@
1
+ # Hook Development Guide
2
+
3
+ This guide covers how to develop, modify, and test hooks in Salesforce Claude Code (SCC). Hooks are lifecycle scripts that run automatically at specific points during a Claude Code session, providing validation, warnings, quality checks, and session management.
4
+
5
+ ## Hook Lifecycle Events
6
+
7
+ SCC hooks fire at seven lifecycle points defined in `hooks/hooks.json`:
8
+
9
+ | Event | When It Fires | Use Cases |
10
+ |---|---|---|
11
+ | **SessionStart** | When a new Claude Code session begins | Display project context, detect SF CLI version, list connected orgs |
12
+ | **PreToolUse** | Before any tool executes (Read, Write, Edit, Bash, etc.) | Block dangerous commands, validate SF CLI usage, warn before destructive operations |
13
+ | **PostToolUse** | After a tool executes successfully | Check governor limits on edited Apex, warn about console.log, run quality gates |
14
+ | **PostToolUseFailure** | After a tool execution fails | Track MCP failures, attempt server reconnection |
15
+ | **PreCompact** | Before context window compaction | Save session state so critical information survives compaction |
16
+ | **Stop** | When the agent stops (user presses Escape or task completes) | Summarize changes, check for leftover console.log, persist session, track costs |
17
+ | **SessionEnd** | When the session fully terminates | Mark session end in state store |
18
+
19
+ ## Hook File Structure
20
+
21
+ Every hook consists of two parts: an entry in `hooks/hooks.json` and a script file in `scripts/hooks/`.
22
+
23
+ ### hooks.json Entry
24
+
25
+ Each lifecycle event contains an array of hook definitions:
26
+
27
+ ```json
28
+ {
29
+ "hooks": {
30
+ "PostToolUse": [
31
+ {
32
+ "matcher": "Edit",
33
+ "hooks": [
34
+ {
35
+ "type": "command",
36
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/run-with-flags.js\" governor-check standard \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/governor-check.js\"",
37
+ "async": true,
38
+ "timeout": 10
39
+ }
40
+ ],
41
+ "description": "Check edited Apex files for governor limit violations (SOQL/DML in loops)"
42
+ }
43
+ ]
44
+ }
45
+ }
46
+ ```
47
+
48
+ **Fields:**
49
+
50
+ - `matcher` — Which tool triggers this hook. Values: `"Bash"`, `"Edit"`, `"Write"`, `"Read"`, `"Edit|Write"` (regex OR), `"*"` (all tools). Only used in `PreToolUse`, `PostToolUse`, and `PostToolUseFailure`.
51
+ - `hooks[].type` — Always `"command"` for script-based hooks.
52
+ - `hooks[].command` — The shell command to execute. Use `${CLAUDE_PLUGIN_ROOT}` for the plugin root path.
53
+ - `hooks[].async` — When `true`, the hook runs without blocking the agent. Most hooks should be async.
54
+ - `hooks[].timeout` — Maximum execution time in seconds. The hook is killed if it exceeds this.
55
+ - `description` — Human-readable description of what the hook does. Required by CI validation.
56
+
57
+ ### Hook Script Structure
58
+
59
+ Hook scripts are Node.js CommonJS modules in `scripts/hooks/`. There are two patterns:
60
+
61
+ **Modern pattern (recommended) -- exports a `run()` function:**
62
+
63
+ ```javascript
64
+ #!/usr/bin/env node
65
+ 'use strict';
66
+
67
+ const fs = require('fs');
68
+ const path = require('path');
69
+
70
+ function run(rawInput) {
71
+ try {
72
+ const input = JSON.parse(rawInput);
73
+ const filePath = String(input.tool_input?.file_path || '');
74
+
75
+ // Your hook logic here
76
+ if (shouldWarn(filePath)) {
77
+ process.stderr.write('[SCC MyHook] Warning: something detected\n');
78
+ }
79
+ } catch {
80
+ // Always handle errors gracefully -- never crash
81
+ }
82
+ return rawInput; // Pass stdin through to stdout unchanged
83
+ }
84
+
85
+ // Support both direct execution and require()
86
+ if (require.main === module) {
87
+ const MAX_STDIN = 1024 * 1024;
88
+ let raw = '';
89
+ process.stdin.setEncoding('utf8');
90
+ process.stdin.on('data', chunk => {
91
+ if (raw.length < MAX_STDIN) {
92
+ raw += chunk.substring(0, MAX_STDIN - raw.length);
93
+ }
94
+ });
95
+ process.stdin.on('end', () => {
96
+ const result = run(raw);
97
+ process.stdout.write(result);
98
+ });
99
+ }
100
+
101
+ module.exports = { run };
102
+ ```
103
+
104
+ **Legacy pattern -- reads stdin directly (still supported):**
105
+
106
+ ```javascript
107
+ #!/usr/bin/env node
108
+ 'use strict';
109
+
110
+ const readline = require('readline');
111
+
112
+ const MAX_STDIN = 1024 * 1024;
113
+ let rawInput = '';
114
+ const rl = readline.createInterface({ input: process.stdin });
115
+ rl.on('line', line => {
116
+ if (rawInput.length < MAX_STDIN) rawInput += line + '\n';
117
+ });
118
+
119
+ rl.on('close', () => {
120
+ let input = {};
121
+ try {
122
+ input = JSON.parse(rawInput.trim() || '{}');
123
+ } catch {
124
+ process.exit(0);
125
+ }
126
+
127
+ // Your hook logic here
128
+ process.exit(0);
129
+ });
130
+ ```
131
+
132
+ **Key conventions:**
133
+
134
+ - Output warnings/diagnostics to **stderr** (`process.stderr.write()`) -- these are shown to the user.
135
+ - Output the passthrough data to **stdout** (`process.stdout.write()`) -- this is the hook's return value.
136
+ - Always return the original stdin data unless you intend to modify the tool input/output.
137
+ - Exit with code 0 on success or non-fatal warnings. A non-zero exit code blocks the tool execution (for PreToolUse hooks) or signals failure.
138
+
139
+ ## Profile Gating with run-with-flags.js
140
+
141
+ Most hooks are wrapped with `run-with-flags.js` to control which hooks run based on the user's profile setting. This prevents aggressive hooks from running on users who want a lightweight experience.
142
+
143
+ ### Profile Levels
144
+
145
+ | Profile | Level | Description |
146
+ |---|---|---|
147
+ | `minimal` | 1 | Only essential hooks (session markers, cost tracking, pre-compact state saving) |
148
+ | `standard` | 2 | Default. All quality checks, governor detection, SF CLI validation, session persistence |
149
+ | `strict` | 3 | Everything in standard plus auto-formatting, type-checking, tmux reminders, sfdx-scanner |
150
+
151
+ ### How Profile Gating Works
152
+
153
+ The `run-with-flags.js` wrapper takes three arguments:
154
+
155
+ ```
156
+ node run-with-flags.js <hook-name> <min-profile> <script-path>
157
+ ```
158
+
159
+ - `hook-name` -- A unique identifier for the hook (used in `SCC_DISABLED_HOOKS`).
160
+ - `min-profile` -- The minimum profile required to run this hook (`minimal`, `standard`, or `strict`).
161
+ - `script-path` -- Absolute path to the hook script.
162
+
163
+ The wrapper:
164
+
165
+ 1. Reads stdin (the tool input/output JSON).
166
+ 2. Checks if the hook is disabled via `SCC_DISABLED_HOOKS`.
167
+ 3. Checks if the current `SCC_HOOK_PROFILE` meets the minimum level.
168
+ 4. If the hook should run, it either `require()`s the script (if it exports `run()`) or spawns it as a child process.
169
+ 5. If the hook should be skipped, it passes stdin through to stdout unchanged.
170
+
171
+ ### hooks.json Example with Profile Gating
172
+
173
+ ```json
174
+ {
175
+ "matcher": "Edit",
176
+ "hooks": [
177
+ {
178
+ "type": "command",
179
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/run-with-flags.js\" post-edit-format strict \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/post-edit-format.js\"",
180
+ "async": true,
181
+ "timeout": 15
182
+ }
183
+ ],
184
+ "description": "Auto-format edited files with Prettier (strict profile only)"
185
+ }
186
+ ```
187
+
188
+ This hook only runs when `SCC_HOOK_PROFILE=strict`.
189
+
190
+ ### Hooks Without Profile Gating
191
+
192
+ Some hooks run unconditionally (no `run-with-flags.js` wrapper):
193
+
194
+ - `session-start.js` -- Always displays project context.
195
+ - `pre-tool-use.js` -- Always validates SF CLI commands.
196
+ - `stop-hook.js` -- Always summarizes changes.
197
+ - `block-no-verify` (npm package) -- Always blocks `--no-verify` flag.
198
+
199
+ ## Environment Variables
200
+
201
+ | Variable | Default | Description |
202
+ |---|---|---|
203
+ | `SCC_HOOK_PROFILE` | `standard` | Controls which hooks run. Values: `minimal`, `standard`, `strict`. |
204
+ | `SCC_DISABLED_HOOKS` | (empty) | Comma-separated list of hook names to skip. Example: `governor-check,quality-gate`. |
205
+ | `CLAUDE_PLUGIN_ROOT` | Auto-detected | Root directory of the SCC plugin installation. Set automatically during install. |
206
+
207
+ ### Setting the Profile
208
+
209
+ ```bash
210
+ # In your shell profile (.zshrc, .bashrc)
211
+ export SCC_HOOK_PROFILE=strict
212
+
213
+ # Or per-session
214
+ SCC_HOOK_PROFILE=minimal claude
215
+
216
+ # Disable specific hooks
217
+ export SCC_DISABLED_HOOKS=post-edit-format,pre-bash-tmux-reminder
218
+ ```
219
+
220
+ ## How to Create a New Hook
221
+
222
+ Follow these steps to add a new hook to SCC.
223
+
224
+ ### Step 1 -- Write the Hook Script
225
+
226
+ Create a new file in `scripts/hooks/`. Use the modern `run()` export pattern:
227
+
228
+ ```javascript
229
+ #!/usr/bin/env node
230
+ 'use strict';
231
+
232
+ const fs = require('fs');
233
+ const path = require('path');
234
+
235
+ const MAX_STDIN = 1024 * 1024;
236
+
237
+ function log(msg) {
238
+ process.stderr.write(`${msg}\n`);
239
+ }
240
+
241
+ /**
242
+ * Main hook logic. Receives raw stdin JSON, returns it unchanged.
243
+ */
244
+ function run(rawInput) {
245
+ try {
246
+ const input = JSON.parse(rawInput);
247
+ const filePath = String(input.tool_input?.file_path || '');
248
+
249
+ // Example: check if the file is an Apex class
250
+ if (!filePath.endsWith('.cls') && !filePath.endsWith('.trigger')) {
251
+ return rawInput;
252
+ }
253
+
254
+ // Read and analyze the file
255
+ if (fs.existsSync(filePath)) {
256
+ const content = fs.readFileSync(filePath, 'utf8');
257
+ // ... your analysis logic ...
258
+
259
+ if (issuesFound) {
260
+ log('\n[SCC MyHook] Issues detected:');
261
+ log(' [WARNING] Description of the issue');
262
+ log(' Fix: How to resolve it\n');
263
+ }
264
+ }
265
+ } catch {
266
+ // Graceful failure -- never crash
267
+ }
268
+ return rawInput;
269
+ }
270
+
271
+ if (require.main === module) {
272
+ let raw = '';
273
+ process.stdin.setEncoding('utf8');
274
+ process.stdin.on('data', chunk => {
275
+ if (raw.length < MAX_STDIN) {
276
+ raw += chunk.substring(0, MAX_STDIN - raw.length);
277
+ }
278
+ });
279
+ process.stdin.on('end', () => {
280
+ const result = run(raw);
281
+ process.stdout.write(result);
282
+ });
283
+ }
284
+
285
+ module.exports = { run };
286
+ ```
287
+
288
+ ### Step 2 -- Add the Entry to hooks.json
289
+
290
+ Edit `hooks/hooks.json` and add your hook under the appropriate lifecycle event:
291
+
292
+ ```json
293
+ {
294
+ "matcher": "Edit",
295
+ "hooks": [
296
+ {
297
+ "type": "command",
298
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/run-with-flags.js\" my-hook-name standard \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/my-hook.js\"",
299
+ "async": true,
300
+ "timeout": 10
301
+ }
302
+ ],
303
+ "description": "Short description of what this hook does"
304
+ }
305
+ ```
306
+
307
+ Choose the right lifecycle event:
308
+
309
+ - **PreToolUse** -- For validation/warnings before the action happens.
310
+ - **PostToolUse** -- For analysis/checks after the action succeeds.
311
+ - **PostToolUseFailure** -- For error recovery after the action fails.
312
+ - **Stop** -- For session-end summaries and cleanup.
313
+
314
+ ### Step 3 -- Write Tests
315
+
316
+ Create a test file at `tests/hooks/my-hook.test.js`. Follow the pattern used by existing tests:
317
+
318
+ ```javascript
319
+ #!/usr/bin/env node
320
+ 'use strict';
321
+
322
+ const assert = require('assert');
323
+ const fs = require('fs');
324
+ const path = require('path');
325
+ const os = require('os');
326
+
327
+ const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT || path.join(__dirname, '..', '..');
328
+ const hookPath = path.join(pluginRoot, 'scripts', 'hooks', 'my-hook.js');
329
+
330
+ let passCount = 0;
331
+ let failCount = 0;
332
+
333
+ function test(name, fn) {
334
+ try {
335
+ fn();
336
+ console.log(` PASS ${name}`);
337
+ passCount++;
338
+ } catch (err) {
339
+ console.error(` FAIL ${name}`);
340
+ console.error(` ${err.message}`);
341
+ failCount++;
342
+ }
343
+ }
344
+
345
+ test('my-hook.js: module exists', () => {
346
+ assert.ok(fs.existsSync(hookPath), 'my-hook.js not found');
347
+ });
348
+
349
+ if (fs.existsSync(hookPath)) {
350
+ const myHook = require(hookPath);
351
+
352
+ test('my-hook.js: exports run function', () => {
353
+ assert.ok(typeof myHook.run === 'function', 'Should export run()');
354
+ });
355
+
356
+ test('my-hook.js: handles empty input gracefully', () => {
357
+ const result = myHook.run('{}');
358
+ assert.ok(typeof result === 'string');
359
+ });
360
+
361
+ test('my-hook.js: detects the target condition', () => {
362
+ // Create a temp file, run the hook, check stderr output
363
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'scc-test-'));
364
+ const testFile = path.join(tmpDir, 'TestClass.cls');
365
+ fs.writeFileSync(testFile, 'public class TestClass { /* bad pattern */ }');
366
+
367
+ const captured = [];
368
+ const origWrite = process.stderr.write;
369
+ process.stderr.write = (msg) => { captured.push(msg); };
370
+ try {
371
+ const input = JSON.stringify({ tool_input: { file_path: testFile } });
372
+ myHook.run(input);
373
+ } finally {
374
+ process.stderr.write = origWrite;
375
+ fs.rmSync(tmpDir, { recursive: true });
376
+ }
377
+ const output = captured.join('');
378
+ assert.ok(output.includes('expected warning text'), 'Should detect the target condition');
379
+ });
380
+ }
381
+
382
+ console.log(`\nmy-hook.test.js: ${passCount} passed, ${failCount} failed`);
383
+ if (failCount > 0) process.exit(1);
384
+ ```
385
+
386
+ ### Step 4 -- Update the Cursor Mirror
387
+
388
+ For Cursor IDE parity, add a corresponding hook in `.cursor/hooks/`. Cursor hooks use different lifecycle names but the adapter layer (`adapter.js`) maps them.
389
+
390
+ | Claude Code Event | Cursor Equivalent |
391
+ |---|---|
392
+ | SessionStart | `session-start.js` |
393
+ | PreToolUse (Bash) | `before-shell-execution.js` |
394
+ | PreToolUse (Write/Edit) | `before-read-file.js` / `before-submit-prompt.js` |
395
+ | PostToolUse (Write/Edit) | `after-file-edit.js` / `after-tab-file-edit.js` |
396
+ | PostToolUse (Bash) | `after-shell-execution.js` |
397
+ | PreToolUse (MCP) | `before-mcp-execution.js` |
398
+ | PostToolUse (MCP) | `after-mcp-execution.js` |
399
+ | Stop | `stop.js` |
400
+ | SessionEnd | `session-end.js` |
401
+ | PreCompact | `pre-compact.js` |
402
+
403
+ ### Step 5 -- Run CI Validation
404
+
405
+ ```bash
406
+ node scripts/ci/validate-hooks.js
407
+ ```
408
+
409
+ This validator checks that:
410
+
411
+ - `hooks/hooks.json` is valid JSON and conforms to `schemas/hooks.schema.json`.
412
+ - Every script referenced in hooks.json actually exists on disk.
413
+ - Every hook entry has a `description` field.
414
+
415
+ ### Step 6 -- Run the Full Test Suite
416
+
417
+ ```bash
418
+ node tests/run-all.js
419
+ ```
420
+
421
+ ## Matcher Patterns for Tool-Specific Hooks
422
+
423
+ Matchers use regex-style patterns to target specific tools:
424
+
425
+ | Matcher | Targets |
426
+ |---|---|
427
+ | `"Bash"` | Shell/terminal command execution |
428
+ | `"Edit"` | File edit operations |
429
+ | `"Write"` | File write (create new file) operations |
430
+ | `"Read"` | File read operations |
431
+ | `"Edit\|Write"` | Either Edit or Write (regex OR syntax) |
432
+ | `"*"` | All tool invocations |
433
+
434
+ **Matcher-less hooks** (no `matcher` field) fire unconditionally for that lifecycle event. This is used for `SessionStart`, `PreCompact`, `Stop`, and `SessionEnd` events.
435
+
436
+ ## Timeout Configuration
437
+
438
+ Every hook should specify a `timeout` value (in seconds) to prevent runaway scripts from blocking the agent.
439
+
440
+ **Guidelines:**
441
+
442
+ | Hook Type | Recommended Timeout |
443
+ |---|---|
444
+ | Simple file checks (regex, lint) | 5-10 seconds |
445
+ | File analysis (AST parsing, governor checks) | 10-15 seconds |
446
+ | External tool invocation (Prettier, TypeScript compiler) | 15-30 seconds |
447
+ | Network operations (MCP health checks) | 10-15 seconds |
448
+ | Scanner/static analysis (sfdx-scanner PMD) | 30-45 seconds |
449
+
450
+ If a hook exceeds its timeout, `run-with-flags.js` kills the process and writes a timeout message to stderr. The agent continues normally.
451
+
452
+ ## Stdin/Stdout Protocol
453
+
454
+ Claude Code passes JSON to hooks via stdin and reads their response from stdout.
455
+
456
+ **PreToolUse stdin:**
457
+
458
+ ```json
459
+ {
460
+ "tool_name": "Bash",
461
+ "tool_input": {
462
+ "command": "sf project deploy start --source-dir force-app/"
463
+ }
464
+ }
465
+ ```
466
+
467
+ **PostToolUse stdin:**
468
+
469
+ ```json
470
+ {
471
+ "tool_name": "Edit",
472
+ "tool_input": {
473
+ "file_path": "/path/to/AccountService.cls",
474
+ "old_string": "...",
475
+ "new_string": "..."
476
+ },
477
+ "tool_output": "File edited successfully"
478
+ }
479
+ ```
480
+
481
+ **Stdout:** Return the original stdin JSON unchanged (passthrough). For PreToolUse hooks that need to block execution, exit with a non-zero code.
482
+
483
+ **Stderr:** Write diagnostic messages, warnings, and recommendations. These are displayed to the user in the Claude Code interface.
484
+
485
+ ## Best Practices
486
+
487
+ 1. **Fast execution.** Hooks run on every tool invocation. Keep execution under 100ms for common-path hooks. Use early returns when the hook does not apply (wrong file type, wrong tool, etc.).
488
+
489
+ 2. **Graceful failure.** Never let a hook crash or throw an unhandled exception. Wrap all logic in try/catch. A broken hook should fail silently, not break the user's workflow.
490
+
491
+ 3. **No blocking on async hooks.** Set `"async": true` for all hooks except those that must block tool execution (like `block-no-verify`). Blocking hooks freeze the agent until they complete.
492
+
493
+ 4. **Limit stdin reads.** Cap stdin reads at 1MB (`MAX_STDIN = 1024 * 1024`) to prevent memory issues with large tool outputs.
494
+
495
+ 5. **Use stderr for output.** All user-facing messages go to stderr. Stdout is reserved for the passthrough protocol.
496
+
497
+ 6. **Prefix messages.** Always prefix stderr output with `[SCC HookName]` so users can identify which hook produced the message.
498
+
499
+ 7. **Respect profiles.** Use `run-with-flags.js` for any hook that is not universally needed. Assign the lowest profile level that makes sense:
500
+ - `minimal` -- Essential infrastructure (session markers, cost tracking).
501
+ - `standard` -- Quality and safety checks most developers want.
502
+ - `strict` -- Aggressive checks for teams with strict standards.
503
+
504
+ 8. **Test with temp files.** Hook tests should create temporary files, run the hook, and clean up. Never depend on files existing in the repo.
505
+
506
+ 9. **Keep hooks stateless.** Hooks should not write to shared files or maintain global state between invocations. Use environment variables or the SCC state store for persistence.
507
+
508
+ 10. **Document the hook.** Every hooks.json entry requires a `description`. Make it concise but clear about what the hook checks and what action it takes.
509
+
510
+ ## Shell-Based Hooks
511
+
512
+ Some hooks use `run-with-flags-shell.sh` instead of the Node.js wrapper, for hooks written as shell scripts:
513
+
514
+ ```json
515
+ {
516
+ "matcher": "*",
517
+ "hooks": [{
518
+ "type": "command",
519
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/run-with-flags-shell.sh\" \"pre:observe\" \"scripts/hooks/learning-observe.sh\" \"standard,strict\"",
520
+ "async": true,
521
+ "timeout": 10
522
+ }],
523
+ "description": "Capture tool use observations for continuous learning"
524
+ }
525
+ ```
526
+
527
+ The shell wrapper follows the same profile-gating logic but for Bash scripts. The third argument is a comma-separated list of profiles that should run the hook.
528
+
529
+ ## Existing Hooks Reference
530
+
531
+ ### SessionStart
532
+
533
+ - **session-start.js** -- Detects sfdx-project.json, SF CLI version, connected orgs. Runs unconditionally.
534
+
535
+ ### PreToolUse
536
+
537
+ - **block-no-verify** -- Blocks `--no-verify` flag on git commands. No profile gating.
538
+ - **mcp-health-check.js** -- Checks MCP server health before MCP tool calls. Standard profile.
539
+ - **observe.sh** -- Captures tool use events for continuous learning. Standard/strict profiles.
540
+ - **pre-tool-use.js** -- Validates SF CLI commands (deprecation/danger warnings). No profile gating.
541
+ - **doc-file-warning.js** -- Warns about non-standard documentation files (Write matcher). Standard profile.
542
+ - **sfdx-validate.js** -- Validates SFDX commands for best practices. Standard profile.
543
+ - **pre-bash-git-push-reminder.js** -- Reminds to review changes before git push. Standard profile.
544
+ - **sfdx-scanner-check.js** -- Runs sfdx-scanner PMD analysis before deploy/push. Standard/strict profiles.
545
+ - **pre-bash-tmux-reminder.js** -- Suggests tmux for long-running SF CLI commands. Strict profile.
546
+ - **suggest-compact.js** -- Tracks tool call count, suggests compaction. Standard profile.
547
+
548
+ ### PostToolUse
549
+
550
+ - **observe.sh** -- Captures tool results for continuous learning. Standard/strict profiles.
551
+ - **post-write.js** -- Reminds about test coverage after Apex/LWC file writes. No profile gating.
552
+ - **quality-gate.js** -- Runs quality checks on edited Apex/LWC files. Standard profile.
553
+ - **governor-check.js** -- Checks for governor limit violations (SOQL/DML in loops). Standard profile.
554
+ - **post-edit-console-warn.js** -- Warns about console.log in JS/LWC files. Standard profile.
555
+ - **post-edit-format.js** -- Auto-formats with Prettier. Strict profile.
556
+ - **post-edit-typecheck.js** -- Type-checks TypeScript/LWC files. Strict profile.
557
+ - **post-bash-build-complete.js** -- Detects build/deploy completion. Standard profile.
558
+ - **post-bash-pr-created.js** -- Detects PR creation and logs review command. Standard profile.
559
+
560
+ ### PostToolUseFailure
561
+
562
+ - **mcp-health-check.js** -- Tracks failed MCP calls, marks unhealthy servers. Standard profile.
563
+
564
+ ### PreCompact
565
+
566
+ - **pre-compact.js** -- Saves session state before context compaction. Minimal profile.
567
+
568
+ ### Stop
569
+
570
+ - **stop-hook.js** -- Summarizes Salesforce changes and suggests next steps. No profile gating.
571
+ - **check-console-log.js** -- Checks for console.log in modified files. Standard profile.
572
+ - **session-end.js** -- Persists session summary. Standard profile.
573
+ - **cost-tracker.js** -- Tracks token usage and estimated costs. Minimal profile.
574
+ - **evaluate-session.js** -- Evaluates session for extractable patterns. Standard profile.
575
+
576
+ ### SessionEnd
577
+
578
+ - **session-end-marker.js** -- Non-blocking session end lifecycle marker. Minimal profile.