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,170 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * install-apply.js — Apply SCC content installation.
6
+ *
7
+ * Usage:
8
+ * node install-apply.js [target] [--profile <name>] [--target <name>] [--dry-run] [--help]
9
+ *
10
+ * Targets: apex, lwc, all (shorthand for 'full' profile)
11
+ * Profiles: core, apex, lwc, devops, security, full
12
+ */
13
+
14
+ const path = require('path');
15
+ const { executeInstall, VALID_TARGETS, VALID_PROFILES } = require('../lib/install-executor');
16
+ const { loadInstallConfig } = require('../lib/install-config');
17
+
18
+ function showHelp(exitCode = 0) {
19
+ console.log(`
20
+ scc install — Install SCC content
21
+
22
+ Usage:
23
+ scc install [target] [options]
24
+ scc install --profile <name> --target <name>
25
+
26
+ Shorthand targets:
27
+ apex Install Apex profile content
28
+ lwc Install LWC profile content
29
+ all Install full profile content
30
+
31
+ Options:
32
+ --profile <name> Profile to install: core|apex|lwc|devops|security|full (default: full)
33
+ --target <name> Install target: ${VALID_TARGETS.join('|')} (default: claude)
34
+ --config <path> Load install config from scc-install.json (CLI args override config)
35
+ --project <dir> Project root directory (default: current directory)
36
+ --dry-run Show what would be installed without making changes
37
+ --help, -h Show this help
38
+
39
+ Examples:
40
+ scc install apex
41
+ scc install all
42
+ scc install --config scc-install.json
43
+ scc install --config scc-install.json --target cursor
44
+ scc install --profile security --target claude
45
+ scc install --profile lwc --target cursor --dry-run
46
+ `);
47
+ process.exit(exitCode);
48
+ }
49
+
50
+ function parseArgs(argv) {
51
+ const args = argv.slice(2);
52
+ const opts = {
53
+ profile: null,
54
+ target: null,
55
+ projectRoot: process.cwd(),
56
+ dryRun: false,
57
+ help: false,
58
+ config: null,
59
+ };
60
+
61
+ for (let i = 0; i < args.length; i++) {
62
+ const arg = args[i];
63
+ if (arg === '--help' || arg === '-h') {
64
+ opts.help = true;
65
+ } else if (arg === '--dry-run') {
66
+ opts.dryRun = true;
67
+ } else if (arg === '--config' && args[i + 1]) {
68
+ opts.config = args[++i];
69
+ } else if (arg === '--profile' && args[i + 1]) {
70
+ opts.profile = args[++i];
71
+ } else if (arg === '--target' && args[i + 1]) {
72
+ opts.target = args[++i];
73
+ } else if (arg === '--project' && args[i + 1]) {
74
+ opts.projectRoot = path.resolve(args[++i]);
75
+ } else if (!arg.startsWith('--')) {
76
+ // Positional: treat as shorthand target/profile
77
+ switch (arg) {
78
+ case 'apex':
79
+ opts.profile = opts.profile || 'apex';
80
+ break;
81
+ case 'lwc':
82
+ opts.profile = opts.profile || 'lwc';
83
+ break;
84
+ case 'all':
85
+ opts.profile = opts.profile || 'full';
86
+ break;
87
+ case 'core':
88
+ case 'devops':
89
+ case 'security':
90
+ case 'full':
91
+ opts.profile = opts.profile || arg;
92
+ break;
93
+ default:
94
+ // Could be a target name
95
+ if (VALID_TARGETS.includes(arg)) {
96
+ opts.target = arg;
97
+ } else {
98
+ console.error(`[ERROR] Unknown argument: ${arg}`);
99
+ process.exit(1);
100
+ }
101
+ }
102
+ }
103
+ }
104
+
105
+ return opts;
106
+ }
107
+
108
+ /**
109
+ * Merge CLI opts with config file. CLI args override config values.
110
+ */
111
+ function mergeWithConfig(opts) {
112
+ if (!opts.config) {
113
+ // No config file — apply defaults
114
+ if (!opts.profile) opts.profile = 'full';
115
+ if (!opts.target) opts.target = 'claude';
116
+ return opts;
117
+ }
118
+
119
+ try {
120
+ const config = loadInstallConfig(opts.config);
121
+ console.log(`[INFO] Loaded config from ${config.path}`);
122
+
123
+ // CLI args override config values
124
+ if (!opts.profile) opts.profile = config.profile || 'full';
125
+ if (!opts.target) opts.target = config.target || 'claude';
126
+
127
+ return opts;
128
+ } catch (err) {
129
+ console.error(`[ERROR] Config: ${err.message}`);
130
+ process.exit(1);
131
+ }
132
+ }
133
+
134
+ function validateArgs(opts) {
135
+ if (!VALID_PROFILES.includes(opts.profile)) {
136
+ console.error(`[ERROR] Invalid profile: ${opts.profile}`);
137
+ console.error(`Valid profiles: ${VALID_PROFILES.join(', ')}`);
138
+ process.exit(1);
139
+ }
140
+ if (!VALID_TARGETS.includes(opts.target)) {
141
+ console.error(`[ERROR] Invalid target: ${opts.target}`);
142
+ console.error(`Valid targets: ${VALID_TARGETS.join(', ')}`);
143
+ process.exit(1);
144
+ }
145
+ }
146
+
147
+ const opts = mergeWithConfig(parseArgs(process.argv));
148
+
149
+ if (opts.help) {
150
+ showHelp(0);
151
+ }
152
+
153
+ validateArgs(opts);
154
+
155
+ try {
156
+ const result = executeInstall(opts.profile, opts.target, {
157
+ dryRun: opts.dryRun,
158
+ projectRoot: opts.projectRoot,
159
+ });
160
+
161
+ if (result.fileCount === 0 && !opts.dryRun) {
162
+ console.log('\n[INFO] No files were installed. Check your manifests or profile definition.');
163
+ } else {
164
+ console.log('\nDone.');
165
+ }
166
+ } catch (err) {
167
+ console.error(`\n[ERROR] Installation failed: ${err.message}`);
168
+ if (process.env.DEBUG) console.error(err.stack);
169
+ process.exit(1);
170
+ }
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * uninstall.js — Remove SCC-managed files.
6
+ *
7
+ * Reads the state store to find all files installed by SCC and removes them.
8
+ * Optionally prunes empty directories.
9
+ */
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const readline = require('readline');
14
+ const { loadState, clearState, removeFiles } = require('../lib/state-store');
15
+ const { fileExists } = require('../lib/utils');
16
+
17
+ function showHelp(exitCode = 0) {
18
+ console.log(`
19
+ scc uninstall — Remove SCC-managed files
20
+
21
+ Usage:
22
+ scc uninstall [options]
23
+
24
+ Options:
25
+ --target <name> Only uninstall files for a specific target
26
+ --dry-run Show what would be removed without making changes
27
+ --yes, -y Skip confirmation prompt
28
+ --keep-state Remove files but keep the state store
29
+ --json Output result as JSON
30
+ --help, -h Show this help
31
+
32
+ Notes:
33
+ Only files tracked in the SCC state store will be removed.
34
+ Files you manually added to .claude/ etc. will not be touched.
35
+ `);
36
+ process.exit(exitCode);
37
+ }
38
+
39
+ function parseArgs(argv) {
40
+ const args = argv.slice(2);
41
+ const opts = { target: null, dryRun: false, yes: false, keepState: false, json: false, help: false };
42
+ for (let i = 0; i < args.length; i++) {
43
+ const arg = args[i];
44
+ if (arg === '--help' || arg === '-h') opts.help = true;
45
+ else if (arg === '--dry-run') opts.dryRun = true;
46
+ else if (arg === '--yes' || arg === '-y') opts.yes = true;
47
+ else if (arg === '--keep-state') opts.keepState = true;
48
+ else if (arg === '--json') opts.json = true;
49
+ else if (arg === '--target' && args[i + 1]) opts.target = args[++i];
50
+ }
51
+ return opts;
52
+ }
53
+
54
+ async function confirm(question) {
55
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
56
+ return new Promise(resolve => {
57
+ rl.question(question, answer => {
58
+ rl.close();
59
+ resolve(answer.trim().toLowerCase());
60
+ });
61
+ });
62
+ }
63
+
64
+ async function main() {
65
+ const opts = parseArgs(process.argv);
66
+ if (opts.help) showHelp(0);
67
+
68
+ const state = loadState();
69
+
70
+ if (!state.installedFiles || state.installedFiles.length === 0) {
71
+ const msg = 'No SCC installation found. Nothing to uninstall.';
72
+ if (opts.json) console.log(JSON.stringify({ status: 'not-installed', message: msg }));
73
+ else console.log(`[INFO] ${msg}`);
74
+ process.exit(0);
75
+ }
76
+
77
+ // Filter by target if specified
78
+ let filesToRemove = state.installedFiles;
79
+ if (opts.target) {
80
+ filesToRemove = filesToRemove.filter(f => f.target === opts.target);
81
+ if (filesToRemove.length === 0) {
82
+ console.log(`[INFO] No files found for target: ${opts.target}`);
83
+ process.exit(0);
84
+ }
85
+ }
86
+
87
+ // Only consider files that actually exist
88
+ const existingFiles = filesToRemove.filter(f => fileExists(f.destPath));
89
+ const missingFiles = filesToRemove.filter(f => !fileExists(f.destPath));
90
+
91
+ if (!opts.json) {
92
+ console.log(`\nSCC Uninstall${opts.dryRun ? ' (DRY RUN)' : ''}`);
93
+ console.log(`${'─'.repeat(50)}`);
94
+ console.log(`Files to remove : ${existingFiles.length}`);
95
+ if (missingFiles.length > 0) {
96
+ console.log(`Already missing : ${missingFiles.length} (will clear from state)`);
97
+ }
98
+ console.log();
99
+
100
+ if (opts.dryRun || opts.json) {
101
+ // just list
102
+ } else if (existingFiles.length > 0) {
103
+ console.log('Files that will be deleted:');
104
+ for (const f of existingFiles) {
105
+ console.log(` ${f.destPath}`);
106
+ }
107
+ console.log();
108
+ }
109
+ }
110
+
111
+ if (opts.dryRun) {
112
+ if (opts.json) {
113
+ console.log(JSON.stringify({ status: 'dry-run', wouldRemove: existingFiles.map(f => f.destPath), alreadyMissing: missingFiles.map(f => f.destPath) }, null, 2));
114
+ } else {
115
+ console.log(`[dry-run] Would remove ${existingFiles.length} file(s).`);
116
+ }
117
+ process.exit(0);
118
+ }
119
+
120
+ // Prompt for confirmation unless --yes
121
+ if (!opts.yes && !opts.json && existingFiles.length > 0) {
122
+ const answer = await confirm(`Remove ${existingFiles.length} file(s)? [y/N] `);
123
+ if (answer !== 'y' && answer !== 'yes') {
124
+ console.log('Aborted.');
125
+ process.exit(0);
126
+ }
127
+ }
128
+
129
+ // Remove files
130
+ const removed = [];
131
+ const errors = [];
132
+
133
+ for (const f of existingFiles) {
134
+ try {
135
+ fs.unlinkSync(f.destPath);
136
+ removed.push(f.destPath);
137
+ if (!opts.json) console.log(` [REMOVED] ${f.destPath}`);
138
+ } catch (err) {
139
+ errors.push({ path: f.destPath, error: err.message });
140
+ if (!opts.json) console.error(` [ERROR] Failed to remove ${f.destPath}: ${err.message}`);
141
+ }
142
+ }
143
+
144
+ // Try to prune empty directories
145
+ const dirsToCheck = new Set(existingFiles.map(f => path.dirname(f.destPath)));
146
+ const pruned = [];
147
+ for (const dir of dirsToCheck) {
148
+ try {
149
+ const entries = fs.readdirSync(dir);
150
+ if (entries.length === 0) {
151
+ fs.rmdirSync(dir);
152
+ pruned.push(dir);
153
+ if (!opts.json) console.log(` [PRUNED] empty dir: ${dir}`);
154
+ }
155
+ } catch { /* ignore */ }
156
+ }
157
+
158
+ // Update state
159
+ if (!opts.keepState) {
160
+ if (opts.target) {
161
+ // Only remove files for this target from state
162
+ removeFiles(filesToRemove.map(f => f.destPath));
163
+ } else {
164
+ clearState();
165
+ }
166
+ }
167
+
168
+ const result = {
169
+ status: errors.length > 0 ? 'partial' : 'ok',
170
+ removed: removed.length,
171
+ failed: errors.length,
172
+ prunedDirs: pruned.length,
173
+ removedFiles: removed,
174
+ failedFiles: errors,
175
+ };
176
+
177
+ if (opts.json) {
178
+ console.log(JSON.stringify(result, null, 2));
179
+ } else {
180
+ console.log();
181
+ console.log(`Removed: ${removed.length} file(s).`);
182
+ if (pruned.length > 0) console.log(`Pruned : ${pruned.length} empty director(ies).`);
183
+ if (errors.length > 0) console.log(`Errors : ${errors.length} file(s) could not be removed.`);
184
+ if (!opts.keepState) console.log('State : cleared.');
185
+ }
186
+
187
+ process.exit(errors.length > 0 ? 1 : 0);
188
+ }
189
+
190
+ main().catch(err => {
191
+ console.error(`[FATAL] ${err.message}`);
192
+ process.exit(1);
193
+ });
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Stop Hook: Check for console.log statements in modified LWC/JS files
5
+ *
6
+ * Cross-platform (Windows, macOS, Linux)
7
+ *
8
+ * Runs after each response and checks if any modified JavaScript/TypeScript
9
+ * files contain console.log statements. Particularly useful for LWC development
10
+ * where console.log should be removed before deployment.
11
+ *
12
+ * Exclusions: test files, config files, and scripts/ directory.
13
+ */
14
+
15
+ const fs = require('fs');
16
+
17
+ // Files where console.log is expected and should not trigger warnings
18
+ const EXCLUDED_PATTERNS = [
19
+ /\.test\.[jt]sx?$/,
20
+ /\.spec\.[jt]sx?$/,
21
+ /\.config\.[jt]s$/,
22
+ /scripts\//,
23
+ /__tests__\//,
24
+ /__mocks__\//,
25
+ ];
26
+
27
+ function isGitRepo() {
28
+ try {
29
+ const { execSync } = require('child_process');
30
+ execSync('git rev-parse --is-inside-work-tree', { stdio: 'pipe' });
31
+ return true;
32
+ } catch {
33
+ return false;
34
+ }
35
+ }
36
+
37
+ function getGitModifiedFiles(patterns) {
38
+ try {
39
+ const { execSync } = require('child_process');
40
+ const output = execSync('git diff --name-only HEAD 2>/dev/null || git diff --name-only', {
41
+ encoding: 'utf8',
42
+ stdio: ['pipe', 'pipe', 'pipe']
43
+ }).trim();
44
+ if (!output) return [];
45
+ const files = output.split('\n').filter(Boolean);
46
+ if (patterns && patterns.length > 0) {
47
+ return files.filter(f => patterns.some(p => new RegExp(p).test(f)));
48
+ }
49
+ return files;
50
+ } catch {
51
+ return [];
52
+ }
53
+ }
54
+
55
+ const MAX_STDIN = 1024 * 1024; // 1MB limit
56
+ let data = '';
57
+ process.stdin.setEncoding('utf8');
58
+
59
+ process.stdin.on('data', chunk => {
60
+ if (data.length < MAX_STDIN) {
61
+ const remaining = MAX_STDIN - data.length;
62
+ data += chunk.substring(0, remaining);
63
+ }
64
+ });
65
+
66
+ process.stdin.on('end', () => {
67
+ try {
68
+ if (!isGitRepo()) {
69
+ process.stdout.write(data);
70
+ process.exit(0);
71
+ }
72
+
73
+ const files = getGitModifiedFiles(['\\.tsx?$', '\\.jsx?$'])
74
+ .filter(f => fs.existsSync(f))
75
+ .filter(f => !EXCLUDED_PATTERNS.some(pattern => pattern.test(f)));
76
+
77
+ let hasConsole = false;
78
+
79
+ for (const file of files) {
80
+ try {
81
+ const content = fs.readFileSync(file, 'utf8');
82
+ if (content && content.includes('console.log')) {
83
+ console.error(`[Hook] WARNING: console.log found in ${file}`);
84
+ hasConsole = true;
85
+ }
86
+ } catch {
87
+ // Skip unreadable files
88
+ }
89
+ }
90
+
91
+ if (hasConsole) {
92
+ console.error('[Hook] Remove console.log statements before committing (especially in LWC)');
93
+ }
94
+ } catch (err) {
95
+ console.error(`[Hook] check-console-log error: ${err.message}`);
96
+ }
97
+
98
+ // Always output the original data
99
+ process.stdout.write(data);
100
+ process.exit(0);
101
+ });
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Helper: Check if a hook is enabled based on profile and disabled list.
6
+ * Returns "yes" or "no" based on SCC_HOOK_PROFILE and SCC_DISABLED_HOOKS.
7
+ */
8
+
9
+ const { isHookEnabled } = require('../lib/hook-flags');
10
+
11
+ const [, , hookId, profilesCsv] = process.argv;
12
+ if (!hookId) {
13
+ process.stdout.write('yes');
14
+ process.exit(0);
15
+ }
16
+
17
+ process.stdout.write(isHookEnabled(hookId, { profiles: profilesCsv }) ? 'yes' : 'no');
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * SessionStart hook: checks if platform reference docs are outdated.
6
+ * Warns the user to run /update-platform-docs if files haven't been
7
+ * verified in more than SCC_PLATFORM_DOCS_AGE_MONTHS months (default: 4).
8
+ *
9
+ * Uses CLAUDE_PLUGIN_ROOT / SCC_PLUGIN_ROOT env vars — no hardcoded paths.
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+
15
+ const PLUGIN_ROOT = process.env.CLAUDE_PLUGIN_ROOT
16
+ || process.env.SCC_PLUGIN_ROOT
17
+ || path.resolve(__dirname, '../..');
18
+
19
+ const MONTHS_THRESHOLD = parseInt(
20
+ process.env.SCC_PLATFORM_DOCS_AGE_MONTHS || '4',
21
+ 10
22
+ );
23
+
24
+ const FILES_TO_CHECK = [
25
+ path.join(PLUGIN_ROOT, 'skills', '_reference', 'DEPRECATIONS.md'),
26
+ path.join(PLUGIN_ROOT, 'skills', '_reference', 'API_VERSIONS.md')
27
+ ];
28
+
29
+ for (const filePath of FILES_TO_CHECK) {
30
+ if (!fs.existsSync(filePath)) continue;
31
+
32
+ const content = fs.readFileSync(filePath, 'utf8');
33
+ const match = content.match(/Last verified:\s*(\d{4}-\d{2}-\d{2})/);
34
+ if (!match) continue;
35
+
36
+ const verifiedDate = new Date(match[1]);
37
+ const threshold = new Date();
38
+ threshold.setMonth(threshold.getMonth() - MONTHS_THRESHOLD);
39
+
40
+ if (verifiedDate < threshold) {
41
+ const name = path.basename(filePath);
42
+ const age = Math.round((Date.now() - verifiedDate.getTime()) / (1000 * 60 * 60 * 24 * 30));
43
+ console.log(
44
+ `Platform docs outdated: ${name} was last verified ${match[1]} (${age} months ago). ` +
45
+ `Run /update-platform-docs to refresh with latest Salesforce release info.`
46
+ );
47
+ }
48
+ }
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Cost Tracker Hook
4
+ *
5
+ * Appends lightweight session usage metrics to ~/.claude/metrics/costs.jsonl.
6
+ * Runs on Stop event to log token usage and estimated costs.
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const { ensureDir } = require('../lib/utils');
14
+
15
+ const MAX_STDIN = 1024 * 1024;
16
+
17
+ function getClaudeDir() {
18
+ return path.join(process.env.HOME || process.env.USERPROFILE || '/tmp', '.claude');
19
+ }
20
+
21
+ function toNumber(value) {
22
+ const n = Number(value);
23
+ return Number.isFinite(n) ? n : 0;
24
+ }
25
+
26
+ function estimateCost(model, inputTokens, outputTokens) {
27
+ const table = {
28
+ 'haiku': { in: 0.8, out: 4.0 },
29
+ 'sonnet': { in: 3.0, out: 15.0 },
30
+ 'opus': { in: 15.0, out: 75.0 },
31
+ };
32
+
33
+ const normalized = String(model || '').toLowerCase();
34
+ let rates = table.sonnet;
35
+ if (normalized.includes('haiku')) rates = table.haiku;
36
+ if (normalized.includes('opus')) rates = table.opus;
37
+
38
+ const cost = (inputTokens / 1_000_000) * rates.in + (outputTokens / 1_000_000) * rates.out;
39
+ return Math.round(cost * 1e6) / 1e6;
40
+ }
41
+
42
+ let raw = '';
43
+ process.stdin.setEncoding('utf8');
44
+ process.stdin.on('data', chunk => {
45
+ if (raw.length < MAX_STDIN) {
46
+ raw += chunk.substring(0, MAX_STDIN - raw.length);
47
+ }
48
+ });
49
+
50
+ process.stdin.on('end', () => {
51
+ try {
52
+ const input = raw.trim() ? JSON.parse(raw) : {};
53
+ const usage = input.usage || input.token_usage || {};
54
+ const inputTokens = toNumber(usage.input_tokens || usage.prompt_tokens || 0);
55
+ const outputTokens = toNumber(usage.output_tokens || usage.completion_tokens || 0);
56
+
57
+ const model = String(input.model || process.env.CLAUDE_MODEL || 'unknown');
58
+ const sessionId = String(process.env.CLAUDE_SESSION_ID || 'default');
59
+
60
+ const metricsDir = path.join(getClaudeDir(), 'metrics');
61
+ ensureDir(metricsDir);
62
+
63
+ const row = {
64
+ timestamp: new Date().toISOString(),
65
+ session_id: sessionId,
66
+ model,
67
+ input_tokens: inputTokens,
68
+ output_tokens: outputTokens,
69
+ estimated_cost_usd: estimateCost(model, inputTokens, outputTokens),
70
+ };
71
+
72
+ fs.appendFileSync(path.join(metricsDir, 'costs.jsonl'), `${JSON.stringify(row)}\n`);
73
+ } catch {
74
+ // Keep hook non-blocking
75
+ }
76
+
77
+ process.stdout.write(raw);
78
+ });
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Doc file warning hook (PreToolUse - Write)
4
+ * Warns about non-standard documentation files.
5
+ * Exit code 0 always (warns only, never blocks).
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ const path = require('path');
11
+
12
+ const MAX_STDIN = 1024 * 1024;
13
+ let data = '';
14
+
15
+ function isAllowedDocPath(filePath) {
16
+ const normalized = filePath.replace(/\\/g, '/');
17
+ const basename = path.basename(filePath);
18
+
19
+ if (!/\.(md|txt)$/i.test(filePath)) return true;
20
+
21
+ if (/^(README|CLAUDE|AGENTS|CONTRIBUTING|CHANGELOG|LICENSE|SKILL|MEMORY|WORKLOG)\.md$/i.test(basename)) {
22
+ return true;
23
+ }
24
+
25
+ if (/\.claude\/(commands|plans|projects)\//.test(normalized)) {
26
+ return true;
27
+ }
28
+
29
+ if (/(^|\/)(docs|skills|\.history|memory)\//.test(normalized)) {
30
+ return true;
31
+ }
32
+
33
+ if (/\.plan\.md$/i.test(basename)) {
34
+ return true;
35
+ }
36
+
37
+ return false;
38
+ }
39
+
40
+ process.stdin.setEncoding('utf8');
41
+ process.stdin.on('data', c => {
42
+ if (data.length < MAX_STDIN) {
43
+ const remaining = MAX_STDIN - data.length;
44
+ data += c.substring(0, remaining);
45
+ }
46
+ });
47
+
48
+ process.stdin.on('end', () => {
49
+ try {
50
+ const input = JSON.parse(data);
51
+ const filePath = String((input.tool_input && input.tool_input.file_path) || '');
52
+
53
+ if (filePath && !isAllowedDocPath(filePath)) {
54
+ console.error('[Hook] WARNING: Non-standard documentation file detected');
55
+ console.error(`[Hook] File: ${filePath}`);
56
+ console.error('[Hook] Consider consolidating into README.md or docs/ directory');
57
+ }
58
+ } catch {
59
+ // ignore parse errors
60
+ }
61
+
62
+ process.stdout.write(data);
63
+ });