@ncukondo/gcal-cli 0.3.0 → 0.5.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 +1010 -185
- 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.5.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
|
};
|
|
@@ -588008,6 +588022,7 @@ async function getAuthenticatedClient(fs, fetchFn = globalThis.fetch) {
|
|
|
588008
588022
|
var OAUTH_SCOPES = [
|
|
588009
588023
|
"https://www.googleapis.com/auth/calendar.readonly",
|
|
588010
588024
|
"https://www.googleapis.com/auth/calendar.events",
|
|
588025
|
+
"https://www.googleapis.com/auth/tasks",
|
|
588011
588026
|
"email"
|
|
588012
588027
|
];
|
|
588013
588028
|
async function startOAuthFlow(credentials, fs, fetchFn = globalThis.fetch) {
|
|
@@ -588207,6 +588222,24 @@ function createAuthCommand() {
|
|
|
588207
588222
|
return cmd;
|
|
588208
588223
|
}
|
|
588209
588224
|
|
|
588225
|
+
// src/lib/api-utils.ts
|
|
588226
|
+
var MAX_PAGES = 100;
|
|
588227
|
+
function isGoogleApiError(error) {
|
|
588228
|
+
return error instanceof Error && "code" in error && typeof error.code === "number";
|
|
588229
|
+
}
|
|
588230
|
+
function mapApiError(error) {
|
|
588231
|
+
if (isGoogleApiError(error)) {
|
|
588232
|
+
if (error.code === 401 || error.code === 403) {
|
|
588233
|
+
throw new ApiError("AUTH_REQUIRED", error.message);
|
|
588234
|
+
}
|
|
588235
|
+
if (error.code === 404) {
|
|
588236
|
+
throw new ApiError("NOT_FOUND", error.message);
|
|
588237
|
+
}
|
|
588238
|
+
throw new ApiError("API_ERROR", error.message);
|
|
588239
|
+
}
|
|
588240
|
+
throw error;
|
|
588241
|
+
}
|
|
588242
|
+
|
|
588210
588243
|
// src/lib/api.ts
|
|
588211
588244
|
class ApiError extends Error {
|
|
588212
588245
|
code;
|
|
@@ -588216,7 +588249,6 @@ class ApiError extends Error {
|
|
|
588216
588249
|
this.name = "ApiError";
|
|
588217
588250
|
}
|
|
588218
588251
|
}
|
|
588219
|
-
var MAX_PAGES = 100;
|
|
588220
588252
|
var EventStatusSchema = _enum(["confirmed", "tentative", "cancelled"]).catch("confirmed");
|
|
588221
588253
|
var TransparencySchema = _enum(["opaque", "transparent"]).catch("opaque");
|
|
588222
588254
|
function normalizeEvent(event, calendarId, calendarName) {
|
|
@@ -588380,24 +588412,9 @@ async function deleteEvent(api2, calendarId, eventId) {
|
|
|
588380
588412
|
mapApiError(error);
|
|
588381
588413
|
}
|
|
588382
588414
|
}
|
|
588383
|
-
function isGoogleApiError(error) {
|
|
588384
|
-
return error instanceof Error && "code" in error && typeof error.code === "number";
|
|
588385
|
-
}
|
|
588386
588415
|
function isAuthRequiredError(error) {
|
|
588387
588416
|
return (error instanceof ApiError || error instanceof AuthError) && (error.code === "AUTH_REQUIRED" || error.code === "AUTH_EXPIRED");
|
|
588388
588417
|
}
|
|
588389
|
-
function mapApiError(error) {
|
|
588390
|
-
if (isGoogleApiError(error)) {
|
|
588391
|
-
if (error.code === 401 || error.code === 403) {
|
|
588392
|
-
throw new ApiError("AUTH_REQUIRED", error.message);
|
|
588393
|
-
}
|
|
588394
|
-
if (error.code === 404) {
|
|
588395
|
-
throw new ApiError("NOT_FOUND", error.message);
|
|
588396
|
-
}
|
|
588397
|
-
throw new ApiError("API_ERROR", error.message);
|
|
588398
|
-
}
|
|
588399
|
-
throw error;
|
|
588400
|
-
}
|
|
588401
588418
|
|
|
588402
588419
|
// src/lib/filter.ts
|
|
588403
588420
|
function filterByTransparency(events, option) {
|
|
@@ -588424,6 +588441,102 @@ function applyFilters(events, options) {
|
|
|
588424
588441
|
const afterTransparency = filterByTransparency(events, options.transparency);
|
|
588425
588442
|
return filterByStatus(afterTransparency, options);
|
|
588426
588443
|
}
|
|
588444
|
+
|
|
588445
|
+
// src/commands/shared.ts
|
|
588446
|
+
import * as nodeFs from "node:fs";
|
|
588447
|
+
var fsAdapter = {
|
|
588448
|
+
existsSync: (p) => nodeFs.existsSync(p),
|
|
588449
|
+
readFileSync: (p) => nodeFs.readFileSync(p, "utf-8"),
|
|
588450
|
+
writeFileSync: (p, d) => nodeFs.writeFileSync(p, d, "utf-8"),
|
|
588451
|
+
mkdirSync: (p) => nodeFs.mkdirSync(p, { recursive: true }),
|
|
588452
|
+
unlinkSync: (p) => nodeFs.unlinkSync(p),
|
|
588453
|
+
chmodSync: (p, m) => nodeFs.chmodSync(p, m)
|
|
588454
|
+
};
|
|
588455
|
+
function collect(value, previous) {
|
|
588456
|
+
return [...previous, value];
|
|
588457
|
+
}
|
|
588458
|
+
function createGoogleTasksClient(tasks) {
|
|
588459
|
+
return {
|
|
588460
|
+
tasklists: {
|
|
588461
|
+
list: async (p) => {
|
|
588462
|
+
const res = await tasks.tasklists.list(p);
|
|
588463
|
+
const data = {};
|
|
588464
|
+
if (res.data.items)
|
|
588465
|
+
data.items = res.data.items;
|
|
588466
|
+
if (res.data.nextPageToken)
|
|
588467
|
+
data.nextPageToken = res.data.nextPageToken;
|
|
588468
|
+
return { data };
|
|
588469
|
+
}
|
|
588470
|
+
},
|
|
588471
|
+
tasks: {
|
|
588472
|
+
list: async (p) => {
|
|
588473
|
+
const res = await tasks.tasks.list(p);
|
|
588474
|
+
const data = {};
|
|
588475
|
+
if (res.data.items)
|
|
588476
|
+
data.items = res.data.items;
|
|
588477
|
+
if (res.data.nextPageToken)
|
|
588478
|
+
data.nextPageToken = res.data.nextPageToken;
|
|
588479
|
+
return { data };
|
|
588480
|
+
},
|
|
588481
|
+
get: async (p) => {
|
|
588482
|
+
const res = await tasks.tasks.get(p);
|
|
588483
|
+
return { data: res.data };
|
|
588484
|
+
},
|
|
588485
|
+
insert: async (p) => {
|
|
588486
|
+
const res = await tasks.tasks.insert(p);
|
|
588487
|
+
return { data: res.data };
|
|
588488
|
+
},
|
|
588489
|
+
patch: async (p) => {
|
|
588490
|
+
const res = await tasks.tasks.patch(p);
|
|
588491
|
+
return { data: res.data };
|
|
588492
|
+
},
|
|
588493
|
+
delete: async (p) => {
|
|
588494
|
+
await tasks.tasks.delete(p);
|
|
588495
|
+
}
|
|
588496
|
+
}
|
|
588497
|
+
};
|
|
588498
|
+
}
|
|
588499
|
+
function createGoogleCalendarApi(calendar) {
|
|
588500
|
+
return {
|
|
588501
|
+
calendarList: {
|
|
588502
|
+
list: async (p) => {
|
|
588503
|
+
const res = await calendar.calendarList.list(p);
|
|
588504
|
+
const data = {};
|
|
588505
|
+
if (res.data.items)
|
|
588506
|
+
data.items = res.data.items;
|
|
588507
|
+
if (res.data.nextPageToken)
|
|
588508
|
+
data.nextPageToken = res.data.nextPageToken;
|
|
588509
|
+
return { data };
|
|
588510
|
+
}
|
|
588511
|
+
},
|
|
588512
|
+
events: {
|
|
588513
|
+
list: async (p) => {
|
|
588514
|
+
const res = await calendar.events.list(p);
|
|
588515
|
+
const data = {};
|
|
588516
|
+
if (res.data.items)
|
|
588517
|
+
data.items = res.data.items;
|
|
588518
|
+
if (res.data.nextPageToken)
|
|
588519
|
+
data.nextPageToken = res.data.nextPageToken;
|
|
588520
|
+
return { data };
|
|
588521
|
+
},
|
|
588522
|
+
get: async (p) => {
|
|
588523
|
+
const res = await calendar.events.get(p);
|
|
588524
|
+
return { data: res.data };
|
|
588525
|
+
},
|
|
588526
|
+
insert: async (p) => {
|
|
588527
|
+
const res = await calendar.events.insert(p);
|
|
588528
|
+
return { data: res.data };
|
|
588529
|
+
},
|
|
588530
|
+
patch: async (p) => {
|
|
588531
|
+
const res = await calendar.events.patch(p);
|
|
588532
|
+
return { data: res.data };
|
|
588533
|
+
},
|
|
588534
|
+
delete: async (p) => {
|
|
588535
|
+
await calendar.events.delete(p);
|
|
588536
|
+
}
|
|
588537
|
+
}
|
|
588538
|
+
};
|
|
588539
|
+
}
|
|
588427
588540
|
// node_modules/date-fns/locale/en-US/_lib/formatDistance.mjs
|
|
588428
588541
|
var formatDistanceLocale = {
|
|
588429
588542
|
lessThanXSeconds: {
|
|
@@ -590596,8 +590709,8 @@ function parseDateTimeInZone(dateStr, timezone) {
|
|
|
590596
590709
|
// src/commands/search.ts
|
|
590597
590710
|
var DEFAULT_SEARCH_DAYS = 30;
|
|
590598
590711
|
async function handleSearch(opts) {
|
|
590599
|
-
const { api: api2, query, format: format4, calendars, timezone, write } = opts;
|
|
590600
|
-
const writeErr = opts.writeErr ?? (() => {});
|
|
590712
|
+
const { api: api2, query, format: format4, calendars, timezone, write, quiet } = opts;
|
|
590713
|
+
const writeErr = quiet ? () => {} : opts.writeErr ?? (() => {});
|
|
590601
590714
|
const now = new Date;
|
|
590602
590715
|
const days = opts.days ?? DEFAULT_SEARCH_DAYS;
|
|
590603
590716
|
const isNegativeDays = days < 0;
|
|
@@ -590605,7 +590718,7 @@ async function handleSearch(opts) {
|
|
|
590605
590718
|
let timeMax;
|
|
590606
590719
|
if (opts.from && opts.to) {
|
|
590607
590720
|
timeMin = formatDateTimeInZone(parseDateTimeInZone(opts.from, timezone), timezone);
|
|
590608
|
-
timeMax = formatDateTimeInZone(parseDateTimeInZone(opts.to
|
|
590721
|
+
timeMax = formatDateTimeInZone(addDays(parseDateTimeInZone(opts.to, timezone), 1), timezone);
|
|
590609
590722
|
} else if (opts.from) {
|
|
590610
590723
|
const startDate = parseDateTimeInZone(opts.from, timezone);
|
|
590611
590724
|
timeMin = formatDateTimeInZone(startDate, timezone);
|
|
@@ -590613,7 +590726,7 @@ async function handleSearch(opts) {
|
|
|
590613
590726
|
endDate.setDate(endDate.getDate() + days);
|
|
590614
590727
|
timeMax = formatDateTimeInZone(endDate, timezone);
|
|
590615
590728
|
} else if (opts.to) {
|
|
590616
|
-
timeMax = formatDateTimeInZone(parseDateTimeInZone(opts.to
|
|
590729
|
+
timeMax = formatDateTimeInZone(addDays(parseDateTimeInZone(opts.to, timezone), 1), timezone);
|
|
590617
590730
|
timeMin = formatDateTimeInZone(now, timezone);
|
|
590618
590731
|
} else if (isNegativeDays) {
|
|
590619
590732
|
const pastDate = new Date(now.getTime());
|
|
@@ -590627,7 +590740,7 @@ async function handleSearch(opts) {
|
|
|
590627
590740
|
timeMax = formatDateTimeInZone(endDate, timezone);
|
|
590628
590741
|
}
|
|
590629
590742
|
const displayFrom = timeMin.slice(0, 10);
|
|
590630
|
-
const displayTo = timeMax.slice(0, 10);
|
|
590743
|
+
const displayTo = opts.to ?? timeMax.slice(0, 10);
|
|
590631
590744
|
writeErr(`Searching: ${displayFrom} to ${displayTo}`);
|
|
590632
590745
|
const hasExplicitRange = opts.days !== undefined || opts.from !== undefined || opts.to !== undefined;
|
|
590633
590746
|
if (!hasExplicitRange) {
|
|
@@ -590648,6 +590761,8 @@ async function handleSearch(opts) {
|
|
|
590648
590761
|
events: filtered,
|
|
590649
590762
|
count: filtered.length
|
|
590650
590763
|
}));
|
|
590764
|
+
} else if (quiet) {
|
|
590765
|
+
write(formatQuietText(filtered));
|
|
590651
590766
|
} else {
|
|
590652
590767
|
write(formatSearchResultText(query, filtered));
|
|
590653
590768
|
}
|
|
@@ -590655,9 +590770,10 @@ async function handleSearch(opts) {
|
|
|
590655
590770
|
}
|
|
590656
590771
|
function createSearchCommand() {
|
|
590657
590772
|
const cmd = new Command("search").description("Search events by keyword").argument("<query>", "Search query string");
|
|
590773
|
+
cmd.option("-c, --calendar <id>", "Target calendar ID (repeatable)", collect, []);
|
|
590658
590774
|
cmd.option("--from <date>", "Start date for search range");
|
|
590659
590775
|
cmd.option("--to <date>", "End date for search range");
|
|
590660
|
-
cmd.option("--days <n>", "Search within next n days (default: 30)", Number.parseInt);
|
|
590776
|
+
cmd.option("--days <n>", "Search within next n days (default: 30)", (v) => Number.parseInt(v, 10));
|
|
590661
590777
|
const daysOpt = cmd.options.find((o) => o.long === "--days");
|
|
590662
590778
|
const fromOpt = cmd.options.find((o) => o.long === "--from");
|
|
590663
590779
|
const toOpt = cmd.options.find((o) => o.long === "--to");
|
|
@@ -590667,32 +590783,26 @@ function createSearchCommand() {
|
|
|
590667
590783
|
cmd.option("--busy", "Show only busy (opaque) events");
|
|
590668
590784
|
cmd.option("--free", "Show only free (transparent) events");
|
|
590669
590785
|
cmd.option("--confirmed", "Show only confirmed events");
|
|
590670
|
-
cmd.option("--include-tentative", "Include tentative events");
|
|
590786
|
+
cmd.option("--include-tentative", "Include tentative events (excluded by default)");
|
|
590787
|
+
const busyOpt = cmd.options.find((o) => o.long === "--busy");
|
|
590788
|
+
const freeOpt = cmd.options.find((o) => o.long === "--free");
|
|
590789
|
+
busyOpt.conflicts(["free"]);
|
|
590790
|
+
freeOpt.conflicts(["busy"]);
|
|
590671
590791
|
return cmd;
|
|
590672
590792
|
}
|
|
590673
590793
|
|
|
590674
590794
|
// src/commands/show.ts
|
|
590675
590795
|
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;
|
|
590796
|
+
const { api: api2, eventId, calendarId, calendarName, format: format4, quiet, timezone, write } = opts;
|
|
590797
|
+
const event = await getEvent(api2, calendarId, calendarName, eventId, timezone);
|
|
590798
|
+
if (format4 === "json") {
|
|
590799
|
+
write(formatJsonSuccess({ event }));
|
|
590800
|
+
} else if (quiet) {
|
|
590801
|
+
write(`${event.title} ${event.start} ${event.end}`);
|
|
590802
|
+
} else {
|
|
590803
|
+
write(formatEventDetailText(event));
|
|
590695
590804
|
}
|
|
590805
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
590696
590806
|
}
|
|
590697
590807
|
function createShowCommand() {
|
|
590698
590808
|
return new Command("show").description("Show event details").argument("<event-id>", "Event ID").option("-c, --calendar <id>", "Calendar ID to query");
|
|
@@ -590829,11 +590939,16 @@ function skipComment(str, ptr) {
|
|
|
590829
590939
|
}
|
|
590830
590940
|
function skipVoid(str, ptr, banNewLines, banComments) {
|
|
590831
590941
|
let c;
|
|
590832
|
-
while (
|
|
590942
|
+
while (true) {
|
|
590943
|
+
while ((c = str[ptr]) === " " || c === "\t" || !banNewLines && (c === `
|
|
590833
590944
|
` || c === "\r" && str[ptr + 1] === `
|
|
590834
590945
|
`))
|
|
590835
|
-
|
|
590836
|
-
|
|
590946
|
+
ptr++;
|
|
590947
|
+
if (banComments || c !== "#")
|
|
590948
|
+
break;
|
|
590949
|
+
ptr = skipComment(str, ptr);
|
|
590950
|
+
}
|
|
590951
|
+
return ptr;
|
|
590837
590952
|
}
|
|
590838
590953
|
function skipUntil(str, ptr, sep, end, banNewLines = false) {
|
|
590839
590954
|
if (!end) {
|
|
@@ -591665,6 +591780,11 @@ function parseConfig(toml) {
|
|
|
591665
591780
|
name: String(c["name"]),
|
|
591666
591781
|
enabled: Boolean(c["enabled"])
|
|
591667
591782
|
})) : [];
|
|
591783
|
+
const task_lists = Array.isArray(raw["task_lists"]) ? raw["task_lists"].map((t) => ({
|
|
591784
|
+
id: String(t["id"]),
|
|
591785
|
+
name: String(t["name"]),
|
|
591786
|
+
enabled: Boolean(t["enabled"])
|
|
591787
|
+
})) : [];
|
|
591668
591788
|
const envFormat = process.env["GCAL_CLI_FORMAT"];
|
|
591669
591789
|
const envTimezone = process.env["GCAL_CLI_TIMEZONE"];
|
|
591670
591790
|
const fileFormat = typeof raw["default_format"] === "string" ? validateOutputFormat(raw["default_format"], "config file") : "text";
|
|
@@ -591672,7 +591792,8 @@ function parseConfig(toml) {
|
|
|
591672
591792
|
const timezone = envTimezone || fileTimezone;
|
|
591673
591793
|
const config2 = {
|
|
591674
591794
|
default_format: envFormat ? validateOutputFormat(envFormat, "GCAL_CLI_FORMAT env var") : fileFormat,
|
|
591675
|
-
calendars
|
|
591795
|
+
calendars,
|
|
591796
|
+
task_lists
|
|
591676
591797
|
};
|
|
591677
591798
|
if (timezone) {
|
|
591678
591799
|
config2.timezone = timezone;
|
|
@@ -591708,7 +591829,7 @@ function getDefaultConfigPath() {
|
|
|
591708
591829
|
function escapeTomlString(value) {
|
|
591709
591830
|
return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
591710
591831
|
}
|
|
591711
|
-
function generateConfigToml(calendars, timezone) {
|
|
591832
|
+
function generateConfigToml(calendars, timezone, taskLists) {
|
|
591712
591833
|
const lines = [];
|
|
591713
591834
|
if (timezone) {
|
|
591714
591835
|
lines.push(`timezone = "${escapeTomlString(timezone)}"`);
|
|
@@ -591721,6 +591842,15 @@ function generateConfigToml(calendars, timezone) {
|
|
|
591721
591842
|
lines.push(`enabled = ${String(cal.enabled)}`);
|
|
591722
591843
|
lines.push("");
|
|
591723
591844
|
}
|
|
591845
|
+
if (taskLists && taskLists.length > 0) {
|
|
591846
|
+
for (const tl of taskLists) {
|
|
591847
|
+
lines.push("[[task_lists]]");
|
|
591848
|
+
lines.push(`id = "${escapeTomlString(tl.id)}"`);
|
|
591849
|
+
lines.push(`name = "${escapeTomlString(tl.name)}"`);
|
|
591850
|
+
lines.push(`enabled = ${String(tl.enabled)}`);
|
|
591851
|
+
lines.push("");
|
|
591852
|
+
}
|
|
591853
|
+
}
|
|
591724
591854
|
return lines.join(`
|
|
591725
591855
|
`);
|
|
591726
591856
|
}
|
|
@@ -591778,24 +591908,6 @@ function resolveDateRange(input, timezone, now = () => new Date) {
|
|
|
591778
591908
|
timeMax: formatDateTimeInZone(end, timezone)
|
|
591779
591909
|
};
|
|
591780
591910
|
}
|
|
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
591911
|
async function handleList(options, deps) {
|
|
591800
591912
|
const config2 = deps.loadConfig();
|
|
591801
591913
|
const timezone = resolveTimezone(options.timezone, config2.timezone);
|
|
@@ -591813,7 +591925,7 @@ async function handleList(options, deps) {
|
|
|
591813
591925
|
if (dateRange.warning && deps.writeErr) {
|
|
591814
591926
|
deps.writeErr(dateRange.warning);
|
|
591815
591927
|
}
|
|
591816
|
-
const calendars = selectCalendars(options.calendar, config2);
|
|
591928
|
+
const calendars = selectCalendars(options.calendar && options.calendar.length > 0 ? options.calendar : undefined, config2);
|
|
591817
591929
|
const apiOptions = {
|
|
591818
591930
|
timeMin: dateRange.timeMin,
|
|
591819
591931
|
timeMax: dateRange.timeMax
|
|
@@ -591852,6 +591964,7 @@ async function handleList(options, deps) {
|
|
|
591852
591964
|
}
|
|
591853
591965
|
function createListCommand() {
|
|
591854
591966
|
const cmd = new Command("list").description("List events within a date range");
|
|
591967
|
+
cmd.option("-c, --calendar <id>", "Target calendar ID (repeatable)", collect, []);
|
|
591855
591968
|
cmd.option("--today", "Show today's events");
|
|
591856
591969
|
cmd.option("--days <n>", "Events for next n days (default: 7)", (v) => Number.parseInt(v, 10));
|
|
591857
591970
|
cmd.option("--from <date>", "Start date (ISO 8601 or YYYY-MM-DD)");
|
|
@@ -591865,9 +591978,11 @@ function createListCommand() {
|
|
|
591865
591978
|
const fromOpt = cmd.options.find((o) => o.long === "--from");
|
|
591866
591979
|
const busyOpt = cmd.options.find((o) => o.long === "--busy");
|
|
591867
591980
|
const freeOpt = cmd.options.find((o) => o.long === "--free");
|
|
591981
|
+
const toOpt = cmd.options.find((o) => o.long === "--to");
|
|
591868
591982
|
todayOpt.conflicts(["days", "from"]);
|
|
591869
|
-
daysOpt.conflicts(["today", "from"]);
|
|
591983
|
+
daysOpt.conflicts(["today", "from", "to"]);
|
|
591870
591984
|
fromOpt.conflicts(["today", "days"]);
|
|
591985
|
+
toOpt.conflicts(["days"]);
|
|
591871
591986
|
busyOpt.conflicts(["free"]);
|
|
591872
591987
|
freeOpt.conflicts(["busy"]);
|
|
591873
591988
|
return cmd;
|
|
@@ -592133,9 +592248,14 @@ async function handleUpdate(opts) {
|
|
|
592133
592248
|
}
|
|
592134
592249
|
const updated = await updateEvent(api2, calendarId, calendarName, eventId, input);
|
|
592135
592250
|
if (format4 === "json") {
|
|
592136
|
-
write(formatJsonSuccess({ event: updated }));
|
|
592251
|
+
write(formatJsonSuccess({ event: updated, message: "Event updated" }));
|
|
592252
|
+
} else if (opts.quiet) {
|
|
592253
|
+
write(updated.id);
|
|
592137
592254
|
} else {
|
|
592138
|
-
|
|
592255
|
+
const detail = formatEventDetailText(updated);
|
|
592256
|
+
write(`Event updated
|
|
592257
|
+
|
|
592258
|
+
${detail}`);
|
|
592139
592259
|
}
|
|
592140
592260
|
return { exitCode: ExitCode.SUCCESS };
|
|
592141
592261
|
}
|
|
@@ -592261,9 +592381,37 @@ async function handleAdd(options, deps) {
|
|
|
592261
592381
|
if (options.description !== undefined) {
|
|
592262
592382
|
input.description = options.description;
|
|
592263
592383
|
}
|
|
592384
|
+
if (options.dryRun) {
|
|
592385
|
+
const preview = {
|
|
592386
|
+
title: input.title,
|
|
592387
|
+
start: input.start,
|
|
592388
|
+
end: input.end
|
|
592389
|
+
};
|
|
592390
|
+
if (input.description !== undefined)
|
|
592391
|
+
preview.description = input.description;
|
|
592392
|
+
if (input.transparency !== "opaque")
|
|
592393
|
+
preview.transparency = input.transparency;
|
|
592394
|
+
if (options.format === "json") {
|
|
592395
|
+
deps.write(formatJsonSuccess({ dry_run: true, action: "add", event: preview }));
|
|
592396
|
+
} else {
|
|
592397
|
+
const lines = ["DRY RUN: Would create event:"];
|
|
592398
|
+
lines.push(` title: "${preview.title}"`);
|
|
592399
|
+
lines.push(` start: "${preview.start}"`);
|
|
592400
|
+
lines.push(` end: "${preview.end}"`);
|
|
592401
|
+
if (preview.description !== undefined)
|
|
592402
|
+
lines.push(` description: "${preview.description}"`);
|
|
592403
|
+
if (preview.transparency !== undefined)
|
|
592404
|
+
lines.push(` transparency: ${preview.transparency}`);
|
|
592405
|
+
deps.write(lines.join(`
|
|
592406
|
+
`));
|
|
592407
|
+
}
|
|
592408
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
592409
|
+
}
|
|
592264
592410
|
const event = await deps.createEvent(calendarId, calendarName, input);
|
|
592265
592411
|
if (options.format === "json") {
|
|
592266
592412
|
deps.write(formatJsonSuccess({ event, message: "Event created" }));
|
|
592413
|
+
} else if (options.quiet) {
|
|
592414
|
+
deps.write(event.id);
|
|
592267
592415
|
} else {
|
|
592268
592416
|
const detail = formatEventDetailText(event);
|
|
592269
592417
|
deps.write(`Event created
|
|
@@ -592278,9 +592426,11 @@ function createAddCommand() {
|
|
|
592278
592426
|
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.");
|
|
592279
592427
|
cmd.option("-e, --end <datetime>", "End date or datetime. Optional. Default: same day (all-day) or +1h (timed). All-day end is inclusive.");
|
|
592280
592428
|
cmd.option("--duration <duration>", "Duration instead of --end (e.g. 30m, 1h, 2d, 1h30m). Mutually exclusive with --end.");
|
|
592429
|
+
cmd.option("-c, --calendar <id>", "Target calendar ID");
|
|
592281
592430
|
cmd.option("-d, --description <text>", "Event description");
|
|
592282
592431
|
cmd.option("--busy", "Mark as busy (default)");
|
|
592283
592432
|
cmd.option("--free", "Mark as free (transparent)");
|
|
592433
|
+
cmd.option("--dry-run", "Preview without executing");
|
|
592284
592434
|
const endOpt = cmd.options.find((o) => o.long === "--end");
|
|
592285
592435
|
const durationOpt = cmd.options.find((o) => o.long === "--duration");
|
|
592286
592436
|
endOpt.conflicts(["duration"]);
|
|
@@ -592306,8 +592456,7 @@ Examples:
|
|
|
592306
592456
|
async function handleDelete(opts) {
|
|
592307
592457
|
const { api: api2, eventId, calendarId, format: format4, quiet, dryRun = false, write } = opts;
|
|
592308
592458
|
if (!eventId) {
|
|
592309
|
-
|
|
592310
|
-
return { exitCode: ExitCode.ARGUMENT };
|
|
592459
|
+
throw new ApiError("INVALID_ARGS", "event-id is required");
|
|
592311
592460
|
}
|
|
592312
592461
|
if (dryRun) {
|
|
592313
592462
|
if (format4 === "json") {
|
|
@@ -592322,27 +592471,15 @@ async function handleDelete(opts) {
|
|
|
592322
592471
|
}
|
|
592323
592472
|
return { exitCode: ExitCode.SUCCESS };
|
|
592324
592473
|
}
|
|
592325
|
-
|
|
592326
|
-
|
|
592327
|
-
if (
|
|
592328
|
-
|
|
592329
|
-
|
|
592330
|
-
|
|
592331
|
-
write("Event deleted");
|
|
592332
|
-
}
|
|
592333
|
-
}
|
|
592334
|
-
return { exitCode: ExitCode.SUCCESS };
|
|
592335
|
-
} catch (error) {
|
|
592336
|
-
if (error instanceof ApiError) {
|
|
592337
|
-
if (format4 === "json") {
|
|
592338
|
-
write(formatJsonError(error.code, error.message));
|
|
592339
|
-
} else {
|
|
592340
|
-
write(`Error: ${error.message}`);
|
|
592341
|
-
}
|
|
592342
|
-
return { exitCode: errorCodeToExitCode(error.code) };
|
|
592474
|
+
await deleteEvent(api2, calendarId, eventId);
|
|
592475
|
+
if (!quiet) {
|
|
592476
|
+
if (format4 === "json") {
|
|
592477
|
+
write(formatJsonSuccess({ deleted_id: eventId, message: "Event deleted" }));
|
|
592478
|
+
} else {
|
|
592479
|
+
write("Event deleted");
|
|
592343
592480
|
}
|
|
592344
|
-
throw error;
|
|
592345
592481
|
}
|
|
592482
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
592346
592483
|
}
|
|
592347
592484
|
function createDeleteCommand() {
|
|
592348
592485
|
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");
|
|
@@ -592361,20 +592498,7 @@ function mergeCalendarsWithConfig(apiCalendars, configCalendars) {
|
|
|
592361
592498
|
}
|
|
592362
592499
|
async function handleCalendars(opts) {
|
|
592363
592500
|
const { api: api2, format: format4, quiet, write, configCalendars } = opts;
|
|
592364
|
-
|
|
592365
|
-
try {
|
|
592366
|
-
apiCalendars = await listCalendars(api2);
|
|
592367
|
-
} catch (error) {
|
|
592368
|
-
if (error instanceof ApiError) {
|
|
592369
|
-
if (format4 === "json") {
|
|
592370
|
-
write(formatJsonError(error.code, error.message));
|
|
592371
|
-
} else {
|
|
592372
|
-
write(error.message);
|
|
592373
|
-
}
|
|
592374
|
-
return { exitCode: errorCodeToExitCode(error.code) };
|
|
592375
|
-
}
|
|
592376
|
-
throw error;
|
|
592377
|
-
}
|
|
592501
|
+
const apiCalendars = await listCalendars(api2);
|
|
592378
592502
|
const calendars = mergeCalendarsWithConfig(apiCalendars, configCalendars);
|
|
592379
592503
|
if (quiet) {
|
|
592380
592504
|
write(calendars.map((c) => c.id).join(`
|
|
@@ -592399,6 +592523,7 @@ function resolveTimezone2(cliTimezone) {
|
|
|
592399
592523
|
}
|
|
592400
592524
|
async function handleInit(opts) {
|
|
592401
592525
|
const { fs, format: format4, quiet, write, force, all, local, requestAuth } = opts;
|
|
592526
|
+
const writeErr = quiet ? () => {} : opts.writeErr ?? (() => {});
|
|
592402
592527
|
const configPath = local ? `${process.cwd()}/gcal-cli.toml` : getDefaultConfigPath();
|
|
592403
592528
|
if (!force && fs.existsSync(configPath)) {
|
|
592404
592529
|
const msg = `Config file already exists: ${configPath}
|
|
@@ -592443,18 +592568,32 @@ Use --force to overwrite.`;
|
|
|
592443
592568
|
name: cal.name,
|
|
592444
592569
|
enabled: all || cal.primary
|
|
592445
592570
|
}));
|
|
592571
|
+
let configTaskLists = [];
|
|
592572
|
+
if (opts.listTaskLists) {
|
|
592573
|
+
try {
|
|
592574
|
+
const taskLists = await opts.listTaskLists();
|
|
592575
|
+
configTaskLists = taskLists.map((tl) => ({
|
|
592576
|
+
id: tl.id,
|
|
592577
|
+
name: tl.title,
|
|
592578
|
+
enabled: all || tl.id === "@default"
|
|
592579
|
+
}));
|
|
592580
|
+
} catch {
|
|
592581
|
+
writeErr("[init] Tasks API unavailable, skipping task lists");
|
|
592582
|
+
}
|
|
592583
|
+
}
|
|
592446
592584
|
const timezone = resolveTimezone2(opts.timezone);
|
|
592447
|
-
const toml = generateConfigToml(configCalendars, timezone);
|
|
592585
|
+
const toml = generateConfigToml(configCalendars, timezone, configTaskLists.length > 0 ? configTaskLists : undefined);
|
|
592448
592586
|
const dir = path.dirname(configPath);
|
|
592449
592587
|
fs.mkdirSync(dir, { recursive: true });
|
|
592450
592588
|
fs.writeFileSync(configPath, toml);
|
|
592451
592589
|
const enabledCalendars = configCalendars.filter((c) => c.enabled);
|
|
592590
|
+
const enabledTaskLists = configTaskLists.filter((t) => t.enabled);
|
|
592452
592591
|
if (quiet) {
|
|
592453
592592
|
write(configPath);
|
|
592454
592593
|
return { exitCode: ExitCode.SUCCESS };
|
|
592455
592594
|
}
|
|
592456
592595
|
if (format4 === "json") {
|
|
592457
|
-
|
|
592596
|
+
const data = {
|
|
592458
592597
|
path: configPath,
|
|
592459
592598
|
timezone,
|
|
592460
592599
|
calendars: configCalendars.map((c) => ({
|
|
@@ -592464,7 +592603,15 @@ Use --force to overwrite.`;
|
|
|
592464
592603
|
})),
|
|
592465
592604
|
enabled_count: enabledCalendars.length,
|
|
592466
592605
|
total_count: configCalendars.length
|
|
592467
|
-
}
|
|
592606
|
+
};
|
|
592607
|
+
if (configTaskLists.length > 0) {
|
|
592608
|
+
data.task_lists = configTaskLists.map((t) => ({
|
|
592609
|
+
id: t.id,
|
|
592610
|
+
name: t.name,
|
|
592611
|
+
enabled: t.enabled
|
|
592612
|
+
}));
|
|
592613
|
+
}
|
|
592614
|
+
write(formatJsonSuccess(data));
|
|
592468
592615
|
} else {
|
|
592469
592616
|
write(`Config file created: ${configPath}`);
|
|
592470
592617
|
write("");
|
|
@@ -592472,6 +592619,13 @@ Use --force to overwrite.`;
|
|
|
592472
592619
|
for (const cal of enabledCalendars) {
|
|
592473
592620
|
write(` - ${cal.name} (${cal.id})`);
|
|
592474
592621
|
}
|
|
592622
|
+
if (enabledTaskLists.length > 0) {
|
|
592623
|
+
write("");
|
|
592624
|
+
write("Enabled task lists:");
|
|
592625
|
+
for (const tl of enabledTaskLists) {
|
|
592626
|
+
write(` - ${tl.name} (${tl.id})`);
|
|
592627
|
+
}
|
|
592628
|
+
}
|
|
592475
592629
|
write("");
|
|
592476
592630
|
write(`Timezone: ${timezone}`);
|
|
592477
592631
|
}
|
|
@@ -592486,56 +592640,551 @@ function createInitCommand() {
|
|
|
592486
592640
|
return cmd;
|
|
592487
592641
|
}
|
|
592488
592642
|
|
|
592489
|
-
// src/commands/
|
|
592490
|
-
|
|
592491
|
-
|
|
592492
|
-
|
|
592493
|
-
|
|
592494
|
-
|
|
592495
|
-
|
|
592496
|
-
|
|
592497
|
-
|
|
592498
|
-
|
|
592499
|
-
|
|
592643
|
+
// src/commands/tasks/index.ts
|
|
592644
|
+
function createTasksCommand() {
|
|
592645
|
+
const tasksCmd = new Command("tasks").description("Manage Google Tasks");
|
|
592646
|
+
const listsCmd = new Command("lists").description("List task lists");
|
|
592647
|
+
tasksCmd.addCommand(listsCmd);
|
|
592648
|
+
const listCmd = new Command("list").description("List tasks").option("-l, --list <name-or-id>", "Task list name or ID").option("--all", "Include completed tasks").option("--completed", "Show only completed tasks").option("--due-before <date>", "Tasks due before date (YYYY-MM-DD)").option("--due-after <date>", "Tasks due after date (YYYY-MM-DD)");
|
|
592649
|
+
tasksCmd.addCommand(listCmd);
|
|
592650
|
+
const showCmd = new Command("show").description("Show task details").argument("<task-id>", "Task ID").option("-l, --list <name-or-id>", "Task list name or ID");
|
|
592651
|
+
tasksCmd.addCommand(showCmd);
|
|
592652
|
+
const addCmd = new Command("add").description("Create a new task").requiredOption("-t, --title <title>", "Task title").option("-n, --notes <text>", "Notes").option("--due <date>", "Due date (YYYY-MM-DD)").option("-l, --list <name-or-id>", "Task list name or ID").option("--parent <task-id>", "Parent task ID (create as subtask)");
|
|
592653
|
+
tasksCmd.addCommand(addCmd);
|
|
592654
|
+
const updateCmd = new Command("update").description("Update an existing task").argument("<task-id>", "Task ID to update").option("-t, --title <title>", "New title").option("-n, --notes <text>", "New notes").option("--due <date>", "New due date (YYYY-MM-DD)").option("-l, --list <name-or-id>", "Task list name or ID");
|
|
592655
|
+
tasksCmd.addCommand(updateCmd);
|
|
592656
|
+
const doneCmd = new Command("done").description("Mark a task as completed").argument("<task-id>", "Task ID to complete").option("-l, --list <name-or-id>", "Task list name or ID");
|
|
592657
|
+
tasksCmd.addCommand(doneCmd);
|
|
592658
|
+
const undoneCmd = new Command("undone").description("Mark a task as not completed").argument("<task-id>", "Task ID to reopen").option("-l, --list <name-or-id>", "Task list name or ID");
|
|
592659
|
+
tasksCmd.addCommand(undoneCmd);
|
|
592660
|
+
const deleteCmd = new Command("delete").description("Delete a task").argument("<task-id>", "Task ID to delete").option("-l, --list <name-or-id>", "Task list name or ID");
|
|
592661
|
+
tasksCmd.addCommand(deleteCmd);
|
|
592662
|
+
return { tasksCmd, listsCmd, listCmd, showCmd, addCmd, updateCmd, doneCmd, undoneCmd, deleteCmd };
|
|
592663
|
+
}
|
|
592664
|
+
|
|
592665
|
+
// src/lib/tasks-api.ts
|
|
592666
|
+
function normalizeTaskList(raw) {
|
|
592500
592667
|
return {
|
|
592501
|
-
|
|
592502
|
-
|
|
592503
|
-
|
|
592504
|
-
|
|
592505
|
-
|
|
592506
|
-
|
|
592507
|
-
|
|
592508
|
-
|
|
592509
|
-
|
|
592668
|
+
id: raw.id ?? "",
|
|
592669
|
+
title: raw.title ?? "",
|
|
592670
|
+
updated: raw.updated ?? ""
|
|
592671
|
+
};
|
|
592672
|
+
}
|
|
592673
|
+
var VALID_TASK_STATUSES = ["needsAction", "completed"];
|
|
592674
|
+
function parseTaskStatus(value) {
|
|
592675
|
+
if (value && VALID_TASK_STATUSES.includes(value)) {
|
|
592676
|
+
return value;
|
|
592677
|
+
}
|
|
592678
|
+
return "needsAction";
|
|
592679
|
+
}
|
|
592680
|
+
function parseDueDate(due) {
|
|
592681
|
+
if (!due)
|
|
592682
|
+
return null;
|
|
592683
|
+
return due.slice(0, 10);
|
|
592684
|
+
}
|
|
592685
|
+
function normalizeTask(raw, listId, listTitle) {
|
|
592686
|
+
return {
|
|
592687
|
+
id: raw.id ?? "",
|
|
592688
|
+
title: raw.title ?? "",
|
|
592689
|
+
notes: raw.notes ?? null,
|
|
592690
|
+
status: parseTaskStatus(raw.status),
|
|
592691
|
+
due: parseDueDate(raw.due),
|
|
592692
|
+
completed: raw.completed ?? null,
|
|
592693
|
+
list_id: listId,
|
|
592694
|
+
list_title: listTitle,
|
|
592695
|
+
parent: raw.parent ?? null,
|
|
592696
|
+
updated: raw.updated ?? ""
|
|
592697
|
+
};
|
|
592698
|
+
}
|
|
592699
|
+
async function listTaskLists(client) {
|
|
592700
|
+
try {
|
|
592701
|
+
const results = [];
|
|
592702
|
+
let pageToken;
|
|
592703
|
+
let pages = 0;
|
|
592704
|
+
do {
|
|
592705
|
+
if (pages >= MAX_PAGES) {
|
|
592706
|
+
throw new ApiError("API_ERROR", `Pagination limit of ${MAX_PAGES} pages exceeded`);
|
|
592510
592707
|
}
|
|
592511
|
-
|
|
592512
|
-
|
|
592513
|
-
|
|
592514
|
-
|
|
592515
|
-
const data = {};
|
|
592516
|
-
if (res.data.items)
|
|
592517
|
-
data.items = res.data.items;
|
|
592518
|
-
if (res.data.nextPageToken)
|
|
592519
|
-
data.nextPageToken = res.data.nextPageToken;
|
|
592520
|
-
return { data };
|
|
592521
|
-
},
|
|
592522
|
-
get: async (p) => {
|
|
592523
|
-
const res = await calendar.events.get(p);
|
|
592524
|
-
return { data: res.data };
|
|
592525
|
-
},
|
|
592526
|
-
insert: async (p) => {
|
|
592527
|
-
const res = await calendar.events.insert(p);
|
|
592528
|
-
return { data: res.data };
|
|
592529
|
-
},
|
|
592530
|
-
patch: async (p) => {
|
|
592531
|
-
const res = await calendar.events.patch(p);
|
|
592532
|
-
return { data: res.data };
|
|
592533
|
-
},
|
|
592534
|
-
delete: async (p) => {
|
|
592535
|
-
await calendar.events.delete(p);
|
|
592708
|
+
const response = await client.tasklists.list(pageToken ? { pageToken } : undefined);
|
|
592709
|
+
const items = response.data.items ?? [];
|
|
592710
|
+
for (const item of items) {
|
|
592711
|
+
results.push(normalizeTaskList(item));
|
|
592536
592712
|
}
|
|
592713
|
+
pageToken = response.data.nextPageToken;
|
|
592714
|
+
pages++;
|
|
592715
|
+
} while (pageToken);
|
|
592716
|
+
return results;
|
|
592717
|
+
} catch (error) {
|
|
592718
|
+
mapApiError(error);
|
|
592719
|
+
}
|
|
592720
|
+
}
|
|
592721
|
+
async function listTasks(client, taskListId, listTitle, options) {
|
|
592722
|
+
try {
|
|
592723
|
+
const results = [];
|
|
592724
|
+
let pageToken;
|
|
592725
|
+
let pages = 0;
|
|
592726
|
+
do {
|
|
592727
|
+
if (pages >= MAX_PAGES) {
|
|
592728
|
+
throw new ApiError("API_ERROR", `Pagination limit of ${MAX_PAGES} pages exceeded`);
|
|
592729
|
+
}
|
|
592730
|
+
const params = {
|
|
592731
|
+
tasklist: taskListId,
|
|
592732
|
+
...options
|
|
592733
|
+
};
|
|
592734
|
+
if (pageToken) {
|
|
592735
|
+
params.pageToken = pageToken;
|
|
592736
|
+
}
|
|
592737
|
+
const response = await client.tasks.list(params);
|
|
592738
|
+
const items = response.data.items ?? [];
|
|
592739
|
+
for (const item of items) {
|
|
592740
|
+
results.push(normalizeTask(item, taskListId, listTitle));
|
|
592741
|
+
}
|
|
592742
|
+
pageToken = response.data.nextPageToken;
|
|
592743
|
+
pages++;
|
|
592744
|
+
} while (pageToken);
|
|
592745
|
+
return results;
|
|
592746
|
+
} catch (error) {
|
|
592747
|
+
mapApiError(error);
|
|
592748
|
+
}
|
|
592749
|
+
}
|
|
592750
|
+
async function getTask(client, taskListId, listTitle, taskId) {
|
|
592751
|
+
try {
|
|
592752
|
+
const response = await client.tasks.get({ tasklist: taskListId, task: taskId });
|
|
592753
|
+
return normalizeTask(response.data, taskListId, listTitle);
|
|
592754
|
+
} catch (error) {
|
|
592755
|
+
mapApiError(error);
|
|
592756
|
+
}
|
|
592757
|
+
}
|
|
592758
|
+
async function createTask(client, taskListId, listTitle, input) {
|
|
592759
|
+
try {
|
|
592760
|
+
const requestBody = {
|
|
592761
|
+
title: input.title
|
|
592762
|
+
};
|
|
592763
|
+
if (input.notes !== undefined) {
|
|
592764
|
+
requestBody.notes = input.notes;
|
|
592765
|
+
}
|
|
592766
|
+
if (input.due !== undefined) {
|
|
592767
|
+
requestBody.due = input.due;
|
|
592768
|
+
}
|
|
592769
|
+
const params = { tasklist: taskListId, requestBody };
|
|
592770
|
+
if (input.parent !== undefined) {
|
|
592771
|
+
params.parent = input.parent;
|
|
592772
|
+
}
|
|
592773
|
+
const response = await client.tasks.insert(params);
|
|
592774
|
+
return normalizeTask(response.data, taskListId, listTitle);
|
|
592775
|
+
} catch (error) {
|
|
592776
|
+
mapApiError(error);
|
|
592777
|
+
}
|
|
592778
|
+
}
|
|
592779
|
+
async function updateTask(client, taskListId, listTitle, taskId, input) {
|
|
592780
|
+
try {
|
|
592781
|
+
const requestBody = {};
|
|
592782
|
+
if (input.title !== undefined) {
|
|
592783
|
+
requestBody.title = input.title;
|
|
592784
|
+
}
|
|
592785
|
+
if (input.notes !== undefined) {
|
|
592786
|
+
requestBody.notes = input.notes;
|
|
592787
|
+
}
|
|
592788
|
+
if (input.due !== undefined) {
|
|
592789
|
+
requestBody.due = input.due;
|
|
592537
592790
|
}
|
|
592791
|
+
const response = await client.tasks.patch({
|
|
592792
|
+
tasklist: taskListId,
|
|
592793
|
+
task: taskId,
|
|
592794
|
+
requestBody
|
|
592795
|
+
});
|
|
592796
|
+
return normalizeTask(response.data, taskListId, listTitle);
|
|
592797
|
+
} catch (error) {
|
|
592798
|
+
mapApiError(error);
|
|
592799
|
+
}
|
|
592800
|
+
}
|
|
592801
|
+
async function deleteTask(client, taskListId, taskId) {
|
|
592802
|
+
try {
|
|
592803
|
+
await client.tasks.delete({ tasklist: taskListId, task: taskId });
|
|
592804
|
+
} catch (error) {
|
|
592805
|
+
mapApiError(error);
|
|
592806
|
+
}
|
|
592807
|
+
}
|
|
592808
|
+
async function completeTask(client, taskListId, listTitle, taskId) {
|
|
592809
|
+
try {
|
|
592810
|
+
const response = await client.tasks.patch({
|
|
592811
|
+
tasklist: taskListId,
|
|
592812
|
+
task: taskId,
|
|
592813
|
+
requestBody: { status: "completed" }
|
|
592814
|
+
});
|
|
592815
|
+
return normalizeTask(response.data, taskListId, listTitle);
|
|
592816
|
+
} catch (error) {
|
|
592817
|
+
mapApiError(error);
|
|
592818
|
+
}
|
|
592819
|
+
}
|
|
592820
|
+
async function uncompleteTask(client, taskListId, listTitle, taskId) {
|
|
592821
|
+
try {
|
|
592822
|
+
const response = await client.tasks.patch({
|
|
592823
|
+
tasklist: taskListId,
|
|
592824
|
+
task: taskId,
|
|
592825
|
+
requestBody: { status: "needsAction", completed: null }
|
|
592826
|
+
});
|
|
592827
|
+
return normalizeTask(response.data, taskListId, listTitle);
|
|
592828
|
+
} catch (error) {
|
|
592829
|
+
mapApiError(error);
|
|
592830
|
+
}
|
|
592831
|
+
}
|
|
592832
|
+
|
|
592833
|
+
// src/commands/tasks/lists.ts
|
|
592834
|
+
function mergeTaskListsWithConfig(apiLists, configLists) {
|
|
592835
|
+
const hasConfig = configLists.length > 0;
|
|
592836
|
+
const configMap = new Map(configLists.map((c) => [c.id, c]));
|
|
592837
|
+
return apiLists.map((list) => {
|
|
592838
|
+
const config2 = configMap.get(list.id);
|
|
592839
|
+
return {
|
|
592840
|
+
...list,
|
|
592841
|
+
enabled: hasConfig ? config2 ? config2.enabled : true : true
|
|
592842
|
+
};
|
|
592843
|
+
});
|
|
592844
|
+
}
|
|
592845
|
+
function formatTaskListText(lists) {
|
|
592846
|
+
const lines = ["Task Lists:"];
|
|
592847
|
+
for (const list of lists) {
|
|
592848
|
+
const checkbox = list.enabled ? "[x]" : "[ ]";
|
|
592849
|
+
const suffix = list.enabled ? "" : " (disabled)";
|
|
592850
|
+
lines.push(` ${checkbox} ${list.title} (${list.id})${suffix}`);
|
|
592851
|
+
}
|
|
592852
|
+
return lines.join(`
|
|
592853
|
+
`);
|
|
592854
|
+
}
|
|
592855
|
+
async function handleTaskLists(opts) {
|
|
592856
|
+
const { client, format: format4, quiet, write, configTaskLists } = opts;
|
|
592857
|
+
const apiLists = await listTaskLists(client);
|
|
592858
|
+
const lists = mergeTaskListsWithConfig(apiLists, configTaskLists);
|
|
592859
|
+
if (quiet) {
|
|
592860
|
+
write(lists.map((l) => l.id).join(`
|
|
592861
|
+
`));
|
|
592862
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
592863
|
+
}
|
|
592864
|
+
if (format4 === "json") {
|
|
592865
|
+
write(formatJsonSuccess({ task_lists: lists, count: lists.length }));
|
|
592866
|
+
} else {
|
|
592867
|
+
write(formatTaskListText(lists));
|
|
592868
|
+
}
|
|
592869
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
592870
|
+
}
|
|
592871
|
+
|
|
592872
|
+
// src/commands/tasks/resolve.ts
|
|
592873
|
+
function resolveTaskListFromConfig(configLists, listOption) {
|
|
592874
|
+
if (!listOption) {
|
|
592875
|
+
const enabled = configLists.find((c) => c.enabled);
|
|
592876
|
+
if (enabled)
|
|
592877
|
+
return { id: enabled.id, title: enabled.name };
|
|
592878
|
+
return null;
|
|
592879
|
+
}
|
|
592880
|
+
const byName = configLists.find((c) => c.name === listOption);
|
|
592881
|
+
if (byName)
|
|
592882
|
+
return { id: byName.id, title: byName.name };
|
|
592883
|
+
const byId = configLists.find((c) => c.id === listOption);
|
|
592884
|
+
if (byId)
|
|
592885
|
+
return { id: byId.id, title: byId.name };
|
|
592886
|
+
return null;
|
|
592887
|
+
}
|
|
592888
|
+
async function resolveTaskList(client, configLists, listOption) {
|
|
592889
|
+
const fromConfig = resolveTaskListFromConfig(configLists, listOption);
|
|
592890
|
+
if (fromConfig)
|
|
592891
|
+
return fromConfig;
|
|
592892
|
+
if (listOption) {
|
|
592893
|
+
const apiLists = await listTaskLists(client);
|
|
592894
|
+
const byTitle = apiLists.find((l) => l.title === listOption);
|
|
592895
|
+
if (byTitle)
|
|
592896
|
+
return { id: byTitle.id, title: byTitle.title };
|
|
592897
|
+
return { id: listOption, title: listOption };
|
|
592898
|
+
}
|
|
592899
|
+
return { id: "@default", title: "My Tasks" };
|
|
592900
|
+
}
|
|
592901
|
+
|
|
592902
|
+
// src/commands/tasks/list.ts
|
|
592903
|
+
function isValidDateString(value) {
|
|
592904
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value))
|
|
592905
|
+
return false;
|
|
592906
|
+
const date3 = new Date(`${value}T00:00:00Z`);
|
|
592907
|
+
if (Number.isNaN(date3.getTime()))
|
|
592908
|
+
return false;
|
|
592909
|
+
return date3.toISOString().startsWith(value);
|
|
592910
|
+
}
|
|
592911
|
+
function formatDueInfo(task) {
|
|
592912
|
+
const parts = [];
|
|
592913
|
+
if (task.due) {
|
|
592914
|
+
const month = task.due.slice(5, 7);
|
|
592915
|
+
const day = task.due.slice(8, 10);
|
|
592916
|
+
parts.push(`due: ${month}/${day}`);
|
|
592917
|
+
}
|
|
592918
|
+
if (task.status === "completed" && task.completed) {
|
|
592919
|
+
const month = task.completed.slice(5, 7);
|
|
592920
|
+
const day = task.completed.slice(8, 10);
|
|
592921
|
+
parts.push(`completed: ${month}/${day}`);
|
|
592922
|
+
}
|
|
592923
|
+
return parts.length > 0 ? ` (${parts.join(", ")})` : "";
|
|
592924
|
+
}
|
|
592925
|
+
function formatTaskLine(task) {
|
|
592926
|
+
const checkbox = task.status === "completed" ? "☑" : "□";
|
|
592927
|
+
return `${checkbox} ${task.title}${formatDueInfo(task)}`;
|
|
592928
|
+
}
|
|
592929
|
+
function formatTaskListText2(listTitle, tasks) {
|
|
592930
|
+
const lines = [`${listTitle}:`];
|
|
592931
|
+
for (const task of tasks) {
|
|
592932
|
+
lines.push(` ${formatTaskLine(task)}`);
|
|
592933
|
+
if (task.notes) {
|
|
592934
|
+
const firstLine = task.notes.split(`
|
|
592935
|
+
`)[0];
|
|
592936
|
+
lines.push(` Notes: ${firstLine}`);
|
|
592937
|
+
}
|
|
592938
|
+
}
|
|
592939
|
+
return lines.join(`
|
|
592940
|
+
`);
|
|
592941
|
+
}
|
|
592942
|
+
function formatQuietTaskList(tasks) {
|
|
592943
|
+
return tasks.map((task) => formatTaskLine(task)).join(`
|
|
592944
|
+
`);
|
|
592945
|
+
}
|
|
592946
|
+
function filterTasks(tasks, options) {
|
|
592947
|
+
let filtered = tasks;
|
|
592948
|
+
if (options.completed) {
|
|
592949
|
+
filtered = filtered.filter((t) => t.status === "completed");
|
|
592950
|
+
} else if (!options.all) {
|
|
592951
|
+
filtered = filtered.filter((t) => t.status === "needsAction");
|
|
592952
|
+
}
|
|
592953
|
+
if (options.dueBefore) {
|
|
592954
|
+
filtered = filtered.filter((t) => t.due !== null && t.due <= options.dueBefore);
|
|
592955
|
+
}
|
|
592956
|
+
if (options.dueAfter) {
|
|
592957
|
+
filtered = filtered.filter((t) => t.due !== null && t.due >= options.dueAfter);
|
|
592958
|
+
}
|
|
592959
|
+
return filtered;
|
|
592960
|
+
}
|
|
592961
|
+
async function handleTaskList(opts) {
|
|
592962
|
+
const { client, format: format4, quiet, write, configTaskLists, all, completed, dueBefore, dueAfter } = opts;
|
|
592963
|
+
if (dueBefore !== undefined && !isValidDateString(dueBefore)) {
|
|
592964
|
+
write(`Error: Invalid date for --due-before: "${dueBefore}". Expected format: YYYY-MM-DD`);
|
|
592965
|
+
return { exitCode: ExitCode.ARGUMENT };
|
|
592966
|
+
}
|
|
592967
|
+
if (dueAfter !== undefined && !isValidDateString(dueAfter)) {
|
|
592968
|
+
write(`Error: Invalid date for --due-after: "${dueAfter}". Expected format: YYYY-MM-DD`);
|
|
592969
|
+
return { exitCode: ExitCode.ARGUMENT };
|
|
592970
|
+
}
|
|
592971
|
+
const resolved = await resolveTaskList(client, configTaskLists, opts.list);
|
|
592972
|
+
const apiOptions = {};
|
|
592973
|
+
if (all || completed) {
|
|
592974
|
+
apiOptions.showCompleted = true;
|
|
592975
|
+
apiOptions.showHidden = true;
|
|
592976
|
+
}
|
|
592977
|
+
const allTasks = await listTasks(client, resolved.id, resolved.title, apiOptions);
|
|
592978
|
+
const filterOpts = {
|
|
592979
|
+
all: all ?? false,
|
|
592980
|
+
completed: completed ?? false
|
|
592538
592981
|
};
|
|
592982
|
+
if (dueBefore !== undefined)
|
|
592983
|
+
filterOpts.dueBefore = dueBefore;
|
|
592984
|
+
if (dueAfter !== undefined)
|
|
592985
|
+
filterOpts.dueAfter = dueAfter;
|
|
592986
|
+
const tasks = filterTasks(allTasks, filterOpts);
|
|
592987
|
+
if (quiet) {
|
|
592988
|
+
write(formatQuietTaskList(tasks));
|
|
592989
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
592990
|
+
}
|
|
592991
|
+
if (format4 === "json") {
|
|
592992
|
+
write(formatJsonSuccess({
|
|
592993
|
+
tasks,
|
|
592994
|
+
count: tasks.length,
|
|
592995
|
+
list_id: resolved.id,
|
|
592996
|
+
list_title: resolved.title
|
|
592997
|
+
}));
|
|
592998
|
+
} else {
|
|
592999
|
+
write(formatTaskListText2(resolved.title, tasks));
|
|
593000
|
+
}
|
|
593001
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
593002
|
+
}
|
|
593003
|
+
|
|
593004
|
+
// src/commands/tasks/show.ts
|
|
593005
|
+
var LABEL_WIDTH = 11;
|
|
593006
|
+
function detailLine2(label, value) {
|
|
593007
|
+
return `${label}:`.padEnd(LABEL_WIDTH) + value;
|
|
593008
|
+
}
|
|
593009
|
+
function stripMilliseconds(iso) {
|
|
593010
|
+
return iso.replace(/\.\d{3}Z$/, "Z");
|
|
593011
|
+
}
|
|
593012
|
+
function formatTaskDetailText(task) {
|
|
593013
|
+
const lines = [];
|
|
593014
|
+
lines.push(detailLine2("ID", task.id));
|
|
593015
|
+
lines.push(detailLine2("Title", task.title));
|
|
593016
|
+
lines.push(detailLine2("Status", task.status));
|
|
593017
|
+
if (task.due) {
|
|
593018
|
+
lines.push(detailLine2("Due", task.due));
|
|
593019
|
+
}
|
|
593020
|
+
if (task.notes) {
|
|
593021
|
+
lines.push(detailLine2("Notes", task.notes));
|
|
593022
|
+
}
|
|
593023
|
+
lines.push(detailLine2("List", task.list_title));
|
|
593024
|
+
lines.push(detailLine2("Updated", stripMilliseconds(task.updated)));
|
|
593025
|
+
return lines.join(`
|
|
593026
|
+
`);
|
|
593027
|
+
}
|
|
593028
|
+
async function handleTaskShow(opts) {
|
|
593029
|
+
const { client, taskId, format: format4, quiet, write, configTaskLists } = opts;
|
|
593030
|
+
const resolved = await resolveTaskList(client, configTaskLists, opts.list);
|
|
593031
|
+
const task = await getTask(client, resolved.id, resolved.title, taskId);
|
|
593032
|
+
if (format4 === "json") {
|
|
593033
|
+
write(formatJsonSuccess({ task }));
|
|
593034
|
+
} else if (quiet) {
|
|
593035
|
+
write(`${task.title} ${task.status} ${task.due ?? ""}`);
|
|
593036
|
+
} else {
|
|
593037
|
+
write(formatTaskDetailText(task));
|
|
593038
|
+
}
|
|
593039
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
593040
|
+
}
|
|
593041
|
+
|
|
593042
|
+
// src/commands/tasks/add.ts
|
|
593043
|
+
function isValidDateString2(value) {
|
|
593044
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value))
|
|
593045
|
+
return false;
|
|
593046
|
+
const date3 = new Date(`${value}T00:00:00Z`);
|
|
593047
|
+
if (Number.isNaN(date3.getTime()))
|
|
593048
|
+
return false;
|
|
593049
|
+
return date3.toISOString().startsWith(value);
|
|
593050
|
+
}
|
|
593051
|
+
async function handleTaskAdd(opts) {
|
|
593052
|
+
const { client, title, format: format4, quiet, write, configTaskLists } = opts;
|
|
593053
|
+
if (!title) {
|
|
593054
|
+
const msg = "--title is required";
|
|
593055
|
+
if (format4 === "json") {
|
|
593056
|
+
write(formatJsonError("INVALID_ARGS", msg));
|
|
593057
|
+
} else {
|
|
593058
|
+
write(`Error: ${msg}`);
|
|
593059
|
+
}
|
|
593060
|
+
return { exitCode: ExitCode.ARGUMENT };
|
|
593061
|
+
}
|
|
593062
|
+
if (opts.due !== undefined && !isValidDateString2(opts.due)) {
|
|
593063
|
+
const msg = `Invalid date format: ${opts.due} (expected YYYY-MM-DD)`;
|
|
593064
|
+
if (format4 === "json") {
|
|
593065
|
+
write(formatJsonError("INVALID_ARGS", msg));
|
|
593066
|
+
} else {
|
|
593067
|
+
write(`Error: ${msg}`);
|
|
593068
|
+
}
|
|
593069
|
+
return { exitCode: ExitCode.ARGUMENT };
|
|
593070
|
+
}
|
|
593071
|
+
const resolved = await resolveTaskList(client, configTaskLists, opts.list);
|
|
593072
|
+
const input = { title };
|
|
593073
|
+
if (opts.notes !== undefined) {
|
|
593074
|
+
input.notes = opts.notes;
|
|
593075
|
+
}
|
|
593076
|
+
if (opts.due !== undefined) {
|
|
593077
|
+
input.due = `${opts.due}T00:00:00.000Z`;
|
|
593078
|
+
}
|
|
593079
|
+
if (opts.parent !== undefined) {
|
|
593080
|
+
input.parent = opts.parent;
|
|
593081
|
+
}
|
|
593082
|
+
const task = await createTask(client, resolved.id, resolved.title, input);
|
|
593083
|
+
if (format4 === "json") {
|
|
593084
|
+
write(formatJsonSuccess({ task, message: "Task created" }));
|
|
593085
|
+
} else if (quiet) {
|
|
593086
|
+
write(task.id);
|
|
593087
|
+
} else {
|
|
593088
|
+
write(`Task created: ${task.title} (${task.id})`);
|
|
593089
|
+
}
|
|
593090
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
593091
|
+
}
|
|
593092
|
+
|
|
593093
|
+
// src/commands/tasks/update.ts
|
|
593094
|
+
function isValidDateString3(value) {
|
|
593095
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value))
|
|
593096
|
+
return false;
|
|
593097
|
+
const date3 = new Date(`${value}T00:00:00Z`);
|
|
593098
|
+
if (Number.isNaN(date3.getTime()))
|
|
593099
|
+
return false;
|
|
593100
|
+
return date3.toISOString().startsWith(value);
|
|
593101
|
+
}
|
|
593102
|
+
async function handleTaskUpdate(opts) {
|
|
593103
|
+
const { client, taskId, format: format4, quiet, write, configTaskLists } = opts;
|
|
593104
|
+
const hasUpdate = opts.title !== undefined || opts.notes !== undefined || opts.due !== undefined;
|
|
593105
|
+
if (!hasUpdate) {
|
|
593106
|
+
const msg = "at least one update option must be provided (--title, --notes, or --due)";
|
|
593107
|
+
if (format4 === "json") {
|
|
593108
|
+
write(formatJsonError("INVALID_ARGS", msg));
|
|
593109
|
+
} else {
|
|
593110
|
+
write(`Error: ${msg}`);
|
|
593111
|
+
}
|
|
593112
|
+
return { exitCode: ExitCode.ARGUMENT };
|
|
593113
|
+
}
|
|
593114
|
+
if (opts.due !== undefined && !isValidDateString3(opts.due)) {
|
|
593115
|
+
const msg = `Invalid date format: ${opts.due} (expected YYYY-MM-DD)`;
|
|
593116
|
+
if (format4 === "json") {
|
|
593117
|
+
write(formatJsonError("INVALID_ARGS", msg));
|
|
593118
|
+
} else {
|
|
593119
|
+
write(`Error: ${msg}`);
|
|
593120
|
+
}
|
|
593121
|
+
return { exitCode: ExitCode.ARGUMENT };
|
|
593122
|
+
}
|
|
593123
|
+
const resolved = await resolveTaskList(client, configTaskLists, opts.list);
|
|
593124
|
+
const input = {};
|
|
593125
|
+
if (opts.title !== undefined) {
|
|
593126
|
+
input.title = opts.title;
|
|
593127
|
+
}
|
|
593128
|
+
if (opts.notes !== undefined) {
|
|
593129
|
+
input.notes = opts.notes;
|
|
593130
|
+
}
|
|
593131
|
+
if (opts.due !== undefined) {
|
|
593132
|
+
input.due = `${opts.due}T00:00:00.000Z`;
|
|
593133
|
+
}
|
|
593134
|
+
const task = await updateTask(client, resolved.id, resolved.title, taskId, input);
|
|
593135
|
+
if (format4 === "json") {
|
|
593136
|
+
write(formatJsonSuccess({ task, message: "Task updated" }));
|
|
593137
|
+
} else if (quiet) {
|
|
593138
|
+
write(task.id);
|
|
593139
|
+
} else {
|
|
593140
|
+
write(`Task updated: ${task.title} (${task.id})`);
|
|
593141
|
+
}
|
|
593142
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
593143
|
+
}
|
|
593144
|
+
|
|
593145
|
+
// src/commands/tasks/done.ts
|
|
593146
|
+
async function handleTaskDone(opts) {
|
|
593147
|
+
const { client, taskId, format: format4, quiet, write, configTaskLists } = opts;
|
|
593148
|
+
const resolved = await resolveTaskList(client, configTaskLists, opts.list);
|
|
593149
|
+
const task = await completeTask(client, resolved.id, resolved.title, taskId);
|
|
593150
|
+
if (format4 === "json") {
|
|
593151
|
+
write(formatJsonSuccess({ task, message: "Task completed" }));
|
|
593152
|
+
} else if (quiet) {
|
|
593153
|
+
write(task.id);
|
|
593154
|
+
} else {
|
|
593155
|
+
write(`Task completed: ${task.title} (${task.id})`);
|
|
593156
|
+
}
|
|
593157
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
593158
|
+
}
|
|
593159
|
+
|
|
593160
|
+
// src/commands/tasks/undone.ts
|
|
593161
|
+
async function handleTaskUndone(opts) {
|
|
593162
|
+
const { client, taskId, format: format4, quiet, write, configTaskLists } = opts;
|
|
593163
|
+
const resolved = await resolveTaskList(client, configTaskLists, opts.list);
|
|
593164
|
+
const task = await uncompleteTask(client, resolved.id, resolved.title, taskId);
|
|
593165
|
+
if (format4 === "json") {
|
|
593166
|
+
write(formatJsonSuccess({ task, message: "Task reopened" }));
|
|
593167
|
+
} else if (quiet) {
|
|
593168
|
+
write(task.id);
|
|
593169
|
+
} else {
|
|
593170
|
+
write(`Task reopened: ${task.title} (${task.id})`);
|
|
593171
|
+
}
|
|
593172
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
593173
|
+
}
|
|
593174
|
+
|
|
593175
|
+
// src/commands/tasks/delete.ts
|
|
593176
|
+
async function handleTaskDelete(opts) {
|
|
593177
|
+
const { client, taskId, format: format4, quiet, write, configTaskLists } = opts;
|
|
593178
|
+
const resolved = await resolveTaskList(client, configTaskLists, opts.list);
|
|
593179
|
+
await deleteTask(client, resolved.id, taskId);
|
|
593180
|
+
if (!quiet) {
|
|
593181
|
+
if (format4 === "json") {
|
|
593182
|
+
write(formatJsonSuccess({ deleted_id: taskId, message: "Task deleted" }));
|
|
593183
|
+
} else {
|
|
593184
|
+
write(`Task deleted (${taskId})`);
|
|
593185
|
+
}
|
|
593186
|
+
}
|
|
593187
|
+
return { exitCode: ExitCode.SUCCESS };
|
|
592539
593188
|
}
|
|
592540
593189
|
|
|
592541
593190
|
// src/cli.ts
|
|
@@ -592550,7 +593199,6 @@ function resolveGlobalOptions2(program2) {
|
|
|
592550
593199
|
}
|
|
592551
593200
|
return {
|
|
592552
593201
|
format: formatResult.data,
|
|
592553
|
-
calendar: raw.calendar,
|
|
592554
593202
|
timezone: raw.timezone,
|
|
592555
593203
|
quiet: raw.quiet
|
|
592556
593204
|
};
|
|
@@ -592625,6 +593273,25 @@ async function resolveEventCalendar(api2, eventId, calendars) {
|
|
|
592625
593273
|
}
|
|
592626
593274
|
|
|
592627
593275
|
// src/commands/index.ts
|
|
593276
|
+
async function runTaskAction(program2, handler) {
|
|
593277
|
+
const globalOpts = resolveGlobalOptions2(program2);
|
|
593278
|
+
try {
|
|
593279
|
+
const config2 = loadConfig(fsAdapter);
|
|
593280
|
+
const oauth2Client = await getAuthenticatedClient(fsAdapter);
|
|
593281
|
+
const client = createGoogleTasksClient(import_googleapis2.google.tasks({ version: "v1", auth: oauth2Client }));
|
|
593282
|
+
const result = await handler({
|
|
593283
|
+
client,
|
|
593284
|
+
format: globalOpts.format,
|
|
593285
|
+
quiet: globalOpts.quiet,
|
|
593286
|
+
write: (msg) => process.stdout.write(msg + `
|
|
593287
|
+
`),
|
|
593288
|
+
configTaskLists: config2.task_lists
|
|
593289
|
+
});
|
|
593290
|
+
process.exit(result.exitCode);
|
|
593291
|
+
} catch (error) {
|
|
593292
|
+
handleError2(error, globalOpts.format);
|
|
593293
|
+
}
|
|
593294
|
+
}
|
|
592628
593295
|
function registerCommands(program2) {
|
|
592629
593296
|
const authCmd = createAuthCommand();
|
|
592630
593297
|
authCmd.action(async () => {
|
|
@@ -592663,28 +593330,175 @@ ${url}`);
|
|
|
592663
593330
|
const calendarsCmd = createCalendarsCommand();
|
|
592664
593331
|
calendarsCmd.action(async () => {
|
|
592665
593332
|
const globalOpts = resolveGlobalOptions2(program2);
|
|
592666
|
-
|
|
592667
|
-
|
|
592668
|
-
|
|
592669
|
-
|
|
592670
|
-
|
|
592671
|
-
|
|
592672
|
-
|
|
592673
|
-
|
|
592674
|
-
|
|
593333
|
+
try {
|
|
593334
|
+
const config2 = loadConfig(fsAdapter);
|
|
593335
|
+
const oauth2Client = await getAuthenticatedClient(fsAdapter);
|
|
593336
|
+
const calendar = import_googleapis2.google.calendar({ version: "v3", auth: oauth2Client });
|
|
593337
|
+
const api2 = createGoogleCalendarApi(calendar);
|
|
593338
|
+
const result = await handleCalendars({
|
|
593339
|
+
api: api2,
|
|
593340
|
+
format: globalOpts.format,
|
|
593341
|
+
quiet: globalOpts.quiet,
|
|
593342
|
+
write: (msg) => process.stdout.write(msg + `
|
|
592675
593343
|
`),
|
|
592676
|
-
|
|
592677
|
-
|
|
592678
|
-
|
|
593344
|
+
configCalendars: config2.calendars
|
|
593345
|
+
});
|
|
593346
|
+
process.exit(result.exitCode);
|
|
593347
|
+
} catch (error) {
|
|
593348
|
+
handleError2(error, globalOpts.format);
|
|
593349
|
+
}
|
|
592679
593350
|
});
|
|
592680
593351
|
program2.addCommand(calendarsCmd);
|
|
593352
|
+
const {
|
|
593353
|
+
tasksCmd,
|
|
593354
|
+
listsCmd: tasksListsCmd,
|
|
593355
|
+
listCmd: tasksListCmd,
|
|
593356
|
+
showCmd: tasksShowCmd,
|
|
593357
|
+
addCmd: tasksAddCmd,
|
|
593358
|
+
updateCmd: tasksUpdateCmd,
|
|
593359
|
+
doneCmd: tasksDoneCmd,
|
|
593360
|
+
undoneCmd: tasksUndoneCmd,
|
|
593361
|
+
deleteCmd: tasksDeleteCmd
|
|
593362
|
+
} = createTasksCommand();
|
|
593363
|
+
tasksListsCmd.action(async () => {
|
|
593364
|
+
const globalOpts = resolveGlobalOptions2(program2);
|
|
593365
|
+
try {
|
|
593366
|
+
const config2 = loadConfig(fsAdapter);
|
|
593367
|
+
const oauth2Client = await getAuthenticatedClient(fsAdapter);
|
|
593368
|
+
const tasksClient = createGoogleTasksClient(import_googleapis2.google.tasks({ version: "v1", auth: oauth2Client }));
|
|
593369
|
+
const result = await handleTaskLists({
|
|
593370
|
+
client: tasksClient,
|
|
593371
|
+
format: globalOpts.format,
|
|
593372
|
+
quiet: globalOpts.quiet,
|
|
593373
|
+
write: (msg) => process.stdout.write(msg + `
|
|
593374
|
+
`),
|
|
593375
|
+
configTaskLists: config2.task_lists
|
|
593376
|
+
});
|
|
593377
|
+
process.exit(result.exitCode);
|
|
593378
|
+
} catch (error) {
|
|
593379
|
+
handleError2(error, globalOpts.format);
|
|
593380
|
+
}
|
|
593381
|
+
});
|
|
593382
|
+
tasksListCmd.action(async () => {
|
|
593383
|
+
const globalOpts = resolveGlobalOptions2(program2);
|
|
593384
|
+
const listOpts = tasksListCmd.opts();
|
|
593385
|
+
try {
|
|
593386
|
+
const config2 = loadConfig(fsAdapter);
|
|
593387
|
+
const oauth2Client = await getAuthenticatedClient(fsAdapter);
|
|
593388
|
+
const tasksClient = createGoogleTasksClient(import_googleapis2.google.tasks({ version: "v1", auth: oauth2Client }));
|
|
593389
|
+
const opts = {
|
|
593390
|
+
client: tasksClient,
|
|
593391
|
+
format: globalOpts.format,
|
|
593392
|
+
quiet: globalOpts.quiet,
|
|
593393
|
+
write: (msg) => process.stdout.write(msg + `
|
|
593394
|
+
`),
|
|
593395
|
+
configTaskLists: config2.task_lists
|
|
593396
|
+
};
|
|
593397
|
+
if (listOpts.list !== undefined)
|
|
593398
|
+
opts.list = listOpts.list;
|
|
593399
|
+
if (listOpts.all)
|
|
593400
|
+
opts.all = true;
|
|
593401
|
+
if (listOpts.completed)
|
|
593402
|
+
opts.completed = true;
|
|
593403
|
+
if (listOpts.dueBefore !== undefined)
|
|
593404
|
+
opts.dueBefore = listOpts.dueBefore;
|
|
593405
|
+
if (listOpts.dueAfter !== undefined)
|
|
593406
|
+
opts.dueAfter = listOpts.dueAfter;
|
|
593407
|
+
const result = await handleTaskList(opts);
|
|
593408
|
+
process.exit(result.exitCode);
|
|
593409
|
+
} catch (error) {
|
|
593410
|
+
handleError2(error, globalOpts.format);
|
|
593411
|
+
}
|
|
593412
|
+
});
|
|
593413
|
+
tasksShowCmd.action(async (taskId) => {
|
|
593414
|
+
const globalOpts = resolveGlobalOptions2(program2);
|
|
593415
|
+
const showOpts = tasksShowCmd.opts();
|
|
593416
|
+
try {
|
|
593417
|
+
const config2 = loadConfig(fsAdapter);
|
|
593418
|
+
const oauth2Client = await getAuthenticatedClient(fsAdapter);
|
|
593419
|
+
const tasksClient = createGoogleTasksClient(import_googleapis2.google.tasks({ version: "v1", auth: oauth2Client }));
|
|
593420
|
+
const opts = {
|
|
593421
|
+
client: tasksClient,
|
|
593422
|
+
taskId,
|
|
593423
|
+
format: globalOpts.format,
|
|
593424
|
+
quiet: globalOpts.quiet,
|
|
593425
|
+
write: (msg) => process.stdout.write(msg + `
|
|
593426
|
+
`),
|
|
593427
|
+
configTaskLists: config2.task_lists
|
|
593428
|
+
};
|
|
593429
|
+
if (showOpts.list !== undefined)
|
|
593430
|
+
opts.list = showOpts.list;
|
|
593431
|
+
const result = await handleTaskShow(opts);
|
|
593432
|
+
process.exit(result.exitCode);
|
|
593433
|
+
} catch (error) {
|
|
593434
|
+
handleError2(error, globalOpts.format);
|
|
593435
|
+
}
|
|
593436
|
+
});
|
|
593437
|
+
tasksAddCmd.action(async () => {
|
|
593438
|
+
const addOpts = tasksAddCmd.opts();
|
|
593439
|
+
await runTaskAction(program2, (deps) => {
|
|
593440
|
+
const opts = { ...deps, title: addOpts.title };
|
|
593441
|
+
if (addOpts.notes !== undefined)
|
|
593442
|
+
opts.notes = addOpts.notes;
|
|
593443
|
+
if (addOpts.due !== undefined)
|
|
593444
|
+
opts.due = addOpts.due;
|
|
593445
|
+
if (addOpts.list !== undefined)
|
|
593446
|
+
opts.list = addOpts.list;
|
|
593447
|
+
if (addOpts.parent !== undefined)
|
|
593448
|
+
opts.parent = addOpts.parent;
|
|
593449
|
+
return handleTaskAdd(opts);
|
|
593450
|
+
});
|
|
593451
|
+
});
|
|
593452
|
+
tasksUpdateCmd.action(async (taskId) => {
|
|
593453
|
+
const updateOpts = tasksUpdateCmd.opts();
|
|
593454
|
+
await runTaskAction(program2, (deps) => {
|
|
593455
|
+
const opts = { ...deps, taskId };
|
|
593456
|
+
if (updateOpts.title !== undefined)
|
|
593457
|
+
opts.title = updateOpts.title;
|
|
593458
|
+
if (updateOpts.notes !== undefined)
|
|
593459
|
+
opts.notes = updateOpts.notes;
|
|
593460
|
+
if (updateOpts.due !== undefined)
|
|
593461
|
+
opts.due = updateOpts.due;
|
|
593462
|
+
if (updateOpts.list !== undefined)
|
|
593463
|
+
opts.list = updateOpts.list;
|
|
593464
|
+
return handleTaskUpdate(opts);
|
|
593465
|
+
});
|
|
593466
|
+
});
|
|
593467
|
+
tasksDoneCmd.action(async (taskId) => {
|
|
593468
|
+
const doneOpts = tasksDoneCmd.opts();
|
|
593469
|
+
await runTaskAction(program2, (deps) => {
|
|
593470
|
+
const opts = { ...deps, taskId };
|
|
593471
|
+
if (doneOpts.list !== undefined)
|
|
593472
|
+
opts.list = doneOpts.list;
|
|
593473
|
+
return handleTaskDone(opts);
|
|
593474
|
+
});
|
|
593475
|
+
});
|
|
593476
|
+
tasksUndoneCmd.action(async (taskId) => {
|
|
593477
|
+
const undoneOpts = tasksUndoneCmd.opts();
|
|
593478
|
+
await runTaskAction(program2, (deps) => {
|
|
593479
|
+
const opts = { ...deps, taskId };
|
|
593480
|
+
if (undoneOpts.list !== undefined)
|
|
593481
|
+
opts.list = undoneOpts.list;
|
|
593482
|
+
return handleTaskUndone(opts);
|
|
593483
|
+
});
|
|
593484
|
+
});
|
|
593485
|
+
tasksDeleteCmd.action(async (taskId) => {
|
|
593486
|
+
const deleteOpts = tasksDeleteCmd.opts();
|
|
593487
|
+
await runTaskAction(program2, (deps) => {
|
|
593488
|
+
const opts = { ...deps, taskId };
|
|
593489
|
+
if (deleteOpts.list !== undefined)
|
|
593490
|
+
opts.list = deleteOpts.list;
|
|
593491
|
+
return handleTaskDelete(opts);
|
|
593492
|
+
});
|
|
593493
|
+
});
|
|
593494
|
+
program2.addCommand(tasksCmd);
|
|
592681
593495
|
const listCmd = createListCommand();
|
|
592682
593496
|
listCmd.action(async () => {
|
|
592683
593497
|
const globalOpts = resolveGlobalOptions2(program2);
|
|
592684
593498
|
const listOpts = listCmd.opts();
|
|
592685
593499
|
try {
|
|
592686
593500
|
const auth = await getAuthenticatedClient(fsAdapter);
|
|
592687
|
-
const api2 = import_googleapis2.google.calendar({ version: "v3", auth });
|
|
593501
|
+
const api2 = createGoogleCalendarApi(import_googleapis2.google.calendar({ version: "v3", auth }));
|
|
592688
593502
|
const deps = {
|
|
592689
593503
|
listEvents: (calendarId, calendarName, options) => listEvents(api2, calendarId, calendarName, options),
|
|
592690
593504
|
loadConfig: () => loadConfig(fsAdapter),
|
|
@@ -592696,8 +593510,7 @@ ${url}`);
|
|
|
592696
593510
|
const handleOpts = {
|
|
592697
593511
|
...listOpts,
|
|
592698
593512
|
format: globalOpts.format,
|
|
592699
|
-
quiet: globalOpts.quiet
|
|
592700
|
-
calendar: globalOpts.calendar
|
|
593513
|
+
quiet: globalOpts.quiet
|
|
592701
593514
|
};
|
|
592702
593515
|
if (globalOpts.timezone)
|
|
592703
593516
|
handleOpts.timezone = globalOpts.timezone;
|
|
@@ -592718,11 +593531,12 @@ ${url}`);
|
|
|
592718
593531
|
const calendarApi = import_googleapis2.google.calendar({ version: "v3", auth });
|
|
592719
593532
|
const api2 = createGoogleCalendarApi(calendarApi);
|
|
592720
593533
|
const timezone = resolveTimezone(globalOpts.timezone, config2.timezone);
|
|
592721
|
-
const calendars = selectCalendars(
|
|
593534
|
+
const calendars = selectCalendars(searchOpts.calendar.length > 0 ? searchOpts.calendar : undefined, config2);
|
|
592722
593535
|
const result = await handleSearch({
|
|
592723
593536
|
api: api2,
|
|
592724
593537
|
query,
|
|
592725
593538
|
format: globalOpts.format,
|
|
593539
|
+
quiet: globalOpts.quiet,
|
|
592726
593540
|
calendars,
|
|
592727
593541
|
timezone,
|
|
592728
593542
|
days: searchOpts.days,
|
|
@@ -592744,7 +593558,7 @@ ${url}`);
|
|
|
592744
593558
|
});
|
|
592745
593559
|
program2.addCommand(searchCmd);
|
|
592746
593560
|
const showCmd = createShowCommand();
|
|
592747
|
-
showCmd.action(async () => {
|
|
593561
|
+
showCmd.action(async (eventId) => {
|
|
592748
593562
|
const globalOpts = resolveGlobalOptions2(program2);
|
|
592749
593563
|
const showOpts = showCmd.opts();
|
|
592750
593564
|
try {
|
|
@@ -592752,23 +593566,24 @@ ${url}`);
|
|
|
592752
593566
|
const auth = await getAuthenticatedClient(fsAdapter);
|
|
592753
593567
|
const calendarApi = import_googleapis2.google.calendar({ version: "v3", auth });
|
|
592754
593568
|
const api2 = createGoogleCalendarApi(calendarApi);
|
|
592755
|
-
const calendarId = showOpts.calendar
|
|
593569
|
+
const calendarId = showOpts.calendar;
|
|
592756
593570
|
let cal;
|
|
592757
593571
|
if (calendarId) {
|
|
592758
593572
|
const found = config2.calendars.find((c) => c.id === calendarId);
|
|
592759
593573
|
cal = found ? { id: found.id, name: found.name } : { id: calendarId, name: calendarId };
|
|
592760
593574
|
} else {
|
|
592761
593575
|
const calendars = selectCalendars(undefined, config2);
|
|
592762
|
-
const resolved = await resolveEventCalendar(api2,
|
|
593576
|
+
const resolved = await resolveEventCalendar(api2, eventId, calendars);
|
|
592763
593577
|
cal = resolved;
|
|
592764
593578
|
}
|
|
592765
593579
|
const timezone = resolveTimezone(globalOpts.timezone, config2.timezone);
|
|
592766
593580
|
const result = await handleShow({
|
|
592767
593581
|
api: api2,
|
|
592768
|
-
eventId
|
|
593582
|
+
eventId,
|
|
592769
593583
|
calendarId: cal.id,
|
|
592770
593584
|
calendarName: cal.name,
|
|
592771
593585
|
format: globalOpts.format,
|
|
593586
|
+
quiet: globalOpts.quiet,
|
|
592772
593587
|
timezone,
|
|
592773
593588
|
write: (msg) => process.stdout.write(msg + `
|
|
592774
593589
|
`)
|
|
@@ -592789,8 +593604,8 @@ ${url}`);
|
|
|
592789
593604
|
const calendarApi = import_googleapis2.google.calendar({ version: "v3", auth });
|
|
592790
593605
|
const api2 = createGoogleCalendarApi(calendarApi);
|
|
592791
593606
|
let resolvedCalendarId;
|
|
592792
|
-
if (deleteOpts.calendar
|
|
592793
|
-
const calendars = selectCalendars(
|
|
593607
|
+
if (deleteOpts.calendar) {
|
|
593608
|
+
const calendars = selectCalendars([deleteOpts.calendar], config2);
|
|
592794
593609
|
resolvedCalendarId = calendars[0]?.id ?? "primary";
|
|
592795
593610
|
} else {
|
|
592796
593611
|
const calendars = selectCalendars(undefined, config2);
|
|
@@ -592834,10 +593649,12 @@ ${url}`);
|
|
|
592834
593649
|
description: addOpts.description,
|
|
592835
593650
|
busy: addOpts.busy,
|
|
592836
593651
|
free: addOpts.free,
|
|
593652
|
+
dryRun: addOpts.dryRun,
|
|
593653
|
+
quiet: globalOpts.quiet,
|
|
592837
593654
|
format: globalOpts.format
|
|
592838
593655
|
};
|
|
592839
|
-
if (
|
|
592840
|
-
handleOpts.calendar =
|
|
593656
|
+
if (addOpts.calendar)
|
|
593657
|
+
handleOpts.calendar = addOpts.calendar;
|
|
592841
593658
|
if (globalOpts.timezone)
|
|
592842
593659
|
handleOpts.timezone = globalOpts.timezone;
|
|
592843
593660
|
const result = await handleAdd(handleOpts, deps);
|
|
@@ -592868,6 +593685,11 @@ ${url}`);
|
|
|
592868
593685
|
const api2 = await getApi();
|
|
592869
593686
|
return listCalendars(api2);
|
|
592870
593687
|
},
|
|
593688
|
+
listTaskLists: async () => {
|
|
593689
|
+
const oauth2Client = await getAuthenticatedClient(fsAdapter);
|
|
593690
|
+
const tasksClient = createGoogleTasksClient(import_googleapis2.google.tasks({ version: "v1", auth: oauth2Client }));
|
|
593691
|
+
return listTaskLists(tasksClient);
|
|
593692
|
+
},
|
|
592871
593693
|
requestAuth: async () => {
|
|
592872
593694
|
apiRef = null;
|
|
592873
593695
|
const promptFn = createReadlinePrompt();
|
|
@@ -592887,6 +593709,8 @@ ${authUrl}`);
|
|
|
592887
593709
|
format: globalOpts.format,
|
|
592888
593710
|
quiet: globalOpts.quiet,
|
|
592889
593711
|
write,
|
|
593712
|
+
writeErr: (msg) => process.stderr.write(msg + `
|
|
593713
|
+
`),
|
|
592890
593714
|
force: initOpts.force ?? false,
|
|
592891
593715
|
all: initOpts.all ?? false,
|
|
592892
593716
|
local: initOpts.local ?? false,
|
|
@@ -592910,8 +593734,8 @@ ${authUrl}`);
|
|
|
592910
593734
|
const timezone = resolveTimezone(globalOpts.timezone, config2.timezone);
|
|
592911
593735
|
const updateOpsCalendar = updateOpts.calendar;
|
|
592912
593736
|
let cal;
|
|
592913
|
-
if (updateOpsCalendar
|
|
592914
|
-
const calendars = selectCalendars(
|
|
593737
|
+
if (updateOpsCalendar) {
|
|
593738
|
+
const calendars = selectCalendars([updateOpsCalendar], config2);
|
|
592915
593739
|
cal = calendars[0];
|
|
592916
593740
|
} else {
|
|
592917
593741
|
const calendars = selectCalendars(undefined, config2);
|
|
@@ -592924,6 +593748,7 @@ ${authUrl}`);
|
|
|
592924
593748
|
calendarId: cal.id,
|
|
592925
593749
|
calendarName: cal.name,
|
|
592926
593750
|
format: globalOpts.format,
|
|
593751
|
+
quiet: globalOpts.quiet,
|
|
592927
593752
|
timezone,
|
|
592928
593753
|
write: (msg) => process.stdout.write(msg + `
|
|
592929
593754
|
`),
|