Enhance calendar CLI: add search, date, range, month commands
This commit is contained in:
parent
2206332ff0
commit
27d8f16313
2 changed files with 105 additions and 7 deletions
6
TOOLS.md
6
TOOLS.md
|
|
@ -141,6 +141,12 @@ calendar today # Today's events (default)
|
|||
calendar tomorrow # Tomorrow's events
|
||||
calendar week # Next 7 days
|
||||
calendar next # Next 14 days
|
||||
calendar month # Next 30 days
|
||||
calendar date 2026-02-20 # Events on a specific date
|
||||
calendar 2026-02-20 # Shorthand for date
|
||||
calendar range 2026-02-18 2026-02-25 # Date range
|
||||
calendar search dentist # Search by name/location (next 90 days)
|
||||
calendar search rpg 180 # Search with custom day range
|
||||
```
|
||||
|
||||
- Credentials: `.credentials/services.env` (NEXTCLOUD_URL, NEXTCLOUD_USER, NEXTCLOUD_PASS, CALDAV_CALENDAR)
|
||||
|
|
|
|||
102
bin/calendar
102
bin/calendar
|
|
@ -137,7 +137,29 @@ async function main() {
|
|||
const args = process.argv.slice(2);
|
||||
const cmd = args[0] || 'today';
|
||||
|
||||
// Parse date string (YYYY-MM-DD or natural offsets)
|
||||
function parseDate(str) {
|
||||
const m = str.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
||||
if (m) {
|
||||
const d = new Date(Date.UTC(+m[1], +m[2]-1, +m[3]));
|
||||
d.setUTCHours(0, 0, 0, 0);
|
||||
return d;
|
||||
}
|
||||
// Try as number of days offset
|
||||
const n = parseInt(str);
|
||||
if (!isNaN(n)) {
|
||||
const d = new Date();
|
||||
d.setUTCHours(0, 0, 0, 0);
|
||||
d.setUTCDate(d.getUTCDate() + n);
|
||||
return d;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
let range;
|
||||
let label = cmd;
|
||||
const searchQuery = args.slice(1).join(' ').toLowerCase();
|
||||
|
||||
switch (cmd) {
|
||||
case 'today':
|
||||
range = getDateRange(0, 1);
|
||||
|
|
@ -151,12 +173,71 @@ async function main() {
|
|||
case 'next':
|
||||
range = getDateRange(0, 14);
|
||||
break;
|
||||
case 'month':
|
||||
range = getDateRange(0, 30);
|
||||
break;
|
||||
case 'range': {
|
||||
// calendar range 2026-02-18 2026-02-25
|
||||
const from = args[1] && parseDate(args[1]);
|
||||
const to = args[2] && parseDate(args[2]);
|
||||
if (!from || !to) {
|
||||
console.error('Usage: calendar range <start-date> <end-date>');
|
||||
console.error(' Dates: YYYY-MM-DD or offset in days (e.g., 0 = today, 7 = in 7 days)');
|
||||
process.exit(1);
|
||||
}
|
||||
const fmt = d => d.toISOString().replace(/[-:]/g, '').replace(/\.\d+/, '');
|
||||
range = { start: fmt(from), end: fmt(to) };
|
||||
label = `${args[1]} to ${args[2]}`;
|
||||
break;
|
||||
}
|
||||
case 'search': {
|
||||
// calendar search <query> [days] — search events by name, default 30 days
|
||||
if (!searchQuery) {
|
||||
console.error('Usage: calendar search <query> [days]');
|
||||
console.error(' Searches event summaries/locations. Default: next 30 days.');
|
||||
process.exit(1);
|
||||
}
|
||||
const days = parseInt(args[args.length - 1]);
|
||||
const searchDays = (!isNaN(days) && args.length > 2) ? days : 90;
|
||||
range = getDateRange(0, searchDays);
|
||||
label = `search "${searchQuery}" (${searchDays} days)`;
|
||||
break;
|
||||
}
|
||||
case 'date': {
|
||||
// calendar date 2026-02-20
|
||||
const d = args[1] && parseDate(args[1]);
|
||||
if (!d) {
|
||||
console.error('Usage: calendar date <YYYY-MM-DD>');
|
||||
process.exit(1);
|
||||
}
|
||||
const next = new Date(d);
|
||||
next.setUTCDate(next.getUTCDate() + 1);
|
||||
const fmt = d => d.toISOString().replace(/[-:]/g, '').replace(/\.\d+/, '');
|
||||
range = { start: fmt(d), end: fmt(next) };
|
||||
label = args[1];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.log('Usage: calendar [today|tomorrow|week|next]');
|
||||
// Try as date: calendar 2026-02-20
|
||||
const asDate = parseDate(cmd);
|
||||
if (asDate) {
|
||||
const next = new Date(asDate);
|
||||
next.setUTCDate(next.getUTCDate() + 1);
|
||||
const fmt = d => d.toISOString().replace(/[-:]/g, '').replace(/\.\d+/, '');
|
||||
range = { start: fmt(asDate), end: fmt(next) };
|
||||
label = cmd;
|
||||
break;
|
||||
}
|
||||
console.log('Usage: calendar <command>');
|
||||
console.log(' today — Events for today (default)');
|
||||
console.log(' tomorrow — Events for tomorrow');
|
||||
console.log(' week — Events for the next 7 days');
|
||||
console.log(' next — Events for the next 14 days');
|
||||
console.log(' week — Next 7 days');
|
||||
console.log(' next — Next 14 days');
|
||||
console.log(' month — Next 30 days');
|
||||
console.log(' date <YYYY-MM-DD> — Events on a specific date');
|
||||
console.log(' <YYYY-MM-DD> — Shorthand for date');
|
||||
console.log(' range <from> <to> — Events in date range (YYYY-MM-DD or day offset)');
|
||||
console.log(' search <query> [days] — Search events by name/location (default: 90 days)');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
|
@ -167,9 +248,20 @@ async function main() {
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
const events = parseEvents(res.data);
|
||||
let events = parseEvents(res.data);
|
||||
|
||||
// Filter by search query if searching
|
||||
if (cmd === 'search' && searchQuery) {
|
||||
const q = searchQuery.replace(/\s+\d+$/, ''); // strip trailing days number
|
||||
events = events.filter(e =>
|
||||
(e.summary || '').toLowerCase().includes(q) ||
|
||||
(e.location || '').toLowerCase().includes(q) ||
|
||||
(e.description || '').toLowerCase().includes(q)
|
||||
);
|
||||
}
|
||||
|
||||
if (events.length === 0) {
|
||||
console.log(`No events (${cmd}).`);
|
||||
console.log(`No events (${label}).`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue