filedist 0.31.0 → 0.33.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 (129) hide show
  1. package/README.md +301 -254
  2. package/dist/cli/actions/check.d.ts +5 -2
  3. package/dist/cli/actions/check.d.ts.map +1 -1
  4. package/dist/cli/actions/check.js +9 -3
  5. package/dist/cli/actions/check.js.map +1 -1
  6. package/dist/cli/actions/init.d.ts.map +1 -1
  7. package/dist/cli/actions/init.js +10 -3
  8. package/dist/cli/actions/init.js.map +1 -1
  9. package/dist/cli/actions/install.d.ts +7 -0
  10. package/dist/cli/actions/install.d.ts.map +1 -0
  11. package/dist/cli/actions/{extract.js → install.js} +15 -13
  12. package/dist/cli/actions/install.js.map +1 -0
  13. package/dist/cli/actions/list.d.ts +1 -1
  14. package/dist/cli/actions/list.d.ts.map +1 -1
  15. package/dist/cli/actions/list.js +4 -2
  16. package/dist/cli/actions/list.js.map +1 -1
  17. package/dist/cli/actions/remove.d.ts +20 -0
  18. package/dist/cli/actions/remove.d.ts.map +1 -0
  19. package/dist/cli/actions/remove.js +133 -0
  20. package/dist/cli/actions/remove.js.map +1 -0
  21. package/dist/cli/actions/update.d.ts +8 -0
  22. package/dist/cli/actions/update.d.ts.map +1 -0
  23. package/dist/cli/actions/update.js +40 -0
  24. package/dist/cli/actions/update.js.map +1 -0
  25. package/dist/cli/argv.d.ts +8 -5
  26. package/dist/cli/argv.d.ts.map +1 -1
  27. package/dist/cli/argv.js +40 -15
  28. package/dist/cli/argv.js.map +1 -1
  29. package/dist/cli/binpkg.d.ts +1 -12
  30. package/dist/cli/binpkg.d.ts.map +1 -1
  31. package/dist/cli/binpkg.js +64 -12
  32. package/dist/cli/binpkg.js.map +1 -1
  33. package/dist/cli/cli.d.ts.map +1 -1
  34. package/dist/cli/cli.js +80 -41
  35. package/dist/cli/cli.js.map +1 -1
  36. package/dist/cli/usage.d.ts.map +1 -1
  37. package/dist/cli/usage.js +65 -33
  38. package/dist/cli/usage.js.map +1 -1
  39. package/dist/fileset/check.d.ts +0 -1
  40. package/dist/fileset/check.d.ts.map +1 -1
  41. package/dist/fileset/check.js +7 -8
  42. package/dist/fileset/check.js.map +1 -1
  43. package/dist/fileset/constants.d.ts.map +1 -1
  44. package/dist/fileset/constants.js +3 -2
  45. package/dist/fileset/constants.js.map +1 -1
  46. package/dist/fileset/execute.d.ts.map +1 -1
  47. package/dist/fileset/execute.js +2 -1
  48. package/dist/fileset/execute.js.map +1 -1
  49. package/dist/fileset/gitignore.js +3 -3
  50. package/dist/fileset/gitignore.js.map +1 -1
  51. package/dist/fileset/markers.d.ts +1 -2
  52. package/dist/fileset/markers.d.ts.map +1 -1
  53. package/dist/fileset/markers.js +6 -14
  54. package/dist/fileset/markers.js.map +1 -1
  55. package/dist/fileset/test-utils.d.ts.map +1 -1
  56. package/dist/fileset/test-utils.js +2 -1
  57. package/dist/fileset/test-utils.js.map +1 -1
  58. package/dist/index.d.ts +9 -5
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +15 -5
  61. package/dist/index.js.map +1 -1
  62. package/dist/package/action-check.d.ts +19 -9
  63. package/dist/package/action-check.d.ts.map +1 -1
  64. package/dist/package/action-check.js +76 -32
  65. package/dist/package/action-check.js.map +1 -1
  66. package/dist/package/action-init.d.ts +6 -2
  67. package/dist/package/action-init.d.ts.map +1 -1
  68. package/dist/package/action-init.js +26 -15
  69. package/dist/package/action-init.js.map +1 -1
  70. package/dist/package/action-install.d.ts +22 -0
  71. package/dist/package/action-install.d.ts.map +1 -0
  72. package/dist/package/{action-extract.js → action-install.js} +205 -32
  73. package/dist/package/action-install.js.map +1 -0
  74. package/dist/package/action-list.d.ts +5 -2
  75. package/dist/package/action-list.d.ts.map +1 -1
  76. package/dist/package/action-list.js +5 -4
  77. package/dist/package/action-list.js.map +1 -1
  78. package/dist/package/action-remove.d.ts +65 -0
  79. package/dist/package/action-remove.d.ts.map +1 -0
  80. package/dist/package/action-remove.js +171 -0
  81. package/dist/package/action-remove.js.map +1 -0
  82. package/dist/package/action-update.d.ts +28 -0
  83. package/dist/package/action-update.d.ts.map +1 -0
  84. package/dist/package/action-update.js +45 -0
  85. package/dist/package/action-update.js.map +1 -0
  86. package/dist/package/calculate-diff.d.ts +1 -1
  87. package/dist/package/calculate-diff.d.ts.map +1 -1
  88. package/dist/package/calculate-diff.js +11 -13
  89. package/dist/package/calculate-diff.js.map +1 -1
  90. package/dist/package/config.d.ts +40 -27
  91. package/dist/package/config.d.ts.map +1 -1
  92. package/dist/package/config.js +164 -113
  93. package/dist/package/config.js.map +1 -1
  94. package/dist/package/index.d.ts +6 -4
  95. package/dist/package/index.d.ts.map +1 -1
  96. package/dist/package/index.js +7 -5
  97. package/dist/package/index.js.map +1 -1
  98. package/dist/package/lockfile.d.ts +69 -0
  99. package/dist/package/lockfile.d.ts.map +1 -0
  100. package/dist/package/lockfile.js +191 -0
  101. package/dist/package/lockfile.js.map +1 -0
  102. package/dist/package/resolve-files.d.ts +14 -0
  103. package/dist/package/resolve-files.d.ts.map +1 -1
  104. package/dist/package/resolve-files.js +5 -1
  105. package/dist/package/resolve-files.js.map +1 -1
  106. package/dist/package/source.d.ts +13 -0
  107. package/dist/package/source.d.ts.map +1 -1
  108. package/dist/package/source.js +32 -11
  109. package/dist/package/source.js.map +1 -1
  110. package/dist/package/symlinks.d.ts.map +1 -1
  111. package/dist/package/symlinks.js +8 -3
  112. package/dist/package/symlinks.js.map +1 -1
  113. package/dist/types.d.ts +7 -6
  114. package/dist/types.d.ts.map +1 -1
  115. package/package.json +1 -2
  116. package/dist/cli/actions/extract.d.ts +0 -7
  117. package/dist/cli/actions/extract.d.ts.map +0 -1
  118. package/dist/cli/actions/extract.js.map +0 -1
  119. package/dist/cli/actions/purge.d.ts +0 -6
  120. package/dist/cli/actions/purge.d.ts.map +0 -1
  121. package/dist/cli/actions/purge.js +0 -42
  122. package/dist/cli/actions/purge.js.map +0 -1
  123. package/dist/package/action-extract.d.ts +0 -20
  124. package/dist/package/action-extract.d.ts.map +0 -1
  125. package/dist/package/action-extract.js.map +0 -1
  126. package/dist/package/action-purge.d.ts +0 -19
  127. package/dist/package/action-purge.d.ts.map +0 -1
  128. package/dist/package/action-purge.js +0 -135
  129. package/dist/package/action-purge.js.map +0 -1
