@trendai-crem/claude-skills 0.7.2 → 0.8.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.
Files changed (2) hide show
  1. package/cli.js +68 -25
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -65,15 +65,23 @@ function setupAutoUpdate() {
65
65
  readFileSync(join(__dir, 'package.json'), 'utf8')
66
66
  );
67
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-version-check.json');
72
- const settingsPath = join(claudeDir, 'settings.json');
68
+ const claudeDir = join(homedir(), '.claude');
69
+ const hooksDir = join(claudeDir, 'hooks');
70
+ const cacheDir = join(homedir(), '.cache');
71
+ const installScript = join(hooksDir, 'claude-skills-install-update.sh');
72
+ const notifyScript = join(hooksDir, 'auto-update-claude-skills.sh');
73
+ const installStamp = join(cacheDir, 'claude-skills-install-check.json');
74
+ const notifyStamp = join(cacheDir, 'claude-skills-version-check.json');
75
+ const settingsPath = join(claudeDir, 'settings.json');
73
76
 
74
77
  mkdirSync(hooksDir, { recursive: true });
75
- mkdirSync(join(homedir(), '.cache'), { recursive: true });
76
- writeFileSync(hookScript, buildHookScript(stampFile, installedVersion), { mode: 0o755 });
78
+ mkdirSync(cacheDir, { recursive: true });
79
+
80
+ // SessionStart: auto-install if update available (24h throttle, synchronous)
81
+ writeFileSync(installScript, buildInstallScript(installStamp, installedVersion), { mode: 0o755 });
82
+
83
+ // UserPromptSubmit: notify only if update available (2h throttle)
84
+ writeFileSync(notifyScript, buildNotifyScript(notifyStamp, installedVersion), { mode: 0o755 });
77
85
 
78
86
  // Merge hooks into ~/.claude/settings.json (idempotent)
79
87
  let settings = {};
