@ihsandeen/aya 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/CONTRIBUTING.md +39 -0
  2. package/LICENSE +21 -0
  3. package/README.md +141 -0
  4. package/dist/commands/adab.js +28 -0
  5. package/dist/commands/adhan.js +58 -0
  6. package/dist/commands/anatomy.js +29 -0
  7. package/dist/commands/blame.js +29 -0
  8. package/dist/commands/commit.js +44 -0
  9. package/dist/commands/diff.js +54 -0
  10. package/dist/commands/dua.js +34 -0
  11. package/dist/commands/fast.js +36 -0
  12. package/dist/commands/friday.js +21 -0
  13. package/dist/commands/hero.js +69 -0
  14. package/dist/commands/hijri.js +42 -0
  15. package/dist/commands/history.js +98 -0
  16. package/dist/commands/init.js +54 -0
  17. package/dist/commands/invest.js +26 -0
  18. package/dist/commands/journal.js +84 -0
  19. package/dist/commands/journey.js +24 -0
  20. package/dist/commands/lens.js +58 -0
  21. package/dist/commands/memorize.js +117 -0
  22. package/dist/commands/mirror.js +47 -0
  23. package/dist/commands/names.js +48 -0
  24. package/dist/commands/nature.js +28 -0
  25. package/dist/commands/nazm.js +100 -0
  26. package/dist/commands/parable.js +332 -0
  27. package/dist/commands/prayers.js +63 -0
  28. package/dist/commands/pull.js +28 -0
  29. package/dist/commands/push.js +156 -0
  30. package/dist/commands/qibla.js +118 -0
  31. package/dist/commands/repo.js +34 -0
  32. package/dist/commands/sabr.js +32 -0
  33. package/dist/commands/scene.js +54 -0
  34. package/dist/commands/seek.js +28 -0
  35. package/dist/commands/shukr.js +22 -0
  36. package/dist/commands/sleep.js +26 -0
  37. package/dist/commands/sound.js +35 -0
  38. package/dist/commands/status.js +109 -0
  39. package/dist/commands/sunnah.js +24 -0
  40. package/dist/commands/tafsir.js +89 -0
  41. package/dist/commands/tasbih.js +50 -0
  42. package/dist/commands/wudu.js +22 -0
  43. package/dist/commands/zakat.js +72 -0
  44. package/dist/data/commands-db.js +365 -0
  45. package/dist/data/events.js +105 -0
  46. package/dist/data/gems.js +160 -0
  47. package/dist/data/nak.js +616 -0
  48. package/dist/data/tafsir.js +157 -0
  49. package/dist/data/vocab.js +105 -0
  50. package/dist/index.js +86 -0
  51. package/dist/server.js +140 -0
  52. package/dist/utils/config.js +38 -0
  53. package/dist/utils/logger.js +104 -0
  54. package/dist/utils/printer.js +36 -0
  55. package/docs/index.html +1048 -0
  56. package/docs/repo.html +952 -0
  57. package/package.json +55 -0
  58. package/public/hero.html +285 -0
  59. package/public/index.html +1039 -0
  60. package/public/repo.html +904 -0
  61. package/src/commands/adab.ts +24 -0
  62. package/src/commands/adhan.ts +55 -0
  63. package/src/commands/anatomy.ts +25 -0
  64. package/src/commands/blame.ts +31 -0
  65. package/src/commands/commit.ts +42 -0
  66. package/src/commands/diff.ts +56 -0
  67. package/src/commands/dua.ts +34 -0
  68. package/src/commands/fast.ts +35 -0
  69. package/src/commands/friday.ts +17 -0
  70. package/src/commands/hero.ts +73 -0
  71. package/src/commands/hijri.ts +43 -0
  72. package/src/commands/history.ts +103 -0
  73. package/src/commands/init.ts +53 -0
  74. package/src/commands/invest.ts +22 -0
  75. package/src/commands/journal.ts +97 -0
  76. package/src/commands/journey.ts +20 -0
  77. package/src/commands/lens.ts +58 -0
  78. package/src/commands/memorize.ts +131 -0
  79. package/src/commands/mirror.ts +48 -0
  80. package/src/commands/names.ts +46 -0
  81. package/src/commands/nature.ts +24 -0
  82. package/src/commands/nazm.ts +102 -0
  83. package/src/commands/parable.ts +360 -0
  84. package/src/commands/prayers.ts +65 -0
  85. package/src/commands/pull.ts +28 -0
  86. package/src/commands/push.ts +171 -0
  87. package/src/commands/qibla.ts +127 -0
  88. package/src/commands/repo.ts +34 -0
  89. package/src/commands/sabr.ts +28 -0
  90. package/src/commands/scene.ts +56 -0
  91. package/src/commands/seek.ts +24 -0
  92. package/src/commands/shukr.ts +19 -0
  93. package/src/commands/sleep.ts +23 -0
  94. package/src/commands/sound.ts +34 -0
  95. package/src/commands/status.ts +132 -0
  96. package/src/commands/sunnah.ts +21 -0
  97. package/src/commands/tafsir.ts +86 -0
  98. package/src/commands/tasbih.ts +49 -0
  99. package/src/commands/wudu.ts +19 -0
  100. package/src/commands/zakat.ts +73 -0
  101. package/src/data/commands-db.ts +372 -0
  102. package/src/data/events.ts +113 -0
  103. package/src/data/gems.ts +163 -0
  104. package/src/data/nak.ts +805 -0
  105. package/src/data/tafsir.ts +165 -0
  106. package/src/data/vocab.ts +114 -0
  107. package/src/index.ts +94 -0
  108. package/src/server.ts +128 -0
  109. package/src/utils/config.ts +44 -0
  110. package/src/utils/logger.ts +122 -0
  111. package/src/utils/printer.ts +38 -0
  112. package/tsconfig.json +16 -0
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.historyCommand = void 0;
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const inquirer_1 = __importDefault(require("inquirer"));
10
+ const ora_1 = __importDefault(require("ora"));
11
+ const events_1 = require("../data/events");
12
+ const printer_1 = require("../utils/printer");
13
+ const sleep = (ms) => new Promise(r => setTimeout(r, ms));
14
+ exports.historyCommand = new commander_1.Command('history')
15
+ .description('Interactive Timeline of Revelation')
16
+ .argument('[event]', 'Name of the historical event (e.g., badr, uhud, migration)')
17
+ .action(async (event) => {
18
+ (0, printer_1.printCommandHeader)('history');
19
+ if (event) {
20
+ const selectedEvent = events_1.eventsList.find(e => e.name.toLowerCase().includes(event.toLowerCase()) || e.id.toLowerCase().includes(event.toLowerCase()));
21
+ if (selectedEvent) {
22
+ await displayEvent(selectedEvent);
23
+ }
24
+ else {
25
+ console.log(chalk_1.default.red('Event not found.'));
26
+ }
27
+ return;
28
+ }
29
+ // Interactive Mode
30
+ let currentIndex = 0;
31
+ let keepRunning = true;
32
+ while (keepRunning) {
33
+ console.clear();
34
+ const currentEvent = events_1.eventsList[currentIndex];
35
+ console.log(chalk_1.default.yellow.bold('\n Timeline of the Seerah\n'));
36
+ // Timeline visualization
37
+ const totalEvents = events_1.eventsList.length;
38
+ const progress = Math.round(((currentIndex + 1) / totalEvents) * 20);
39
+ const progressBar = '█'.repeat(progress) + '░'.repeat(20 - progress);
40
+ console.log(chalk_1.default.gray(`[${progressBar}] ${currentIndex + 1}/${totalEvents}`));
41
+ await displayEvent(currentEvent, false);
42
+ const { action } = await inquirer_1.default.prompt([
43
+ {
44
+ type: 'list',
45
+ name: 'action',
46
+ message: 'Navigate:',
47
+ choices: [
48
+ { name: 'Next Event ▶', value: 'next', disabled: currentIndex === events_1.eventsList.length - 1 },
49
+ { name: 'Previous Event ◀', value: 'prev', disabled: currentIndex === 0 },
50
+ { name: 'Select Specific Event', value: 'select' },
51
+ { name: 'Exit', value: 'exit' }
52
+ ]
53
+ }
54
+ ]);
55
+ if (action === 'next') {
56
+ currentIndex++;
57
+ }
58
+ else if (action === 'prev') {
59
+ currentIndex--;
60
+ }
61
+ else if (action === 'select') {
62
+ const { selected } = await inquirer_1.default.prompt([
63
+ {
64
+ type: 'list',
65
+ name: 'selected',
66
+ message: 'Jump to:',
67
+ choices: events_1.eventsList.map((e, index) => ({ name: `${e.year} - ${e.name}`, value: index }))
68
+ }
69
+ ]);
70
+ currentIndex = selected;
71
+ }
72
+ else {
73
+ keepRunning = false;
74
+ }
75
+ }
76
+ });
77
+ async function displayEvent(event, animate = true) {
78
+ if (animate) {
79
+ const spinner = (0, ora_1.default)('Traveling back in time...').start();
80
+ await sleep(1000);
81
+ spinner.stop();
82
+ }
83
+ console.log(chalk_1.default.green.bold(`\n Year: ${event.year}`));
84
+ console.log(chalk_1.default.green(` Location: ${event.location}`));
85
+ console.log(chalk_1.default.blue.bold(`Event: ${event.name}`));
86
+ console.log('');
87
+ console.log(chalk_1.default.white.italic(event.scene));
88
+ console.log('');
89
+ if (animate)
90
+ await sleep(1500);
91
+ console.log(chalk_1.default.yellow.bold(' Revelation Sent Down:'));
92
+ console.log(chalk_1.default.cyan(`"${event.revelation}"`));
93
+ console.log(chalk_1.default.gray(`(Surah ${event.ayah})`));
94
+ if (event.details) {
95
+ console.log(chalk_1.default.gray(`\nNote: ${event.details}`));
96
+ }
97
+ console.log('');
98
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.initCommand = void 0;
7
+ const commander_1 = require("commander");
8
+ const inquirer_1 = __importDefault(require("inquirer"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const config_1 = require("../utils/config");
11
+ const printer_1 = require("../utils/printer");
12
+ exports.initCommand = new commander_1.Command('init')
13
+ .description('Set your intention (niyyah) for this session')
14
+ .action(async () => {
15
+ (0, printer_1.printCommandHeader)('init');
16
+ const config = (0, config_1.getConfig)();
17
+ console.log(chalk_1.default.green('Bismillah. Let us begin with the right intention.'));
18
+ const answers = await inquirer_1.default.prompt([
19
+ {
20
+ type: 'input',
21
+ name: 'name',
22
+ message: 'What is your name?',
23
+ default: config.name || 'Abdullah'
24
+ },
25
+ {
26
+ type: 'input',
27
+ name: 'intention',
28
+ message: 'What is your intention for this session?',
29
+ default: config.intention || 'Seeking the pleasure of Allah through code'
30
+ },
31
+ {
32
+ type: 'input',
33
+ name: 'city',
34
+ message: 'Where are you located (City)?',
35
+ default: config.location?.city || 'Mecca'
36
+ },
37
+ {
38
+ type: 'input',
39
+ name: 'country',
40
+ message: 'Where are you located (Country)?',
41
+ default: config.location?.country || 'Saudi Arabia'
42
+ }
43
+ ]);
44
+ (0, config_1.setConfig)({
45
+ name: answers.name,
46
+ intention: answers.intention,
47
+ location: {
48
+ city: answers.city,
49
+ country: answers.country
50
+ }
51
+ });
52
+ console.log(chalk_1.default.cyan(`\n✨ Intention set: "${answers.intention}"`));
53
+ console.log(chalk_1.default.gray('May Allah accept your efforts and place Barakah in your code.'));
54
+ });
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.investCommand = void 0;
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const inquirer_1 = __importDefault(require("inquirer"));
10
+ const printer_1 = require("../utils/printer");
11
+ exports.investCommand = new commander_1.Command('invest')
12
+ .description('Sadaqah Calculator (The Infinite ROI)')
13
+ .action(async () => {
14
+ (0, printer_1.printCommandHeader)('invest');
15
+ const { amount } = await inquirer_1.default.prompt([{
16
+ type: 'number',
17
+ name: 'amount',
18
+ message: 'Enter amount to invest (Sadaqah):'
19
+ }]);
20
+ console.log(chalk_1.default.yellow.bold(`\n Investment Analysis for $${amount}`));
21
+ console.log(chalk_1.default.white('\n Guarantor: The Lord of the Worlds'));
22
+ console.log(chalk_1.default.green(' Multiplier: 700x to Infinity (Surah Al-Baqarah 2:261)'));
23
+ console.log(chalk_1.default.blue(` Minimum Return (Hereafter): ${amount * 700} deeds`));
24
+ console.log(chalk_1.default.cyan(' Risk Factor: 0% ("Charity does not decrease wealth")'));
25
+ console.log(chalk_1.default.gray('\n "Who is it that would loan Allah a goodly loan so He may multiply it for him many times over?" (2:245)\n'));
26
+ });
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.journalCommand = void 0;
7
+ const commander_1 = require("commander");
8
+ const inquirer_1 = __importDefault(require("inquirer"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const os_1 = __importDefault(require("os"));
12
+ const path_1 = __importDefault(require("path"));
13
+ const boxen_1 = __importDefault(require("boxen"));
14
+ const printer_1 = require("../utils/printer");
15
+ const JOURNAL_FILE = path_1.default.join(os_1.default.homedir(), '.islamic-cli', 'journal.json');
16
+ const prescriptions = {
17
+ 'Anxious': {
18
+ ayah: '"Unquestionably, by the remembrance of Allah hearts are assured." (13:28)',
19
+ advice: 'Anxiety comes from fearing the future. But the future is in the Hands of the One who loves you most. Let go of the control you never had.',
20
+ dhikr: 'Hasbunallahu wa ni\'mal wakil (Allah is sufficient for us and He is the best Disposer of affairs)'
21
+ },
22
+ 'Grateful': {
23
+ ayah: '"If you are grateful, I will surely increase you." (14:7)',
24
+ advice: 'This is a beautiful state. Bind this blessing with gratitude so it doesn\'t escape. Use this energy to serve someone else today.',
25
+ dhikr: 'Alhamdulillah hamdan kathiran tayyiban mubarakan feeh'
26
+ },
27
+ 'Distracted': {
28
+ ayah: '"Competition in [worldly] increase diverts you until you visit the graveyards." (102:1-2)',
29
+ advice: 'The dunya is loud. It screams for your attention. But the grave is silent. Focus on what will matter when the noise stops.',
30
+ dhikr: 'La ilaha illa Allah (There is no deity but Allah)'
31
+ },
32
+ 'Empty': {
33
+ ayah: '"And We are closer to him than [his] jugular vein." (50:16)',
34
+ advice: 'That emptiness you feel? It\'s a hunger. Not for food, not for code, but for connection. Your soul is starving for its Creator. Feed it.',
35
+ dhikr: 'Ya Hayyu Ya Qayyum, bi rahmatika astagheeth'
36
+ },
37
+ 'Overwhelmed': {
38
+ ayah: '"Allah does not burden a soul beyond that it can bear." (2:286)',
39
+ advice: 'You feel like you\'re drowning, but you are just learning to swim in deeper waters. This pressure is building your capacity, not destroying you.',
40
+ dhikr: 'La hawla wa la quwwata illa billah (There is no power and no strength except by Allah)'
41
+ }
42
+ };
43
+ exports.journalCommand = new commander_1.Command('journal')
44
+ .description('Track your spiritual state (Tazkiyah)')
45
+ .action(async () => {
46
+ (0, printer_1.printCommandHeader)('journal');
47
+ console.log(chalk_1.default.green.bold('\nWelcome to your spiritual debugger.'));
48
+ console.log(chalk_1.default.gray('Let\'s check the logs of the heart.\n'));
49
+ const answers = await inquirer_1.default.prompt([
50
+ {
51
+ type: 'list',
52
+ name: 'state',
53
+ message: 'How is your heart feeling right now?',
54
+ choices: Object.keys(prescriptions)
55
+ }
56
+ ]);
57
+ const state = answers.state;
58
+ const prescription = prescriptions[state];
59
+ console.log('');
60
+ console.log((0, boxen_1.default)(`${chalk_1.default.bold(prescription.ayah)}\n\n` +
61
+ `${chalk_1.default.cyan(prescription.advice)}\n\n` +
62
+ `${chalk_1.default.yellow.bold('Prescribed Dhikr:')} ${prescription.dhikr}`, { padding: 1, margin: 1, borderStyle: 'round', borderColor: 'green', title: `Prescription for ${state}` }));
63
+ // Save to journal
64
+ let journal = [];
65
+ if (fs_1.default.existsSync(JOURNAL_FILE)) {
66
+ try {
67
+ journal = JSON.parse(fs_1.default.readFileSync(JOURNAL_FILE, 'utf-8'));
68
+ }
69
+ catch (e) {
70
+ journal = [];
71
+ }
72
+ }
73
+ journal.push({
74
+ date: new Date().toISOString(),
75
+ state
76
+ });
77
+ // Ensure directory exists
78
+ const dir = path_1.default.dirname(JOURNAL_FILE);
79
+ if (!fs_1.default.existsSync(dir)) {
80
+ fs_1.default.mkdirSync(dir, { recursive: true });
81
+ }
82
+ fs_1.default.writeFileSync(JOURNAL_FILE, JSON.stringify(journal, null, 2));
83
+ console.log(chalk_1.default.gray(`Entry logged. ${journal.length} entries in your history.`));
84
+ });
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.journeyCommand = void 0;
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const nak_1 = require("../data/nak");
10
+ const printer_1 = require("../utils/printer");
11
+ exports.journeyCommand = new commander_1.Command('journey')
12
+ .description('The Roadmap of the Soul (Alam al-Arwah to Jannah)')
13
+ .action(() => {
14
+ (0, printer_1.printCommandHeader)('journey');
15
+ console.log(chalk_1.default.yellow.bold('\n The Journey of the Soul\n'));
16
+ nak_1.journeyData.forEach((stage, index) => {
17
+ console.log(chalk_1.default.blue.bold(` ${index + 1}. ${stage.stage} (${stage.arabic})`));
18
+ console.log(chalk_1.default.white(` ${stage.description}`));
19
+ console.log(chalk_1.default.gray(` Reality: ${stage.reality}\n`));
20
+ if (index < nak_1.journeyData.length - 1) {
21
+ console.log(chalk_1.default.green(' |\n V\n'));
22
+ }
23
+ });
24
+ });
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.lensCommand = void 0;
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const inquirer_1 = __importDefault(require("inquirer"));
10
+ const nak_1 = require("../data/nak");
11
+ const printer_1 = require("../utils/printer");
12
+ exports.lensCommand = new commander_1.Command('lens')
13
+ .description('The Perspective Shifter (Contextual Meaning)')
14
+ .argument('[ref]', 'The Ayah reference (e.g. 20:25)')
15
+ .action(async (ref) => {
16
+ (0, printer_1.printCommandHeader)('lens');
17
+ // If no ref, list available or default?
18
+ let selectedData = ref
19
+ ? nak_1.lensData.find(d => d.ref === ref)
20
+ : null;
21
+ if (!selectedData) {
22
+ if (ref) {
23
+ console.log(chalk_1.default.red('Perspective analysis not found for that Ayah.'));
24
+ console.log(chalk_1.default.gray('Available: 20:25'));
25
+ return;
26
+ }
27
+ // Interactive selection
28
+ const { choice } = await inquirer_1.default.prompt([{
29
+ type: 'list',
30
+ name: 'choice',
31
+ message: 'Select an Ayah to view through different lenses:',
32
+ choices: nak_1.lensData.map(d => ({
33
+ name: `${d.ref}: ${d.text}`,
34
+ value: d
35
+ }))
36
+ }]);
37
+ selectedData = choice;
38
+ }
39
+ if (!selectedData)
40
+ return;
41
+ console.clear();
42
+ console.log(chalk_1.default.cyan.bold(`\n Aya Lens: ${selectedData.ref}`));
43
+ console.log(chalk_1.default.white.italic(`"${selectedData.text}"`));
44
+ console.log(chalk_1.default.gray('How does this Ayah hit differently depending on your state?\n'));
45
+ // Prompt for mode
46
+ const { mode } = await inquirer_1.default.prompt([{
47
+ type: 'list',
48
+ name: 'mode',
49
+ message: 'Select your current state/perspective:',
50
+ choices: selectedData.modes.map(m => ({
51
+ name: m.mode,
52
+ value: m
53
+ }))
54
+ }]);
55
+ console.log(chalk_1.default.green.bold(`\n Perspective: ${mode.mode}`));
56
+ console.log(chalk_1.default.white(mode.reflection));
57
+ console.log('');
58
+ });
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.memorizeCommand = void 0;
7
+ const commander_1 = require("commander");
8
+ const inquirer_1 = __importDefault(require("inquirer"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const os_1 = __importDefault(require("os"));
12
+ const path_1 = __importDefault(require("path"));
13
+ const vocab_1 = require("../data/vocab");
14
+ const printer_1 = require("../utils/printer");
15
+ const MEMORIZE_FILE = path_1.default.join(os_1.default.homedir(), '.islamic-cli', 'memorize.json');
16
+ function loadStats() {
17
+ try {
18
+ if (fs_1.default.existsSync(MEMORIZE_FILE)) {
19
+ return JSON.parse(fs_1.default.readFileSync(MEMORIZE_FILE, 'utf-8'));
20
+ }
21
+ }
22
+ catch (error) {
23
+ // Ignore error
24
+ }
25
+ return { streak: 0, lastPlayed: '', totalCorrect: 0 };
26
+ }
27
+ function saveStats(stats) {
28
+ try {
29
+ const dir = path_1.default.dirname(MEMORIZE_FILE);
30
+ if (!fs_1.default.existsSync(dir)) {
31
+ fs_1.default.mkdirSync(dir, { recursive: true });
32
+ }
33
+ fs_1.default.writeFileSync(MEMORIZE_FILE, JSON.stringify(stats, null, 2));
34
+ }
35
+ catch (error) {
36
+ console.error('Failed to save stats:', error);
37
+ }
38
+ }
39
+ exports.memorizeCommand = new commander_1.Command('memorize')
40
+ .description('Spaced repetition for Quranic vocabulary')
41
+ .action(async () => {
42
+ (0, printer_1.printCommandHeader)('memorize');
43
+ const stats = loadStats();
44
+ const today = new Date().toISOString().split('T')[0];
45
+ // Check streak
46
+ if (stats.lastPlayed) {
47
+ const lastDate = new Date(stats.lastPlayed);
48
+ const diffTime = Math.abs(new Date().getTime() - lastDate.getTime());
49
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
50
+ if (diffDays > 1 && stats.lastPlayed !== today) {
51
+ console.log(chalk_1.default.red('\nStreak broken!'));
52
+ stats.streak = 0;
53
+ }
54
+ }
55
+ if (stats.lastPlayed !== today) {
56
+ // New day
57
+ }
58
+ console.log(chalk_1.default.cyan.bold('\n Quranic Vocabulary Challenge'));
59
+ console.log(chalk_1.default.yellow(` Current Streak: ${stats.streak} days`));
60
+ console.log(chalk_1.default.gray(` Total Correct: ${stats.totalCorrect}`));
61
+ console.log('');
62
+ const { category } = await inquirer_1.default.prompt([
63
+ {
64
+ type: 'list',
65
+ name: 'category',
66
+ message: 'Choose a category:',
67
+ choices: [
68
+ { name: 'All Categories', value: 'all' },
69
+ { name: 'Surah Al-Fatiha', value: 'fatiha' },
70
+ { name: 'Names of Allah', value: 'names_of_allah' },
71
+ { name: 'Common Words', value: 'common' },
72
+ { name: 'Short Surahs', value: 'short_surahs' }
73
+ ]
74
+ }
75
+ ]);
76
+ let questions = vocab_1.vocabList;
77
+ if (category !== 'all') {
78
+ questions = vocab_1.vocabList.filter(v => v.category === category);
79
+ }
80
+ // Pick a random question
81
+ const vocab = questions[Math.floor(Math.random() * questions.length)];
82
+ console.log(chalk_1.default.white.bold(`\nComplete the Ayah (${vocab.category.replace('_', ' ')}):`));
83
+ console.log(chalk_1.default.green.italic(vocab.ayah.replace('_____', '_____')));
84
+ console.log('');
85
+ const { guess } = await inquirer_1.default.prompt([
86
+ {
87
+ type: 'input',
88
+ name: 'guess',
89
+ message: 'Type the missing word (transliteration):'
90
+ }
91
+ ]);
92
+ const userGuess = guess.toLowerCase().trim();
93
+ const correct = vocab.answer.toLowerCase();
94
+ // Simple Levenshtein distance check or substring check could be better, but exact match for now
95
+ // We can allow some leniency
96
+ if (userGuess === correct) {
97
+ console.log(chalk_1.default.green.bold('\nCorrect! MashAllah! 🎉'));
98
+ console.log(chalk_1.default.white(`Meaning: ${vocab.meaning}`));
99
+ if (stats.lastPlayed !== today) {
100
+ stats.streak += 1;
101
+ stats.lastPlayed = today;
102
+ }
103
+ stats.totalCorrect += 1;
104
+ saveStats(stats);
105
+ }
106
+ else {
107
+ console.log(chalk_1.default.red.bold('\nNot quite.'));
108
+ console.log(`The correct word is: ${chalk_1.default.yellow.bold(vocab.answer)}`);
109
+ console.log(`Meaning: ${vocab.meaning}`);
110
+ // Streak logic: strictly speaking, failing doesn't break streak unless you miss a day entirely.
111
+ // But maybe we don't increment streak if they fail?
112
+ // Let's just update lastPlayed so they keep the streak if they try again.
113
+ stats.lastPlayed = today;
114
+ saveStats(stats);
115
+ }
116
+ console.log('');
117
+ });
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.mirrorCommand = void 0;
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const inquirer_1 = __importDefault(require("inquirer"));
10
+ const nak_1 = require("../data/nak");
11
+ const printer_1 = require("../utils/printer");
12
+ exports.mirrorCommand = new commander_1.Command('mirror')
13
+ .description('The Quranic Personality Test')
14
+ .action(async () => {
15
+ (0, printer_1.printCommandHeader)('mirror');
16
+ console.clear();
17
+ console.log(chalk_1.default.magenta.bold('\n Aya Mirror: Finding Yourself in the Text'));
18
+ console.log(chalk_1.default.gray('"The Quran reads you while you read it."\n'));
19
+ // Loop through questions
20
+ for (const test of nak_1.mirrorData) {
21
+ const answer = await inquirer_1.default.prompt([{
22
+ type: 'list',
23
+ name: 'choice',
24
+ message: test.question,
25
+ choices: test.options.map(o => ({
26
+ name: o.label,
27
+ value: o.label // Using label as key for simplicity
28
+ }))
29
+ }]);
30
+ const result = test.options.find(o => o.label === answer.choice);
31
+ if (result) {
32
+ console.log(chalk_1.default.blue.bold(`\n Result: ${result.result}`));
33
+ console.log(chalk_1.default.green.italic(` Prescription: ${result.prescription}`));
34
+ }
35
+ console.log(chalk_1.default.gray('\n----------------------------------------\n'));
36
+ const { next } = await inquirer_1.default.prompt([{
37
+ type: 'confirm',
38
+ name: 'next',
39
+ message: 'Continue reflecting?',
40
+ default: true
41
+ }]);
42
+ if (!next)
43
+ break;
44
+ console.clear();
45
+ }
46
+ console.log(chalk_1.default.magenta('Reflection complete. May Allah guide our hearts.'));
47
+ });
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.namesCommand = void 0;
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const inquirer_1 = __importDefault(require("inquirer"));
10
+ const nak_1 = require("../data/nak");
11
+ const printer_1 = require("../utils/printer");
12
+ exports.namesCommand = new commander_1.Command('names')
13
+ .description('The 99 Names of Allah with Linguistic Nuance')
14
+ .action(async () => {
15
+ (0, printer_1.printCommandHeader)('names');
16
+ const { mode } = await inquirer_1.default.prompt([{
17
+ type: 'list',
18
+ name: 'mode',
19
+ message: 'Select a mode:',
20
+ choices: [
21
+ { name: 'Random Gem', value: 'random' },
22
+ { name: 'Browse All', value: 'browse' }
23
+ ]
24
+ }]);
25
+ if (mode === 'random') {
26
+ const gem = nak_1.namesData[Math.floor(Math.random() * nak_1.namesData.length)];
27
+ displayName(gem);
28
+ }
29
+ else {
30
+ const { name } = await inquirer_1.default.prompt([{
31
+ type: 'list',
32
+ name: 'name',
33
+ message: 'Select a Name:',
34
+ choices: nak_1.namesData.map(n => ({ name: `${n.transliteration} - ${n.translation}`, value: n }))
35
+ }]);
36
+ displayName(name);
37
+ }
38
+ });
39
+ function displayName(gem) {
40
+ console.clear();
41
+ console.log(chalk_1.default.yellow.bold(`\n ${gem.arabic} `));
42
+ console.log(chalk_1.default.white.bold(` ${gem.transliteration}`));
43
+ console.log(chalk_1.default.gray(` ${gem.translation}\n`));
44
+ console.log(chalk_1.default.cyan.bold(' Linguistic Nuance:'));
45
+ console.log(chalk_1.default.white(` ${gem.linguisticNuance}\n`));
46
+ console.log(chalk_1.default.green.bold(' Reflection:'));
47
+ console.log(chalk_1.default.white.italic(` ${gem.reflection}\n`));
48
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.natureCommand = void 0;
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const inquirer_1 = __importDefault(require("inquirer"));
10
+ const nak_1 = require("../data/nak");
11
+ const printer_1 = require("../utils/printer");
12
+ exports.natureCommand = new commander_1.Command('nature')
13
+ .description('Tadabbur in Creation')
14
+ .action(async () => {
15
+ (0, printer_1.printCommandHeader)('nature');
16
+ const { sign } = await inquirer_1.default.prompt([{
17
+ type: 'list',
18
+ name: 'sign',
19
+ message: 'Select a sign of creation to reflect upon:',
20
+ choices: nak_1.natureData.map(n => n.name)
21
+ }]);
22
+ const data = nak_1.natureData.find(n => n.name === sign);
23
+ if (data) {
24
+ console.log(chalk_1.default.green(data.ascii));
25
+ console.log(chalk_1.default.blue.bold(`\n ${data.name} (${data.ayah})`));
26
+ console.log(chalk_1.default.white(`\n ${data.reflection}\n`));
27
+ }
28
+ });