package/README.md CHANGED
@@ -5,7 +5,7 @@ Publish folders as npm packages or git repositories and extract them in any work
5
5
  ## How it works
6
6
 
7
7
  - **Publisher**: a project that has folders to share. Running `init` prepares its `package.json` so those folders are included when the package is published.
8
- - **Consumer**: any project that installs that package and runs `extract` to download the files locally. A `.filedist` marker file is written alongside the managed files to track ownership and enable safe updates.
8
+ - **Consumer**: any project that installs that package and runs `install` to download the files locally. A `.filedist` marker file is written alongside the managed files to track ownership and enable safe updates.
9
9
 
10
10
  ## Extraction patterns
11
11
 
@@ -13,75 +13,73 @@ There are three ways to extract data with `filedist`. Choose the one that fits y
13
13
 
14
14
  ### Pattern 1 — Ad-hoc CLI extraction
15
15
 
16
- Use `npx filedist extract` directly from the command line whenever you need to pull files from a package without any prior setup.
16
+ Use `npx filedist install` directly from the command line whenever you need to pull files from a package without any prior setup.
17
17
 
18
18
  ```sh
19
- npx filedist extract --packages my-shared-assets@^2.0.0 --output ./data
19
+ npx filedist install my-shared-assets@^2.0.0 --output ./data
20
20
 
21
21
  # or use a git repository as the source
22
- npx filedist extract --packages git:github.com/flaviostutz/xdrs-core@1.3.0 --output ./xdrs
22
+ npx filedist install git:github.com/flaviostutz/xdrs-core@1.3.0 --output ./xdrs
23
23
  ```
24
24
 
25
25
  Package specs support optional source prefixes. Use `git:` for git repositories and `npm:` when you want to make the npm source explicit. When no prefix is present, filedist treats the spec as npm. Git specs accept full repository URLs and host/path shorthands such as `git:github.com/org/repo.git@ref`.
26
26
 
27
- #### Auto-save to `.filedistrc.yml`
27
+ #### Auto-save to `.filedist.yml`
28
28
 
29
- Whenever `--packages` is used, filedist automatically creates or updates a `.filedistrc.yml` file in the current directory with the packages and selectors from that run. This means subsequent updates can be done with a single command — no flags needed:
29
+ Whenever a package argument is supplied, filedist automatically creates or updates a `.filedist.yml` file in the current directory with the package and selectors from that run. This means subsequent updates can be done with a single command — no flags needed:
30
30
 
31
31
  ```sh
32
- # First run: extract and save to .filedistrc.yml automatically
33
- npx filedist extract --packages my-shared-assets@^2.0.0 --output ./data
32
+ # First run: extract and save to .filedist.yml automatically
33
+ npx filedist install my-shared-assets@^2.0.0 --output ./data
34
34
 
35
- # .filedistrc.yml is now created:
35
+ # .filedist.yml is now created:
36
36
  # sets:
37
37
  # - package: my-shared-assets@^2.0.0
38
38
  # output:
39
39
  # path: ./data
40
40
 
41
- # Future bumps: just run extract (reads .filedistrc.yml)
42
- npx filedist extract
41
+ # Future bumps: just run install (reads .filedist.yml)
42
+ npx filedist install
43
43
 
44
44
  # Or bump to a newer version
45
- npx filedist extract --packages my-shared-assets@^3.0.0 --output ./data
46
- # .filedistrc.yml is updated in place (same entry, new version)
45
+ npx filedist install my-shared-assets@^3.0.0 --output ./data
46
+ # .filedist.yml is updated in place (same entry, new version)
47
47
  ```
48
48
 
49
- If the entry already exists in `.filedistrc.yml` with identical content, the file is left unchanged. Use `--no-save` to run a one-off extraction without reading or updating `.filedistrc.yml`:
49
+ If the entry already exists in `.filedist.yml` with identical content, the file is left unchanged. Use `--no-save` to run a one-off extraction without reading or updating `.filedist.yml`:
50
50
 
51
51
  ```sh
52
- npx filedist extract --packages my-shared-assets@^2.0.0 --output ./tmp --no-save
52
+ npx filedist install my-shared-assets@^2.0.0 --output ./tmp --no-save
53
53
  ```
54
54
 
55
55
  ### Pattern 2 — Data packages with embedded configuration
56
56
 
57
- Create a dedicated npm package whose `package.json` declares an `filedist` config block. That config encodes the extraction sources, output directories, filtering rules, and any combination of upstream packages. Consumers install the data package and run its bundled script — they don't need to know the internals.
57
+ Create a dedicated npm package with a `.filedist-package.yml` file that encodes the extraction sources, output directories, filtering rules, and any combination of upstream packages. Consumers install the data package and run its bundled script — they don't need to know the internals.
58
58
 
59
- **Publisher** — add an `filedist` block to the data package's `package.json`:
59
+ **Publisher** — create a `.filedist-package.yml` in the data package root:
60
60
 
