rootless-config 1.7.1 → 1.7.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rootless-config",
3
- "version": "1.7.1",
3
+ "version": "1.7.3",
4
4
  "description": "Store project config files outside the project root, auto-deploy them where tools expect them.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -133,9 +133,14 @@ export default {
133
133
  logger.success('Rootless hook already installed.')
134
134
  }
135
135
 
136
- // --profile-only: только установить профиль, без вывода кода в stdout
137
- // Используется в postinstall при npm install -g
138
- if (args.profileOnly) return
136
+ // --profile-only: используется в postinstall при npm install -g
137
+ // Только устанавливает профиль, без вывода кода в stdout
138
+ if (args.profileOnly) {
139
+ if (!alreadyInstalled) {
140
+ process.stderr.write('\x1b[32m✔ [rootless] Profile hook installed — open a new terminal to activate.\x1b[0m\n')
141
+ }
142
+ return
143
+ }
139
144
 
140
145
  // Если stdout пайпится (Invoke-Expression) — выводим HOOK_BODY
141
146
  // Если терминал — показываем подсказку
@@ -1,7 +1,7 @@
1
1
  /*-------- rootless migrate — moves existing root configs into .root container --------*/
2
2
 
3
3
  import path from 'node:path'
4
- import { readdir, unlink, cp, rm } from 'node:fs/promises'
4
+ import { readdir, unlink } from 'node:fs/promises'
5
5
  import { createLogger } from '../../utils/logger.js'
6
6
  import { fileExists, ensureDir, atomicWrite, copyFile, readJsonFile } from '../../utils/fsUtils.js'
7
7
  import { confirm } from '../../utils/prompt.js'
@@ -12,15 +12,6 @@ const SYSTEM_FILES = new Set([
12
12
  '.DS_Store', 'Thumbs.db', 'desktop.ini', '.git', '.svn',
13
13
  ])
14
14
 
15
- // Directories that must never be migrated
16
- const NEVER_MIGRATE_DIRS = new Set([
17
- 'node_modules', '.git', '.svn', '.hg', '.root',
18
- 'dist', 'build', 'out', '.next', '.nuxt', '.output',
19
- '.github', '.gitlab', '.circleci',
20
- '.vscode', '.idea', '.vs',
21
- '__pycache__', '.cache', '.parcel-cache', '.turbo',
22
- ])
23
-
24
15
  /**
25
16
  * Determine which .root sub-folder a file should land in:
26
17
  * env/ — .env* files (always copied to root by prepare)
@@ -34,20 +25,20 @@ function getDestSubdir(filename) {
34
25
  }
35
26
 
36
27
  /**
37
- * Returns ALL files AND directories in projectRoot that should be migrated.
38
- * Excludes: package manager locks, OS noise, VCS dirs, build outputs, editor dirs.
28
+ * Returns ALL files in projectRoot that should be migrated.
29
+ * Excludes: directories, package manager lock files, OS noise.
39
30
  */
40
31
  async function findMigratableFiles(projectRoot) {
41
32
  const entries = await readdir(projectRoot, { withFileTypes: true })
42
33
  return entries
43
34
  .filter(e => {
35
+ if (!e.isFile()) return false
44
36
  if (NEVER_MIGRATE.has(e.name)) return false
45
37
  if (SYSTEM_FILES.has(e.name)) return false
46
38
  if (e.name === '.root') return false
47
- if (e.isDirectory()) return !NEVER_MIGRATE_DIRS.has(e.name)
48
- return e.isFile()
39
+ return true
49
40
  })
50
- .map(e => ({ name: e.name, isDir: e.isDirectory() }))
41
+ .map(e => ({ name: e.name, isDir: false }))
51
42
  .sort((a, b) => a.name.localeCompare(b.name))
52
43
  }
53
44
 
@@ -77,10 +68,8 @@ export default {
77
68
  return
78
69
  }
79
70
 
80
- const fileCount = candidates.filter(c => !c.isDir).length
81
- const dirCount = candidates.filter(c => c.isDir).length
82
- const summary = candidates.map(c => c.isDir ? `${c.name}/` : c.name).join('\n ')
83
- logger.info(`Found ${fileCount} files + ${dirCount} directories to migrate:\n ${summary}`)
71
+ const summary = candidates.map(c => c.name).join('\n ')
72
+ logger.info(`Found ${candidates.length} files to migrate:\n ${summary}`)
84
73
 
85
74
  if (isCleanMode) {
86
75
  logger.info('Mode: clean — originals will be DELETED from root, package.json scripts will be patched')
@@ -94,27 +83,14 @@ export default {
94
83
  return
95
84
  }
96
85
 
97
- for (const { name, isDir } of candidates) {
86
+ for (const { name } of candidates) {
98
87
  const src = path.join(projectRoot, name)
99
- // Directories always go to assets/; files use normal routing
100
- const destSubdir = isDir ? 'assets' : getDestSubdir(name)
88
+ const destSubdir = getDestSubdir(name)
101
89
  const destDir = path.join(containerPath, destSubdir)
102
90
 
103
91
  await ensureDir(destDir)
104
92
  const dest = path.join(destDir, name)
105
93
 
106
- if (isDir) {
107
- // Recursively copy entire directory tree, then delete source
108
- await cp(src, dest, { recursive: true })
109
- if (isCleanMode) {
110
- await rm(src, { recursive: true, force: true })
111
- logger.success(`Moved dir .root/${destSubdir}/${name}/ (deleted from root)`)
112
- } else {
113
- logger.success(`Copied dir .root/${destSubdir}/${name}/`)
114
- }
115
- continue
116
- }
117
-
118
94
  if (isCleanMode) {
119
95
  // Binary-safe stream copy — works for .png, .js, .css, etc.
120
96
  await copyFile(src, dest)