antigravity-seo-kit 2.0.1 → 2.1.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/lib/installer.js CHANGED
@@ -514,7 +514,7 @@ function setupWorkspace(cwd) {
514
514
  const localAgentDir = path.join(cwd, '.agent');
515
515
 
516
516
  if (fs.existsSync(localAgentDir)) {
517
- return;
517
+ info('Existing .agent directory found. Re-synchronizing and updating files...');
518
518
  }
519
519
 
520
520
  if (!fs.existsSync(globalDir)) {
@@ -529,7 +529,7 @@ function setupWorkspace(cwd) {
529
529
 
530
530
  // Only copy necessary directories. agents and rules are loaded globally via the plugin.
531
531
  // skills are copied but filtered to exclude .md files to save space and avoid duplicate prompts/instructions.
532
- const directoriesToCopy = ['.shared', 'config', 'dashboard', 'docs', 'scripts', 'workflows'];
532
+ const directoriesToCopy = ['.shared', 'config', 'dashboard', 'docs', 'scripts', 'workflows', 'skills', 'mcp-server'];
533
533
  const filesToCopy = ['seo-architecture.md'];
534
534
 
535
535
  let count = 0;
@@ -544,7 +544,7 @@ function setupWorkspace(cwd) {
544
544
  filter: (filePath) => !filePath.endsWith('.md')
545
545
  });
546
546
  } else if (dir === 'config') {
547
- count += copyRecursive(src, dest, { overwrite: true, mergeJson: true });
547
+ count += copyRecursive(src, dest, { overwrite: true });
548
548
  } else {
549
549
  count += copyRecursive(src, dest, { overwrite: true });
550
550
  }
package/lib/utils.js CHANGED
@@ -156,6 +156,46 @@ function smartMergeJsonFile(srcPath, destPath) {
156
156
  fs.writeFileSync(destPath, JSON.stringify(merged, null, 2), 'utf-8');
157
157
  }
158
158
 
159
+ /**
160
+ * Detects if a JSON file contains actual custom API keys, secrets, or tokens that are not defaults/placeholders.
161
+ */
162
+ function isJsonWithApiKey(filePath) {
163
+ if (!fs.existsSync(filePath)) return false;
164
+ try {
165
+ const content = fs.readFileSync(filePath, 'utf-8');
166
+ // Fast path: if it doesn't contain potential key/token/secret terms, skip
167
+ if (!/key|token|secret|password|credential|license/i.test(content)) {
168
+ return false;
169
+ }
170
+ const json = JSON.parse(content);
171
+
172
+ // Recursive check for custom secrets
173
+ function hasSecret(obj) {
174
+ if (typeof obj !== 'object' || obj === null) return false;
175
+ for (const k of Object.keys(obj)) {
176
+ const val = obj[k];
177
+ if (typeof val === 'string') {
178
+ const lowerK = k.toLowerCase();
179
+ if (/key|token|secret|password|credential|license/i.test(lowerK)) {
180
+ // Check if it's not a placeholder
181
+ const isPlaceholder = /YOUR_.*_HERE|ENTER_.*_HERE|PLACEHOLDER|sk-[xX]+-[xX]+-[xX]+/i.test(val);
182
+ if (val.trim() !== '' && !isPlaceholder) {
183
+ return true;
184
+ }
185
+ }
186
+ } else if (typeof val === 'object') {
187
+ if (hasSecret(val)) return true;
188
+ }
189
+ }
190
+ return false;
191
+ }
192
+
193
+ return hasSecret(json);
194
+ } catch (err) {
195
+ return false;
196
+ }
197
+ }
198
+
159
199
  /**
160
200
  * Recursively copy a directory, merging with existing content.
161
201
  * Does not overwrite existing files unless `overwrite` is true.
@@ -180,7 +220,12 @@ function copyRecursive(src, dest, { overwrite = false, fileCallback = null, filt
180
220
  } else {
181
221
  fs.mkdirSync(path.dirname(dest), { recursive: true });
182
222
  const isJson = src.endsWith('.json');
183
- if (isJson && mergeJson && fs.existsSync(dest)) {
223
+ if (isJson && fs.existsSync(dest) && isJsonWithApiKey(dest)) {
224
+ // Safely merge JSON files containing real user API keys instead of overwriting them
225
+ smartMergeJsonFile(src, dest);
226
+ count = 1;
227
+ if (fileCallback) fileCallback(dest);
228
+ } else if (isJson && mergeJson && fs.existsSync(dest)) {
184
229
  smartMergeJsonFile(src, dest);
185
230
  count = 1;
186
231
  if (fileCallback) fileCallback(dest);
@@ -245,7 +290,7 @@ function isValidKeyFormat(key) {
245
290
  const BANNER = `
246
291
  ${colorize('cyan', '╔═══════════════════════════════════════════════════════╗')}
247
292
  ${colorize('cyan', '║')} ${colorize('bold', '🔍 SEO Kit for Google Antigravity')} ${colorize('cyan', '║')}
248
- ${colorize('cyan', '║')} ${colorize('dim', 'v2.0.1 — Professional Agentic SEO Platform')} ${colorize('cyan', '║')}
293
+ ${colorize('cyan', '║')} ${colorize('dim', 'v2.1.0 — Professional Agentic SEO Platform')} ${colorize('cyan', '║')}
249
294
  ${colorize('cyan', '╚═══════════════════════════════════════════════════════╝')}
250
295
  `;
251
296
 
@@ -373,7 +418,8 @@ module.exports = {
373
418
  writeLicenseFile,
374
419
  removeLicenseFile,
375
420
  LICENSE_FILE,
376
- PACKAGE_VERSION: '2.0.1',
421
+ PACKAGE_VERSION: '2.1.0',
377
422
  deepMergeJson,
378
423
  smartMergeJsonFile,
424
+ isJsonWithApiKey,
379
425
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antigravity-seo-kit",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "Professional Agentic SEO Platform for Google Antigravity 2 AI Agent — 44 specialized skills covering technical audit, E-E-A-T, schema, GEO, local SEO & more",
5
5
  "main": "lib/installer.js",
6
6
  "bin": {