61
- ```json
62
- {
63
- "name": "my-org-configs",
64
- "version": "1.0.0",
65
- "filedist": {
66
- "sets": [
67
- {
68
- "package": "base-datasets@^3.0.0",
69
- "selector": { "files": ["datasets/**"] },
70
- "output": { "path": "./data/base" }
71
- },
72
- {
73
- "package": "org-configs@^1.2.0",
74
- "selector": { "contentRegexes": ["env: production"] },
75
- "output": { "path": "./configs" }
76
- },
77
- {
78
- "package": "git:github.com/flaviostutz/xdrs-core@1.3.0",
79
- "selector": { "files": ["docs/**"] },
80
- "output": { "path": "./xdrs" }
81
- }
82
- ]
83
- }
84
- }
61
+ ```yaml
62
+ sets:
63
+ - package: base-datasets@^3.0.0
64
+ selector:
65
+ files:
66
+ - datasets/**
67
+ output:
68
+ path: ./data/base
69
+
70
+ - package: org-configs@^1.2.0
71
+ selector:
72
+ contentRegexes:
73
+ - env: production
74
+ output:
75
+ path: ./configs
76
+
77
+ - package: git:github.com/flaviostutz/xdrs-core@1.3.0
78
+ selector:
79
+ files:
80
+ - docs/**
81
+ output:
82
+ path: ./xdrs
85
83
  ```
86
84
 
87
85
  Run `pnpm dlx filedist init` in that package and then `npm publish` to release it.
@@ -98,76 +96,43 @@ No knowledge of the upstream packages or transformation rules is required.
98
96
 
99
97
  ### Pattern 3 — Config file mode
100
98
 
101
- Add an `filedist` configuration directly to a project's own `package.json` (or a `.filedistrc` file) and then run `filedist extract` without `--packages`. The CLI automatically loads the configuration and runs every entry, reusing the same runner logic as data packages.
99
+ Add a `.filedist.yml` file to your project and run `filedist install` without a package argument. The CLI automatically loads the configuration and runs every entry, reusing the same runner logic as data packages.
102
100
 
103
- **Consumer** — declare the config inline in `package.json`:
104
-
105
- ```json
106
- {
107
- "name": "my-project",
108
- "filedist": {
109
- "defaultPresets": ["prod"],
110
- "sets": [
111
- {
112
- "package": "base-datasets@^3.0.0",
113
- "selector": { "files": ["datasets/**"] },
114
- "output": { "path": "./data" }
115
- },
116
- {
117
- "package": "git:github.com/flaviostutz/xdrs-core@1.3.0",
118
- "selector": { "files": ["docs/**"] },
119
- "output": { "path": "./xdrs" }
120
- }
121
- ]
122
- }
123
- }
124
- ```
101
+ **Consumer** — create a `.filedist.yml` in the project root:
125
102
 
126
- Or write a standalone `.filedistrc` (JSON object at the top level):
103
+ ```yaml
104
+ defaultPresets:
105
+ - prod
106
+ sets:
107
+ - package: base-datasets@^3.0.0
108
+ selector:
109
+ files:
110
+ - datasets/**
111
+ output:
112
+ path: ./data
127
113
 
128
- ```json
129
- {
130
- "sets": [
131
- {
132
- "package": "base-datasets@^3.0.0",
133
- "selector": { "files": ["datasets/**"] },
134
- "output": { "path": "./data" }
135
- },
136
- {
137
- "package": "git:file:///absolute/path/to/local-repo@v2.0.0",
138
- "selector": { "files": ["conf/**"] },
139
- "output": { "path": "./local-conf" }
140
- }
141
- ]
142
- }
114
+ - package: git:github.com/flaviostutz/xdrs-core@1.3.0
115
+ selector:
116
+ files:
117
+ - docs/**
118
+ output:
119
+ path: ./xdrs
143
120
  ```
144
121
 
145
- For a local Windows path, use the same `file://` form with a drive letter, for example `git:file:///C:/work/local-repo@v2.0.0`.
122
+ For a local git repository, use the `file://` form with an absolute path, for example `git:file:///absolute/path/to/local-repo@v2.0.0`. On Windows use a drive letter: `git:file:///C:/work/local-repo@v2.0.0`.
146
123
 
147
- Then run any command without `--packages`:
124
+ Then run any command without a package argument:
148
125
 
149
126
  ```sh
150
- npx filedist # same as 'npx filedist extract'
151
- npx filedist extract # reads config, extracts all entries or only defaultPresets when defined
127
+ npx filedist # same as 'npx filedist install'
128
+ npx filedist install # reads .filedist.yml, extracts all entries or only defaultPresets when defined
152
129
  npx filedist check # checks the same effective set selection
153
- npx filedist purge # purges the same effective set selection
154
130
  ```
155
131
 
156
- Config is resolved using [cosmiconfig](https://github.com/cosmiconfig/cosmiconfig). Sources searched in order from the current directory:
157
-
158
- | Source | Key / format | Notes |
159
- |---|---|---|
160
- | `.filedistrc.local.yml` | YAML object with `"sets"` array | Local-only override; checked first; not searched in parent dirs |
161
- | `package.json` | `"filedist"` key — object with `"sets"` array | |
162
- | `.filedistrc` | JSON or YAML object with `"sets"` array | |
163
- | `.filedistrc.json` | JSON object with `"sets"` array | |
164
- | `.filedistrc.yaml` / `.filedistrc.yml` | YAML object with `"sets"` array | |
165
- | `filedist.config.js` | CommonJS module exporting object with `sets` array | |
166
-
167
- When `.filedistrc.local.yml` is present in the current directory it takes full priority over all other config sources. This is useful when you are developing a package that already ships its own filedist config (e.g. in `package.json`) but you need to run extra extractions locally — for example to pull other packages into your workspace — without those entries being part of the published package config.
132
+ filedist reads only `.filedist.yml` from the current working directory. No parent-directory traversal is performed.
168
133
 
169
134
  All runner flags (`--dry-run`, `--silent`, `--verbose`, `--gitignore=false`, `--managed=false`, `--presets`, `--output`) work as usual.
170
- When `filedist.defaultPresets` is defined, `extract`, `check`, and `purge` behave as if `--presets <tags>` had been passed automatically. Passing `--presets` explicitly overrides that configured default for the current invocation.
135
+ When `filedist.defaultPresets` is defined, `install` and `check` behave as if `--presets <tags>` had been passed automatically. Passing `--presets` explicitly overrides that configured default for the current invocation.
171
136
  Use `--all` to ignore `defaultPresets` for one run and process every configured entry.
172
137
 
173
138
  Config-file mode can mix npm packages and git repositories in the same `sets` array. Use the `git:` prefix for git entries.
@@ -186,11 +151,9 @@ In the project whose folders you want to share:
186
151
  # share specific folders by glob pattern (required)
187
152
  pnpm dlx filedist init --files "docs/**,data/**,configs/**"
188
153
 
189
- # also bundle an additional package so consumers get data from both sources
190
- pnpm dlx filedist init --files "docs/**" --packages shared-configs@^1.0.0
191
-
192
- # share multiple upstream sources, including git
193
- pnpm dlx filedist init --files "docs/**" --packages "shared-configs@^1.0.0,git:github.com/flaviostutz/xdrs-core@1.3.0"
154
+ # to also bundle upstream packages, add them manually to .filedist-package.yml after init
155
+ pnpm dlx filedist init --files "docs/**"
156
+ # then edit .filedist-package.yml and add entries for shared-configs@^1.0.0, git sources, etc.
194
157
 
195
158
  ```
196
159
 
@@ -204,46 +167,45 @@ npm publish
204
167
 
205
168
  ```sh
206
169
  # npm package examples
207
- npx filedist extract --packages my-shared-assets --output ./data
208
- npx filedist extract --packages my-shared-assets@^2.0.0 --output ./data
209
- npx filedist extract --packages "my-shared-assets@^2.0.0,another-pkg@1.x" --output ./data
210
- npx filedist extract --packages my-shared-assets --files "**/*.md" --output ./docs
211
- npx filedist extract --packages my-shared-assets --content-regex "env: production" --output ./configs
212
- npx filedist extract --packages my-shared-assets --output ./data --force
213
- npx filedist extract --packages my-shared-assets --output ./data --gitignore=false
214
- npx filedist extract --packages my-shared-assets --output ./data --managed=false
215
- npx filedist extract --packages my-shared-assets --output ./data --dry-run
216
- npx filedist extract --packages my-shared-assets@latest --output ./data --upgrade
170
+ npx filedist install my-shared-assets --output ./data
171
+ npx filedist install my-shared-assets@^2.0.0 --output ./data
172
+ npx filedist install my-shared-assets --files "**/*.md" --output ./docs
173
+ npx filedist install my-shared-assets --content-regex "env: production" --output ./configs
174
+ npx filedist install my-shared-assets --output ./data --force
175
+ npx filedist install my-shared-assets --output ./data --gitignore=false
176
+ npx filedist install my-shared-assets --output ./data --managed=false
177
+ npx filedist install my-shared-assets --output ./data --dry-run
178
+ npx filedist install my-shared-assets@latest --output ./data --upgrade
217
179
 
