taskair-cli 1.0.6 → 1.0.8
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 +453 -195
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { program } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/config.tsx
|
|
7
|
-
import
|
|
7
|
+
import React4, { useState as useState4, useEffect as useEffect4 } from "react";
|
|
8
8
|
import { Box as Box4, Text as Text4, useInput, useApp } from "ink";
|
|
9
9
|
import { hostname } from "os";
|
|
10
10
|
import http from "http";
|
|
@@ -283,6 +283,7 @@ function Spinner({
|
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
// src/components/AsciiHeader.tsx
|
|
286
|
+
import { useState as useState3, useEffect as useEffect3 } from "react";
|
|
286
287
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
287
288
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
288
289
|
var LOGO = [
|
|
@@ -293,23 +294,86 @@ var LOGO = [
|
|
|
293
294
|
" \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551",
|
|
294
295
|
" \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D"
|
|
295
296
|
];
|
|
296
|
-
var
|
|
297
|
-
|
|
297
|
+
var WAVE_COLORS = [
|
|
298
|
+
"#FF0080",
|
|
299
|
+
"#EE40FB",
|
|
300
|
+
"#B44FFF",
|
|
301
|
+
"#7B61FF",
|
|
302
|
+
"#5B8AFF",
|
|
303
|
+
"#00D4FF",
|
|
304
|
+
"#5B8AFF",
|
|
305
|
+
"#7B61FF",
|
|
306
|
+
"#B44FFF",
|
|
307
|
+
"#EE40FB"
|
|
308
|
+
];
|
|
309
|
+
var DIVIDER_COLORS = [
|
|
310
|
+
"#7B61FF",
|
|
311
|
+
"#B44FFF",
|
|
312
|
+
"#FF0080",
|
|
313
|
+
"#B44FFF",
|
|
314
|
+
"#7B61FF",
|
|
315
|
+
"#5B8AFF",
|
|
316
|
+
"#00D4FF",
|
|
317
|
+
"#5B8AFF"
|
|
318
|
+
];
|
|
319
|
+
var TAGLINE = "\u2726 CLI \xB7 MCP \xB7 Web \u2726";
|
|
320
|
+
var DIVIDER_LEN = 60;
|
|
321
|
+
function AnimatedDivider() {
|
|
322
|
+
const [frame, setFrame] = useState3(0);
|
|
323
|
+
useEffect3(() => {
|
|
324
|
+
const id = setInterval(() => {
|
|
325
|
+
setFrame((f) => (f + 1) % DIVIDER_COLORS.length);
|
|
326
|
+
}, 280);
|
|
327
|
+
return () => clearInterval(id);
|
|
328
|
+
}, []);
|
|
329
|
+
return /* @__PURE__ */ jsx3(Text3, { color: DIVIDER_COLORS[frame], children: "\u2500".repeat(DIVIDER_LEN) });
|
|
330
|
+
}
|
|
331
|
+
function PremiumHeader() {
|
|
332
|
+
const [visibleLines, setVisibleLines] = useState3(0);
|
|
333
|
+
const [colorFrame, setColorFrame] = useState3(0);
|
|
334
|
+
const [taglineChars, setTaglineChars] = useState3(0);
|
|
335
|
+
const [showDivider, setShowDivider] = useState3(false);
|
|
336
|
+
const revealed = visibleLines >= LOGO.length;
|
|
337
|
+
useEffect3(() => {
|
|
338
|
+
if (visibleLines >= LOGO.length) return;
|
|
339
|
+
const id = setTimeout(() => setVisibleLines((v) => v + 1), 55);
|
|
340
|
+
return () => clearTimeout(id);
|
|
341
|
+
}, [visibleLines]);
|
|
342
|
+
useEffect3(() => {
|
|
343
|
+
if (!revealed) return;
|
|
344
|
+
const id = setInterval(() => {
|
|
345
|
+
setColorFrame((f) => (f + 1) % WAVE_COLORS.length);
|
|
346
|
+
}, 110);
|
|
347
|
+
return () => clearInterval(id);
|
|
348
|
+
}, [revealed]);
|
|
349
|
+
useEffect3(() => {
|
|
350
|
+
if (!revealed || taglineChars >= TAGLINE.length) return;
|
|
351
|
+
const id = setTimeout(() => setTaglineChars((c) => c + 1), 38);
|
|
352
|
+
return () => clearTimeout(id);
|
|
353
|
+
}, [revealed, taglineChars]);
|
|
354
|
+
useEffect3(() => {
|
|
355
|
+
if (taglineChars >= TAGLINE.length && !showDivider) {
|
|
356
|
+
setShowDivider(true);
|
|
357
|
+
}
|
|
358
|
+
}, [taglineChars, showDivider]);
|
|
298
359
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginBottom: 1, children: [
|
|
299
|
-
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: LOGO.map((line, i) =>
|
|
300
|
-
|
|
301
|
-
|
|
360
|
+
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: LOGO.slice(0, visibleLines).map((line, i) => {
|
|
361
|
+
const colorIdx = (i * 2 + colorFrame) % WAVE_COLORS.length;
|
|
362
|
+
return /* @__PURE__ */ jsx3(Text3, { color: revealed ? WAVE_COLORS[colorIdx] : "#B44FFF", bold: true, children: line }, i);
|
|
363
|
+
}) }),
|
|
364
|
+
revealed && taglineChars > 0 && /* @__PURE__ */ jsx3(Box3, { marginTop: 0, children: /* @__PURE__ */ jsxs3(Text3, { color: "#00D4FF", bold: true, children: [
|
|
365
|
+
" ",
|
|
366
|
+
TAGLINE.slice(0, taglineChars),
|
|
367
|
+
taglineChars < TAGLINE.length ? /* @__PURE__ */ jsx3(Text3, { color: "#7B61FF", children: "\u258C" }) : null
|
|
368
|
+
] }) }),
|
|
369
|
+
showDivider && /* @__PURE__ */ jsx3(Box3, { marginTop: 0, children: /* @__PURE__ */ jsx3(AnimatedDivider, {}) })
|
|
302
370
|
] });
|
|
303
371
|
}
|
|
372
|
+
function AsciiHeader() {
|
|
373
|
+
return /* @__PURE__ */ jsx3(PremiumHeader, {});
|
|
374
|
+
}
|
|
304
375
|
function MiniHeader() {
|
|
305
|
-
return /* @__PURE__ */
|
|
306
|
-
/* @__PURE__ */ jsxs3(Text3, { color: "magenta", bold: true, children: [
|
|
307
|
-
"\u2726",
|
|
308
|
-
" "
|
|
309
|
-
] }),
|
|
310
|
-
/* @__PURE__ */ jsx3(Text3, { color: "cyan", bold: true, children: "TaskAir" }),
|
|
311
|
-
/* @__PURE__ */ jsx3(Text3, { color: "#7B61FF", children: " \u2014 Space-grade task management" })
|
|
312
|
-
] });
|
|
376
|
+
return /* @__PURE__ */ jsx3(PremiumHeader, {});
|
|
313
377
|
}
|
|
314
378
|
|
|
315
379
|
// src/commands/config.tsx
|
|
@@ -321,12 +385,12 @@ function openBrowser(url) {
|
|
|
321
385
|
}
|
|
322
386
|
function ConfigUI({ initialApiUrl }) {
|
|
323
387
|
const { exit } = useApp();
|
|
324
|
-
const [stage, setStage] =
|
|
325
|
-
const [apiUrl, setApiUrl] =
|
|
326
|
-
const [currentInput, setCurrentInput] =
|
|
327
|
-
const [port, setPort] =
|
|
328
|
-
const [errorMsg, setErrorMsg] =
|
|
329
|
-
const [authDetails, setAuthDetails] =
|
|
388
|
+
const [stage, setStage] = useState4("input_api_url");
|
|
389
|
+
const [apiUrl, setApiUrl] = useState4(initialApiUrl);
|
|
390
|
+
const [currentInput, setCurrentInput] = useState4(initialApiUrl);
|
|
391
|
+
const [port, setPort] = useState4(0);
|
|
392
|
+
const [errorMsg, setErrorMsg] = useState4("");
|
|
393
|
+
const [authDetails, setAuthDetails] = useState4(null);
|
|
330
394
|
useInput((input, key) => {
|
|
331
395
|
if (stage === "input_api_url") {
|
|
332
396
|
if (key.return) {
|
|
@@ -350,7 +414,7 @@ function ConfigUI({ initialApiUrl }) {
|
|
|
350
414
|
}
|
|
351
415
|
}
|
|
352
416
|
});
|
|
353
|
-
|
|
417
|
+
useEffect4(() => {
|
|
354
418
|
if (stage !== "waiting_for_browser") return;
|
|
355
419
|
let server = null;
|
|
356
420
|
let isActive = true;
|
|
@@ -557,7 +621,7 @@ function ConfigUI({ initialApiUrl }) {
|
|
|
557
621
|
}
|
|
558
622
|
};
|
|
559
623
|
}, [stage, apiUrl]);
|
|
560
|
-
|
|
624
|
+
useEffect4(() => {
|
|
561
625
|
if (stage !== "registering" || !authDetails) return;
|
|
562
626
|
async function registerAndSave() {
|
|
563
627
|
try {
|
|
@@ -633,7 +697,7 @@ function registerConfig(program2) {
|
|
|
633
697
|
const existing = readCredentials();
|
|
634
698
|
const { render } = await import("ink");
|
|
635
699
|
render(
|
|
636
|
-
|
|
700
|
+
React4.createElement(ConfigUI, {
|
|
637
701
|
initialApiUrl: existing?.api_url ?? "http://localhost:3001"
|
|
638
702
|
})
|
|
639
703
|
);
|
|
@@ -641,19 +705,19 @@ function registerConfig(program2) {
|
|
|
641
705
|
}
|
|
642
706
|
|
|
643
707
|
// src/commands/login.tsx
|
|
644
|
-
import
|
|
708
|
+
import React5, { useState as useState5, useEffect as useEffect5 } from "react";
|
|
645
709
|
import { Box as Box5, Text as Text5, useInput as useInput2, useApp as useApp2 } from "ink";
|
|
646
710
|
import { hostname as hostname2 } from "os";
|
|
647
711
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
648
712
|
function LoginUI() {
|
|
649
713
|
const { exit } = useApp2();
|
|
650
714
|
const creds = readCredentials();
|
|
651
|
-
const [email, setEmail] =
|
|
652
|
-
const [password, setPassword] =
|
|
653
|
-
const [stage, setStage] =
|
|
654
|
-
const [currentInput, setCurrentInput] =
|
|
655
|
-
const [errorMsg, setErrorMsg] =
|
|
656
|
-
|
|
715
|
+
const [email, setEmail] = useState5(creds?.email ?? "");
|
|
716
|
+
const [password, setPassword] = useState5("");
|
|
717
|
+
const [stage, setStage] = useState5("input_email");
|
|
718
|
+
const [currentInput, setCurrentInput] = useState5(creds?.email ?? "");
|
|
719
|
+
const [errorMsg, setErrorMsg] = useState5("");
|
|
720
|
+
useEffect5(() => {
|
|
657
721
|
if (stage === "loading") {
|
|
658
722
|
const apiUrl = creds?.api_url ?? "http://localhost:3001";
|
|
659
723
|
apiLogin(apiUrl, email, password).then(async (res) => {
|
|
@@ -750,19 +814,19 @@ function LoginUI() {
|
|
|
750
814
|
function registerLogin(program2) {
|
|
751
815
|
program2.command("login").description("Authenticate with TaskAir API").action(async () => {
|
|
752
816
|
const { render } = await import("ink");
|
|
753
|
-
render(
|
|
817
|
+
render(React5.createElement(LoginUI));
|
|
754
818
|
});
|
|
755
819
|
}
|
|
756
820
|
|
|
757
821
|
// src/commands/logout.tsx
|
|
758
|
-
import
|
|
822
|
+
import React6, { useEffect as useEffect6, useState as useState6 } from "react";
|
|
759
823
|
import { Box as Box6, useApp as useApp3 } from "ink";
|
|
760
824
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
761
825
|
function LogoutUI() {
|
|
762
826
|
const { exit } = useApp3();
|
|
763
|
-
const [status, setStatus] =
|
|
764
|
-
const [message, setMessage] =
|
|
765
|
-
|
|
827
|
+
const [status, setStatus] = useState6("loading");
|
|
828
|
+
const [message, setMessage] = useState6("");
|
|
829
|
+
useEffect6(() => {
|
|
766
830
|
const creds = readCredentials();
|
|
767
831
|
if (!creds?.access_token) {
|
|
768
832
|
setMessage("Not logged in.");
|
|
@@ -789,12 +853,12 @@ function LogoutUI() {
|
|
|
789
853
|
function registerLogout(program2) {
|
|
790
854
|
program2.command("logout").description("Clear local credentials and revoke session").action(async () => {
|
|
791
855
|
const { render } = await import("ink");
|
|
792
|
-
render(
|
|
856
|
+
render(React6.createElement(LogoutUI));
|
|
793
857
|
});
|
|
794
858
|
}
|
|
795
859
|
|
|
796
860
|
// src/commands/whoami.tsx
|
|
797
|
-
import
|
|
861
|
+
import React7 from "react";
|
|
798
862
|
import { Box as Box7, Text as Text7 } from "ink";
|
|
799
863
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
800
864
|
function WhoamiUI() {
|
|
@@ -854,12 +918,12 @@ function WhoamiUI() {
|
|
|
854
918
|
function registerWhoami(program2) {
|
|
855
919
|
program2.command("whoami").description("Display the currently authenticated user").action(async () => {
|
|
856
920
|
const { render } = await import("ink");
|
|
857
|
-
render(
|
|
921
|
+
render(React7.createElement(WhoamiUI));
|
|
858
922
|
});
|
|
859
923
|
}
|
|
860
924
|
|
|
861
925
|
// src/commands/add.tsx
|
|
862
|
-
import
|
|
926
|
+
import React8, { useEffect as useEffect7, useState as useState7 } from "react";
|
|
863
927
|
import { Box as Box8, Text as Text8, useApp as useApp4 } from "ink";
|
|
864
928
|
import { v4 as uuidv42 } from "uuid";
|
|
865
929
|
|
|
@@ -1034,12 +1098,12 @@ function AddUI({
|
|
|
1034
1098
|
tags
|
|
1035
1099
|
}) {
|
|
1036
1100
|
const { exit } = useApp4();
|
|
1037
|
-
const [status, setStatus] =
|
|
1038
|
-
const [syncStatus, setSyncStatus] =
|
|
1039
|
-
const [syncMessage, setSyncMessage] =
|
|
1040
|
-
const [taskId, setTaskId] =
|
|
1041
|
-
const [errorMsg, setErrorMsg] =
|
|
1042
|
-
|
|
1101
|
+
const [status, setStatus] = useState7("working");
|
|
1102
|
+
const [syncStatus, setSyncStatus] = useState7("idle");
|
|
1103
|
+
const [syncMessage, setSyncMessage] = useState7("");
|
|
1104
|
+
const [taskId, setTaskId] = useState7("");
|
|
1105
|
+
const [errorMsg, setErrorMsg] = useState7("");
|
|
1106
|
+
useEffect7(() => {
|
|
1043
1107
|
async function createTaskAndSync() {
|
|
1044
1108
|
try {
|
|
1045
1109
|
const auth = requireAuth();
|
|
@@ -1156,7 +1220,7 @@ function registerAdd(program2) {
|
|
|
1156
1220
|
const tags = options.tags ? options.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
1157
1221
|
const { render } = await import("ink");
|
|
1158
1222
|
render(
|
|
1159
|
-
|
|
1223
|
+
React8.createElement(AddUI, {
|
|
1160
1224
|
description,
|
|
1161
1225
|
priority,
|
|
1162
1226
|
due: options.due,
|
|
@@ -1167,11 +1231,11 @@ function registerAdd(program2) {
|
|
|
1167
1231
|
}
|
|
1168
1232
|
|
|
1169
1233
|
// src/commands/list.tsx
|
|
1170
|
-
import
|
|
1234
|
+
import React10, { useEffect as useEffect8, useState as useState8 } from "react";
|
|
1171
1235
|
import { Box as Box10, Text as Text10, useApp as useApp5 } from "ink";
|
|
1172
1236
|
|
|
1173
1237
|
// src/components/TaskTable.tsx
|
|
1174
|
-
import
|
|
1238
|
+
import React9 from "react";
|
|
1175
1239
|
import { Box as Box9, Text as Text9 } from "ink";
|
|
1176
1240
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1177
1241
|
function priorityColor(p) {
|
|
@@ -1273,7 +1337,7 @@ function TaskTable({ tasks }) {
|
|
|
1273
1337
|
/* @__PURE__ */ jsx9(TopBorder, {}),
|
|
1274
1338
|
/* @__PURE__ */ jsx9(Header, {}),
|
|
1275
1339
|
/* @__PURE__ */ jsx9(Separator, {}),
|
|
1276
|
-
tasks.map((task, i) => /* @__PURE__ */ jsxs9(
|
|
1340
|
+
tasks.map((task, i) => /* @__PURE__ */ jsxs9(React9.Fragment, { children: [
|
|
1277
1341
|
/* @__PURE__ */ jsx9(TableRow, { task }),
|
|
1278
1342
|
i < tasks.length - 1 && /* @__PURE__ */ jsx9(Separator, {})
|
|
1279
1343
|
] }, task.id)),
|
|
@@ -1330,8 +1394,8 @@ function TaskCompact({ tasks }) {
|
|
|
1330
1394
|
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1331
1395
|
function ListUI({ filter, format }) {
|
|
1332
1396
|
const { exit } = useApp5();
|
|
1333
|
-
const [tasks, setTasks] =
|
|
1334
|
-
|
|
1397
|
+
const [tasks, setTasks] = useState8([]);
|
|
1398
|
+
useEffect8(() => {
|
|
1335
1399
|
const results = filterTasks(filter);
|
|
1336
1400
|
results.sort((a, b) => {
|
|
1337
1401
|
const pOrder = { high: 0, medium: 1, low: 2 };
|
|
@@ -1394,78 +1458,204 @@ function registerList(program2) {
|
|
|
1394
1458
|
return;
|
|
1395
1459
|
}
|
|
1396
1460
|
const { render } = await import("ink");
|
|
1397
|
-
render(
|
|
1461
|
+
render(React10.createElement(ListUI, { filter, format }));
|
|
1398
1462
|
});
|
|
1399
1463
|
}
|
|
1400
1464
|
|
|
1401
1465
|
// src/commands/done.tsx
|
|
1402
|
-
import
|
|
1466
|
+
import React11, { useEffect as useEffect9, useState as useState9 } from "react";
|
|
1403
1467
|
import { Box as Box11, Text as Text11, useApp as useApp6 } from "ink";
|
|
1404
|
-
import {
|
|
1468
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1405
1469
|
function DoneUI({ id, note }) {
|
|
1406
1470
|
const { exit } = useApp6();
|
|
1407
|
-
const [status, setStatus] =
|
|
1408
|
-
const [
|
|
1409
|
-
const [
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1471
|
+
const [status, setStatus] = useState9("working");
|
|
1472
|
+
const [syncStatus, setSyncStatus] = useState9("idle");
|
|
1473
|
+
const [syncMessage, setSyncMessage] = useState9("");
|
|
1474
|
+
const [message, setMessage] = useState9("");
|
|
1475
|
+
const [description, setDescription] = useState9("");
|
|
1476
|
+
useEffect9(() => {
|
|
1477
|
+
async function completeTaskAndSync() {
|
|
1478
|
+
try {
|
|
1479
|
+
const auth = requireAuth();
|
|
1480
|
+
const task = getTask(id);
|
|
1481
|
+
if (!task) {
|
|
1482
|
+
setMessage(`No task found with ID starting with "${id}"`);
|
|
1483
|
+
setStatus("error");
|
|
1484
|
+
setTimeout(() => exit(new Error("Task not found")), 1200);
|
|
1485
|
+
return;
|
|
1486
|
+
}
|
|
1487
|
+
if (task.status === "completed") {
|
|
1488
|
+
setMessage(`Task is already marked as completed.`);
|
|
1489
|
+
setStatus("error");
|
|
1490
|
+
setTimeout(() => exit(), 1200);
|
|
1491
|
+
return;
|
|
1492
|
+
}
|
|
1493
|
+
const updated = updateTask(task.id, {
|
|
1494
|
+
status: "completed",
|
|
1495
|
+
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1496
|
+
completion_note: note
|
|
1497
|
+
});
|
|
1498
|
+
if (updated) {
|
|
1499
|
+
setDescription(task.description);
|
|
1500
|
+
setMessage(`Task marked complete!`);
|
|
1501
|
+
setStatus("success");
|
|
1502
|
+
setSyncStatus("syncing");
|
|
1503
|
+
const tasks = getAllTasks();
|
|
1504
|
+
const bundle = {
|
|
1505
|
+
tasks,
|
|
1506
|
+
schema_version: "1",
|
|
1507
|
+
exported_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1508
|
+
};
|
|
1509
|
+
const plaintext = JSON.stringify(bundle);
|
|
1510
|
+
const blobChecksum = checksum(plaintext);
|
|
1511
|
+
const syncPassword = auth.password;
|
|
1512
|
+
if (!syncPassword) {
|
|
1513
|
+
setSyncStatus("failed");
|
|
1514
|
+
setSyncMessage('Encryption password required. Run "taskair sync --password <pwd>".');
|
|
1515
|
+
setTimeout(() => exit(), 3e3);
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
const blob = encrypt(plaintext, syncPassword);
|
|
1519
|
+
const res = await apiUploadSync(
|
|
1520
|
+
auth.apiUrl,
|
|
1521
|
+
auth.accessToken,
|
|
1522
|
+
blob,
|
|
1523
|
+
blobChecksum,
|
|
1524
|
+
auth.deviceId
|
|
1525
|
+
);
|
|
1526
|
+
if (res.success) {
|
|
1527
|
+
clearSyncQueue();
|
|
1528
|
+
setSyncStatus("synced");
|
|
1529
|
+
setTimeout(() => exit(), 2e3);
|
|
1530
|
+
} else if (res.error?.code === "NETWORK_ERROR") {
|
|
1531
|
+
setSyncStatus("offline");
|
|
1532
|
+
setTimeout(() => exit(), 2500);
|
|
1533
|
+
} else {
|
|
1534
|
+
setSyncStatus("failed");
|
|
1535
|
+
setSyncMessage(res.error?.message ?? "Sync failed");
|
|
1536
|
+
setTimeout(() => exit(), 3500);
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
} catch (e) {
|
|
1540
|
+
setMessage(e.message);
|
|
1541
|
+
setStatus("error");
|
|
1542
|
+
setTimeout(() => exit(e), 2e3);
|
|
1543
|
+
}
|
|
1434
1544
|
}
|
|
1545
|
+
completeTaskAndSync();
|
|
1435
1546
|
}, []);
|
|
1436
1547
|
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", padding: 1, children: [
|
|
1437
1548
|
/* @__PURE__ */ jsx11(MiniHeader, {}),
|
|
1438
|
-
/* @__PURE__ */ jsx11(
|
|
1549
|
+
status === "working" && /* @__PURE__ */ jsx11(Spinner, { label: "Updating task\u2026", type: "star", color: "green" }),
|
|
1550
|
+
status === "success" && /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
1439
1551
|
/* @__PURE__ */ jsx11(StarBurst, { label: message, color: "green" }),
|
|
1440
|
-
|
|
1441
|
-
/* @__PURE__ */
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1552
|
+
/* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", children: [
|
|
1553
|
+
description && /* @__PURE__ */ jsxs11(Box11, { children: [
|
|
1554
|
+
/* @__PURE__ */ jsx11(Text11, { color: "gray", children: " Task: " }),
|
|
1555
|
+
/* @__PURE__ */ jsx11(Text11, { color: "white", children: description })
|
|
1556
|
+
] }),
|
|
1557
|
+
note && /* @__PURE__ */ jsxs11(Box11, { children: [
|
|
1558
|
+
/* @__PURE__ */ jsx11(Text11, { color: "gray", children: " Note: " }),
|
|
1559
|
+
/* @__PURE__ */ jsx11(Text11, { color: "cyan", children: note })
|
|
1560
|
+
] }),
|
|
1561
|
+
/* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
|
|
1562
|
+
/* @__PURE__ */ jsx11(Text11, { color: "gray", children: " Sync: " }),
|
|
1563
|
+
syncStatus === "syncing" && /* @__PURE__ */ jsx11(Text11, { color: "magenta", children: "Syncing to cloud (E2E encrypted)..." }),
|
|
1564
|
+
syncStatus === "synced" && /* @__PURE__ */ jsx11(Text11, { color: "green", children: "\u2713 Synced to cloud" }),
|
|
1565
|
+
syncStatus === "offline" && /* @__PURE__ */ jsx11(Text11, { color: "yellow", children: "\u2601 Offline (queued locally)" }),
|
|
1566
|
+
syncStatus === "failed" && /* @__PURE__ */ jsxs11(Text11, { color: "red", children: [
|
|
1567
|
+
"\u2717 ",
|
|
1568
|
+
syncMessage
|
|
1569
|
+
] })
|
|
1570
|
+
] })
|
|
1448
1571
|
] })
|
|
1449
|
-
] })
|
|
1572
|
+
] }),
|
|
1573
|
+
status === "error" && /* @__PURE__ */ jsx11(StatusBadge, { type: "error", message })
|
|
1450
1574
|
] });
|
|
1451
1575
|
}
|
|
1452
1576
|
function registerDone(program2) {
|
|
1453
1577
|
program2.command("done <id>").alias("-d").description("Mark a task as complete").option("-n, --note <note>", "Completion note").action(async (id, options) => {
|
|
1454
1578
|
const { render } = await import("ink");
|
|
1455
|
-
render(
|
|
1579
|
+
render(React11.createElement(DoneUI, { id, note: options.note }));
|
|
1456
1580
|
});
|
|
1457
1581
|
}
|
|
1458
1582
|
|
|
1459
1583
|
// src/commands/remove.tsx
|
|
1460
|
-
import
|
|
1584
|
+
import React12, { useEffect as useEffect10, useState as useState10 } from "react";
|
|
1461
1585
|
import { Box as Box12, Text as Text12, useApp as useApp7, useInput as useInput3 } from "ink";
|
|
1462
1586
|
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1463
1587
|
function RemoveUI({ id, force }) {
|
|
1464
1588
|
const { exit } = useApp7();
|
|
1465
|
-
const [stage, setStage] =
|
|
1466
|
-
const [
|
|
1589
|
+
const [stage, setStage] = useState10("confirm");
|
|
1590
|
+
const [syncStatus, setSyncStatus] = useState10("idle");
|
|
1591
|
+
const [syncMessage, setSyncMessage] = useState10("");
|
|
1592
|
+
const [message, setMessage] = useState10("");
|
|
1467
1593
|
const task = getTask(id);
|
|
1468
|
-
|
|
1594
|
+
const performDeleteAndSync = async () => {
|
|
1595
|
+
try {
|
|
1596
|
+
const auth = requireAuth();
|
|
1597
|
+
setStage("deleting");
|
|
1598
|
+
const deleted = deleteTask(task.id);
|
|
1599
|
+
if (deleted) {
|
|
1600
|
+
setMessage(`Task removed: ${task.description}`);
|
|
1601
|
+
setSyncStatus("syncing");
|
|
1602
|
+
const tasks = getAllTasks();
|
|
1603
|
+
const bundle = {
|
|
1604
|
+
tasks,
|
|
1605
|
+
schema_version: "1",
|
|
1606
|
+
exported_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1607
|
+
};
|
|
1608
|
+
const plaintext = JSON.stringify(bundle);
|
|
1609
|
+
const blobChecksum = checksum(plaintext);
|
|
1610
|
+
const syncPassword = auth.password;
|
|
1611
|
+
if (!syncPassword) {
|
|
1612
|
+
setSyncStatus("failed");
|
|
1613
|
+
setSyncMessage('Encryption password required. Run "taskair sync --password <pwd>".');
|
|
1614
|
+
setStage("success");
|
|
1615
|
+
setTimeout(() => exit(), 3e3);
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
const blob = encrypt(plaintext, syncPassword);
|
|
1619
|
+
const res = await apiUploadSync(
|
|
1620
|
+
auth.apiUrl,
|
|
1621
|
+
auth.accessToken,
|
|
1622
|
+
blob,
|
|
1623
|
+
blobChecksum,
|
|
1624
|
+
auth.deviceId
|
|
1625
|
+
);
|
|
1626
|
+
setStage("success");
|
|
1627
|
+
if (res.success) {
|
|
1628
|
+
clearSyncQueue();
|
|
1629
|
+
setSyncStatus("synced");
|
|
1630
|
+
setTimeout(() => exit(), 2e3);
|
|
1631
|
+
} else if (res.error?.code === "NETWORK_ERROR") {
|
|
1632
|
+
setSyncStatus("offline");
|
|
1633
|
+
setTimeout(() => exit(), 2500);
|
|
1634
|
+
} else {
|
|
1635
|
+
setSyncStatus("failed");
|
|
1636
|
+
setSyncMessage(res.error?.message ?? "Sync failed");
|
|
1637
|
+
setTimeout(() => exit(), 3500);
|
|
1638
|
+
}
|
|
1639
|
+
} else {
|
|
1640
|
+
setMessage("Failed to delete task.");
|
|
1641
|
+
setStage("error");
|
|
1642
|
+
setTimeout(() => exit(new Error("Delete failed")), 1200);
|
|
1643
|
+
}
|
|
1644
|
+
} catch (e) {
|
|
1645
|
+
setMessage(e.message);
|
|
1646
|
+
setStage("error");
|
|
1647
|
+
setTimeout(() => exit(e), 2e3);
|
|
1648
|
+
}
|
|
1649
|
+
};
|
|
1650
|
+
useEffect10(() => {
|
|
1651
|
+
try {
|
|
1652
|
+
requireAuth();
|
|
1653
|
+
} catch (e) {
|
|
1654
|
+
setMessage(e.message);
|
|
1655
|
+
setStage("error");
|
|
1656
|
+
setTimeout(() => exit(e), 2e3);
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1469
1659
|
if (!task) {
|
|
1470
1660
|
setMessage(`No task found with ID starting with "${id}"`);
|
|
1471
1661
|
setStage("error");
|
|
@@ -1473,23 +1663,13 @@ function RemoveUI({ id, force }) {
|
|
|
1473
1663
|
return;
|
|
1474
1664
|
}
|
|
1475
1665
|
if (force) {
|
|
1476
|
-
|
|
1477
|
-
if (deleted) {
|
|
1478
|
-
setMessage(`Task removed: ${task.description}`);
|
|
1479
|
-
setStage("success");
|
|
1480
|
-
setTimeout(() => exit(), 1200);
|
|
1481
|
-
}
|
|
1666
|
+
performDeleteAndSync();
|
|
1482
1667
|
}
|
|
1483
1668
|
}, []);
|
|
1484
1669
|
useInput3((input) => {
|
|
1485
1670
|
if (stage !== "confirm" || !task) return;
|
|
1486
1671
|
if (input.toLowerCase() === "y") {
|
|
1487
|
-
|
|
1488
|
-
if (deleted) {
|
|
1489
|
-
setMessage(`Task removed: ${task.description}`);
|
|
1490
|
-
setStage("success");
|
|
1491
|
-
setTimeout(() => exit(), 1200);
|
|
1492
|
-
}
|
|
1672
|
+
performDeleteAndSync();
|
|
1493
1673
|
} else if (input.toLowerCase() === "n" || input === "") {
|
|
1494
1674
|
setStage("cancelled");
|
|
1495
1675
|
setTimeout(() => exit(), 800);
|
|
@@ -1525,7 +1705,20 @@ function RemoveUI({ id, force }) {
|
|
|
1525
1705
|
/* @__PURE__ */ jsx12(Text12, { color: "gray", children: " to cancel: " })
|
|
1526
1706
|
] })
|
|
1527
1707
|
] }),
|
|
1528
|
-
stage === "
|
|
1708
|
+
stage === "deleting" && /* @__PURE__ */ jsx12(Spinner, { label: "Removing task\u2026", type: "star", color: "cyan" }),
|
|
1709
|
+
stage === "success" && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
1710
|
+
/* @__PURE__ */ jsx12(StarBurst, { label: message, color: "cyan" }),
|
|
1711
|
+
/* @__PURE__ */ jsx12(Box12, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsxs12(Box12, { children: [
|
|
1712
|
+
/* @__PURE__ */ jsx12(Text12, { color: "gray", children: " Sync: " }),
|
|
1713
|
+
syncStatus === "syncing" && /* @__PURE__ */ jsx12(Text12, { color: "magenta", children: "Syncing to cloud (E2E encrypted)..." }),
|
|
1714
|
+
syncStatus === "synced" && /* @__PURE__ */ jsx12(Text12, { color: "green", children: "\u2713 Synced to cloud" }),
|
|
1715
|
+
syncStatus === "offline" && /* @__PURE__ */ jsx12(Text12, { color: "yellow", children: "\u2601 Offline (queued locally)" }),
|
|
1716
|
+
syncStatus === "failed" && /* @__PURE__ */ jsxs12(Text12, { color: "red", children: [
|
|
1717
|
+
"\u2717 ",
|
|
1718
|
+
syncMessage
|
|
1719
|
+
] })
|
|
1720
|
+
] }) })
|
|
1721
|
+
] }),
|
|
1529
1722
|
stage === "error" && /* @__PURE__ */ jsx12(StatusBadge, { type: "error", message }),
|
|
1530
1723
|
stage === "cancelled" && /* @__PURE__ */ jsx12(StatusBadge, { type: "info", message: "Deletion cancelled." })
|
|
1531
1724
|
] });
|
|
@@ -1533,92 +1726,153 @@ function RemoveUI({ id, force }) {
|
|
|
1533
1726
|
function registerRemove(program2) {
|
|
1534
1727
|
program2.command("remove <id>").alias("-r").description("Delete a task").option("--force", "Skip confirmation prompt", false).action(async (id, options) => {
|
|
1535
1728
|
const { render } = await import("ink");
|
|
1536
|
-
render(
|
|
1729
|
+
render(React12.createElement(RemoveUI, { id, force: options.force }));
|
|
1537
1730
|
});
|
|
1538
1731
|
}
|
|
1539
1732
|
|
|
1540
1733
|
// src/commands/edit.tsx
|
|
1541
|
-
import
|
|
1734
|
+
import React13, { useState as useState11, useEffect as useEffect11 } from "react";
|
|
1542
1735
|
import { Box as Box13, Text as Text13, useApp as useApp8 } from "ink";
|
|
1543
|
-
import {
|
|
1736
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1544
1737
|
function EditUI({ id, updates }) {
|
|
1545
1738
|
const { exit } = useApp8();
|
|
1546
|
-
const [status, setStatus] =
|
|
1547
|
-
const [
|
|
1548
|
-
const [
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1739
|
+
const [status, setStatus] = useState11("working");
|
|
1740
|
+
const [syncStatus, setSyncStatus] = useState11("idle");
|
|
1741
|
+
const [syncMessage, setSyncMessage] = useState11("");
|
|
1742
|
+
const [message, setMessage] = useState11("");
|
|
1743
|
+
const [changes, setChanges] = useState11([]);
|
|
1744
|
+
useEffect11(() => {
|
|
1745
|
+
async function editTaskAndSync() {
|
|
1746
|
+
try {
|
|
1747
|
+
const auth = requireAuth();
|
|
1748
|
+
const task = getTask(id);
|
|
1749
|
+
if (!task) {
|
|
1750
|
+
setMessage(`No task found with ID starting with "${id}"`);
|
|
1751
|
+
setStatus("error");
|
|
1752
|
+
setTimeout(() => exit(new Error("Task not found")), 1200);
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
const taskUpdates = {};
|
|
1756
|
+
const changesLog = [];
|
|
1757
|
+
if (updates.description) {
|
|
1758
|
+
taskUpdates.description = updates.description;
|
|
1759
|
+
changesLog.push(`description \u2192 "${updates.description}"`);
|
|
1760
|
+
}
|
|
1761
|
+
if (updates.priority) {
|
|
1762
|
+
taskUpdates.priority = updates.priority;
|
|
1763
|
+
changesLog.push(`priority \u2192 ${updates.priority}`);
|
|
1764
|
+
}
|
|
1765
|
+
if (updates.status) {
|
|
1766
|
+
taskUpdates.status = updates.status;
|
|
1767
|
+
if (updates.status === "completed") {
|
|
1768
|
+
taskUpdates.completed_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1769
|
+
}
|
|
1770
|
+
changesLog.push(`status \u2192 ${updates.status}`);
|
|
1771
|
+
}
|
|
1772
|
+
if (updates.due) {
|
|
1773
|
+
taskUpdates.due_date = updates.due;
|
|
1774
|
+
changesLog.push(`due date \u2192 ${updates.due}`);
|
|
1775
|
+
}
|
|
1776
|
+
if (updates.tags) {
|
|
1777
|
+
taskUpdates.tags = updates.tags.split(",").map((t) => t.trim());
|
|
1778
|
+
changesLog.push(`tags \u2192 [${taskUpdates.tags.join(", ")}]`);
|
|
1779
|
+
}
|
|
1780
|
+
if (updates.note) {
|
|
1781
|
+
taskUpdates.completion_note = updates.note;
|
|
1782
|
+
changesLog.push(`note \u2192 "${updates.note}"`);
|
|
1783
|
+
}
|
|
1784
|
+
if (changesLog.length === 0) {
|
|
1785
|
+
setMessage("No changes specified. Use options like --description, --priority, etc.");
|
|
1786
|
+
setStatus("error");
|
|
1787
|
+
setTimeout(() => exit(), 1200);
|
|
1788
|
+
return;
|
|
1789
|
+
}
|
|
1790
|
+
const updated = updateTask(task.id, taskUpdates);
|
|
1791
|
+
if (updated) {
|
|
1792
|
+
setChanges(changesLog);
|
|
1793
|
+
setMessage(`Task ${task.id.slice(0, 8)} updated!`);
|
|
1794
|
+
setStatus("success");
|
|
1795
|
+
setSyncStatus("syncing");
|
|
1796
|
+
const tasks = getAllTasks();
|
|
1797
|
+
const bundle = {
|
|
1798
|
+
tasks,
|
|
1799
|
+
schema_version: "1",
|
|
1800
|
+
exported_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1801
|
+
};
|
|
1802
|
+
const plaintext = JSON.stringify(bundle);
|
|
1803
|
+
const blobChecksum = checksum(plaintext);
|
|
1804
|
+
const syncPassword = auth.password;
|
|
1805
|
+
if (!syncPassword) {
|
|
1806
|
+
setSyncStatus("failed");
|
|
1807
|
+
setSyncMessage('Encryption password required. Run "taskair sync --password <pwd>".');
|
|
1808
|
+
setTimeout(() => exit(), 3e3);
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
const blob = encrypt(plaintext, syncPassword);
|
|
1812
|
+
const res = await apiUploadSync(
|
|
1813
|
+
auth.apiUrl,
|
|
1814
|
+
auth.accessToken,
|
|
1815
|
+
blob,
|
|
1816
|
+
blobChecksum,
|
|
1817
|
+
auth.deviceId
|
|
1818
|
+
);
|
|
1819
|
+
if (res.success) {
|
|
1820
|
+
clearSyncQueue();
|
|
1821
|
+
setSyncStatus("synced");
|
|
1822
|
+
setTimeout(() => exit(), 2e3);
|
|
1823
|
+
} else if (res.error?.code === "NETWORK_ERROR") {
|
|
1824
|
+
setSyncStatus("offline");
|
|
1825
|
+
setTimeout(() => exit(), 2500);
|
|
1826
|
+
} else {
|
|
1827
|
+
setSyncStatus("failed");
|
|
1828
|
+
setSyncMessage(res.error?.message ?? "Sync failed");
|
|
1829
|
+
setTimeout(() => exit(), 3500);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
} catch (e) {
|
|
1833
|
+
setMessage(e.message);
|
|
1834
|
+
setStatus("error");
|
|
1835
|
+
setTimeout(() => exit(e), 2e3);
|
|
1571
1836
|
}
|
|
1572
|
-
changesLog.push(`status \u2192 ${updates.status}`);
|
|
1573
|
-
}
|
|
1574
|
-
if (updates.due) {
|
|
1575
|
-
taskUpdates.due_date = updates.due;
|
|
1576
|
-
changesLog.push(`due date \u2192 ${updates.due}`);
|
|
1577
|
-
}
|
|
1578
|
-
if (updates.tags) {
|
|
1579
|
-
taskUpdates.tags = updates.tags.split(",").map((t) => t.trim());
|
|
1580
|
-
changesLog.push(`tags \u2192 [${taskUpdates.tags.join(", ")}]`);
|
|
1581
|
-
}
|
|
1582
|
-
if (updates.note) {
|
|
1583
|
-
taskUpdates.completion_note = updates.note;
|
|
1584
|
-
changesLog.push(`note \u2192 "${updates.note}"`);
|
|
1585
|
-
}
|
|
1586
|
-
if (changesLog.length === 0) {
|
|
1587
|
-
setMessage("No changes specified. Use options like --description, --priority, etc.");
|
|
1588
|
-
setStatus("error");
|
|
1589
|
-
setTimeout(() => exit(), 1200);
|
|
1590
|
-
return;
|
|
1591
|
-
}
|
|
1592
|
-
const updated = updateTask(task.id, taskUpdates);
|
|
1593
|
-
if (updated) {
|
|
1594
|
-
setChanges(changesLog);
|
|
1595
|
-
setMessage(`Task ${task.id.slice(0, 8)} updated!`);
|
|
1596
|
-
setStatus("success");
|
|
1597
|
-
setTimeout(() => exit(), 1500);
|
|
1598
1837
|
}
|
|
1838
|
+
editTaskAndSync();
|
|
1599
1839
|
}, []);
|
|
1600
1840
|
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
|
|
1601
1841
|
/* @__PURE__ */ jsx13(MiniHeader, {}),
|
|
1602
|
-
/* @__PURE__ */ jsx13(
|
|
1842
|
+
status === "working" && /* @__PURE__ */ jsx13(Spinner, { label: "Updating task\u2026", type: "star", color: "magenta" }),
|
|
1843
|
+
status === "success" && /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
|
|
1603
1844
|
/* @__PURE__ */ jsx13(StarBurst, { label: message, color: "magenta" }),
|
|
1604
|
-
|
|
1605
|
-
/* @__PURE__ */
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1845
|
+
/* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
|
|
1846
|
+
changes.map((c) => /* @__PURE__ */ jsxs13(Box13, { marginTop: 0, children: [
|
|
1847
|
+
/* @__PURE__ */ jsx13(Text13, { color: "gray", children: " \u21B3 " }),
|
|
1848
|
+
/* @__PURE__ */ jsx13(Text13, { color: "white", children: c })
|
|
1849
|
+
] }, c)),
|
|
1850
|
+
/* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
|
|
1851
|
+
/* @__PURE__ */ jsx13(Text13, { color: "gray", children: " Sync: " }),
|
|
1852
|
+
syncStatus === "syncing" && /* @__PURE__ */ jsx13(Text13, { color: "magenta", children: "Syncing to cloud (E2E encrypted)..." }),
|
|
1853
|
+
syncStatus === "synced" && /* @__PURE__ */ jsx13(Text13, { color: "green", children: "\u2713 Synced to cloud" }),
|
|
1854
|
+
syncStatus === "offline" && /* @__PURE__ */ jsx13(Text13, { color: "yellow", children: "\u2601 Offline (queued locally)" }),
|
|
1855
|
+
syncStatus === "failed" && /* @__PURE__ */ jsxs13(Text13, { color: "red", children: [
|
|
1856
|
+
"\u2717 ",
|
|
1857
|
+
syncMessage
|
|
1858
|
+
] })
|
|
1859
|
+
] })
|
|
1860
|
+
] })
|
|
1861
|
+
] }),
|
|
1862
|
+
status === "error" && /* @__PURE__ */ jsx13(StatusBadge, { type: "error", message })
|
|
1609
1863
|
] });
|
|
1610
1864
|
}
|
|
1611
1865
|
function registerEdit(program2) {
|
|
1612
1866
|
program2.command("edit <id>").alias("-e").description("Update one or more fields of a task").option("--description <text>", "New description").option("--priority <level>", "New priority: high | medium | low").option("--status <status>", "New status: pending | in_progress | completed").option("--due <datetime>", "New due date").option("--tags <tags>", "New comma-separated tags").option("--note <note>", "Add a completion note").action(async (id, options) => {
|
|
1613
1867
|
const { render } = await import("ink");
|
|
1614
|
-
render(
|
|
1868
|
+
render(React13.createElement(EditUI, { id, updates: options }));
|
|
1615
1869
|
});
|
|
1616
1870
|
}
|
|
1617
1871
|
|
|
1618
1872
|
// src/commands/stats.tsx
|
|
1619
|
-
import
|
|
1873
|
+
import React14, { useEffect as useEffect12 } from "react";
|
|
1620
1874
|
import { Box as Box14, Text as Text14, useApp as useApp9 } from "ink";
|
|
1621
|
-
import { Fragment as
|
|
1875
|
+
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1622
1876
|
function ProgressBar({
|
|
1623
1877
|
value,
|
|
1624
1878
|
max,
|
|
@@ -1637,7 +1891,7 @@ function ProgressBar({
|
|
|
1637
1891
|
function StatsUI() {
|
|
1638
1892
|
const { exit } = useApp9();
|
|
1639
1893
|
const stats = computeStats();
|
|
1640
|
-
|
|
1894
|
+
useEffect12(() => {
|
|
1641
1895
|
setTimeout(() => exit(), 100);
|
|
1642
1896
|
}, []);
|
|
1643
1897
|
const rows = [
|
|
@@ -1673,7 +1927,7 @@ function StatsUI() {
|
|
|
1673
1927
|
row.label.padEnd(16)
|
|
1674
1928
|
] }),
|
|
1675
1929
|
/* @__PURE__ */ jsx14(Text14, { color: row.color, bold: true, children: String(row.value).padStart(4) }),
|
|
1676
|
-
stats.total > 0 && /* @__PURE__ */ jsxs14(
|
|
1930
|
+
stats.total > 0 && /* @__PURE__ */ jsxs14(Fragment2, { children: [
|
|
1677
1931
|
/* @__PURE__ */ jsx14(Text14, { color: "gray", children: " " }),
|
|
1678
1932
|
/* @__PURE__ */ jsx14(
|
|
1679
1933
|
ProgressBar,
|
|
@@ -1695,7 +1949,7 @@ function StatsUI() {
|
|
|
1695
1949
|
row.label.padEnd(20)
|
|
1696
1950
|
] }),
|
|
1697
1951
|
/* @__PURE__ */ jsx14(Text14, { color: row.color, bold: true, children: String(row.value).padStart(4) }),
|
|
1698
|
-
stats.total > 0 && /* @__PURE__ */ jsxs14(
|
|
1952
|
+
stats.total > 0 && /* @__PURE__ */ jsxs14(Fragment2, { children: [
|
|
1699
1953
|
/* @__PURE__ */ jsx14(Text14, { color: "gray", children: " " }),
|
|
1700
1954
|
/* @__PURE__ */ jsx14(
|
|
1701
1955
|
ProgressBar,
|
|
@@ -1728,20 +1982,20 @@ function StatsUI() {
|
|
|
1728
1982
|
function registerStats(program2) {
|
|
1729
1983
|
program2.command("stats").description("Show task analytics and completion stats").action(async () => {
|
|
1730
1984
|
const { render } = await import("ink");
|
|
1731
|
-
render(
|
|
1985
|
+
render(React14.createElement(StatsUI));
|
|
1732
1986
|
});
|
|
1733
1987
|
}
|
|
1734
1988
|
|
|
1735
1989
|
// src/commands/sync.tsx
|
|
1736
|
-
import
|
|
1990
|
+
import React15, { useState as useState12, useEffect as useEffect13 } from "react";
|
|
1737
1991
|
import { Box as Box15, Text as Text15, useApp as useApp10 } from "ink";
|
|
1738
|
-
import { Fragment as
|
|
1992
|
+
import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1739
1993
|
function SyncUI({ dryRun, password }) {
|
|
1740
1994
|
const { exit } = useApp10();
|
|
1741
|
-
const [status, setStatus] =
|
|
1742
|
-
const [message, setMessage] =
|
|
1743
|
-
const [details, setDetails] =
|
|
1744
|
-
|
|
1995
|
+
const [status, setStatus] = useState12("loading");
|
|
1996
|
+
const [message, setMessage] = useState12("");
|
|
1997
|
+
const [details, setDetails] = useState12([]);
|
|
1998
|
+
useEffect13(() => {
|
|
1745
1999
|
async function doSync() {
|
|
1746
2000
|
try {
|
|
1747
2001
|
const auth = requireAuth();
|
|
@@ -1816,7 +2070,7 @@ function SyncUI({ dryRun, password }) {
|
|
|
1816
2070
|
/* @__PURE__ */ jsx15(MiniHeader, {}),
|
|
1817
2071
|
/* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "column", children: [
|
|
1818
2072
|
status === "loading" && /* @__PURE__ */ jsx15(Spinner, { label: "Syncing to cloud (E2E encrypted)\u2026", type: "orbit", color: "magenta" }),
|
|
1819
|
-
status === "success" && /* @__PURE__ */ jsxs15(
|
|
2073
|
+
status === "success" && /* @__PURE__ */ jsxs15(Fragment3, { children: [
|
|
1820
2074
|
/* @__PURE__ */ jsx15(StarBurst, { label: message, color: "cyan" }),
|
|
1821
2075
|
details.map((d) => /* @__PURE__ */ jsxs15(Box15, { children: [
|
|
1822
2076
|
/* @__PURE__ */ jsx15(Text15, { color: "gray", children: " \xB7 " }),
|
|
@@ -1844,7 +2098,7 @@ function SyncUI({ dryRun, password }) {
|
|
|
1844
2098
|
function registerSync(program2) {
|
|
1845
2099
|
program2.command("sync").description("Sync tasks with cloud (E2E encrypted)").option("--dry-run", "Preview what would be synced without making changes", false).option("--password <password>", "Master password for encryption").action(async (options) => {
|
|
1846
2100
|
const { render } = await import("ink");
|
|
1847
|
-
render(
|
|
2101
|
+
render(React15.createElement(SyncUI, { dryRun: options.dryRun, password: options.password }));
|
|
1848
2102
|
});
|
|
1849
2103
|
}
|
|
1850
2104
|
|
|
@@ -1910,12 +2164,12 @@ function registerExport(program2) {
|
|
|
1910
2164
|
}
|
|
1911
2165
|
|
|
1912
2166
|
// src/commands/upgrade.tsx
|
|
1913
|
-
import
|
|
2167
|
+
import React16, { useState as useState13, useEffect as useEffect14 } from "react";
|
|
1914
2168
|
import { Box as Box16, Text as Text16, useApp as useApp11 } from "ink";
|
|
1915
2169
|
import { exec as exec2 } from "child_process";
|
|
1916
2170
|
|
|
1917
2171
|
// src/lib/version.ts
|
|
1918
|
-
var CLI_VERSION = "1.0.
|
|
2172
|
+
var CLI_VERSION = "1.0.7";
|
|
1919
2173
|
|
|
1920
2174
|
// src/commands/upgrade.tsx
|
|
1921
2175
|
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
@@ -1935,7 +2189,7 @@ function UpgradeUI({ target }) {
|
|
|
1935
2189
|
const { exit } = useApp11();
|
|
1936
2190
|
const shouldUpgradeCli = !target || target.toLowerCase() === "cli";
|
|
1937
2191
|
const shouldUpgradeMcp = !target || target.toLowerCase() === "mcp";
|
|
1938
|
-
const [cliState, setCliState] =
|
|
2192
|
+
const [cliState, setCliState] = useState13({
|
|
1939
2193
|
name: "TaskAir CLI",
|
|
1940
2194
|
pkgName: "taskair-cli",
|
|
1941
2195
|
current: CLI_VERSION,
|
|
@@ -1943,7 +2197,7 @@ function UpgradeUI({ target }) {
|
|
|
1943
2197
|
status: shouldUpgradeCli ? "checking" : "up-to-date",
|
|
1944
2198
|
errorMsg: ""
|
|
1945
2199
|
});
|
|
1946
|
-
const [mcpState, setMcpState] =
|
|
2200
|
+
const [mcpState, setMcpState] = useState13({
|
|
1947
2201
|
name: "TaskAir MCP Server",
|
|
1948
2202
|
pkgName: "taskair-mcp",
|
|
1949
2203
|
current: "",
|
|
@@ -1951,7 +2205,7 @@ function UpgradeUI({ target }) {
|
|
|
1951
2205
|
status: shouldUpgradeMcp ? "checking" : "up-to-date",
|
|
1952
2206
|
errorMsg: ""
|
|
1953
2207
|
});
|
|
1954
|
-
|
|
2208
|
+
useEffect14(() => {
|
|
1955
2209
|
async function checkAndUpgrade() {
|
|
1956
2210
|
const tasks = [];
|
|
1957
2211
|
let mcpCurrent = "";
|
|
@@ -2146,13 +2400,13 @@ function UpgradeUI({ target }) {
|
|
|
2146
2400
|
function registerUpgrade(program2) {
|
|
2147
2401
|
program2.command("upgrade [target]").description('Upgrade TaskAir CLI and MCP Server. Target can be "cli", "mcp", or omitted to upgrade both.').action(async (target) => {
|
|
2148
2402
|
const { render } = await import("ink");
|
|
2149
|
-
render(
|
|
2403
|
+
render(React16.createElement(UpgradeUI, { target }));
|
|
2150
2404
|
});
|
|
2151
2405
|
}
|
|
2152
2406
|
|
|
2153
2407
|
// src/index.ts
|
|
2154
2408
|
program.name("taskair").description(
|
|
2155
|
-
"\u2726
|
|
2409
|
+
"\u2726 Privacy-first task management with E2E encryption \xB7 AI-native \xB7 CLI \xB7 MCP \xB7 Web"
|
|
2156
2410
|
).version(CLI_VERSION, "-v, --version", "Output the current version").helpOption("-h, --help", "Display help information");
|
|
2157
2411
|
registerConfig(program);
|
|
2158
2412
|
registerLogin(program);
|
|
@@ -2170,10 +2424,14 @@ registerExport(program);
|
|
|
2170
2424
|
program.addHelpText(
|
|
2171
2425
|
"beforeAll",
|
|
2172
2426
|
`
|
|
2173
|
-
\
|
|
2174
|
-
\u2551
|
|
2175
|
-
\u2551
|
|
2176
|
-
\
|
|
2427
|
+
\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
2428
|
+
\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
|
|
2429
|
+
\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
|
|
2430
|
+
\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
|
|
2431
|
+
\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551
|
|
2432
|
+
\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
|
|
2433
|
+
|
|
2434
|
+
\u2726 CLI \xB7 MCP \xB7 Web \u2726
|
|
2177
2435
|
`
|
|
2178
2436
|
);
|
|
2179
2437
|
var args = [...process.argv];
|