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,313 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ /**
7
+ * Read a JSON file safely, returning null on error.
8
+ */
9
+ function readJson(filePath) {
10
+ try {
11
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
12
+ } catch (err) {
13
+ if (err.code !== 'ENOENT') {
14
+ process.stderr.write(`[SCC] readJson failed for ${filePath}: ${err.message}\n`);
15
+ }
16
+ return null;
17
+ }
18
+ }
19
+
20
+ /**
21
+ * Check if a file exists.
22
+ */
23
+ function fileExists(filePath) {
24
+ try {
25
+ fs.accessSync(filePath, fs.constants.F_OK);
26
+ return true;
27
+ } catch {
28
+ return false;
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Ensure a directory exists (mkdir -p).
34
+ */
35
+ function ensureDir(dirPath) {
36
+ fs.mkdirSync(dirPath, { recursive: true });
37
+ }
38
+
39
+ /**
40
+ * Copy a file, creating parent directories as needed.
41
+ */
42
+ function copyFile(src, dest) {
43
+ ensureDir(path.dirname(dest));
44
+ fs.copyFileSync(src, dest);
45
+ }
46
+
47
+ /**
48
+ * Get the SCC plugin root directory.
49
+ */
50
+ function getPluginRoot() {
51
+ return process.env.CLAUDE_PLUGIN_ROOT || process.env.SCC_PLUGIN_ROOT || path.join(__dirname, '..', '..');
52
+ }
53
+
54
+ /**
55
+ * Parse YAML frontmatter from a markdown file.
56
+ * Returns { frontmatter: Object, body: string }.
57
+ *
58
+ * Supports:
59
+ * - Simple scalars: key: value
60
+ * - Quoted strings: key: "value" or key: 'value'
61
+ * - Booleans: key: true / key: false (returned as JS boolean)
62
+ * - Inline arrays: key: ["a", "b"] or key: [a, b]
63
+ * - Folded block scalar: key: >- (multi-line, joined with spaces, trailing newline stripped)
64
+ * - Folded block scalar: key: > (multi-line, joined with spaces, trailing newline kept)
65
+ * - Literal block scalar: key: |- (multi-line, newlines preserved, trailing newline stripped)
66
+ * - Literal block scalar: key: | (multi-line, newlines preserved, trailing newline kept)
67
+ *
68
+ * The old implementation parsed line-by-line and returned the literal string ">-" for
69
+ * block scalar keys, silently discarding the actual multi-line content. This version
70
+ * collects all indented continuation lines and folds/preserves them correctly.
71
+ */
72
+ function parseFrontmatter(content) {
73
+ // Normalise CRLF → LF for Windows compatibility
74
+ const normalised = content.replace(/\r\n/g, '\n');
75
+ const match = normalised.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
76
+
77
+ if (!match) return { frontmatter: {}, body: content };
78
+
79
+ const frontmatter = {};
80
+ const yamlLines = match[1].split('\n');
81
+ let i = 0;
82
+
83
+ while (i < yamlLines.length) {
84
+ const line = yamlLines[i];
85
+ const colonIdx = line.indexOf(':');
86
+
87
+ // Skip blank lines and lines without a colon
88
+ if (colonIdx === -1 || line.trim() === '') { i++; continue; }
89
+
90
+ const key = line.slice(0, colonIdx).trim();
91
+ const raw = line.slice(colonIdx + 1).trim();
92
+
93
+ if (!key) { i++; continue; }
94
+
95
+ // ── YAML block scalar: >-, >, |-, | ──────────────────────────────────────
96
+ // When the value is a block indicator the actual content is on the
97
+ // following indented lines.
98
+ if (raw === '>-' || raw === '>' || raw === '|-' || raw === '|') {
99
+ const isFolded = raw === '>' || raw === '>-';
100
+ const stripFinal = raw === '>-' || raw === '|-';
101
+
102
+ const blockLines = [];
103
+ i++;
104
+
105
+ while (i < yamlLines.length) {
106
+ const next = yamlLines[i];
107
+ // Block content: indented with at least one space or tab
108
+ if (next.startsWith(' ') || next.startsWith('\t')) {
109
+ blockLines.push(next.trim());
110
+ i++;
111
+ } else if (next.trim() === '') {
112
+ // Blank lines inside a block scalar are allowed — preserve as paragraph break
113
+ blockLines.push('');
114
+ i++;
115
+ } else {
116
+ break; // Non-indented line signals end of block
117
+ }
118
+ }
119
+
120
+ // Remove leading/trailing empty strings caused by blank lines at block edges
121
+ while (blockLines.length > 0 && blockLines[0] === '') blockLines.shift();
122
+ while (blockLines.length > 0 && blockLines[blockLines.length - 1] === '') blockLines.pop();
123
+
124
+ let value;
125
+ if (isFolded) {
126
+ // Folded (>): join lines with a single space, collapsing internal whitespace
127
+ value = blockLines
128
+ .join(' ')
129
+ .replace(/\s{2,}/g, ' ')
130
+ .trim();
131
+ } else {
132
+ // Literal (|): preserve newlines exactly
133
+ value = blockLines.join('\n');
134
+ if (stripFinal) value = value.replace(/\n+$/, '');
135
+ }
136
+
137
+ frontmatter[key] = value;
138
+ continue;
139
+ }
140
+
141
+ // ── Inline array ─────────────────────────────────────────────────────────
142
+ if (raw.startsWith('[') && raw.endsWith(']')) {
143
+ frontmatter[key] = raw
144
+ .slice(1, -1)
145
+ .split(',')
146
+ .map(v => v.trim().replace(/^["']|["']$/g, ''))
147
+ .filter(Boolean);
148
+ i++;
149
+ continue;
150
+ }
151
+
152
+ // ── Plain string (remove surrounding quotes) ──────────────────────────────
153
+ // NOTE: true/false are intentionally kept as strings ("true"/"false") for
154
+ // backward compatibility — all existing callers use string comparison.
155
+ // Use parseBool(frontmatter[key]) when you need an actual boolean.
156
+ frontmatter[key] = raw.replace(/^["']|["']$/g, '');
157
+ i++;
158
+ }
159
+
160
+ return { frontmatter, body: match[2] };
161
+ }
162
+
163
+ /**
164
+ * Recursively list all files under a directory.
165
+ * Returns an array of absolute paths.
166
+ */
167
+ function listFilesRecursive(dir) {
168
+ const results = [];
169
+ if (!fs.existsSync(dir)) return results;
170
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
171
+ for (const entry of entries) {
172
+ const full = path.join(dir, entry.name);
173
+ if (entry.isDirectory()) {
174
+ results.push(...listFilesRecursive(full));
175
+ } else {
176
+ results.push(full);
177
+ }
178
+ }
179
+ return results;
180
+ }
181
+
182
+ /**
183
+ * Compute a simple hash (used for drift detection).
184
+ * Returns a hex string based on file content length + first 512 bytes.
185
+ */
186
+ function simpleHash(filePath) {
187
+ try {
188
+ const buf = fs.readFileSync(filePath);
189
+ let hash = buf.length;
190
+ const sample = buf.slice(0, 512);
191
+ for (let i = 0; i < sample.length; i++) {
192
+ hash = ((hash << 5) - hash + sample[i]) & 0xffffffff;
193
+ }
194
+ return (hash >>> 0).toString(16).padStart(8, '0');
195
+ } catch {
196
+ return null;
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Read a text file safely, returning null on error.
202
+ */
203
+ function readFile(filePath) {
204
+ try {
205
+ return fs.readFileSync(filePath, 'utf8');
206
+ } catch (err) {
207
+ if (err.code !== 'ENOENT') {
208
+ process.stderr.write(`[SCC] readFile failed for ${filePath}: ${err.message}\n`);
209
+ }
210
+ return null;
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Count regex matches in a file.
216
+ */
217
+ function countInFile(filePath, pattern) {
218
+ const content = readFile(filePath);
219
+ if (content === null) return 0;
220
+
221
+ let regex;
222
+ try {
223
+ if (pattern instanceof RegExp) {
224
+ regex = new RegExp(pattern.source, pattern.flags.includes('g') ? pattern.flags : pattern.flags + 'g');
225
+ } else if (typeof pattern === 'string') {
226
+ regex = new RegExp(pattern, 'g');
227
+ } else {
228
+ return 0;
229
+ }
230
+ } catch {
231
+ return 0;
232
+ }
233
+ const matches = content.match(regex);
234
+ return matches ? matches.length : 0;
235
+ }
236
+
237
+ /**
238
+ * Safely coerce a frontmatter boolean field to a JS boolean.
239
+ *
240
+ * parseFrontmatter returns ALL values as strings for backward compatibility.
241
+ * Use this helper whenever you need an actual boolean from a frontmatter field:
242
+ *
243
+ * parseBool(frontmatter['user-invocable']) // → true | false | undefined
244
+ *
245
+ * Returns undefined (not false) when value is absent, so callers can
246
+ * distinguish "not set" from "explicitly false".
247
+ */
248
+ function parseBool(value) {
249
+ if (value === undefined || value === null) return undefined;
250
+ if (typeof value === 'boolean') return value;
251
+ const s = String(value).trim().toLowerCase();
252
+ if (s === 'true') return true;
253
+ if (s === 'false') return false;
254
+ return undefined;
255
+ }
256
+
257
+ /**
258
+ * Serialize a frontmatter object and body back into a markdown string.
259
+ *
260
+ * Multi-line string values (containing \n or longer than 80 chars) are
261
+ * written as YAML folded block scalars (>-) so they round-trip correctly
262
+ * through parseFrontmatter.
263
+ */
264
+ function serializeFrontmatter(frontmatter, body) {
265
+ const keys = Object.keys(frontmatter);
266
+ if (keys.length === 0) return body;
267
+
268
+ const lines = [];
269
+ for (const key of keys) {
270
+ const value = frontmatter[key];
271
+ if (value === undefined || value === null) continue;
272
+
273
+ if (Array.isArray(value)) {
274
+ lines.push(`${key}: [${value.map(v => `"${v}"`).join(', ')}]`);
275
+ } else if (typeof value === 'boolean') {
276
+ lines.push(`${key}: ${value}`);
277
+ } else if (typeof value === 'string' && (value.includes('\n') || value.length > 80)) {
278
+ // Use folded block scalar for long or multi-line strings
279
+ const indented = value
280
+ .split('\n')
281
+ .map(l => ` ${l}`)
282
+ .join('\n');
283
+ lines.push(`${key}: >-\n${indented}`);
284
+ } else {
285
+ lines.push(`${key}: ${value}`);
286
+ }
287
+ }
288
+
289
+ return `---\n${lines.join('\n')}\n---\n${body}`;
290
+ }
291
+
292
+ /**
293
+ * Log to stderr (visible in Claude Code output, not captured as tool result).
294
+ */
295
+ function log(message) {
296
+ console.error(message);
297
+ }
298
+
299
+ module.exports = {
300
+ readJson,
301
+ readFile,
302
+ fileExists,
303
+ ensureDir,
304
+ copyFile,
305
+ getPluginRoot,
306
+ parseFrontmatter,
307
+ parseBool,
308
+ serializeFrontmatter,
309
+ listFilesRecursive,
310
+ simpleHash,
311
+ countInFile,
312
+ log,
313
+ };
package/scripts/scc.js ADDED
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { spawnSync } = require('child_process');
5
+ const path = require('path');
6
+
7
+ const COMMANDS = {
8
+ install: { script: 'cli/install-apply.js', description: 'Install SCC content into a supported target (apex, lwc, all)' },
9
+ plan: { script: 'dev/install-plan.js', description: 'Inspect selective-install manifests' },
10
+ 'list-installed': { script: 'dev/list-installed.js', description: 'List currently installed SCC content' },
11
+ doctor: { script: 'dev/doctor.js', description: 'Diagnose missing or drifted files' },
12
+ repair: { script: 'dev/repair.js', description: 'Restore drifted files' },
13
+ status: { script: 'dev/status.js', description: 'Query JSON state store' },
14
+ sessions: { script: 'dev/sessions-cli.js', description: 'List or inspect sessions' },
15
+ 'session-inspect': { script: 'dev/session-inspect.js', description: 'Emit canonical SCC session snapshots from dmux or Claude history targets' },
16
+ uninstall: { script: 'cli/uninstall.js', description: 'Remove SCC-managed files' },
17
+ };
18
+
19
+ const PRIMARY_COMMANDS = ['install', 'plan', 'list-installed', 'doctor', 'repair', 'status', 'sessions', 'session-inspect', 'uninstall'];
20
+
21
+ function showHelp(exitCode = 0) {
22
+ console.log(`
23
+ SCC — Salesforce Claude Code CLI
24
+
25
+ Usage:
26
+ scc <command> [args...]
27
+ scc [install args...]
28
+
29
+ Commands:
30
+ ${PRIMARY_COMMANDS.map(cmd => ` ${cmd.padEnd(18)} ${COMMANDS[cmd].description}`).join('\n')}
31
+
32
+ Compatibility:
33
+ scc [args...] Without a command, args are routed to "install"
34
+ scc help <command> Show help for a specific command
35
+
36
+ Install targets:
37
+ apex Install Apex development content
38
+ lwc Install LWC development content
39
+ all Install everything
40
+
41
+ Install profiles:
42
+ --profile apex Apex development suite (core + apex + platform + devops + security)
43
+ --profile lwc LWC development suite (core + lwc + platform + devops + security)
44
+ --profile full Complete suite — all 7 bundles (default)
45
+
46
+ Examples:
47
+ scc apex
48
+ scc all
49
+ scc install --config scc-install.json
50
+ scc install --profile apex --target claude
51
+ scc plan --config scc-install.json --target cursor
52
+ scc doctor
53
+ scc repair --dry-run
54
+ scc status --json
55
+ scc sessions
56
+ scc session-inspect claude:latest
57
+ scc uninstall --dry-run
58
+
59
+ Environment:
60
+ SCC_HOOK_PROFILE Hook profile: minimal | standard | strict
61
+ SCC_DISABLED_HOOKS Comma-separated list of hooks to disable
62
+ SF_ORG_ALIAS Default Salesforce org alias
63
+
64
+ Documentation: https://github.com/jiten-singh-shahi/salesforce-claude-code
65
+ `);
66
+ process.exit(exitCode);
67
+ }
68
+
69
+ function resolveCommand(argv) {
70
+ const args = argv.slice(2);
71
+ if (args.length === 0) return { mode: 'help' };
72
+
73
+ const [firstArg, ...restArgs] = args;
74
+
75
+ if (firstArg === '--help' || firstArg === '-h') return { mode: 'help' };
76
+ if (firstArg === '--version' || firstArg === '-v') return { mode: 'version' };
77
+
78
+ if (firstArg === 'help') {
79
+ return { mode: 'help-command', command: restArgs[0] || null };
80
+ }
81
+
82
+ if (COMMANDS[firstArg]) {
83
+ return { mode: 'delegate', command: firstArg, args: restArgs };
84
+ }
85
+
86
+ // Treat as install target shorthand
87
+ return { mode: 'delegate', command: 'install', args };
88
+ }
89
+
90
+ function runCommand(commandName, args) {
91
+ const command = COMMANDS[commandName];
92
+ if (!command) {
93
+ throw new Error(`Unknown command: ${commandName}`);
94
+ }
95
+
96
+ const result = spawnSync(
97
+ process.execPath,
98
+ [path.join(__dirname, command.script), ...args],
99
+ {
100
+ cwd: process.cwd(),
101
+ env: { ...process.env, CLAUDE_PLUGIN_ROOT: path.join(__dirname, '..'), SCC_PLUGIN_ROOT: path.join(__dirname, '..') },
102
+ encoding: 'utf8',
103
+ maxBuffer: 10 * 1024 * 1024,
104
+ }
105
+ );
106
+
107
+ if (result.error) {
108
+ throw result.error;
109
+ }
110
+
111
+ if (result.stdout) {
112
+ process.stdout.write(result.stdout);
113
+ }
114
+
115
+ if (result.stderr) {
116
+ process.stderr.write(result.stderr);
117
+ }
118
+
119
+ if (typeof result.status === 'number') {
120
+ return result.status;
121
+ }
122
+
123
+ if (result.signal) {
124
+ throw new Error(`Command "${commandName}" terminated by signal ${result.signal}`);
125
+ }
126
+
127
+ return 1;
128
+ }
129
+
130
+ function main() {
131
+ try {
132
+ const resolved = resolveCommand(process.argv);
133
+
134
+ if (resolved.mode === 'help') {
135
+ showHelp(0);
136
+ }
137
+
138
+ if (resolved.mode === 'version') {
139
+ const pkg = require('../package.json');
140
+ console.log(pkg.version);
141
+ process.exit(0);
142
+ }
143
+
144
+ if (resolved.mode === 'help-command') {
145
+ if (!resolved.command) {
146
+ showHelp(0);
147
+ }
148
+
149
+ if (!COMMANDS[resolved.command]) {
150
+ throw new Error(`Unknown command: ${resolved.command}`);
151
+ }
152
+
153
+ process.exitCode = runCommand(resolved.command, ['--help']);
154
+ return;
155
+ }
156
+
157
+ process.exitCode = runCommand(resolved.command, resolved.args);
158
+ } catch (error) {
159
+ console.error(`Error: ${error.message}`);
160
+ process.exit(1);
161
+ }
162
+ }
163
+
164
+ main();
@@ -0,0 +1,112 @@
1
+ # Agentforce Patterns — Reference
2
+
3
+ > Source: <https://developer.salesforce.com/docs/ai/agentforce/guide/get-started-actions.html>
4
+ > Also: <https://developer.salesforce.com/blogs/2025/07/best-practices-for-building-agentforce-apex-actions>
5
+ > Also: <https://developer.salesforce.com/blogs/2025/01/how-to-write-effective-natural-language-instructions-for-agentforce>
6
+ > Last verified: API v66.0, Spring '26 (2026-03-28)
7
+
8
+ ## Architecture
9
+
10
+ ```
11
+ Agent
12
+ +-- Topic (job-to-be-done container, e.g. "Order Management")
13
+ | +-- Classification Description (routes user queries to this topic)
14
+ | +-- Scope (what the agent WILL and WILL NOT do)
15
+ | +-- Instructions (numbered guidelines for agent behavior)
16
+ | +-- Actions (1..N tools the agent can invoke)
17
+ | +-- Action Instructions (purpose, goal, scope)
18
+ | +-- Input Parameters (with input instructions)
19
+ | +-- Output Parameters (with output instructions)
20
+ +-- Topic ...
21
+ ```
22
+
23
+ **Recommended limits**: max 10 topics per agent; 12-15 actions per topic. Exceeding causes context confusion in the Atlas reasoning engine.
24
+
25
+ ## Action Types
26
+
27
+ | Action Source | How It Works | When to Use |
28
+ |---|---|---|
29
+ | **Apex `@InvocableMethod`** | Annotated static method exposed to Agentforce Builder | Custom business logic, DML, callouts |
30
+ | **Apex REST** | `@RestResource` class registered via API catalog | External API wrappers |
31
+ | **AuraEnabled** | `@AuraEnabled` controller method with OpenAPI doc | Reusing existing LWC controller logic |
32
+ | **Autolaunched Flow** | Flow with no screens; invoked as action | Declarative orchestration, record ops |
33
+ | **Prompt Template** | Flex prompt template from Prompt Builder | LLM-generated text, summaries, classification |
34
+ | **Named Query (Beta)** | Custom SOQL exposed as action | Read-only data retrieval |
35
+ | **MCP Server** | External tool via Model Context Protocol | Third-party integrations |
36
+
37
+ All action types support enhancement via: Lightning Types (rich UI), Global Copy, Apex Citations (knowledge articles, PDFs, external URLs).
38
+
39
+ ## Apex Action Rules
40
+
41
+ | Rule | Detail |
42
+ |---|---|
43
+ | Annotation | `@InvocableMethod(label='...' description='...')` on a `public static` method |
44
+ | Sharing | Always use `with sharing`; run DML/queries in `with user` mode |
45
+ | Bulkification | Actions do NOT bulkify by default; each executes in its own transaction |
46
+ | Error handling | Use `try-catch`; return user-friendly messages; use `Database` class for partial processing |
47
+ | Decomposition | Break complex actions into smaller ones to avoid CPU timeout (10s sync limit) |
48
+ | Async work | Use Queueable Apex for long-running tasks; return a requestId for status tracking |
49
+ | Labels | Keep Apex `label`/`description` in sync with Agentforce Builder action config |
50
+
51
+ ## Instruction Guidelines
52
+
53
+ | Instruction Type | Rules |
54
+ |---|---|
55
+ | **Topic Classification** | Concise; describes what queries route here. E.g. "Manages customer inquiries about order status and returns." |
56
+ | **Topic Scope** | Explicit WILL/WILL NOT. E.g. "Handle resending confirmations, but do not create new reservations." |
57
+ | **Topic Instructions** | Numbered list in a single box. Positive framing ("always do X" not "don't do Y"). No deterministic business rules here -- put those in action code. |
58
+ | **Action Instructions** | 1-3 sentences: purpose, goal, scope. Specify dependent actions. Use varied verb names across actions. |
59
+ | **Input Instructions** | Specify field name, data type, format. E.g. "accountId -- The 18-digit unique Account record ID" |
60
+ | **Output Instructions** | Describe return value with type. E.g. "balance: numeric value representing current account balance" |
61
+
62
+ **Anti-patterns**: Overusing "must"/"never"/"always" (agent gets stuck); relying on topic instructions for input validation (use action code); similar action names like "Get Project Details" vs "Get Task Details" (use varied verbs: "Locate" vs "Retrieve").
63
+
64
+ ## Agent Script (Agentforce Builder)
65
+
66
+ Agent Script combines natural language instructions with programmatic expressions.
67
+
68
+ | Element | Purpose |
69
+ |---|---|
70
+ | Instructions | LLM reasoning areas (non-deterministic) |
71
+ | Expressions | If/else conditions, transitions, variable ops (deterministic) |
72
+ | Variables | Store conversation state; prevent context window overflow |
73
+ | `@` references | Link to actions and topics in Canvas view |
74
+ | `/` shortcut | Insert expressions in Canvas view |
75
+ | Topic pass-through | Chain actions across topics; deterministic or LLM-controlled |
76
+
77
+ Development surfaces: Canvas View (visual blocks), Script View (syntax highlighting + autocomplete), Agentforce DX (local VS Code with `sf agent` CLI).
78
+
79
+ ## Invocation Channels
80
+
81
+ | Channel | Method |
82
+ |---|---|
83
+ | Flow | Standard "AI Agent" action in Flow Builder; pass user message + optional session ID |
84
+ | Apex | Invocable Action API with agent API name; REST-exposable |
85
+ | LWC | Via Apex method call |
86
+ | External systems | REST with OAuth 2.0 (Web-Server or User-Agent flow) |
87
+ | Agent-to-agent | Flow-based agent action invocation |
88
+ | Slack, websites, apps | Deploy via Agentforce channel configuration |
89
+
90
+ Session ID ties multi-turn conversations together. First message generates the ID; pass it with subsequent messages.
91
+
92
+ ## Testing
93
+
94
+ | Tool | Purpose |
95
+ |---|---|
96
+ | **Agent Builder Preview** | Real-time conversational testing with context simulation (language, app, page, record) |
97
+ | **Agentforce Testing Center** | Bulk test execution; auto-generates test cases from knowledge base content |
98
+ | **Agentforce DX CLI** | `sf agent generate test-spec` (YAML), `sf agent test create`, `sf agent test run` |
99
+ | **VS Code Agent Panel** | View/run tests; Agent Preview pane for conversations; Apex Replay Debugger for actions |
100
+ | **Testing API** | REST API + Connect API for programmatic test execution |
101
+ | **Apex unit tests** | Standard `@isTest` for action implementation code |
102
+
103
+ DX test workflow: generate YAML spec -> customize test cases -> create in org -> run -> integrate into CI pipeline.
104
+
105
+ ## Context Engineering Principles
106
+
107
+ 1. Limit topics (max 10) and actions per topic (12-15) to avoid context confusion
108
+ 2. Use variables to store key facts instead of relying on conversation memory
109
+ 3. Eliminate contradictions across topic instructions, action instructions, and scope definitions
110
+ 4. Validate RAG/knowledge data is current and accurate
111
+ 5. Use structured actions for critical business logic; reserve natural language for conversational tasks
112
+ 6. Four failure modes to watch: context distraction, context clash, context poisoning, context confusion