218
180
  # git source examples
219
- npx filedist extract --packages https://github.com/flaviostutz/xdrs-core@1.3.0 --output ./xdrs
220
- npx filedist extract --packages https://github.com/flaviostutz/xdrs-core@main --output ./xdrs
221
- npx filedist extract --packages "https://github.com/org/repo-a@v1.0.0,file:///tmp/repo-b@main" --output ./git-data
222
- npx filedist extract --packages https://github.com/flaviostutz/xdrs-core@1.3.0 --files "docs/**/*.md" --output ./docs
223
- npx filedist extract --packages https://github.com/flaviostutz/xdrs-core@1.3.0 --content-regex "Decision Outcome" --output ./filtered-docs
224
- npx filedist extract --packages https://github.com/flaviostutz/xdrs-core@1.3.0 --output ./xdrs --force
225
- npx filedist extract --packages https://github.com/flaviostutz/xdrs-core@1.3.0 --output ./xdrs --gitignore=false
226
- npx filedist extract --packages https://github.com/flaviostutz/xdrs-core@1.3.0 --output ./xdrs --managed=false
227
- npx filedist extract --packages https://github.com/flaviostutz/xdrs-core@1.3.0 --output ./xdrs --dry-run
228
- npx filedist extract --packages https://github.com/flaviostutz/xdrs-core@main --output ./xdrs --upgrade
181
+ npx filedist install git:github.com/flaviostutz/xdrs-core@1.3.0 --output ./xdrs
182
+ npx filedist install git:github.com/flaviostutz/xdrs-core@main --output ./xdrs
183
+ npx filedist install git:github.com/flaviostutz/xdrs-core@1.3.0 --files "docs/**/*.md" --output ./docs
184
+ npx filedist install git:github.com/flaviostutz/xdrs-core@1.3.0 --content-regex "Decision Outcome" --output ./filtered-docs
185
+ npx filedist install git:github.com/flaviostutz/xdrs-core@1.3.0 --output ./xdrs --force
186
+ npx filedist install git:github.com/flaviostutz/xdrs-core@1.3.0 --output ./xdrs --gitignore=false
187
+ npx filedist install git:github.com/flaviostutz/xdrs-core@1.3.0 --output ./xdrs --managed=false
188
+ npx filedist install git:github.com/flaviostutz/xdrs-core@1.3.0 --output ./xdrs --dry-run
189
+ npx filedist install git:github.com/flaviostutz/xdrs-core@main --output ./xdrs --upgrade
190
+ # For multiple packages at once, use a config file (.filedistrc) and run: npx filedist install
229
191
  ```
230
192
 
231
- `extract` logs every file change as it happens:
193
+ `install` logs every file change as it happens:
232
194
 
233
195
  ```
234
- A data/users-dataset/user1.json
235
- M data/configs/app.config.json
236
- D data/old-file.json
196
+ + data/users-dataset/user1.json (M,I)
197
+ ~ data/configs/app.config.json (M,I)
198
+ - data/old-file.json
237
199
  ```
238
200
 
239
201
  If the published package includes its own bin script (normally when it's prepared using "init") you can also call it directly so it extracts data that is inside the package itself:
240
202
 
241
203
  ```sh
242
- npx my-shared-assets extract --output ./data
204
+ npx my-shared-assets install --output ./data
243
205
  npx my-shared-assets check --output ./data
