@vltpkg/cli-sdk 1.0.0-rc.3 → 1.0.0-rc.30

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 (210) hide show
  1. package/dist/commands/access.d.ts +22 -0
  2. package/dist/commands/access.js +246 -0
  3. package/dist/commands/bugs.d.ts +17 -0
  4. package/dist/commands/bugs.js +163 -0
  5. package/dist/{esm/commands → commands}/build.d.ts +0 -1
  6. package/dist/{esm/commands → commands}/build.js +0 -1
  7. package/dist/{esm/commands → commands}/cache.d.ts +0 -1
  8. package/dist/{esm/commands → commands}/cache.js +0 -1
  9. package/dist/{esm/commands → commands}/ci.d.ts +0 -1
  10. package/dist/{esm/commands → commands}/ci.js +11 -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 +8 -0
  14. package/dist/commands/create.js +102 -0
  15. package/dist/commands/deprecate.d.ts +13 -0
  16. package/dist/commands/deprecate.js +139 -0
  17. package/dist/commands/dist-tag.d.ts +21 -0
  18. package/dist/commands/dist-tag.js +177 -0
  19. package/dist/{esm/commands → commands}/docs.d.ts +0 -1
  20. package/dist/{esm/commands → commands}/docs.js +2 -3
  21. package/dist/{esm/commands → commands}/exec-cache.d.ts +0 -1
  22. package/dist/{esm/commands → commands}/exec-cache.js +0 -1
  23. package/dist/{esm/commands → 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 +0 -1
  26. package/dist/{esm/commands → commands}/exec.js +84 -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 +21 -3
  34. package/dist/commands/install.js +140 -0
  35. package/dist/{esm/commands → commands}/list.d.ts +4 -2
  36. package/dist/{esm/commands → commands}/list.js +8 -10
  37. package/dist/{esm/commands → commands}/login.d.ts +0 -1
  38. package/dist/{esm/commands → commands}/login.js +10 -1
  39. package/dist/{esm/commands/token.d.ts → commands/logout.d.ts} +0 -1
  40. package/dist/{esm/commands → commands}/logout.js +10 -1
  41. package/dist/{esm/commands → commands}/pack.d.ts +0 -1
  42. package/dist/{esm/commands → commands}/pack.js +90 -32
  43. package/dist/commands/ping.d.ts +17 -0
  44. package/dist/commands/ping.js +114 -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 +13 -0
  48. package/dist/commands/profile.js +104 -0
  49. package/dist/{esm/commands → commands}/publish.d.ts +1 -2
  50. package/dist/{esm/commands → commands}/publish.js +63 -12
  51. package/dist/{esm/commands → commands}/query.d.ts +4 -2
  52. package/dist/{esm/commands → commands}/query.js +12 -10
  53. package/dist/commands/repo.d.ts +17 -0
  54. package/dist/commands/repo.js +157 -0
  55. package/dist/{esm/commands → commands}/run-exec.d.ts +0 -1
  56. package/dist/commands/run-exec.js +40 -0
  57. package/dist/{esm/commands → commands}/run.d.ts +0 -1
  58. package/dist/{esm/commands → commands}/run.js +27 -1
  59. package/dist/commands/token.d.ts +31 -0
  60. package/dist/commands/token.js +186 -0
  61. package/dist/{esm/commands → commands}/uninstall.d.ts +0 -1
  62. package/dist/{esm/commands → commands}/uninstall.js +16 -3
  63. package/dist/commands/unpublish.d.ts +15 -0
  64. package/dist/commands/unpublish.js +200 -0
  65. package/dist/{esm/commands → commands}/update.d.ts +0 -1
  66. package/dist/{esm/commands → commands}/update.js +6 -1
  67. package/dist/{esm/commands → commands}/version.d.ts +0 -1
  68. package/dist/{esm/commands → commands}/version.js +27 -1
  69. package/dist/commands/view.d.ts +22 -0
  70. package/dist/commands/view.js +334 -0
  71. package/dist/{esm/commands → commands}/whoami.d.ts +0 -1
  72. package/dist/{esm/commands → commands}/whoami.js +10 -1
  73. package/dist/{esm/config → config}/definition.d.ts +39 -19
  74. package/dist/{esm/config → config}/definition.js +74 -39
  75. package/dist/{esm/config → config}/index.d.ts +0 -1
  76. package/dist/{esm/config → config}/index.js +37 -2
  77. package/dist/{esm/config → config}/merge.d.ts +0 -1
  78. package/dist/{esm/config → config}/merge.js +0 -1
  79. package/dist/{esm/config → config}/usage.d.ts +0 -1
  80. package/dist/{esm/config → config}/usage.js +0 -1
  81. package/dist/{esm/custom-help.d.ts → custom-help.d.ts} +0 -1
  82. package/dist/{esm/custom-help.js → custom-help.js} +35 -9
  83. package/dist/{esm/exec-command.d.ts → exec-command.d.ts} +0 -1
  84. package/dist/{esm/exec-command.js → exec-command.js} +14 -8
  85. package/dist/{esm/index.d.ts → index.d.ts} +0 -1
  86. package/dist/{esm/index.js → index.js} +1 -2
  87. package/dist/{esm/load-command.d.ts → load-command.d.ts} +0 -1
  88. package/dist/{esm/load-command.js → load-command.js} +0 -1
  89. package/dist/mermaid-image-view.d.ts +18 -0
  90. package/dist/mermaid-image-view.js +36 -0
  91. package/dist/{esm/output.d.ts → output.d.ts} +2 -2
  92. package/dist/{esm/output.js → output.js} +55 -2
  93. package/dist/{esm/pack-tarball.d.ts → pack-tarball.d.ts} +15 -1
  94. package/dist/{esm/pack-tarball.js → pack-tarball.js} +133 -91
  95. package/dist/{esm/parse-add-remove-args.d.ts → parse-add-remove-args.d.ts} +9 -3
  96. package/dist/{esm/parse-add-remove-args.js → parse-add-remove-args.js} +43 -11
  97. package/dist/{esm/print-err.d.ts → print-err.d.ts} +0 -1
  98. package/dist/{esm/print-err.js → print-err.js} +18 -3
  99. package/dist/query-diff-files.d.ts +17 -0
  100. package/dist/query-diff-files.js +63 -0
  101. package/dist/{esm/query-host-contexts.d.ts → query-host-contexts.d.ts} +0 -1
  102. package/dist/{esm/query-host-contexts.js → query-host-contexts.js} +8 -7
  103. package/dist/{esm/read-password.d.ts → read-password.d.ts} +0 -1
  104. package/dist/{esm/read-password.js → read-password.js} +0 -1
  105. package/dist/read-project-folders.d.ts +17 -0
  106. package/dist/read-project-folders.js +100 -0
  107. package/dist/reload-config.d.ts +2 -0
  108. package/dist/reload-config.js +11 -0
  109. package/dist/render-mermaid.d.ts +22 -0
  110. package/dist/render-mermaid.js +68 -0
  111. package/dist/telemetry.d.ts +58 -0
  112. package/dist/telemetry.js +170 -0
  113. package/dist/{esm/view.d.ts → view.d.ts} +0 -1
  114. package/dist/{esm/view.js → view.js} +1 -2
  115. package/package.json +69 -83
  116. package/dist/esm/commands/build.d.ts.map +0 -1
  117. package/dist/esm/commands/build.js.map +0 -1
  118. package/dist/esm/commands/cache.d.ts.map +0 -1
  119. package/dist/esm/commands/cache.js.map +0 -1
  120. package/dist/esm/commands/ci.d.ts.map +0 -1
  121. package/dist/esm/commands/ci.js.map +0 -1
  122. package/dist/esm/commands/config.d.ts.map +0 -1
  123. package/dist/esm/commands/config.js.map +0 -1
  124. package/dist/esm/commands/docs.d.ts.map +0 -1
  125. package/dist/esm/commands/docs.js.map +0 -1
  126. package/dist/esm/commands/exec-cache.d.ts.map +0 -1
  127. package/dist/esm/commands/exec-cache.js.map +0 -1
  128. package/dist/esm/commands/exec-local.d.ts.map +0 -1
  129. package/dist/esm/commands/exec-local.js.map +0 -1
  130. package/dist/esm/commands/exec.d.ts.map +0 -1
  131. package/dist/esm/commands/exec.js.map +0 -1
  132. package/dist/esm/commands/help.d.ts.map +0 -1
  133. package/dist/esm/commands/help.js.map +0 -1
  134. package/dist/esm/commands/init.d.ts.map +0 -1
  135. package/dist/esm/commands/init.js.map +0 -1
  136. package/dist/esm/commands/install/reporter.d.ts.map +0 -1
  137. package/dist/esm/commands/install/reporter.js.map +0 -1
  138. package/dist/esm/commands/install.d.ts.map +0 -1
  139. package/dist/esm/commands/install.js +0 -45
  140. package/dist/esm/commands/install.js.map +0 -1
  141. package/dist/esm/commands/list.d.ts.map +0 -1
  142. package/dist/esm/commands/list.js.map +0 -1
  143. package/dist/esm/commands/login.d.ts.map +0 -1
  144. package/dist/esm/commands/login.js.map +0 -1
  145. package/dist/esm/commands/logout.d.ts +0 -4
  146. package/dist/esm/commands/logout.d.ts.map +0 -1
  147. package/dist/esm/commands/logout.js.map +0 -1
  148. package/dist/esm/commands/pack.d.ts.map +0 -1
  149. package/dist/esm/commands/pack.js.map +0 -1
  150. package/dist/esm/commands/pkg.d.ts.map +0 -1
  151. package/dist/esm/commands/pkg.js.map +0 -1
  152. package/dist/esm/commands/publish.d.ts.map +0 -1
  153. package/dist/esm/commands/publish.js.map +0 -1
  154. package/dist/esm/commands/query.d.ts.map +0 -1
  155. package/dist/esm/commands/query.js.map +0 -1
  156. package/dist/esm/commands/run-exec.d.ts.map +0 -1
  157. package/dist/esm/commands/run-exec.js +0 -14
  158. package/dist/esm/commands/run-exec.js.map +0 -1
  159. package/dist/esm/commands/run.d.ts.map +0 -1
  160. package/dist/esm/commands/run.js.map +0 -1
  161. package/dist/esm/commands/serve.d.ts +0 -14
  162. package/dist/esm/commands/serve.d.ts.map +0 -1
  163. package/dist/esm/commands/serve.js +0 -103
  164. package/dist/esm/commands/serve.js.map +0 -1
  165. package/dist/esm/commands/token.d.ts.map +0 -1
  166. package/dist/esm/commands/token.js +0 -30
  167. package/dist/esm/commands/token.js.map +0 -1
  168. package/dist/esm/commands/uninstall.d.ts.map +0 -1
  169. package/dist/esm/commands/uninstall.js.map +0 -1
  170. package/dist/esm/commands/update.d.ts.map +0 -1
  171. package/dist/esm/commands/update.js.map +0 -1
  172. package/dist/esm/commands/version.d.ts.map +0 -1
  173. package/dist/esm/commands/version.js.map +0 -1
  174. package/dist/esm/commands/whoami.d.ts.map +0 -1
  175. package/dist/esm/commands/whoami.js.map +0 -1
  176. package/dist/esm/config/definition.d.ts.map +0 -1
  177. package/dist/esm/config/definition.js.map +0 -1
  178. package/dist/esm/config/index.d.ts.map +0 -1
  179. package/dist/esm/config/index.js.map +0 -1
  180. package/dist/esm/config/merge.d.ts.map +0 -1
  181. package/dist/esm/config/merge.js.map +0 -1
  182. package/dist/esm/config/usage.d.ts.map +0 -1
  183. package/dist/esm/config/usage.js.map +0 -1
  184. package/dist/esm/custom-help.d.ts.map +0 -1
  185. package/dist/esm/custom-help.js.map +0 -1
  186. package/dist/esm/exec-command.d.ts.map +0 -1
  187. package/dist/esm/exec-command.js.map +0 -1
  188. package/dist/esm/index.d.ts.map +0 -1
  189. package/dist/esm/index.js.map +0 -1
  190. package/dist/esm/load-command.d.ts.map +0 -1
  191. package/dist/esm/load-command.js.map +0 -1
  192. package/dist/esm/output.d.ts.map +0 -1
  193. package/dist/esm/output.js.map +0 -1
  194. package/dist/esm/pack-tarball.d.ts.map +0 -1
  195. package/dist/esm/pack-tarball.js.map +0 -1
  196. package/dist/esm/package.json +0 -3
  197. package/dist/esm/parse-add-remove-args.d.ts.map +0 -1
  198. package/dist/esm/parse-add-remove-args.js.map +0 -1
  199. package/dist/esm/print-err.d.ts.map +0 -1
  200. package/dist/esm/print-err.js.map +0 -1
  201. package/dist/esm/query-host-contexts.d.ts.map +0 -1
  202. package/dist/esm/query-host-contexts.js.map +0 -1
  203. package/dist/esm/read-password.d.ts.map +0 -1
  204. package/dist/esm/read-password.js.map +0 -1
  205. package/dist/esm/start-gui.d.ts +0 -10
  206. package/dist/esm/start-gui.d.ts.map +0 -1
  207. package/dist/esm/start-gui.js +0 -60
  208. package/dist/esm/start-gui.js.map +0 -1
  209. package/dist/esm/view.d.ts.map +0 -1
  210. package/dist/esm/view.js.map +0 -1
@@ -4,6 +4,16 @@ import { defaultView } from "./config/definition.js";
4
4
  import { printErr, formatOptions } from "./print-err.js";
5
5
  import { isViewClass } from "./view.js";
6
6
  import { generateDefaultHelp, generateFullHelp, } from "./custom-help.js";
7
+ import { flush as flushTelemetry, trackCommand, trackError, } from "./telemetry.js";
8
+ /* c8 ignore start - CI env detection is a best-effort heuristic */
9
+ const isCI = () => !!(process.env.CI ||
10
+ process.env.GITHUB_ACTIONS ||
11
+ process.env.GITLAB_CI ||
12
+ process.env.CIRCLECI ||
13
+ process.env.JENKINS_URL ||
14
+ process.env.BUILDKITE ||
15
+ process.env.TRAVIS);
16
+ /* c8 ignore stop */
7
17
  const supportsColor = (stream) => {
8
18
  const res = createSupportsColor(stream, { sniffFlags: false });
9
19
  if (res === false)
@@ -77,7 +87,9 @@ const startView = (conf, opts, views, { start } = { start: Date.now() }) => {
77
87
  * the user-requested view, or the default if the user requested a view
78
88
  * that is not defined for this command.
79
89
  */
80
- export const outputCommand = async (cliCommand, conf, { start } = { start: Date.now() }) => {
90
+ export const outputCommand = async (cliCommand, conf, { start, vltVersion } = {
91
+ start: Date.now(),
92
+ }) => {
81
93
  const { usage, views, command } = cliCommand;
82
94
  const stdoutColor = conf.values.color ?? supportsColor(process.stdout);
83
95
  const stderrColor = conf.values.color ?? supportsColor(process.stderr);
@@ -102,8 +114,21 @@ export const outputCommand = async (cliCommand, conf, { start } = { start: Date.
102
114
  const { onDone, onError } = startView(conf,
103
115
  // assume views will always output to stdout so use color support from there
104
116
  { colors: stdoutColor }, views, { start });
117
+ const telemetryEnabled = conf.values.telemetry;
118
+ const commandName = conf.command;
105
119
  try {
106
120
  const output = await onDone(await command(conf));
121
+ const duration_ms = Date.now() - start;
122
+ trackCommand({
123
+ command: commandName,
124
+ duration_ms,
125
+ success: true,
126
+ node_version: process.version,
127
+ vlt_version: vltVersion ?? 'unknown',
128
+ os: process.platform,
129
+ arch: process.arch,
130
+ ci: isCI(),
131
+ }, telemetryEnabled);
107
132
  if (output !== undefined && conf.values.view !== 'silent') {
108
133
  stdout(conf.values.view === 'json' ?
109
134
  JSON.stringify(output, null, 2)
@@ -112,10 +137,39 @@ export const outputCommand = async (cliCommand, conf, { start } = { start: Date.
112
137
  colors: stdoutColor,
113
138
  }, output));
114
139
  }
140
+ // Await the flush so pending telemetry events are sent before
141
+ // the process exits. The flush has a built-in timeout cap
142
+ // (SHUTDOWN_TIMEOUT_MS) so it will never block for long, and the
143
+ // timer is unreffed so even if this is not awaited the process
144
+ // can still exit promptly.
145
+ await flushTelemetry();
115
146
  }
116
147
  catch (err) {
117
148
  onError?.(err);
118
149
  process.exitCode ||= 1;
150
+ const duration_ms = Date.now() - start;
151
+ trackCommand({
152
+ command: commandName,
153
+ duration_ms,
154
+ success: false,
155
+ node_version: process.version,
156
+ vlt_version: vltVersion ?? 'unknown',
157
+ os: process.platform,
158
+ arch: process.arch,
159
+ ci: isCI(),
160
+ }, telemetryEnabled);
161
+ const errorCode = (err instanceof Error &&
162
+ err.cause &&
163
+ typeof err.cause === 'object' &&
164
+ 'code' in err.cause &&
165
+ typeof err.cause.code === 'string') ?
166
+ err.cause.code
167
+ : undefined;
168
+ trackError({
169
+ command: commandName,
170
+ error_code: errorCode,
171
+ }, telemetryEnabled);
172
+ await flushTelemetry();
119
173
  printErr(err, usage, stderr, {
120
174
  ...formatOptions,
121
175
  colors: stderrColor,
@@ -123,4 +177,3 @@ export const outputCommand = async (cliCommand, conf, { start } = { start: Date.
123
177
  process.exit(process.exitCode);
124
178
  }
125
179
  };
126
- //# sourceMappingURL=output.js.map
@@ -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
@@ -1,3 +1,4 @@
1
+ import type { PathScurry } from 'path-scurry';
1
2
  import type { AddImportersDependenciesMap, RemoveImportersDependenciesMap } from '@vltpkg/graph';
2
3
  import type { Monorepo } from '@vltpkg/workspaces';
3
4
  import type { LoadedConfig } from './config/index.ts';
@@ -17,6 +18,11 @@ export type WorkspaceTypes = {
17
18
  workspace?: string[];
18
19
  'workspace-group'?: string[];
19
20
  };
20
- export declare const parseAddArgs: (config: LoadedConfig, monorepo?: Monorepo) => ParsedAddArgs;
21
- export declare const parseRemoveArgs: (config: LoadedConfig, monorepo?: Monorepo) => ParsedRemoveArgs;
22
- //# sourceMappingURL=parse-add-remove-args.d.ts.map
21
+ /**
22
+ * Parses the positional arguments into {@link AddImportersDependenciesMap}.
23
+ */
24
+ export declare const parseAddArgs: (config: LoadedConfig, scurry: PathScurry, monorepo?: Monorepo) => ParsedAddArgs;
25
+ /**
26
+ * Parses the positional arguments into {@link RemoveImportersDependenciesMap}.
27
+ */
28
+ export declare const parseRemoveArgs: (config: LoadedConfig, scurry: PathScurry, monorepo?: Monorepo) => ParsedRemoveArgs;
@@ -1,12 +1,27 @@
1
- import { joinDepIDTuple } from '@vltpkg/dep-id';
2
1
  import { asDependency } from '@vltpkg/graph';
2
+ import { joinDepIDTuple } from '@vltpkg/dep-id';
3
3
  import { Spec } from '@vltpkg/spec';
4
4
  const rootDepID = joinDepIDTuple(['file', '.']);
5
+ /**
6
+ * Compute a DepID for the current working directory relative to the project
7
+ * root. Returns the root DepID if cwd is the project root, otherwise returns
8
+ * the computed DepID.
9
+ */
10
+ const getCwdDepID = (scurry) => {
11
+ const cwd = process.cwd();
12
+ const relPath = scurry.relativePosix(cwd);
13
+ // If cwd is the project root or outside it, return root DepID
14
+ if (!relPath || relPath.startsWith('..')) {
15
+ return rootDepID;
16
+ }
17
+ // Return a DepID for the nested folder (posix-style path)
18
+ return joinDepIDTuple(['file', relPath.split('\\').join('/')]);
19
+ };
5
20
  /**
6
21
  * Get the list of importers that are currently selected
7
22
  * in {@link WorkspaceTypes}.
8
23
  */
9
- const getImporters = (opts, monorepo) => {
24
+ const getWorkspaceImporters = (opts, monorepo) => {
10
25
  const res = new Set();
11
26
  // collects DepID references to any selected workspace
12
27
  if (monorepo) {
@@ -14,10 +29,6 @@ const getImporters = (opts, monorepo) => {
14
29
  res.add(ws.id);
15
30
  }
16
31
  }
17
- // if no references were found, default behavior is to point to project root
18
- if (!res.size) {
19
- res.add(rootDepID);
20
- }
21
32
  return res;
22
33
  };
23
34
  const getType = (opts) => opts['save-prod'] ? 'prod'
@@ -34,38 +45,59 @@ class AddImportersDependenciesMapImpl extends Map {
34
45
  class RemoveImportersDependenciesMapImpl extends Map {
35
46
  modifiedDependencies = false;
36
47
  }
37
- export const parseAddArgs = (config, monorepo) => {
48
+ /**
49
+ * Parses the positional arguments into {@link AddImportersDependenciesMap}.
50
+ */
51
+ export const parseAddArgs = (config, scurry, monorepo) => {
38
52
  const add = new AddImportersDependenciesMapImpl();
39
53
  const items = config.positionals;
40
54
  const type = getType(config.values);
41
- const importers = getImporters(config.values, monorepo);
55
+ const importers = getWorkspaceImporters(config.values, monorepo);
42
56
  const newDependencies = new Map();
43
57
  const specOptions = config.options;
44
58
  // nameless spec definitions will need to use their full
45
59
  // stringified spec result instead of their name in order
46
60
  // to have an unique key name in the resulting Map
47
61
  const getName = (s) => s.name === '(unknown)' ? s.spec : s.name;
62
+ // parses each positional argument into a Spec and
63
+ // adds it to the new dependencies Map
48
64
  for (const item of items) {
49
65
  const spec = Spec.parseArgs(item, specOptions);
50
66
  newDependencies.set(getName(spec), asDependency({ spec, type }));
51
67
  add.modifiedDependencies = true;
52
68
  }
69
+ // assigns the new dependencies to each selected workspace importer
53
70
  for (const importer of importers) {
54
71
  add.set(importer, newDependencies);
55
72
  }
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);
79
+ }
56
80
  return {
57
81
  add,
58
82
  };
59
83
  };
60
- export const parseRemoveArgs = (config, monorepo) => {
84
+ /**
85
+ * Parses the positional arguments into {@link RemoveImportersDependenciesMap}.
86
+ */
87
+ export const parseRemoveArgs = (config, scurry, monorepo) => {
61
88
  const remove = new RemoveImportersDependenciesMapImpl();
62
- const importers = getImporters(config.values, monorepo);
89
+ const importers = getWorkspaceImporters(config.values, monorepo);
63
90
  for (const importer of importers) {
64
91
  remove.set(importer, new Set(config.positionals));
65
92
  remove.modifiedDependencies = true;
66
93
  }
94
+ // if no workspaces were selected, default to the cwd importer
95
+ if (!importers.size) {
96
+ const cwdDepID = getCwdDepID(scurry);
97
+ remove.set(cwdDepID, new Set(config.positionals));
98
+ remove.modifiedDependencies = true;
99
+ }
67
100
  return {
68
101
  remove,
69
102
  };
70
103
  };
71
- //# 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 = {
@@ -33,6 +33,14 @@ const writeErrorLog = (e, format) => {
33
33
  return null;
34
34
  }
35
35
  };
36
+ const readErrorLog = (file) => {
37
+ try {
38
+ return readFileSync(file, 'utf8');
39
+ }
40
+ catch {
41
+ return null;
42
+ }
43
+ };
36
44
  export const printErr = (e, usage, stderr, baseOpts) => {
37
45
  const format = (arg, opts) => {
38
46
  const { maxLines = 200, ...rest } = {
@@ -62,6 +70,14 @@ export const printErr = (e, usage, stderr, baseOpts) => {
62
70
  if (fileWritten) {
63
71
  stderr('');
64
72
  stderr(`Full details written to: ${fileWritten}`);
73
+ if (process.env.CI) {
74
+ const fullErrorLog = readErrorLog(fileWritten);
75
+ if (fullErrorLog) {
76
+ stderr('');
77
+ stderr('Full details:');
78
+ stderr(fullErrorLog);
79
+ }
80
+ }
65
81
  }
66
82
  if (!knownError || knownError.bug) {
67
83
  stderr('');
@@ -175,4 +191,3 @@ const printCode = (err, usage, stderr, format) => {
175
191
  }
176
192
  }
177
193
  };
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