@vltpkg/cli-sdk 1.0.0-rc.8 → 1.0.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 (227) hide show
  1. package/dist/commands/access.d.ts +23 -0
  2. package/dist/commands/access.js +251 -0
  3. package/dist/{esm/commands → commands}/bugs.d.ts +0 -1
  4. package/dist/{esm/commands → commands}/bugs.js +0 -1
  5. package/dist/{esm/commands → commands}/build.d.ts +1 -1
  6. package/dist/{esm/commands → commands}/build.js +1 -1
  7. package/dist/{esm/commands → commands}/cache.d.ts +1 -1
  8. package/dist/{esm/commands → commands}/cache.js +1 -1
  9. package/dist/{esm/commands → commands}/ci.d.ts +1 -1
  10. package/dist/{esm/commands → commands}/ci.js +12 -3
  11. package/dist/{esm/commands → commands}/config.d.ts +0 -1
  12. package/dist/{esm/commands → commands}/config.js +6 -1
  13. package/dist/commands/create.d.ts +9 -0
  14. package/dist/commands/create.js +103 -0
  15. package/dist/commands/deprecate.d.ts +14 -0
  16. package/dist/commands/deprecate.js +142 -0
  17. package/dist/commands/dist-tag.d.ts +22 -0
  18. package/dist/commands/dist-tag.js +179 -0
  19. package/dist/{esm/commands → commands}/docs.d.ts +0 -1
  20. package/dist/{esm/commands → commands}/docs.js +0 -1
  21. package/dist/{esm/commands → commands}/exec-cache.d.ts +1 -1
  22. package/dist/{esm/commands → commands}/exec-cache.js +1 -1
  23. package/dist/{esm/commands/run-exec.d.ts → commands/exec-local.d.ts} +0 -1
  24. package/dist/{esm/commands → commands}/exec-local.js +23 -1
  25. package/dist/{esm/commands → commands}/exec.d.ts +1 -1
  26. package/dist/{esm/commands → commands}/exec.js +85 -10
  27. package/dist/{esm/commands → commands}/help.d.ts +0 -1
  28. package/dist/{esm/commands → commands}/help.js +5 -1
  29. package/dist/{esm/commands → commands}/init.d.ts +0 -1
  30. package/dist/{esm/commands → commands}/init.js +31 -10
  31. package/dist/{esm/commands → commands}/install/reporter.d.ts +0 -1
  32. package/dist/{esm/commands → commands}/install/reporter.js +0 -1
  33. package/dist/{esm/commands → commands}/install.d.ts +22 -3
  34. package/dist/commands/install.js +152 -0
  35. package/dist/{esm/commands → commands}/list.d.ts +5 -2
  36. package/dist/{esm/commands → commands}/list.js +9 -10
  37. package/dist/{esm/commands → commands}/login.d.ts +0 -1
  38. package/dist/commands/login.js +35 -0
  39. package/dist/{esm/commands → commands}/logout.d.ts +1 -1
  40. package/dist/commands/logout.js +27 -0
  41. package/dist/{esm/commands → commands}/pack.d.ts +1 -1
  42. package/dist/{esm/commands → commands}/pack.js +91 -32
  43. package/dist/commands/ping.d.ts +18 -0
  44. package/dist/commands/ping.js +117 -0
  45. package/dist/{esm/commands → commands}/pkg.d.ts +0 -1
  46. package/dist/{esm/commands → commands}/pkg.js +27 -1
  47. package/dist/commands/profile.d.ts +14 -0
  48. package/dist/commands/profile.js +106 -0
  49. package/dist/{esm/commands → commands}/publish.d.ts +2 -2
  50. package/dist/{esm/commands → commands}/publish.js +70 -16
  51. package/dist/{esm/commands → commands}/query.d.ts +5 -2
  52. package/dist/{esm/commands → commands}/query.js +54 -11
  53. package/dist/commands/registry.d.ts +26 -0
  54. package/dist/commands/registry.js +99 -0
  55. package/dist/commands/repo.d.ts +17 -0
  56. package/dist/commands/repo.js +157 -0
  57. package/dist/{esm/commands/exec-local.d.ts → commands/run-exec.d.ts} +1 -1
  58. package/dist/commands/run-exec.js +41 -0
  59. package/dist/{esm/commands → commands}/run.d.ts +0 -1
  60. package/dist/{esm/commands → commands}/run.js +27 -1
  61. package/dist/commands/setup.d.ts +25 -0
  62. package/dist/commands/setup.js +142 -0
  63. package/dist/commands/token.d.ts +32 -0
  64. package/dist/commands/token.js +193 -0
  65. package/dist/{esm/commands → commands}/uninstall.d.ts +1 -1
  66. package/dist/{esm/commands → commands}/uninstall.js +15 -1
  67. package/dist/commands/unpublish.d.ts +16 -0
  68. package/dist/commands/unpublish.js +203 -0
  69. package/dist/{esm/commands → commands}/update.d.ts +1 -1
  70. package/dist/{esm/commands → commands}/update.js +7 -1
  71. package/dist/{esm/commands → commands}/version.d.ts +0 -1
  72. package/dist/{esm/commands → commands}/version.js +27 -1
  73. package/dist/commands/view.d.ts +23 -0
  74. package/dist/commands/view.js +335 -0
  75. package/dist/{esm/commands → commands}/whoami.d.ts +1 -1
  76. package/dist/commands/whoami.js +33 -0
  77. package/dist/{esm/config → config}/definition.d.ts +72 -19
  78. package/dist/{esm/config → config}/definition.js +157 -50
  79. package/dist/{esm/config → config}/index.d.ts +0 -1
  80. package/dist/{esm/config → config}/index.js +43 -2
  81. package/dist/{esm/config → config}/merge.d.ts +0 -1
  82. package/dist/{esm/config → config}/merge.js +0 -1
  83. package/dist/{esm/config → config}/usage.d.ts +0 -1
  84. package/dist/{esm/config → config}/usage.js +0 -1
  85. package/dist/{esm/custom-help.d.ts → custom-help.d.ts} +0 -1
  86. package/dist/{esm/custom-help.js → custom-help.js} +95 -120
  87. package/dist/{esm/exec-command.d.ts → exec-command.d.ts} +0 -1
  88. package/dist/{esm/exec-command.js → exec-command.js} +14 -8
  89. package/dist/{esm/index.d.ts → index.d.ts} +0 -1
  90. package/dist/{esm/index.js → index.js} +5 -2
  91. package/dist/{esm/load-command.d.ts → load-command.d.ts} +6 -1
  92. package/dist/{esm/load-command.js → load-command.js} +0 -1
  93. package/dist/mermaid-image-view.d.ts +18 -0
  94. package/dist/mermaid-image-view.js +36 -0
  95. package/dist/{esm/output.d.ts → output.d.ts} +2 -2
  96. package/dist/{esm/output.js → output.js} +70 -3
  97. package/dist/{esm/pack-tarball.d.ts → pack-tarball.d.ts} +15 -1
  98. package/dist/{esm/pack-tarball.js → pack-tarball.js} +133 -91
  99. package/dist/{esm/parse-add-remove-args.d.ts → parse-add-remove-args.d.ts} +0 -1
  100. package/dist/{esm/parse-add-remove-args.js → parse-add-remove-args.js} +65 -12
  101. package/dist/{esm/print-err.d.ts → print-err.d.ts} +0 -1
  102. package/dist/{esm/print-err.js → print-err.js} +28 -4
  103. package/dist/query-diff-files.d.ts +17 -0
  104. package/dist/query-diff-files.js +63 -0
  105. package/dist/{esm/query-host-contexts.d.ts → query-host-contexts.d.ts} +0 -1
  106. package/dist/{esm/query-host-contexts.js → query-host-contexts.js} +8 -7
  107. package/dist/{esm/read-password.d.ts → read-password.d.ts} +0 -1
  108. package/dist/{esm/read-password.js → read-password.js} +0 -1
  109. package/dist/read-project-folders.d.ts +17 -0
  110. package/dist/read-project-folders.js +100 -0
  111. package/dist/registry-error-message.d.ts +2 -0
  112. package/dist/registry-error-message.js +29 -0
  113. package/dist/reload-config.d.ts +2 -0
  114. package/dist/reload-config.js +11 -0
  115. package/dist/render-mermaid.d.ts +22 -0
  116. package/dist/render-mermaid.js +68 -0
  117. package/dist/require-registry.d.ts +48 -0
  118. package/dist/require-registry.js +122 -0
  119. package/dist/select-registry.d.ts +23 -0
  120. package/dist/select-registry.js +40 -0
  121. package/dist/telemetry.d.ts +58 -0
  122. package/dist/telemetry.js +170 -0
  123. package/dist/verbose-log.d.ts +31 -0
  124. package/dist/verbose-log.js +62 -0
  125. package/dist/{esm/view.d.ts → view.d.ts} +0 -1
  126. package/dist/{esm/view.js → view.js} +1 -2
  127. package/package.json +75 -82
  128. package/dist/esm/commands/bugs.d.ts.map +0 -1
  129. package/dist/esm/commands/bugs.js.map +0 -1
  130. package/dist/esm/commands/build.d.ts.map +0 -1
  131. package/dist/esm/commands/build.js.map +0 -1
  132. package/dist/esm/commands/cache.d.ts.map +0 -1
  133. package/dist/esm/commands/cache.js.map +0 -1
  134. package/dist/esm/commands/ci.d.ts.map +0 -1
  135. package/dist/esm/commands/ci.js.map +0 -1
  136. package/dist/esm/commands/config.d.ts.map +0 -1
  137. package/dist/esm/commands/config.js.map +0 -1
  138. package/dist/esm/commands/docs.d.ts.map +0 -1
  139. package/dist/esm/commands/docs.js.map +0 -1
  140. package/dist/esm/commands/exec-cache.d.ts.map +0 -1
  141. package/dist/esm/commands/exec-cache.js.map +0 -1
  142. package/dist/esm/commands/exec-local.d.ts.map +0 -1
  143. package/dist/esm/commands/exec-local.js.map +0 -1
  144. package/dist/esm/commands/exec.d.ts.map +0 -1
  145. package/dist/esm/commands/exec.js.map +0 -1
  146. package/dist/esm/commands/help.d.ts.map +0 -1
  147. package/dist/esm/commands/help.js.map +0 -1
  148. package/dist/esm/commands/init.d.ts.map +0 -1
  149. package/dist/esm/commands/init.js.map +0 -1
  150. package/dist/esm/commands/install/reporter.d.ts.map +0 -1
  151. package/dist/esm/commands/install/reporter.js.map +0 -1
  152. package/dist/esm/commands/install.d.ts.map +0 -1
  153. package/dist/esm/commands/install.js +0 -46
  154. package/dist/esm/commands/install.js.map +0 -1
  155. package/dist/esm/commands/list.d.ts.map +0 -1
  156. package/dist/esm/commands/list.js.map +0 -1
  157. package/dist/esm/commands/login.d.ts.map +0 -1
  158. package/dist/esm/commands/login.js +0 -13
  159. package/dist/esm/commands/login.js.map +0 -1
  160. package/dist/esm/commands/logout.d.ts.map +0 -1
  161. package/dist/esm/commands/logout.js +0 -13
  162. package/dist/esm/commands/logout.js.map +0 -1
  163. package/dist/esm/commands/pack.d.ts.map +0 -1
  164. package/dist/esm/commands/pack.js.map +0 -1
  165. package/dist/esm/commands/pkg.d.ts.map +0 -1
  166. package/dist/esm/commands/pkg.js.map +0 -1
  167. package/dist/esm/commands/publish.d.ts.map +0 -1
  168. package/dist/esm/commands/publish.js.map +0 -1
  169. package/dist/esm/commands/query.d.ts.map +0 -1
  170. package/dist/esm/commands/query.js.map +0 -1
  171. package/dist/esm/commands/run-exec.d.ts.map +0 -1
  172. package/dist/esm/commands/run-exec.js +0 -14
  173. package/dist/esm/commands/run-exec.js.map +0 -1
  174. package/dist/esm/commands/run.d.ts.map +0 -1
  175. package/dist/esm/commands/run.js.map +0 -1
  176. package/dist/esm/commands/serve.d.ts +0 -14
  177. package/dist/esm/commands/serve.d.ts.map +0 -1
  178. package/dist/esm/commands/serve.js +0 -103
  179. package/dist/esm/commands/serve.js.map +0 -1
  180. package/dist/esm/commands/token.d.ts +0 -4
  181. package/dist/esm/commands/token.d.ts.map +0 -1
  182. package/dist/esm/commands/token.js +0 -30
  183. package/dist/esm/commands/token.js.map +0 -1
  184. package/dist/esm/commands/uninstall.d.ts.map +0 -1
  185. package/dist/esm/commands/uninstall.js.map +0 -1
  186. package/dist/esm/commands/update.d.ts.map +0 -1
  187. package/dist/esm/commands/update.js.map +0 -1
  188. package/dist/esm/commands/version.d.ts.map +0 -1
  189. package/dist/esm/commands/version.js.map +0 -1
  190. package/dist/esm/commands/whoami.d.ts.map +0 -1
  191. package/dist/esm/commands/whoami.js +0 -19
  192. package/dist/esm/commands/whoami.js.map +0 -1
  193. package/dist/esm/config/definition.d.ts.map +0 -1
  194. package/dist/esm/config/definition.js.map +0 -1
  195. package/dist/esm/config/index.d.ts.map +0 -1
  196. package/dist/esm/config/index.js.map +0 -1
  197. package/dist/esm/config/merge.d.ts.map +0 -1
  198. package/dist/esm/config/merge.js.map +0 -1
  199. package/dist/esm/config/usage.d.ts.map +0 -1
  200. package/dist/esm/config/usage.js.map +0 -1
  201. package/dist/esm/custom-help.d.ts.map +0 -1
  202. package/dist/esm/custom-help.js.map +0 -1
  203. package/dist/esm/exec-command.d.ts.map +0 -1
  204. package/dist/esm/exec-command.js.map +0 -1
  205. package/dist/esm/index.d.ts.map +0 -1
  206. package/dist/esm/index.js.map +0 -1
  207. package/dist/esm/load-command.d.ts.map +0 -1
  208. package/dist/esm/load-command.js.map +0 -1
  209. package/dist/esm/output.d.ts.map +0 -1
  210. package/dist/esm/output.js.map +0 -1
  211. package/dist/esm/pack-tarball.d.ts.map +0 -1
  212. package/dist/esm/pack-tarball.js.map +0 -1
  213. package/dist/esm/package.json +0 -3
  214. package/dist/esm/parse-add-remove-args.d.ts.map +0 -1
  215. package/dist/esm/parse-add-remove-args.js.map +0 -1
  216. package/dist/esm/print-err.d.ts.map +0 -1
  217. package/dist/esm/print-err.js.map +0 -1
  218. package/dist/esm/query-host-contexts.d.ts.map +0 -1
  219. package/dist/esm/query-host-contexts.js.map +0 -1
  220. package/dist/esm/read-password.d.ts.map +0 -1
  221. package/dist/esm/read-password.js.map +0 -1
  222. package/dist/esm/start-gui.d.ts +0 -10
  223. package/dist/esm/start-gui.d.ts.map +0 -1
  224. package/dist/esm/start-gui.js +0 -60
  225. package/dist/esm/start-gui.js.map +0 -1
  226. package/dist/esm/view.d.ts.map +0 -1
  227. package/dist/esm/view.js.map +0 -1