244
206
  ```
245
207
 
246
- When the data package defines multiple `filedist` entries in its `package.json`, you can limit which entries are processed using the `--presets` option. Only entries whose `presets` list includes at least one of the requested presets will be extracted; entries with no presets are skipped when a preset filter is active.
208
+ When the data package defines multiple entries in its `.filedist-package.yml`, you can limit which entries are processed using the `--presets` option. Only entries whose `presets` list includes at least one of the requested presets will be extracted; entries with no presets are skipped when a preset filter is active.
247
209
 
248
210
  ```sh
249
211
  # run only entries tagged with "prod"
@@ -253,17 +215,21 @@ npx my-shared-assets --presets prod
253
215
  npx my-shared-assets --presets prod,staging
254
216
  ```
255
217
 
256
- To use presets, add a `presets` array to each `filedist` entry in the data package's `package.json`:
218
+ To use presets, add a `presets` array to each entry in the data package's `.filedist-package.yml`:
257
219
 
258
- ```json
259
- {
260
- "filedist": {
261
- "sets": [
262
- { "package": "my-shared-assets", "output": { "path": "./data" }, "presets": ["prod"] },
263
- { "package": "my-dev-assets", "output": { "path": "./dev-data" }, "presets": ["dev", "staging"] }
264
- ]
265
- }
266
- }
220
+ ```yaml
221
+ sets:
222
+ - package: my-shared-assets
223
+ output:
224
+ path: ./data
225
+ presets:
226
+ - prod
227
+ - package: my-dev-assets
228
+ output:
229
+ path: ./dev-data
230
+ presets:
231
+ - dev
232
+ - staging
267
233
  ```
268
234
 
269
235
  Check the /examples folder to see this in action
@@ -323,8 +289,8 @@ Top-level config fields:
323
289
 
324
290
  | Option | Type | Default | Description |
325
291
  |---|---|---|---|
326
- | `defaultPresets` | `string[]` | none | CLI-only fallback for config-file mode. `extract`, `check`, and `purge` behave as if `--presets <tags>` had been passed when the flag is omitted. |
327
- | `postExtractCmd` | `string[]` | none | Command argv run after a successful non-dry-run `extract`. The first array item is the executable and the remaining items are its arguments. Full extract argv is appended. |
292
+ | `defaultPresets` | `string[]` | none | CLI-only fallback for config-file mode. `install` and `check` behave as if `--presets <tags>` had been passed when the flag is omitted. |
293
+ | `postExtractCmd` | `string[]` | none | Command argv run after a successful non-dry-run `install`. The first array item is the executable and the remaining items are its arguments. Full install argv is appended. |
328
294
 
329
295
  #### SymlinkConfig
330
296
 
@@ -347,57 +313,50 @@ After extraction, for each config the runner finds workspace files matching `fil
347
313
 
348
314
  Example with multiple options:
349
315
 
350
- ```json
351
- {
352
- "filedist": {
353
- "sets": [
354
- {
355
- "package": "my-shared-assets@^2.0.0",
356
- "selector": {
357
- "files": ["docs/**", "configs/*.json"],
358
- "upgrade": true
359
- },
360
- "output": {
361
- "path": "./data",
362
- "gitignore": true,
363
- "symlinks": [
364
- { "source": "**\/skills\/**", "target": ".github/skills" }
365
- ],
366
- "contentReplacements": [
367
- { "files": "docs/**\/*.md", "match": "<!-- version: .* -->", "replace": "<!-- version: 2.0.0 -->" }
368
- ]
369
- },
370
- "presets": ["prod"]
371
- },
372
- {
373
- "package": "git:github.com/flaviostutz/xdrs-core@1.3.0",
374
- "selector": {
375
- "files": ["docs/**"],
376
- "upgrade": true
377
- },
378
- "output": {
379
- "path": "./xdrs",
380
- "gitignore": false
381
- },
382
- "presets": ["prod"]
383
- }
384
- ]
385
- }
386
- }
316
+ ```yaml
317
+ sets:
318
+ - package: my-shared-assets@^2.0.0
319
+ selector:
320
+ files:
321
+ - docs/**
322
+ - configs/*.json
323
+ upgrade: true
324
+ output:
325
+ path: ./data
326
+ gitignore: true
327
+ symlinks:
328
+ - source: "**/skills/**"
329
+ target: .github/skills
330
+ contentReplacements:
331
+ - files: docs/**/*.md
332
+ match: "<!-- version: .* -->"
333
+ replace: "<!-- version: 2.0.0 -->"
334
+ presets:
335
+ - prod
336
+
337
+ - package: git:github.com/flaviostutz/xdrs-core@1.3.0
338
+ selector:
339
+ files:
340
+ - docs/**
341
+ upgrade: true
342
+ output:
343
+ path: ./xdrs
344
+ gitignore: false
345
+ presets:
346
+ - prod
387
347
  ```
388
348
 
389
349
  ### 3. Check files are in sync
390
350
 
391
- Verifies that every file in the output directory matches what is currently in the published package. When the target package itself declares `filedist.sets`, check recurses into those transitive dependencies reporting drift at every level of the hierarchy without downloading anything new beyond what is already installed. Use `selector.presets` on an entry to restrict which of the target's sets are checked.
351
+ Verifies that every file in the output directory matches what was installed. `check` reads exclusively from `.filedist.lock`it does **not** read your `.filedist.yml` configuration and does **not** require `--packages`. The lockfile must exist (run `filedist install` first).
392
352
 
393
353
  ```sh
394
- npx filedist check --packages my-shared-assets --output ./data
354
+ npx filedist check
395
355
  # exit 0 = in sync, exit 1 = drift or error
396
-
397
- # check multiple packages
398
- npx filedist check --packages "my-shared-assets,another-pkg" --output ./data
399
356
  ```
400
357
 
358
+ `check` uses the pinned package versions recorded in `.filedist.lock` so results are fully reproducible without any network access beyond what is already cached.
359
+
401
360
  The check command reports differences per package:
402
361
 
403
362
  ```
@@ -409,7 +368,7 @@ The check command reports differences per package:
409
368
 
410
369
  #### Offline / local-only check
411
370
 
412
- By default `check` installs packages (or uses an already-installed version) to detect *extra* files — files that exist in the package source but were never extracted. If you want a fast, fully offline check that skips all network and install steps, use `--local-only`:
371
+ By default `check` compares local files against the package versions pinned in `.filedist.lock` to also detect *extra* files — files that exist in the package source but were never extracted. If you want a fast, fully offline check that skips all network and install steps, use `--local-only`:
413
372
 
414
373
  ```sh
