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.
Files changed (2) hide show
  1. package/README.md +39 -274
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,312 +1,77 @@
1
1
  # sf-compact
2
2
 
3
- Convert Salesforce metadata XML to AI-friendly compact formats. Semantically lossless roundtrip for Salesforce metadata.
3
+ Cut Salesforce metadata tokens in half for AI coding agents.
4
4
 
5
- Salesforce metadata XML is extremely verbose — profiles, permission sets, flows, and objects can be 20,000–50,000+ lines of XML with 7085% structural overhead. This burns tokens and money when AI tools (Claude Code, Codex, Cursor, etc.) read or edit your metadata.
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
- **sf-compact** converts it to compact YAML or JSON, saving 42–54% of tokens depending on format.
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
- cargo install --path .
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
- ```bash
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
- # Pack as JSON for maximum token savings
88
- sf-compact pack force-app --format json
17
+ ## Why YAML is the Default
89
18
 
90
- # Pack specific directories
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
- # Pack only profiles
94
- sf-compact pack force-app --include "*.profile-meta.xml"
95
- ```
21
+ ## Install
96
22
 
97
- ### Unpack (compact format → XML)
23
+ ### npm (recommended)
98
24
  ```bash
99
- sf-compact unpack [source...] [-o output] [--include pattern]
25
+ npm install -g sf-compact-cli
100
26
  ```
101
27
 
102
- Auto-detects format by file extension (`.yaml` or `.json`).
103
-
28
+ ### Homebrew (macOS / Linux)
104
29
  ```bash
105
- sf-compact unpack .sf-compact -o force-app
30
+ brew install vradko/tap/sf-compact
106
31
  ```
107
32
 
108
- ### Stats (preview savings)
33
+ ### From crates.io
109
34
  ```bash
110
- sf-compact stats [source...] [--include pattern] [--files]
35
+ cargo install sf-compact
111
36
  ```
112
37
 
113
- Analyze metadata and preview token/byte savings without writing files.
38
+ ## Commands
114
39
 
115
40
  ```bash
116
- $ sf-compact stats force-app
117
-
118
- Preview: what sf-compact pack would produce
119
- Tokenizer: cl100k_base (GPT-4 / Claude)
120
-
121
- XML (now) YAML (after) savings
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 changes [-o compact-dir] # show all modified files (global)
217
- sf-compact changes --since-deploy # show changes since last deploy reset
218
- sf-compact changes --json # machine-readable JSON output
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
- Tracks which compact files were modified (by AI or human) since last `pack`. Per-branch tracking with two scopes: global (all changes) and deployment (delta since last deploy reset).
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
- # Add to your project's .mcp.json
231
- sf-compact init mcp
232
-
233
- # Or start manually
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. **Configure** (once): `sf-compact config init` — creates `.sfcompact.yaml` with smart defaults
290
- 2. **Pull metadata** from Salesforce (`sf project retrieve`)
291
- 3. **Pack**: `sf-compact pack` — creates `.sf-compact/` with compact files
292
- 4. **Work with compact files** let AI tools read/edit the YAML/JSON format
293
- 5. **Unpack**: `sf-compact unpack` restores XML for deployment
294
- 6. **Deploy** to Salesforce (`sf project deploy`)
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
- Token counting uses the `cl100k_base` tokenizer (same family used by GPT-4 and Claude).
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.3.3",
4
- "description": "Convert Salesforce metadata XML to compact AI-friendly formats (YAML/JSON). Semantically lossless roundtrip.",
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",