@bobfrankston/npmglobalize 1.0.153 → 1.0.155

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -301,6 +301,8 @@ Publishing requires being on a branch so commits and tags can be properly tracke
301
301
  -force-publish Republish dependencies even if version exists
302
302
  -fix Run npm audit fix after transformation
303
303
  -no-fix Don't run npm audit
304
+ -no-use-paths, -nup Declare package standalone; do not resolve file: deps
305
+ from sibling checkouts (see Configuration File)
304
306
  ```
305
307
 
306
308
  ### Install Options
@@ -323,10 +325,21 @@ Publishing requires being on a branch so commits and tags can be properly tracke
323
325
  -git private Set GitHub repo to private (default for new repos)
324
326
  -git public Set GitHub repo to public (requires confirmation)
325
327
  Works on both new and existing repos
326
- -npm private Mark npm package private (skip publish) (default)
327
- -npm public Publish to npm
328
+ -npm <values> Comma-separated list of npm options:
329
+ private (default) | public package visibility
330
+ ts — keep .ts source (and *.map,
331
+ tsconfig.json) in npm tarball
332
+ nts — exclude .ts source
333
+ (default for non-noEmit projects)
334
+ Example: -npm public,ts
328
335
  ```
329
336
 
337
+ `ts` is already the default on git (source is tracked). Pass `-npm ts` to ship
338
+ the same files to npm — useful for debugging installed packages or "source on
339
+ demand" packages. `noEmit` projects automatically ship `.ts` files (they *are*
340
+ the runtime); pass `-npm nts` to override. `allowTs` persists to
341
+ `.globalize.json5`.
342
+
330
343
  ### Workspace Options
331
344
  ```
332
345
  -w, -workspace <pkg> Filter to specific package (repeatable)
@@ -400,12 +413,26 @@ Settings can be saved in `.globalize.json5`:
400
413
  "fix": true, // Auto-run npm audit fix
401
414
  "verbose": false, // Show detailed output
402
415
  "gitVisibility": "private",
403
- "npmVisibility": "public"
416
+ "npmVisibility": "public",
417
+ "usePaths": true // Resolve file: deps from sibling checkouts (see below)
404
418
  }
405
419
  ```
406
420
 
407
421
  Configuration persists across runs. CLI flags override config file.
408
422
 
423
+ ### `usePaths` — Standalone packages
424
+
425
+ Default: `true`. Set to `false` (or pass `-no-use-paths` / `-nup`) to mark a
426
+ package as **standalone** — one that should be publishable/installable on a
427
+ machine that does not have sibling `file:` dep checkouts available. Example:
428
+ a backup/recovery utility you want to `npm install -g` on any host.
429
+
430
+ Currently this setting is **declarative** — it is parsed, persisted to
431
+ `.globalize.json5`, and surfaced in the settings banner, but the tool does
432
+ not yet change its behavior based on it. Behavior wiring (e.g. resolving
433
+ `file:` deps to the latest published npm version instead of walking siblings)
434
+ is planned.
435
+
409
436
  ## Common Workflows
410
437
 
411
438
  ### Standard Release
package/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * npmglobalize CLI - Transform file: dependencies to npm versions for publishing
4
4
  */
5
- import { globalize, globalizeWorkspace, installCleanupHandlers, readConfig, readPackageJson, readUserNpmConfig, writeConfig, writePackageJson, confirm, getBuildIssues, clearBuildIssues, recordBuildIssue, extractFirstTscError } from './lib.js';
5
+ import { globalize, globalizeWorkspace, installCleanupHandlers, readConfig, readPackageJson, readUserNpmConfig, writeConfig, writePackageJson, confirm, getBuildIssues, clearBuildIssues, recordBuildIssue, extractFirstTscError, ensureFileDepModules } from './lib.js';
6
6
  import fs from 'fs';
7
7
  import path from 'path';
8
8
  import { styleText } from 'util';
@@ -37,6 +37,9 @@ Dependency Options:
37
37
  -no-prescan, -nps Skip upfront dep-graph prescan
38
38
  -force-publish Republish dependencies even if version exists
39
39
  -fix Run npm audit fix after transformation