415
374
  npx filedist check --local-only
@@ -443,26 +402,45 @@ another-pkg@1.0.0
443
402
  data/other-file.txt
444
403
  ```
445
404
 
446
- ### 5. Purge managed files
405
+ ### 5. Remove a package set
447
406
 
448
- Remove all files previously extracted by one or more packages without touching any other files in the output directory. No network access or package installation is required only the local `.filedist` marker state is used. When the target package itself declares `filedist.sets`, purge recurses into those transitive dependencies and removes their managed files too, mirroring what extract originally created.
407
+ Remove one or more set entries from your config file and delete their managed files from disk. `remove` reads your `.filedist.yml` config **not** `.filedist.lock`. It deletes the matching entries from the config file, then runs a full install with the remaining entries so the lockfile is updated and orphaned files are deleted. This is equivalent to manually deleting the sets from your config and running `filedist install`.
449
408
 
450
409
  ```sh
451
- # remove all files managed by a package
452
- npx filedist purge --packages my-shared-assets --output ./data
410
+ # remove all entries for a package (version is ignored during matching)
411
+ npx filedist remove my-shared-assets
412
+
413
+ # remove only the entry pointing to a specific output directory
414
+ npx filedist remove my-shared-assets --output ./data
453
415
 
454
- # purge multiple packages at once
455
- npx filedist purge --packages "my-shared-assets,another-pkg" --output ./data
416
+ # remove every set entry from the config (clears all managed files)
417
+ npx filedist remove --all
456
418
 
457
- # preview what would be deleted without removing anything
458
- npx filedist purge --packages my-shared-assets --output ./data --dry-run
419
+ # preview changes without modifying config or disk
420
+ npx filedist remove my-shared-assets --dry-run
459
421
  ```
460
422
 
461
- After a purge, the corresponding entries are removed from the `.filedist` marker file and any empty directories are cleaned up. `.gitignore` sections written by `extract` are also removed.
423
+ After the config is updated, `remove` calls `install` internally (without `--frozen-lockfile`) so:
424
+ - The lockfile is rewritten with the remaining sets.
425
+ - Files that were managed by the removed package are deleted from disk.
426
+ - Files managed by other packages are left untouched.
427
+
428
+ ### 6. Update to latest versions
429
+
430
+ Bumps all packages to their latest available versions, updates `.filedist.lock`, and re-extracts the files.
431
+
432
+ ```sh
433
+ npx filedist update
434
+
435
+ # preview what would change without writing anything
436
+ npx filedist update --dry-run
437
+ ```
438
+
439
+ `update` reads the current `sets` recorded in `.filedist.lock` (falling back to your config file if no lockfile exists), forces a fresh install of every package, and writes the new resolved versions back to `.filedist.lock`.
462
440
 
463
441
  ## Hierarchical package resolution
464
442
 
465
- `extract`, `check`, and `purge` are all hierarchy-aware: when a target package or git repository carries its own `filedist.sets` block in its `package.json` or `.filedistrc*`, the command automatically recurses into those transitive dependencies.
443
+ `extract` and `check` are all hierarchy-aware: when a target package or git repository carries its own `.filedist-package.yml`, the command automatically recurses into those transitive dependencies.
466
444
 
467
445
  This lets you build layered data package chains:
468
446
 
@@ -474,7 +452,7 @@ consumer project
474
452
  └─ raw-assets (leaf package)
475
453
  ```
476
454
 
477
- Running `npx filedist extract --packages my-org-configs --output ./data` will extract files from every package in the chain, not just `my-org-configs` itself.
455
+ Running `npx filedist install my-org-configs --output ./data` will extract files from every package in the chain, not just `my-org-configs` itself.
478
456
 
479
457
  When the source is git, filedist clones repositories into `.filedist-tmp` inside the working directory, adds that folder to `.gitignore` if needed, resolves nested config from the cloned repository, and removes `.filedist-tmp` when the command ends.
480
458
 
@@ -482,9 +460,9 @@ When the source is git, filedist clones repositories into `.filedist-tmp` inside
482
460
 
483
461
  Each level's `output.path` is resolved relative to the caller's own `output.path`. A package at depth 1 with `output.path: "./configs"` and a transitive dependency with `output.path: "./shared"` will land at `./configs/shared`.
484
462
 
485
- ### Caller overrides (extract only)
463
+ ### Caller overrides (install only)
486
464
 
487
- When `extract` recurses, the caller's `output` flags are inherited by every transitive dependency, with caller-defined values always winning:
465
+ When `install` recurses, the caller's `output` flags are inherited by every transitive dependency, with caller-defined values always winning:
488
466
 
489
467
  | Caller sets | Effect on transitive entries |
490
468
  |---|---|
@@ -501,21 +479,17 @@ Settings that are undefined on the caller are left as-is so the transitive packa
501
479
 
502
480
  Set `selector.presets` on an entry to control which sets inside the target package are recursed into. Only sets whose `presets` tag overlaps with the filter are processed; sets with no `presets` are skipped when a filter is active.
503
481
 
504
- ```json
505
- {
506
- "filedist": {
507
- "sets": [
508
- {
509
- "package": "my-org-configs@^2.0.0",
510
- "output": { "path": "./data" },
511
- "selector": { "presets": ["prod"] }
512
- }
513
- ]
514
- }
515
- }
482
+ ```yaml
483
+ sets:
484
+ - package: my-org-configs@^2.0.0
485
+ output:
486
+ path: ./data
487
+ selector:
488
+ presets:
489
+ - prod
516
490
  ```
517
491
 
518
- The same filtering is applied during `check` and `purge` so they stay in sync with what `extract` originally wrote.
492
+ The same filtering is applied during `check` so they stay in sync with what `extract` originally wrote.
519
493
 
520
494
  ### Circular dependency detection
521
495
 
@@ -525,14 +499,15 @@ If a package chain references itself (directly or transitively), the command sto
525
499
 
526
500
  ```
527
501
  Usage:
528
- npx filedist [init|extract|check|list|purge] [options]
502
+ npx filedist [init|install|check|list|remove|update] [options]
529
503
 