@@ -10,7 +10,22 @@ export type PackTarballResult = {
10
10
  files: string[];
11
11
  integrity?: string;
12
12
  shasum?: string;
13
+ /** The manifest used for packing (may differ from input when publishConfig.directory is set). */
14
+ resolvedManifest: NormalizedManifest;
13
15
  };
16
+ /**
17
+ * Build the tar filter function for packing.
18
+ *
19
+ * Follows npm's precedence rules:
20
+ * 1. `files` field in package.json → allowlist (ignore files are not read)
21
+ * 2. `.npmignore` → denylist (`.gitignore` is NOT read)
22
+ * 3. `.gitignore` → fallback denylist when no `.npmignore` exists
23
+ *
24
+ * Regardless of mode, always-excluded files (lockfiles, .git, node_modules,
25
+ * .npmrc, vlt.json, etc.) are excluded and always-included files (package.json,
26
+ * README, LICENSE, etc.) are included.
27
+ */
28
+ export declare const buildPackFilter: (manifest: NormalizedManifest, packDir: string) => ((path: string) => boolean);
14
29
  /**
15
30
  * Create a tarball from a package directory
16
31
  * @param {NormalizedManifest} manifest - The manifest of the package to pack
@@ -19,4 +34,3 @@ export type PackTarballResult = {
19
34
  * @returns {Promise<PackTarballResult>} The manifest, filename, and tarball data (unless dry run)
20
35
  */
