@trendai-crem/claude-skills 0.4.0 → 0.5.1
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/cli.js +105 -10
- package/package.json +4 -1
package/cli.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { execFileSync } from 'child_process';
|
|
4
|
-
import { readFileSync, readdirSync } from 'fs';
|
|
4
|
+
import { readFileSync, readdirSync, writeFileSync, copyFileSync, mkdirSync, existsSync } from 'fs';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { dirname, join } from 'path';
|
|
7
|
+
import { homedir, tmpdir } from 'os';
|
|
8
|
+
import { renameSync } from 'fs';
|
|
7
9
|
|
|
8
10
|
const __dir = dirname(fileURLToPath(import.meta.url));
|
|
9
11
|
|
|
@@ -55,13 +57,106 @@ if (externalFailed.length > 0) {
|
|
|
55
57
|
console.warn(`\nWARN: ${externalFailed.length} external source(s) failed — team skills installed successfully.`);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const { version:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
// Configure auto-update hook in ~/.claude/settings.json
|
|
61
|
+
setupAutoUpdate();
|
|
62
|
+
|
|
63
|
+
function setupAutoUpdate() {
|
|
64
|
+
const { version: installedVersion } = JSON.parse(
|
|
65
|
+
readFileSync(join(__dir, 'package.json'), 'utf8')
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const claudeDir = join(homedir(), '.claude');
|
|
69
|
+
const hooksDir = join(claudeDir, 'hooks');
|
|
70
|
+
const hookScript = join(hooksDir, 'auto-update-claude-skills.sh');
|
|
71
|
+
const stampFile = join(homedir(), '.cache', 'claude-skills-update.json');
|
|
72
|
+
const settingsPath = join(claudeDir, 'settings.json');
|
|
73
|
+
|
|
74
|
+
// Write the auto-update hook script
|
|
75
|
+
mkdirSync(hooksDir, { recursive: true });
|
|
76
|
+
writeFileSync(hookScript, buildHookScript(stampFile, installedVersion), { mode: 0o755 });
|
|
77
|
+
|
|
78
|
+
// Merge SessionStart hook into ~/.claude/settings.json (idempotent)
|
|
79
|
+
let settings = {};
|
|
80
|
+
if (existsSync(settingsPath)) {
|
|
81
|
+
try {
|
|
82
|
+
settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
83
|
+
} catch (err) {
|
|
84
|
+
// Back up corrupt file rather than silently overwriting
|
|
85
|
+
const backup = `${settingsPath}.bak.${Date.now()}`;
|
|
86
|
+
copyFileSync(settingsPath, backup);
|
|
87
|
+
console.warn(`\nWARN: ~/.claude/settings.json has invalid JSON — backed up to ${backup}`);
|
|
88
|
+
console.warn('A fresh settings file will be created with the auto-update hook only.');
|
|
89
|
+
console.warn('Manually merge your settings from the backup if needed.\n');
|
|
90
|
+
}
|
|
66
91
|
}
|
|
67
|
-
|
|
92
|
+
|
|
93
|
+
settings.hooks ??= {};
|
|
94
|
+
settings.hooks.SessionStart ??= [];
|
|
95
|
+
settings.hooks.SessionStart = settings.hooks.SessionStart.filter(
|
|
96
|
+
e => !e.hooks?.some(h => typeof h.command === 'string' && h.command === hookScript)
|
|
97
|
+
);
|
|
98
|
+
settings.hooks.SessionStart.push({
|
|
99
|
+
hooks: [{ type: 'command', command: hookScript }]
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Atomic write — prevents corruption if process is killed mid-write
|
|
103
|
+
const tmpPath = join(tmpdir(), `claude-settings-${process.pid}.json`);
|
|
104
|
+
writeFileSync(tmpPath, JSON.stringify(settings, null, 2) + '\n');
|
|
105
|
+
renameSync(tmpPath, settingsPath);
|
|
106
|
+
|
|
107
|
+
console.log('\n✓ Auto-update configured (runs daily at session start)');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function buildHookScript(stampFile, installedVersion) {
|
|
111
|
+
// Validate installedVersion is semver before embedding in bash
|
|
112
|
+
if (!/^\d+\.\d+\.\d+(-[\w.]+)?$/.test(installedVersion)) {
|
|
113
|
+
throw new Error(`Invalid version format in package.json: ${installedVersion}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return `#!/usr/bin/env bash
|
|
117
|
+
# Auto-update @trendai-crem/claude-skills at Claude Code session start (max once per 24h).
|
|
118
|
+
set -euo pipefail
|
|
119
|
+
|
|
120
|
+
STAMP="${stampFile}"
|
|
121
|
+
PACKAGE="@trendai-crem/claude-skills"
|
|
122
|
+
MIN_INTERVAL=$((60 * 60 * 24))
|
|
123
|
+
LOG="$(dirname "$STAMP")/claude-skills-update.log"
|
|
124
|
+
|
|
125
|
+
mkdir -p "$(dirname "$STAMP")"
|
|
126
|
+
|
|
127
|
+
# Read stamp using sys.argv to avoid shell injection
|
|
128
|
+
LAST_TS=0
|
|
129
|
+
CURRENT_VER="${installedVersion}"
|
|
130
|
+
if [ -f "$STAMP" ]; then
|
|
131
|
+
LAST_TS=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1])).get('ts',0))" "$STAMP" 2>/dev/null || echo 0)
|
|
132
|
+
CURRENT_VER=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1])).get('version',sys.argv[2]))" "$STAMP" "${installedVersion}" 2>/dev/null || echo "${installedVersion}")
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
# Guard against corrupt stamp values
|
|
136
|
+
[[ "$LAST_TS" =~ ^[0-9]+$ ]] || LAST_TS=0
|
|
137
|
+
|
|
138
|
+
NOW=$(date +%s)
|
|
139
|
+
[ $(( NOW - LAST_TS )) -lt $MIN_INTERVAL ] && exit 0
|
|
140
|
+
|
|
141
|
+
# Write timestamp now to prevent parallel session runs
|
|
142
|
+
python3 -c "import json,sys; json.dump({'ts': int(sys.argv[1]), 'version': sys.argv[2]}, open(sys.argv[3],'w'))" "$NOW" "$CURRENT_VER" "$STAMP"
|
|
143
|
+
|
|
144
|
+
LATEST=$(npm view "$PACKAGE" version 2>/dev/null || echo "")
|
|
145
|
+
{ [ -z "$LATEST" ] || [ "$LATEST" = "$CURRENT_VER" ]; } && exit 0
|
|
146
|
+
|
|
147
|
+
# Validate LATEST is semver before executing
|
|
148
|
+
[[ "$LATEST" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]] || { echo "[$(date -Iseconds)] Invalid version from npm: $LATEST" >> "$LOG"; exit 1; }
|
|
149
|
+
|
|
150
|
+
# Update in background — stamp written only on success
|
|
151
|
+
echo "🔄 Auto-updating claude-skills: $CURRENT_VER → $LATEST"
|
|
152
|
+
(
|
|
153
|
+
echo "[$(date -Iseconds)] Updating $CURRENT_VER → $LATEST" >> "$LOG"
|
|
154
|
+
if npx --yes "${PACKAGE}@${LATEST}" >> "$LOG" 2>&1; then
|
|
155
|
+
python3 -c "import json,sys; json.dump({'ts': int(sys.argv[1]), 'version': sys.argv[2]}, open(sys.argv[3],'w'))" "$NOW" "$LATEST" "$STAMP"
|
|
156
|
+
echo "[$(date -Iseconds)] Update successful" >> "$LOG"
|
|
157
|
+
else
|
|
158
|
+
echo "[$(date -Iseconds)] Update failed — will retry next session" >> "$LOG"
|
|
159
|
+
fi
|
|
160
|
+
) &
|
|
161
|
+
`;
|
|
162
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trendai-crem/claude-skills",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Claude Code skills installer for the trendai-crem team",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
"engines": {
|
|
19
19
|
"node": ">=20"
|
|
20
20
|
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"prepare": "git config core.hooksPath .githooks"
|
|
23
|
+
},
|
|
21
24
|
"dependencies": {
|
|
22
25
|
"skills": "1.4.5"
|
|
23
26
|
}
|