530
504
  Commands:
531
505
  init Set up publishing configuration in a package
532
- extract Extract files from a published package into a local directory
533
- check Verify local files are in sync with the published package
506
+ install Extract files from a published package into a local directory (alias: extract)
507
+ check Verify local files are in sync with the lockfile (reads .filedist.lock)
534
508
  list List all files managed by filedist in an output directory
535
- purge Remove all managed files previously extracted by given packages
509
+ remove Remove a package set from config and delete its managed files (reads .filedist.yml)
510
+ update Bump packages to latest versions, update lockfile, and re-extract
536
511
 
537
512
  Global options:
538
513
  --help, -h Show help
@@ -541,20 +516,13 @@ Global options:
541
516
  Init options:
542
517
  --files <patterns> Comma-separated glob patterns of files to publish
543
518
  e.g. "docs/**,data/**,configs/*.json"
544
- --packages <specs> Comma-separated additional package specs to bundle as data sources.
545
- Each spec is "name" or "name@version", e.g.
546
- "shared-configs@^1.0.0,base-templates@2.x".
547
- Added to `dependencies` so consumers pull data from all of them.
548
519
  --output, -o <dir> Directory to scaffold into (default: current directory)
549
520
 
550
- Extract options:
551
- --packages <specs> Comma-separated package specs.
552
- When omitted, filedist searches for a configuration file
553
- (package.json "filedist" key, .filedistrc, etc.) and runs all
554
- entries defined there.
555
- Each spec is `name`, `name@version`, `npm:name@version`, or
556
- `git:github.com/org/repo.git@ref`, e.g.
557
- "my-pkg@^1.0.0,git:github.com/org/repo.git@main"
521
+ Install options:
522
+ [<package>] Package spec to add/install (positional; omit to use config file).
523
+ When provided, the entry is saved to .filedist.yml automatically.
524
+ Spec formats: name, name@version, npm:name@version, or
525
+ git:github.com/org/repo.git@ref
558
526
  --output, -o <dir> Output directory (default: current directory)
559
527
  --force Overwrite existing files or files owned by a different package
