@hardlydifficult/shared-config 0.0.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/README.md +64 -0
- package/dist/postinstall.d.ts +3 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +80 -0
- package/dist/postinstall.js.map +1 -0
- package/files/.claude/.gitkeep +0 -0
- package/files/.github/dependabot.yml +13 -0
- package/package.json +18 -0
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# @hardlydifficult/shared-config
|
|
2
|
+
|
|
3
|
+
Shared configuration files synced to consuming repos via a `postinstall` hook.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -D @hardlydifficult/shared-config
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## What Gets Synced
|
|
12
|
+
|
|
13
|
+
| Path | Strategy | Details |
|
|
14
|
+
|------|----------|---------|
|
|
15
|
+
| `.gitignore` | Overwrite | Shared config is authoritative |
|
|
16
|
+
| `.github/dependabot.yml` | Overwrite | Shared config is authoritative |
|
|
17
|
+
| `.claude/` | Merge | Shared files overwrite, local additions preserved |
|
|
18
|
+
|
|
19
|
+
## How It Works
|
|
20
|
+
|
|
21
|
+
The package has a `postinstall` hook that runs automatically on `npm install`. It copies the bundled shared files into the consuming repo's root directory using the strategies listed above.
|
|
22
|
+
|
|
23
|
+
No manual steps required after installation. Every `npm install` re-syncs the files.
|
|
24
|
+
|
|
25
|
+
## Updating
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Re-sync with the currently installed version
|
|
29
|
+
npm install
|
|
30
|
+
|
|
31
|
+
# Bump to the latest published version
|
|
32
|
+
npm install @hardlydifficult/shared-config@latest
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Both commands trigger the `postinstall` hook, which re-syncs all shared files.
|
|
36
|
+
|
|
37
|
+
## Skill Repos
|
|
38
|
+
|
|
39
|
+
`skill-repos.json` lists external GitHub repos (in `owner/repo` format) used as skill sources:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
[
|
|
43
|
+
"some-org/some-repo",
|
|
44
|
+
"another-org/another-repo"
|
|
45
|
+
]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Pull the latest skills from those repos into the local `.claude/` directory:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx sync-skills
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
This fetches skills via the GitHub API. It runs in the monorepo only and is not published to npm.
|
|
55
|
+
|
|
56
|
+
## Local .claude/ Files
|
|
57
|
+
|
|
58
|
+
The `.claude/` merge strategy means any files you add locally are preserved across syncs. Only files that exist in the shared config are overwritten.
|
|
59
|
+
|
|
60
|
+
To see which `.claude/` files are local additions (not from the shared config):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx log-local-skills
|
|
64
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postinstall.d.ts","sourceRoot":"","sources":["../src/postinstall.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
function findRepoRoot() {
|
|
7
|
+
// INIT_CWD is set by npm to the directory where npm install was run
|
|
8
|
+
if (process.env.INIT_CWD !== undefined && process.env.INIT_CWD !== "") {
|
|
9
|
+
return process.env.INIT_CWD;
|
|
10
|
+
}
|
|
11
|
+
// Fallback: walk up from our location past node_modules
|
|
12
|
+
let dir = __dirname;
|
|
13
|
+
while (dir !== (0, path_1.dirname)(dir)) {
|
|
14
|
+
if (dir.endsWith("node_modules")) {
|
|
15
|
+
return (0, path_1.dirname)(dir);
|
|
16
|
+
}
|
|
17
|
+
dir = (0, path_1.dirname)(dir);
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
function findFilesDir() {
|
|
22
|
+
// When installed from npm: files/ is a sibling of dist/
|
|
23
|
+
const fromDist = (0, path_1.join)(__dirname, "..", "files");
|
|
24
|
+
if ((0, fs_1.existsSync)(fromDist)) {
|
|
25
|
+
return fromDist;
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
function copyDirMerge(src, dest) {
|
|
30
|
+
if (!(0, fs_1.existsSync)(dest)) {
|
|
31
|
+
(0, fs_1.mkdirSync)(dest, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
for (const entry of (0, fs_1.readdirSync)(src)) {
|
|
34
|
+
const srcPath = (0, path_1.join)(src, entry);
|
|
35
|
+
const destPath = (0, path_1.join)(dest, entry);
|
|
36
|
+
const stat = (0, fs_1.statSync)(srcPath);
|
|
37
|
+
if (stat.isDirectory()) {
|
|
38
|
+
copyDirMerge(srcPath, destPath);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
(0, fs_1.copyFileSync)(srcPath, destPath);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function copyFileWithDir(src, dest) {
|
|
46
|
+
const destDir = (0, path_1.dirname)(dest);
|
|
47
|
+
if (!(0, fs_1.existsSync)(destDir)) {
|
|
48
|
+
(0, fs_1.mkdirSync)(destDir, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
(0, fs_1.copyFileSync)(src, dest);
|
|
51
|
+
}
|
|
52
|
+
function main() {
|
|
53
|
+
const repoRoot = findRepoRoot();
|
|
54
|
+
if (repoRoot === null) {
|
|
55
|
+
// Can't determine repo root, skip silently
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const filesDir = findFilesDir();
|
|
59
|
+
if (filesDir === null) {
|
|
60
|
+
// No files directory found (probably in development), skip silently
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Copy .gitignore (overwrite - shared config is authoritative)
|
|
64
|
+
const gitignoreSrc = (0, path_1.join)(filesDir, ".gitignore");
|
|
65
|
+
if ((0, fs_1.existsSync)(gitignoreSrc)) {
|
|
66
|
+
copyFileWithDir(gitignoreSrc, (0, path_1.join)(repoRoot, ".gitignore"));
|
|
67
|
+
}
|
|
68
|
+
// Copy .github/dependabot.yml (overwrite - shared config is authoritative)
|
|
69
|
+
const dependabotSrc = (0, path_1.join)(filesDir, ".github", "dependabot.yml");
|
|
70
|
+
if ((0, fs_1.existsSync)(dependabotSrc)) {
|
|
71
|
+
copyFileWithDir(dependabotSrc, (0, path_1.join)(repoRoot, ".github", "dependabot.yml"));
|
|
72
|
+
}
|
|
73
|
+
// Merge .claude/ (additive only - never delete local files)
|
|
74
|
+
const claudeSrc = (0, path_1.join)(filesDir, ".claude");
|
|
75
|
+
if ((0, fs_1.existsSync)(claudeSrc)) {
|
|
76
|
+
copyDirMerge(claudeSrc, (0, path_1.join)(repoRoot, ".claude"));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
main();
|
|
80
|
+
//# sourceMappingURL=postinstall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postinstall.js","sourceRoot":"","sources":["../src/postinstall.ts"],"names":[],"mappings":"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"}
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: npm
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
open-pull-requests-limit: 10
|
|
8
|
+
versioning-strategy: increase
|
|
9
|
+
- package-ecosystem: github-actions
|
|
10
|
+
directory: /
|
|
11
|
+
schedule:
|
|
12
|
+
interval: weekly
|
|
13
|
+
open-pull-requests-limit: 5
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hardlydifficult/shared-config",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"build": "tsc",
|
|
6
|
+
"clean": "rm -rf dist",
|
|
7
|
+
"lint": "tsc --noEmit",
|
|
8
|
+
"postinstall": "node -e \"try{require('./dist/postinstall.js')}catch{}\""
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"files"
|
|
13
|
+
],
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/node": "20.19.31",
|
|
16
|
+
"typescript": "5.8.3"
|
|
17
|
+
}
|
|
18
|
+
}
|