40
+ -no-use-paths, -nup Declare this package standalone — file: deps shouldn't
41
+ be resolved from sibling checkouts (persisted as
42
+ usePaths:false in .globalize.json5; FYI for now)
40
43
 
41
44
  Install Options:
42
45
  -install, -i Global install after publish (from registry)
@@ -57,8 +60,12 @@ Git/npm Visibility:
57
60
  -git private Set GitHub repo to private (default for new repos)
58
61
  -git public Set GitHub repo to public (requires confirmation)
59
62
  Works on both new and existing repos
60
- -npm private Mark npm package private (skip publish) (default)
61
- -npm public Publish to npm
63
+ -npm <values> Comma-separated list of npm options:
64
+ private (default) | public package visibility
65
+ ts — keep .ts source in npm tarball
66
+ nts — exclude .ts source (default for
67
+ non-noEmit projects)
68
+ Example: -npm public,ts
62
69
 
63
70
  Workspace Options:
64
71
  -w, -workspace <pkg> Filter to specific package (repeatable)
@@ -214,12 +221,30 @@ function parseArgs(args) {
214
221
  break;
215
222
  case '-npm':
216
223
  i++;
217
- if (args[i] === 'private' || args[i] === 'public') {
218
- options.npmVisibility = args[i];
219
- options.explicitKeys.add('npmVisibility');
224
+ if (!args[i]) {
225
+ options.error = `-npm requires a value (private|public, ts, nts — comma-separated)`;
226
+ break;
220
227
  }
221
- else {
222
- options.error = `-npm requires 'private' or 'public', got: ${args[i]}`;
228
+ {
229
+ const tokens = args[i].split(',').map(t => t.trim()).filter(t => t);
230
+ for (const tok of tokens) {
231
+ if (tok === 'private' || tok === 'public') {
232
+ options.npmVisibility = tok;
233
+ options.explicitKeys.add('npmVisibility');
234
+ }
235
+ else if (tok === 'ts') {
236
+ options.allowTs = true;
237
+ options.explicitKeys.add('allowTs');
238
+ }
239
+ else if (tok === 'nts') {
240
+ options.allowTs = false;
241
+ options.explicitKeys.add('allowTs');
242
+ }
243
+ else {
244
+ options.error = `-npm: unknown value '${tok}' (expected private|public|ts|nts)`;
245
+ break;
246
+ }
247
+ }
223
248
  }
224
249
  break;
225
250
  case '-message':
@@ -266,6 +291,11 @@ function parseArgs(args) {
266
291
  case '-npd':
267
292
  options.publishDeps = false; // Disable auto-publishing
268
293
  break;
294
+ case '-no-use-paths':
295
+ case '-nup':
296
+ options.usePaths = false; // Skip sibling-path resolution; use latest npm version for file: deps
297
+ options.explicitKeys.add('usePaths');
298
+ break;
269
299
  case '-no-prescan':
270
300
  case '-nps':
271
301
  options.noPrescan = true;
@@ -423,6 +453,7 @@ export async function main() {
423
453
  }
424
454
  }
425
455
  if (pkg.scripts?.build) {
456
+ ensureFileDepModules(cwd, !!cliOptions.verbose);
426
457
  const { spawnSync } = await import('child_process');
427
458
  console.log(`Building ${cwd}...`);
428
459
  const buildResult = spawnSync('npm', ['run', 'build'], {
package/lib/config.js CHANGED
@@ -58,7 +58,8 @@ export function writeConfig(dir, config, explicitKeys) {
58
58
  wsl: false,
59
59
  force: false,
60
60
  verbose: false,
61
- freeze: false
61
+ freeze: false,
62
+ usePaths: true
62
63
  };
63
64
  // Read existing config to preserve values
64
65
  const existing = readConfig(dir);
@@ -119,6 +120,8 @@ export function writeConfig(dir, config, explicitKeys) {
119
120
  comment = ' // Transform but don\'t publish';
120
121
  else if (key === 'freeze')
121
122
  comment = ' // Freeze node_modules (replace symlinks with real copies)';
123
+ else if (key === 'usePaths')
124
+ comment = ' // Resolve file: deps from sibling checkouts (set false for standalone packages)';
122
125
  lines.push(` "${key}": ${jsonValue}${comma}${comment}`);
123
126
  });
124
127
  lines.push('');
@@ -139,6 +142,7 @@ export function writeConfig(dir, config, explicitKeys) {
139
142
  lines.push(' // "local": false // Local install only (skip transform/publish)');
140
143
  lines.push(' // "noPublish": false // Transform but don\'t publish');
141
144
  lines.push(' // "freeze": false // Freeze node_modules (replace symlinks with real copies)');
145
+ lines.push(' // "usePaths": true // Resolve file: deps from siblings; false = use latest npm version (standalone)');
142
146
  lines.push('}');
143
147
  fs.writeFileSync(configPath, lines.join('\n') + '\n');
144
148
  }
package/lib/types.d.ts CHANGED
@@ -78,6 +78,11 @@ export interface GlobalizeOptions {
78
78
  once?: boolean;
79
79
  /** Run importgen to update import maps before publishing */
80
80
  importgen?: boolean;
81
+ /** Use filesystem paths for `file:` deps (default true). Set false to
82
+ * mark a package as publishable/installable even when sibling checkouts
83
+ * are absent. Currently declarative (recorded in config and displayed);
84
+ * the actual conversion path is TODO. */
85
+ usePaths?: boolean;
81
86
  /** Local install only — skip transform/publish, just npm install -g . */
82
87
  local?: boolean;
83
88
  /** Freeze node_modules: replace symlinks/junctions with real copies for network share use */
package/lib.d.ts CHANGED
@@ -55,6 +55,10 @@ export interface GlobalizeOptions {
55
55
  gitVisibility?: 'private' | 'public';
56
56
  /** npm visibility: private (default) or public */
57
57
  npmVisibility?: 'private' | 'public';
58
+ /** Allow .ts source files (and *.map, tsconfig.json) in the published npm tarball.
59
+ * undefined: follow noEmit detection (noEmit → allow). true: always allow.
60
+ * false: always exclude via .npmignore. Set via `-npm ts` / `-npm nts`. */
61
+ allowTs?: boolean;
58
62
  /** Custom commit message */
59
63
  message?: string;
60
64
  /** Check and update ignore files to conform to best practices */
@@ -91,6 +95,11 @@ export interface GlobalizeOptions {
91
95
  once?: boolean;
92
96
  /** Run importgen to update import maps before publishing */
93
97
  importgen?: boolean;
98
+ /** Use filesystem paths for `file:` deps (default true). Set false to
99
+ * mark a package as publishable/installable even when sibling checkouts
100
+ * are absent. Currently declarative (recorded in config and displayed);
101
+ * the actual conversion path is TODO. */
102
+ usePaths?: boolean;
94
103
  /** Local install only — skip transform/publish, just npm install -g . */
95
104
  local?: boolean;
96
105
  /** Freeze node_modules: replace symlinks/junctions with real copies for network share use */
@@ -234,6 +243,12 @@ export declare function parseVersionTag(tag: string): number[] | null;
234
243
  export declare function compareVersions(a: number[], b: number[]): number;
235
244
  /** Fix version/tag mismatches */
236
245
  export declare function fixVersionTagMismatch(cwd: string, pkg: any, verbose?: boolean): boolean;
246
+ /** Walk `file:` deps transitively and run `npm install` in any target whose
247
+ * package.json declares deps but has no `node_modules/`. Recovers from prior
248
+ * aborted runs (or pre-1.0.153 `--clean-nested-modules` damage) so the
249
+ * upcoming build/pack can resolve transitive package imports.
250
+ * Cycle-safe via the shared `visited` set. */
251
+ export declare function ensureFileDepModules(cwd: string, verbose?: boolean, visited?: Set<string>): void;
237
252
  /** Run a command and return success status */
238
253
  export declare function runCommand(cmd: string, args: string[], options?: {
239
254
  silent?: boolean;
@@ -272,7 +287,7 @@ export declare function promptText(message: string, defaultValue?: string): Prom
272
287
  /** Prompt user for multiple choice */
273
288
  export declare function promptChoice(message: string, choices: string[]): Promise<string | null>;
274
289
  /** Initialize git repository */
275
- export declare function initGit(cwd: string, visibility: 'private' | 'public', dryRun: boolean): Promise<boolean>;
290
+ export declare function initGit(cwd: string, visibility: 'private' | 'public', dryRun: boolean, allowTs?: boolean): Promise<boolean>;
276
291
  /** Main globalize function */
277
292
  /** Run npm audit and optionally fix vulnerabilities */
278
293
  export declare function runNpmAudit(cwd: string, fix?: boolean, verbose?: boolean): {
package/lib.js CHANGED
@@ -230,7 +230,8 @@ export function writeConfig(dir, config, explicitKeys) {
230
230
  wsl: false,
231
231
  force: false,
232
232
  verbose: false,
233
- freeze: false
233
+ freeze: false,
234
+ usePaths: true
234
235
  };
235
236
  // Read existing config to preserve values
236
237
  const existing = readConfig(dir);
@@ -291,6 +292,10 @@ export function writeConfig(dir, config, explicitKeys) {
291
292
  comment = ' // Transform but don\'t publish';
292
293
  else if (key === 'freeze')
293
294
  comment = ' // Freeze node_modules (replace symlinks with real copies)';
295
+ else if (key === 'usePaths')
296
+ comment = ' // Resolve file: deps from sibling checkouts (set false for standalone packages)';
297
+ else if (key === 'allowTs')
298
+ comment = ' // Keep .ts source (and *.map, tsconfig.json) in the published npm tarball';
294
299
  lines.push(` "${key}": ${jsonValue}${comma}${comment}`);
295
300
  });
296
301
  lines.push('');
@@ -311,6 +316,8 @@ export function writeConfig(dir, config, explicitKeys) {
311
316
  lines.push(' // "local": false // Local install only (skip transform/publish)');
312
317
  lines.push(' // "noPublish": false // Transform but don\'t publish');
313
318
  lines.push(' // "freeze": false // Freeze node_modules (replace symlinks with real copies)');
319
+ lines.push(' // "usePaths": true // Resolve file: deps from siblings; false = use latest npm version (standalone)');
320
+ lines.push(' // "allowTs": false // Include .ts source in npm tarball (auto-true for noEmit projects)');
314
321
  lines.push('}');
315
322
  fs.writeFileSync(configPath, lines.join('\n') + '\n');
316
323
  }
@@ -1315,6 +1322,56 @@ function restoreNestedDepModules(stashed, verbose) {
1315
1322
  }
1316
1323
  }
1317
1324
  }
1325
+ /** Walk `file:` deps transitively and run `npm install` in any target whose
1326
+ * package.json declares deps but has no `node_modules/`. Recovers from prior
1327
+ * aborted runs (or pre-1.0.153 `--clean-nested-modules` damage) so the
1328
+ * upcoming build/pack can resolve transitive package imports.
1329
+ * Cycle-safe via the shared `visited` set. */
1330
+ export function ensureFileDepModules(cwd, verbose = false, visited = new Set()) {
1331
+ const abs = path.resolve(cwd);
1332
+ if (visited.has(abs))
1333
+ return;
1334
+ visited.add(abs);
1335
+ let pkg;
1336
+ try {
1337
+ pkg = readPackageJson(cwd);
1338
+ }
1339
+ catch {
1340
+ return;
1341
+ }
1342
+ for (const key of ['dependencies', 'devDependencies']) {
1343
+ const deps = pkg?.[key];
1344
+ if (!deps || typeof deps !== 'object')
1345
+ continue;
1346
+ for (const [name, spec] of Object.entries(deps)) {
1347
+ if (typeof spec !== 'string' || !spec.startsWith('file:'))
1348
+ continue;
1349
+ const target = path.resolve(cwd, spec.slice('file:'.length));
1350
+ if (!fs.existsSync(path.join(target, 'package.json')))
1351
+ continue;
1352
+ let targetPkg;
1353
+ try {
1354
+ targetPkg = readPackageJson(target);
1355
+ }
1356
+ catch {
1357
+ continue;
1358
+ }
1359
+ const hasDeps = (targetPkg?.dependencies && Object.keys(targetPkg.dependencies).length > 0) ||
1360
+ (targetPkg?.devDependencies && Object.keys(targetPkg.devDependencies).length > 0);
1361
+ const nm = path.join(target, 'node_modules');
1362
+ if (hasDeps && !fs.existsSync(nm)) {
1363
+ console.log(colors.yellow(`↻ restoring node_modules in ${name} (${target})`));
1364
+ const r = runCommand('npm', ['install'], { cwd: target, silent: !verbose });
1365
+ if (!r.success) {
1366
+ console.error(colors.red(` ✗ npm install failed in ${target}`));
1367
+ if (r.stderr)
1368
+ console.error(colors.dim(r.stderr.split('\n').slice(0, 5).join('\n')));
1369
+ }
1370
+ }
1371
+ ensureFileDepModules(target, verbose, visited);
1372
+ }
1373
+ }
1374
+ }
1318
1375
  /** Run npm install -g with retries for registry propagation delay */
1319
1376
  function installGlobalWithRetry(pkgSpec, cwd, maxRetries = 3) {
1320
1377
  let result = runCommand('npm', ['install', '-g', pkgSpec], { cwd, silent: false, showCommand: true });
@@ -1808,9 +1865,16 @@ function isNoEmitProject(cwd) {
1808
1865
  return false;
1809
1866
  }
1810
1867
  }
1811
- /** Get applicable npmignore patterns, excluding TS patterns for noEmit projects */
1812
- function getApplicableNpmignorePatterns(cwd) {
1813
- if (isNoEmitProject(cwd)) {
1868
+ /** Resolve whether .ts source files should be kept in the published tarball.
1869
+ * Explicit allowTs wins; otherwise noEmit projects default to including .ts. */
1870
+ function resolveAllowTs(cwd, allowTs) {
1871
+ if (allowTs !== undefined)
1872
+ return allowTs;
1873
+ return isNoEmitProject(cwd);
1874
+ }
1875
+ /** Get applicable npmignore patterns, excluding TS patterns when .ts files should ship */
1876
+ function getApplicableNpmignorePatterns(cwd, allowTs) {
1877
+ if (resolveAllowTs(cwd, allowTs)) {
1814
1878
  return ALL_NPMIGNORE.filter(p => !TS_NPMIGNORE_PATTERNS.has(p));
1815
1879
  }
1816
1880
  return ALL_NPMIGNORE;
@@ -2173,7 +2237,7 @@ function checkIgnoreFiles(cwd, options) {
2173
2237
  if (fs.existsSync(npmignorePath)) {
2174
2238
  const content = fs.readFileSync(npmignorePath, 'utf-8');
2175
2239
  const lines = content.split('\n').map(l => l.trim());
2176
- const applicableNpm = getApplicableNpmignorePatterns(cwd);
2240
+ const applicableNpm = getApplicableNpmignorePatterns(cwd, options.allowTs);
2177
2241
  for (const pattern of applicableNpm) {
2178
2242
  if (!lineHasPattern(lines, pattern)) {
2179
2243
  if (securityNpm.has(pattern)) {
@@ -2184,13 +2248,21 @@ function checkIgnoreFiles(cwd, options) {
2184
2248
  }
2185
2249
  }
2186
2250
  }
2251
+ // If .ts should ship, flag TS patterns already in .npmignore for removal
2252
+ if (resolveAllowTs(cwd, options.allowTs)) {
2253
+ for (const ts of TS_NPMIGNORE_PATTERNS) {
2254
+ if (lineHasPattern(lines, ts)) {
2255
+ changes.push(` .npmignore has (should remove): ${ts}`);
2256
+ }
2257
+ }
2258
+ }
2187
2259
  }
2188
2260
  const needsUpdate = changes.length > 0 || securityChanges.length > 0;
2189
2261
  return { needsUpdate, changes, securityChanges };
2190
2262
  }
2191
2263
  /** Update ignore files to conform to best practices.
2192
2264
  * securityOnly: if true, only add security patterns (auto-fix without prompting). */
2193
- function conformIgnoreFiles(cwd, securityOnly = false) {
2265
+ function conformIgnoreFiles(cwd, securityOnly = false, allowTs) {
2194
2266
  if (!securityOnly) {
2195
2267
  // Ensure .gitattributes for LF line endings (use proper helper)
2196
2268
  ensureGitattributes(cwd);
@@ -2209,8 +2281,8 @@ function conformIgnoreFiles(cwd, securityOnly = false) {
2209
2281
  }
2210
2282
  }
2211
2283
  const patternsGit = securityOnly ? getSecurityGitignorePatterns() : getApplicableGitignorePatterns(cwd);
2212
- const patternsNpm = securityOnly ? getSecurityNpmignorePatterns() : getApplicableNpmignorePatterns(cwd);
2213
- const noEmit = isNoEmitProject(cwd);
2284
+ const patternsNpm = securityOnly ? getSecurityNpmignorePatterns() : getApplicableNpmignorePatterns(cwd, allowTs);
2285
+ const shipTs = resolveAllowTs(cwd, allowTs);
2214
2286
  // Update .gitignore
2215
2287
  const gitignorePath = path.join(cwd, '.gitignore');
2216
2288
  if (fs.existsSync(gitignorePath)) {
@@ -2237,8 +2309,8 @@ function conformIgnoreFiles(cwd, securityOnly = false) {
2237
2309
  const lines = content.split('\n').map(l => l.trim());
2238
2310
  const newLines = new Set(lines.filter(l => l));
2239
2311
  let updated = false;
2240
- if (!securityOnly && !noEmit) {
2241
- // Add TypeScript exclusions (only in full conform, skip for noEmit projects)
2312
+ if (!securityOnly && !shipTs) {
2313
+ // Add TypeScript exclusions (only in full conform, skip when .ts should ship)
2242
2314
  for (const ts of ['*.ts', '!*.d.ts', '*.map']) {
2243
2315
  if (!newLines.has(ts)) {
2244
2316
  newLines.add(ts);
@@ -2246,8 +2318,8 @@ function conformIgnoreFiles(cwd, securityOnly = false) {
2246
2318
  }
2247
2319
  }
2248
2320
  }
2249
- // For noEmit projects, remove TS patterns that shouldn't be ignored
2250
- if (noEmit) {
2321
+ // When .ts should ship (noEmit or allowTs=true), remove TS patterns
2322
+ if (shipTs) {
2251
2323
  for (const ts of TS_NPMIGNORE_PATTERNS) {
2252
2324
  if (newLines.has(ts)) {
2253
2325
  newLines.delete(ts);
@@ -2264,8 +2336,9 @@ function conformIgnoreFiles(cwd, securityOnly = false) {
2264
2336
  if (updated) {
2265
2337
  const newContent = Array.from(newLines).join('\n') + '\n';
2266
2338
  fs.writeFileSync(npmignorePath, newContent);
2267
- if (noEmit) {
2268
- console.log(colors.cyan(' ✓ .npmignore updated (noEmit: kept *.ts files)'));
2339
+ if (shipTs) {
2340
+ const reason = allowTs === true ? 'allowTs' : 'noEmit';
2341
+ console.log(colors.cyan(` ✓ .npmignore updated (${reason}: kept *.ts files)`));
2269
2342
  }
2270
2343
  else {
2271
2344
  console.log(colors.cyan(' ✓ Auto-added security patterns to .npmignore'));
@@ -2324,11 +2397,11 @@ function ensureGitignore(cwd) {
2324
2397
  }
2325
2398
  }
2326
2399
  /** Ensure .npmignore exists with recommended patterns */
2327
- function ensureNpmignore(cwd) {
2400
+ function ensureNpmignore(cwd, allowTs) {
2328
2401
  const npmignorePath = path.join(cwd, '.npmignore');
2329
2402
  if (!fs.existsSync(npmignorePath)) {
2330
2403
  console.log(' Creating .npmignore...');
2331
- const patterns = getApplicableNpmignorePatterns(cwd);
2404
+ const patterns = getApplicableNpmignorePatterns(cwd, allowTs);
2332
2405
  const content = patterns.join('\n') + '\n';
2333
2406
  fs.writeFileSync(npmignorePath, content);
2334
2407
  console.log(colors.green(' ✓ .npmignore created'));
@@ -2355,7 +2428,7 @@ function ensureGitattributes(cwd) {
2355
2428
  }
2356
2429
  }
2357
2430
  /** Initialize git repository */
2358
- export async function initGit(cwd, visibility, dryRun) {
2431
+ export async function initGit(cwd, visibility, dryRun, allowTs) {
2359
2432
  const pkg = readPackageJson(cwd);
2360
2433
  const repoName = pkg.name.replace(/^@[^/]+\//, ''); // Remove scope
2361
2434
  console.log('Initializing git repository...');
@@ -2378,7 +2451,7 @@ export async function initGit(cwd, visibility, dryRun) {
2378
2451
  // Ensure .gitignore exists and includes node_modules
2379
2452
  ensureGitignore(cwd);
2380
2453
  // Ensure .npmignore exists with recommended patterns
2381
- ensureNpmignore(cwd);
2454
+ ensureNpmignore(cwd, allowTs);
2382
2455
  // Ensure .gitattributes exists for LF line endings
2383
2456
  ensureGitattributes(cwd);
2384
2457
  // git init
@@ -2643,7 +2716,7 @@ async function doLocalInstall(cwd, options) {
2643
2716
  export async function globalize(cwd, options = {}, configOptions = {}) {
2644
2717
  const { bump = 'patch', noPublish = false, cleanup = false, install = false, link = false, wsl = false, force = false, files = true, dryRun = false, quiet = true, verbose = false, init = false, gitVisibility = 'private', npmVisibility = 'private', message, conform = false, asis = false, updateDeps = false, updateMajor = false, publishDeps = true, // Default to publishing deps for safety
2645
2718
  publishDepsYes = false, // -pd: auto-yes to dep-cascade prompts (private only)
2646
- noPrescan = false, forcePublish = false, fix = true, fixTags = false, rebase = false, show = false, local = false, freeze = false } = options;
2719
+ noPrescan = false, forcePublish = false, fix = true, fixTags = false, rebase = false, show = false, local = false, freeze = false, usePaths = true, allowTs } = options;
2647
2720
  // Show tool version only for recursive dep calls (CLI already prints it at startup)
2648
2721
  const toolVersion = getToolVersion();
2649
2722
  if (!options._fromWorkspace && !options._fromCli) {
@@ -2702,6 +2775,12 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2702
2775
  settings.push('-local');
2703
2776
  if (configOptions.freeze)
2704
2777
  settings.push('-freeze');
2778
+ if (configOptions.usePaths === false)
2779
+ settings.push('--no-use-paths');
2780
+ if (configOptions.allowTs === true)
2781
+ settings.push('-npm ts');
2782
+ if (configOptions.allowTs === false)
2783
+ settings.push('-npm nts');
2705
2784
  if (settings.length > 0) {
2706
2785
  console.log(colors.dim(`Settings from .globalize.json5: ${settings.join(', ')}`));
2707
2786
  }
@@ -2782,7 +2861,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2782
2861
  }
2783
2862
  // Check ignore files first (unless cleanup mode)
2784
2863
  if (!cleanup && !asis) {
2785
- const checkResult = checkIgnoreFiles(cwd, { conform, asis, verbose });
2864
+ const checkResult = checkIgnoreFiles(cwd, { conform, asis, verbose, allowTs });
2786
2865
  // Auto-add security patterns without prompting
2787
2866
  if (checkResult.securityChanges.length > 0) {
2788
2867
  const secGit = [];
@@ -2795,7 +2874,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2795
2874
  secNpm.push(change.replace(' .npmignore missing: ', '').trim());
2796
2875
  }
2797
2876
  }
2798
- conformIgnoreFiles(cwd, true);
2877
+ conformIgnoreFiles(cwd, true, allowTs);
2799
2878
  if (secGit.length > 0) {
2800
2879
  console.log(colors.cyan(' .gitignore: auto-added ') + secGit.join(', '));
2801
2880
  }
@@ -2826,7 +2905,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2826
2905
  console.log('');
2827
2906
  if (conform) {
2828
2907
  console.log('Applying changes (--conform)...');
2829
- conformIgnoreFiles(cwd);
2908
+ conformIgnoreFiles(cwd, false, allowTs);
2830
2909
  console.log('');
2831
2910
  }
2832
2911
  else {
@@ -2838,7 +2917,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2838
2917
  const choice = await promptChoice('Your choice [ok/asis/abort]:', ['ok', 'asis', 'abort']);
2839
2918
  if (choice === 'ok') {
2840
2919
  console.log('Applying changes...');
2841
- conformIgnoreFiles(cwd);
2920
+ conformIgnoreFiles(cwd, false, allowTs);
2842
2921
  console.log(colors.green('✓ Ignore files updated'));
2843
2922
  console.log('');
2844
2923
  }
@@ -2896,13 +2975,13 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2896
2975
  options.autoInit = true;
2897
2976
  }
2898
2977
  // choice is '1', 'a', or '' (default)
2899
- const success = await initGit(cwd, gitVisibility, dryRun);
2978
+ const success = await initGit(cwd, gitVisibility, dryRun, allowTs);
2900
2979
  if (!success)
2901
2980
  return false;
2902
2981
  justInitialized = true;
2903
2982
  }
2904
2983
  else {
2905
- const success = await initGit(cwd, gitVisibility, dryRun);
2984
+ const success = await initGit(cwd, gitVisibility, dryRun, allowTs);
2906
2985
  if (!success)
2907
2986
  return false;
2908
2987
  justInitialized = true;
@@ -2925,7 +3004,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2925
3004
  options.autoInit = true;
2926
3005
  }
2927
3006
  }
2928
- const success = await initGit(cwd, gitVisibility, dryRun);
3007
+ const success = await initGit(cwd, gitVisibility, dryRun, allowTs);
2929
3008
  if (!success)
2930
3009
  return false;
2931
3010
  justInitialized = true;
@@ -3061,6 +3140,8 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
3061
3140
  const pkg = readPackageJson(cwd);
3062
3141
  // Run build step if package.json has a build script (skip if CLI already built)
3063
3142
  if (pkg.scripts?.build && !options._fromCli) {
3143
+ if (!dryRun)
3144
+ ensureFileDepModules(cwd, verbose);
3064
3145
  console.log(`${timestamp()} Running build...`);
3065
3146
  if (!dryRun) {
3066
3147
  // Always capture output so we can extract tsc errors for the summary
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/npmglobalize",
3
- "version": "1.0.153",
3
+ "version": "1.0.155",
4
4
  "description": "Transform file: dependencies to npm versions for publishing",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -33,6 +33,7 @@
33
33
  "dependencies": {
34
34
  "@bobfrankston/freezepak": "^0.1.7",
35
35
  "@bobfrankston/importgen": "^0.1.34",
36
+ "@bobfrankston/npmglobalize": "^1.0.153",
36
37
  "@bobfrankston/themecolors": "^0.1.5",
37
38
  "@bobfrankston/userconfig": "^1.0.7",
38
39
  "@npmcli/package-json": "^7.0.4",
@@ -48,6 +49,7 @@
48
49
  ".dependencies": {
49
50
  "@bobfrankston/freezepak": "file:../freezepak",
50
51
  "@bobfrankston/importgen": "file:../importgen",
52
+ "@bobfrankston/npmglobalize": "^1.0.153",
51
53
  "@bobfrankston/themecolors": "file:../themecolors",
52
54
  "@bobfrankston/userconfig": "file:../userconfig",
53
55
  "@npmcli/package-json": "^7.0.4",
@@ -61,6 +63,7 @@
61
63
  "dependencies": {
62
64
  "@bobfrankston/freezepak": "^0.1.7",
63
65
  "@bobfrankston/importgen": "^0.1.34",
66
+ "@bobfrankston/npmglobalize": "^1.0.153",
64
67
  "@bobfrankston/themecolors": "^0.1.5",
65
68
  "@bobfrankston/userconfig": "^1.0.7",
66
69
  "@npmcli/package-json": "^7.0.4",