sticky-note-cli 3.1.11 → 3.1.13
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/bin/cli.js +36 -17
- package/package.json +1 -1
- package/templates/hooks/sticky-utils.js +18 -13
package/bin/cli.js
CHANGED
|
@@ -95,9 +95,8 @@ function resolveHookPaths(_obj, _rootDir) {
|
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
// Detects hook commands in an existing settings.json that
|
|
99
|
-
//
|
|
100
|
-
// machine). Returns the list of stale command strings, or [] if all clean.
|
|
98
|
+
// Detects hook commands in an existing settings.json that are broken or stale.
|
|
99
|
+
// Returns the list of stale command strings, or [] if all clean.
|
|
101
100
|
function findStaleHookPaths(settings) {
|
|
102
101
|
const stale = [];
|
|
103
102
|
const hooks = (settings && settings.hooks) || {};
|
|
@@ -107,9 +106,6 @@ function findStaleHookPaths(settings) {
|
|
|
107
106
|
const cmd = h && h.command;
|
|
108
107
|
if (typeof cmd !== "string") continue;
|
|
109
108
|
// Absolute paths (Unix /Users, /home, /root or Windows C:/, D:/ etc.)
|
|
110
|
-
// inside the hook command are the smoking gun. Match anywhere in the
|
|
111
|
-
// string — the path may be preceded by other tokens (env vars, shell
|
|
112
|
-
// prefixes) and may contain spaces.
|
|
113
109
|
if (
|
|
114
110
|
/["'][A-Za-z]:[\\/]/.test(cmd) ||
|
|
115
111
|
/["']\/(?:Users|home|root|tmp)\//.test(cmd) ||
|
|
@@ -117,12 +113,9 @@ function findStaleHookPaths(settings) {
|
|
|
117
113
|
) {
|
|
118
114
|
stale.push(cmd);
|
|
119
115
|
}
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
// not relative to where .claude/settings.json lives. The fix is to
|
|
124
|
-
// use `npx sticky-note run-hook foo` which walks up to find the hooks.
|
|
125
|
-
if (/node\s+["']\.claude[\\/]hooks[\\/][^"']+\.js["']/.test(cmd)) {
|
|
116
|
+
// Broken `npx sticky-note run-hook X` — npm has no package named "sticky-note"
|
|
117
|
+
// (the package is "sticky-note-cli"). Written by earlier 3.x releases.
|
|
118
|
+
if (/^npx\s+sticky-note\s+run-hook\s+\S+/.test(cmd)) {
|
|
126
119
|
stale.push(cmd);
|
|
127
120
|
}
|
|
128
121
|
}
|
|
@@ -3052,6 +3045,10 @@ function provisionCloudBackend() {
|
|
|
3052
3045
|
if (namespaceId) {
|
|
3053
3046
|
const tomlPath = path.join(serverDir, "wrangler.toml");
|
|
3054
3047
|
let toml = fs.readFileSync(tomlPath, "utf-8");
|
|
3048
|
+
// Reset any previously-written ID back to placeholder first, then patch.
|
|
3049
|
+
// This makes re-runs idempotent even when provisionCloudBackend is called
|
|
3050
|
+
// multiple times in the same init (e.g. after auto-installing wrangler).
|
|
3051
|
+
toml = toml.replace(/id\s*=\s*"[^"]*"/, 'id = "PLACEHOLDER_KV_NAMESPACE_ID"');
|
|
3055
3052
|
toml = toml.replace("PLACEHOLDER_KV_NAMESPACE_ID", namespaceId);
|
|
3056
3053
|
fs.writeFileSync(tomlPath, toml);
|
|
3057
3054
|
print(" [OK] wrangler.toml updated with namespace ID");
|
|
@@ -3073,7 +3070,20 @@ function provisionCloudBackend() {
|
|
|
3073
3070
|
|
|
3074
3071
|
const urlMatch = deployResult.match(/(https:\/\/[^\s]+\.workers\.dev)/);
|
|
3075
3072
|
const workerUrl = urlMatch ? urlMatch[1] : null;
|
|
3076
|
-
|
|
3073
|
+
|
|
3074
|
+
// Reuse an existing API key from .env.sticky if present — prevents divergence
|
|
3075
|
+
// when init is re-run on an already-provisioned repo. Only generate a new key
|
|
3076
|
+
// if there isn't one already.
|
|
3077
|
+
const envPath = path.join(process.cwd(), ".env.sticky");
|
|
3078
|
+
let apiKey = null;
|
|
3079
|
+
try {
|
|
3080
|
+
const existing = fs.readFileSync(envPath, "utf-8");
|
|
3081
|
+
const m = existing.match(/^STICKY_API_KEY=(.+)$/m);
|
|
3082
|
+
if (m && m[1].trim()) apiKey = m[1].trim();
|
|
3083
|
+
} catch (_) { /* no existing .env.sticky */ }
|
|
3084
|
+
if (!apiKey) {
|
|
3085
|
+
apiKey = require("crypto").randomBytes(24).toString("base64url");
|
|
3086
|
+
}
|
|
3077
3087
|
|
|
3078
3088
|
if (workerUrl) {
|
|
3079
3089
|
print(` [OK] Worker deployed: ${workerUrl}`);
|
|
@@ -3081,7 +3091,7 @@ function provisionCloudBackend() {
|
|
|
3081
3091
|
print(" [OK] Worker deployed (URL not detected — check wrangler output)");
|
|
3082
3092
|
}
|
|
3083
3093
|
|
|
3084
|
-
// Step 3: Set API key
|
|
3094
|
+
// Step 3: Set API key on Worker — always sync so Worker and .env.sticky agree
|
|
3085
3095
|
print(" Step 3: Setting API key on Worker...");
|
|
3086
3096
|
let secretSet = false;
|
|
3087
3097
|
try {
|
|
@@ -3098,11 +3108,20 @@ function provisionCloudBackend() {
|
|
|
3098
3108
|
if (workerUrl) print(` Set it manually: echo '${apiKey}' | wrangler secret put STICKY_API_KEY --name ${workerName}`);
|
|
3099
3109
|
}
|
|
3100
3110
|
|
|
3101
|
-
// Write .env.sticky
|
|
3102
|
-
|
|
3103
|
-
|
|
3111
|
+
// Write .env.sticky only after the secret is confirmed set on the Worker,
|
|
3112
|
+
// so the local key always matches what the Worker expects.
|
|
3113
|
+
if (workerUrl && secretSet) {
|
|
3104
3114
|
fs.writeFileSync(envPath, `STICKY_URL=${workerUrl}\nSTICKY_API_KEY=${apiKey}\n`, "utf-8");
|
|
3105
3115
|
print(" [OK] .env.sticky written with STICKY_URL and STICKY_API_KEY");
|
|
3116
|
+
} else if (workerUrl && !secretSet) {
|
|
3117
|
+
// Secret set failed — still write .env.sticky with the key we tried,
|
|
3118
|
+
// and tell the user to set it manually so both sides match.
|
|
3119
|
+
fs.writeFileSync(envPath, `STICKY_URL=${workerUrl}\nSTICKY_API_KEY=${apiKey}\n`, "utf-8");
|
|
3120
|
+
print(" [WARN] .env.sticky written but STICKY_API_KEY was NOT set on the Worker.");
|
|
3121
|
+
print(` Sync manually: echo '${apiKey}' | wrangler secret put STICKY_API_KEY --name ${workerName}`);
|
|
3122
|
+
}
|
|
3123
|
+
|
|
3124
|
+
if (workerUrl) {
|
|
3106
3125
|
|
|
3107
3126
|
// Write sticky_url to committed config so teammates get it on git pull
|
|
3108
3127
|
const configPath = path.join(process.cwd(), ".sticky-note", "sticky-note-config.json");
|
package/package.json
CHANGED
|
@@ -157,13 +157,13 @@ function selfHealHookPaths(settingsPath) {
|
|
|
157
157
|
try { settings = JSON.parse(raw); } catch (_) { return result; }
|
|
158
158
|
if (!settings || !settings.hooks) return result;
|
|
159
159
|
|
|
160
|
-
//
|
|
160
|
+
// Stale patterns that need rewriting to the canonical template format:
|
|
161
161
|
// 1. Absolute paths (written by older sticky-note-cli or copied from another machine)
|
|
162
|
-
// 2.
|
|
163
|
-
//
|
|
164
|
-
//
|
|
162
|
+
// 2. `npx sticky-note run-hook X` — broken: npm has no package named "sticky-note"
|
|
163
|
+
// (the package is "sticky-note-cli"). Written by earlier 3.x releases via the
|
|
164
|
+
// now-removed selfHeal rewrite. Canonical form is `node ".claude/hooks/X.js"`.
|
|
165
165
|
const STALE_ABSOLUTE = /["'][A-Za-z]:[\\/]|["']\/(?:Users|home|root|tmp)\/|\$\(git rev-parse/;
|
|
166
|
-
const
|
|
166
|
+
const STALE_NPX = /^npx\s+sticky-note\s+run-hook\s+(\S+)/;
|
|
167
167
|
// Match the script basename in either quoted or bare form.
|
|
168
168
|
const BASENAME = /([A-Za-z0-9_.-]+)\.(?:js|sh|cjs|mjs)(?:["'`\s]|$)/;
|
|
169
169
|
|
|
@@ -174,12 +174,17 @@ function selfHealHookPaths(settingsPath) {
|
|
|
174
174
|
for (const h of (entry && entry.hooks) || []) {
|
|
175
175
|
const cmd = h && h.command;
|
|
176
176
|
if (typeof cmd !== "string") continue;
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const
|
|
180
|
-
if (
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
let basename = null;
|
|
178
|
+
// Check for broken `npx sticky-note run-hook X` pattern first
|
|
179
|
+
const npxMatch = cmd.match(STALE_NPX);
|
|
180
|
+
if (npxMatch) {
|
|
181
|
+
basename = npxMatch[1];
|
|
182
|
+
} else if (STALE_ABSOLUTE.test(cmd)) {
|
|
183
|
+
const m = cmd.match(BASENAME);
|
|
184
|
+
if (m) basename = m[1];
|
|
185
|
+
}
|
|
186
|
+
if (!basename) continue;
|
|
187
|
+
const newCmd = `node ".claude/hooks/${basename}.js"`;
|
|
183
188
|
result.push({ event, oldCommand: cmd, newCommand: newCmd });
|
|
184
189
|
h.command = newCmd;
|
|
185
190
|
changed = true;
|
|
@@ -192,9 +197,9 @@ function selfHealHookPaths(settingsPath) {
|
|
|
192
197
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
193
198
|
try {
|
|
194
199
|
const summary =
|
|
195
|
-
`[STICKY-NOTE] ⚠️ Detected ${result.length} stale hook
|
|
200
|
+
`[STICKY-NOTE] ⚠️ Detected ${result.length} stale hook command(s) in ` +
|
|
196
201
|
`${path.relative(process.cwd(), settingsPath) || settingsPath} — rewrote to ` +
|
|
197
|
-
`"
|
|
202
|
+
`"node \\".claude/hooks/<name>.js\\"" (canonical form). ` +
|
|
198
203
|
`Commit the change to share the fix with your team.`;
|
|
199
204
|
process.stderr.write(summary + "\n");
|
|
200
205
|
for (const { event, oldCommand, newCommand } of result.slice(0, 5)) {
|