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 +3 -3
- package/lib/utils.js +49 -3
- package/package.json +1 -1
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
|
-
|
|
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
|
|
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 &&
|
|
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
|
|
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
|
|
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
|
|
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": {
|