@leejungkiin/awkit 1.4.0 → 1.4.3
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/bin/awk.js +458 -7
- package/bin/claude-generators.js +122 -0
- package/core/AGENTS.md +16 -0
- package/core/CLAUDE.md +155 -0
- package/core/GEMINI.md +44 -9
- package/package.json +1 -1
- package/skills/ai-sprite-maker/SKILL.md +81 -0
- package/skills/ai-sprite-maker/scripts/animate_sprite.py +102 -0
- package/skills/ai-sprite-maker/scripts/process_sprites.py +140 -0
- package/skills/code-review/SKILL.md +21 -33
- package/skills/lucylab-tts/SKILL.md +64 -0
- package/skills/lucylab-tts/resources/voices_library.json +908 -0
- package/skills/lucylab-tts/scripts/.env +1 -0
- package/skills/lucylab-tts/scripts/lucylab_tts.py +506 -0
- package/skills/orchestrator/SKILL.md +5 -0
- package/skills/short-maker/SKILL.md +150 -0
- package/skills/short-maker/_backup/storyboard.html +106 -0
- package/skills/short-maker/_backup/video_mixer.py +296 -0
- package/skills/short-maker/outputs/fitbite-promo/background.jpg +0 -0
- package/skills/short-maker/outputs/fitbite-promo/final/promo-final.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/script.md +19 -0
- package/skills/short-maker/outputs/fitbite-promo/segments/scene-01.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/segments/scene-02.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/segments/scene-03.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/segments/scene-04.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/storyboard/scene-01.png +0 -0
- package/skills/short-maker/outputs/fitbite-promo/storyboard/scene-02.png +0 -0
- package/skills/short-maker/outputs/fitbite-promo/storyboard/scene-03.png +0 -0
- package/skills/short-maker/outputs/fitbite-promo/storyboard/scene-04.png +0 -0
- package/skills/short-maker/outputs/fitbite-promo/storyboard.html +133 -0
- package/skills/short-maker/outputs/fitbite-promo/storyboard.json +38 -0
- package/skills/short-maker/outputs/fitbite-promo/temp/merged_chroma.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/temp/merged_crossfaded.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/temp/ready_00.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/temp/ready_01.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/temp/ready_02.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/temp/ready_03.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/tts/manifest.json +31 -0
- package/skills/short-maker/outputs/fitbite-promo/tts/scene-01.wav +0 -0
- package/skills/short-maker/outputs/fitbite-promo/tts/scene-02.wav +0 -0
- package/skills/short-maker/outputs/fitbite-promo/tts/scene-03.wav +0 -0
- package/skills/short-maker/outputs/fitbite-promo/tts/scene-04.wav +0 -0
- package/skills/short-maker/outputs/fitbite-promo/tts_script.txt +11 -0
- package/skills/short-maker/scripts/google-flow-cli/.project-identity +41 -0
- package/skills/short-maker/scripts/google-flow-cli/.trae/rules/project_rules.md +52 -0
- package/skills/short-maker/scripts/google-flow-cli/CODEBASE.md +67 -0
- package/skills/short-maker/scripts/google-flow-cli/GoogleFlowCli.code-workspace +29 -0
- package/skills/short-maker/scripts/google-flow-cli/README.md +168 -0
- package/skills/short-maker/scripts/google-flow-cli/docs/specs/PROJECT.md +12 -0
- package/skills/short-maker/scripts/google-flow-cli/docs/specs/REQUIREMENTS.md +22 -0
- package/skills/short-maker/scripts/google-flow-cli/docs/specs/ROADMAP.md +16 -0
- package/skills/short-maker/scripts/google-flow-cli/docs/specs/TECH-SPEC.md +13 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/__init__.py +3 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/api/__init__.py +19 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/api/client.py +1921 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/api/models.py +64 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/api/rpc_ids.py +98 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/auth/__init__.py +15 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/auth/browser_auth.py +692 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/auth/humanizer.py +417 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/auth/proxy_ext.py +120 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/auth/recaptcha.py +482 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/batchexecute/__init__.py +5 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/batchexecute/client.py +414 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/cli/__init__.py +1 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/cli/main.py +1075 -0
- package/skills/short-maker/scripts/google-flow-cli/pyproject.toml +36 -0
- package/skills/short-maker/scripts/google-flow-cli/script.txt +22 -0
- package/skills/short-maker/scripts/google-flow-cli/tests/__init__.py +0 -0
- package/skills/short-maker/scripts/google-flow-cli/tests/test_batchexecute.py +113 -0
- package/skills/short-maker/scripts/google-flow-cli/tests/test_client.py +190 -0
- package/skills/short-maker/templates/aida_script.md +40 -0
- package/skills/short-maker/templates/mimic_analyzer.md +29 -0
- package/skills/single-flow-task-execution/SKILL.md +9 -6
- package/skills/skill-creator/SKILL.md +44 -0
- package/skills/spm-build-analysis/SKILL.md +92 -0
- package/skills/spm-build-analysis/references/build-optimization-sources.md +155 -0
- package/skills/spm-build-analysis/references/recommendation-format.md +85 -0
- package/skills/spm-build-analysis/references/spm-analysis-checks.md +105 -0
- package/skills/spm-build-analysis/scripts/check_spm_pins.py +118 -0
- package/skills/symphony-enforcer/SKILL.md +51 -83
- package/skills/symphony-orchestrator/SKILL.md +1 -1
- package/skills/trello-sync/SKILL.md +27 -28
- package/skills/verification-gate/SKILL.md +13 -2
- package/skills/xcode-build-benchmark/SKILL.md +88 -0
- package/skills/xcode-build-benchmark/references/benchmark-artifacts.md +94 -0
- package/skills/xcode-build-benchmark/references/benchmarking-workflow.md +67 -0
- package/skills/xcode-build-benchmark/schemas/build-benchmark.schema.json +230 -0
- package/skills/xcode-build-benchmark/scripts/benchmark_builds.py +308 -0
- package/skills/xcode-build-fixer/SKILL.md +218 -0
- package/skills/xcode-build-fixer/references/build-settings-best-practices.md +216 -0
- package/skills/xcode-build-fixer/references/fix-patterns.md +290 -0
- package/skills/xcode-build-fixer/references/recommendation-format.md +85 -0
- package/skills/xcode-build-fixer/scripts/benchmark_builds.py +308 -0
- package/skills/xcode-build-orchestrator/SKILL.md +156 -0
- package/skills/xcode-build-orchestrator/references/benchmark-artifacts.md +94 -0
- package/skills/xcode-build-orchestrator/references/build-settings-best-practices.md +216 -0
- package/skills/xcode-build-orchestrator/references/orchestration-report-template.md +143 -0
- package/skills/xcode-build-orchestrator/references/recommendation-format.md +85 -0
- package/skills/xcode-build-orchestrator/scripts/benchmark_builds.py +308 -0
- package/skills/xcode-build-orchestrator/scripts/diagnose_compilation.py +273 -0
- package/skills/xcode-build-orchestrator/scripts/generate_optimization_report.py +533 -0
- package/skills/xcode-compilation-analyzer/SKILL.md +89 -0
- package/skills/xcode-compilation-analyzer/references/build-optimization-sources.md +155 -0
- package/skills/xcode-compilation-analyzer/references/code-compilation-checks.md +106 -0
- package/skills/xcode-compilation-analyzer/references/recommendation-format.md +85 -0
- package/skills/xcode-compilation-analyzer/scripts/diagnose_compilation.py +273 -0
- package/skills/xcode-project-analyzer/SKILL.md +76 -0
- package/skills/xcode-project-analyzer/references/build-optimization-sources.md +155 -0
- package/skills/xcode-project-analyzer/references/build-settings-best-practices.md +216 -0
- package/skills/xcode-project-analyzer/references/project-audit-checks.md +101 -0
- package/skills/xcode-project-analyzer/references/recommendation-format.md +85 -0
- package/templates/project-identity/android.json +0 -10
- package/templates/project-identity/backend-nestjs.json +0 -10
- package/templates/project-identity/expo.json +0 -10
- package/templates/project-identity/ios.json +0 -10
- package/templates/project-identity/web-nextjs.json +0 -10
- package/workflows/_uncategorized/ship-to-code.md +85 -0
- package/workflows/context/codebase-sync.md +10 -87
package/bin/awk.js
CHANGED
|
@@ -36,6 +36,7 @@ const HOME = process.env.HOME || process.env.USERPROFILE;
|
|
|
36
36
|
|
|
37
37
|
const { generateClineRules, generateClineWorkflows, generateClineSkills } = require('./cline-generators');
|
|
38
38
|
const { generateCodexAgentsMd, generateCodexSkills, generateCodexAgents } = require('./codex-generators');
|
|
39
|
+
const { generateClaudeRules, generateClaudeSkills } = require('./claude-generators');
|
|
39
40
|
|
|
40
41
|
// ─── Platform Definitions ──────────────────────────────────────────────────
|
|
41
42
|
|
|
@@ -73,6 +74,15 @@ const PLATFORMS = {
|
|
|
73
74
|
agents: 'agents',
|
|
74
75
|
skills: '../.agents/skills',
|
|
75
76
|
},
|
|
77
|
+
},
|
|
78
|
+
claude: {
|
|
79
|
+
name: 'Claude Code',
|
|
80
|
+
globalRoot: process.cwd(), // Local to project
|
|
81
|
+
rulesFile: 'CLAUDE.md',
|
|
82
|
+
versionFile: '.claude/awk_version',
|
|
83
|
+
dirs: {
|
|
84
|
+
skills: '.claude/skills',
|
|
85
|
+
},
|
|
76
86
|
}
|
|
77
87
|
};
|
|
78
88
|
|
|
@@ -304,8 +314,9 @@ function cmdInstall(args = []) {
|
|
|
304
314
|
selectedPlatforms = Object.keys(PLATFORMS);
|
|
305
315
|
} else {
|
|
306
316
|
if (args.includes('--gemini') || args.includes('-g') || args.includes('antigravity')) selectedPlatforms.push('antigravity');
|
|
307
|
-
if (args.includes('--
|
|
317
|
+
if (args.includes('--cline') || args.includes('cline')) selectedPlatforms.push('cline');
|
|
308
318
|
if (args.includes('--codex') || args.includes('-x')) selectedPlatforms.push('codex');
|
|
319
|
+
if (args.includes('--claude-code') || args.includes('--claude') || args.includes('-c') || args.includes('claude')) selectedPlatforms.push('claude');
|
|
309
320
|
|
|
310
321
|
const pIdx = args.indexOf('--platform');
|
|
311
322
|
let legacyArg = null;
|
|
@@ -324,19 +335,21 @@ function cmdInstall(args = []) {
|
|
|
324
335
|
if (isUpdate) {
|
|
325
336
|
selectedPlatforms = [getActivePlatform()];
|
|
326
337
|
} else {
|
|
327
|
-
log(`${C.cyan}Select platforms to install (e.g., type "1,2", "all", or "1,2,3"):${C.reset}`);
|
|
338
|
+
log(`${C.cyan}Select platforms to install (e.g., type "1,2", "all", or "1,2,3,4"):${C.reset}`);
|
|
328
339
|
log(` 1. Gemini Code Assist (antigravity)`);
|
|
329
|
-
log(` 2.
|
|
340
|
+
log(` 2. Cline (VS Code)`);
|
|
330
341
|
log(` 3. Codex CLI (codex)`);
|
|
331
|
-
log(` 4.
|
|
332
|
-
|
|
342
|
+
log(` 4. Claude Code (.claude/)`);
|
|
343
|
+
log(` 5. All of the above`);
|
|
344
|
+
const choice = promptChoice('Choice', '5').trim().toLowerCase();
|
|
333
345
|
|
|
334
|
-
if (choice === '
|
|
346
|
+
if (choice === '5' || choice === 'all' || choice === '') {
|
|
335
347
|
selectedPlatforms = Object.keys(PLATFORMS);
|
|
336
348
|
} else {
|
|
337
349
|
if (choice.includes('1')) selectedPlatforms.push('antigravity');
|
|
338
350
|
if (choice.includes('2')) selectedPlatforms.push('cline');
|
|
339
351
|
if (choice.includes('3')) selectedPlatforms.push('codex');
|
|
352
|
+
if (choice.includes('4')) selectedPlatforms.push('claude');
|
|
340
353
|
}
|
|
341
354
|
}
|
|
342
355
|
}
|
|
@@ -391,6 +404,11 @@ function cmdInstall(args = []) {
|
|
|
391
404
|
} else if (platform === 'codex') {
|
|
392
405
|
info('Generating Codex AGENTS.md...');
|
|
393
406
|
generateCodexAgentsMd(path.join(AWK_ROOT, 'core', 'GEMINI.md'), plat.rulesFile);
|
|
407
|
+
} else if (platform === 'claude') {
|
|
408
|
+
info('Generating Claude Code CLAUDE.md...');
|
|
409
|
+
const claudeTemplateSrc = path.join(AWK_ROOT, 'core', 'CLAUDE.md');
|
|
410
|
+
const claudeRulesDest = path.join(target, plat.rulesFile);
|
|
411
|
+
generateClaudeRules(claudeTemplateSrc, claudeRulesDest);
|
|
394
412
|
}
|
|
395
413
|
|
|
396
414
|
// 3. Backup and install workflows
|
|
@@ -444,6 +462,8 @@ function cmdInstall(args = []) {
|
|
|
444
462
|
generateCodexSkills(skillsSrc, skillsDest);
|
|
445
463
|
const agentsDest = path.join(target, plat.dirs.agents);
|
|
446
464
|
generateCodexAgents(skillsSrc, agentsDest);
|
|
465
|
+
} else if (platform === 'claude') {
|
|
466
|
+
generateClaudeSkills(skillsSrc, skillsDest);
|
|
447
467
|
} else {
|
|
448
468
|
const skillCount = copyDirRecursive(skillsSrc, skillsDest);
|
|
449
469
|
ok(`${skillCount} skill files installed`);
|
|
@@ -716,6 +736,77 @@ function cmdDoctor() {
|
|
|
716
736
|
log('');
|
|
717
737
|
}
|
|
718
738
|
|
|
739
|
+
/**
|
|
740
|
+
* Handle browser-related tasks (e.g., cleaning up recordings).
|
|
741
|
+
*/
|
|
742
|
+
function cmdBrowser(args) {
|
|
743
|
+
if (args[0] !== 'clean') {
|
|
744
|
+
err('Unknown browser command. Use "awkit browser clean".');
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
const recordingsDir = path.join(TARGETS.antigravity, 'browser_recordings');
|
|
749
|
+
|
|
750
|
+
log('');
|
|
751
|
+
log(`${C.cyan}${C.bold}🧹 AWK Browser Cleanup${C.reset}`);
|
|
752
|
+
log('');
|
|
753
|
+
|
|
754
|
+
if (!fs.existsSync(recordingsDir)) {
|
|
755
|
+
ok(`No browser_recordings directory found at ${recordingsDir}. Nothing to clean.`);
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const files = fs.readdirSync(recordingsDir).filter(f => f.endsWith('.webm') || f.endsWith('.webp') || f.endsWith('.mp4'));
|
|
760
|
+
if (files.length === 0) {
|
|
761
|
+
ok('No browser recordings found. Nothing to clean.');
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
let keepDays = 7; // default 7 days
|
|
766
|
+
const daysArgIdx = args.indexOf('--days');
|
|
767
|
+
if (daysArgIdx !== -1 && args[daysArgIdx + 1]) {
|
|
768
|
+
keepDays = parseInt(args[daysArgIdx + 1], 10);
|
|
769
|
+
} else if (args.includes('--all')) {
|
|
770
|
+
keepDays = 0;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (keepDays === 0) {
|
|
774
|
+
log(`Cleaning ${C.yellow}ALL${C.reset} browser recordings...`);
|
|
775
|
+
} else {
|
|
776
|
+
log(`Cleaning browser recordings older than ${C.yellow}${keepDays} days${C.reset}...`);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
const now = Date.now();
|
|
780
|
+
const cutoff = now - (keepDays * 24 * 60 * 60 * 1000);
|
|
781
|
+
let deletedCount = 0;
|
|
782
|
+
let totalSizeFreed = 0;
|
|
783
|
+
|
|
784
|
+
for (const file of files) {
|
|
785
|
+
const filePath = path.join(recordingsDir, file);
|
|
786
|
+
try {
|
|
787
|
+
const stats = fs.statSync(filePath);
|
|
788
|
+
if (stats.mtimeMs < cutoff) {
|
|
789
|
+
totalSizeFreed += stats.size;
|
|
790
|
+
fs.unlinkSync(filePath);
|
|
791
|
+
deletedCount++;
|
|
792
|
+
dim(`Deleted: ${file}`);
|
|
793
|
+
}
|
|
794
|
+
} catch (e) {
|
|
795
|
+
warn(`Failed to process ${file}: ${e.message}`);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
log('');
|
|
800
|
+
const sizeMb = (totalSizeFreed / (1024 * 1024)).toFixed(2);
|
|
801
|
+
if (deletedCount > 0) {
|
|
802
|
+
ok(`Cleaned ${C.green}${C.bold}${deletedCount}${C.reset} recording(s).`);
|
|
803
|
+
ok(`Freed ${C.green}${C.bold}${sizeMb} MB${C.reset} of disk space.`);
|
|
804
|
+
} else {
|
|
805
|
+
ok(`No recordings older than ${keepDays} days found. Disk space is already optimized.`);
|
|
806
|
+
}
|
|
807
|
+
log('');
|
|
808
|
+
}
|
|
809
|
+
|
|
719
810
|
/**
|
|
720
811
|
* Find a compatible Python interpreter meeting the minimum version requirement.
|
|
721
812
|
* Tries python3.13, python3.12, python3.11, python3, python in order.
|
|
@@ -1420,6 +1511,55 @@ async function cmdAdmin() {
|
|
|
1420
1511
|
}
|
|
1421
1512
|
}
|
|
1422
1513
|
|
|
1514
|
+
async function cmdRestart() {
|
|
1515
|
+
info('Đang restart service awkit (Symphony)...');
|
|
1516
|
+
try {
|
|
1517
|
+
const { execSync, spawn } = require('child_process');
|
|
1518
|
+
try {
|
|
1519
|
+
// Find and kill process on port 3100
|
|
1520
|
+
const pids = execSync('lsof -t -i:3100').toString().trim().split('\n');
|
|
1521
|
+
for (const pid of pids) {
|
|
1522
|
+
if (pid) {
|
|
1523
|
+
process.kill(parseInt(pid, 10), 'SIGTERM');
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
info('Đã dừng service hiện tại.');
|
|
1527
|
+
} catch (e) {
|
|
1528
|
+
// Probably no process running on port 3100
|
|
1529
|
+
dim('Không tìm thấy service đang chạy.');
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
1533
|
+
|
|
1534
|
+
// Auto-build production bundle so code changes take effect
|
|
1535
|
+
const symphonyDir = path.join(AWK_ROOT, '..', 'symphony');
|
|
1536
|
+
if (fs.existsSync(path.join(symphonyDir, 'package.json'))) {
|
|
1537
|
+
info('Đang build production bundle...');
|
|
1538
|
+
try {
|
|
1539
|
+
execSync('npm run build', { cwd: symphonyDir, stdio: 'pipe' });
|
|
1540
|
+
log(`${C.green}✅ Build thành công!${C.reset}`);
|
|
1541
|
+
} catch (buildErr) {
|
|
1542
|
+
warn('Build thất bại, sử dụng bundle cũ.');
|
|
1543
|
+
dim(buildErr.message?.slice(0, 200));
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
info('Đang khởi động lại service ngầm...');
|
|
1548
|
+
const child = spawn('symphony', ['start'], {
|
|
1549
|
+
detached: true,
|
|
1550
|
+
stdio: 'ignore'
|
|
1551
|
+
});
|
|
1552
|
+
child.unref();
|
|
1553
|
+
|
|
1554
|
+
info('Vui lòng đợi 3 giây để service khởi động...');
|
|
1555
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
1556
|
+
|
|
1557
|
+
log(`${C.green}✅ Restart thành công!${C.reset}`);
|
|
1558
|
+
} catch (e) {
|
|
1559
|
+
err('Lỗi khi restart service: ' + e.message);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1423
1563
|
function cmdHelp() {
|
|
1424
1564
|
const line = `${C.gray}${'─'.repeat(56)}${C.reset}`;
|
|
1425
1565
|
log('');
|
|
@@ -1447,6 +1587,15 @@ function cmdHelp() {
|
|
|
1447
1587
|
log(` ${C.gray} CODEBASE.md, .symphony/ (Symphony task DB)${C.reset}`);
|
|
1448
1588
|
log('');
|
|
1449
1589
|
|
|
1590
|
+
// Maintenance
|
|
1591
|
+
log(`${C.bold}🧹 Maintenance${C.reset}`);
|
|
1592
|
+
log(line);
|
|
1593
|
+
log(` ${C.green}serve${C.reset} [dir] [-p <port>] Start local HTTP server for assets in CWD`);
|
|
1594
|
+
log(` ${C.green}browser clean${C.reset} Clean browser recordings`);
|
|
1595
|
+
log(` ${C.gray} --days <N>${C.reset} Keep recordings from last N days (default: 7)`);
|
|
1596
|
+
log(` ${C.gray} --all${C.reset} Delete all recordings`);
|
|
1597
|
+
log('');
|
|
1598
|
+
|
|
1450
1599
|
// Sync
|
|
1451
1600
|
log(`${C.bold}🔄 Sync${C.reset}`);
|
|
1452
1601
|
log(line);
|
|
@@ -2009,6 +2158,29 @@ async function cmdInit(forceFlag = false) {
|
|
|
2009
2158
|
}
|
|
2010
2159
|
}
|
|
2011
2160
|
|
|
2161
|
+
// ── 5.5. GitNexus: Code Intelligence Index ──────────────────────────────
|
|
2162
|
+
info('Indexing codebase with GitNexus...');
|
|
2163
|
+
try {
|
|
2164
|
+
// Only index if there are actual source files
|
|
2165
|
+
const hasSource = execSync(
|
|
2166
|
+
`find . -maxdepth 4 \\( -name "*.swift" -o -name "*.kt" -o -name "*.ts" -o -name "*.js" -o -name "*.dart" -o -name "*.py" \\) -not -path "*/node_modules/*" -not -path "*/.build/*" -not -path "*/Pods/*" | head -1`,
|
|
2167
|
+
{ cwd, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
|
|
2168
|
+
).trim();
|
|
2169
|
+
|
|
2170
|
+
if (hasSource) {
|
|
2171
|
+
execSync('npx -y gitnexus analyze', {
|
|
2172
|
+
cwd,
|
|
2173
|
+
stdio: 'ignore',
|
|
2174
|
+
});
|
|
2175
|
+
ok('GitNexus index created (.gitnexus/)');
|
|
2176
|
+
} else {
|
|
2177
|
+
dim('No source files found — skipping GitNexus index (run later: npx gitnexus analyze)');
|
|
2178
|
+
}
|
|
2179
|
+
} catch (e) {
|
|
2180
|
+
warn(`GitNexus indexing failed: ${e.message}`);
|
|
2181
|
+
dim('Run manually later: npx gitnexus analyze');
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2012
2184
|
// ── 6. Summary ─────────────────────────────────────────────────────────────
|
|
2013
2185
|
log('');
|
|
2014
2186
|
log(`${C.gray}${'─'.repeat(56)}${C.reset}`);
|
|
@@ -2017,11 +2189,13 @@ async function cmdInit(forceFlag = false) {
|
|
|
2017
2189
|
dim(`Type: ${projectType}`);
|
|
2018
2190
|
dim(`Firebase: analytics, crashlytics, remote-config, auth`);
|
|
2019
2191
|
dim(`Files: .project-identity, ${workspaceName}, CODEBASE.md`);
|
|
2020
|
-
dim(`Symphony: task tracking ready
|
|
2192
|
+
dim(`Symphony: task tracking ready`);
|
|
2193
|
+
dim(`GitNexus: code intelligence index`);
|
|
2021
2194
|
log('');
|
|
2022
2195
|
log(`${C.cyan}👉 Open ${workspaceName} in VS Code to get started.${C.reset}`);
|
|
2023
2196
|
log(`${C.cyan}👉 Run '/codebase-sync' in AI chat to keep CODEBASE.md updated.${C.reset}`);
|
|
2024
2197
|
log(`${C.cyan}👉 Run 'symphony task list' to manage tasks.${C.reset}`);
|
|
2198
|
+
log(`${C.cyan}👉 Run 'npx gitnexus analyze' after major changes to refresh index.${C.reset}`);
|
|
2025
2199
|
log('');
|
|
2026
2200
|
}
|
|
2027
2201
|
|
|
@@ -2219,6 +2393,178 @@ function cmdTelegram(args) {
|
|
|
2219
2393
|
}
|
|
2220
2394
|
}
|
|
2221
2395
|
|
|
2396
|
+
// ─── Credentials Management ───────────────────────────────────────────────────
|
|
2397
|
+
|
|
2398
|
+
const CREDENTIALS_CONFIG_PATH = path.join(TARGETS.antigravity, '.credentials.json');
|
|
2399
|
+
|
|
2400
|
+
function credentialsLoad() {
|
|
2401
|
+
if (!fs.existsSync(CREDENTIALS_CONFIG_PATH)) return {};
|
|
2402
|
+
try {
|
|
2403
|
+
return JSON.parse(fs.readFileSync(CREDENTIALS_CONFIG_PATH, 'utf8'));
|
|
2404
|
+
} catch (_) {
|
|
2405
|
+
return {};
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
function credentialsSave(config) {
|
|
2410
|
+
const dir = path.dirname(CREDENTIALS_CONFIG_PATH);
|
|
2411
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
2412
|
+
fs.writeFileSync(CREDENTIALS_CONFIG_PATH, JSON.stringify(config, null, 2) + '\n');
|
|
2413
|
+
}
|
|
2414
|
+
|
|
2415
|
+
function credentialsHelp() {
|
|
2416
|
+
log('');
|
|
2417
|
+
log(`${C.cyan}${C.bold}🔑 Credentials Commands${C.reset}`);
|
|
2418
|
+
log('');
|
|
2419
|
+
log(` ${C.green}awkit credentials list${C.reset} List all stored credentials`);
|
|
2420
|
+
log(` ${C.green}awkit credentials set${C.reset} <key> <value> Set a credential`);
|
|
2421
|
+
log(` ${C.green}awkit credentials get${C.reset} <key> Get a credential value`);
|
|
2422
|
+
log(` ${C.green}awkit credentials remove${C.reset} <key> Remove a credential`);
|
|
2423
|
+
log(` ${C.green}awkit credentials setup${C.reset} Interactive setup wizard`);
|
|
2424
|
+
log('');
|
|
2425
|
+
log(` ${C.gray}Known keys: gemini_api_key, lucylab_bearer${C.reset}`);
|
|
2426
|
+
log(` ${C.gray}Config: ${CREDENTIALS_CONFIG_PATH}${C.reset}`);
|
|
2427
|
+
log('');
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
async function credentialsSetup() {
|
|
2431
|
+
log('');
|
|
2432
|
+
log(`${C.cyan}${C.bold}🔑 API Credentials Setup${C.reset}`);
|
|
2433
|
+
log('');
|
|
2434
|
+
log(`${C.gray} Credentials are stored in: ${CREDENTIALS_CONFIG_PATH}${C.reset}`);
|
|
2435
|
+
log(`${C.gray} Used by Short Maker, Symphony Admin, and other services.${C.reset}`);
|
|
2436
|
+
log('');
|
|
2437
|
+
|
|
2438
|
+
const readline = require('readline');
|
|
2439
|
+
const rl = readline.createInterface({
|
|
2440
|
+
input: process.stdin,
|
|
2441
|
+
output: process.stdout
|
|
2442
|
+
});
|
|
2443
|
+
|
|
2444
|
+
const question = (query) => new Promise(resolve => rl.question(query, resolve));
|
|
2445
|
+
const sanitize = (s) => s.trim().replace(/^bearer\s+/i, '').replace(/\s+/g, '');
|
|
2446
|
+
|
|
2447
|
+
const config = credentialsLoad();
|
|
2448
|
+
|
|
2449
|
+
try {
|
|
2450
|
+
// Gemini API Key
|
|
2451
|
+
log(`${C.gray} Get your key at: https://aistudio.google.com/apikey${C.reset}`);
|
|
2452
|
+
const geminiKey = sanitize(await question(` ${C.yellow}Gemini API Key${config.gemini_api_key ? ` [${config.gemini_api_key.slice(0, 8)}...]` : ''}: ${C.reset}`));
|
|
2453
|
+
if (geminiKey) {
|
|
2454
|
+
config.gemini_api_key = geminiKey;
|
|
2455
|
+
ok('Gemini API Key saved');
|
|
2456
|
+
} else if (config.gemini_api_key) {
|
|
2457
|
+
dim('Kept existing Gemini API Key');
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
log('');
|
|
2461
|
+
|
|
2462
|
+
// LucyLab Bearer
|
|
2463
|
+
log(`${C.gray} LucyLab TTS bearer token for voice generation${C.reset}`);
|
|
2464
|
+
const lucylabToken = sanitize(await question(` ${C.yellow}LucyLab Bearer${config.lucylab_bearer ? ` [${config.lucylab_bearer.slice(0, 8)}...]` : ''}: ${C.reset}`));
|
|
2465
|
+
if (lucylabToken) {
|
|
2466
|
+
config.lucylab_bearer = lucylabToken;
|
|
2467
|
+
ok('LucyLab Bearer saved');
|
|
2468
|
+
} else if (config.lucylab_bearer) {
|
|
2469
|
+
dim('Kept existing LucyLab Bearer');
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
credentialsSave(config);
|
|
2473
|
+
log('');
|
|
2474
|
+
ok(`Credentials saved to ${CREDENTIALS_CONFIG_PATH}`);
|
|
2475
|
+
log('');
|
|
2476
|
+
} catch (e) {
|
|
2477
|
+
warn(`Failed to setup credentials: ${e.message}`);
|
|
2478
|
+
} finally {
|
|
2479
|
+
rl.close();
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
function cmdCredentials(args) {
|
|
2484
|
+
const subCmd = args[0];
|
|
2485
|
+
const key = args[1];
|
|
2486
|
+
const value = args.slice(2).join(' ');
|
|
2487
|
+
|
|
2488
|
+
switch (subCmd) {
|
|
2489
|
+
case 'list': {
|
|
2490
|
+
const config = credentialsLoad();
|
|
2491
|
+
const keys = Object.keys(config);
|
|
2492
|
+
if (keys.length === 0) {
|
|
2493
|
+
warn('No credentials stored. Run "awkit credentials setup" to configure.');
|
|
2494
|
+
return;
|
|
2495
|
+
}
|
|
2496
|
+
log('');
|
|
2497
|
+
log(`${C.cyan}${C.bold}🔑 Stored Credentials${C.reset}`);
|
|
2498
|
+
log('');
|
|
2499
|
+
for (const k of keys) {
|
|
2500
|
+
const val = config[k];
|
|
2501
|
+
const masked = val ? `${val.slice(0, 8)}${'•'.repeat(Math.max(0, val.length - 8))}` : '(empty)';
|
|
2502
|
+
log(` ${C.green}${k}${C.reset} = ${C.gray}${masked}${C.reset}`);
|
|
2503
|
+
}
|
|
2504
|
+
log('');
|
|
2505
|
+
dim(`Config: ${CREDENTIALS_CONFIG_PATH}`);
|
|
2506
|
+
log('');
|
|
2507
|
+
break;
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2510
|
+
case 'set': {
|
|
2511
|
+
let valueToSet = value;
|
|
2512
|
+
if (valueToSet) {
|
|
2513
|
+
valueToSet = valueToSet.trim().replace(/^bearer\s+/i, '').replace(/\s+/g, '');
|
|
2514
|
+
}
|
|
2515
|
+
if (!key || !valueToSet) {
|
|
2516
|
+
err('Usage: awkit credentials set <key> <value>');
|
|
2517
|
+
dim('Example: awkit credentials set gemini_api_key AIzaSy...');
|
|
2518
|
+
return;
|
|
2519
|
+
}
|
|
2520
|
+
const config = credentialsLoad();
|
|
2521
|
+
config[key] = valueToSet;
|
|
2522
|
+
credentialsSave(config);
|
|
2523
|
+
ok(`${key} saved ✅`);
|
|
2524
|
+
break;
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
case 'get': {
|
|
2528
|
+
if (!key) {
|
|
2529
|
+
err('Usage: awkit credentials get <key>');
|
|
2530
|
+
return;
|
|
2531
|
+
}
|
|
2532
|
+
const config = credentialsLoad();
|
|
2533
|
+
if (config[key]) {
|
|
2534
|
+
log(config[key]);
|
|
2535
|
+
} else {
|
|
2536
|
+
warn(`Key "${key}" not found.`);
|
|
2537
|
+
}
|
|
2538
|
+
break;
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
case 'remove':
|
|
2542
|
+
case 'delete': {
|
|
2543
|
+
if (!key) {
|
|
2544
|
+
err('Usage: awkit credentials remove <key>');
|
|
2545
|
+
return;
|
|
2546
|
+
}
|
|
2547
|
+
const config = credentialsLoad();
|
|
2548
|
+
if (config[key]) {
|
|
2549
|
+
delete config[key];
|
|
2550
|
+
credentialsSave(config);
|
|
2551
|
+
ok(`${key} removed`);
|
|
2552
|
+
} else {
|
|
2553
|
+
warn(`Key "${key}" not found.`);
|
|
2554
|
+
}
|
|
2555
|
+
break;
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
case 'setup':
|
|
2559
|
+
credentialsSetup();
|
|
2560
|
+
break;
|
|
2561
|
+
|
|
2562
|
+
default:
|
|
2563
|
+
credentialsHelp();
|
|
2564
|
+
break;
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2222
2568
|
// ─── Trello Integration ───────────────────────────────────────────────────────
|
|
2223
2569
|
|
|
2224
2570
|
/**
|
|
@@ -2490,6 +2836,98 @@ function checkAutoUpdate() {
|
|
|
2490
2836
|
}
|
|
2491
2837
|
}
|
|
2492
2838
|
|
|
2839
|
+
// ─── Native HTTP Server ───────────────────────────────────────────────────────
|
|
2840
|
+
|
|
2841
|
+
function cmdServe(args) {
|
|
2842
|
+
const http = require('http');
|
|
2843
|
+
|
|
2844
|
+
let port = 8080;
|
|
2845
|
+
let serveDir = process.cwd();
|
|
2846
|
+
|
|
2847
|
+
for (let i = 0; i < args.length; i++) {
|
|
2848
|
+
if (args[i] === '--port' || args[i] === '-p') {
|
|
2849
|
+
port = parseInt(args[++i], 10) || 8080;
|
|
2850
|
+
} else if (!args[i].startsWith('-')) {
|
|
2851
|
+
serveDir = path.resolve(process.cwd(), args[i]);
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
|
|
2855
|
+
if (!fs.existsSync(serveDir)) {
|
|
2856
|
+
err(`Directory not found: ${serveDir}`);
|
|
2857
|
+
return;
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
const mimeTypes = {
|
|
2861
|
+
'.html': 'text/html',
|
|
2862
|
+
'.js': 'text/javascript',
|
|
2863
|
+
'.css': 'text/css',
|
|
2864
|
+
'.json': 'application/json',
|
|
2865
|
+
'.png': 'image/png',
|
|
2866
|
+
'.jpg': 'image/jpeg',
|
|
2867
|
+
'.jpeg': 'image/jpeg',
|
|
2868
|
+
'.gif': 'image/gif',
|
|
2869
|
+
'.svg': 'image/svg+xml',
|
|
2870
|
+
'.wav': 'audio/wav',
|
|
2871
|
+
'.mp4': 'video/mp4',
|
|
2872
|
+
'.woff': 'application/font-woff',
|
|
2873
|
+
'.ttf': 'application/font-ttf',
|
|
2874
|
+
'.eot': 'application/vnd.ms-fontobject',
|
|
2875
|
+
'.otf': 'application/font-otf',
|
|
2876
|
+
'.wasm': 'application/wasm'
|
|
2877
|
+
};
|
|
2878
|
+
|
|
2879
|
+
const server = http.createServer((request, response) => {
|
|
2880
|
+
response.setHeader('Access-Control-Allow-Origin', '*');
|
|
2881
|
+
response.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
|
2882
|
+
response.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
2883
|
+
|
|
2884
|
+
if (request.method === 'OPTIONS') {
|
|
2885
|
+
response.writeHead(200);
|
|
2886
|
+
response.end();
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2890
|
+
let filePath = '.' + request.url.split('?')[0];
|
|
2891
|
+
if (filePath === './') {
|
|
2892
|
+
filePath = './index.html';
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
const absPath = path.join(serveDir, filePath);
|
|
2896
|
+
const extname = String(path.extname(absPath)).toLowerCase();
|
|
2897
|
+
const contentType = mimeTypes[extname] || 'application/octet-stream';
|
|
2898
|
+
|
|
2899
|
+
fs.readFile(absPath, (error, content) => {
|
|
2900
|
+
if (error) {
|
|
2901
|
+
if (error.code === 'ENOENT') {
|
|
2902
|
+
response.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
2903
|
+
response.end('404 Not Found', 'utf-8');
|
|
2904
|
+
} else {
|
|
2905
|
+
response.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
2906
|
+
response.end('500 Internal Server Error: ' + error.code, 'utf-8');
|
|
2907
|
+
}
|
|
2908
|
+
} else {
|
|
2909
|
+
response.writeHead(200, { 'Content-Type': contentType });
|
|
2910
|
+
response.end(content, 'utf-8');
|
|
2911
|
+
}
|
|
2912
|
+
});
|
|
2913
|
+
});
|
|
2914
|
+
|
|
2915
|
+
server.listen(port, '0.0.0.0', () => {
|
|
2916
|
+
log('');
|
|
2917
|
+
log(`${C.cyan}${C.bold}🚀 awkit serve running at:${C.reset}`);
|
|
2918
|
+
log(`${C.green} http://localhost:${port}${C.reset}`);
|
|
2919
|
+
dim(`Serving directory: ${serveDir}`);
|
|
2920
|
+
dim(`Press Ctrl+C to stop`);
|
|
2921
|
+
log('');
|
|
2922
|
+
}).on('error', (e) => {
|
|
2923
|
+
if (e.code === 'EADDRINUSE') {
|
|
2924
|
+
err(`Port ${port} is already in use. Try a different port with --port <number>`);
|
|
2925
|
+
} else {
|
|
2926
|
+
err(`Server error: ${e.message}`);
|
|
2927
|
+
}
|
|
2928
|
+
});
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2493
2931
|
// ─── Main ────────────────────────────────────────────────────────────────────
|
|
2494
2932
|
|
|
2495
2933
|
// Check for updates (max once per day) before continuing
|
|
@@ -2523,6 +2961,9 @@ const [, , command, ...args] = process.argv;
|
|
|
2523
2961
|
case 'doctor':
|
|
2524
2962
|
cmdDoctor();
|
|
2525
2963
|
break;
|
|
2964
|
+
case 'browser':
|
|
2965
|
+
cmdBrowser(args);
|
|
2966
|
+
break;
|
|
2526
2967
|
case 'enable-pack':
|
|
2527
2968
|
cmdEnablePack(args[0]);
|
|
2528
2969
|
break;
|
|
@@ -2547,9 +2988,19 @@ const [, , command, ...args] = process.argv;
|
|
|
2547
2988
|
case 'telegram':
|
|
2548
2989
|
cmdTelegram(args);
|
|
2549
2990
|
break;
|
|
2991
|
+
case 'credentials':
|
|
2992
|
+
case 'creds':
|
|
2993
|
+
cmdCredentials(args);
|
|
2994
|
+
break;
|
|
2995
|
+
case 'serve':
|
|
2996
|
+
cmdServe(args);
|
|
2997
|
+
break;
|
|
2550
2998
|
case 'admin':
|
|
2551
2999
|
cmdAdmin();
|
|
2552
3000
|
break;
|
|
3001
|
+
case 'restart':
|
|
3002
|
+
await cmdRestart();
|
|
3003
|
+
break;
|
|
2553
3004
|
case 'help':
|
|
2554
3005
|
case '--help':
|
|
2555
3006
|
case '-h':
|