560
528
  --mutable Skip files that already exist; mark extracted files as mutable (check ignores
@@ -569,22 +537,29 @@ Extract options:
569
537
  --upgrade Reinstall the package even if already present
570
538
  --silent Print only the final result line, suppressing per-file output
571
539
  --verbose, -v Print detailed progress information for each step
572
- --no-save Skip loading and updating the local .filedistrc.yml config file.
573
- By default, when --packages is provided the run is saved to
574
- .filedistrc.yml so future `filedist extract` calls (without
575
- --packages) reuse the same config automatically.
540
+ --no-save Skip loading and updating the local .filedist.yml config file.
541
+ By default, when a positional package is provided the entry is saved to
542
+ .filedist.yml so future `filedist install` calls reuse the same config.
543
+ --frozen-lockfile Use .filedist.lock exclusively; fail if the lock file does not
544
+ exist. Does not update the lock file.
576
545
 
577
546
  Check options:
578
- --packages <specs> Same format as extract.
579
- When omitted, reads from a configuration file (see Pattern 3).
580
- --output, -o <dir> Output directory to check (default: current directory)
581
-
582
- Purge options:
583
- --packages <specs> Comma-separated package names whose managed files should be removed.
584
- When omitted, reads from a configuration file (see Pattern 3).
585
- --output, -o <dir> Output directory to purge from (default: current directory)
586
- --dry-run Simulate purge without removing any files
547
+ (no extra options reads exclusively from .filedist.lock)
548
+ --local-only Skip package install; verify only file checksums from .filedist markers
549
+ --verbose, -v Print detailed progress information
550
+
551
+ Update options:
552
+ --dry-run Preview changes without writing any files
553
+ --verbose, -v Print detailed progress information
554
+
555
+ Remove options:
556
+ <package> Package name to remove (version/ref is ignored during matching)
557
+ --output, -o <dir> Only remove entries whose output.path equals this value
558
+ --all Remove every set entry from the config
559
+ --dry-run Preview changes without modifying config or disk
560
+ --config <file> Path to a config file (overrides default .filedist.yml)
587
561
  --silent Suppress per-file output
562
+ --verbose, -v Print detailed progress information
588
563
 
589
564
  List options:
590
565
  --output, -o <dir> Output directory to inspect (default: current directory)
@@ -595,8 +570,9 @@ List options:
595
570
  `filedist` also exports a programmatic API:
596
571
 
597
572
  ```typescript
598
- import { actionExtract, actionCheck, actionList, actionPurge } from 'filedist';
573
+ import { actionInstall, actionCheck, actionList, actionRemove, actionUpdate } from 'filedist';
599
574
  import type { FiledistExtractEntry, ProgressEvent } from 'filedist';
575
+ import path from 'node:path';
600
576
 
601
577
  const entries: FiledistExtractEntry[] = [
602
578
  { package: 'my-shared-assets@^2.0.0', output: { path: './data' } },
@@ -604,35 +580,58 @@ const entries: FiledistExtractEntry[] = [
604
580
  const cwd = process.cwd();
605
581
 
606
582
  // extract files
607
- const result = await actionExtract({ entries, cwd });
583
+ const result = await actionInstall({ entries, cwd });
608
584
  console.log(result.added, result.modified, result.deleted);
609
585
 
610
586
  // dry-run: preview changes without writing files
611
- const dryResult = await actionExtract({ entries: entries.map(e => ({ ...e, output: { ...e.output, dryRun: true } })), cwd });
587
+ const dryResult = await actionInstall({ entries: entries.map(e => ({ ...e, output: { ...e.output, dryRun: true } })), cwd });
612
588
  console.log('Would add', dryResult.added, 'files');
613
589
 
614
590
  // track progress file-by-file
615
- await actionExtract({
591
+ await actionInstall({
616
592
  entries,
617
593
  cwd,
618
594
  onProgress: (event: ProgressEvent) => {
619
- if (event.type === 'file-added') console.log('A', event.file);
620
- if (event.type === 'file-modified') console.log('M', event.file);
621
- if (event.type === 'file-deleted') console.log('D', event.file);
595
+ if (event.type === 'file-added') console.log('+', event.file);
596
+ if (event.type === 'file-modified') console.log('~', event.file);
597
+ if (event.type === 'file-deleted') console.log('-', event.file);
622
598
  },
623
599
  });
624
600
 
625
- // check sync status
626
- const summary = await actionCheck({ entries, cwd });
627
- const hasDrift = summary.missing.length > 0 || summary.modified.length > 0 || summary.extra.length > 0;
601
+ // use frozen lockfile (reads .filedist.lock, fails if missing, does not update it)
602
+ const frozenResult = await actionInstall({ entries, cwd, frozenLockfile: true });
603
+ console.log(frozenResult.added, frozenResult.modified);
604
+
605
+ // check sync status (reads .filedist.lock; pass entries:[] to let lockfile drive)
606
+ const lockfilePath = '.filedist.lock';
607
+ const summary = await actionCheck({ entries: [], cwd, lockfilePath, frozenLockfile: true });
608
+ const hasDrift = summary.missing.length > 0 || summary.conflict.length > 0 || summary.extra.length > 0;
628
609
  if (hasDrift) {
629
610
  console.log('Missing:', summary.missing);
630
- console.log('Modified:', summary.modified);
611
+ console.log('Conflict:', summary.conflict);
631
612
  console.log('Extra:', summary.extra);
632
613
  }
633
614
 
634
- // remove all managed files (no network required)
635
- await actionPurge({ entries, config: null, cwd });
615
+ // remove a specific package set from config and delete its managed files
616
+ const removeResult = await actionRemove({
617
+ cwd,
618
+ packageSpec: 'my-shared-assets',
619
+ configFilePath: path.join(cwd, '.filedist.yml'),
620
+ lockfilePath: path.join(cwd, '.filedist.lock'),
621
+ });
622
+ console.log('Removed entries:', removeResult.removedEntries, 'deleted files:', removeResult.install.deleted);
623
+
624
+ // remove all sets from config (clears all managed files)
625
+ await actionRemove({
626
+ cwd,
627
+ all: true,
628
+ configFilePath: path.join(cwd, '.filedist.yml'),
629
+ lockfilePath: path.join(cwd, '.filedist.lock'),
630
+ });
631
+
632
+ // update all packages to latest versions
633
+ const updateResult = await actionUpdate({ cwd });
634
+ console.log('Updated:', updateResult.added, 'added,', updateResult.modified, 'modified,', updateResult.deleted, 'deleted');
636
635
 
637
636
  // list all files managed by filedist in an output directory
638
637
  const managed = await actionList({ entries, config: null, cwd });
@@ -653,11 +652,59 @@ type ProgressEvent =
653
652
 
654
653
  ### `postExtractCmd`
655
654
 
656
- Set `postExtractCmd` at the top level of your config to run a command after a successful non-dry-run `extract`.
655
+ Set `postExtractCmd` at the top level of your config to run a command after a successful non-dry-run `install`.
657
656
  Use an argv array such as `["node", "scripts/post-extract.js"]`; shell strings are rejected so common quoting mistakes fail clearly.
658
657
 
659
658
  See the root [README.md](../README.md) for the full documentation.
660
659
 
660
+ ## Lock file
661
+
662
+ Each `install` run writes a `.filedist.lock` file in the working directory that records:
663
+
664
+ - **`packages`** — the exact resolved version for every package in the dependency graph
665
+ - **`sets`** — the full entry definitions (package specs, selectors, output paths) that were used for this install
666
+ - **`managed_files`** — the list of all files managed after the install
667
+
668
+ ```json
669
+ {
670
+ "lockfileVersion": 1,
671
+ "packages": {
672
+ "my-shared-assets": { "source": "npm", "spec": "my-shared-assets", "resolvedVersion": "2.3.1" },
673
+ "git:github.com/org/repo.git@main": { "source": "git", "spec": "git:github.com/org/repo.git@main", "resolvedVersion": "abc123def456" }
674
+ },
675
+ "sets": [
676
+ { "package": "my-shared-assets@^2.0.0", "output": { "path": "./data" } }
677
+ ],
678
+ "managed_files": ["data/user1.json", "data/configs/app.config.json"]
679
+ }
680
+ ```
681
+
682
+ This file makes installs **reproducible** — even if a newer version of a package is published between runs, repeating `install` will fetch exactly the versions that were used the first time.
683
+
684
+ `check` reads **exclusively from `.filedist.lock`** (using the `sets` stored there) and does not read your `.filedist.yml` configuration. This ensures it always operates on the same entry definitions that were used during install, regardless of any local config changes.
685
+
686
+ When `--frozen-lockfile` is passed to `install`, it also validates that the current managed files match the list stored in the lockfile, failing if they differ.
687
+
688
+ ### `--frozen-lockfile`
689
+
690
+ Pass `--frozen-lockfile` to enforce that the lock file is used as-is without any resolution or update:
691
+
692
+ ```sh
693
+ # use exactly the versions from .filedist.lock, fail if it does not exist
694
+ npx filedist install --frozen-lockfile
695
+ ```
696
+
697
+ Behaviour:
698
+ - Reads `.filedist.lock` and pins every package to its recorded version.
699
+ - Fails immediately if `.filedist.lock` does not exist.
700
+ - Does **not** write or update `.filedist.lock`.
701
+
702
+ ### Commit `.filedist.lock`
703
+
704
+ Commit `.filedist.lock` alongside `.filedist.yml` so that everyone on the team and all CI jobs install identical file versions.
705
+
706
+ ---
707
+
661
708
  ## Managed file tracking
662
709
 
663
710
  Extracted files are set read-only (`444`) and tracked in a `.filedist` marker file in each output directory. On subsequent extractions:
@@ -677,7 +724,7 @@ Multiple packages can coexist in the same output directory; each owns its own fi
677
724
  | Folder / file | Purpose |
678
725
  |---|---|
679
726
  | `src/cli/` | CLI entry-points: argument parsing, help text, config loading, per-command handlers |
680
- | `src/package/` | Package-level orchestration: config resolution, fileset iteration, purge and init coordination |
727
+ | `src/package/` | Package-level orchestration: config resolution, fileset iteration, and init coordination |
681
728
  | `src/fileset/` | File-level extraction, diff, check, and sync logic |
682
729
  | `src/types.ts` | Shared TypeScript types |
683
730
  | `src/utils.ts` | Low-level utilities: package install, glob/hash helpers, package manager detection |