@leejungkiin/awkit 1.6.2 → 1.6.4
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/package.json +3 -2
- package/scripts/automation-gate.js +384 -0
- package/scripts/bootstrap.js +122 -0
- package/scripts/harvest.js +253 -0
- package/scripts/rename-to-awk.js +143 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leejungkiin/awkit",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.4",
|
|
4
4
|
"description": "Antigravity Workflow Kit v12.5. Unified AI agent orchestration system with Mindful Checkpoints.",
|
|
5
5
|
"main": "bin/awk.js",
|
|
6
6
|
"bin": {
|
|
@@ -33,11 +33,12 @@
|
|
|
33
33
|
"schemas/",
|
|
34
34
|
"templates/",
|
|
35
35
|
"docs/",
|
|
36
|
+
"scripts/",
|
|
36
37
|
"README.md",
|
|
37
38
|
"CHANGELOG.md"
|
|
38
39
|
],
|
|
39
40
|
"dependencies": {
|
|
40
|
-
"@leejungkiin/awkit-symphony": "^1.
|
|
41
|
+
"@leejungkiin/awkit-symphony": "^0.1.0",
|
|
41
42
|
"@duytransipher/gitnexus": "latest"
|
|
42
43
|
}
|
|
43
44
|
}
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Automation Gate — Enforces .project-identity automation config.
|
|
5
|
+
*
|
|
6
|
+
* Reads automation.git / automation.trello / automation.telegram from
|
|
7
|
+
* .project-identity BEFORE executing any operation. Blocks if disabled.
|
|
8
|
+
*
|
|
9
|
+
* Usage (via awkit CLI):
|
|
10
|
+
* awkit gate git commit "feat: add feature"
|
|
11
|
+
* awkit gate git push
|
|
12
|
+
* awkit gate git auto "feat: add feature"
|
|
13
|
+
* awkit gate trello complete "Task name"
|
|
14
|
+
* awkit gate trello comment "Note"
|
|
15
|
+
* awkit gate telegram send "Message"
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const { execSync } = require('child_process');
|
|
21
|
+
|
|
22
|
+
// ─── Color helpers (borrowed from main CLI) ──────────────────────────────────
|
|
23
|
+
|
|
24
|
+
const C = {
|
|
25
|
+
reset: '\x1b[0m',
|
|
26
|
+
red: '\x1b[31m',
|
|
27
|
+
green: '\x1b[32m',
|
|
28
|
+
yellow: '\x1b[33m',
|
|
29
|
+
cyan: '\x1b[36m',
|
|
30
|
+
gray: '\x1b[90m',
|
|
31
|
+
bold: '\x1b[1m',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const log = (msg) => console.log(msg);
|
|
35
|
+
const ok = (msg) => log(`${C.green}✔${C.reset} ${msg}`);
|
|
36
|
+
const warn = (msg) => log(`${C.yellow}⚠${C.reset} ${msg}`);
|
|
37
|
+
const err = (msg) => log(`${C.red}✖${C.reset} ${msg}`);
|
|
38
|
+
const info = (msg) => log(`${C.cyan}ℹ${C.reset} ${msg}`);
|
|
39
|
+
const dim = (msg) => log(`${C.gray}${msg}${C.reset}`);
|
|
40
|
+
|
|
41
|
+
// ─── .project-identity reader ─────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Walk up directories from `startDir` to find .project-identity.
|
|
45
|
+
* Returns parsed JSON or null.
|
|
46
|
+
*/
|
|
47
|
+
function readProjectIdentity(startDir = process.cwd()) {
|
|
48
|
+
let dir = path.resolve(startDir);
|
|
49
|
+
const root = path.parse(dir).root;
|
|
50
|
+
|
|
51
|
+
while (dir !== root) {
|
|
52
|
+
const candidate = path.join(dir, '.project-identity');
|
|
53
|
+
if (fs.existsSync(candidate)) {
|
|
54
|
+
try {
|
|
55
|
+
return JSON.parse(fs.readFileSync(candidate, 'utf8'));
|
|
56
|
+
} catch (e) {
|
|
57
|
+
warn(`Failed to parse ${candidate}: ${e.message}`);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
dir = path.dirname(dir);
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ─── Gate checker ─────────────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check if an automation action is allowed.
|
|
70
|
+
*
|
|
71
|
+
* @param {string} domain - 'git' | 'trello' | 'telegram'
|
|
72
|
+
* @param {string} action - Domain-specific action name
|
|
73
|
+
* @returns {{ allowed: boolean, config: object|null, reason: string }}
|
|
74
|
+
*/
|
|
75
|
+
function checkGate(domain, action) {
|
|
76
|
+
const identity = readProjectIdentity();
|
|
77
|
+
|
|
78
|
+
if (!identity) {
|
|
79
|
+
return { allowed: true, config: null, reason: 'No .project-identity found — default allow' };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const automation = identity.automation;
|
|
83
|
+
if (!automation) {
|
|
84
|
+
return { allowed: true, config: null, reason: 'No automation config — default allow' };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
switch (domain) {
|
|
88
|
+
case 'git': {
|
|
89
|
+
const gitConfig = automation.git;
|
|
90
|
+
if (!gitConfig) {
|
|
91
|
+
return { allowed: true, config: null, reason: 'No automation.git config — default allow' };
|
|
92
|
+
}
|
|
93
|
+
if (action === 'commit' && gitConfig.autoCommit === false) {
|
|
94
|
+
return { allowed: false, config: gitConfig, reason: 'automation.git.autoCommit is false' };
|
|
95
|
+
}
|
|
96
|
+
if (action === 'push' && gitConfig.autoPush === false) {
|
|
97
|
+
return { allowed: false, config: gitConfig, reason: 'automation.git.autoPush is false' };
|
|
98
|
+
}
|
|
99
|
+
return { allowed: true, config: gitConfig, reason: 'automation.git allows this action' };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
case 'trello': {
|
|
103
|
+
const trelloConfig = automation.trello;
|
|
104
|
+
if (!trelloConfig) {
|
|
105
|
+
return { allowed: true, config: null, reason: 'No automation.trello config — default allow' };
|
|
106
|
+
}
|
|
107
|
+
if (trelloConfig.enabled === false || trelloConfig.autoSync === false) {
|
|
108
|
+
return { allowed: false, config: trelloConfig, reason: 'automation.trello is disabled (enabled=false or autoSync=false)' };
|
|
109
|
+
}
|
|
110
|
+
// Check trigger-level gates
|
|
111
|
+
if (trelloConfig.triggers) {
|
|
112
|
+
const triggerMap = {
|
|
113
|
+
'complete': 'task_complete',
|
|
114
|
+
'comment': 'milestone',
|
|
115
|
+
'block': 'blocked',
|
|
116
|
+
};
|
|
117
|
+
const trigger = triggerMap[action];
|
|
118
|
+
if (trigger && trelloConfig.triggers[trigger] === false) {
|
|
119
|
+
return { allowed: false, config: trelloConfig, reason: `automation.trello.triggers.${trigger} is false` };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { allowed: true, config: trelloConfig, reason: 'automation.trello allows this action' };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
case 'telegram': {
|
|
126
|
+
const tgConfig = automation.telegram;
|
|
127
|
+
if (!tgConfig) {
|
|
128
|
+
return { allowed: true, config: null, reason: 'No automation.telegram config — default allow' };
|
|
129
|
+
}
|
|
130
|
+
if (tgConfig.enabled === false) {
|
|
131
|
+
return { allowed: false, config: tgConfig, reason: 'automation.telegram.enabled is false' };
|
|
132
|
+
}
|
|
133
|
+
// Check trigger-level gates
|
|
134
|
+
if (tgConfig.triggers && action !== 'send') {
|
|
135
|
+
const triggerMap = {
|
|
136
|
+
'git_push': 'git_push',
|
|
137
|
+
'task_complete': 'task_complete',
|
|
138
|
+
'deploy': 'deploy',
|
|
139
|
+
};
|
|
140
|
+
const trigger = triggerMap[action];
|
|
141
|
+
if (trigger && tgConfig.triggers[trigger] === false) {
|
|
142
|
+
return { allowed: false, config: tgConfig, reason: `automation.telegram.triggers.${trigger} is false` };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return { allowed: true, config: tgConfig, reason: 'automation.telegram allows this action' };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
default:
|
|
149
|
+
return { allowed: true, config: null, reason: `Unknown domain '${domain}' — default allow` };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ─── Git executors ────────────────────────────────────────────────────────────
|
|
154
|
+
|
|
155
|
+
function execGitCommit(message) {
|
|
156
|
+
const gate = checkGate('git', 'commit');
|
|
157
|
+
if (!gate.allowed) {
|
|
158
|
+
err(`🚫 GIT COMMIT BLOCKED: ${gate.reason}`);
|
|
159
|
+
dim(' Modify .project-identity automation.git.autoCommit to change this.');
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
execSync('git add -A', { stdio: 'inherit' });
|
|
165
|
+
execSync(`git commit -m "${message.replace(/"/g, '\\"')}"`, { stdio: 'inherit' });
|
|
166
|
+
ok(`Committed: ${message}`);
|
|
167
|
+
return true;
|
|
168
|
+
} catch (e) {
|
|
169
|
+
// git commit returns non-zero if nothing to commit
|
|
170
|
+
if (e.status === 1) {
|
|
171
|
+
warn('Nothing to commit (working tree clean).');
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
err(`Git commit failed: ${e.message}`);
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function execGitPush() {
|
|
180
|
+
const gate = checkGate('git', 'push');
|
|
181
|
+
if (!gate.allowed) {
|
|
182
|
+
err(`🚫 GIT PUSH BLOCKED: ${gate.reason}`);
|
|
183
|
+
dim(' Modify .project-identity automation.git.autoPush to change this.');
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
execSync('git push', { stdio: 'inherit' });
|
|
189
|
+
ok('Pushed successfully.');
|
|
190
|
+
return true;
|
|
191
|
+
} catch (e) {
|
|
192
|
+
warn('Push failed. Retrying with git pull --rebase...');
|
|
193
|
+
try {
|
|
194
|
+
execSync('git pull --rebase && git push', { stdio: 'inherit' });
|
|
195
|
+
ok('Pushed successfully after rebase.');
|
|
196
|
+
return true;
|
|
197
|
+
} catch (e2) {
|
|
198
|
+
err(`Push failed after retry: ${e2.message}`);
|
|
199
|
+
err('Please resolve conflicts manually. DO NOT force push.');
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function execGitAuto(message) {
|
|
206
|
+
log('');
|
|
207
|
+
log(`${C.cyan}${C.bold}🔒 Automation Gate — Git Auto${C.reset}`);
|
|
208
|
+
dim(` Checking .project-identity...`);
|
|
209
|
+
|
|
210
|
+
const committed = execGitCommit(message);
|
|
211
|
+
if (!committed) return false;
|
|
212
|
+
|
|
213
|
+
const pushed = execGitPush();
|
|
214
|
+
if (!pushed) return false;
|
|
215
|
+
|
|
216
|
+
// Trigger Telegram notification if git_push trigger is enabled
|
|
217
|
+
const tgGate = checkGate('telegram', 'git_push');
|
|
218
|
+
if (tgGate.allowed) {
|
|
219
|
+
info('Triggering Telegram notification...');
|
|
220
|
+
try {
|
|
221
|
+
execSync(`awkit tg send "✅ Pushed: ${message.replace(/"/g, '\\"')}"`, { stdio: 'inherit' });
|
|
222
|
+
} catch (_) {
|
|
223
|
+
dim('Telegram notification skipped (not configured or failed).');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// ─── Trello executors ─────────────────────────────────────────────────────────
|
|
231
|
+
|
|
232
|
+
function execTrelloAction(action, args) {
|
|
233
|
+
const gate = checkGate('trello', action);
|
|
234
|
+
if (!gate.allowed) {
|
|
235
|
+
err(`🚫 TRELLO ${action.toUpperCase()} BLOCKED: ${gate.reason}`);
|
|
236
|
+
dim(' Modify .project-identity automation.trello to change this.');
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
const cmd = `awkit trello ${action} ${args.map(a => `"${a}"`).join(' ')}`;
|
|
242
|
+
execSync(cmd, { stdio: 'inherit' });
|
|
243
|
+
return true;
|
|
244
|
+
} catch (e) {
|
|
245
|
+
err(`Trello ${action} failed: ${e.message}`);
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ─── Telegram executor ────────────────────────────────────────────────────────
|
|
251
|
+
|
|
252
|
+
function execTelegramSend(args) {
|
|
253
|
+
const gate = checkGate('telegram', 'send');
|
|
254
|
+
if (!gate.allowed) {
|
|
255
|
+
err(`🚫 TELEGRAM BLOCKED: ${gate.reason}`);
|
|
256
|
+
dim(' Modify .project-identity automation.telegram to change this.');
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
const cmd = `awkit tg send ${args.map(a => `"${a}"`).join(' ')}`;
|
|
262
|
+
execSync(cmd, { stdio: 'inherit' });
|
|
263
|
+
return true;
|
|
264
|
+
} catch (e) {
|
|
265
|
+
err(`Telegram send failed: ${e.message}`);
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ─── CLI handler ──────────────────────────────────────────────────────────────
|
|
271
|
+
|
|
272
|
+
function gateHelp() {
|
|
273
|
+
log('');
|
|
274
|
+
log(`${C.cyan}${C.bold}🔒 Automation Gate${C.reset}`);
|
|
275
|
+
log(`${C.gray} Enforces .project-identity automation config before executing.${C.reset}`);
|
|
276
|
+
log('');
|
|
277
|
+
log(` ${C.green}awkit gate git commit${C.reset} <message> Gated git add + commit`);
|
|
278
|
+
log(` ${C.green}awkit gate git push${C.reset} Gated git push`);
|
|
279
|
+
log(` ${C.green}awkit gate git auto${C.reset} <message> Commit + push + telegram`);
|
|
280
|
+
log('');
|
|
281
|
+
log(` ${C.green}awkit gate trello complete${C.reset} <name> Gated trello complete`);
|
|
282
|
+
log(` ${C.green}awkit gate trello comment${C.reset} <text> Gated trello comment`);
|
|
283
|
+
log(` ${C.green}awkit gate trello block${C.reset} <reason> Gated trello block`);
|
|
284
|
+
log('');
|
|
285
|
+
log(` ${C.green}awkit gate telegram send${C.reset} <message> Gated telegram send`);
|
|
286
|
+
log('');
|
|
287
|
+
log(` ${C.green}awkit gate check${C.reset} <domain> Check gate status (dry-run)`);
|
|
288
|
+
log('');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function gateCheck(domain) {
|
|
292
|
+
log('');
|
|
293
|
+
log(`${C.cyan}${C.bold}🔒 Gate Status — ${domain || 'all'}${C.reset}`);
|
|
294
|
+
log('');
|
|
295
|
+
|
|
296
|
+
const domains = domain ? [domain] : ['git', 'trello', 'telegram'];
|
|
297
|
+
const actions = {
|
|
298
|
+
git: ['commit', 'push'],
|
|
299
|
+
trello: ['complete', 'comment', 'block'],
|
|
300
|
+
telegram: ['send', 'git_push', 'task_complete', 'deploy'],
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
for (const d of domains) {
|
|
304
|
+
log(` ${C.bold}${d}${C.reset}`);
|
|
305
|
+
for (const a of (actions[d] || [])) {
|
|
306
|
+
const gate = checkGate(d, a);
|
|
307
|
+
const icon = gate.allowed ? `${C.green}✔${C.reset}` : `${C.red}✖${C.reset}`;
|
|
308
|
+
log(` ${icon} ${a}: ${C.gray}${gate.reason}${C.reset}`);
|
|
309
|
+
}
|
|
310
|
+
log('');
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Main handler for `awkit gate` subcommand.
|
|
316
|
+
* @param {string[]} args - CLI args after 'gate'
|
|
317
|
+
*/
|
|
318
|
+
function cmdGate(args) {
|
|
319
|
+
const domain = args[0];
|
|
320
|
+
const action = args[1];
|
|
321
|
+
const rest = args.slice(2);
|
|
322
|
+
|
|
323
|
+
if (!domain || domain === 'help' || domain === '--help' || domain === '-h') {
|
|
324
|
+
gateHelp();
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (domain === 'check') {
|
|
329
|
+
gateCheck(action); // action is optional domain filter
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
switch (domain) {
|
|
334
|
+
case 'git':
|
|
335
|
+
switch (action) {
|
|
336
|
+
case 'commit':
|
|
337
|
+
execGitCommit(rest.join(' ') || 'chore: update');
|
|
338
|
+
break;
|
|
339
|
+
case 'push':
|
|
340
|
+
execGitPush();
|
|
341
|
+
break;
|
|
342
|
+
case 'auto':
|
|
343
|
+
execGitAuto(rest.join(' ') || 'chore: update');
|
|
344
|
+
break;
|
|
345
|
+
default:
|
|
346
|
+
err(`Unknown git action: ${action}`);
|
|
347
|
+
gateHelp();
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
break;
|
|
351
|
+
|
|
352
|
+
case 'trello':
|
|
353
|
+
if (!action || !rest.length) {
|
|
354
|
+
err(`Usage: awkit gate trello <action> <text>`);
|
|
355
|
+
gateHelp();
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
execTrelloAction(action, rest);
|
|
359
|
+
break;
|
|
360
|
+
|
|
361
|
+
case 'telegram':
|
|
362
|
+
case 'tg':
|
|
363
|
+
if (action === 'send') {
|
|
364
|
+
execTelegramSend(rest);
|
|
365
|
+
} else {
|
|
366
|
+
err(`Unknown telegram action: ${action}`);
|
|
367
|
+
gateHelp();
|
|
368
|
+
}
|
|
369
|
+
break;
|
|
370
|
+
|
|
371
|
+
default:
|
|
372
|
+
err(`Unknown gate domain: ${domain}`);
|
|
373
|
+
gateHelp();
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// ─── Exports ──────────────────────────────────────────────────────────────────
|
|
379
|
+
|
|
380
|
+
module.exports = {
|
|
381
|
+
cmdGate,
|
|
382
|
+
checkGate,
|
|
383
|
+
readProjectIdentity,
|
|
384
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
const HOME = os.homedir();
|
|
6
|
+
const MAIN_AWF_DIR = path.join(__dirname, '..');
|
|
7
|
+
|
|
8
|
+
// Nguồn v4 (Chi tiết, Persona, Auto-test loop)
|
|
9
|
+
const AWF_V4_DIR = path.join(HOME, 'Dev', 'NodeJS', 'awf');
|
|
10
|
+
// Nguồn v5 (Symphony, Brain, Fast execution)
|
|
11
|
+
const ANTIGRAVITY_V5_DIR = path.join(HOME, '.gemini', 'antigravity');
|
|
12
|
+
|
|
13
|
+
function ensureDir(dir) {
|
|
14
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function copyFile(src, dest) {
|
|
18
|
+
if (fs.existsSync(src)) {
|
|
19
|
+
ensureDir(path.dirname(dest));
|
|
20
|
+
fs.copyFileSync(src, dest);
|
|
21
|
+
console.log(`✅ Copied: ${path.basename(dest)}`);
|
|
22
|
+
return true;
|
|
23
|
+
} else {
|
|
24
|
+
console.log(`❌ Source not found: ${src}`);
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function copySkill(skillName, destDir) {
|
|
30
|
+
const destPath = path.join(MAIN_AWF_DIR, 'skills', destDir || skillName, 'SKILL.md');
|
|
31
|
+
|
|
32
|
+
// Try sources in order of priority
|
|
33
|
+
const sources = [
|
|
34
|
+
path.join(ANTIGRAVITY_V5_DIR, 'skills', `awf-${skillName}`, 'SKILL.md'),
|
|
35
|
+
path.join(ANTIGRAVITY_V5_DIR, 'skills', skillName, 'SKILL.md'),
|
|
36
|
+
path.join(AWF_V4_DIR, 'awf_skills', `awf-${skillName}`, 'SKILL.md')
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
for (const src of sources) {
|
|
40
|
+
if (fs.existsSync(src)) {
|
|
41
|
+
ensureDir(path.dirname(destPath));
|
|
42
|
+
fs.copyFileSync(src, destPath);
|
|
43
|
+
console.log(`✅ Skill installed: ${skillName}`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
console.log(`⚠️ Skill NOT found: ${skillName}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function run() {
|
|
51
|
+
console.log('🚀 Bootstrapping AWF v6.0 Workflows & Skills...\n');
|
|
52
|
+
|
|
53
|
+
// 1. CURATE LIFECYCLE WORKFLOWS
|
|
54
|
+
console.log('--- Lifecycle Workflows ---');
|
|
55
|
+
// V4 is better for deep planning & coding
|
|
56
|
+
copyFile(path.join(AWF_V4_DIR, 'workflows', 'code.md'), path.join(MAIN_AWF_DIR, 'workflows', 'lifecycle', 'code.md'));
|
|
57
|
+
copyFile(path.join(AWF_V4_DIR, 'workflows', 'plan.md'), path.join(MAIN_AWF_DIR, 'workflows', 'lifecycle', 'plan.md'));
|
|
58
|
+
copyFile(path.join(AWF_V4_DIR, 'workflows', 'debug.md'), path.join(MAIN_AWF_DIR, 'workflows', 'lifecycle', 'debug.md'));
|
|
59
|
+
copyFile(path.join(AWF_V4_DIR, 'workflows', 'brainstorm.md'), path.join(MAIN_AWF_DIR, 'workflows', 'lifecycle', 'brainstorm.md'));
|
|
60
|
+
copyFile(path.join(AWF_V4_DIR, 'workflows', 'test.md'), path.join(MAIN_AWF_DIR, 'workflows', 'lifecycle', 'test.md'));
|
|
61
|
+
copyFile(path.join(AWF_V4_DIR, 'workflows', 'deploy.md'), path.join(MAIN_AWF_DIR, 'workflows', 'lifecycle', 'deploy.md'));
|
|
62
|
+
copyFile(path.join(AWF_V4_DIR, 'workflows', 'refactor.md'), path.join(MAIN_AWF_DIR, 'workflows', 'lifecycle', 'refactor.md'));
|
|
63
|
+
// V5 is better for init (has project-identity integration)
|
|
64
|
+
copyFile(path.join(ANTIGRAVITY_V5_DIR, 'global_workflows', 'init.md'), path.join(MAIN_AWF_DIR, 'workflows', 'lifecycle', 'init.md'));
|
|
65
|
+
|
|
66
|
+
// 2. CURATE CONTEXT WORKFLOWS
|
|
67
|
+
console.log('\n--- Context Workflows ---');
|
|
68
|
+
// Both from V5
|
|
69
|
+
copyFile(path.join(ANTIGRAVITY_V5_DIR, 'global_workflows', 'save-brain.md'), path.join(MAIN_AWF_DIR, 'workflows', 'context', 'save-brain.md'));
|
|
70
|
+
copyFile(path.join(ANTIGRAVITY_V5_DIR, 'global_workflows', 'recap.md'), path.join(MAIN_AWF_DIR, 'workflows', 'context', 'recap.md'));
|
|
71
|
+
copyFile(path.join(ANTIGRAVITY_V5_DIR, 'global_workflows', 'next.md'), path.join(MAIN_AWF_DIR, 'workflows', 'context', 'next.md'));
|
|
72
|
+
|
|
73
|
+
// 3. CURATE QUALITY & UI WORKFLOWS (From v5)
|
|
74
|
+
console.log('\n--- Quality & UI Workflows ---');
|
|
75
|
+
const v5Workflows = [
|
|
76
|
+
['audit.md', 'quality'],
|
|
77
|
+
['performance-audit.md', 'quality'],
|
|
78
|
+
['ux-audit.md', 'quality'],
|
|
79
|
+
['visualize.md', 'ui'],
|
|
80
|
+
['design-to-ui.md', 'ui'],
|
|
81
|
+
['ui-review.md', 'ui'],
|
|
82
|
+
['ads-audit.md', 'ads'],
|
|
83
|
+
['ads-optimize.md', 'ads'],
|
|
84
|
+
['adsExpert.md', 'ads'],
|
|
85
|
+
['git-commit-workflow.md', 'git', 'commit.md'],
|
|
86
|
+
['hotfix.md', 'git'],
|
|
87
|
+
['planExpert.md', 'expert'],
|
|
88
|
+
['codeExpert.md', 'expert'],
|
|
89
|
+
['debugExpert.md', 'expert']
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
for (const [file, category, rename] of v5Workflows) {
|
|
93
|
+
const src = path.join(ANTIGRAVITY_V5_DIR, 'global_workflows', file);
|
|
94
|
+
const dest = path.join(MAIN_AWF_DIR, 'workflows', category, rename || file);
|
|
95
|
+
copyFile(src, dest);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 4. CURATE META WORKFLOWS (From v4)
|
|
99
|
+
console.log('\n--- Meta Workflows ---');
|
|
100
|
+
copyFile(path.join(AWF_V4_DIR, 'workflows', 'customize.md'), path.join(MAIN_AWF_DIR, 'workflows', 'meta', 'customize.md'));
|
|
101
|
+
copyFile(path.join(AWF_V4_DIR, 'workflows', 'help.md'), path.join(MAIN_AWF_DIR, 'workflows', 'meta', 'help.md'));
|
|
102
|
+
copyFile(path.join(AWF_V4_DIR, 'workflows', 'awf-update.md'), path.join(MAIN_AWF_DIR, 'workflows', 'meta', 'awf-update.md'));
|
|
103
|
+
copyFile(path.join(AWF_V4_DIR, 'workflows', 'rollback.md'), path.join(MAIN_AWF_DIR, 'workflows', 'meta', 'rollback.md'));
|
|
104
|
+
|
|
105
|
+
// 5. CURATE CORE SKILLS
|
|
106
|
+
console.log('\n--- Core Skills ---');
|
|
107
|
+
const coreSkills = [
|
|
108
|
+
'session-restore',
|
|
109
|
+
'auto-save',
|
|
110
|
+
'adaptive-language',
|
|
111
|
+
'error-translator',
|
|
112
|
+
'context-help',
|
|
113
|
+
'symphony-orchestrator'
|
|
114
|
+
];
|
|
115
|
+
for (const skill of coreSkills) {
|
|
116
|
+
copySkill(skill, skill);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log('\n✅ Bootstrap Complete! Essential framework files synchronized.');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
run().catch(console.error);
|
|
@@ -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);
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* AWK Rename Script — Renames awf → awk throughout main-awf
|
|
4
|
+
* Updates: package.json, VERSION, copies awf.js → awk.js
|
|
5
|
+
* Created by Kien AI
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const AWK_ROOT = path.join(__dirname, '..');
|
|
12
|
+
const C = {
|
|
13
|
+
reset: '\x1b[0m', green: '\x1b[32m', yellow: '\x1b[33m',
|
|
14
|
+
cyan: '\x1b[36m', gray: '\x1b[90m', bold: '\x1b[1m',
|
|
15
|
+
};
|
|
16
|
+
const ok = (m) => console.log(`${C.green}✅ ${m}${C.reset}`);
|
|
17
|
+
const info = (m) => console.log(`${C.cyan}ℹ️ ${m}${C.reset}`);
|
|
18
|
+
const dim = (m) => console.log(`${C.gray} ${m}${C.reset}`);
|
|
19
|
+
const head = (m) => console.log(`\n${C.cyan}${C.bold}── ${m} ──${C.reset}`);
|
|
20
|
+
|
|
21
|
+
async function run() {
|
|
22
|
+
console.log('');
|
|
23
|
+
console.log(`${C.cyan}${C.bold}╔══════════════════════════════════════════════════════════╗${C.reset}`);
|
|
24
|
+
console.log(`${C.cyan}${C.bold}║ 🔤 AWK Rename — awf → awk everywhere ║${C.reset}`);
|
|
25
|
+
console.log(`${C.cyan}${C.bold}╚══════════════════════════════════════════════════════════╝${C.reset}`);
|
|
26
|
+
console.log('');
|
|
27
|
+
|
|
28
|
+
// ── 1. Update package.json ─────────────────────────────────────────────────
|
|
29
|
+
head('package.json');
|
|
30
|
+
const pkgPath = path.join(AWK_ROOT, 'package.json');
|
|
31
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
32
|
+
|
|
33
|
+
pkg.name = '@zeroteam/awk';
|
|
34
|
+
pkg.version = '7.0.0';
|
|
35
|
+
pkg.description = 'AWK v7.0 — Antigravity Workflow Kit. Unified AI agent orchestration system.';
|
|
36
|
+
pkg.bin = { awk: 'bin/awk.js' };
|
|
37
|
+
pkg.scripts = {
|
|
38
|
+
...pkg.scripts,
|
|
39
|
+
'install-global': 'node bin/awk.js install',
|
|
40
|
+
'uninstall-global': 'node bin/awk.js uninstall',
|
|
41
|
+
update: 'node bin/awk.js update',
|
|
42
|
+
test: 'node bin/awk.js doctor',
|
|
43
|
+
harvest: 'node scripts/harvest.js',
|
|
44
|
+
'harvest-dry': 'node scripts/harvest.js --dry-run',
|
|
45
|
+
};
|
|
46
|
+
pkg.keywords = ['awk', 'antigravity-workflow-kit', 'ai-agent', 'workflow', 'gemini', 'claude'];
|
|
47
|
+
|
|
48
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
49
|
+
ok('package.json updated → @zeroteam/awk v7.0.0');
|
|
50
|
+
dim('bin: { awk: "bin/awk.js" }');
|
|
51
|
+
|
|
52
|
+
// ── 2. Bump VERSION ────────────────────────────────────────────────────────
|
|
53
|
+
head('VERSION');
|
|
54
|
+
const versionPath = path.join(AWK_ROOT, 'VERSION');
|
|
55
|
+
fs.writeFileSync(versionPath, '7.0.0\n');
|
|
56
|
+
ok('VERSION → 7.0.0');
|
|
57
|
+
|
|
58
|
+
// ── 3. Copy awf.js → awk.js (with updated references) ─────────────────────
|
|
59
|
+
head('bin/awk.js');
|
|
60
|
+
const awfJsPath = path.join(AWK_ROOT, 'bin', 'awf.js');
|
|
61
|
+
const awkJsPath = path.join(AWK_ROOT, 'bin', 'awk.js');
|
|
62
|
+
|
|
63
|
+
let content = fs.readFileSync(awfJsPath, 'utf8');
|
|
64
|
+
|
|
65
|
+
// Update banner and references
|
|
66
|
+
content = content
|
|
67
|
+
.replace(/AWF v\$\{AWF_VERSION\}/g, 'AWK v${AWK_VERSION}')
|
|
68
|
+
.replace(/AWF v\$\{AWF_VERSION\}/g, 'AWK v${AWK_VERSION}')
|
|
69
|
+
.replace(/const AWF_VERSION/g, 'const AWK_VERSION')
|
|
70
|
+
.replace(/const AWF_ROOT/g, 'const AWK_ROOT')
|
|
71
|
+
.replace(/AWF_VERSION/g, 'AWK_VERSION')
|
|
72
|
+
.replace(/AWF_ROOT/g, 'AWK_ROOT')
|
|
73
|
+
.replace(/AWF v6\.0 CLI/g, 'AWK v7.0 CLI')
|
|
74
|
+
.replace(/AWF v6\.0 — Antigravity Workflow Framework/g, 'AWK v7.0 — Antigravity Workflow Kit')
|
|
75
|
+
.replace(/Antigravity Workflow Framework/g, 'Antigravity Workflow Kit')
|
|
76
|
+
.replace(/AWF v\$\{/g, 'AWK v${')
|
|
77
|
+
.replace(/AWF installed/g, 'AWK installed')
|
|
78
|
+
.replace(/AWF is healthy/g, 'AWK is healthy')
|
|
79
|
+
.replace(/AWF Health Check/g, 'AWK Health Check')
|
|
80
|
+
.replace(/\bawf\b(?! skills| v| update| version)/g, 'awk')
|
|
81
|
+
// Fix awf_version path reference
|
|
82
|
+
.replace(/awf_version/g, 'awk_version');
|
|
83
|
+
|
|
84
|
+
// Update TARGETS to use awk_version
|
|
85
|
+
content = content.replace(
|
|
86
|
+
"versionFile: path.join(HOME, '.gemini', 'awf_version')",
|
|
87
|
+
"versionFile: path.join(HOME, '.gemini', 'awk_version')"
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// Update script header comment
|
|
91
|
+
content = content.replace(
|
|
92
|
+
`#!/usr/bin/env node
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* AWF v6.0 CLI — Antigravity Workflow Framework`,
|
|
96
|
+
`#!/usr/bin/env node
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* AWK v7.0 CLI — Antigravity Workflow Kit`
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
fs.writeFileSync(awkJsPath, content);
|
|
103
|
+
ok('bin/awk.js created');
|
|
104
|
+
dim('All AWF → AWK references updated');
|
|
105
|
+
|
|
106
|
+
// Make executable
|
|
107
|
+
try {
|
|
108
|
+
const { execSync } = require('child_process');
|
|
109
|
+
execSync(`chmod +x "${awkJsPath}"`);
|
|
110
|
+
ok('bin/awk.js is now executable');
|
|
111
|
+
} catch (e) {
|
|
112
|
+
// Ignore
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ── 4. Update core/GEMINI.md references ───────────────────────────────────
|
|
116
|
+
head('core/GEMINI.md — Update binary references');
|
|
117
|
+
const geminiPath = path.join(AWK_ROOT, 'core', 'GEMINI.md');
|
|
118
|
+
if (fs.existsSync(geminiPath)) {
|
|
119
|
+
let gemini = fs.readFileSync(geminiPath, 'utf8');
|
|
120
|
+
// Update references from awf install to awk install
|
|
121
|
+
gemini = gemini
|
|
122
|
+
.replace(/\bawf install\b/g, 'awk install')
|
|
123
|
+
.replace(/\bawf doctor\b/g, 'awk doctor')
|
|
124
|
+
.replace(/\bawf update\b/g, 'awk update')
|
|
125
|
+
.replace(/\bnode bin\/awf\.js\b/g, 'node bin/awk.js');
|
|
126
|
+
fs.writeFileSync(geminiPath, gemini);
|
|
127
|
+
ok('core/GEMINI.md binary references updated');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ── 5. Summary ────────────────────────────────────────────────────────────
|
|
131
|
+
console.log('');
|
|
132
|
+
console.log(`${C.gray}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}`);
|
|
133
|
+
console.log(`${C.yellow}${C.bold}🎉 Rename Complete! main-awf is now AWK v7.0${C.reset}`);
|
|
134
|
+
console.log('');
|
|
135
|
+
dim('Package: @zeroteam/awk v7.0.0');
|
|
136
|
+
dim('Binary: bin/awk.js');
|
|
137
|
+
dim('Command: awk install / awk doctor / awk update');
|
|
138
|
+
console.log('');
|
|
139
|
+
console.log(`${C.cyan}Next: node bin/awk.js doctor${C.reset}`);
|
|
140
|
+
console.log('');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
run().catch(console.error);
|