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 CHANGED
@@ -1,6 +1,8 @@
1
1
  # ๐ŸŒ™ ramadan-cal
2
2
 
3
- A beautiful terminal Ramadan calendar with prayer times, daily progress, and Hijri date tracking.
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 you'll be asked if you want to set up Claude Code integration. If enabled, type `ramadan` inside any Claude Code session to see your calendar โ€” zero tokens used.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ramadan-cal",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "๐ŸŒ™ A beautiful terminal Ramadan calendar with prayer times, daily progress, and Hijri date",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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 isAlreadyConfigured() {
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
- // Check if already configured
58
- if (isAlreadyConfigured()) {
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 sessions. (y/n) ');
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 (existsSync(claudeMd)) {
103
- appendFileSync(claudeMd, CLAUDE_ENTRY);
104
- console.log(' โœ“ Added ramadan command to ~/.claude/CLAUDE.md');
105
- } else {
106
- writeFileSync(claudeMd, CLAUDE_ENTRY.trimStart());
107
- console.log(' โœ“ Created ~/.claude/CLAUDE.md');
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 and it\'ll just work.\n');
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('');