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,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
|