@leejungkiin/awkit 1.5.2 → 1.5.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.
Files changed (64) hide show
  1. package/bin/awk.js +141 -141
  2. package/core/GEMINI.md +1 -0
  3. package/package.json +1 -1
  4. package/skill-packs/ads-management/pack.json +8 -0
  5. package/skill-packs/mobile-android/pack.json +2 -6
  6. package/skill-packs/neural-memory/pack.json +2 -2
  7. package/skill-packs/reverse-engineering/pack.json +9 -0
  8. package/workflows/mobile/reverse-android-build.md +0 -222
  9. package/workflows/mobile/reverse-android-design.md +0 -139
  10. package/workflows/mobile/reverse-android-discover.md +0 -150
  11. package/workflows/mobile/reverse-android.md +0 -143
  12. package/workflows/mobile/reverse-ios-build.md +0 -240
  13. package/workflows/mobile/reverse-ios-design.md +0 -112
  14. package/workflows/mobile/reverse-ios-discover.md +0 -120
  15. package/workflows/mobile/reverse-ios.md +0 -152
  16. /package/{skills → skill-packs/ads-management/skills}/admob-roas/SKILL.md +0 -0
  17. /package/{workflows/ads → skill-packs/ads-management/workflows}/ads-analyst.md +0 -0
  18. /package/{workflows/ads → skill-packs/ads-management/workflows}/ads-audit.md +0 -0
  19. /package/{workflows/_uncategorized → skill-packs/ads-management/workflows}/ads-creative.md +0 -0
  20. /package/{workflows/_uncategorized → skill-packs/ads-management/workflows}/ads-full-optimization.md +0 -0
  21. /package/{workflows/ads → skill-packs/ads-management/workflows}/ads-optimize.md +0 -0
  22. /package/{workflows/_uncategorized → skill-packs/ads-management/workflows}/ads-plan.md +0 -0
  23. /package/{workflows/ads → skill-packs/ads-management/workflows}/ads-targeting.md +0 -0
  24. /package/{workflows/_uncategorized → skill-packs/ads-management/workflows}/ads-user-analysis.md +0 -0
  25. /package/{workflows/ads → skill-packs/ads-management/workflows}/adsExpert.md +0 -0
  26. /package/{skills → skill-packs/reverse-engineering/skills}/android-re-analyzer/SKILL.md +0 -0
  27. /package/{skills → skill-packs/reverse-engineering/skills}/android-re-analyzer/references/api-extraction-patterns.md +0 -0
  28. /package/{skills → skill-packs/reverse-engineering/skills}/android-re-analyzer/references/call-flow-analysis.md +0 -0
  29. /package/{skills → skill-packs/reverse-engineering/skills}/android-re-analyzer/references/fernflower-usage.md +0 -0
  30. /package/{skills → skill-packs/reverse-engineering/skills}/android-re-analyzer/references/jadx-usage.md +0 -0
  31. /package/{skills → skill-packs/reverse-engineering/skills}/android-re-analyzer/references/setup-guide.md +0 -0
  32. /package/{skills → skill-packs/reverse-engineering/skills}/android-re-analyzer/scripts/check-deps.sh +0 -0
  33. /package/{skills → skill-packs/reverse-engineering/skills}/android-re-analyzer/scripts/decompile.sh +0 -0
  34. /package/{skills → skill-packs/reverse-engineering/skills}/android-re-analyzer/scripts/find-api-calls.sh +0 -0
  35. /package/{skills → skill-packs/reverse-engineering/skills}/android-re-analyzer/scripts/install-dep.sh +0 -0
  36. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/SKILL.md +0 -0
  37. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/examples/getting-started/tech-stack.md +0 -0
  38. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/examples/pipeline/data-ui-parity.md +0 -0
  39. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/examples/pipeline/scanner-and-bootstrap.md +0 -0
  40. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/library-patterns.md +0 -0
  41. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/phase-0-discovery.md +0 -0
  42. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/phase-1-architecture.md +0 -0
  43. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/phase-2-blueprint-ui.md +0 -0
  44. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/phase-2-blueprint.md +0 -0
  45. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/phase-3-build.md +0 -0
  46. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/phase-3-logic-build.md +0 -0
  47. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/smali-reading-guide.md +0 -0
  48. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/templates/app-map.md +0 -0
  49. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/templates/architecture.md +0 -0
  50. /package/{skills → skill-packs/reverse-engineering/skills}/smali-to-kotlin/templates/blueprint.md +0 -0
  51. /package/{workflows/_uncategorized → skill-packs/reverse-engineering/workflows}/reverse-android-build.md +0 -0
  52. /package/{workflows/_uncategorized → skill-packs/reverse-engineering/workflows}/reverse-android-design.md +0 -0
  53. /package/{workflows/_uncategorized → skill-packs/reverse-engineering/workflows}/reverse-android-discover.md +0 -0
  54. /package/{workflows/_uncategorized → skill-packs/reverse-engineering/workflows}/reverse-android-scan.md +0 -0
  55. /package/{workflows/_uncategorized → skill-packs/reverse-engineering/workflows}/reverse-android.md +0 -0
  56. /package/{workflows/_uncategorized → skill-packs/reverse-engineering/workflows}/reverse-ios-build.md +0 -0
  57. /package/{workflows/_uncategorized → skill-packs/reverse-engineering/workflows}/reverse-ios-design.md +0 -0
  58. /package/{workflows/_uncategorized → skill-packs/reverse-engineering/workflows}/reverse-ios-discover.md +0 -0
  59. /package/{workflows/_uncategorized → skill-packs/reverse-engineering/workflows}/reverse-ios-scan.md +0 -0
  60. /package/{workflows/_uncategorized → skill-packs/reverse-engineering/workflows}/reverse-ios.md +0 -0
  61. /package/{workflows/ads → skill-packs/reverse-engineering/workflows}/smali-ads-config.md +0 -0
  62. /package/{workflows/ads → skill-packs/reverse-engineering/workflows}/smali-ads-flow.md +0 -0
  63. /package/{workflows/ads → skill-packs/reverse-engineering/workflows}/smali-ads-interstitial.md +0 -0
  64. /package/{workflows/ads → skill-packs/reverse-engineering/workflows}/smali-ads-native.md +0 -0
