sf-compact-cli 0.3.3 → 0.4.1
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/README.md +39 -274
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,312 +1,77 @@
|
|
|
1
1
|
# sf-compact
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Cut Salesforce metadata tokens in half for AI coding agents.
|
|
4
4
|
|
|
5
|
-
Salesforce metadata XML is extremely verbose —
|
|
5
|
+
Salesforce metadata XML is extremely verbose — 70-85% structural overhead. **sf-compact** converts it to compact YAML/JSON. In controlled benchmarks, this reduced Claude Code costs by **11.5%** — and by **33%** with a custom exploration agent.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Quick Start
|
|
8
8
|
|
|
9
|
-
## Output Formats
|
|
10
|
-
|
|
11
|
-
| Format | Preserves order | Human-readable | Token savings |
|
|
12
|
-
|--------|:-:|:-:|:-:|
|
|
13
|
-
| `yaml` | No | Yes | ~49% |
|
|
14
|
-
| `yaml-ordered` | Yes | Yes | ~42% |
|
|
15
|
-
| `json` | Yes | Less | ~54% |
|
|
16
|
-
|
|
17
|
-
- **yaml** — groups repeated elements into arrays. Most compact YAML, but sibling order may change. Best for order-insensitive types (Profile, PermissionSet).
|
|
18
|
-
- **yaml-ordered** — uses `_children` sequences to preserve exact element order. Best for order-sensitive types (Flow, FlexiPage, Layout).
|
|
19
|
-
- **json** — compact single-line JSON with arrays. Preserves order, fewest tokens, less human-readable.
|
|
20
|
-
|
|
21
|
-
## Before / After
|
|
22
|
-
|
|
23
|
-
**XML (848 tokens):**
|
|
24
|
-
```xml
|
|
25
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
26
|
-
<Profile xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
27
|
-
<custom>false</custom>
|
|
28
|
-
<userLicense>Salesforce</userLicense>
|
|
29
|
-
<fieldPermissions>
|
|
30
|
-
<editable>true</editable>
|
|
31
|
-
<field>Account.AnnualRevenue</field>
|
|
32
|
-
<readable>true</readable>
|
|
33
|
-
</fieldPermissions>
|
|
34
|
-
<fieldPermissions>
|
|
35
|
-
<editable>false</editable>
|
|
36
|
-
<field>Account.BillingCity</field>
|
|
37
|
-
<readable>true</readable>
|
|
38
|
-
</fieldPermissions>
|
|
39
|
-
...
|
|
40
|
-
</Profile>
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
**YAML (432 tokens — 49% reduction):**
|
|
44
|
-
```yaml
|
|
45
|
-
_tag: Profile
|
|
46
|
-
_ns: http://soap.sforce.com/2006/04/metadata
|
|
47
|
-
custom: false
|
|
48
|
-
userLicense: Salesforce
|
|
49
|
-
fieldPermissions:
|
|
50
|
-
- editable: true
|
|
51
|
-
field: Account.AnnualRevenue
|
|
52
|
-
readable: true
|
|
53
|
-
- editable: false
|
|
54
|
-
field: Account.BillingCity
|
|
55
|
-
readable: true
|
|
56
|
-
...
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
**JSON (389 tokens — 54% reduction):**
|
|
60
|
-
```json
|
|
61
|
-
{"_tag":"Profile","_ns":"http://soap.sforce.com/2006/04/metadata","custom":"false","userLicense":"Salesforce","fieldPermissions":[{"editable":"true","field":"Account.AnnualRevenue","readable":"true"},{"editable":"false","field":"Account.BillingCity","readable":"true"}]}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Install
|
|
65
|
-
|
|
66
|
-
### From source (Rust required)
|
|
67
9
|
```bash
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
### From crates.io
|
|
72
|
-
```bash
|
|
73
|
-
cargo install sf-compact
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## Usage
|
|
77
|
-
|
|
78
|
-
### Pack (XML → compact format)
|
|
79
|
-
```bash
|
|
80
|
-
sf-compact pack [source...] [-o output] [--format yaml|yaml-ordered|json] [--include pattern]
|
|
10
|
+
npm install -g sf-compact-cli
|
|
11
|
+
sf-compact pack
|
|
12
|
+
sf-compact init instructions
|
|
81
13
|
```
|
|
82
14
|
|
|
83
|
-
|
|
84
|
-
# Pack entire project (default: YAML format)
|
|
85
|
-
sf-compact pack force-app -o .sf-compact
|
|
15
|
+
`init instructions` injects a directive into your CLAUDE.md telling the AI to read from `.sf-compact/` instead of `force-app/`. In 17 benchmark variants, this was the simplest approach that reliably worked.
|
|
86
16
|
|
|
87
|
-
|
|
88
|
-
sf-compact pack force-app --format json
|
|
17
|
+
## Why YAML is the Default
|
|
89
18
|
|
|
90
|
-
|
|
91
|
-
sf-compact pack force-app/main/default/profiles force-app/main/default/classes
|
|
19
|
+
Token savings vary by metadata type. JSON saves 31-34% on large types (profiles, objects) but is *worse* for small types — fields (+0.4%), list views (+1.1%), compact layouts (+5.5%). YAML avoids the JSON `_children` overhead and works well across all sizes.
|
|
92
20
|
|
|
93
|
-
|
|
94
|
-
sf-compact pack force-app --include "*.profile-meta.xml"
|
|
95
|
-
```
|
|
21
|
+
## Install
|
|
96
22
|
|
|
97
|
-
###
|
|
23
|
+
### npm (recommended)
|
|
98
24
|
```bash
|
|
99
|
-
|
|
25
|
+
npm install -g sf-compact-cli
|
|
100
26
|
```
|
|
101
27
|
|
|
102
|
-
|
|
103
|
-
|
|
28
|
+
### Homebrew (macOS / Linux)
|
|
104
29
|
```bash
|
|
105
|
-
|
|
30
|
+
brew install vradko/tap/sf-compact
|
|
106
31
|
```
|
|
107
32
|
|
|
108
|
-
###
|
|
33
|
+
### From crates.io
|
|
109
34
|
```bash
|
|
110
|
-
sf-compact
|
|
35
|
+
cargo install sf-compact
|
|
111
36
|
```
|
|
112
37
|
|
|
113
|
-
|
|
38
|
+
## Commands
|
|
114
39
|
|
|
115
40
|
```bash
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
Bytes 7313 3418 53.3%
|
|
124
|
-
Tokens 1719 925 46.2%
|
|
125
|
-
|
|
126
|
-
Would save 794 tokens across 5 files
|
|
127
|
-
|
|
128
|
-
By metadata type:
|
|
129
|
-
type files now → after tokens saved
|
|
130
|
-
----------------------------------------------------------------------
|
|
131
|
-
profile 1 848 → 432 tokens 49.1%
|
|
132
|
-
flow 1 464 → 268 tokens 42.2%
|
|
133
|
-
field 1 232 → 126 tokens 45.7%
|
|
134
|
-
js 1 116 → 66 tokens 43.1%
|
|
135
|
-
cls 1 59 → 33 tokens 44.1%
|
|
41
|
+
sf-compact pack # XML -> compact (force-app -> .sf-compact)
|
|
42
|
+
sf-compact unpack .sf-compact -o force-app # compact -> XML
|
|
43
|
+
sf-compact watch # auto-pack on changes
|
|
44
|
+
sf-compact stats force-app # preview savings
|
|
45
|
+
sf-compact diff # detect unpacked changes
|
|
46
|
+
sf-compact lint # CI validation (exit 1 if stale)
|
|
47
|
+
sf-compact changes --since-deploy # track modified files
|
|
136
48
|
```
|
|
137
49
|
|
|
138
|
-
Use `--files` for per-file breakdown, `--include` to filter by glob pattern.
|
|
139
|
-
|
|
140
50
|
### Configuration
|
|
141
|
-
|
|
142
|
-
sf-compact uses a `.sfcompact.yaml` config file for per-type format control.
|
|
143
|
-
|
|
144
|
-
```bash
|
|
145
|
-
# Create config with smart defaults (json default, yaml for order-insensitive types)
|
|
146
|
-
sf-compact config init
|
|
147
|
-
|
|
148
|
-
# Set format for specific types (batch — multiple types in one call)
|
|
149
|
-
sf-compact config set flow json profile yaml flexipage yaml-ordered
|
|
150
|
-
|
|
151
|
-
# Change default format for all types
|
|
152
|
-
sf-compact config set default json
|
|
153
|
-
|
|
154
|
-
# Skip a metadata type from conversion
|
|
155
|
-
sf-compact config skip customMetadata
|
|
156
|
-
|
|
157
|
-
# View current configuration
|
|
158
|
-
sf-compact config show
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
Default config after `config init`:
|
|
162
|
-
|
|
163
|
-
```yaml
|
|
164
|
-
default_format: json
|
|
165
|
-
formats:
|
|
166
|
-
Profile: yaml
|
|
167
|
-
PermissionSet: yaml
|
|
168
|
-
PermissionSetGroup: yaml
|
|
169
|
-
# ... other order-insensitive types get yaml for readability
|
|
170
|
-
skip: []
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
When `pack` runs, it reads `.sfcompact.yaml` and applies the format per metadata type. The `--format` CLI flag overrides the config for a single run.
|
|
174
|
-
|
|
175
|
-
### Watch (auto-pack on changes)
|
|
176
|
-
```bash
|
|
177
|
-
sf-compact watch [source...] [-o output] [--format yaml|yaml-ordered|json] [--include pattern]
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
Watches source directories for XML changes and automatically repacks. Runs an initial pack, then monitors for file changes.
|
|
181
|
-
|
|
182
|
-
```bash
|
|
183
|
-
# Watch default force-app directory
|
|
184
|
-
sf-compact watch
|
|
185
|
-
|
|
186
|
-
# Watch with JSON format
|
|
187
|
-
sf-compact watch force-app --format json
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### Diff (detect unpacked changes)
|
|
191
|
-
```bash
|
|
192
|
-
sf-compact diff [source...] [-o packed-dir] [--include pattern]
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
Compare current XML metadata against the last packed output. Shows new, modified, and deleted files.
|
|
196
|
-
|
|
197
|
-
```bash
|
|
198
|
-
$ sf-compact diff
|
|
199
|
-
|
|
200
|
-
+ force-app/main/default/profiles/NewProfile.profile-meta.xml (new — not yet packed)
|
|
201
|
-
~ force-app/main/default/flows/Case_Assignment.flow-meta.xml (modified since last pack)
|
|
202
|
-
|
|
203
|
-
1 new, 1 modified, 0 deleted, 3 unchanged
|
|
204
|
-
Run `sf-compact pack` to update.
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### Lint (CI validation)
|
|
208
|
-
```bash
|
|
209
|
-
sf-compact lint [source...] [-o packed-dir] [--include pattern]
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
Check that compact files are up-to-date. Exits with code 1 if any files are stale, new, or orphaned. Use in CI pipelines.
|
|
213
|
-
|
|
214
|
-
### Changes (track modified compact files)
|
|
215
51
|
```bash
|
|
216
|
-
sf-compact
|
|
217
|
-
sf-compact
|
|
218
|
-
sf-compact
|
|
219
|
-
sf-compact changes reset --global # clear all tracking
|
|
220
|
-
sf-compact changes reset --since-deploy # clear deployment tracking only
|
|
52
|
+
sf-compact config init # create .sfcompact.yaml with smart defaults
|
|
53
|
+
sf-compact config set flow json profile yaml # set format per type
|
|
54
|
+
sf-compact config show # view current config
|
|
221
55
|
```
|
|
222
56
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
### MCP Server
|
|
226
|
-
|
|
227
|
-
sf-compact includes a built-in [MCP](https://modelcontextprotocol.io/) server for direct AI tool integration.
|
|
228
|
-
|
|
57
|
+
### AI Tool Integration
|
|
229
58
|
```bash
|
|
230
|
-
#
|
|
231
|
-
sf-compact init
|
|
232
|
-
|
|
233
|
-
#
|
|
234
|
-
sf-compact mcp-serve
|
|
59
|
+
sf-compact init instructions # CLAUDE.md / .cursorrules / etc. (recommended)
|
|
60
|
+
sf-compact init agent # sf-explorer agent for Claude Code (-33% cost)
|
|
61
|
+
sf-compact init hook # PreToolUse hook (optional)
|
|
62
|
+
sf-compact init mcp # MCP server
|
|
235
63
|
```
|
|
236
64
|
|
|
237
|
-
This exposes `sf_compact_pack`, `sf_compact_unpack`, `sf_compact_stats`, `sf_compact_lint`, and `sf_compact_changes` as MCP tools that Claude Code, Cursor, and other MCP-compatible tools can discover and use automatically.
|
|
238
|
-
|
|
239
|
-
### AI Instructions
|
|
240
|
-
|
|
241
|
-
Inject a compact directive block into your AI tool's instruction file. Auto-detects which AI tools are configured in the project and writes to all of them.
|
|
242
|
-
|
|
243
|
-
```bash
|
|
244
|
-
# Auto-detect AI tools and inject into all found instruction files
|
|
245
|
-
sf-compact init instructions
|
|
246
|
-
|
|
247
|
-
# Inject only into a specific tool's file
|
|
248
|
-
sf-compact init instructions --target claude # CLAUDE.md
|
|
249
|
-
sf-compact init instructions --target cursor # .cursorrules
|
|
250
|
-
sf-compact init instructions --target copilot # .github/copilot-instructions.md
|
|
251
|
-
sf-compact init instructions --target codex # AGENTS.md
|
|
252
|
-
|
|
253
|
-
# Remove sf-compact blocks from all AI instruction files
|
|
254
|
-
sf-compact init instructions --remove
|
|
255
|
-
|
|
256
|
-
# Legacy: create standalone reference file
|
|
257
|
-
sf-compact init instructions --name SF_COMPACT.md
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### Manifest
|
|
261
|
-
|
|
262
|
-
Output supported metadata types in JSON (includes format support and order-sensitivity flags):
|
|
263
|
-
|
|
264
|
-
```bash
|
|
265
|
-
sf-compact manifest
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
## Supported Metadata Types
|
|
269
|
-
|
|
270
|
-
76 file extensions mapping to Salesforce metadata types across 10 categories:
|
|
271
|
-
|
|
272
|
-
| Category | Types |
|
|
273
|
-
|----------|-------|
|
|
274
|
-
| **Security** | Profile, PermissionSet, PermissionSetGroup, RemoteSiteSetting, CspTrustedSite, ConnectedApp, SharingRules, CustomPermission, Role, Group, AuthProvider, SamlSsoConfig, Certificate |
|
|
275
|
-
| **Schema** | CustomObject, CustomField, ValidationRule, CustomMetadata, GlobalValueSet, StandardValueSet, RecordType, MatchingRule, DuplicateRule, CustomIndex, FieldSet |
|
|
276
|
-
| **Code** | ApexClass, ApexTrigger, ApexComponent, ApexPage, LightningComponentBundle (js/css/html/xml), AuraDefinitionBundle (cmp/evt), StaticResource |
|
|
277
|
-
| **Automation** | Flow*, Workflow, WorkflowRule, AssignmentRules, AutoResponseRules, EscalationRules |
|
|
278
|
-
| **UI** | Layout*, CustomLabels, CustomApplication, CustomTab, FlexiPage*, CustomSite, QuickAction, PathAssistant, ListView, CompactLayout, WebLink, HomePageLayout, AppMenu, Community, Letterhead |
|
|
279
|
-
| **Analytics** | ReportType, Report, Dashboard |
|
|
280
|
-
| **Integration** | ExternalServiceRegistration, NamedCredential, ExternalCredential |
|
|
281
|
-
| **Config** | Settings, InstalledPackage, TopicsForObjects, CustomNotificationType, CleanDataService, NotificationTypeConfig, PlatformEventChannelMember |
|
|
282
|
-
| **Translation** | CustomObjectTranslation, CustomFieldTranslation |
|
|
283
|
-
| **Content** | EmailTemplate, ManagedContentType, IframeWhiteListUrlSettings, LightningMessageChannel |
|
|
284
|
-
|
|
285
|
-
\* Order-sensitive types — `config init` defaults these to `yaml-ordered` to preserve element order.
|
|
286
|
-
|
|
287
65
|
## Workflow
|
|
288
66
|
|
|
289
|
-
1.
|
|
290
|
-
2.
|
|
291
|
-
3.
|
|
292
|
-
4.
|
|
293
|
-
5.
|
|
294
|
-
6.
|
|
295
|
-
|
|
296
|
-
> Use `sf-compact watch` during development to auto-pack on changes, and `sf-compact diff` to check if a repack is needed.
|
|
297
|
-
|
|
298
|
-
> Tip: Add `.sf-compact/` to `.gitignore` if you treat it as a build artifact, or commit it for AI-friendly diffs.
|
|
299
|
-
|
|
300
|
-
## How it works
|
|
301
|
-
|
|
302
|
-
- Parses Salesforce metadata XML into a tree structure
|
|
303
|
-
- Groups repeated elements (e.g., `<fieldPermissions>`) into arrays (YAML) or `_children` sequences (yaml-ordered, JSON)
|
|
304
|
-
- Coerces booleans: `"true"` → `true`, `"false"` → `false`. All other values (including numeric strings like `"59.0"`, `"0012"`) are preserved as-is
|
|
305
|
-
- Flattens simple key-value containers into inline mappings
|
|
306
|
-
- Preserves namespaces, attributes, and all structural information for semantically lossless roundtrip
|
|
307
|
-
- Order-sensitive types (Flow, FlexiPage, Layout) default to `yaml-ordered` format, which preserves exact element order via `_children` sequences
|
|
67
|
+
1. `sf-compact config init` (once)
|
|
68
|
+
2. `sf project retrieve start`
|
|
69
|
+
3. `sf-compact pack`
|
|
70
|
+
4. `sf-compact init instructions` (once)
|
|
71
|
+
5. AI reads compact files via CLAUDE.md directive
|
|
72
|
+
6. `sf-compact unpack` -> `sf project deploy start`
|
|
308
73
|
|
|
309
|
-
|
|
74
|
+
Full documentation: [github.com/vradko/sf-compact](https://github.com/vradko/sf-compact)
|
|
310
75
|
|
|
311
76
|
## License
|
|
312
77
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sf-compact-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.4.1",
|
|
4
|
+
"description": "Cut Salesforce metadata tokens in half for AI coding agents. Converts XML to compact YAML/JSON with AI instruction file integration.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|