rootless-config 1.4.4 → 1.4.6
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 +1 -1
- package/src/cli/commands/migrate.js +25 -8
- package/src/cli/commands/setup.js +70 -24
package/package.json
CHANGED
|
@@ -5,20 +5,38 @@ 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'
|
|
8
|
-
import { patchPackageScripts,
|
|
8
|
+
import { patchPackageScripts, isPatchable, NEVER_MIGRATE } from '../../core/scriptPatcher.js'
|
|
9
9
|
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
// Files that are OS/editor/VCS noise — never migrate, never touch
|
|
11
|
+
const SYSTEM_FILES = new Set([
|
|
12
|
+
'.DS_Store', 'Thumbs.db', 'desktop.ini', '.git', '.svn',
|
|
13
|
+
])
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Determine which .root sub-folder a file should land in:
|
|
17
|
+
* env/ — .env* files (always copied to root by prepare)
|
|
18
|
+
* configs/ — tool configs that support --config flags (scripts get patched)
|
|
19
|
+
* assets/ — everything else (always copied to root by prepare)
|
|
20
|
+
*/
|
|
21
|
+
function getDestSubdir(filename) {
|
|
22
|
+
if (/^\.env/.test(filename)) return 'env'
|
|
23
|
+
if (isPatchable(filename)) return 'configs'
|
|
24
|
+
return 'assets'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Returns ALL files in projectRoot that should be migrated.
|
|
29
|
+
* Excludes: directories, package manager lock files, OS noise.
|
|
30
|
+
*/
|
|
15
31
|
async function findMigratableFiles(projectRoot) {
|
|
16
32
|
const entries = await readdir(projectRoot, { withFileTypes: true })
|
|
17
33
|
return entries
|
|
18
34
|
.filter(e => {
|
|
19
35
|
if (!e.isFile()) return false
|
|
20
36
|
if (NEVER_MIGRATE.has(e.name)) return false
|
|
21
|
-
|
|
37
|
+
if (SYSTEM_FILES.has(e.name)) return false
|
|
38
|
+
if (e.name === '.root') return false
|
|
39
|
+
return true // migrate EVERYTHING else
|
|
22
40
|
})
|
|
23
41
|
.map(e => e.name)
|
|
24
42
|
.sort()
|
|
@@ -66,8 +84,7 @@ export default {
|
|
|
66
84
|
|
|
67
85
|
for (const name of candidates) {
|
|
68
86
|
const src = path.join(projectRoot, name)
|
|
69
|
-
const
|
|
70
|
-
const destSubdir = isEnv ? 'env' : (isWebAsset(name) ? 'assets' : 'configs')
|
|
87
|
+
const destSubdir = getDestSubdir(name)
|
|
71
88
|
const destDir = path.join(containerPath, destSubdir)
|
|
72
89
|
|
|
73
90
|
await ensureDir(destDir)
|
|
@@ -1,21 +1,62 @@
|
|
|
1
|
-
/*-------- rootless setup — one-command full root cleanup: init +
|
|
1
|
+
/*-------- rootless setup — one-command full root cleanup: init + normalize + migrate --------*/
|
|
2
2
|
|
|
3
3
|
import path from 'node:path'
|
|
4
|
+
import { readdir, rename } from 'node:fs/promises'
|
|
4
5
|
import { createLogger } from '../../utils/logger.js'
|
|
6
|
+
import { fileExists, ensureDir } from '../../utils/fsUtils.js'
|
|
7
|
+
import { isPatchable } from '../../core/scriptPatcher.js'
|
|
5
8
|
import initCmd from './init.js'
|
|
6
9
|
import migrateCmd from './migrate.js'
|
|
7
|
-
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Fix files that ended up in the wrong subfolder from a previous run.
|
|
13
|
+
* Non-patchable files (web assets, docs, scripts) belong in assets/, not configs/.
|
|
14
|
+
*/
|
|
15
|
+
async function normalizeContainer(containerPath, logger) {
|
|
16
|
+
const configsDir = path.join(containerPath, 'configs')
|
|
17
|
+
const assetsDir = path.join(containerPath, 'assets')
|
|
18
|
+
if (!(await fileExists(configsDir))) return
|
|
19
|
+
|
|
20
|
+
const entries = await readdir(configsDir, { withFileTypes: true })
|
|
21
|
+
for (const e of entries) {
|
|
22
|
+
if (!e.isFile()) continue
|
|
23
|
+
if (!isPatchable(e.name)) {
|
|
24
|
+
// Not a tool config — belongs in assets/
|
|
25
|
+
await ensureDir(assetsDir)
|
|
26
|
+
await rename(
|
|
27
|
+
path.join(configsDir, e.name),
|
|
28
|
+
path.join(assetsDir, e.name)
|
|
29
|
+
)
|
|
30
|
+
logger.debug(`Normalized: .root/configs/${e.name} → .root/assets/${e.name}`)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Count total files managed across all .root subdirectories.
|
|
37
|
+
*/
|
|
38
|
+
async function countRootFiles(containerPath) {
|
|
39
|
+
let total = 0
|
|
40
|
+
for (const sub of ['env', 'assets', 'configs']) {
|
|
41
|
+
const dir = path.join(containerPath, sub)
|
|
42
|
+
if (!(await fileExists(dir))) continue
|
|
43
|
+
const entries = await readdir(dir, { withFileTypes: true })
|
|
44
|
+
total += entries.filter(e => e.isFile()).length
|
|
45
|
+
}
|
|
46
|
+
return total
|
|
47
|
+
}
|
|
8
48
|
|
|
9
49
|
export default {
|
|
10
50
|
name: 'setup',
|
|
11
|
-
description: 'Full automated root cleanup:
|
|
51
|
+
description: 'Full automated root cleanup: move ALL files into .root container (run prepare to deploy)',
|
|
12
52
|
|
|
13
53
|
async handler(args) {
|
|
14
54
|
const logger = createLogger({ verbose: args.verbose ?? false })
|
|
15
55
|
const projectRoot = args.cwd ? path.resolve(args.cwd) : process.cwd()
|
|
56
|
+
const containerPath = path.join(projectRoot, '.root')
|
|
16
57
|
|
|
17
58
|
logger.info('─────────────────────────────────────────')
|
|
18
|
-
logger.info(' rootless setup —
|
|
59
|
+
logger.info(' rootless setup — moving everything to .root/')
|
|
19
60
|
logger.info('─────────────────────────────────────────')
|
|
20
61
|
logger.info('')
|
|
21
62
|
|
|
@@ -24,31 +65,36 @@ export default {
|
|
|
24
65
|
await initCmd.handler({ ...args, yes: true, cwd: projectRoot })
|
|
25
66
|
logger.info('')
|
|
26
67
|
|
|
27
|
-
// ── Step 2:
|
|
28
|
-
logger.info('[2/3]
|
|
29
|
-
await
|
|
68
|
+
// ── Step 2: normalize existing .root structure (fix misrouted files) ──────
|
|
69
|
+
logger.info('[2/3] Normalizing .root structure…')
|
|
70
|
+
await normalizeContainer(containerPath, logger)
|
|
71
|
+
logger.success('Structure normalized')
|
|
30
72
|
logger.info('')
|
|
31
73
|
|
|
32
|
-
// ── Step 3:
|
|
33
|
-
logger.info('[3/3]
|
|
34
|
-
await
|
|
74
|
+
// ── Step 3: migrate ALL files from root → .root/ ──────────────────────────
|
|
75
|
+
logger.info('[3/3] Migrating files from root to .root/…')
|
|
76
|
+
await migrateCmd.handler({ ...args, yes: true, cwd: projectRoot })
|
|
35
77
|
logger.info('')
|
|
36
78
|
|
|
79
|
+
const total = await countRootFiles(containerPath)
|
|
80
|
+
|
|
37
81
|
logger.info('─────────────────────────────────────────')
|
|
38
|
-
logger.success(
|
|
39
|
-
logger.info('')
|
|
40
|
-
logger.info('
|
|
41
|
-
logger.info('
|
|
42
|
-
logger.info('
|
|
43
|
-
logger.info('
|
|
44
|
-
logger.info('
|
|
45
|
-
logger.info('
|
|
46
|
-
logger.info('
|
|
47
|
-
logger.info('')
|
|
48
|
-
logger.info('
|
|
49
|
-
logger.info('
|
|
50
|
-
logger.info('
|
|
51
|
-
logger.info('
|
|
82
|
+
logger.success(`Setup complete! ${total} files now managed in .root/`)
|
|
83
|
+
logger.info('')
|
|
84
|
+
logger.info('Your project root is now clean.')
|
|
85
|
+
logger.info('')
|
|
86
|
+
logger.info(' .root/env/ — .env files')
|
|
87
|
+
logger.info(' .root/assets/ — web assets, HTML, images, scripts')
|
|
88
|
+
logger.info(' .root/configs/ — tool configs (vite, eslint, jest…)')
|
|
89
|
+
logger.info('')
|
|
90
|
+
logger.info('⚠ Files were REMOVED from root.')
|
|
91
|
+
logger.info(' Run the following before deploying or starting the project:')
|
|
92
|
+
logger.info('')
|
|
93
|
+
logger.info(' rootless prepare — copies files back to root')
|
|
94
|
+
logger.info('')
|
|
95
|
+
logger.info('Other commands:')
|
|
96
|
+
logger.info(' rootless status — show what is managed')
|
|
97
|
+
logger.info(' rootless watch — auto-sync .root/ → root on changes')
|
|
52
98
|
logger.info('─────────────────────────────────────────')
|
|
53
99
|
},
|
|
54
100
|
}
|