ramadan-cal 1.0.0 โ 1.0.2
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/README.md +5 -3
- package/package.json +1 -1
- package/scripts/postinstall.js +71 -12
- package/src/display.js +12 -0
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# ๐ ramadan-cal
|
|
2
2
|
|
|
3
|
-
A beautiful terminal Ramadan calendar with prayer times, daily progress
|
|
3
|
+
A beautiful terminal Ramadan 2026 (1447 Hijri) calendar with prayer times, Eid countdown, and daily progress โ available as a CLI tool and inside Claude Code.
|
|
4
|
+
|
|
5
|
+
[**Website**](https://ramadan-cal-site.onrender.com) ยท [**npm**](https://www.npmjs.com/package/ramadan-cal)
|
|
4
6
|
|
|
5
7
|
## Install
|
|
6
8
|
|
|
@@ -11,7 +13,7 @@ npm install -g ramadan-cal
|
|
|
11
13
|
## Usage
|
|
12
14
|
|
|
13
15
|
```bash
|
|
14
|
-
ramadan # Full display: prayer times + calendar
|
|
16
|
+
ramadan # Full display: prayer times + calendar + progress
|
|
15
17
|
ramadan times # Prayer times only
|
|
16
18
|
ramadan calendar # Calendar only
|
|
17
19
|
ramadan check # Check prayer times for any city
|
|
@@ -27,7 +29,7 @@ Prayer times are calculated offline using the [adhan](https://github.com/batoula
|
|
|
27
29
|
|
|
28
30
|
## Claude Code
|
|
29
31
|
|
|
30
|
-
During installation
|
|
32
|
+
During installation, ramadan-cal automatically sets up a Claude Code skill. Just type `ramadan` inside any Claude Code session to see your Ramadan dashboard โ prayer times, calendar, and Eid countdown โ without leaving your coding flow. Zero tokens used.
|
|
31
33
|
|
|
32
34
|
If you skipped during install, run `npm rebuild ramadan-cal` to set it up later.
|
|
33
35
|
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -14,6 +14,9 @@ import { createInterface } from 'readline';
|
|
|
14
14
|
const home = homedir();
|
|
15
15
|
const claudeDir = join(home, '.claude');
|
|
16
16
|
const claudeMd = join(claudeDir, 'CLAUDE.md');
|
|
17
|
+
const skillsDir = join(claudeDir, 'skills');
|
|
18
|
+
const ramadanSkillDir = join(skillsDir, 'ramadan');
|
|
19
|
+
const ramadanSkillFile = join(ramadanSkillDir, 'SKILL.md');
|
|
17
20
|
|
|
18
21
|
const MARKER = '<!-- ramadan-cal -->';
|
|
19
22
|
const CLAUDE_ENTRY = `
|
|
@@ -23,6 +26,22 @@ When the user types "ramadan" or any command starting with "ramadan" (like "rama
|
|
|
23
26
|
${MARKER}
|
|
24
27
|
`;
|
|
25
28
|
|
|
29
|
+
const SKILL_MARKER = '<!-- ramadan-cal-skill -->';
|
|
30
|
+
const RAMADAN_SKILL = `---
|
|
31
|
+
name: ramadan
|
|
32
|
+
description: Show Ramadan prayer times, Eid countdown, and Islamic calendar info. Use when the user invokes /ramadan with optional subcommands: times, calendar, eid YYYY-MM-DD, reset, check.
|
|
33
|
+
disable-model-invocation: true
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
${SKILL_MARKER}
|
|
37
|
+
|
|
38
|
+
Run the Ramadan CLI and display the output exactly as returned:
|
|
39
|
+
|
|
40
|
+
\`\`\`bash
|
|
41
|
+
ramadan $ARGUMENTS
|
|
42
|
+
\`\`\`
|
|
43
|
+
`;
|
|
44
|
+
|
|
26
45
|
function isClaudeInstalled() {
|
|
27
46
|
try {
|
|
28
47
|
execSync('which claude', { stdio: 'ignore' });
|
|
@@ -32,12 +51,24 @@ function isClaudeInstalled() {
|
|
|
32
51
|
}
|
|
33
52
|
}
|
|
34
53
|
|
|
35
|
-
function
|
|
54
|
+
function isClaudeMdConfigured() {
|
|
36
55
|
if (!existsSync(claudeMd)) return false;
|
|
37
56
|
const content = readFileSync(claudeMd, 'utf-8');
|
|
38
57
|
return content.includes(MARKER);
|
|
39
58
|
}
|
|
40
59
|
|
|
60
|
+
function isSkillInstalled() {
|
|
61
|
+
if (!existsSync(ramadanSkillFile)) return false;
|
|
62
|
+
const content = readFileSync(ramadanSkillFile, 'utf-8');
|
|
63
|
+
return content.includes(SKILL_MARKER);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function isConflictingSkill() {
|
|
67
|
+
if (!existsSync(ramadanSkillFile)) return false;
|
|
68
|
+
const content = readFileSync(ramadanSkillFile, 'utf-8');
|
|
69
|
+
return !content.includes(SKILL_MARKER);
|
|
70
|
+
}
|
|
71
|
+
|
|
41
72
|
function ask(question) {
|
|
42
73
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
43
74
|
return new Promise((resolve) => {
|
|
@@ -54,8 +85,11 @@ async function main() {
|
|
|
54
85
|
console.log(' Run `ramadan` to get started.');
|
|
55
86
|
console.log('');
|
|
56
87
|
|
|
57
|
-
|
|
58
|
-
|
|
88
|
+
const claudeMdConfigured = isClaudeMdConfigured();
|
|
89
|
+
const skillInstalled = isSkillInstalled();
|
|
90
|
+
|
|
91
|
+
// Check if already fully configured
|
|
92
|
+
if (claudeMdConfigured && skillInstalled) {
|
|
59
93
|
console.log(' โ Claude Code integration already configured');
|
|
60
94
|
return;
|
|
61
95
|
}
|
|
@@ -64,7 +98,6 @@ async function main() {
|
|
|
64
98
|
const claudeInstalled = isClaudeInstalled();
|
|
65
99
|
|
|
66
100
|
if (!claudeInstalled) {
|
|
67
|
-
// Not interactive โ just check if they might want it later
|
|
68
101
|
const answer = await ask(' Do you use Claude Code? (y/n) ');
|
|
69
102
|
|
|
70
103
|
if (answer !== 'y' && answer !== 'yes') {
|
|
@@ -84,7 +117,7 @@ async function main() {
|
|
|
84
117
|
} else {
|
|
85
118
|
console.log(' โ Claude Code detected');
|
|
86
119
|
|
|
87
|
-
const answer = await ask(' Set up Claude Code integration? Type `ramadan` in Claude Code
|
|
120
|
+
const answer = await ask(' Set up Claude Code integration? Type `ramadan` or `/ramadan` in Claude Code. (y/n) ');
|
|
88
121
|
|
|
89
122
|
if (answer !== 'y' && answer !== 'yes') {
|
|
90
123
|
console.log(' โ Skipped. Run `npm rebuild ramadan-cal` anytime to set it up later.\n');
|
|
@@ -99,15 +132,41 @@ async function main() {
|
|
|
99
132
|
}
|
|
100
133
|
|
|
101
134
|
// Write or append to CLAUDE.md
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
135
|
+
if (!claudeMdConfigured) {
|
|
136
|
+
if (existsSync(claudeMd)) {
|
|
137
|
+
appendFileSync(claudeMd, CLAUDE_ENTRY);
|
|
138
|
+
console.log(' โ Added ramadan command to ~/.claude/CLAUDE.md');
|
|
139
|
+
} else {
|
|
140
|
+
writeFileSync(claudeMd, CLAUDE_ENTRY.trimStart());
|
|
141
|
+
console.log(' โ Created ~/.claude/CLAUDE.md');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Create skills directory and ramadan skill
|
|
146
|
+
if (!skillInstalled) {
|
|
147
|
+
if (isConflictingSkill()) {
|
|
148
|
+
console.log(' โ ~/.claude/skills/ramadan/SKILL.md already exists (not created by this package).');
|
|
149
|
+
const overwrite = await ask(' Overwrite it? (y/n) ');
|
|
150
|
+
if (overwrite !== 'y' && overwrite !== 'yes') {
|
|
151
|
+
console.log(' โ Skipped skill creation. You can add it manually later.');
|
|
152
|
+
} else {
|
|
153
|
+
writeFileSync(ramadanSkillFile, RAMADAN_SKILL);
|
|
154
|
+
console.log(' โ Created ramadan skill โ type `/ramadan` in Claude Code');
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
if (!existsSync(skillsDir)) {
|
|
158
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
159
|
+
console.log(' โ Created ~/.claude/skills/');
|
|
160
|
+
}
|
|
161
|
+
if (!existsSync(ramadanSkillDir)) {
|
|
162
|
+
mkdirSync(ramadanSkillDir, { recursive: true });
|
|
163
|
+
}
|
|
164
|
+
writeFileSync(ramadanSkillFile, RAMADAN_SKILL);
|
|
165
|
+
console.log(' โ Created ramadan skill โ type `/ramadan` in Claude Code');
|
|
166
|
+
}
|
|
108
167
|
}
|
|
109
168
|
|
|
110
|
-
console.log(' โ Done! Type "ramadan" inside Claude Code
|
|
169
|
+
console.log(' โ Done! Type "ramadan" or "/ramadan" inside Claude Code.\n');
|
|
111
170
|
}
|
|
112
171
|
|
|
113
172
|
// Handle non-interactive environments (CI, piped input)
|
package/src/display.js
CHANGED
|
@@ -105,6 +105,18 @@ export function render(config, view = 'full') {
|
|
|
105
105
|
output.push(DIVIDER);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
// Last 10 nights โ odd night reminder
|
|
109
|
+
if (currentDay >= 20) {
|
|
110
|
+
const oddNights = [20, 22, 24, 26, 28];
|
|
111
|
+
if (oddNights.includes(currentDay)) {
|
|
112
|
+
output.push('');
|
|
113
|
+
output.push(chalk.bold.magenta('โจ Tonight is an odd night โ seek Laylatul Qadr'));
|
|
114
|
+
} else {
|
|
115
|
+
output.push('');
|
|
116
|
+
output.push(chalk.dim('๐ Tonight is not an odd night'));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
108
120
|
// Eid prompt
|
|
109
121
|
if (!config.eidDate && currentDay >= 28) {
|
|
110
122
|
output.push('');
|