21
36
  export declare const packTarball: (manifest: NormalizedManifest, dir: string, config: LoadedConfig) => Promise<PackTarballResult>;
22
- //# sourceMappingURL=pack-tarball.d.ts.map
@@ -3,10 +3,11 @@ import { minimatch } from 'minimatch';
3
3
  import { error } from '@vltpkg/error-cause';
4
4
  import * as ssri from 'ssri';
5
5
  import assert from 'node:assert';
6
- import { existsSync, statSync } from 'node:fs';
6
+ import { existsSync, readFileSync, statSync } from 'node:fs';
7
7
  import { Spec } from '@vltpkg/spec';
8
8
  import { join } from 'node:path';
9
9
  import { parse, stringify } from 'polite-json';
10
+ import ignore from 'ignore';
10
11
  /**
11
12
  * Replace workspace: and catalog: specs with actual versions
12
13
  * @param {NormalizedManifest} manifest_ - The manifest to process
@@ -82,6 +83,121 @@ const replaceWorkspaceAndCatalogSpecs = (manifest_, config) => {
82
83
  }
83
84
  return manifest;
84
85
  };
86
+ const alwaysExcludePatterns = [
87
+ /^\.?\/?\.git(\/|$)/,
88
+ /^\.?\/?node_modules(\/|$)/,
89
+ /^\.?\/?\.nyc_output(\/|$)/,
90
+ /^\.?\/?coverage(\/|$)/,
91
+ /^\.?\/?\.vscode(\/|$)/,
92
+ /^\.?\/?\.idea(\/|$)/,
93
+ /^\.?\/?\.DS_Store$/,
94
+ /^\.?\/?\.npmrc$/,
95
+ /^\.?\/?\.gitignore$/,
96
+ /^\.?\/?\.npmignore$/,
97
+ /^\.?\/?\.editorconfig$/,
98
+ /^\.?\/?package-lock\.json$/,
99
+ /^\.?\/?yarn\.lock$/,
100
+ /^\.?\/?pnpm-lock\.yaml$/,
101
+ /^\.?\/?bun\.lockb$/,
102
+ /^\.?\/?bun\.lock$/,
103
+ /^\.?\/?vlt-lock\.json$/,
104
+ /^\.?\/?vlt\.json$/,
105
+ /~$/,
106
+ /\.swp$/,
107
+ /\.tgz$/,
108
+ ];
109
+ const alwaysIncludePatterns = [
110
+ /^README(\..*)?$/i,
111
+ /^CHANGELOG(\..*)?$/i,
112
+ /^HISTORY(\..*)?$/i,
113
+ /^LICENSE(\..*)?$/i,
114
+ /^LICENCE(\..*)?$/i,
115
+ ];
116
+ /**
117
+ * Read an ignore file (.npmignore or .gitignore) and return its contents,
118
+ * or undefined if the file does not exist.
119
+ */
120
+ const readIgnoreFile = (dir, name) => {
121
+ const filePath = join(dir, name);
122
+ if (!existsSync(filePath))
123
+ return undefined;
124
+ return readFileSync(filePath, 'utf8');
125
+ };
126
+ /**
127
+ * Build the tar filter function for packing.
128
+ *
129
+ * Follows npm's precedence rules:
130
+ * 1. `files` field in package.json → allowlist (ignore files are not read)
131
+ * 2. `.npmignore` → denylist (`.gitignore` is NOT read)
132
+ * 3. `.gitignore` → fallback denylist when no `.npmignore` exists
133
+ *
134
+ * Regardless of mode, always-excluded files (lockfiles, .git, node_modules,
135
+ * .npmrc, vlt.json, etc.) are excluded and always-included files (package.json,
136
+ * README, LICENSE, etc.) are included.
137
+ */
138
+ export const buildPackFilter = (manifest, packDir) => {
139
+ const manifestWithFiles = manifest;
140
+ const hasFilesField = Array.isArray(manifestWithFiles.files) &&
141
+ manifestWithFiles.files.length > 0;
142
+ const hasEmptyFilesField = Array.isArray(manifestWithFiles.files) &&
143
+ manifestWithFiles.files.length === 0;
144
+ // Build ignore matcher from .npmignore or .gitignore (only when no files field)
145
+ let ig;
146
+ if (!hasFilesField && !hasEmptyFilesField) {
147
+ const npmignoreContent = readIgnoreFile(packDir, '.npmignore');
148
+ if (npmignoreContent !== undefined) {
149
+ ig = ignore().add(npmignoreContent);
150
+ }
151
+ else {
152
+ const gitignoreContent = readIgnoreFile(packDir, '.gitignore');
153
+ if (gitignoreContent !== undefined) {
154
+ ig = ignore().add(gitignoreContent);
155
+ }
156
+ }
157
+ }
158
+ return (path) => {
159
+ const normalizedPath = path.replace(/^\.\//, '');
160
+ if (path === '.' || normalizedPath === '') {
161
+ return true;
162
+ }
163
+ if (alwaysExcludePatterns.some(pattern => pattern.test(normalizedPath))) {
164
+ return false;
165
+ }
166
+ if (alwaysIncludePatterns.some(pattern => pattern.test(normalizedPath))) {
167
+ return true;
168
+ }
169
+ if (normalizedPath === 'package.json') {
170
+ return true;
171
+ }
172
+ // files field: allowlist mode
173
+ if (hasEmptyFilesField) {
174
+ return false;
175
+ }
176
+ if (hasFilesField && manifestWithFiles.files) {
177
+ return manifestWithFiles.files.some((pattern) => {
178
+ if (pattern.endsWith('/')) {
179
+ const dirName = pattern.slice(0, -1);
180
+ const globPattern = pattern.replace(/\/$/, '/**');
181
+ const matchesDir = normalizedPath === dirName;
182
+ const matchesContents = minimatch(normalizedPath, globPattern, { dot: true });
183
+ return matchesDir || matchesContents;
184
+ }
185
+ const directMatch = minimatch(normalizedPath, pattern, {
186
+ dot: true,
187
+ });
188
+ const isParentDir = pattern.includes('/') &&
189
+ pattern.startsWith(normalizedPath + '/');
190
+ const isChildOfPattern = minimatch(normalizedPath, pattern + '/**', { dot: true });
191
+ return directMatch || isParentDir || isChildOfPattern;
192
+ });
193
+ }
194
+ // Ignore-file mode: apply .npmignore or .gitignore deny patterns
195
+ if (ig?.ignores(normalizedPath)) {
196
+ return false;
197
+ }
198
+ return true;
199
+ };
200
+ };
85
201
  /**
86
202
  * Create a tarball from a package directory
87
203
  * @param {NormalizedManifest} manifest - The manifest of the package to pack
@@ -91,21 +207,25 @@ const replaceWorkspaceAndCatalogSpecs = (manifest_, config) => {
91
207
  */
92
208
  export const packTarball = async (manifest, dir, config) => {
93
209
  let packDir = dir;
94
- // Check if publishDirectory is configured
95
- const publishDirectory = config.get('publish-directory');
210
+ // Check if publishDirectory is configured via CLI flag or package.json publishConfig.directory
211
+ const cliPublishDir = config.get('publish-directory');
212
+ const manifestPublishDir = manifest.publishConfig?.directory;
213
+ const publishDirectory = cliPublishDir ?? manifestPublishDir;
96
214
  if (publishDirectory) {
215
+ // CLI flag paths are used as-is; publishConfig.directory is relative to the package dir
216
+ const resolvedPublishDir = cliPublishDir ? publishDirectory : join(dir, publishDirectory);
97
217
  // Validate that the publish directory exists and is a directory
98
- assert(existsSync(publishDirectory), error(`Publish directory does not exist: ${publishDirectory}`, {
99
- found: publishDirectory,
218
+ assert(existsSync(resolvedPublishDir), error(`Publish directory does not exist: ${resolvedPublishDir}`, {
219
+ found: resolvedPublishDir,
100
220
  }));
101
- assert(statSync(publishDirectory).isDirectory(), error(`Publish directory is not a directory: ${publishDirectory}`, {
102
- found: publishDirectory,
221
+ assert(statSync(resolvedPublishDir).isDirectory(), error(`Publish directory is not a directory: ${resolvedPublishDir}`, {
222
+ found: resolvedPublishDir,
103
223
  wanted: 'directory',
104
224
  }));
105
- if (existsSync(join(publishDirectory, 'package.json'))) {
106
- manifest = config.options.packageJson.read(publishDirectory);
225
+ if (existsSync(join(resolvedPublishDir, 'package.json'))) {
226
+ manifest = config.options.packageJson.read(resolvedPublishDir);
107
227
  }
108
- packDir = publishDirectory;
228
+ packDir = resolvedPublishDir;
109
229
  }
110
230
  assert(manifest.name && manifest.version, error('Package must have a name and version'));
111
231
  const processedManifest = replaceWorkspaceAndCatalogSpecs(manifest, config);
@@ -113,91 +233,13 @@ export const packTarball = async (manifest, dir, config) => {
113
233
  const tarballName = `${manifest.name}-${manifest.version}.tgz`;
114
234
  try {
115
235
  config.options.packageJson.write(packDir, processedManifest);
236
+ const packFilter = buildPackFilter(manifest, packDir);
116
237
  const tarballData = await tarCreate({
117
238
  cwd: packDir,
118
239
  gzip: true,
119
240
  portable: true,
120
241
  prefix: 'package/',
121
- filter: (path) => {
122
- // Normalize path - remove leading './'
123
- const normalizedPath = path.replace(/^\.\//, '');
124
- // Always include root directory
125
- if (path === '.' || normalizedPath === '') {
126
- return true;
127
- }
128
- // Always exclude certain files/directories
129
- const alwaysExcludePatterns = [
130
- /^\.?\/?\.git(\/|$)/,
131
- /^\.?\/?node_modules(\/|$)/,
132
- /^\.?\/?\.nyc_output(\/|$)/,
133
- /^\.?\/?coverage(\/|$)/,
134
- /^\.?\/?\.DS_Store$/,
135
- /^\.?\/?\.npmrc$/,
136
- /^\.?\/?package-lock\.json$/,
137
- /^\.?\/?yarn\.lock$/,
138
- /^\.?\/?pnpm-lock\.yaml$/,
139
- /^\.?\/?bun\.lockb$/,
140
- /^\.?\/?bun\.lock$/,
141
- /^\.?\/?vlt-lock\.json$/,
142
- /~$/,
143
- /\.swp$/,
144
- ];
145
- if (alwaysExcludePatterns.some(pattern => pattern.test(normalizedPath))) {
146
- return false;
147
- }
148
- // Always include certain files
149
- const alwaysIncludePatterns = [
150
- /^README(\..*)?$/i,
151
- /^CHANGELOG(\..*)?$/i,
152
- /^HISTORY(\..*)?$/i,
153
- /^LICENSE(\..*)?$/i,
154
- /^LICENCE(\..*)?$/i,
155
- ];
156
- if (alwaysIncludePatterns.some(pattern => pattern.test(normalizedPath))) {
157
- return true;
158
- }
159
- // Always include package.json
160
- if (normalizedPath === 'package.json') {
161
- return true;
162
- }
163
- // If files field is specified in package.json, use it for inclusion
164
- const manifestWithFiles = manifest;
165
- if (manifestWithFiles.files &&
166
- Array.isArray(manifestWithFiles.files)) {
167
- // Empty files array means exclude everything except always-included files
168
- if (manifestWithFiles.files.length === 0) {
169
- return false;
170
- }
171
- return manifestWithFiles.files.some((pattern) => {
172
- if (pattern.endsWith('/')) {
173
- const dirName = pattern.slice(0, -1);
174
- const globPattern = pattern.replace(/\/$/, '/**');
175
- const matchesDir = normalizedPath === dirName;
176
- const matchesContents = minimatch(normalizedPath, globPattern, {
177
- dot: true,
178
- });
179
- return matchesDir || matchesContents;
180
- }
181
- // File pattern: check direct match and if this path is a directory that could contain the pattern
182
- const directMatch = minimatch(normalizedPath, pattern, {
183
- dot: true,
184
- });
185
- // Check if this path is a directory that could contain the pattern
186
- const isParentDir = pattern.includes('/') &&
187
- pattern.startsWith(normalizedPath + '/');
188
- return directMatch || isParentDir;
189
- });
190
- }
191
- // Default behavior when no files field - exclude common development files
192
- const defaultExcludePatterns = [
193
- /^\.?\/?\.vscode(\/|$)/,
194
- /^\.?\/?\.idea(\/|$)/,
195
- /^\.?\/?\.gitignore$/,
196
- /^\.?\/?\.npmignore$/,
197
- /^\.?\/?\.editorconfig$/,
198
- ];
199
- return !defaultExcludePatterns.some(pattern => pattern.test(normalizedPath));
200
- },
242
+ filter: packFilter,
201
243
  }, ['.']).concat();
202
244
  let unpackedSize = 0;
203
245
  const files = [];
@@ -239,6 +281,7 @@ export const packTarball = async (manifest, dir, config) => {
239
281
  files,
240
282
  integrity,
241
283
  shasum,
284
+ resolvedManifest: processedManifest,
242
285
  };
243
286
  }
244
287
  finally {
@@ -246,4 +289,3 @@ export const packTarball = async (manifest, dir, config) => {
246
289
  config.options.packageJson.write(packDir, manifest);
247
290
  }
248
291
  };
249
- //# sourceMappingURL=pack-tarball.js.map
@@ -26,4 +26,3 @@ export declare const parseAddArgs: (config: LoadedConfig, scurry: PathScurry, mo
26
26
  * Parses the positional arguments into {@link RemoveImportersDependenciesMap}.
27
27
  */
28
28
  export declare const parseRemoveArgs: (config: LoadedConfig, scurry: PathScurry, monorepo?: Monorepo) => ParsedRemoveArgs;
29
- //# sourceMappingURL=parse-add-remove-args.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import { asDependency } from '@vltpkg/graph';
2
- import { joinDepIDTuple } from '@vltpkg/dep-id';
2
+ import { joinDepIDTuple, splitDepID } from '@vltpkg/dep-id';
3
3
  import { Spec } from '@vltpkg/spec';
4
+ import { isAbsolute, relative, resolve } from 'node:path';
4
5
  const rootDepID = joinDepIDTuple(['file', '.']);
5
6
  /**
6
7
  * Compute a DepID for the current working directory relative to the project
@@ -45,6 +46,36 @@ class AddImportersDependenciesMapImpl extends Map {
45
46
  class RemoveImportersDependenciesMapImpl extends Map {
46
47
  modifiedDependencies = false;
47
48
  }
49
+ /**
50
+ * Rebase a file: spec's relative path from process.cwd() to the
51
+ * importer's location. CLI positional args are relative to cwd,
52
+ * but the graph resolver resolves file: paths relative to the
53
+ * importer node's location. When these differ (e.g. `-w` flag),
54
+ * the path must be rebased.
55
+ *
56
+ * Also detects when the target path is a workspace and converts
57
+ * the spec to `workspace:*`.
58
+ */
59
+ const rebaseFileSpec = (spec, importerPath, scurryCwd, specOptions, monorepo) => {
60
+ if (spec.type !== 'file' || !spec.file || isAbsolute(spec.file)) {
61
+ return spec;
62
+ }
63
+ const targetAbs = resolve(process.cwd(), spec.file);
64
+ if (monorepo) {
65
+ for (const ws of monorepo.values()) {
66
+ if (ws.fullpath === targetAbs) {
67
+ return Spec.parse(ws.name, 'workspace:*', specOptions);
68
+ }
69
+ }
70
+ }
71
+ const importerAbs = resolve(scurryCwd, importerPath);
72
+ const rebasedPath = relative(importerAbs, targetAbs)
73
+ .split('\\')
74
+ .join('/');
75
+ if (rebasedPath === spec.file)
76
+ return spec;
77
+ return Spec.parseArgs(rebasedPath, specOptions);
78
+ };
48
79
  /**
49
80
  * Parses the positional arguments into {@link AddImportersDependenciesMap}.
50
81
  */
@@ -53,7 +84,6 @@ export const parseAddArgs = (config, scurry, monorepo) => {
53
84
  const items = config.positionals;
54
85
  const type = getType(config.values);
55
86
  const importers = getWorkspaceImporters(config.values, monorepo);
56
- const newDependencies = new Map();
57
87
  const specOptions = config.options;
58
88
  // nameless spec definitions will need to use their full
59
89
  // stringified spec result instead of their name in order
@@ -61,21 +91,45 @@ export const parseAddArgs = (config, scurry, monorepo) => {
61
91
  const getName = (s) => s.name === '(unknown)' ? s.spec : s.name;
62
92
  // parses each positional argument into a Spec and
63
93
  // adds it to the new dependencies Map
94
+ const parsedItems = [];
95
+ let hasFileSpecs = false;
64
96
  for (const item of items) {
65
97
  const spec = Spec.parseArgs(item, specOptions);
66
- newDependencies.set(getName(spec), asDependency({ spec, type }));
98
+ parsedItems.push({ spec, type });
99
+ if (spec.type === 'file')
100
+ hasFileSpecs = true;
67
101
  add.modifiedDependencies = true;
68
102
  }
69
103
  // assigns the new dependencies to each selected workspace importer
70
- for (const importer of importers) {
71
- add.set(importer, newDependencies);
104
+ // file: specs need per-importer rebasing since CLI paths are relative
105
+ // to process.cwd() but get resolved relative to the importer's location
106
+ if (hasFileSpecs && importers.size) {
107
+ const scurryCwd = scurry.cwd.fullpath();
108
+ for (const importer of importers) {
109
+ const [, importerPath] = splitDepID(importer);
110
+ const importerDeps = new Map();
111
+ for (const { spec, type: depType } of parsedItems) {
112
+ const rebased = rebaseFileSpec(spec, importerPath, scurryCwd, specOptions, monorepo);
113
+ importerDeps.set(getName(rebased), asDependency({ spec: rebased, type: depType }));
114
+ }
115
+ add.set(importer, importerDeps);
116
+ }
72
117
  }
73
- // if no workspaces were selected, default to the cwd importer which
74
- // can be either the root or a nested folder in case the user is installing
75
- // from a subfolder that is also a file: type dependency
76
- if (!importers.size) {
77
- const cwdDepID = getCwdDepID(scurry);
78
- add.set(cwdDepID, newDependencies);
118
+ else {
119
+ const newDependencies = new Map();
120
+ for (const { spec, type: depType } of parsedItems) {
121
+ newDependencies.set(getName(spec), asDependency({ spec, type: depType }));
122
+ }
123
+ for (const importer of importers) {
124
+ add.set(importer, newDependencies);
125
+ }
126
+ // if no workspaces were selected, default to the cwd importer which
127
+ // can be either the root or a nested folder in case the user is installing
128
+ // from a subfolder that is also a file: type dependency
129
+ if (!importers.size) {
130
+ const cwdDepID = getCwdDepID(scurry);
131
+ add.set(cwdDepID, newDependencies);
132
+ }
79
133
  }
80
134
  return {
81
135
  add,
@@ -101,4 +155,3 @@ export const parseRemoveArgs = (config, scurry, monorepo) => {
101
155
  remove,
102
156
  };
103
157
  };
104
- //# sourceMappingURL=parse-add-remove-args.js.map
@@ -11,4 +11,3 @@ export type ErrorFormatOptions = InspectOptions & {
11
11
  export type Formatter = (arg: unknown, options?: ErrorFormatOptions) => string;
12
12
  export declare const indent: (lines: string, num?: number) => string;
13
13
  export declare const printErr: (e: unknown, usage: CommandUsage, stderr: (...a: string[]) => void, baseOpts?: ErrorFormatOptions) => void;
14
- //# sourceMappingURL=print-err.d.ts.map
@@ -2,8 +2,8 @@ import { splitDepID } from '@vltpkg/dep-id';
2
2
  import { parseError } from '@vltpkg/output/error';
3
3
  import { isErrorWithCause, isObject } from '@vltpkg/types';
4
4
  import { XDG } from '@vltpkg/xdg';
5
- import { isGraphRunError } from 'graph-run';
6
- import { mkdirSync, writeFileSync } from 'node:fs';
5
+ import { isGraphRunError } from '@vltpkg/graph-run';
6
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
7
7
  import { join } from 'node:path';
8
8
  import { formatWithOptions } from 'node:util';
9
9
  export const formatOptions = {
@@ -13,6 +13,15 @@ export const formatOptions = {
13
13
  };
14
14
  const isNonEmptyString = (v) => !!v && typeof v === 'string';
15
15
  const formatURL = (v, format) => v instanceof URL ? v.toString() : /* c8 ignore next */ format(v);
16
+ // True when `v` overrides the default `Object.prototype.toString`, i.e.
17
+ // stringifying it yields something meaningful (like a `Spec` → `next@*`)
18
+ // rather than `[object Object]`.
19
+ const hasCustomToString = (v) => isObject(v) && v.toString !== Object.prototype.toString;
20
+ // Render a value that has a meaningful custom `toString()` (such as a
21
+ // `Spec`, e.g. `next@*`) as a concise string rather than dumping its
22
+ // entire internal structure via util.inspect. Falls back to `format`
23
+ // for plain values/objects.
24
+ const formatToString = (v, format) => hasCustomToString(v) ? v.toString() : format(v);
16
25
  const formatArray = (v, format, joiner = ', ') => Array.isArray(v) ? v.join(joiner) : /* c8 ignore next */ format(v);
17
26
  export const indent = (lines, num = 2) => lines
18
27
  .split('\n')
@@ -33,6 +42,14 @@ const writeErrorLog = (e, format) => {
33
42
  return null;
34
43
  }
35
44
  };
45
+ const readErrorLog = (file) => {
46
+ try {
47
+ return readFileSync(file, 'utf8');
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ };
36
53
  export const printErr = (e, usage, stderr, baseOpts) => {
37
54
  const format = (arg, opts) => {
38
55
  const { maxLines = 200, ...rest } = {
@@ -62,6 +79,14 @@ export const printErr = (e, usage, stderr, baseOpts) => {
62
79
  if (fileWritten) {
63
80
  stderr('');
64
81
  stderr(`Full details written to: ${fileWritten}`);
82
+ if (process.env.CI) {
83
+ const fullErrorLog = readErrorLog(fileWritten);
84
+ if (fullErrorLog) {
85
+ stderr('');
86
+ stderr('Full details:');
87
+ stderr(fullErrorLog);
88
+ }
89
+ }
65
90
  }
66
91
  if (!knownError || knownError.bug) {
67
92
  stderr('');
@@ -131,7 +156,7 @@ const printCode = (err, usage, stderr, format) => {
131
156
  stderr(indent(`While fetching: ${formatURL(url, format)}`));
132
157
  }
133
158
  if (spec) {
134
- stderr(indent(`To satisfy: ${format(spec)}`));
159
+ stderr(indent(`To satisfy: ${formatToString(spec, format)}`));
135
160
  }
136
161
  if (from) {
137
162
  stderr(indent(`From: ${format(from)}`));
@@ -175,4 +200,3 @@ const printCode = (err, usage, stderr, format) => {
175
200
  }
176
201
  }
177
202
  };
178
- //# sourceMappingURL=print-err.js.map
@@ -0,0 +1,17 @@
1
+ import type { DiffFilesProvider } from '@vltpkg/query';
2
+ /**
3
+ * Validates that a commitish string is safe to use
4
+ * in a git command.
5
+ */
6
+ export declare const validateCommitish: (commitish: string) => string;
7
+ /**
8
+ * Creates a {@link DiffFilesProvider} that uses
9
+ * `git diff --name-only` to determine changed files.
10
+ * @param {string} projectRoot - The absolute path to the
11
+ * project root directory where git commands will be
12
+ * executed.
13
+ * @returns {DiffFilesProvider} A function that takes a
14
+ * commitish and returns a Set of changed file paths
15
+ * relative to the project root.
16
+ */
17
+ export declare const createDiffFilesProvider: (projectRoot: string) => DiffFilesProvider;
@@ -0,0 +1,63 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { error } from '@vltpkg/error-cause';
3
+ /**
4
+ * Pattern to validate commitish arguments.
5
+ * Allows branch names, tags, SHAs, HEAD~N, HEAD^N, etc.
6
+ * Rejects shell metacharacters to prevent command injection.
7
+ */
8
+ const VALID_COMMITISH = /^[a-zA-Z0-9_./@^~:#{}-]+$/;
9
+ /**
10
+ * Validates that a commitish string is safe to use
11
+ * in a git command.
12
+ */
13
+ export const validateCommitish = (commitish) => {
14
+ if (!commitish) {
15
+ throw error('Missing commitish argument for :diff() selector');
16
+ }
17
+ if (!VALID_COMMITISH.test(commitish)) {
18
+ throw error('Invalid commitish argument for :diff() selector', {
19
+ found: commitish,
20
+ });
21
+ }
22
+ return commitish;
23
+ };
24
+ /**
25
+ * Creates a {@link DiffFilesProvider} that uses
26
+ * `git diff --name-only` to determine changed files.
27
+ * @param {string} projectRoot - The absolute path to the
28
+ * project root directory where git commands will be
29
+ * executed.
30
+ * @returns {DiffFilesProvider} A function that takes a
31
+ * commitish and returns a Set of changed file paths
32
+ * relative to the project root.
33
+ */
34
+ export const createDiffFilesProvider = (projectRoot) => {
35
+ // Cache results per commitish to avoid repeated git calls
36
+ const cache = new Map();
37
+ return (commitish) => {
38
+ const cached = cache.get(commitish);
39
+ if (cached)
40
+ return cached;
41
+ const safeCommitish = validateCommitish(commitish);
42
+ try {
43
+ const stdout = execSync(`git diff --name-only ${safeCommitish}`, {
44
+ cwd: projectRoot,
45
+ encoding: 'utf8',
46
+ stdio: ['pipe', 'pipe', 'pipe'],
47
+ timeout: 30_000,
48
+ });
49
+ const files = new Set();
50
+ for (const line of stdout.split('\n')) {
51
+ const trimmed = line.trim();
52
+ if (trimmed) {
53
+ files.add(trimmed);
54
+ }
55
+ }
56
+ cache.set(commitish, files);
57
+ return files;
58
+ }
59
+ catch (err) {
60
+ throw error(`Failed to run git diff for commitish: ${safeCommitish}`, { cause: err });
61
+ }
62
+ };
63
+ };
@@ -13,4 +13,3 @@ export type HostContextsMapResult = {
13
13
  * pseudo selector to dynamically load graphs from different sources.
14
14
  */
15
15
  export declare const createHostContextsMap: (conf: LoadedConfig) => Promise<Map<string, () => Promise<HostContextsMapResult>>>;
16
- //# sourceMappingURL=query-host-contexts.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import { homedir } from 'node:os';
2
2
  import { parse, posix } from 'node:path';
3
- import { getProjectData, readProjectFolders, reloadConfig, } from '@vltpkg/server';
3
+ import { readProjectFolders } from "./read-project-folders.js";
4
+ import { reloadConfig } from "./reload-config.js";
4
5
  import { actual, createVirtualRoot } from '@vltpkg/graph';
5
6
  import { SecurityArchive } from '@vltpkg/security-archive';
6
7
  import { error } from '@vltpkg/error-cause';
@@ -13,6 +14,11 @@ try {
13
14
  }
14
15
  catch { }
15
16
  const home = foundHome ?? posix.dirname(posix.format(parse(process.cwd())));
17
+ const isVltInstalled = (folder) => !!folder.resolve('node_modules/.vlt').lstatSync()?.isDirectory() ||
18
+ !!folder
19
+ .resolve('node_modules/.vlt-lock.json')
20
+ .lstatSync()
21
+ ?.isFile();
16
22
  /**
17
23
  * Generates possible project keys for a given folder.
18
24
  */
@@ -89,12 +95,8 @@ export const createHostContextsMap = async (conf) => {
89
95
  for (const folder of projectFolders) {
90
96
  try {
91
97
  const config = await reloadConfig(folder.fullpath());
92
- const projectInfo = getProjectData({
93
- packageJson: config.options.packageJson,
94
- scurry: config.options.scurry,
95
- }, folder);
96
98
  // only include projects that are vlt-installed
97
- if (!projectInfo.vltInstalled) {
99
+ if (!isVltInstalled(folder)) {
98
100
  continue;
99
101
  }
100
102
  // load each individual graph
@@ -132,4 +134,3 @@ export const createHostContextsMap = async (conf) => {
132
134
  });
133
135
  return hostContexts;
134
136
  };
135
- //# sourceMappingURL=query-host-contexts.js.map
@@ -5,4 +5,3 @@ export type Streams = {
5
5
  stdout: NodeJS.WritableStream;
6
6
  };
7
7
  export declare const readPassword: (prompt: string, { stdin, stdout }?: Streams) => Promise<string>;
8
- //# sourceMappingURL=read-password.d.ts.map
@@ -30,4 +30,3 @@ export const readPassword = async (prompt, { stdin, stdout } = process) => {
30
30
  });
31
31
  return input;
32
32
  };
33
- //# sourceMappingURL=read-password.js.map
@@ -0,0 +1,17 @@
1
+ import type { PathBase, PathScurry } from 'path-scurry';
2
+ type ProjectFolderOptions = {
3
+ path?: string;
4
+ scurry: PathScurry;
5
+ userDefinedProjectPaths: string[];
6
+ };
7
+ /**
8
+ * Retrieves folders from a given directory, if that directory is
9
+ * recognized to be the current cli project root folder then we
10
+ * proceed to read its siblings.
11
+ *
12
+ * Traverses nested directory recursively until project folders can
13
+ * be find, always stopping at the first level where a package.json
14
+ * is present.
15
+ */
16
+ export declare const readProjectFolders: ({ path, scurry, userDefinedProjectPaths, }: ProjectFolderOptions, maxDepth?: number) => Promise<PathBase[]>;
17
+ export {};