@ncukondo/gcal-cli 0.1.0 → 0.1.4

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 (2) hide show
  1. package/dist/index.js +185 -7
  2. package/package.json +5 -1
package/dist/index.js CHANGED
@@ -587628,6 +587628,28 @@ function formatEventListText(events) {
587628
587628
  return lines.join(`
587629
587629
  `);
587630
587630
  }
587631
+ function formatSearchEventLine(event) {
587632
+ const date3 = getDateKey(event);
587633
+ const time3 = formatTimeRange(event).padEnd(11);
587634
+ if (event.all_day) {
587635
+ return `${date3} ${time3} ${event.title} (${event.calendar_name})`;
587636
+ }
587637
+ const tag = transparencyTag(event);
587638
+ return `${date3} ${time3} ${event.title} (${event.calendar_name}) ${tag}`;
587639
+ }
587640
+ function formatSearchResultText(query, events) {
587641
+ const count = events.length;
587642
+ const plural = count === 1 ? "event" : "events";
587643
+ if (count === 0)
587644
+ return `Found 0 events matching "${query}".`;
587645
+ const header = `Found ${count} ${plural} matching "${query}":`;
587646
+ const lines = [header, ""];
587647
+ for (const event of events) {
587648
+ lines.push(formatSearchEventLine(event));
587649
+ }
587650
+ return lines.join(`
587651
+ `);
587652
+ }
587631
587653
  var CALENDAR_ID_MAX = 15;
587632
587654
  var CALENDAR_ID_COL = 18;
