permachine 0.2.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 JosXa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,474 @@
1
+ # permachine
2
+
3
+ Per-machine config management with git for tools that don't support it natively. Automatically merge machine-specific configurations with a base config.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/permachine.svg)](https://www.npmjs.com/package/permachine)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Problem
9
+
10
+ When syncing dotfiles across multiple machines, you often need:
11
+
12
+ - **Shared configuration** - Settings that work across all machines
13
+ - **Machine-specific overrides** - Local paths, API keys, ports, etc.
14
+ - **Automatic merging** - No manual copy-paste or merge steps
15
+
16
+ ## Solution
17
+
18
+ `permachine` automatically:
19
+
20
+ 1. Detects your machine name
21
+ 2. Finds machine-specific config files (e.g. `config.my-laptop.json`, `config.workstation.json`)
22
+ 3. Merges them with base configs (e.g., `config.base.json`)
23
+ 4. Outputs the final config (e.g., `config.json`)
24
+ 5. **Manages .gitignore** - Adds output files and removes from git tracking
25
+ 6. Runs automatically on git operations via hooks
26
+
27
+ ## Quick Start
28
+
29
+ ```bash
30
+ # Install globally
31
+ npm install -g permachine
32
+
33
+ # In your repository
34
+ cd /path/to/your/repo
35
+
36
+ # Initialize (one-time setup)
37
+ permachine init
38
+
39
+ # That's it! Your configs will now auto-merge on git operations when a file ends with `.<machine-name>.<ext>`
40
+ ```
41
+
42
+ ## CLI Reference
43
+
44
+ ```
45
+ permachine - Automatically merge machine-specific config files
46
+
47
+ USAGE:
48
+ permachine <command> [options]
49
+
50
+ COMMANDS:
51
+ init Initialize permachine in current repository
52
+ merge Manually trigger merge operation
53
+ info Show information about current setup
54
+ uninstall Uninstall git hooks
55
+ watch Watch for file changes and auto-merge
56
+
57
+ OPTIONS:
58
+ --help, -h Show this help message
59
+ --version, -v Show version number
60
+ --silent, -s Suppress all output except errors (for merge command)
61
+ --legacy Use legacy .git/hooks wrapping (for init command)
62
+ --auto Auto-detect best installation method (for init command)
63
+ --no-gitignore Don't manage .gitignore or git tracking (for init/merge commands)
64
+ --debounce <ms> Debounce delay in milliseconds (for watch command, default: 300)
65
+ --verbose Show detailed file change events (for watch command)
66
+
67
+ EXAMPLES:
68
+ permachine init
69
+ permachine merge --silent
70
+ permachine info
71
+ permachine uninstall
72
+ permachine watch
73
+ permachine watch --debounce 500 --verbose
74
+ ```
75
+
76
+ ## Usage
77
+
78
+ ### File Naming Convention
79
+
80
+ Given machine name `my-laptop` (auto-detected from hostname):
81
+
82
+ | Purpose | Filename | In Git? |
83
+ | --------------------- | ----------------------- | ------------------ |
84
+ | Base config (shared) | `config.base.json` | ✅ Yes |
85
+ | Machine-specific | `config.my-laptop.json` | ✅ Yes |
86
+ | Final output (merged) | `config.json` | ❌ No (gitignored) |
87
+
88
+ Same pattern works for `.env` files:
89
+
90
+ | Purpose | Filename | In Git? |
91
+ | ---------------- | ---------------- | ------------------ |
92
+ | Base config | `.env.base` | ✅ Yes |
93
+ | Machine-specific | `.env.my-laptop` | ✅ Yes |
94
+ | Final output | `.env` | ❌ No (gitignored) |
95
+
96
+ ### Basic Commands
97
+
98
+ #### Initialize in Repository
99
+
100
+ ```bash
101
+ permachine init
102
+ ```
103
+
104
+ **What it does:**
105
+
106
+ - Detects your machine name (e.g., `laptop`, `desktop`, `workstation`)
107
+ - Installs git hooks for automatic merging
108
+ - Scans for existing machine-specific files
109
+ - **Prompts for confirmation** if existing files will be overwritten
110
+ - Performs initial merge
111
+ - Adds output files to `.gitignore` and removes them from git tracking
112
+
113
+ **Example output:**
114
+
115
+ ```
116
+ ✓ Machine detected: laptop
117
+ ✓ Git hooks installed via core.hooksPath
118
+ ✓ Merged 2 file(s)
119
+ ✓ Added 2 file(s) to .gitignore
120
+ ✓ Removed 1 file(s) from git tracking
121
+
122
+ Git hooks will auto-merge on:
123
+ - checkout (switching branches)
124
+ - merge (git pull/merge)
125
+ - commit
126
+ ```
127
+
128
+ #### Manual Merge
129
+
130
+ ```bash
131
+ permachine merge
132
+ ```
133
+
134
+ **Prompts for confirmation** if existing files will be overwritten. Useful for testing or running without git hooks.
135
+
136
+ #### Watch Mode
137
+
138
+ ```bash
139
+ permachine watch
140
+ ```
141
+
142
+ **What it does:**
143
+
144
+ - Watches all base and machine-specific files for changes
145
+ - Automatically merges when you save any watched file
146
+
147
+ #### Check Setup
148
+
149
+ ```bash
150
+ permachine info
151
+ ```
152
+
153
+ **Example output:**
154
+
155
+ ```
156
+ Machine name: laptop
157
+ Repository: /path/to/repo
158
+ Hooks method: core.hooksPath
159
+ Hooks path: .permachine/hooks
160
+ Tracked patterns: 2
161
+ - config.base.json + config.laptop.json → config.json
162
+ - .env.base + .env.laptop → .env
163
+
164
+ Output files: 2 total, 1 existing
165
+ Existing output files:
166
+ - config.json
167
+ ```
168
+
169
+ ## Cookbook / Recipes
170
+
171
+ ### Recipe 1: VSCode Settings Per Machine
172
+
173
+ Different settings for work laptop vs home desktop:
174
+
175
+ ```bash
176
+ # On work laptop (machine: "worklaptop")
177
+ .vscode/
178
+ ├── settings.base.json # Shared: theme, font size
179
+ ├── settings.worklaptop.json # Work paths, proxy settings
180
+ └── settings.json # ← Merged output (gitignored)
181
+
182
+ # On home desktop (machine: "desktop")
183
+ .vscode/
184
+ ├── settings.base.json # Shared: theme, font size
185
+ ├── settings.desktop.json # Home paths, no proxy
186
+ └── settings.json # ← Merged output (gitignored)
187
+ ```
188
+
189
+ **setup.base.json:**
190
+
191
+ ```json
192
+ {
193
+ "editor.fontSize": 14,
194
+ "workbench.colorTheme": "Dark+"
195
+ }
196
+ ```
197
+
198
+ **settings.worklaptop.json:**
199
+
200
+ ```json
201
+ {
202
+ "http.proxy": "http://proxy.company.com:8080",
203
+ "terminal.integrated.cwd": "C:/Projects"
204
+ }
205
+ ```
206
+
207
+ ### Recipe 2: Environment Variables
208
+
209
+ Different database credentials per environment:
210
+
211
+ ```bash
212
+ # .env.base (shared defaults)
213
+ NODE_ENV=development
214
+ LOG_LEVEL=info
215
+ API_PORT=3000
216
+
217
+ # .env.laptop (local dev)
218
+ DATABASE_URL=postgresql://localhost:5432/myapp_dev
219
+ API_KEY=dev_key_123
220
+
221
+ # .env.prodserver (production)
222
+ DATABASE_URL=postgresql://prod.db.com:5432/myapp
223
+ API_KEY=prod_key_xyz
224
+
225
+ # .env ← Merged output (gitignored)
226
+ ```
227
+
228
+ ### Recipe 3: Package.json Scripts
229
+
230
+ Different build scripts for different machines:
231
+
232
+ ```bash
233
+ # package.base.json
234
+ {
235
+ "name": "my-app",
236
+ "version": "1.0.0",
237
+ "scripts": {
238
+ "test": "jest"
239
+ },
240
+ "dependencies": {
241
+ "express": "^4.18.0"
242
+ }
243
+ }
244
+
245
+ # package.laptop.json (local development)
246
+ {
247
+ "scripts": {
248
+ "dev": "nodemon src/index.js",
249
+ "build": "webpack --mode development"
250
+ }
251
+ }
252
+
253
+ # package.buildserver.json (CI/CD)
254
+ {
255
+ "scripts": {
256
+ "build": "webpack --mode production",
257
+ "deploy": "aws s3 sync dist/ s3://my-bucket"
258
+ }
259
+ }
260
+
261
+ # package.json ← Merged output
262
+ # Each machine gets appropriate scripts!
263
+ ```
264
+
265
+ ### Recipe 4: Database Configuration
266
+
267
+ Multi-environment database setup:
268
+
269
+ ```bash
270
+ # config/database.base.json
271
+ {
272
+ "pool": {
273
+ "min": 2,
274
+ "max": 10
275
+ },
276
+ "migrations": {
277
+ "directory": "./migrations"
278
+ }
279
+ }
280
+
281
+ # config/database.laptop.json
282
+ {
283
+ "connection": {
284
+ "host": "localhost",
285
+ "port": 5432,
286
+ "database": "myapp_dev",
287
+ "user": "dev",
288
+ "password": "dev123"
289
+ }
290
+ }
291
+
292
+ # config/database.prodserver.json
293
+ {
294
+ "connection": {
295
+ "host": "db.production.com",
296
+ "port": 5432,
297
+ "database": "myapp_production",
298
+ "user": "produser",
299
+ "password": "secure_password_from_vault"
300
+ },
301
+ "pool": {
302
+ "min": 10,
303
+ "max": 50
304
+ }
305
+ }
306
+ ```
307
+
308
+ ### Recipe 5: Multi-File Projects
309
+
310
+ Complex projects with multiple config files:
311
+
312
+ ```bash
313
+ project/
314
+ ├── config.base.json
315
+ ├── config.laptop.json
316
+ ├── settings/
317
+ │ ├── app.base.json
318
+ │ ├── app.laptop.json
319
+ │ ├── database.base.json
320
+ │ └── database.laptop.json
321
+ ├── .env.base
322
+ └── .env.laptop
323
+
324
+ # After `permachine init`, all files auto-merge:
325
+ # - config.json
326
+ # - settings/app.json
327
+ # - settings/database.json
328
+ # - .env
329
+ ```
330
+
331
+ ## How It Works
332
+
333
+ `permachine` uses a simple three-step process:
334
+
335
+ 1. **Machine Detection** - Automatically detects your machine name from hostname (Windows: `COMPUTERNAME`, Linux/Mac: `hostname()`)
336
+
337
+ 2. **File Discovery** - Scans your repository for files matching the pattern `*.{machine}.*` (e.g., `config.laptop.json`, `.env.desktop`)
338
+
339
+ 3. **Smart Merging** - Merges base and machine-specific configs:
340
+
341
+ - **JSON**: Deep recursive merge (machine values override base)
342
+ - **ENV**: Key-value merge with comment preservation
343
+
344
+ 4. **Gitignore Management** - Automatically adds output files to `.gitignore` and removes already-tracked files from git
345
+
346
+ 5. **Git Hooks** - Installs hooks to auto-merge on checkout, merge, and commit operations
347
+
348
+ For detailed implementation information, see [CONTRIBUTING.md](CONTRIBUTING.md).
349
+
350
+ ## Supported File Types
351
+
352
+ | Type | Extensions | Merge Strategy | Status |
353
+ | ----- | --------------------- | --------------------------------- | ------------ |
354
+ | JSON | `.json` | Deep recursive merge | ✅ Supported |
355
+ | JSONC | `.json` with comments | Deep merge + comment preservation | ✅ Supported |
356
+ | ENV | `.env`, `.env.*` | Key-value override | ✅ Supported |
357
+ | YAML | `.yaml`, `.yml` | Deep recursive merge | 🔜 Planned |
358
+ | TOML | `.toml` | Deep recursive merge | 🔜 Planned |
359
+
360
+ ## Troubleshooting
361
+
362
+ ### Hooks not running
363
+
364
+ **Check hook installation:**
365
+
366
+ ```bash
367
+ permachine info
368
+ ```
369
+
370
+ **Verify git config:**
371
+
372
+ ```bash
373
+ git config --get core.hooksPath
374
+ # Should output: .permachine/hooks
375
+ ```
376
+
377
+ **Check hook files exist:**
378
+
379
+ ```bash
380
+ ls .permachine/hooks/
381
+ ```
382
+
383
+ ### Merge not happening
384
+
385
+ **Run manually to see errors:**
386
+
387
+ ```bash
388
+ permachine merge
389
+ ```
390
+
391
+ **Check machine name matches your files:**
392
+
393
+ ```bash
394
+ permachine info
395
+ # Verify "Machine name" matches your file pattern
396
+ ```
397
+
398
+ ### Wrong machine name detected
399
+
400
+ Machine names are auto-detected from your system hostname. To verify:
401
+
402
+ ```bash
403
+ # Windows
404
+ echo %COMPUTERNAME%
405
+
406
+ # Linux/Mac
407
+ hostname
408
+ ```
409
+
410
+ Files must match this name (case-insensitive).
411
+
412
+ ### Conflicts with other git hook tools
413
+
414
+ If you use Husky or other hook managers, use legacy mode:
415
+
416
+ ```bash
417
+ permachine uninstall
418
+ permachine init --legacy
419
+ ```
420
+
421
+ This wraps existing hooks instead of replacing them.
422
+
423
+ ### Output file not being gitignored
424
+
425
+ By default, `permachine init` and `permachine merge` automatically add output files to `.gitignore`. If this isn't working:
426
+
427
+ 1. Check if `.gitignore` exists and contains your output files
428
+ 2. Verify the file was removed from git tracking: `git ls-files config.json` (should return nothing)
429
+ 3. If you used `--no-gitignore`, re-run without that flag
430
+
431
+ To manually fix:
432
+
433
+ ```bash
434
+ echo "config.json" >> .gitignore
435
+ git rm --cached config.json
436
+ ```
437
+
438
+ ## Contributing
439
+
440
+ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for:
441
+
442
+ - Development setup
443
+ - Architecture overview
444
+ - Testing guidelines
445
+ - Code standards
446
+ - How to submit PRs
447
+
448
+ ## License
449
+
450
+ MIT © [JosXa](https://github.com/JosXa)
451
+
452
+ ## Roadmap
453
+
454
+ - [x] JSON support
455
+ - [x] ENV support
456
+ - [x] JSONC support (comments & trailing commas)
457
+ - [x] Git hooks (hooksPath & legacy)
458
+ - [x] Automatic .gitignore management
459
+ - [x] CLI interface
460
+ - [x] Comprehensive tests (81 tests)
461
+ - [x] npm package publication
462
+ - [x] Watch mode for development
463
+ - [ ] YAML support
464
+ - [ ] TOML support
465
+ - [ ] Custom merge strategies
466
+ - [ ] Config file for patterns
467
+ - [ ] Dry-run mode
468
+
469
+ ## Credits
470
+
471
+ Inspired by:
472
+
473
+ - [Husky](https://github.com/typicode/husky) - Git hooks made easy
474
+ - The need for machine-specific configurations across development environments