@leejungkiin/awkit 1.6.3 → 1.6.5

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.
@@ -0,0 +1,253 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * AWK Harvest Script — Phase 1 Migration
4
+ * Pulls all workflows, skills, and GEMINI.md from the live ~/.gemini/antigravity/
5
+ * into main-awf/ so that main-awf becomes the Single Source of Truth.
6
+ *
7
+ * Usage: node scripts/harvest.js [--dry-run]
8
+ * Created by Kien AI
9
+ */
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const os = require('os');
14
+
15
+ const HOME = os.homedir();
16
+ const AWK_ROOT = path.join(__dirname, '..');
17
+ const ANTIGRAVITY = path.join(HOME, '.gemini', 'antigravity');
18
+ const GEMINI_MD_SRC = path.join(HOME, '.gemini', 'GEMINI.md');
19
+
20
+ const DRY_RUN = process.argv.includes('--dry-run');
21
+
22
+ // ─── Colors ───────────────────────────────────────────────────────────────────
23
+ const C = {
24
+ reset: '\x1b[0m', red: '\x1b[31m', green: '\x1b[32m',
25
+ yellow: '\x1b[33m', cyan: '\x1b[36m', gray: '\x1b[90m', bold: '\x1b[1m',
26
+ };
27
+ const ok = (m) => console.log(`${C.green}✅ ${m}${C.reset}`);
28
+ const warn = (m) => console.log(`${C.yellow}⚠️ ${m}${C.reset}`);
29
+ const info = (m) => console.log(`${C.cyan}ℹ️ ${m}${C.reset}`);
30
+ const dim = (m) => console.log(`${C.gray} ${m}${C.reset}`);
31
+ const err = (m) => console.log(`${C.red}❌ ${m}${C.reset}`);
32
+ const head = (m) => console.log(`\n${C.cyan}${C.bold}── ${m} ──${C.reset}`);
33
+
34
+ // ─── Workflow Category Map ─────────────────────────────────────────────────────
35
+ // Maps workflow filename → destination category folder
36
+ const WORKFLOW_CATEGORIES = {
37
+ // Lifecycle
38
+ 'brainstorm.md': 'lifecycle', 'plan.md': 'lifecycle', 'planExpert.md': 'expert',
39
+ 'code.md': 'lifecycle', 'codeExpert.md': 'expert', 'debug.md': 'lifecycle',
40
+ 'debugExpert.md': 'expert', 'test.md': 'lifecycle', 'deploy.md': 'lifecycle',
41
+ 'refactor.md': 'lifecycle', 'init.md': 'lifecycle', 'run.md': 'lifecycle',
42
+ 'migration.md': 'lifecycle', 'hotfix.md': 'git',
43
+ // Context & Memory
44
+ 'recap.md': 'context', 'next.md': 'context', 'save-brain.md': 'context',
45
+ 'codebase-sync.md': 'context', 'auto-execution-workflow.md': 'context',
46
+ 'auto-implement.md': 'context',
47
+ // Quality
48
+ 'audit.md': 'quality', 'performance-audit.md': 'quality', 'ux-audit.md': 'quality',
49
+ 'code-quality-rules.md': 'quality', 'accessibility-audit.md': 'quality',
50
+ 'project-audit.md': 'quality', 'ui-review.md': 'quality', 'visual-debug.md': 'quality',
51
+ 'bug-hunter.md': 'quality', 'code-janitor.md': 'quality', 'self-healing-test.md': 'quality',
52
+ // UI/UX
53
+ 'visualize.md': 'ui', 'design-to-ui.md': 'ui', 'ui-first-methodology.md': 'ui',
54
+ 'app-screen-analyzer.md': 'ui', 'create-feature.md': 'ui', 'feature-completion.md': 'ui',
55
+ 'create-spec-architect.md': 'ui',
56
+ // Ads
57
+ 'ads-audit.md': 'ads', 'ads-optimize.md': 'ads', 'adsExpert.md': 'ads',
58
+ 'ads-analyst.md': 'ads', 'ads-targeting.md': 'ads', 'admob.md': 'ads',
59
+ 'smali-ads-config.md': 'ads', 'smali-ads-flow.md': 'ads',
60
+ 'smali-ads-interstitial.md': 'ads', 'smali-ads-native.md': 'ads',
61
+ // Mobile
62
+ 'maestro-qa-workflow.md': 'mobile', 'maestro-test-workflow.md': 'mobile',
63
+ 'turbo-mobile-build.md': 'mobile', 'app-analysis.md': 'mobile',
64
+ 'structure-clean-architect.md': 'mobile',
65
+ // Git
66
+ 'git-commit-workflow.md': 'git', 'smart-git-ops.md': 'git', 'rollback.md': 'git',
67
+ 'release-notes.md': 'git', 'cloudflare-tunnel.md': 'git',
68
+ // Roles
69
+ 'tech-lead-workflow.md': 'roles', 'product-manager-workflow.md': 'roles',
70
+ 'qa-engineer-workflow.md': 'roles', 'ui-ux-designer-workflow.md': 'roles',
71
+ 'vibe-coding-master-workflow.md': 'roles', 'oracle.md': 'roles',
72
+ // Meta / Config
73
+ 'customize.md': 'meta', 'base-rules.md': 'meta', 'file-protection-rules.md': 'meta',
74
+ 'project-identity-enforcement.md': 'meta', 'help.html': 'meta',
75
+ // Workflows & Logic
76
+ 'plan.md': 'lifecycle', 'logic-reasoning-workflow.md': 'context',
77
+ 'user-intent-analysis-workflow.md': 'context', 'master-code-workflow.md': 'lifecycle',
78
+ };
79
+
80
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
81
+ function ensureDir(dirPath) {
82
+ if (!fs.existsSync(dirPath)) {
83
+ if (!DRY_RUN) fs.mkdirSync(dirPath, { recursive: true });
84
+ }
85
+ }
86
+
87
+ function copyFile(src, dest, label) {
88
+ if (!fs.existsSync(src)) { warn(`Not found: ${label || path.basename(src)}`); return false; }
89
+ ensureDir(path.dirname(dest));
90
+ if (!DRY_RUN) fs.copyFileSync(src, dest);
91
+ dim(`${DRY_RUN ? '[DRY] ' : ''}${label || path.basename(src)}`);
92
+ return true;
93
+ }
94
+
95
+ function copyDirRecursive(src, dest) {
96
+ if (!fs.existsSync(src)) return 0;
97
+ ensureDir(dest);
98
+ let count = 0;
99
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
100
+ if (entry.name === '.DS_Store') continue;
101
+ if (entry.name === '.git') continue;
102
+ if (entry.name === '__pycache__') continue;
103
+ if (entry.name === 'node_modules') continue;
104
+ if (entry.name === '.venv') continue;
105
+ const srcPath = path.join(src, entry.name);
106
+ const destPath = path.join(dest, entry.name);
107
+ if (entry.isDirectory()) {
108
+ count += copyDirRecursive(srcPath, destPath);
109
+ } else {
110
+ if (!DRY_RUN) fs.copyFileSync(srcPath, destPath);
111
+ count++;
112
+ }
113
+ }
114
+ return count;
115
+ }
116
+
117
+ // ─── Main Harvest ─────────────────────────────────────────────────────────────
118
+ async function harvest() {
119
+ console.log('');
120
+ console.log(`${C.cyan}${C.bold}╔══════════════════════════════════════════════════════════╗${C.reset}`);
121
+ console.log(`${C.cyan}${C.bold}║ 🌾 AWK Harvest — Pulling from ~/.gemini/antigravity/ ║${C.reset}`);
122
+ console.log(`${C.cyan}${C.bold}╚══════════════════════════════════════════════════════════╝${C.reset}`);
123
+ if (DRY_RUN) warn('DRY RUN MODE — No files will be written');
124
+ console.log('');
125
+
126
+ // Verify source exists
127
+ if (!fs.existsSync(ANTIGRAVITY)) {
128
+ err(`Source not found: ${ANTIGRAVITY}`);
129
+ process.exit(1);
130
+ }
131
+
132
+ const stats = { workflows: 0, skills: 0, misc: 0 };
133
+
134
+ // ── 1. Harvest GEMINI.md ──────────────────────────────────────────────────
135
+ head('GEMINI.md');
136
+ if (fs.existsSync(GEMINI_MD_SRC)) {
137
+ const destGemini = path.join(AWK_ROOT, 'core', 'GEMINI.md');
138
+ // Backup existing
139
+ if (fs.existsSync(destGemini)) {
140
+ const bak = destGemini + '.bak';
141
+ if (!DRY_RUN) fs.copyFileSync(destGemini, bak);
142
+ dim(`Backed up existing → core/GEMINI.md.bak`);
143
+ }
144
+ copyFile(GEMINI_MD_SRC, destGemini, 'GEMINI.md → core/GEMINI.md');
145
+ ok('GEMINI.md harvested');
146
+ stats.misc++;
147
+ } else {
148
+ warn('GEMINI.md not found at ~/.gemini/GEMINI.md');
149
+ }
150
+
151
+ // ── 2. Harvest Workflows ──────────────────────────────────────────────────
152
+ head('Workflows (77 files → categorized)');
153
+ const wfSrc = path.join(ANTIGRAVITY, 'global_workflows');
154
+
155
+ if (!fs.existsSync(wfSrc)) {
156
+ err(`global_workflows not found: ${wfSrc}`);
157
+ } else {
158
+ const files = fs.readdirSync(wfSrc).filter(f => f.endsWith('.md') || f.endsWith('.html'));
159
+ let categorized = 0, uncategorized = 0;
160
+
161
+ for (const file of files) {
162
+ // Skip AGENTS.md — handled separately
163
+ if (file === 'AGENTS.md') continue;
164
+
165
+ const srcFile = path.join(wfSrc, file);
166
+ const category = WORKFLOW_CATEGORIES[file] || '_uncategorized';
167
+
168
+ if (!WORKFLOW_CATEGORIES[file]) {
169
+ uncategorized++;
170
+ dim(`→ _uncategorized/${file}`);
171
+ } else {
172
+ categorized++;
173
+ }
174
+
175
+ const destFile = path.join(AWK_ROOT, 'workflows', category, file);
176
+ copyFile(srcFile, destFile, `${file} → workflows/${category}/`);
177
+ stats.workflows++;
178
+ }
179
+
180
+ ok(`${stats.workflows} workflow files harvested (${categorized} categorized, ${uncategorized} → _uncategorized)`);
181
+ }
182
+
183
+ // ── 3. Harvest Skills ─────────────────────────────────────────────────────
184
+ head('Skills');
185
+ const skillSrc = path.join(ANTIGRAVITY, 'skills');
186
+
187
+ if (!fs.existsSync(skillSrc)) {
188
+ warn('skills/ not found in antigravity');
189
+ } else {
190
+ const skillDirs = fs.readdirSync(skillSrc, { withFileTypes: true })
191
+ .filter(d => d.isDirectory() && d.name !== '.DS_Store');
192
+
193
+ for (const skillDir of skillDirs) {
194
+ const src = path.join(skillSrc, skillDir.name);
195
+ const dest = path.join(AWK_ROOT, 'skills', skillDir.name);
196
+ const count = copyDirRecursive(src, dest);
197
+ dim(`${skillDir.name}/ (${count} files)`);
198
+ stats.skills++;
199
+ }
200
+
201
+ ok(`${stats.skills} skills harvested`);
202
+ }
203
+
204
+ // ── 4. Harvest brain/ambient-brain skill (special case in main-awf) ───────
205
+ head('Special Skills from main-awf legacy');
206
+ const ambientBrainSrc = path.join(AWK_ROOT, 'skills', 'ambient-brain');
207
+ if (fs.existsSync(ambientBrainSrc)) {
208
+ // Rename ambient-brain → memory-sync if memory-sync not already there from harvest
209
+ const memorySyncDest = path.join(AWK_ROOT, 'skills', 'memory-sync');
210
+ if (!fs.existsSync(memorySyncDest)) {
211
+ if (!DRY_RUN) fs.renameSync(ambientBrainSrc, memorySyncDest);
212
+ ok('ambient-brain → memory-sync (renamed)');
213
+ } else {
214
+ dim('memory-sync already exists (from harvest), ambient-brain kept for reference');
215
+ }
216
+ }
217
+
218
+ // ── 5. Harvest AGENTS.md ──────────────────────────────────────────────────
219
+ head('AGENTS.md');
220
+ const agentsSrc = path.join(ANTIGRAVITY, 'global_workflows', 'AGENTS.md');
221
+ if (fs.existsSync(agentsSrc)) {
222
+ copyFile(agentsSrc, path.join(AWK_ROOT, 'core', 'AGENTS.md'), 'AGENTS.md → core/AGENTS.md');
223
+ ok('AGENTS.md harvested');
224
+ stats.misc++;
225
+ }
226
+
227
+ // ── 6. Harvest schemas & templates ────────────────────────────────────────
228
+ head('Schemas & Templates');
229
+ const schemasSrc = path.join(ANTIGRAVITY, 'schemas');
230
+ if (fs.existsSync(schemasSrc)) {
231
+ const count = copyDirRecursive(schemasSrc, path.join(AWK_ROOT, 'schemas'));
232
+ ok(`${count} schemas harvested`);
233
+ }
234
+ const tmplSrc = path.join(ANTIGRAVITY, 'templates');
235
+ if (fs.existsSync(tmplSrc)) {
236
+ const count = copyDirRecursive(tmplSrc, path.join(AWK_ROOT, 'templates'));
237
+ ok(`${count} templates harvested`);
238
+ }
239
+
240
+ // ── Summary ───────────────────────────────────────────────────────────────
241
+ console.log('');
242
+ console.log(`${C.gray}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}`);
243
+ console.log(`${C.yellow}${C.bold}🎉 Harvest Complete!${DRY_RUN ? ' (DRY RUN)' : ''}${C.reset}`);
244
+ console.log('');
245
+ dim(`Workflows: ${stats.workflows} files`);
246
+ dim(`Skills: ${stats.skills} directories`);
247
+ dim(`Misc: ${stats.misc} files (GEMINI.md, AGENTS.md)`);
248
+ console.log('');
249
+ console.log(`${C.cyan}Next: node scripts/rename-to-awk.js${C.reset}`);
250
+ console.log('');
251
+ }
252
+
253
+ harvest().catch(console.error);