587633
587655
  function truncateId(id) {
@@ -587693,6 +587715,60 @@ var ERROR_CODE_EXIT_MAP = {
587693
587715
  function errorCodeToExitCode(code) {
587694
587716
  return ERROR_CODE_EXIT_MAP[code];
587695
587717
  }
587718
+ // package.json
587719
+ var package_default = {
587720
+ name: "@ncukondo/gcal-cli",
587721
+ version: "0.1.4",
587722
+ type: "module",
587723
+ exports: {
587724
+ ".": "./dist/index.js"
587725
+ },
587726
+ bin: {
587727
+ gcal: "./dist/index.js"
587728
+ },
587729
+ files: [
587730
+ "dist"
587731
+ ],
587732
+ repository: {
587733
+ type: "git",
587734
+ url: "https://github.com/ncukondo/gcal-cli"
587735
+ },
587736
+ publishConfig: {
587737
+ access: "public"
587738
+ },
587739
+ scripts: {
587740
+ dev: "bun run src/index.ts",
587741
+ build: "bun build src/index.ts --outdir dist --target node",
587742
+ "build:bin": "bun build src/index.ts --compile --outfile gcal",
587743
+ test: "vitest",
587744
+ "test:unit": "vitest run src",
587745
+ "test:integration": "vitest run tests/integration",
587746
+ "test:e2e": "vitest run tests/e2e",
587747
+ "test:all": "vitest run",
587748
+ lint: "oxlint src tests",
587749
+ format: "oxfmt src tests",
587750
+ "format:check": "oxfmt --check src tests",
587751
+ typecheck: "tsc --noEmit",
587752
+ prepare: "husky || true",
587753
+ prepublishOnly: "bun run build"
587754
+ },
587755
+ dependencies: {
587756
+ commander: "^12.0.0",
587757
+ "date-fns": "^3.0.0",
587758
+ "date-fns-tz": "^3.0.0",
587759
+ googleapis: "^130.0.0",
587760
+ "smol-toml": "^1.0.0",
587761
+ zod: "^4.0.0-beta"
587762
+ },
587763
+ devDependencies: {
587764
+ "@types/bun": "latest",
587765
+ typescript: "^5.0.0",
587766
+ vitest: "^2.0.0",
587767
+ oxlint: "latest",
587768
+ oxfmt: "latest",
587769
+ husky: "^9.1.7"
587770
+ }
587771
+ };
587696
587772
 
587697
587773
  // src/cli.ts
587698
587774
  var FormatSchema = _enum(["text", "json"]);
@@ -587701,7 +587777,7 @@ function collect(value, previous) {
587701
587777
  }
587702
587778
  function createProgram() {
587703
587779
  const program2 = new Command;
587704
- program2.name("gcal").description("CLI tool for managing Google Calendar events").version("0.1.0").option("-f, --format <format>", "Output format: text | json", "text").option("-c, --calendar <id>", "Target calendar ID (repeatable)", collect, []).option("-q, --quiet", "Minimal output", false).option("--tz, --timezone <zone>", "Timezone (e.g., Asia/Tokyo)");
587780
+ 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("-c, --calendar <id>", "Target calendar ID (repeatable)", collect, []).option("-q, --quiet", "Minimal output", false).option("--tz, --timezone <zone>", "Timezone (e.g., Asia/Tokyo)");
587705
587781
  program2.on("command:*", (operands) => {
587706
587782
  process.stderr.write(`error: unknown command '${operands[0]}'
587707
587783
 
@@ -588140,9 +588216,16 @@ async function listEvents(api2, calendarId, calendarName, options) {
588140
588216
  mapApiError(error);
588141
588217
  }
588142
588218
  }
588143
- async function getEvent(api2, calendarId, calendarName, eventId) {
588219
+ async function getEvent(api2, calendarId, calendarName, eventId, timeZone) {
588144
588220
  try {
588145
- const response = await api2.events.get({ calendarId, eventId });
588221
+ const params = {
588222
+ calendarId,
588223
+ eventId
588224
+ };
588225
+ if (timeZone) {
588226
+ params.timeZone = timeZone;
588227
+ }
588228
+ const response = await api2.events.get(params);
588146
588229
  return normalizeEvent(response.data, calendarId, calendarName);
588147
588230
  } catch (error) {
588148
588231
  mapApiError(error);
@@ -588216,7 +588299,7 @@ function isGoogleApiError(error) {
588216
588299
  return error instanceof Error && "code" in error && typeof error.code === "number";
588217
588300
  }
588218
588301
  function isAuthRequiredError(error) {
588219
- return error instanceof ApiError && error.code === "AUTH_REQUIRED";
588302
+ return (error instanceof ApiError || error instanceof AuthError) && (error.code === "AUTH_REQUIRED" || error.code === "AUTH_EXPIRED");
588220
588303
  }
588221
588304
  function mapApiError(error) {
588222
588305
  if (isGoogleApiError(error)) {
@@ -590427,6 +590510,65 @@ function parseDateTimeInZone(dateStr, timezone) {
590427
590510
  }
590428
590511
 
590429
590512
  // src/commands/search.ts
590513
+ var DEFAULT_SEARCH_DAYS = 30;
590514
+ async function handleSearch(opts) {
590515
+ const { api: api2, query, format: format3, calendars, timezone, write } = opts;
590516
+ const writeErr = opts.writeErr ?? (() => {});
590517
+ const now = new Date;
590518
+ const days = opts.days ?? DEFAULT_SEARCH_DAYS;
590519
+ const isNegativeDays = days < 0;
590520
+ let timeMin;
590521
+ let timeMax;
590522
+ if (opts.from && opts.to) {
590523
+ timeMin = formatDateTimeInZone(parseDateTimeInZone(opts.from, timezone), timezone);
590524
+ timeMax = formatDateTimeInZone(parseDateTimeInZone(opts.to + "T23:59:59", timezone), timezone);
590525
+ } else if (opts.from) {
590526
+ const startDate = parseDateTimeInZone(opts.from, timezone);
590527
+ timeMin = formatDateTimeInZone(startDate, timezone);
590528
+ const endDate = new Date(startDate.getTime());
590529
+ endDate.setDate(endDate.getDate() + days);
590530
+ timeMax = formatDateTimeInZone(endDate, timezone);
590531
+ } else if (opts.to) {
590532
+ timeMax = formatDateTimeInZone(parseDateTimeInZone(opts.to + "T23:59:59", timezone), timezone);
590533
+ timeMin = formatDateTimeInZone(now, timezone);
590534
+ } else if (isNegativeDays) {
590535
+ const pastDate = new Date(now.getTime());
590536
+ pastDate.setDate(pastDate.getDate() + days);
590537
+ timeMin = formatDateTimeInZone(pastDate, timezone);
590538
+ timeMax = formatDateTimeInZone(now, timezone);
590539
+ } else {
590540
+ timeMin = formatDateTimeInZone(now, timezone);
590541
+ const endDate = new Date(now.getTime());
590542
+ endDate.setDate(endDate.getDate() + days);
590543
+ timeMax = formatDateTimeInZone(endDate, timezone);
590544
+ }
590545
+ const displayFrom = timeMin.slice(0, 10);
590546
+ const displayTo = timeMax.slice(0, 10);
590547
+ writeErr(`Searching: ${displayFrom} to ${displayTo}`);
590548
+ const hasExplicitRange = opts.days !== undefined || opts.from !== undefined || opts.to !== undefined;
590549
+ if (!hasExplicitRange) {
590550
+ writeErr("Tip: Use --days <n> or --from/--to to change the search range.");
590551
+ }
590552
+ const results = await Promise.all(calendars.map((cal) => listEvents(api2, cal.id, cal.name, { timeMin, timeMax, q: query })));
590553
+ const allEvents = results.flat();
590554
+ const transparency = opts.busy ? "busy" : opts.free ? "free" : undefined;
590555
+ const filterOpts = { transparency };
590556
+ if (opts.confirmed !== undefined)
590557
+ filterOpts.confirmed = opts.confirmed;
590558
+ if (opts.includeTentative !== undefined)
590559
+ filterOpts.includeTentative = opts.includeTentative;
590560
+ const filtered = applyFilters(allEvents, filterOpts);
590561
+ if (format3 === "json") {
590562
+ write(formatJsonSuccess({
590563
+ query,
590564
+ events: filtered,
590565
+ count: filtered.length
590566
+ }));
590567
+ } else {
590568
+ write(formatSearchResultText(query, filtered));
590569
+ }
590570
+ return { exitCode: ExitCode.SUCCESS };
590571
+ }
590430
590572
  function createSearchCommand() {
590431
590573
  const cmd = new Command("search").description("Search events by keyword").argument("<query>", "Search query string");
590432
590574
  cmd.option("--from <date>", "Start date for search range");
@@ -590447,9 +590589,9 @@ function createSearchCommand() {
590447
590589
 
590448
590590
  // src/commands/show.ts
590449
590591
  async function handleShow(opts) {
590450
- const { api: api2, eventId, calendarId, calendarName, format: format3, write } = opts;
590592
+ const { api: api2, eventId, calendarId, calendarName, format: format3, timezone, write } = opts;
590451
590593
  try {
590452
- const event = await getEvent(api2, calendarId, calendarName, eventId);
590594
+ const event = await getEvent(api2, calendarId, calendarName, eventId, timezone);
590453
590595
  if (format3 === "json") {
590454
590596
  write(formatJsonSuccess({ event }));
590455
590597
  } else {
@@ -592127,7 +592269,41 @@ ${url}`);
592127
592269
  }
592128
592270
  });
592129
592271
  program2.addCommand(listCmd);
592130
- program2.addCommand(createSearchCommand());
592272
+ const searchCmd = createSearchCommand();
592273
+ searchCmd.action(async (query) => {
592274
+ const globalOpts = resolveGlobalOptions2(program2);
592275
+ const searchOpts = searchCmd.opts();
592276
+ try {
592277
+ const config2 = loadConfig(fsAdapter);
592278
+ const auth = await getAuthenticatedClient(fsAdapter);
592279
+ const calendarApi = import_googleapis2.google.calendar({ version: "v3", auth });
592280
+ const api2 = createGoogleCalendarApi(calendarApi);
592281
+ const timezone = resolveTimezone(globalOpts.timezone, config2.timezone);
592282
+ const calendars = selectCalendars(globalOpts.calendar, config2);
592283
+ const result = await handleSearch({
592284
+ api: api2,
592285
+ query,
592286
+ format: globalOpts.format,
592287
+ calendars,
592288
+ timezone,
592289
+ days: searchOpts.days,
592290
+ from: searchOpts.from,
592291
+ to: searchOpts.to,
592292
+ busy: searchOpts.busy,
592293
+ free: searchOpts.free,
592294
+ confirmed: searchOpts.confirmed,
592295
+ includeTentative: searchOpts.includeTentative,
592296
+ write: (msg) => process.stdout.write(msg + `
592297
+ `),
592298
+ writeErr: (msg) => process.stderr.write(msg + `
592299
+ `)
592300
+ });
592301
+ process.exit(result.exitCode);
592302
+ } catch (error) {
592303
+ handleError2(error, globalOpts.format);
592304
+ }
592305
+ });
592306
+ program2.addCommand(searchCmd);
592131
592307
  const showCmd = createShowCommand();
592132
592308
  showCmd.action(async () => {
592133
592309
  const globalOpts = resolveGlobalOptions2(program2);
@@ -592146,12 +592322,14 @@ ${url}`);
592146
592322
  const enabled = config2.calendars.filter((c) => c.enabled);
592147
592323
  cal = enabled[0] ?? { id: "primary", name: "Primary" };
592148
592324
  }
592325
+ const timezone = resolveTimezone(globalOpts.timezone, config2.timezone);
592149
592326
  const result = await handleShow({
592150
592327
  api: api2,
592151
592328
  eventId: showCmd.args[0],
592152
592329
  calendarId: cal.id,
592153
592330
  calendarName: cal.name,
592154
592331
  format: globalOpts.format,
592332
+ timezone,
592155
592333
  write: (msg) => process.stdout.write(msg + `
592156
592334
  `)
592157
592335
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ncukondo/gcal-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dist/index.js"
@@ -11,6 +11,10 @@
11
11
  "files": [
12
12
  "dist"
13
13
  ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/ncukondo/gcal-cli"
17
+ },
14
18
  "publishConfig": {
15
19
  "access": "public"
16
20
  },