package/bin/awk.js CHANGED
@@ -522,7 +522,7 @@ function cmdInstall(args = []) {
522
522
  } else if (args.length > 0 && !args[0].startsWith('-') && args[0] !== 'all' && args[0] !== '--update') {
523
523
  legacyArg = args[0];
524
524
  }
525
-
525
+
526
526
  if (legacyArg && PLATFORMS[legacyArg] && !selectedPlatforms.includes(legacyArg)) {
527
527
  selectedPlatforms.push(legacyArg);
528
528
  }
@@ -543,7 +543,7 @@ function cmdInstall(args = []) {
543
543
  log(` 5. All of the above`);
544
544
  log(`${C.gray}Press Enter to install only the active platform: ${PLATFORMS[defaultPlatform].name}.${C.reset}`);
545
545
  const choice = promptChoice('Choice', defaultChoice).trim().toLowerCase();
546
-
546
+
547
547
  if (choice === '5' || choice === 'all') {
548
548
  selectedPlatforms = Object.keys(PLATFORMS);
549
549
  } else {
@@ -587,73 +587,73 @@ function cmdInstall(args = []) {
587
587
  checkSymphony({ silent: platform !== selectedPlatforms[0] });
588
588
 
589
589
  // 1. Ensure target dirs exist
590
- info('Creating directories...');
591
- const dirKeys = Object.values(plat.dirs);
592
- for (const dir of dirKeys) {
593
- const fullPath = path.join(target, dir);
594
- if (!fs.existsSync(fullPath)) {
595
- fs.mkdirSync(fullPath, { recursive: true });
596
- }
597
- }
598
- ok('Directories ready');
599
-
600
- // 2. Sync rules (platform-specific)
601
- if (platform === 'antigravity') {
602
- info('Syncing GEMINI.md...');
603
- syncGeminiMd();
604
- } else if (platform === 'cline') {
605
- info('Generating Cline global rules...');
606
- generateClineRules(path.join(AWK_ROOT, 'core', 'GEMINI.md'), plat.rulesFile);
607
- } else if (platform === 'codex') {
608
- info('Generating Codex AGENTS.md...');
609
- generateCodexAgentsMd(path.join(AWK_ROOT, 'core', 'GEMINI.md'), plat.rulesFile);
610
- } else if (platform === 'claude') {
611
- info('Generating Claude Code CLAUDE.md...');
612
- const claudeTemplateSrc = path.join(AWK_ROOT, 'core', 'CLAUDE.md');
613
- const claudeRulesDest = path.join(target, plat.rulesFile);
614
- generateClaudeRules(claudeTemplateSrc, claudeRulesDest);
615
- }
616
-
617
- // 3. Backup and install workflows
618
- if (plat.dirs.workflows) {
619
- info('Installing workflows...');
620
- const wfSrc = path.join(AWK_ROOT, 'workflows');
621
- const wfDest = path.join(target, plat.dirs.workflows);
622
-
623
- // Backup existing workflows
624
- if (fs.existsSync(wfDest)) {
625
- const backupDir = getPlatformBackupRoot(platform);
626
- if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir, { recursive: true });
627
-
628
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
629
- const zipFile = path.join(backupDir, `workflows_${timestamp}.bak.zip`);
630
- try {
631
- execSync(`zip -r "${zipFile}" .`, { cwd: wfDest, stdio: 'ignore' });
632
- dim(`Backup: ${zipFile}`);
633
- } catch (e) {
634
- warn(`Failed to create backup: ${e.message}`);
590
+ info('Creating directories...');
591
+ const dirKeys = Object.values(plat.dirs);
592
+ for (const dir of dirKeys) {
593
+ const fullPath = path.join(target, dir);
594
+ if (!fs.existsSync(fullPath)) {
595
+ fs.mkdirSync(fullPath, { recursive: true });
635
596
  }
636
597
  }
598
+ ok('Directories ready');
599
+
600
+ // 2. Sync rules (platform-specific)
601
+ if (platform === 'antigravity') {
602
+ info('Syncing GEMINI.md...');
603
+ syncGeminiMd();
604
+ } else if (platform === 'cline') {
605
+ info('Generating Cline global rules...');
606
+ generateClineRules(path.join(AWK_ROOT, 'core', 'GEMINI.md'), plat.rulesFile);
607
+ } else if (platform === 'codex') {
608
+ info('Generating Codex AGENTS.md...');
609
+ generateCodexAgentsMd(path.join(AWK_ROOT, 'core', 'GEMINI.md'), plat.rulesFile);
610
+ } else if (platform === 'claude') {
611
+ info('Generating Claude Code CLAUDE.md...');
612
+ const claudeTemplateSrc = path.join(AWK_ROOT, 'core', 'CLAUDE.md');
613
+ const claudeRulesDest = path.join(target, plat.rulesFile);
614
+ generateClaudeRules(claudeTemplateSrc, claudeRulesDest);
615
+ }
616
+
617
+ // 3. Backup and install workflows
618
+ if (plat.dirs.workflows) {
619
+ info('Installing workflows...');
620
+ const wfSrc = path.join(AWK_ROOT, 'workflows');
621
+ const wfDest = path.join(target, plat.dirs.workflows);
622
+
623
+ // Backup existing workflows
624
+ if (fs.existsSync(wfDest)) {
625
+ const backupDir = getPlatformBackupRoot(platform);
626
+ if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir, { recursive: true });
627
+
628
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
629
+ const zipFile = path.join(backupDir, `workflows_${timestamp}.bak.zip`);
630
+ try {
631
+ execSync(`zip -r "${zipFile}" .`, { cwd: wfDest, stdio: 'ignore' });
632
+ dim(`Backup: ${zipFile}`);
633
+ } catch (e) {
634
+ warn(`Failed to create backup: ${e.message}`);
635
+ }
636
+ }
637
637
 
638
- if (platform === 'cline') {
639
- generateClineWorkflows(wfSrc, wfDest);
640
- } else if (platform !== 'codex') {
641
- const wfCount = flattenWorkflows(wfSrc, wfDest);
642
- ok(`${wfCount} workflows installed`);
638
+ if (platform === 'cline') {
639
+ generateClineWorkflows(wfSrc, wfDest);
640
+ } else if (platform !== 'codex') {
641
+ const wfCount = flattenWorkflows(wfSrc, wfDest);
642
+ ok(`${wfCount} workflows installed`);
643
+ }
643
644
  }
644
- }
645
645
 
646
- // 4. Copy AGENTS.md
647
- if (platform === 'antigravity' && plat.dirs.workflows) {
648
- const agentsSrc = path.join(AWK_ROOT, 'core', 'AGENTS.md');
649
- const agentsDest = path.join(target, plat.dirs.workflows, 'AGENTS.md');
650
- if (fs.existsSync(agentsSrc)) {
651
- fs.copyFileSync(agentsSrc, agentsDest);
652
- ok('AGENTS.md installed');
646
+ // 4. Copy AGENTS.md
647
+ if (platform === 'antigravity' && plat.dirs.workflows) {
648
+ const agentsSrc = path.join(AWK_ROOT, 'core', 'AGENTS.md');
649
+ const agentsDest = path.join(target, plat.dirs.workflows, 'AGENTS.md');
650
+ if (fs.existsSync(agentsSrc)) {
651
+ fs.copyFileSync(agentsSrc, agentsDest);
652
+ ok('AGENTS.md installed');
653
+ }
653
654
  }
654
- }
655
655
 
656
- // 5. Copy skills
656
+ // 5. Copy skills
657
657
  if (plat.dirs.skills) {
658
658
  info('Installing skills...');
659
659
  const skillsSrc = path.join(AWK_ROOT, 'skills');
@@ -673,36 +673,36 @@ function cmdInstall(args = []) {
673
673
  }
674
674
  }
675
675
 
676
- // 6. Copy orchestrator
677
- if (platform === 'antigravity') {
678
- const orchSrc = path.join(AWK_ROOT, 'core', 'orchestrator.md');
679
- const orchDestDir = path.join(target, plat.dirs.skills, 'orchestrator');
680
- if (!fs.existsSync(orchDestDir)) fs.mkdirSync(orchDestDir, { recursive: true });
681
- fs.copyFileSync(orchSrc, path.join(orchDestDir, 'SKILL.md'));
682
- ok('Orchestrator skill installed');
683
- }
676
+ // 6. Copy orchestrator
677
+ if (platform === 'antigravity') {
678
+ const orchSrc = path.join(AWK_ROOT, 'core', 'orchestrator.md');
679
+ const orchDestDir = path.join(target, plat.dirs.skills, 'orchestrator');
680
+ if (!fs.existsSync(orchDestDir)) fs.mkdirSync(orchDestDir, { recursive: true });
681
+ fs.copyFileSync(orchSrc, path.join(orchDestDir, 'SKILL.md'));
682
+ ok('Orchestrator skill installed');
683
+ }
684
684
 
685
- // 7. Copy schemas (always overwrite)
686
- if (plat.dirs.schemas) {
687
- info('Installing schemas...');
688
- const schemaSrc = path.join(AWK_ROOT, 'schemas');
689
- const schemaDest = path.join(target, plat.dirs.schemas);
690
- const schemaCount = copyDirRecursive(schemaSrc, schemaDest);
691
- ok(`${schemaCount} schemas installed`);
692
- }
685
+ // 7. Copy schemas (always overwrite)
686
+ if (plat.dirs.schemas) {
687
+ info('Installing schemas...');
688
+ const schemaSrc = path.join(AWK_ROOT, 'schemas');
689
+ const schemaDest = path.join(target, plat.dirs.schemas);
690
+ const schemaCount = copyDirRecursive(schemaSrc, schemaDest);
691
+ ok(`${schemaCount} schemas installed`);
692
+ }
693
693
 
694
- // 8. Copy templates (don't overwrite existing)
695
- if (plat.dirs.templates) {
696
- info('Installing templates...');
697
- const tmplSrc = path.join(AWK_ROOT, 'templates');
698
- const tmplDest = path.join(target, plat.dirs.templates);
699
- const tmplCount = copyDirRecursive(tmplSrc, tmplDest, { overwrite: false });
700
- ok(`${tmplCount} templates installed`);
701
- }
694
+ // 8. Copy templates (don't overwrite existing)
695
+ if (plat.dirs.templates) {
696
+ info('Installing templates...');
697
+ const tmplSrc = path.join(AWK_ROOT, 'templates');
698
+ const tmplDest = path.join(target, plat.dirs.templates);
699
+ const tmplCount = copyDirRecursive(tmplSrc, tmplDest, { overwrite: false });
700
+ ok(`${tmplCount} templates installed`);
701
+ }
702
702
 
703
- // 9. Save version
704
- fs.writeFileSync(plat.versionFile, AWK_VERSION);
705
- ok(`Version ${AWK_VERSION} saved`);
703
+ // 9. Save version
704
+ fs.writeFileSync(plat.versionFile, AWK_VERSION);
705
+ ok(`Version ${AWK_VERSION} saved`);
706
706
 
707
707
  // 10. Install default skill packs
708
708
  const defaultPacks = installDefaultPacks();
@@ -732,35 +732,35 @@ function cmdInstall(args = []) {
732
732
  ok(`Install state saved (${desiredSkills.size} active skills)`);
733
733
 
734
734
  // 11. Summary
735
- log('');
736
- log(`${C.gray}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}`);
737
- log(`${C.yellow}${C.bold}🎉 AWK v${AWK_VERSION} installed for ${plat.name}!${C.reset}`);
738
- log('');
739
- dim(`Platform: ${plat.name}`);
740
- if (plat.dirs.workflows) dim(`Workflows: ${path.join(target, plat.dirs.workflows)}`);
741
- if (plat.dirs.skills) dim(`Skills: ${path.join(target, plat.dirs.skills)}`);
742
- if (plat.dirs.schemas) dim(`Schemas: ${path.join(target, plat.dirs.schemas)}`);
743
- if (plat.dirs.templates) dim(`Templates: ${path.join(target, plat.dirs.templates)}`);
744
- if (plat.dirs.agents) dim(`Agents: ${path.join(target, plat.dirs.agents)}`);
735
+ log('');
736
+ log(`${C.gray}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}`);
737
+ log(`${C.yellow}${C.bold}🎉 AWK v${AWK_VERSION} installed for ${plat.name}!${C.reset}`);
738
+ log('');
739
+ dim(`Platform: ${plat.name}`);
740
+ if (plat.dirs.workflows) dim(`Workflows: ${path.join(target, plat.dirs.workflows)}`);
741
+ if (plat.dirs.skills) dim(`Skills: ${path.join(target, plat.dirs.skills)}`);
742
+ if (plat.dirs.schemas) dim(`Schemas: ${path.join(target, plat.dirs.schemas)}`);
743
+ if (plat.dirs.templates) dim(`Templates: ${path.join(target, plat.dirs.templates)}`);
744
+ if (plat.dirs.agents) dim(`Agents: ${path.join(target, plat.dirs.agents)}`);
745
745
 
746
- if (plat.rulesFile) {
747
- dim(`Global Rules: ${plat.rulesFile}`);
748
- }
749
- if (activePacks.length > 0) {
750
- dim(`Packs: ${activePacks.join(', ')}`);
751
- }
752
- if (platform === 'antigravity') {
753
- dim(`Symphony: task tracking ready`);
754
- }
755
- log('');
746
+ if (plat.rulesFile) {
747
+ dim(`Global Rules: ${plat.rulesFile}`);
748
+ }
749
+ if (activePacks.length > 0) {
750
+ dim(`Packs: ${activePacks.join(', ')}`);
751
+ }
752
+ if (platform === 'antigravity') {
753
+ dim(`Symphony: task tracking ready`);
754
+ }
755
+ log('');
756
756
 
757
- if (platform === 'antigravity') {
758
- log(`${C.cyan}👉 Run 'awkit init' in any project to initialize it.${C.reset}`);
759
- } else if (platform === 'codex') {
760
- log(`${C.cyan}👉 Type '$skill' in Codex to invoke skills.${C.reset}`);
761
- }
762
- log(`${C.cyan}👉 Run 'awkit doctor' to verify installation.${C.reset}`);
763
- log('');
757
+ if (platform === 'antigravity') {
758
+ log(`${C.cyan}👉 Run 'awkit init' in any project to initialize it.${C.reset}`);
759
+ } else if (platform === 'codex') {
760
+ log(`${C.cyan}👉 Type '$skill' in Codex to invoke skills.${C.reset}`);
761
+ }
762
+ log(`${C.cyan}👉 Run 'awkit doctor' to verify installation.${C.reset}`);
763
+ log('');
764
764
  } // End of platform loop
765
765
  }
766
766
 
@@ -987,7 +987,7 @@ function cmdBrowser(args) {
987
987
  }
988
988
 
989
989
  const recordingsDir = path.join(TARGETS.antigravity, 'browser_recordings');
990
-
990
+
991
991
  log('');
992
992
  log(`${C.cyan}${C.bold}🧹 AWK Browser Cleanup${C.reset}`);
993
993
  log('');
@@ -1016,7 +1016,7 @@ function cmdBrowser(args) {
1016
1016
  } else {
1017
1017
  log(`Cleaning browser recordings older than ${C.yellow}${keepDays} days${C.reset}...`);
1018
1018
  }
1019
-
1019
+
1020
1020
  const now = Date.now();
1021
1021
  const cutoff = now - (keepDays * 24 * 60 * 60 * 1000);
1022
1022
  let deletedCount = 0;
@@ -1772,7 +1772,7 @@ async function cmdAdmin() {
1772
1772
  stdio: 'ignore'
1773
1773
  });
1774
1774
  child.unref();
1775
-
1775
+
1776
1776
  info('Vui lòng đợi 3 giây để service khởi động...');
1777
1777
  await new Promise(r => setTimeout(r, 3000));
1778
1778
  }
@@ -1805,9 +1805,9 @@ async function cmdRestart() {
1805
1805
  // Probably no process running on port 3100
1806
1806
  dim('Không tìm thấy service đang chạy.');
1807
1807
  }
1808
-
1808
+
1809
1809
  await new Promise(r => setTimeout(r, 1000));
1810
-
1810
+
1811
1811
  // Auto-build production bundle so code changes take effect
1812
1812
  const symphonyDir = path.join(AWK_ROOT, '..', 'symphony');
1813
1813
  if (fs.existsSync(path.join(symphonyDir, 'package.json'))) {
@@ -1820,17 +1820,17 @@ async function cmdRestart() {
1820
1820
  dim(buildErr.message?.slice(0, 200));
1821
1821
  }
1822
1822
  }
1823
-
1823
+
1824
1824
  info('Đang khởi động lại service ngầm...');
1825
1825
  const child = spawn('symphony', ['start'], {
1826
1826
  detached: true,
1827
1827
  stdio: 'ignore'
1828
1828
  });
1829
1829
  child.unref();
1830
-
1830
+
1831
1831
  info('Vui lòng đợi 3 giây để service khởi động...');
1832
1832
  await new Promise(r => setTimeout(r, 3000));
1833
-
1833
+
1834
1834
  log(`${C.green}✅ Restart thành công!${C.reset}`);
1835
1835
  } catch (e) {
1836
1836
  err('Lỗi khi restart service: ' + e.message);
@@ -1958,8 +1958,8 @@ function cmdHelp() {
1958
1958
  log(` ${C.gray}awkit harvest # Pull live edits → repo${C.reset}`);
1959
1959
  log(` ${C.gray}awkit sync # harvest + install in one shot${C.reset}`);
1960
1960
  log('');
1961
- log(` ${C.cyan}# Enable NeuralMemory${C.reset}`);
1962
- log(` ${C.gray}awkit enable-pack neural-memory${C.reset}`);
1961
+ log(` ${C.cyan}# Enable Marketing Skills${C.reset}`);
1962
+ log(` ${C.gray}awkit enable-pack marketing${C.reset}`);
1963
1963
  log('');
1964
1964
  log(` ${C.cyan}# Repo${C.reset}`);
1965
1965
  log(` ${C.gray}https://github.com/babyskill/awk${C.reset}`);
@@ -2359,7 +2359,7 @@ async function cmdInit(forceFlag = false) {
2359
2359
  log('');
2360
2360
  warn('Trello API Key & Token are not set.');
2361
2361
  log(` 👉 To setup Trello integration, please get your credentials at: https://trello.com/app-key`);
2362
-
2362
+
2363
2363
  const readline = require('readline');
2364
2364
  const rl = readline.createInterface({
2365
2365
  input: process.stdin,
@@ -2388,14 +2388,14 @@ async function cmdInit(forceFlag = false) {
2388
2388
  if (!fs.existsSync(profilePath) && fs.existsSync(path.join(os.homedir(), '.bashrc'))) {
2389
2389
  profilePath = path.join(os.homedir(), '.bashrc');
2390
2390
  }
2391
-
2391
+
2392
2392
  const exportLines = `\n# Trello API Credentials for AWKit\nexport TRELLO_KEY="${apiKey}"\nexport TRELLO_TOKEN="${apiToken}"\n`;
2393
2393
  fs.appendFileSync(profilePath, exportLines);
2394
-
2394
+
2395
2395
  // Also inject into current process so immediate awkit trello calls work
2396
2396
  process.env.TRELLO_KEY = apiKey;
2397
2397
  process.env.TRELLO_TOKEN = apiToken;
2398
-
2398
+
2399
2399
  ok(`Credentials saved to ${path.basename(profilePath)} ✅`);
2400
2400
  log(` ${C.green}👉 Trello is ready! Credentials are active for this session and all future terminals.${C.reset}`);
2401
2401
  } else {
@@ -2470,7 +2470,7 @@ Additional project context can be found in:
2470
2470
  // ── 4.5. .gitignore ────────────────────────────────────────────────────────
2471
2471
  const gitignorePath = path.join(cwd, '.gitignore');
2472
2472
  const ignoreRules = ['log.txt', 'tmp/', '.gitnexus/', 'node_modules/'];
2473
-
2473
+
2474
2474
  if (fs.existsSync(gitignorePath)) {
2475
2475
  let content = fs.readFileSync(gitignorePath, 'utf8');
2476
2476
  let added = 0;
@@ -2556,10 +2556,10 @@ Additional project context can be found in:
2556
2556
  let openCmd = 'xdg-open';
2557
2557
  if (platform === 'darwin') openCmd = 'open';
2558
2558
  else if (platform === 'win32') openCmd = 'start ""';
2559
-
2559
+
2560
2560
  execSync(`${openCmd} "help.html"`, { cwd, stdio: 'ignore' });
2561
2561
  dim('Opened help.html in browser');
2562
- } catch(e) {
2562
+ } catch (e) {
2563
2563
  // Silently ignore if opening fails
2564
2564
  }
2565
2565
  }
@@ -3100,35 +3100,35 @@ function cmdTrello(args) {
3100
3100
  err("Credentials or config missing for REST API fallback.");
3101
3101
  break;
3102
3102
  }
3103
-
3103
+
3104
3104
  // 1. Get checklists
3105
3105
  const clRes = spawnSync('npx', ['--yes', 'trello-cli', 'card:checklists', '--board', cfgItem.board, '--list', cfgItem.list, '--card', cfgItem.card, '--format', 'json'], { env: { ...process.env, TRELLO_KEY: credItem.api_key, TRELLO_TOKEN: credItem.api_token }, encoding: 'utf-8' });
3106
-
3106
+
3107
3107
  if (clRes.status !== 0) {
3108
3108
  err(`Failed to get checklists: ${clRes.stderr || clRes.stdout}`);
3109
3109
  break;
3110
3110
  }
3111
-
3111
+
3112
3112
  try {
3113
3113
  // Sometime trello-cli outputs to stdout along with some other logs.
3114
3114
  // We extract the JSON array part.
3115
3115
  const outText = clRes.stdout;
3116
3116
  const jsonStr = outText.substring(outText.indexOf('['));
3117
3117
  const checklists = JSON.parse(jsonStr);
3118
-
3118
+
3119
3119
  if (!checklists || checklists.length === 0) {
3120
3120
  err("No checklists found on card. Create one first using 'awkit trello checklist <name>'.");
3121
3121
  break;
3122
3122
  }
3123
-
3123
+
3124
3124
  // Add to the LAST checklist (most recently appended usually)
3125
3125
  const targetChecklist = checklists[checklists.length - 1];
3126
3126
  const checklistId = targetChecklist.id;
3127
-
3127
+
3128
3128
  // 2. Add item via curl
3129
3129
  const url = `https://api.trello.com/1/checklists/${checklistId}/checkItems?name=${encodeURIComponent(text)}&key=${credItem.api_key}&token=${credItem.api_token}`;
3130
3130
  const addRes = spawnSync('curl', ['-s', '-X', 'POST', url], { encoding: 'utf-8' });
3131
-
3131
+
3132
3132
  const responseJson = JSON.parse(addRes.stdout);
3133
3133
  if (responseJson.id) {
3134
3134
  ok(`Item added successfully to checklist "${targetChecklist.name}".`);
@@ -3205,7 +3205,7 @@ function checkAutoUpdate() {
3205
3205
 
3206
3206
  function cmdServe(args) {
3207
3207
  const http = require('http');
3208
-
3208
+
3209
3209
  let port = 8080;
3210
3210
  let serveDir = process.cwd();
3211
3211
 
package/core/GEMINI.md CHANGED
@@ -54,6 +54,7 @@ Mỗi skill tự xử lý gate logic riêng — xem SKILL.md của từng skill.
54
54
  - KHÔNG hỏi user, KHÔNG chờ approval cho commit thường.
55
55
  - Commit message: conventional format (`fix:`, `feat:`, `refactor:`, `chore:`).
56
56
  - `git push` (non-force) được phép `SafeToAutoRun=true`.
57
+ - Sau khi commit & push thành công → tự động gửi thông báo Telegram qua tool hoặc lệnh `awkit tg send` (nếu người dùng đã cấu hình Telegram, có thể bỏ qua nếu chưa).
57
58
  - Nếu push fail → retry 1 lần với `git pull --rebase && git push`.
58
59
  - Nếu vẫn fail → báo user, KHÔNG force push.
59
60
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leejungkiin/awkit",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "Antigravity Workflow Kit. Unified AI agent orchestration system.",
5
5
  "main": "bin/awk.js",
6
6
  "bin": {
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "ads-management",
3
+ "auto_install": false,
4
+ "description": "App monetization strategies, ASO context, and AdMob ROAS/AARRR optimization",
5
+ "skills": [
6
+ "admob-roas"
7
+ ]
8
+ }
@@ -2,9 +2,5 @@
2
2
  "name": "mobile-android",
3
3
  "auto_install": false,
4
4
  "description": "Android development skills: Kotlin, Jetpack Compose, reverse engineering, AdMob ROAS, and APK analysis",
5
- "skills": [
6
- "smali-to-kotlin",
7
- "android-re-analyzer",
8
- "admob-roas"
9
- ]
10
- }
5
+ "skills": []
6
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neural-memory",
3
- "auto_install": false,
3
+ "auto_install": true,
4
4
  "description": "NeuralMemory-powered ambient brain sync with spreading activation recall",
5
5
  "skills": [
6
6
  "nm-memory-sync",
@@ -38,4 +38,4 @@
38
38
  "Claude Code": "Run: /plugin install neural-memory"
39
39
  }
40
40
  }
41
- }
41
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "reverse-engineering",
3
+ "auto_install": false,
4
+ "description": "Android & iOS remote engineering, decompilation, code porting, and smali modding capabilities",
5
+ "skills": [
6
+ "smali-to-kotlin",
7
+ "android-re-analyzer"
8
+ ]
9
+ }