@@ -89,22 +97,22 @@ function setupAutoUpdate() {
89
97
 
90
98
  settings.hooks ??= {};
91
99
 
92
- // SessionStart — check once at session start
100
+ // SessionStart — auto-install update (24h throttle)
93
101
  settings.hooks.SessionStart ??= [];
94
102
  settings.hooks.SessionStart = settings.hooks.SessionStart.filter(
95
- e => !e.hooks?.some(h => typeof h.command === 'string' && h.command === hookScript)
103
+ e => !e.hooks?.some(h => typeof h.command === 'string' && h.command === installScript)
96
104
  );
97
105
  settings.hooks.SessionStart.push({
98
- hooks: [{ type: 'command', command: hookScript }]
106
+ hooks: [{ type: 'command', command: installScript }]
99
107
  });
100
108
 
101
- // UserPromptSubmit — periodic in-session check (throttled by stamp file)
109
+ // UserPromptSubmit — notify only (2h throttle)
102
110
  settings.hooks.UserPromptSubmit ??= [];
103
111
  settings.hooks.UserPromptSubmit = settings.hooks.UserPromptSubmit.filter(
104
- e => !e.hooks?.some(h => typeof h.command === 'string' && h.command === hookScript)
112
+ e => !e.hooks?.some(h => typeof h.command === 'string' && h.command === notifyScript)
105
113
  );
106
114
  settings.hooks.UserPromptSubmit.push({
107
- hooks: [{ type: 'command', command: hookScript }]
115
+ hooks: [{ type: 'command', command: notifyScript }]
108
116
  });
109
117
 
110
118
  // Atomic write
@@ -112,27 +120,24 @@ function setupAutoUpdate() {
112
120
  writeFileSync(tmpPath, JSON.stringify(settings, null, 2) + '\n');
113
121
  renameSync(tmpPath, settingsPath);
114
122
 
115
- console.log('\n✓ Update-check hooks configured (SessionStart + UserPromptSubmit)');
123
+ console.log('\n✓ Update hooks configured (SessionStart: auto-install, UserPromptSubmit: notify)');
116
124
  }
117
125
 
118
- function buildHookScript(stampFile, installedVersion) {
126
+ function buildInstallScript(stampFile, installedVersion) {
119
127
  if (!/^\d+\.\d+\.\d+(-[\w.]+)?$/.test(installedVersion)) {
120
128
  throw new Error(`Invalid version format in package.json: ${installedVersion}`);
121
129
  }
122
-
123
130
  return `#!/usr/bin/env bash
124
- # claude-skills update check runs at session start and periodically during session.
125
- # If a newer version is available, outputs a systemMessage notification (no auto-install).
131
+ # SessionStart: auto-install claude-skills update if available (24h throttle).
126
132
  set -euo pipefail
127
133
 
128
134
  STAMP="${stampFile}"
129
135
  PACKAGE="@trendai-crem/claude-skills"
130
136
  INSTALLED="${installedVersion}"
131
- MIN_INTERVAL=$((60 * 60 * 2)) # check at most every 2h
137
+ MIN_INTERVAL=$((60 * 60 * 24)) # at most once per 24h
132
138
 
133
139
  mkdir -p "$(dirname "$STAMP")"
134
140
 
135
- # Throttle: skip if checked recently
136
141
  LAST_TS=0
137
142
  if [ -f "$STAMP" ]; then
138
143
  LAST_TS=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1])).get('ts',0))" "$STAMP" 2>/dev/null || echo 0)
@@ -142,18 +147,56 @@ fi
142
147
  NOW=$(date +%s)
143
148
  [ $(( NOW - LAST_TS )) -lt $MIN_INTERVAL ] && exit 0
144
149
 
145
- # Update timestamp
146
150
  python3 -c "import json,sys; json.dump({'ts': int(sys.argv[1])}, open(sys.argv[2],'w'))" "$NOW" "$STAMP"
147
151
 
148
- # Check latest version on npm
149
152
  LATEST=$(npm view "$PACKAGE" version 2>/dev/null || echo "")
150
153
  [ -z "$LATEST" ] && exit 0
151
154
  [ "$LATEST" = "$INSTALLED" ] && exit 0
155
+ [[ "$LATEST" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]] || exit 0
156
+
157
+ # Install update synchronously
158
+ INSTALL_DIR="$(mktemp -d)"
159
+ if npm install --prefix "$INSTALL_DIR" "$PACKAGE@$LATEST" --silent 2>/dev/null \
160
+ && node "$INSTALL_DIR/node_modules/$PACKAGE/cli.js" 2>/dev/null; then
161
+ rm -rf "$INSTALL_DIR"
162
+ python3 -c "import json,sys; print(json.dumps({'systemMessage': 'claude-skills updated: ' + sys.argv[1] + ' \u2192 ' + sys.argv[2]}))" "$INSTALLED" "$LATEST"
163
+ else
164
+ rm -rf "$INSTALL_DIR"
165
+ fi
166
+ `;
167
+ }
168
+
169
+ function buildNotifyScript(stampFile, installedVersion) {
170
+ if (!/^\d+\.\d+\.\d+(-[\w.]+)?$/.test(installedVersion)) {
171
+ throw new Error(`Invalid version format in package.json: ${installedVersion}`);
172
+ }
173
+ return `#!/usr/bin/env bash
174
+ # UserPromptSubmit: notify if claude-skills update available (2h throttle, no auto-install).
175
+ set -euo pipefail
176
+
177
+ STAMP="${stampFile}"
178
+ PACKAGE="@trendai-crem/claude-skills"
179
+ INSTALLED="${installedVersion}"
180
+ MIN_INTERVAL=$((60 * 60 * 2)) # at most every 2h
181
+
182
+ mkdir -p "$(dirname "$STAMP")"
183
+
184
+ LAST_TS=0
185
+ if [ -f "$STAMP" ]; then
186
+ LAST_TS=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1])).get('ts',0))" "$STAMP" 2>/dev/null || echo 0)
187
+ fi
188
+ [[ "$LAST_TS" =~ ^[0-9]+$ ]] || LAST_TS=0
152
189
 
153
- # Validate semver
190
+ NOW=$(date +%s)
191
+ [ $(( NOW - LAST_TS )) -lt $MIN_INTERVAL ] && exit 0
192
+
193
+ python3 -c "import json,sys; json.dump({'ts': int(sys.argv[1])}, open(sys.argv[2],'w'))" "$NOW" "$STAMP"
194
+
195
+ LATEST=$(npm view "$PACKAGE" version 2>/dev/null || echo "")
196
+ [ -z "$LATEST" ] && exit 0
197
+ [ "$LATEST" = "$INSTALLED" ] && exit 0
154
198
  [[ "$LATEST" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]] || exit 0
155
199
 
156
- # Notify via Claude Code systemMessage (shows in UI)
157
- python3 -c "import json,sys; print(json.dumps({'systemMessage': 'claude-skills update: ' + sys.argv[1] + ' \u2192 ' + sys.argv[2] + chr(10) + 'Run: npx @trendai-crem/claude-skills@latest'}))" "$INSTALLED" "$LATEST"
200
+ python3 -c "import json,sys; print(json.dumps({'systemMessage': 'claude-skills update available: ' + sys.argv[1] + ' \u2192 ' + sys.argv[2] + chr(10) + 'Run: npx @trendai-crem/claude-skills@latest'}))" "$INSTALLED" "$LATEST"
158
201
  `;
159
202
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trendai-crem/claude-skills",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "Claude Code skills installer for the trendai-crem team",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {