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.
- package/.claude-plugin/plugin.json +44 -0
- package/.cursor/agents/deep-researcher.md +142 -0
- package/.cursor/agents/doc-updater.md +219 -0
- package/.cursor/agents/eval-runner.md +335 -0
- package/.cursor/agents/learning-engine.md +210 -0
- package/.cursor/agents/loop-operator.md +245 -0
- package/.cursor/agents/refactor-cleaner.md +119 -0
- package/.cursor/agents/sf-admin-agent.md +127 -0
- package/.cursor/agents/sf-agentforce-agent.md +126 -0
- package/.cursor/agents/sf-apex-agent.md +117 -0
- package/.cursor/agents/sf-architect.md +426 -0
- package/.cursor/agents/sf-aura-reviewer.md +369 -0
- package/.cursor/agents/sf-bugfix-agent.md +101 -0
- package/.cursor/agents/sf-flow-agent.md +155 -0
- package/.cursor/agents/sf-integration-agent.md +141 -0
- package/.cursor/agents/sf-lwc-agent.md +123 -0
- package/.cursor/agents/sf-review-agent.md +357 -0
- package/.cursor/agents/sf-visualforce-reviewer.md +465 -0
- package/.cursor/hooks/adapter.js +81 -0
- package/.cursor/hooks/after-file-edit.js +26 -0
- package/.cursor/hooks/after-mcp-execution.js +12 -0
- package/.cursor/hooks/after-shell-execution.js +30 -0
- package/.cursor/hooks/after-tab-file-edit.js +12 -0
- package/.cursor/hooks/before-mcp-execution.js +11 -0
- package/.cursor/hooks/before-read-file.js +13 -0
- package/.cursor/hooks/before-shell-execution.js +29 -0
- package/.cursor/hooks/before-submit-prompt.js +23 -0
- package/.cursor/hooks/pre-compact.js +7 -0
- package/.cursor/hooks/session-end.js +10 -0
- package/.cursor/hooks/session-start.js +10 -0
- package/.cursor/hooks/stop.js +18 -0
- package/.cursor/hooks/subagent-start.js +10 -0
- package/.cursor/hooks/subagent-stop.js +10 -0
- package/.cursor/hooks.json +107 -0
- package/.cursor/skills/aside/SKILL.md +115 -0
- package/.cursor/skills/checkpoint/SKILL.md +50 -0
- package/.cursor/skills/configure-scc/SKILL.md +160 -0
- package/.cursor/skills/continuous-agent-loop/SKILL.md +260 -0
- package/.cursor/skills/mcp-server-patterns/SKILL.md +142 -0
- package/.cursor/skills/model-route/SKILL.md +81 -0
- package/.cursor/skills/prompt-optimizer/SKILL.md +366 -0
- package/.cursor/skills/refactor-clean/SKILL.md +133 -0
- package/.cursor/skills/resume-session/SKILL.md +111 -0
- package/.cursor/skills/save-session/SKILL.md +183 -0
- package/.cursor/skills/search-first/SKILL.md +140 -0
- package/.cursor/skills/security-scan/SKILL.md +142 -0
- package/.cursor/skills/sessions/SKILL.md +124 -0
- package/.cursor/skills/sf-agentforce-development/SKILL.md +449 -0
- package/.cursor/skills/sf-apex-async-patterns/SKILL.md +324 -0
- package/.cursor/skills/sf-apex-best-practices/SKILL.md +421 -0
- package/.cursor/skills/sf-apex-constraints/SKILL.md +79 -0
- package/.cursor/skills/sf-apex-cursor/SKILL.md +336 -0
- package/.cursor/skills/sf-apex-enterprise-patterns/SKILL.md +344 -0
- package/.cursor/skills/sf-apex-testing/SKILL.md +407 -0
- package/.cursor/skills/sf-api-design/SKILL.md +237 -0
- package/.cursor/skills/sf-approval-processes/SKILL.md +312 -0
- package/.cursor/skills/sf-aura-development/SKILL.md +260 -0
- package/.cursor/skills/sf-build-fix/SKILL.md +120 -0
- package/.cursor/skills/sf-data-modeling/SKILL.md +274 -0
- package/.cursor/skills/sf-debugging/SKILL.md +362 -0
- package/.cursor/skills/sf-deployment/SKILL.md +291 -0
- package/.cursor/skills/sf-deployment-constraints/SKILL.md +153 -0
- package/.cursor/skills/sf-devops-ci-cd/SKILL.md +322 -0
- package/.cursor/skills/sf-docs-lookup/SKILL.md +100 -0
- package/.cursor/skills/sf-e2e-testing/SKILL.md +321 -0
- package/.cursor/skills/sf-experience-cloud/SKILL.md +248 -0
- package/.cursor/skills/sf-flow-development/SKILL.md +376 -0
- package/.cursor/skills/sf-governor-limits/SKILL.md +319 -0
- package/.cursor/skills/sf-harness-audit/SKILL.md +139 -0
- package/.cursor/skills/sf-help/SKILL.md +156 -0
- package/.cursor/skills/sf-integration/SKILL.md +479 -0
- package/.cursor/skills/sf-lwc-constraints/SKILL.md +128 -0
- package/.cursor/skills/sf-lwc-development/SKILL.md +302 -0
- package/.cursor/skills/sf-lwc-testing/SKILL.md +387 -0
- package/.cursor/skills/sf-metadata-management/SKILL.md +285 -0
- package/.cursor/skills/sf-platform-events-cdc/SKILL.md +372 -0
- package/.cursor/skills/sf-quickstart/SKILL.md +170 -0
- package/.cursor/skills/sf-security/SKILL.md +330 -0
- package/.cursor/skills/sf-security-constraints/SKILL.md +125 -0
- package/.cursor/skills/sf-soql-constraints/SKILL.md +129 -0
- package/.cursor/skills/sf-soql-optimization/SKILL.md +353 -0
- package/.cursor/skills/sf-tdd-workflow/SKILL.md +332 -0
- package/.cursor/skills/sf-testing-constraints/SKILL.md +198 -0
- package/.cursor/skills/sf-trigger-constraints/SKILL.md +88 -0
- package/.cursor/skills/sf-trigger-frameworks/SKILL.md +343 -0
- package/.cursor/skills/sf-visualforce-development/SKILL.md +259 -0
- package/.cursor/skills/strategic-compact/SKILL.md +205 -0
- package/.cursor/skills/update-docs/SKILL.md +162 -0
- package/.cursor/skills/update-platform-docs/SKILL.md +86 -0
- package/.cursor-plugin/plugin.json +26 -0
- package/LICENSE +21 -0
- package/README.md +522 -0
- package/agents/deep-researcher.md +145 -0
- package/agents/doc-updater.md +222 -0
- package/agents/eval-runner.md +340 -0
- package/agents/learning-engine.md +211 -0
- package/agents/loop-operator.md +247 -0
- package/agents/refactor-cleaner.md +122 -0
- package/agents/sf-admin-agent.md +131 -0
- package/agents/sf-agentforce-agent.md +132 -0
- package/agents/sf-apex-agent.md +124 -0
- package/agents/sf-architect.md +435 -0
- package/agents/sf-aura-reviewer.md +372 -0
- package/agents/sf-bugfix-agent.md +105 -0
- package/agents/sf-flow-agent.md +159 -0
- package/agents/sf-integration-agent.md +146 -0
- package/agents/sf-lwc-agent.md +127 -0
- package/agents/sf-review-agent.md +366 -0
- package/agents/sf-visualforce-reviewer.md +468 -0
- package/assets/logo.svg +18 -0
- package/docs/ARCHITECTURE.md +133 -0
- package/docs/authoring-guide.md +373 -0
- package/docs/hook-development.md +578 -0
- package/docs/token-optimization.md +139 -0
- package/docs/workflow-examples.md +645 -0
- package/examples/agentforce-action/README.md +227 -0
- package/examples/apex-trigger-handler/README.md +114 -0
- package/examples/devops-pipeline/README.md +325 -0
- package/examples/flow-automation/README.md +188 -0
- package/examples/integration-pattern/README.md +416 -0
- package/examples/lwc-component/README.md +180 -0
- package/examples/platform-events/README.md +492 -0
- package/examples/scratch-org-setup/README.md +138 -0
- package/examples/security-audit/README.md +244 -0
- package/examples/visualforce-migration/README.md +314 -0
- package/hooks/hooks.json +338 -0
- package/hooks/memory-persistence/README.md +73 -0
- package/manifests/install-modules.json +217 -0
- package/manifests/install-profiles.json +17 -0
- package/mcp-configs/mcp-servers.json +19 -0
- package/package.json +89 -0
- package/schemas/hooks.schema.json +123 -0
- package/schemas/install-modules.schema.json +76 -0
- package/schemas/install-profiles.schema.json +28 -0
- package/schemas/install-state.schema.json +73 -0
- package/schemas/package-manager.schema.json +18 -0
- package/schemas/plugin.schema.json +112 -0
- package/schemas/scc-install-config.schema.json +29 -0
- package/schemas/state-store.schema.json +111 -0
- package/scripts/cli/install-apply.js +170 -0
- package/scripts/cli/uninstall.js +193 -0
- package/scripts/hooks/check-console-log.js +101 -0
- package/scripts/hooks/check-hook-enabled.js +17 -0
- package/scripts/hooks/check-platform-docs-age.js +48 -0
- package/scripts/hooks/cost-tracker.js +78 -0
- package/scripts/hooks/doc-file-warning.js +63 -0
- package/scripts/hooks/evaluate-session.js +98 -0
- package/scripts/hooks/governor-check.js +220 -0
- package/scripts/hooks/learning-observe.sh +206 -0
- package/scripts/hooks/mcp-health-check.js +588 -0
- package/scripts/hooks/post-bash-build-complete.js +34 -0
- package/scripts/hooks/post-bash-pr-created.js +43 -0
- package/scripts/hooks/post-edit-console-warn.js +61 -0
- package/scripts/hooks/post-edit-format.js +79 -0
- package/scripts/hooks/post-edit-typecheck.js +98 -0
- package/scripts/hooks/post-write.js +168 -0
- package/scripts/hooks/pre-bash-git-push-reminder.js +35 -0
- package/scripts/hooks/pre-bash-tmux-reminder.js +47 -0
- package/scripts/hooks/pre-compact.js +51 -0
- package/scripts/hooks/pre-tool-use.js +163 -0
- package/scripts/hooks/pre-write-doc-warn.js +9 -0
- package/scripts/hooks/quality-gate.js +251 -0
- package/scripts/hooks/run-with-flags-shell.sh +32 -0
- package/scripts/hooks/run-with-flags.js +135 -0
- package/scripts/hooks/session-end-marker.js +29 -0
- package/scripts/hooks/session-end.js +311 -0
- package/scripts/hooks/session-start.js +202 -0
- package/scripts/hooks/sfdx-scanner-check.js +142 -0
- package/scripts/hooks/sfdx-validate.js +119 -0
- package/scripts/hooks/stop-hook.js +170 -0
- package/scripts/hooks/suggest-compact.js +67 -0
- package/scripts/lib/agent-adapter.js +82 -0
- package/scripts/lib/apex-analysis.js +194 -0
- package/scripts/lib/hook-flags.js +74 -0
- package/scripts/lib/install-config.js +73 -0
- package/scripts/lib/install-executor.js +363 -0
- package/scripts/lib/install-state.js +121 -0
- package/scripts/lib/orchestration-session.js +299 -0
- package/scripts/lib/package-manager.js +124 -0
- package/scripts/lib/project-detect.js +228 -0
- package/scripts/lib/schema-validator.js +190 -0
- package/scripts/lib/skill-adapter.js +100 -0
- package/scripts/lib/state-store.js +376 -0
- package/scripts/lib/tmux-worktree-orchestrator.js +598 -0
- package/scripts/lib/utils.js +313 -0
- package/scripts/scc.js +164 -0
- package/skills/_reference/AGENTFORCE_PATTERNS.md +112 -0
- package/skills/_reference/APEX_CURSOR.md +159 -0
- package/skills/_reference/API_VERSIONS.md +78 -0
- package/skills/_reference/APPROVAL_PROCESSES.md +105 -0
- package/skills/_reference/ASYNC_PATTERNS.md +163 -0
- package/skills/_reference/AURA_COMPONENTS.md +146 -0
- package/skills/_reference/DATA_MIGRATION_PATTERNS.md +151 -0
- package/skills/_reference/DATA_MODELING.md +124 -0
- package/skills/_reference/DEBUGGING_TOOLS.md +140 -0
- package/skills/_reference/DEPLOYMENT_CHECKLIST.md +87 -0
- package/skills/_reference/DEPRECATIONS.md +79 -0
- package/skills/_reference/DOCKER_CI_PATTERNS.md +138 -0
- package/skills/_reference/ENTERPRISE_PATTERNS.md +122 -0
- package/skills/_reference/EXPERIENCE_CLOUD.md +143 -0
- package/skills/_reference/FLOW_PATTERNS.md +113 -0
- package/skills/_reference/GOVERNOR_LIMITS.md +77 -0
- package/skills/_reference/INTEGRATION_PATTERNS.md +105 -0
- package/skills/_reference/LWC_PATTERNS.md +79 -0
- package/skills/_reference/METADATA_TYPES.md +115 -0
- package/skills/_reference/NAMING_CONVENTIONS.md +84 -0
- package/skills/_reference/PACKAGE_DEVELOPMENT.md +150 -0
- package/skills/_reference/PLATFORM_EVENTS.md +121 -0
- package/skills/_reference/REPORTING_API.md +143 -0
- package/skills/_reference/SCRATCH_ORG_PATTERNS.md +126 -0
- package/skills/_reference/SECURITY_PATTERNS.md +127 -0
- package/skills/_reference/SHARING_MODEL.md +120 -0
- package/skills/_reference/SOQL_PATTERNS.md +119 -0
- package/skills/_reference/TESTING_STANDARDS.md +96 -0
- package/skills/_reference/TRIGGER_PATTERNS.md +114 -0
- package/skills/_reference/VISUALFORCE_PATTERNS.md +121 -0
- package/skills/aside/SKILL.md +118 -0
- package/skills/checkpoint/SKILL.md +53 -0
- package/skills/configure-scc/SKILL.md +163 -0
- package/skills/continuous-agent-loop/SKILL.md +264 -0
- package/skills/mcp-server-patterns/SKILL.md +146 -0
- package/skills/model-route/SKILL.md +84 -0
- package/skills/prompt-optimizer/SKILL.md +369 -0
- package/skills/refactor-clean/SKILL.md +136 -0
- package/skills/resume-session/SKILL.md +114 -0
- package/skills/save-session/SKILL.md +186 -0
- package/skills/search-first/SKILL.md +144 -0
- package/skills/security-scan/SKILL.md +146 -0
- package/skills/sessions/SKILL.md +127 -0
- package/skills/sf-agentforce-development/SKILL.md +450 -0
- package/skills/sf-apex-async-patterns/SKILL.md +326 -0
- package/skills/sf-apex-best-practices/SKILL.md +425 -0
- package/skills/sf-apex-constraints/SKILL.md +81 -0
- package/skills/sf-apex-cursor/SKILL.md +338 -0
- package/skills/sf-apex-enterprise-patterns/SKILL.md +348 -0
- package/skills/sf-apex-testing/SKILL.md +409 -0
- package/skills/sf-api-design/SKILL.md +238 -0
- package/skills/sf-approval-processes/SKILL.md +315 -0
- package/skills/sf-aura-development/SKILL.md +263 -0
- package/skills/sf-build-fix/SKILL.md +121 -0
- package/skills/sf-data-modeling/SKILL.md +278 -0
- package/skills/sf-debugging/SKILL.md +363 -0
- package/skills/sf-deployment/SKILL.md +295 -0
- package/skills/sf-deployment-constraints/SKILL.md +155 -0
- package/skills/sf-devops-ci-cd/SKILL.md +325 -0
- package/skills/sf-docs-lookup/SKILL.md +103 -0
- package/skills/sf-e2e-testing/SKILL.md +324 -0
- package/skills/sf-experience-cloud/SKILL.md +249 -0
- package/skills/sf-flow-development/SKILL.md +377 -0
- package/skills/sf-governor-limits/SKILL.md +323 -0
- package/skills/sf-harness-audit/SKILL.md +142 -0
- package/skills/sf-help/SKILL.md +159 -0
- package/skills/sf-integration/SKILL.md +483 -0
- package/skills/sf-lwc-constraints/SKILL.md +130 -0
- package/skills/sf-lwc-development/SKILL.md +303 -0
- package/skills/sf-lwc-testing/SKILL.md +388 -0
- package/skills/sf-metadata-management/SKILL.md +288 -0
- package/skills/sf-platform-events-cdc/SKILL.md +375 -0
- package/skills/sf-quickstart/SKILL.md +173 -0
- package/skills/sf-security/SKILL.md +334 -0
- package/skills/sf-security-constraints/SKILL.md +127 -0
- package/skills/sf-soql-constraints/SKILL.md +131 -0
- package/skills/sf-soql-optimization/SKILL.md +354 -0
- package/skills/sf-tdd-workflow/SKILL.md +336 -0
- package/skills/sf-testing-constraints/SKILL.md +200 -0
- package/skills/sf-trigger-constraints/SKILL.md +90 -0
- package/skills/sf-trigger-frameworks/SKILL.md +347 -0
- package/skills/sf-visualforce-development/SKILL.md +260 -0
- package/skills/strategic-compact/SKILL.md +208 -0
- package/skills/update-docs/SKILL.md +165 -0
- 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.
|