@ncukondo/gcal-cli 0.2.3 → 0.4.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.
- package/dist/index.js +409 -217
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -587668,6 +587668,24 @@ function formatSearchResultText(query, events) {
|
|
|
587668
587668
|
return lines.join(`
|
|
587669
587669
|
`);
|
|
587670
587670
|
}
|
|
587671
|
+
function formatQuietText(events) {
|
|
587672
|
+
if (events.length === 0)
|
|
587673
|
+
return "No events found.";
|
|
587674
|
+
const lines = [];
|
|
587675
|
+
for (const event of events) {
|
|
587676
|
+
const month = event.start.slice(5, 7);
|
|
587677
|
+
const day = event.start.slice(8, 10);
|
|
587678
|
+
const datePrefix = `${month}/${day}`;
|
|
587679
|
+
if (event.all_day) {
|
|
587680
|
+
lines.push(`${datePrefix} All day ${event.title}`);
|
|
587681
|
+
} else {
|
|
587682
|
+
const time3 = formatTimeRange(event);
|
|
587683
|
+
lines.push(`${datePrefix} ${time3} ${event.title}`);
|
|
587684
|
+
}
|
|
587685
|
+
}
|
|
587686
|
+
return lines.join(`
|
|
587687
|
+
`);
|
|
587688
|
+
}
|
|
587671
587689
|
var CALENDAR_ID_MAX = 15;
|
|
587672
587690
|
var CALENDAR_ID_COL = 18;
|
|
587673
587691
|
function truncateId(id) {
|
|
@@ -587736,7 +587754,7 @@ function errorCodeToExitCode(code) {
|
|
|
587736
587754
|
// package.json
|
|
587737
587755
|
var package_default = {
|
|
587738
587756
|
name: "@ncukondo/gcal-cli",
|
|
587739
|
-
version: "0.
|
|
587757
|
+
version: "0.4.0",
|
|
587740
587758
|
type: "module",
|
|
587741
587759
|
exports: {
|
|
587742
587760
|
".": "./dist/index.js"
|
|
@@ -587790,12 +587808,9 @@ var package_default = {
|
|
|
587790
587808
|
|
|
587791
587809
|
// src/cli.ts
|
|
587792
587810
|
var FormatSchema = _enum(["text", "json"]);
|
|
587793
|
-
function collect(value, previous) {
|
|
587794
|
-
return [...previous, value];
|
|
587795
|
-
}
|
|
587796
587811
|
function createProgram() {
|
|
587797
587812
|
const program2 = new Command;
|
|
587798
|
-
program2.name("gcal").description("CLI tool for managing Google Calendar events").version(package_default.version).option("-f, --format <format>", "Output format: text | json", "text").option("-
|
|
587813
|
+
program2.name("gcal").description("CLI tool for managing Google Calendar events").version(package_default.version).option("-f, --format <format>", "Output format: text | json", "text").option("-q, --quiet", "Minimal output", false).option("--tz, --timezone <zone>", "Timezone (e.g., Asia/Tokyo)");
|
|
587799
587814
|
program2.on("command:*", (operands) => {
|
|
587800
587815
|
process.stderr.write(`error: unknown command '${operands[0]}'
|
|
587801
587816
|
|
|
@@ -587815,7 +587830,6 @@ function resolveGlobalOptions(program2) {
|
|
|
587815
587830
|
}
|
|
587816
587831
|
return {
|
|
587817
587832
|
format: formatResult.data,
|
|
587818
|
-
calendar: raw.calendar,
|
|
587819
587833
|
timezone: raw.timezone,
|
|
587820
587834
|
quiet: raw.quiet
|
|
587821
587835
|
};
|
|
@@ -588424,6 +588438,61 @@ function applyFilters(events, options) {
|
|
|
588424
588438
|
const afterTransparency = filterByTransparency(events, options.transparency);
|
|
588425
588439
|
return filterByStatus(afterTransparency, options);
|
|
588426
588440
|
}
|
|
588441
|
+
|
|
588442
|
+
// src/commands/shared.ts
|
|
588443
|
+
import * as nodeFs from "node:fs";
|
|
588444
|
+
var fsAdapter = {
|
|
588445
|
+
existsSync: (p) => nodeFs.existsSync(p),
|
|
588446
|
+
readFileSync: (p) => nodeFs.readFileSync(p, "utf-8"),
|
|
588447
|
+
writeFileSync: (p, d) => nodeFs.writeFileSync(p, d, "utf-8"),
|
|
588448
|
+
mkdirSync: (p) => nodeFs.mkdirSync(p, { recursive: true }),
|
|
588449
|
+
unlinkSync: (p) => nodeFs.unlinkSync(p),
|
|
588450
|
+
chmodSync: (p, m) => nodeFs.chmodSync(p, m)
|
|
588451
|
+
};
|
|
588452
|
+
function collect(value, previous) {
|
|
588453
|
+
return [...previous, value];
|
|
588454
|
+
}
|
|
588455
|
+
function createGoogleCalendarApi(calendar) {
|
|
588456
|
+
return {
|
|
588457
|
+
calendarList: {
|
|
588458
|
+
list: async (p) => {
|
|
588459
|
+
const res = await calendar.calendarList.list(p);
|
|
588460
|
+
const data = {};
|
|
588461
|
+
if (res.data.items)
|
|
588462
|
+
data.items = res.data.items;
|
|
588463
|
+
if (res.data.nextPageToken)
|
|
588464
|
+
data.nextPageToken = res.data.nextPageToken;
|
|
588465
|
+
return { data };
|
|
588466
|
+
}
|
|
588467
|
+
},
|
|
588468
|
+
events: {
|
|
588469
|
+
list: async (p) => {
|
|
588470
|
+
const res = await calendar.events.list(p);
|
|
588471
|
+
const data = {};
|
|
588472
|
+
if (res.data.items)
|
|
588473
|
+
data.items = res.data.items;
|
|
588474
|
+
if (res.data.nextPageToken)
|
|
588475
|
+
data.nextPageToken = res.data.nextPageToken;
|
|
588476
|
+
return { data };
|
|
588477
|
+
},
|
|
588478
|
+
get: async (p) => {
|
|
588479
|
+
const res = await calendar.events.get(p);
|
|
588480
|
+
return { data: res.data };
|
|
588481
|
+
},
|
|
588482
|
+
insert: async (p) => {
|
|
588483
|
+
const res = await calendar.events.insert(p);
|
|
588484
|
+
return { data: res.data };
|
|
588485
|
+
},
|
|
588486
|
+
patch: async (p) => {
|
|
588487
|
+
const res = await calendar.events.patch(p);
|
|
588488
|
+
return { data: res.data };
|
|
588489
|
+
},
|
|
588490
|
+
delete: async (p) => {
|
|
588491
|
+
await calendar.events.delete(p);
|
|
588492
|
+
}
|
|
588493
|
+
}
|
|
588494
|
+
};
|
|
588495
|
+
}
|
|
588427
588496
|
// node_modules/date-fns/locale/en-US/_lib/formatDistance.mjs
|
|
588428
588497
|
var formatDistanceLocale = {
|
|
588429
588498
|
lessThanXSeconds: {
|
|
@@ -590596,8 +590665,8 @@ function parseDateTimeInZone(dateStr, timezone) {
|
|
|
590596
590665
|
// src/commands/search.ts
|
|
590597
590666
|
var DEFAULT_SEARCH_DAYS = 30;
|
|
590598
590667
|
async function handleSearch(opts) {
|
|
590599
|
-
const { api: api2, query, format: format4, calendars, timezone, write } = opts;
|
|
590600
|
-
const writeErr = opts.writeErr ?? (() => {});
|
|
590668
|
+
const { api: api2, query, format: format4, calendars, timezone, write, quiet } = opts;
|
|
590669
|
+
const writeErr = quiet ? () => {} : opts.writeErr ?? (() => {});
|
|
590601
590670
|
const now = new Date;
|
|
590602
590671
|
const days = opts.days ?? DEFAULT_SEARCH_DAYS;
|
|
590603
590672
|
const isNegativeDays = days < 0;
|
|
@@ -590605,7 +590674,7 @@ async function handleSearch(opts) {
|
|
|
590605
590674
|
let timeMax;
|
|
590606
590675
|
if (opts.from && opts.to) {
|
|
590607
590676
|
timeMin = formatDateTimeInZone(parseDateTimeInZone(opts.from, timezone), timezone);
|
|
590608
|
-
timeMax = formatDateTimeInZone(parseDateTimeInZone(opts.to
|
|
590677
|
+
timeMax = formatDateTimeInZone(addDays(parseDateTimeInZone(opts.to, timezone), 1), timezone);
|
|
590609
590678
|
} else if (opts.from) {
|
|
590610
590679
|
const startDate = parseDateTimeInZone(opts.from, timezone);
|
|
590611
590680
|
timeMin = formatDateTimeInZone(startDate, timezone);
|
|
@@ -590613,7 +590682,7 @@ async function handleSearch(opts) {
|
|
|
590613
590682
|
endDate.setDate(endDate.getDate() + days);
|
|
590614
590683
|
timeMax = formatDateTimeInZone(endDate, timezone);
|
|
590615
590684
|
} else if (opts.to) {
|
|
590616
|
-
timeMax = formatDateTimeInZone(parseDateTimeInZone(opts.to
|
|
590685
|
+
timeMax = formatDateTimeInZone(addDays(parseDateTimeInZone(opts.to, timezone), 1), timezone);
|
|
590617
590686
|
timeMin = formatDateTimeInZone(now, timezone);
|
|
590618
590687
|
} else if (isNegativeDays) {
|
|
590619
590688
|
const pastDate = new Date(now.getTime());
|
|
@@ -590627,7 +590696,7 @@ async function handleSearch(opts) {
|
|
|
590627
590696
|
timeMax = formatDateTimeInZone(endDate, timezone);
|
|
590628
590697
|
}
|
|
590629
590698
|
const displayFrom = timeMin.slice(0, 10);
|
|
590630
|
-
const displayTo = timeMax.slice(0, 10);
|
|
590699
|
+
const displayTo = opts.to ?? timeMax.slice(0, 10);
|
|
590631
590700
|
writeErr(`Searching: ${displayFrom} to ${displayTo}`);
|
|
590632
590701
|
const hasExplicitRange = opts.days !== undefined || opts.from !== undefined || opts.to !== undefined;
|
|
590633
590702
|
if (!hasExplicitRange) {
|
|
@@ -590648,6 +590717,8 @@ async function handleSearch(opts) {
|
|
|
590648
590717
|
events: filtered,
|
|
590649
590718
|
count: filtered.length
|
|
590650
590719
|
}));
|
|
590720
|
+
} else if (quiet) {
|
|
590721
|
+
write(formatQuietText(filtered));
|
|
590651
590722
|
} else {
|
|
590652
590723
|
write(formatSearchResultText(query, filtered));
|
|
590653
590724
|
}
|
|
@@ -590655,9 +590726,10 @@ async function handleSearch(opts) {
|
|
|
590655
590726
|
}
|
|
590656
590727
|
function createSearchCommand() {
|
|
590657
590728
|
const cmd = new Command("search").description("Search events by keyword").argument("<query>", "Search query string");
|
|
590729
|
+
cmd.option("-c, --calendar <id>", "Target calendar ID (repeatable)", collect, []);
|
|
590658
590730
|
cmd.option("--from <date>", "Start date for search range");
|
|
590659
590731
|
cmd.option("--to <date>", "End date for search range");
|
|
590660
|
-
cmd.option("--days <n>", "Search within next n days (default: 30)", Number.parseInt);
|
|
590732
|
+
cmd.option("--days <n>", "Search within next n days (default: 30)", (v) => Number.parseInt(v, 10));
|
|
590661
590733
|
const daysOpt = cmd.options.find((o) => o.long === "--days");
|
|
590662
590734
|
const fromOpt = cmd.options.find((o) => o.long === "--from");
|
|
590663
590735
|
const toOpt = cmd.options.find((o) => o.long === "--to");
|
|
@@ -590667,32 +590739,26 @@ function createSearchCommand() {
|
|
|
590667
590739
|
cmd.option("--busy", "Show only busy (opaque) events");
|
|
590668
590740
|
cmd.option("--free", "Show only free (transparent) events");
|
|
590669
590741
|
cmd.option("--confirmed", "Show only confirmed events");
|
|
590670
|
-
cmd.option("--include-tentative", "Include tentative events");
|
|
590742
|
+
cmd.option("--include-tentative", "Include tentative events (excluded by default)");
|
|
590743
|
+
const busyOpt = cmd.options.find((o) => o.long === "--busy");
|
|
590744
|
+
const freeOpt = cmd.options.find((o) => o.long === "--free");
|
|
590745
|
+
busyOpt.conflicts(["free"]);
|
|
590746
|
+
freeOpt.conflicts(["busy"]);
|
|
590671
590747
|
return cmd;
|
|
590672
590748
|
}
|
|
590673
590749
|
|
|
590674
590750
|
// src/commands/show.ts
|
|
590675
590751
|
async function handleShow(opts) {
|
|
590676
|
-
const { api: api2, eventId, calendarId, calendarName, format: format4, timezone, write } = opts;
|
|
590677
|
-
|
|
590678
|
-
|
|
590679
|
-
|
|
590680
|
-
|
|
590681
|
-
}
|
|
590682
|
-
|
|
590683
|
-
|
|
590684
|
-
return { exitCode: ExitCode.SUCCESS };
|
|
590685
|
-
} catch (error) {
|
|
590686
|
-
if (error instanceof ApiError) {
|
|
590687
|
-
if (format4 === "json") {
|
|
590688
|
-
write(formatJsonError(error.code, error.message));
|
|
590689
|
-
} else {
|
|
590690
|
-
write(`Error: ${error.message}`);
|
|
590691
|
-
}
|
|
590692
|
-
return { exitCode: errorCodeToExitCode(error.code) };
|
|
590693
|
-
}
|
|
590694
|
-
throw error;
|
|
590752
|
+
const { api: api2, eventId, calendarId, calendarName, format: format4, quiet, timezone, write } = opts;
|
|
590753
|
+
const event = await getEvent(api2, calendarId, calendarName, eventId, timezone);
|
|
590754
|
+
if (format4 === "json") {
|
|
590755
|
+
write(formatJsonSuccess({ event }));
|
|
590756
|
+
} else if (quiet) {
|
|
590757
|
+
write(`${event.title} ${event.start} ${event.end}`);
|
|
590758
|
+
} else {
|
|
590759
|
+
write(formatEventDetailText(event));
|
|
590695
590760
|
}
|
|
590761
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
590696
590762
|
}
|
|
590697
590763
|
function createShowCommand() {
|
|
590698
590764
|
return new Command("show").description("Show event details").argument("<event-id>", "Event ID").option("-c, --calendar <id>", "Calendar ID to query");
|
|
@@ -591778,24 +591844,6 @@ function resolveDateRange(input, timezone, now = () => new Date) {
|
|
|
591778
591844
|
timeMax: formatDateTimeInZone(end, timezone)
|
|
591779
591845
|
};
|
|
591780
591846
|
}
|
|
591781
|
-
function formatQuietText(events) {
|
|
591782
|
-
if (events.length === 0)
|
|
591783
|
-
return "No events found.";
|
|
591784
|
-
const lines = [];
|
|
591785
|
-
for (const event of events) {
|
|
591786
|
-
const month = event.start.slice(5, 7);
|
|
591787
|
-
const day = event.start.slice(8, 10);
|
|
591788
|
-
const datePrefix = `${month}/${day}`;
|
|
591789
|
-
if (event.all_day) {
|
|
591790
|
-
lines.push(`${datePrefix} All day ${event.title}`);
|
|
591791
|
-
} else {
|
|
591792
|
-
const time3 = formatTimeRange(event);
|
|
591793
|
-
lines.push(`${datePrefix} ${time3} ${event.title}`);
|
|
591794
|
-
}
|
|
591795
|
-
}
|
|
591796
|
-
return lines.join(`
|
|
591797
|
-
`);
|
|
591798
|
-
}
|
|
591799
591847
|
async function handleList(options, deps) {
|
|
591800
591848
|
const config2 = deps.loadConfig();
|
|
591801
591849
|
const timezone = resolveTimezone(options.timezone, config2.timezone);
|
|
@@ -591813,7 +591861,7 @@ async function handleList(options, deps) {
|
|
|
591813
591861
|
if (dateRange.warning && deps.writeErr) {
|
|
591814
591862
|
deps.writeErr(dateRange.warning);
|
|
591815
591863
|
}
|
|
591816
|
-
const calendars = selectCalendars(options.calendar, config2);
|
|
591864
|
+
const calendars = selectCalendars(options.calendar && options.calendar.length > 0 ? options.calendar : undefined, config2);
|
|
591817
591865
|
const apiOptions = {
|
|
591818
591866
|
timeMin: dateRange.timeMin,
|
|
591819
591867
|
timeMax: dateRange.timeMax
|
|
@@ -591852,6 +591900,7 @@ async function handleList(options, deps) {
|
|
|
591852
591900
|
}
|
|
591853
591901
|
function createListCommand() {
|
|
591854
591902
|
const cmd = new Command("list").description("List events within a date range");
|
|
591903
|
+
cmd.option("-c, --calendar <id>", "Target calendar ID (repeatable)", collect, []);
|
|
591855
591904
|
cmd.option("--today", "Show today's events");
|
|
591856
591905
|
cmd.option("--days <n>", "Events for next n days (default: 7)", (v) => Number.parseInt(v, 10));
|
|
591857
591906
|
cmd.option("--from <date>", "Start date (ISO 8601 or YYYY-MM-DD)");
|
|
@@ -591865,18 +591914,204 @@ function createListCommand() {
|
|
|
591865
591914
|
const fromOpt = cmd.options.find((o) => o.long === "--from");
|
|
591866
591915
|
const busyOpt = cmd.options.find((o) => o.long === "--busy");
|
|
591867
591916
|
const freeOpt = cmd.options.find((o) => o.long === "--free");
|
|
591917
|
+
const toOpt = cmd.options.find((o) => o.long === "--to");
|
|
591868
591918
|
todayOpt.conflicts(["days", "from"]);
|
|
591869
|
-
daysOpt.conflicts(["today", "from"]);
|
|
591919
|
+
daysOpt.conflicts(["today", "from", "to"]);
|
|
591870
591920
|
fromOpt.conflicts(["today", "days"]);
|
|
591921
|
+
toOpt.conflicts(["days"]);
|
|
591871
591922
|
busyOpt.conflicts(["free"]);
|
|
591872
591923
|
freeOpt.conflicts(["busy"]);
|
|
591873
591924
|
return cmd;
|
|
591874
591925
|
}
|
|
591875
591926
|
|
|
591927
|
+
// src/lib/date-utils.ts
|
|
591928
|
+
var DATE_ONLY_RE2 = /^\d{4}-\d{2}-\d{2}$/;
|
|
591929
|
+
function isDateOnly(input) {
|
|
591930
|
+
if (!DATE_ONLY_RE2.test(input))
|
|
591931
|
+
return false;
|
|
591932
|
+
const [y, m, d] = input.split("-").map(Number);
|
|
591933
|
+
const date3 = new Date(Date.UTC(y, m - 1, d));
|
|
591934
|
+
return date3.getUTCFullYear() === y && date3.getUTCMonth() === m - 1 && date3.getUTCDate() === d;
|
|
591935
|
+
}
|
|
591936
|
+
function addDaysToDateString(dateStr, days) {
|
|
591937
|
+
const [y, m, d] = dateStr.split("-").map(Number);
|
|
591938
|
+
const date3 = new Date(Date.UTC(y, m - 1, d + days));
|
|
591939
|
+
return date3.toISOString().slice(0, 10);
|
|
591940
|
+
}
|
|
591941
|
+
|
|
591942
|
+
// src/lib/duration.ts
|
|
591943
|
+
var DURATION_RE = /^(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?$/;
|
|
591944
|
+
function parseDuration(input) {
|
|
591945
|
+
const match2 = DURATION_RE.exec(input);
|
|
591946
|
+
if (!match2 || input === "") {
|
|
591947
|
+
throw new Error(`Invalid duration: "${input}". Use formats like 30m, 1h, 2d, 1h30m.`);
|
|
591948
|
+
}
|
|
591949
|
+
const days = Number(match2[1] || 0);
|
|
591950
|
+
const hours = Number(match2[2] || 0);
|
|
591951
|
+
const minutes = Number(match2[3] || 0);
|
|
591952
|
+
const ms = ((days * 24 + hours) * 60 + minutes) * 60 * 1000;
|
|
591953
|
+
if (ms === 0) {
|
|
591954
|
+
throw new Error("Duration must be greater than zero.");
|
|
591955
|
+
}
|
|
591956
|
+
return ms;
|
|
591957
|
+
}
|
|
591958
|
+
|
|
591876
591959
|
// src/commands/update.ts
|
|
591960
|
+
var MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
591961
|
+
function resolveTimedEvent(startStr, endStr, timezone) {
|
|
591962
|
+
const parsedStart = parseDateTimeInZone(startStr, timezone);
|
|
591963
|
+
const parsedEnd = parseDateTimeInZone(endStr, timezone);
|
|
591964
|
+
return {
|
|
591965
|
+
start: formatDateTimeInZone(parsedStart, timezone),
|
|
591966
|
+
end: formatDateTimeInZone(parsedEnd, timezone),
|
|
591967
|
+
allDay: false
|
|
591968
|
+
};
|
|
591969
|
+
}
|
|
591970
|
+
function resolveAllDayEvent(startStr, endStr) {
|
|
591971
|
+
return {
|
|
591972
|
+
start: startStr,
|
|
591973
|
+
end: addDaysToDateString(endStr, 1),
|
|
591974
|
+
allDay: true
|
|
591975
|
+
};
|
|
591976
|
+
}
|
|
591977
|
+
function resolveStartAndEnd(startStr, endStr, allDay, timezone) {
|
|
591978
|
+
if (allDay) {
|
|
591979
|
+
return resolveAllDayEvent(startStr, endStr);
|
|
591980
|
+
}
|
|
591981
|
+
return resolveTimedEvent(startStr, endStr, timezone);
|
|
591982
|
+
}
|
|
591983
|
+
function resolveStartAndDuration(startStr, durationMs, allDay, timezone) {
|
|
591984
|
+
if (allDay) {
|
|
591985
|
+
const days = durationMs / MS_PER_DAY;
|
|
591986
|
+
return {
|
|
591987
|
+
start: startStr,
|
|
591988
|
+
end: addDaysToDateString(startStr, days),
|
|
591989
|
+
allDay: true
|
|
591990
|
+
};
|
|
591991
|
+
}
|
|
591992
|
+
const parsedStart = parseDateTimeInZone(startStr, timezone);
|
|
591993
|
+
const endDate = new Date(parsedStart.getTime() + durationMs);
|
|
591994
|
+
return {
|
|
591995
|
+
start: formatDateTimeInZone(parsedStart, timezone),
|
|
591996
|
+
end: formatDateTimeInZone(endDate, timezone),
|
|
591997
|
+
allDay: false
|
|
591998
|
+
};
|
|
591999
|
+
}
|
|
592000
|
+
function resolveStartOnly(startStr, existing, allDay, timezone) {
|
|
592001
|
+
if (allDay) {
|
|
592002
|
+
const existingStartMs2 = new Date(existing.start).getTime();
|
|
592003
|
+
const existingEndMs2 = new Date(existing.end).getTime();
|
|
592004
|
+
const durationDays = Math.round((existingEndMs2 - existingStartMs2) / MS_PER_DAY);
|
|
592005
|
+
return {
|
|
592006
|
+
start: startStr,
|
|
592007
|
+
end: addDaysToDateString(startStr, durationDays),
|
|
592008
|
+
allDay: true,
|
|
592009
|
+
existingEvent: existing
|
|
592010
|
+
};
|
|
592011
|
+
}
|
|
592012
|
+
const existingStartMs = new Date(existing.start).getTime();
|
|
592013
|
+
const existingEndMs = new Date(existing.end).getTime();
|
|
592014
|
+
const durationMs = existingEndMs - existingStartMs;
|
|
592015
|
+
const parsedStart = parseDateTimeInZone(startStr, timezone);
|
|
592016
|
+
const endDate = new Date(parsedStart.getTime() + durationMs);
|
|
592017
|
+
return {
|
|
592018
|
+
start: formatDateTimeInZone(parsedStart, timezone),
|
|
592019
|
+
end: formatDateTimeInZone(endDate, timezone),
|
|
592020
|
+
allDay: false,
|
|
592021
|
+
existingEvent: existing
|
|
592022
|
+
};
|
|
592023
|
+
}
|
|
592024
|
+
function resolveEndOnly(endStr, existing, allDay, timezone) {
|
|
592025
|
+
if (allDay) {
|
|
592026
|
+
return {
|
|
592027
|
+
start: existing.start,
|
|
592028
|
+
end: addDaysToDateString(endStr, 1),
|
|
592029
|
+
allDay: true,
|
|
592030
|
+
existingEvent: existing
|
|
592031
|
+
};
|
|
592032
|
+
}
|
|
592033
|
+
const parsedEnd = parseDateTimeInZone(endStr, timezone);
|
|
592034
|
+
return {
|
|
592035
|
+
start: existing.start,
|
|
592036
|
+
end: formatDateTimeInZone(parsedEnd, timezone),
|
|
592037
|
+
allDay: false,
|
|
592038
|
+
existingEvent: existing
|
|
592039
|
+
};
|
|
592040
|
+
}
|
|
592041
|
+
function resolveDurationOnly(durationMs, existing, allDay, timezone) {
|
|
592042
|
+
if (allDay) {
|
|
592043
|
+
const days = durationMs / MS_PER_DAY;
|
|
592044
|
+
return {
|
|
592045
|
+
start: existing.start,
|
|
592046
|
+
end: addDaysToDateString(existing.start, days),
|
|
592047
|
+
allDay: true,
|
|
592048
|
+
existingEvent: existing
|
|
592049
|
+
};
|
|
592050
|
+
}
|
|
592051
|
+
const existingStartMs = new Date(existing.start).getTime();
|
|
592052
|
+
const endDate = new Date(existingStartMs + durationMs);
|
|
592053
|
+
return {
|
|
592054
|
+
start: existing.start,
|
|
592055
|
+
end: formatDateTimeInZone(endDate, timezone),
|
|
592056
|
+
allDay: false,
|
|
592057
|
+
existingEvent: existing
|
|
592058
|
+
};
|
|
592059
|
+
}
|
|
592060
|
+
async function resolveTimeUpdate(opts) {
|
|
592061
|
+
const { timezone, calendarId, calendarName, eventId, getEvent: getEvent2 } = opts;
|
|
592062
|
+
const hasStart = opts.start !== undefined;
|
|
592063
|
+
const hasEnd = opts.end !== undefined;
|
|
592064
|
+
const hasDuration = opts.duration !== undefined;
|
|
592065
|
+
if (!hasStart && !hasEnd && !hasDuration)
|
|
592066
|
+
return null;
|
|
592067
|
+
const durationMs = hasDuration ? parseDuration(opts.duration) : undefined;
|
|
592068
|
+
const needExisting = hasStart && !hasEnd && !hasDuration || hasEnd && !hasStart || hasDuration && !hasStart;
|
|
592069
|
+
let existing;
|
|
592070
|
+
if (needExisting) {
|
|
592071
|
+
existing = await getEvent2(calendarId, calendarName, eventId, timezone);
|
|
592072
|
+
}
|
|
592073
|
+
const allDay = hasStart ? isDateOnly(opts.start) : existing.all_day;
|
|
592074
|
+
if (hasStart && hasEnd) {
|
|
592075
|
+
const startIsDateOnly = isDateOnly(opts.start);
|
|
592076
|
+
const endIsDateOnly = isDateOnly(opts.end);
|
|
592077
|
+
if (startIsDateOnly !== endIsDateOnly) {
|
|
592078
|
+
throw new ApiError("INVALID_ARGS", "--start and --end must be the same type (both date-only or both datetime)");
|
|
592079
|
+
}
|
|
592080
|
+
}
|
|
592081
|
+
if (hasEnd && !hasStart && existing) {
|
|
592082
|
+
const endIsDateOnly = isDateOnly(opts.end);
|
|
592083
|
+
if (existing.all_day && !endIsDateOnly) {
|
|
592084
|
+
throw new ApiError("INVALID_ARGS", "--end format (datetime) does not match existing event type (all-day). Use date-only format (YYYY-MM-DD) or provide --start to change event type.");
|
|
592085
|
+
}
|
|
592086
|
+
if (!existing.all_day && endIsDateOnly) {
|
|
592087
|
+
throw new ApiError("INVALID_ARGS", "--end format (date-only) does not match existing event type (timed). Use datetime format (YYYY-MM-DDTHH:MM) or provide --start to change event type.");
|
|
592088
|
+
}
|
|
592089
|
+
}
|
|
592090
|
+
if (durationMs !== undefined && allDay) {
|
|
592091
|
+
if (durationMs % MS_PER_DAY !== 0) {
|
|
592092
|
+
throw new ApiError("INVALID_ARGS", "All-day events require day-unit duration (e.g. 1d, 2d). Sub-day durations like hours or minutes are not allowed.");
|
|
592093
|
+
}
|
|
592094
|
+
}
|
|
592095
|
+
if (hasStart && hasEnd) {
|
|
592096
|
+
return resolveStartAndEnd(opts.start, opts.end, allDay, timezone);
|
|
592097
|
+
}
|
|
592098
|
+
if (hasStart && durationMs !== undefined) {
|
|
592099
|
+
return resolveStartAndDuration(opts.start, durationMs, allDay, timezone);
|
|
592100
|
+
}
|
|
592101
|
+
if (hasStart) {
|
|
592102
|
+
return resolveStartOnly(opts.start, existing, allDay, timezone);
|
|
592103
|
+
}
|
|
592104
|
+
if (hasEnd) {
|
|
592105
|
+
return resolveEndOnly(opts.end, existing, allDay, timezone);
|
|
592106
|
+
}
|
|
592107
|
+
if (durationMs !== undefined) {
|
|
592108
|
+
return resolveDurationOnly(durationMs, existing, allDay, timezone);
|
|
592109
|
+
}
|
|
592110
|
+
return null;
|
|
592111
|
+
}
|
|
591877
592112
|
async function handleUpdate(opts) {
|
|
591878
592113
|
const { api: api2, eventId, calendarId, calendarName, format: format4, timezone, write } = opts;
|
|
591879
|
-
const hasUpdate = opts.title !== undefined || opts.start !== undefined || opts.end !== undefined || opts.description !== undefined || opts.busy !== undefined || opts.free !== undefined;
|
|
592114
|
+
const hasUpdate = opts.title !== undefined || opts.start !== undefined || opts.end !== undefined || opts.duration !== undefined || opts.description !== undefined || opts.busy !== undefined || opts.free !== undefined;
|
|
591880
592115
|
if (!hasUpdate) {
|
|
591881
592116
|
throw new ApiError("INVALID_ARGS", "at least one update option must be provided");
|
|
591882
592117
|
}
|
|
@@ -591892,19 +592127,21 @@ async function handleUpdate(opts) {
|
|
|
591892
592127
|
} else if (opts.free) {
|
|
591893
592128
|
input.transparency = "transparent";
|
|
591894
592129
|
}
|
|
591895
|
-
|
|
591896
|
-
|
|
591897
|
-
throw new ApiError("INVALID_ARGS", "start, end, and allDay must all be provided together");
|
|
591898
|
-
}
|
|
591899
|
-
const startStr = opts.start;
|
|
591900
|
-
const endStr = opts.end;
|
|
591901
|
-
const parsedStart = parseDateTimeInZone(startStr, timezone);
|
|
591902
|
-
const parsedEnd = parseDateTimeInZone(endStr, timezone);
|
|
592130
|
+
const timeResult = await resolveTimeUpdate(opts);
|
|
592131
|
+
if (timeResult) {
|
|
591903
592132
|
const withTime = input;
|
|
591904
|
-
withTime.start =
|
|
591905
|
-
withTime.end =
|
|
591906
|
-
withTime.allDay =
|
|
592133
|
+
withTime.start = timeResult.start;
|
|
592134
|
+
withTime.end = timeResult.end;
|
|
592135
|
+
withTime.allDay = timeResult.allDay;
|
|
591907
592136
|
input.timeZone = timezone;
|
|
592137
|
+
if (timeResult.existingEvent) {
|
|
592138
|
+
const existing = timeResult.existingEvent;
|
|
592139
|
+
if (existing.all_day && !timeResult.allDay) {
|
|
592140
|
+
opts.writeStderr("⚠ Event type changed from all-day to timed");
|
|
592141
|
+
} else if (!existing.all_day && timeResult.allDay) {
|
|
592142
|
+
opts.writeStderr("⚠ Event type changed from timed to all-day");
|
|
592143
|
+
}
|
|
592144
|
+
}
|
|
591908
592145
|
}
|
|
591909
592146
|
if (opts.dryRun) {
|
|
591910
592147
|
const changes = {};
|
|
@@ -591919,6 +592156,8 @@ async function handleUpdate(opts) {
|
|
|
591919
592156
|
changes.start = withTime.start;
|
|
591920
592157
|
if (withTime.end !== undefined)
|
|
591921
592158
|
changes.end = withTime.end;
|
|
592159
|
+
if (withTime.allDay !== undefined)
|
|
592160
|
+
changes.allDay = withTime.allDay;
|
|
591922
592161
|
if (format4 === "json") {
|
|
591923
592162
|
write(formatJsonSuccess({
|
|
591924
592163
|
dry_run: true,
|
|
@@ -591945,9 +592184,14 @@ async function handleUpdate(opts) {
|
|
|
591945
592184
|
}
|
|
591946
592185
|
const updated = await updateEvent(api2, calendarId, calendarName, eventId, input);
|
|
591947
592186
|
if (format4 === "json") {
|
|
591948
|
-
write(formatJsonSuccess({ event: updated }));
|
|
592187
|
+
write(formatJsonSuccess({ event: updated, message: "Event updated" }));
|
|
592188
|
+
} else if (opts.quiet) {
|
|
592189
|
+
write(updated.id);
|
|
591949
592190
|
} else {
|
|
591950
|
-
|
|
592191
|
+
const detail = formatEventDetailText(updated);
|
|
592192
|
+
write(`Event updated
|
|
592193
|
+
|
|
592194
|
+
${detail}`);
|
|
591951
592195
|
}
|
|
591952
592196
|
return { exitCode: ExitCode.SUCCESS };
|
|
591953
592197
|
}
|
|
@@ -591955,51 +592199,37 @@ function createUpdateCommand() {
|
|
|
591955
592199
|
const cmd = new Command("update").description("Update an existing event").argument("<event-id>", "Event ID to update");
|
|
591956
592200
|
cmd.option("-c, --calendar <id>", "Calendar ID");
|
|
591957
592201
|
cmd.option("-t, --title <title>", "New title");
|
|
591958
|
-
cmd.option("-s, --start <datetime>", "
|
|
591959
|
-
cmd.option("-e, --end <datetime>", "
|
|
592202
|
+
cmd.option("-s, --start <datetime>", "Start date or datetime. Date-only (YYYY-MM-DD) → all-day. Datetime (YYYY-MM-DDTHH:MM) → timed. Can be specified alone (preserves existing duration).");
|
|
592203
|
+
cmd.option("-e, --end <datetime>", "End date or datetime. Can be specified alone (preserves existing start). All-day end is inclusive.");
|
|
592204
|
+
cmd.option("--duration <duration>", "Duration instead of --end (e.g. 30m, 1h, 2d, 1h30m). Mutually exclusive with --end. Can be specified alone (preserves existing start).");
|
|
591960
592205
|
cmd.option("-d, --description <text>", "New description");
|
|
591961
592206
|
cmd.option("--busy", "Mark as busy");
|
|
591962
592207
|
cmd.option("--free", "Mark as free");
|
|
591963
592208
|
cmd.option("--dry-run", "Preview without executing");
|
|
592209
|
+
const endOpt = cmd.options.find((o) => o.long === "--end");
|
|
592210
|
+
const durationOpt = cmd.options.find((o) => o.long === "--duration");
|
|
592211
|
+
endOpt.conflicts(["duration"]);
|
|
592212
|
+
durationOpt.conflicts(["end"]);
|
|
591964
592213
|
const busyOpt = cmd.options.find((o) => o.long === "--busy");
|
|
591965
592214
|
const freeOpt = cmd.options.find((o) => o.long === "--free");
|
|
591966
592215
|
busyOpt.conflicts(["free"]);
|
|
591967
592216
|
freeOpt.conflicts(["busy"]);
|
|
592217
|
+
cmd.addHelpText("after", `
|
|
592218
|
+
Examples:
|
|
592219
|
+
gcal update abc123 -t "Updated Meeting" # Title only
|
|
592220
|
+
gcal update abc123 -s "2026-01-24T11:00" # Start only, keep duration
|
|
592221
|
+
gcal update abc123 -e "2026-01-24T12:00" # End only, keep start
|
|
592222
|
+
gcal update abc123 --duration 2h # Duration only, keep start
|
|
592223
|
+
gcal update abc123 -s "2026-01-24T11:00" -e "2026-01-24T12:30" # Start + end
|
|
592224
|
+
gcal update abc123 -s "2026-01-24T10:00" --duration 30m # Start + duration
|
|
592225
|
+
gcal update abc123 -s "2026-03-01" -e "2026-03-03" # All-day, 3 days (inclusive)
|
|
592226
|
+
gcal update abc123 -s "2026-03-01" --duration 2d # All-day, 2 days
|
|
592227
|
+
gcal update abc123 --free # Transparency only
|
|
592228
|
+
gcal update abc123 --dry-run -t "Preview" # Dry run
|
|
592229
|
+
`);
|
|
591968
592230
|
return cmd;
|
|
591969
592231
|
}
|
|
591970
592232
|
|
|
591971
|
-
// src/lib/date-utils.ts
|
|
591972
|
-
var DATE_ONLY_RE2 = /^\d{4}-\d{2}-\d{2}$/;
|
|
591973
|
-
function isDateOnly(input) {
|
|
591974
|
-
if (!DATE_ONLY_RE2.test(input))
|
|
591975
|
-
return false;
|
|
591976
|
-
const [y, m, d] = input.split("-").map(Number);
|
|
591977
|
-
const date3 = new Date(Date.UTC(y, m - 1, d));
|
|
591978
|
-
return date3.getUTCFullYear() === y && date3.getUTCMonth() === m - 1 && date3.getUTCDate() === d;
|
|
591979
|
-
}
|
|
591980
|
-
function addDaysToDateString(dateStr, days) {
|
|
591981
|
-
const [y, m, d] = dateStr.split("-").map(Number);
|
|
591982
|
-
const date3 = new Date(Date.UTC(y, m - 1, d + days));
|
|
591983
|
-
return date3.toISOString().slice(0, 10);
|
|
591984
|
-
}
|
|
591985
|
-
|
|
591986
|
-
// src/lib/duration.ts
|
|
591987
|
-
var DURATION_RE = /^(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?$/;
|
|
591988
|
-
function parseDuration(input) {
|
|
591989
|
-
const match2 = DURATION_RE.exec(input);
|
|
591990
|
-
if (!match2 || input === "") {
|
|
591991
|
-
throw new Error(`Invalid duration: "${input}". Use formats like 30m, 1h, 2d, 1h30m.`);
|
|
591992
|
-
}
|
|
591993
|
-
const days = Number(match2[1] || 0);
|
|
591994
|
-
const hours = Number(match2[2] || 0);
|
|
591995
|
-
const minutes = Number(match2[3] || 0);
|
|
591996
|
-
const ms = ((days * 24 + hours) * 60 + minutes) * 60 * 1000;
|
|
591997
|
-
if (ms === 0) {
|
|
591998
|
-
throw new Error("Duration must be greater than zero.");
|
|
591999
|
-
}
|
|
592000
|
-
return ms;
|
|
592001
|
-
}
|
|
592002
|
-
|
|
592003
592233
|
// src/commands/add.ts
|
|
592004
592234
|
async function handleAdd(options, deps) {
|
|
592005
592235
|
if (!options.title) {
|
|
@@ -592045,12 +592275,12 @@ async function handleAdd(options, deps) {
|
|
|
592045
592275
|
deps.write(formatJsonError("INVALID_ARGS", `Invalid duration: "${options.duration}". Use formats like 30m, 1h, 2d, 1h30m.`));
|
|
592046
592276
|
return { exitCode: ExitCode.ARGUMENT };
|
|
592047
592277
|
}
|
|
592048
|
-
const
|
|
592049
|
-
if (durationMs %
|
|
592278
|
+
const MS_PER_DAY2 = 24 * 60 * 60 * 1000;
|
|
592279
|
+
if (durationMs % MS_PER_DAY2 !== 0) {
|
|
592050
592280
|
deps.write(formatJsonError("INVALID_ARGS", "All-day events require day-unit duration (e.g. 1d, 2d). Sub-day durations like hours or minutes are not allowed."));
|
|
592051
592281
|
return { exitCode: ExitCode.ARGUMENT };
|
|
592052
592282
|
}
|
|
592053
|
-
const days = durationMs /
|
|
592283
|
+
const days = durationMs / MS_PER_DAY2;
|
|
592054
592284
|
end = addDaysToDateString(options.start, days);
|
|
592055
592285
|
} else {
|
|
592056
592286
|
end = addDaysToDateString(options.start, 1);
|
|
@@ -592087,9 +592317,37 @@ async function handleAdd(options, deps) {
|
|
|
592087
592317
|
if (options.description !== undefined) {
|
|
592088
592318
|
input.description = options.description;
|
|
592089
592319
|
}
|
|
592320
|
+
if (options.dryRun) {
|
|
592321
|
+
const preview = {
|
|
592322
|
+
title: input.title,
|
|
592323
|
+
start: input.start,
|
|
592324
|
+
end: input.end
|
|
592325
|
+
};
|
|
592326
|
+
if (input.description !== undefined)
|
|
592327
|
+
preview.description = input.description;
|
|
592328
|
+
if (input.transparency !== "opaque")
|
|
592329
|
+
preview.transparency = input.transparency;
|
|
592330
|
+
if (options.format === "json") {
|
|
592331
|
+
deps.write(formatJsonSuccess({ dry_run: true, action: "add", event: preview }));
|
|
592332
|
+
} else {
|
|
592333
|
+
const lines = ["DRY RUN: Would create event:"];
|
|
592334
|
+
lines.push(` title: "${preview.title}"`);
|
|
592335
|
+
lines.push(` start: "${preview.start}"`);
|
|
592336
|
+
lines.push(` end: "${preview.end}"`);
|
|
592337
|
+
if (preview.description !== undefined)
|
|
592338
|
+
lines.push(` description: "${preview.description}"`);
|
|
592339
|
+
if (preview.transparency !== undefined)
|
|
592340
|
+
lines.push(` transparency: ${preview.transparency}`);
|
|
592341
|
+
deps.write(lines.join(`
|
|
592342
|
+
`));
|
|
592343
|
+
}
|
|
592344
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
592345
|
+
}
|
|
592090
592346
|
const event = await deps.createEvent(calendarId, calendarName, input);
|
|
592091
592347
|
if (options.format === "json") {
|
|
592092
592348
|
deps.write(formatJsonSuccess({ event, message: "Event created" }));
|
|
592349
|
+
} else if (options.quiet) {
|
|
592350
|
+
deps.write(event.id);
|
|
592093
592351
|
} else {
|
|
592094
592352
|
const detail = formatEventDetailText(event);
|
|
592095
592353
|
deps.write(`Event created
|
|
@@ -592104,9 +592362,11 @@ function createAddCommand() {
|
|
|
592104
592362
|
cmd.requiredOption("-s, --start <datetime>", "Start date or datetime. Date-only (YYYY-MM-DD) creates all-day event. Datetime (YYYY-MM-DDTHH:MM) creates timed event.");
|
|
592105
592363
|
cmd.option("-e, --end <datetime>", "End date or datetime. Optional. Default: same day (all-day) or +1h (timed). All-day end is inclusive.");
|
|
592106
592364
|
cmd.option("--duration <duration>", "Duration instead of --end (e.g. 30m, 1h, 2d, 1h30m). Mutually exclusive with --end.");
|
|
592365
|
+
cmd.option("-c, --calendar <id>", "Target calendar ID");
|
|
592107
592366
|
cmd.option("-d, --description <text>", "Event description");
|
|
592108
592367
|
cmd.option("--busy", "Mark as busy (default)");
|
|
592109
592368
|
cmd.option("--free", "Mark as free (transparent)");
|
|
592369
|
+
cmd.option("--dry-run", "Preview without executing");
|
|
592110
592370
|
const endOpt = cmd.options.find((o) => o.long === "--end");
|
|
592111
592371
|
const durationOpt = cmd.options.find((o) => o.long === "--duration");
|
|
592112
592372
|
endOpt.conflicts(["duration"]);
|
|
@@ -592132,8 +592392,7 @@ Examples:
|
|
|
592132
592392
|
async function handleDelete(opts) {
|
|
592133
592393
|
const { api: api2, eventId, calendarId, format: format4, quiet, dryRun = false, write } = opts;
|
|
592134
592394
|
if (!eventId) {
|
|
592135
|
-
|
|
592136
|
-
return { exitCode: ExitCode.ARGUMENT };
|
|
592395
|
+
throw new ApiError("INVALID_ARGS", "event-id is required");
|
|
592137
592396
|
}
|
|
592138
592397
|
if (dryRun) {
|
|
592139
592398
|
if (format4 === "json") {
|
|
@@ -592148,27 +592407,15 @@ async function handleDelete(opts) {
|
|
|
592148
592407
|
}
|
|
592149
592408
|
return { exitCode: ExitCode.SUCCESS };
|
|
592150
592409
|
}
|
|
592151
|
-
|
|
592152
|
-
|
|
592153
|
-
if (
|
|
592154
|
-
|
|
592155
|
-
|
|
592156
|
-
|
|
592157
|
-
write("Event deleted");
|
|
592158
|
-
}
|
|
592159
|
-
}
|
|
592160
|
-
return { exitCode: ExitCode.SUCCESS };
|
|
592161
|
-
} catch (error) {
|
|
592162
|
-
if (error instanceof ApiError) {
|
|
592163
|
-
if (format4 === "json") {
|
|
592164
|
-
write(formatJsonError(error.code, error.message));
|
|
592165
|
-
} else {
|
|
592166
|
-
write(`Error: ${error.message}`);
|
|
592167
|
-
}
|
|
592168
|
-
return { exitCode: errorCodeToExitCode(error.code) };
|
|
592410
|
+
await deleteEvent(api2, calendarId, eventId);
|
|
592411
|
+
if (!quiet) {
|
|
592412
|
+
if (format4 === "json") {
|
|
592413
|
+
write(formatJsonSuccess({ deleted_id: eventId, message: "Event deleted" }));
|
|
592414
|
+
} else {
|
|
592415
|
+
write("Event deleted");
|
|
592169
592416
|
}
|
|
592170
|
-
throw error;
|
|
592171
592417
|
}
|
|
592418
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
592172
592419
|
}
|
|
592173
592420
|
function createDeleteCommand() {
|
|
592174
592421
|
return new Command("delete").description("Delete a calendar event").argument("<event-id>", "Event ID").option("-c, --calendar <id>", "Calendar ID to query").option("--dry-run", "Preview without executing");
|
|
@@ -592187,20 +592434,7 @@ function mergeCalendarsWithConfig(apiCalendars, configCalendars) {
|
|
|
592187
592434
|
}
|
|
592188
592435
|
async function handleCalendars(opts) {
|
|
592189
592436
|
const { api: api2, format: format4, quiet, write, configCalendars } = opts;
|
|
592190
|
-
|
|
592191
|
-
try {
|
|
592192
|
-
apiCalendars = await listCalendars(api2);
|
|
592193
|
-
} catch (error) {
|
|
592194
|
-
if (error instanceof ApiError) {
|
|
592195
|
-
if (format4 === "json") {
|
|
592196
|
-
write(formatJsonError(error.code, error.message));
|
|
592197
|
-
} else {
|
|
592198
|
-
write(error.message);
|
|
592199
|
-
}
|
|
592200
|
-
return { exitCode: errorCodeToExitCode(error.code) };
|
|
592201
|
-
}
|
|
592202
|
-
throw error;
|
|
592203
|
-
}
|
|
592437
|
+
const apiCalendars = await listCalendars(api2);
|
|
592204
592438
|
const calendars = mergeCalendarsWithConfig(apiCalendars, configCalendars);
|
|
592205
592439
|
if (quiet) {
|
|
592206
592440
|
write(calendars.map((c) => c.id).join(`
|
|
@@ -592312,58 +592546,6 @@ function createInitCommand() {
|
|
|
592312
592546
|
return cmd;
|
|
592313
592547
|
}
|
|
592314
592548
|
|
|
592315
|
-
// src/commands/shared.ts
|
|
592316
|
-
import * as nodeFs from "node:fs";
|
|
592317
|
-
var fsAdapter = {
|
|
592318
|
-
existsSync: (p) => nodeFs.existsSync(p),
|
|
592319
|
-
readFileSync: (p) => nodeFs.readFileSync(p, "utf-8"),
|
|
592320
|
-
writeFileSync: (p, d) => nodeFs.writeFileSync(p, d, "utf-8"),
|
|
592321
|
-
mkdirSync: (p) => nodeFs.mkdirSync(p, { recursive: true }),
|
|
592322
|
-
unlinkSync: (p) => nodeFs.unlinkSync(p),
|
|
592323
|
-
chmodSync: (p, m) => nodeFs.chmodSync(p, m)
|
|
592324
|
-
};
|
|
592325
|
-
function createGoogleCalendarApi(calendar) {
|
|
592326
|
-
return {
|
|
592327
|
-
calendarList: {
|
|
592328
|
-
list: async (p) => {
|
|
592329
|
-
const res = await calendar.calendarList.list(p);
|
|
592330
|
-
const data = {};
|
|
592331
|
-
if (res.data.items)
|
|
592332
|
-
data.items = res.data.items;
|
|
592333
|
-
if (res.data.nextPageToken)
|
|
592334
|
-
data.nextPageToken = res.data.nextPageToken;
|
|
592335
|
-
return { data };
|
|
592336
|
-
}
|
|
592337
|
-
},
|
|
592338
|
-
events: {
|
|
592339
|
-
list: async (p) => {
|
|
592340
|
-
const res = await calendar.events.list(p);
|
|
592341
|
-
const data = {};
|
|
592342
|
-
if (res.data.items)
|
|
592343
|
-
data.items = res.data.items;
|
|
592344
|
-
if (res.data.nextPageToken)
|
|
592345
|
-
data.nextPageToken = res.data.nextPageToken;
|
|
592346
|
-
return { data };
|
|
592347
|
-
},
|
|
592348
|
-
get: async (p) => {
|
|
592349
|
-
const res = await calendar.events.get(p);
|
|
592350
|
-
return { data: res.data };
|
|
592351
|
-
},
|
|
592352
|
-
insert: async (p) => {
|
|
592353
|
-
const res = await calendar.events.insert(p);
|
|
592354
|
-
return { data: res.data };
|
|
592355
|
-
},
|
|
592356
|
-
patch: async (p) => {
|
|
592357
|
-
const res = await calendar.events.patch(p);
|
|
592358
|
-
return { data: res.data };
|
|
592359
|
-
},
|
|
592360
|
-
delete: async (p) => {
|
|
592361
|
-
await calendar.events.delete(p);
|
|
592362
|
-
}
|
|
592363
|
-
}
|
|
592364
|
-
};
|
|
592365
|
-
}
|
|
592366
|
-
|
|
592367
592549
|
// src/cli.ts
|
|
592368
592550
|
var FormatSchema2 = _enum(["text", "json"]);
|
|
592369
592551
|
function resolveGlobalOptions2(program2) {
|
|
@@ -592376,7 +592558,6 @@ function resolveGlobalOptions2(program2) {
|
|
|
592376
592558
|
}
|
|
592377
592559
|
return {
|
|
592378
592560
|
format: formatResult.data,
|
|
592379
|
-
calendar: raw.calendar,
|
|
592380
592561
|
timezone: raw.timezone,
|
|
592381
592562
|
quiet: raw.quiet
|
|
592382
592563
|
};
|
|
@@ -592489,19 +592670,23 @@ ${url}`);
|
|
|
592489
592670
|
const calendarsCmd = createCalendarsCommand();
|
|
592490
592671
|
calendarsCmd.action(async () => {
|
|
592491
592672
|
const globalOpts = resolveGlobalOptions2(program2);
|
|
592492
|
-
|
|
592493
|
-
|
|
592494
|
-
|
|
592495
|
-
|
|
592496
|
-
|
|
592497
|
-
|
|
592498
|
-
|
|
592499
|
-
|
|
592500
|
-
|
|
592673
|
+
try {
|
|
592674
|
+
const config2 = loadConfig(fsAdapter);
|
|
592675
|
+
const oauth2Client = await getAuthenticatedClient(fsAdapter);
|
|
592676
|
+
const calendar = import_googleapis2.google.calendar({ version: "v3", auth: oauth2Client });
|
|
592677
|
+
const api2 = createGoogleCalendarApi(calendar);
|
|
592678
|
+
const result = await handleCalendars({
|
|
592679
|
+
api: api2,
|
|
592680
|
+
format: globalOpts.format,
|
|
592681
|
+
quiet: globalOpts.quiet,
|
|
592682
|
+
write: (msg) => process.stdout.write(msg + `
|
|
592501
592683
|
`),
|
|
592502
|
-
|
|
592503
|
-
|
|
592504
|
-
|
|
592684
|
+
configCalendars: config2.calendars
|
|
592685
|
+
});
|
|
592686
|
+
process.exit(result.exitCode);
|
|
592687
|
+
} catch (error) {
|
|
592688
|
+
handleError2(error, globalOpts.format);
|
|
592689
|
+
}
|
|
592505
592690
|
});
|
|
592506
592691
|
program2.addCommand(calendarsCmd);
|
|
592507
592692
|
const listCmd = createListCommand();
|
|
@@ -592510,7 +592695,7 @@ ${url}`);
|
|
|
592510
592695
|
const listOpts = listCmd.opts();
|
|
592511
592696
|
try {
|
|
592512
592697
|
const auth = await getAuthenticatedClient(fsAdapter);
|
|
592513
|
-
const api2 = import_googleapis2.google.calendar({ version: "v3", auth });
|
|
592698
|
+
const api2 = createGoogleCalendarApi(import_googleapis2.google.calendar({ version: "v3", auth }));
|
|
592514
592699
|
const deps = {
|
|
592515
592700
|
listEvents: (calendarId, calendarName, options) => listEvents(api2, calendarId, calendarName, options),
|
|
592516
592701
|
loadConfig: () => loadConfig(fsAdapter),
|
|
@@ -592522,8 +592707,7 @@ ${url}`);
|
|
|
592522
592707
|
const handleOpts = {
|
|
592523
592708
|
...listOpts,
|
|
592524
592709
|
format: globalOpts.format,
|
|
592525
|
-
quiet: globalOpts.quiet
|
|
592526
|
-
calendar: globalOpts.calendar
|
|
592710
|
+
quiet: globalOpts.quiet
|
|
592527
592711
|
};
|
|
592528
592712
|
if (globalOpts.timezone)
|
|
592529
592713
|
handleOpts.timezone = globalOpts.timezone;
|
|
@@ -592544,11 +592728,12 @@ ${url}`);
|
|
|
592544
592728
|
const calendarApi = import_googleapis2.google.calendar({ version: "v3", auth });
|
|
592545
592729
|
const api2 = createGoogleCalendarApi(calendarApi);
|
|
592546
592730
|
const timezone = resolveTimezone(globalOpts.timezone, config2.timezone);
|
|
592547
|
-
const calendars = selectCalendars(
|
|
592731
|
+
const calendars = selectCalendars(searchOpts.calendar.length > 0 ? searchOpts.calendar : undefined, config2);
|
|
592548
592732
|
const result = await handleSearch({
|
|
592549
592733
|
api: api2,
|
|
592550
592734
|
query,
|
|
592551
592735
|
format: globalOpts.format,
|
|
592736
|
+
quiet: globalOpts.quiet,
|
|
592552
592737
|
calendars,
|
|
592553
592738
|
timezone,
|
|
592554
592739
|
days: searchOpts.days,
|
|
@@ -592570,7 +592755,7 @@ ${url}`);
|
|
|
592570
592755
|
});
|
|
592571
592756
|
program2.addCommand(searchCmd);
|
|
592572
592757
|
const showCmd = createShowCommand();
|
|
592573
|
-
showCmd.action(async () => {
|
|
592758
|
+
showCmd.action(async (eventId) => {
|
|
592574
592759
|
const globalOpts = resolveGlobalOptions2(program2);
|
|
592575
592760
|
const showOpts = showCmd.opts();
|
|
592576
592761
|
try {
|
|
@@ -592578,23 +592763,24 @@ ${url}`);
|
|
|
592578
592763
|
const auth = await getAuthenticatedClient(fsAdapter);
|
|
592579
592764
|
const calendarApi = import_googleapis2.google.calendar({ version: "v3", auth });
|
|
592580
592765
|
const api2 = createGoogleCalendarApi(calendarApi);
|
|
592581
|
-
const calendarId = showOpts.calendar
|
|
592766
|
+
const calendarId = showOpts.calendar;
|
|
592582
592767
|
let cal;
|
|
592583
592768
|
if (calendarId) {
|
|
592584
592769
|
const found = config2.calendars.find((c) => c.id === calendarId);
|
|
592585
592770
|
cal = found ? { id: found.id, name: found.name } : { id: calendarId, name: calendarId };
|
|
592586
592771
|
} else {
|
|
592587
592772
|
const calendars = selectCalendars(undefined, config2);
|
|
592588
|
-
const resolved = await resolveEventCalendar(api2,
|
|
592773
|
+
const resolved = await resolveEventCalendar(api2, eventId, calendars);
|
|
592589
592774
|
cal = resolved;
|
|
592590
592775
|
}
|
|
592591
592776
|
const timezone = resolveTimezone(globalOpts.timezone, config2.timezone);
|
|
592592
592777
|
const result = await handleShow({
|
|
592593
592778
|
api: api2,
|
|
592594
|
-
eventId
|
|
592779
|
+
eventId,
|
|
592595
592780
|
calendarId: cal.id,
|
|
592596
592781
|
calendarName: cal.name,
|
|
592597
592782
|
format: globalOpts.format,
|
|
592783
|
+
quiet: globalOpts.quiet,
|
|
592598
592784
|
timezone,
|
|
592599
592785
|
write: (msg) => process.stdout.write(msg + `
|
|
592600
592786
|
`)
|
|
@@ -592615,8 +592801,8 @@ ${url}`);
|
|
|
592615
592801
|
const calendarApi = import_googleapis2.google.calendar({ version: "v3", auth });
|
|
592616
592802
|
const api2 = createGoogleCalendarApi(calendarApi);
|
|
592617
592803
|
let resolvedCalendarId;
|
|
592618
|
-
if (deleteOpts.calendar
|
|
592619
|
-
const calendars = selectCalendars(
|
|
592804
|
+
if (deleteOpts.calendar) {
|
|
592805
|
+
const calendars = selectCalendars([deleteOpts.calendar], config2);
|
|
592620
592806
|
resolvedCalendarId = calendars[0]?.id ?? "primary";
|
|
592621
592807
|
} else {
|
|
592622
592808
|
const calendars = selectCalendars(undefined, config2);
|
|
@@ -592660,10 +592846,12 @@ ${url}`);
|
|
|
592660
592846
|
description: addOpts.description,
|
|
592661
592847
|
busy: addOpts.busy,
|
|
592662
592848
|
free: addOpts.free,
|
|
592849
|
+
dryRun: addOpts.dryRun,
|
|
592850
|
+
quiet: globalOpts.quiet,
|
|
592663
592851
|
format: globalOpts.format
|
|
592664
592852
|
};
|
|
592665
|
-
if (
|
|
592666
|
-
handleOpts.calendar =
|
|
592853
|
+
if (addOpts.calendar)
|
|
592854
|
+
handleOpts.calendar = addOpts.calendar;
|
|
592667
592855
|
if (globalOpts.timezone)
|
|
592668
592856
|
handleOpts.timezone = globalOpts.timezone;
|
|
592669
592857
|
const result = await handleAdd(handleOpts, deps);
|
|
@@ -592736,8 +592924,8 @@ ${authUrl}`);
|
|
|
592736
592924
|
const timezone = resolveTimezone(globalOpts.timezone, config2.timezone);
|
|
592737
592925
|
const updateOpsCalendar = updateOpts.calendar;
|
|
592738
592926
|
let cal;
|
|
592739
|
-
if (updateOpsCalendar
|
|
592740
|
-
const calendars = selectCalendars(
|
|
592927
|
+
if (updateOpsCalendar) {
|
|
592928
|
+
const calendars = selectCalendars([updateOpsCalendar], config2);
|
|
592741
592929
|
cal = calendars[0];
|
|
592742
592930
|
} else {
|
|
592743
592931
|
const calendars = selectCalendars(undefined, config2);
|
|
@@ -592750,9 +592938,13 @@ ${authUrl}`);
|
|
|
592750
592938
|
calendarId: cal.id,
|
|
592751
592939
|
calendarName: cal.name,
|
|
592752
592940
|
format: globalOpts.format,
|
|
592941
|
+
quiet: globalOpts.quiet,
|
|
592753
592942
|
timezone,
|
|
592754
592943
|
write: (msg) => process.stdout.write(msg + `
|
|
592755
592944
|
`),
|
|
592945
|
+
writeStderr: (msg) => process.stderr.write(msg + `
|
|
592946
|
+
`),
|
|
592947
|
+
getEvent: (calId, calName, evtId, tz) => getEvent(api2, calId, calName, evtId, tz),
|
|
592756
592948
|
...updateOpts
|
|
592757
592949
|
});
|
|
592758
592950
|
process.exit(result.exitCode);
|