antigravity-seo-kit 1.0.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/utils.js ADDED
@@ -0,0 +1,254 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ // ─── ANSI Colors ────────────────────────────────────────────────────────────
7
+
8
+ const SUPPORTS_COLOR = process.stdout.isTTY && !process.env.NO_COLOR;
9
+
10
+ const colors = {
11
+ reset: SUPPORTS_COLOR ? '\x1b[0m' : '',
12
+ bold: SUPPORTS_COLOR ? '\x1b[1m' : '',
13
+ dim: SUPPORTS_COLOR ? '\x1b[2m' : '',
14
+ red: SUPPORTS_COLOR ? '\x1b[31m' : '',
15
+ green: SUPPORTS_COLOR ? '\x1b[32m' : '',
16
+ yellow: SUPPORTS_COLOR ? '\x1b[33m' : '',
17
+ blue: SUPPORTS_COLOR ? '\x1b[34m' : '',
18
+ magenta: SUPPORTS_COLOR ? '\x1b[35m' : '',
19
+ cyan: SUPPORTS_COLOR ? '\x1b[36m' : '',
20
+ white: SUPPORTS_COLOR ? '\x1b[37m' : '',
21
+ gray: SUPPORTS_COLOR ? '\x1b[90m' : '',
22
+ };
23
+
24
+ function colorize(color, text) {
25
+ return `${colors[color]}${text}${colors.reset}`;
26
+ }
27
+
28
+ // ─── Formatted Output ───────────────────────────────────────────────────────
29
+
30
+ function success(msg) { console.log(`${colorize('green', '✅')} ${msg}`); }
31
+ function error(msg) { console.error(`${colorize('red', '❌')} ${msg}`); }
32
+ function warn(msg) { console.log(`${colorize('yellow', '⚠️')} ${msg}`); }
33
+ function info(msg) { console.log(`${colorize('cyan', 'ℹ️')} ${msg}`); }
34
+ function step(msg) { console.log(`${colorize('blue', '→')} ${msg}`); }
35
+ function file(msg) { console.log(` ${colorize('dim', '📄')} ${colorize('gray', msg)}`); }
36
+ function dir(msg) { console.log(` ${colorize('dim', '📁')} ${colorize('gray', msg)}`); }
37
+
38
+ // ─── Spinner ────────────────────────────────────────────────────────────────
39
+
40
+ const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
41
+
42
+ class Spinner {
43
+ constructor(message) {
44
+ this.message = message;
45
+ this.frameIndex = 0;
46
+ this.interval = null;
47
+ }
48
+
49
+ start() {
50
+ if (!SUPPORTS_COLOR) {
51
+ console.log(`⏳ ${this.message}`);
52
+ return this;
53
+ }
54
+ process.stdout.write('\x1b[?25l'); // hide cursor
55
+ this.interval = setInterval(() => {
56
+ const frame = SPINNER_FRAMES[this.frameIndex % SPINNER_FRAMES.length];
57
+ process.stdout.write(`\r${colorize('cyan', frame)} ${this.message}`);
58
+ this.frameIndex++;
59
+ }, 80);
60
+ return this;
61
+ }
62
+
63
+ succeed(msg) {
64
+ this._stop();
65
+ success(msg || this.message);
66
+ }
67
+
68
+ fail(msg) {
69
+ this._stop();
70
+ error(msg || this.message);
71
+ }
72
+
73
+ _stop() {
74
+ if (this.interval) {
75
+ clearInterval(this.interval);
76
+ this.interval = null;
77
+ }
78
+ if (SUPPORTS_COLOR) {
79
+ process.stdout.write('\r\x1b[K'); // clear line
80
+ process.stdout.write('\x1b[?25h'); // show cursor
81
+ }
82
+ }
83
+ }
84
+
85
+ function spinner(message) {
86
+ return new Spinner(message);
87
+ }
88
+
89
+ // ─── File Operations ────────────────────────────────────────────────────────
90
+
91
+ /**
92
+ * Recursively copy a directory, merging with existing content.
93
+ * Does not overwrite existing files unless `overwrite` is true.
94
+ */
95
+ function copyRecursive(src, dest, { overwrite = false, fileCallback = null } = {}) {
96
+ if (!fs.existsSync(src)) return 0;
97
+
98
+ let count = 0;
99
+
100
+ if (fs.statSync(src).isDirectory()) {
101
+ fs.mkdirSync(dest, { recursive: true });
102
+ const entries = fs.readdirSync(src);
103
+ for (const entry of entries) {
104
+ count += copyRecursive(
105
+ path.join(src, entry),
106
+ path.join(dest, entry),
107
+ { overwrite, fileCallback }
108
+ );
109
+ }
110
+ } else {
111
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
112
+ if (overwrite || !fs.existsSync(dest)) {
113
+ fs.copyFileSync(src, dest);
114
+ count = 1;
115
+ if (fileCallback) fileCallback(dest);
116
+ }
117
+ }
118
+
119
+ return count;
120
+ }
121
+
122
+ /**
123
+ * Recursively remove a directory and all its contents.
124
+ */
125
+ function removeRecursive(target) {
126
+ if (!fs.existsSync(target)) return 0;
127
+
128
+ let count = 0;
129
+
130
+ if (fs.statSync(target).isDirectory()) {
131
+ const entries = fs.readdirSync(target);
132
+ for (const entry of entries) {
133
+ count += removeRecursive(path.join(target, entry));
134
+ }
135
+ fs.rmdirSync(target);
136
+ } else {
137
+ fs.unlinkSync(target);
138
+ count = 1;
139
+ }
140
+
141
+ return count;
142
+ }
143
+
144
+ /**
145
+ * Count files in a directory recursively.
146
+ */
147
+ function countFiles(dir) {
148
+ if (!fs.existsSync(dir)) return 0;
149
+ let count = 0;
150
+ if (fs.statSync(dir).isDirectory()) {
151
+ for (const entry of fs.readdirSync(dir)) {
152
+ count += countFiles(path.join(dir, entry));
153
+ }
154
+ } else {
155
+ count = 1;
156
+ }
157
+ return count;
158
+ }
159
+
160
+ // ─── License Key Validation ────────────────────────────────────────────────
161
+
162
+ const LICENSE_KEY_REGEX = /^SK-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/;
163
+
164
+ function isValidKeyFormat(key) {
165
+ return LICENSE_KEY_REGEX.test(key);
166
+ }
167
+
168
+ // ─── Banner ─────────────────────────────────────────────────────────────────
169
+
170
+ const BANNER = `
171
+ ${colorize('cyan', '╔═══════════════════════════════════════════════════════╗')}
172
+ ${colorize('cyan', '║')} ${colorize('bold', '🔍 SEO Kit for Google Antigravity')} ${colorize('cyan', '║')}
173
+ ${colorize('cyan', '║')} ${colorize('dim', 'v1.0.0 — Professional SEO Analysis Toolkit')} ${colorize('cyan', '║')}
174
+ ${colorize('cyan', '╚═══════════════════════════════════════════════════════╝')}
175
+ `;
176
+
177
+ function showBanner() {
178
+ console.log(BANNER);
179
+ }
180
+
181
+ // ─── Help ───────────────────────────────────────────────────────────────────
182
+
183
+ function showHelp() {
184
+ showBanner();
185
+ console.log(`${colorize('bold', 'Usage:')} npx antigravity-seo-kit <command> [options]`);
186
+ console.log('');
187
+ console.log(`${colorize('bold', 'Commands:')}`);
188
+ console.log(` ${colorize('green', 'install')} --key=SK-XXXX-XXXX-XXXX Install SEO Kit into current workspace`);
189
+ console.log(` ${colorize('green', 'update')} Update to latest version`);
190
+ console.log(` ${colorize('green', 'uninstall')} Remove SEO Kit from workspace`);
191
+ console.log(` ${colorize('green', 'status')} Show license & installation info`);
192
+ console.log(` ${colorize('green', 'devices')} List activated devices`);
193
+ console.log(` ${colorize('green', 'devices remove')} <deviceId> Remove a device from license`);
194
+ console.log('');
195
+ console.log(`${colorize('bold', 'Examples:')}`);
196
+ console.log(` ${colorize('gray', 'npx antigravity-seo-kit install --key=SK-A1B2-C3D4-E5F6')}`);
197
+ console.log(` ${colorize('gray', 'npx antigravity-seo-kit devices')}`);
198
+ console.log(` ${colorize('gray', 'npx antigravity-seo-kit devices remove a1b2c3d4')}`);
199
+ console.log('');
200
+ console.log(`${colorize('bold', 'Purchase:')} https://antigravityseokit.solann.io/`);
201
+ console.log('');
202
+ }
203
+
204
+ // ─── Config File ────────────────────────────────────────────────────────────
205
+
206
+ const LICENSE_FILE = '.seo-kit-license';
207
+
208
+ function readLicenseFile(cwd) {
209
+ const licensePath = path.join(cwd, LICENSE_FILE);
210
+ if (!fs.existsSync(licensePath)) return null;
211
+ try {
212
+ return JSON.parse(fs.readFileSync(licensePath, 'utf-8'));
213
+ } catch {
214
+ return null;
215
+ }
216
+ }
217
+
218
+ function writeLicenseFile(cwd, data) {
219
+ const licensePath = path.join(cwd, LICENSE_FILE);
220
+ fs.writeFileSync(licensePath, JSON.stringify(data, null, 2), 'utf-8');
221
+ }
222
+
223
+ function removeLicenseFile(cwd) {
224
+ const licensePath = path.join(cwd, LICENSE_FILE);
225
+ if (fs.existsSync(licensePath)) {
226
+ fs.unlinkSync(licensePath);
227
+ }
228
+ }
229
+
230
+ // ─── Exports ────────────────────────────────────────────────────────────────
231
+
232
+ module.exports = {
233
+ colors,
234
+ colorize,
235
+ success,
236
+ error,
237
+ warn,
238
+ info,
239
+ step,
240
+ file,
241
+ dir,
242
+ spinner,
243
+ copyRecursive,
244
+ removeRecursive,
245
+ countFiles,
246
+ isValidKeyFormat,
247
+ showBanner,
248
+ showHelp,
249
+ readLicenseFile,
250
+ writeLicenseFile,
251
+ removeLicenseFile,
252
+ LICENSE_FILE,
253
+ PACKAGE_VERSION: '1.0.0',
254
+ };
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "antigravity-seo-kit",
3
+ "version": "1.0.0",
4
+ "description": "Professional SEO Analysis Toolkit for Google Antigravity AI Agent — 44 specialized skills covering technical audit, E-E-A-T, schema, GEO, local SEO & more",
5
+ "main": "lib/installer.js",
6
+ "bin": {
7
+ "antigravity-seo-kit": "bin/cli.js"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "lib/"
12
+ ],
13
+ "keywords": [
14
+ "seo",
15
+ "antigravity",
16
+ "antigravity-kit",
17
+ "antigravity-seo-kit",
18
+ "google-antigravity",
19
+ "ai-agent",
20
+ "seo-geo",
21
+ "seo-audit",
22
+ "seo-toolkit",
23
+ "agent-skills",
24
+ "seo-analysis",
25
+ "technical-seo",
26
+ "eeat"
27
+ ],
28
+ "author": "Antigravity SEO Kit",
29
+ "license": "SEE LICENSE IN LICENSE",
30
+ "homepage": "https://antigravityseokit.solann.io/",
31
+ "engines": {
32
+ "node": ">=18"
33
+ }
34
+ }