@qodalis/cli-todo 2.0.0-beta.2 → 2.0.0-beta.20
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/package.json +2 -2
- package/public-api.d.mts +11 -6
- package/public-api.d.ts +11 -6
- package/public-api.js +117 -62
- package/public-api.js.map +1 -1
- package/public-api.mjs +118 -63
- package/public-api.mjs.map +1 -1
- package/umd/index.global.js +369 -141
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qodalis/cli-todo",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.20",
|
|
4
4
|
"description": "@qodalis/cli extension for managing TODO tasks with add, list, complete, and remove commands.",
|
|
5
5
|
"author": "Nicolae Lupei, Qodalis Solutions",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"umd": "./umd/index.global.js",
|
|
21
21
|
"unpkg": "./umd/index.global.js",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@qodalis/cli-core": "2.0.0-beta.
|
|
23
|
+
"@qodalis/cli-core": "2.0.0-beta.20"
|
|
24
24
|
},
|
|
25
25
|
"sideEffects": false,
|
|
26
26
|
"main": "./public-api.js",
|
package/public-api.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { ICliCommandProcessor, CliProcessorMetadata, CliStateConfiguration, CliProcessCommand, ICliExecutionContext, ICliCompletionProvider, ICliCompletionContext, ICliModule } from '@qodalis/cli-core';
|
|
1
|
+
import { ICliCommandProcessor, CliProcessorMetadata, ICliConfigurationOption, CliStateConfiguration, CliProcessCommand, ICliExecutionContext, ICliCompletionProvider, ICliCompletionContext, ICliModule } from '@qodalis/cli-core';
|
|
3
2
|
|
|
4
3
|
type TodoItem = {
|
|
5
4
|
id: number;
|
|
@@ -18,13 +17,13 @@ declare function lineThroughText(text: string): string;
|
|
|
18
17
|
declare class CliTodoCommandProcessor implements ICliCommandProcessor {
|
|
19
18
|
command: string;
|
|
20
19
|
description: string;
|
|
21
|
-
author:
|
|
20
|
+
author: any;
|
|
22
21
|
version: string;
|
|
23
22
|
processors?: ICliCommandProcessor[];
|
|
24
23
|
metadata?: CliProcessorMetadata;
|
|
24
|
+
configurationOptions?: ICliConfigurationOption[];
|
|
25
25
|
stateConfiguration?: CliStateConfiguration;
|
|
26
26
|
private todos;
|
|
27
|
-
private nextId;
|
|
28
27
|
getTodos(): TodoItem[];
|
|
29
28
|
constructor();
|
|
30
29
|
processCommand(command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
|
|
@@ -33,7 +32,12 @@ declare class CliTodoCommandProcessor implements ICliCommandProcessor {
|
|
|
33
32
|
private formatTodoLine;
|
|
34
33
|
private registerSubProcessors;
|
|
35
34
|
private loadFromOldStorage;
|
|
36
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Change the list and save it, atomically: `change` gets the latest saved
|
|
37
|
+
* list (another tab may have changed it) to edit in place, or returns a
|
|
38
|
+
* new one.
|
|
39
|
+
*/
|
|
40
|
+
private changeTodos;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
declare class CliTodoIdCompletionProvider implements ICliCompletionProvider {
|
|
@@ -45,4 +49,5 @@ declare class CliTodoIdCompletionProvider implements ICliCompletionProvider {
|
|
|
45
49
|
|
|
46
50
|
declare const todoModule: ICliModule;
|
|
47
51
|
|
|
48
|
-
export { CliTodoCommandProcessor, CliTodoIdCompletionProvider,
|
|
52
|
+
export { CliTodoCommandProcessor, CliTodoIdCompletionProvider, formatRelativeDate, isOverdue, lineThroughText, migrateTodoItem, parseDueDate, todoModule };
|
|
53
|
+
export type { TodoItem };
|
package/public-api.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { ICliCommandProcessor, CliProcessorMetadata, CliStateConfiguration, CliProcessCommand, ICliExecutionContext, ICliCompletionProvider, ICliCompletionContext, ICliModule } from '@qodalis/cli-core';
|
|
1
|
+
import { ICliCommandProcessor, CliProcessorMetadata, ICliConfigurationOption, CliStateConfiguration, CliProcessCommand, ICliExecutionContext, ICliCompletionProvider, ICliCompletionContext, ICliModule } from '@qodalis/cli-core';
|
|
3
2
|
|
|
4
3
|
type TodoItem = {
|
|
5
4
|
id: number;
|
|
@@ -18,13 +17,13 @@ declare function lineThroughText(text: string): string;
|
|
|
18
17
|
declare class CliTodoCommandProcessor implements ICliCommandProcessor {
|
|
19
18
|
command: string;
|
|
20
19
|
description: string;
|
|
21
|
-
author:
|
|
20
|
+
author: any;
|
|
22
21
|
version: string;
|
|
23
22
|
processors?: ICliCommandProcessor[];
|
|
24
23
|
metadata?: CliProcessorMetadata;
|
|
24
|
+
configurationOptions?: ICliConfigurationOption[];
|
|
25
25
|
stateConfiguration?: CliStateConfiguration;
|
|
26
26
|
private todos;
|
|
27
|
-
private nextId;
|
|
28
27
|
getTodos(): TodoItem[];
|
|
29
28
|
constructor();
|
|
30
29
|
processCommand(command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
|
|
@@ -33,7 +32,12 @@ declare class CliTodoCommandProcessor implements ICliCommandProcessor {
|
|
|
33
32
|
private formatTodoLine;
|
|
34
33
|
private registerSubProcessors;
|
|
35
34
|
private loadFromOldStorage;
|
|
36
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Change the list and save it, atomically: `change` gets the latest saved
|
|
37
|
+
* list (another tab may have changed it) to edit in place, or returns a
|
|
38
|
+
* new one.
|
|
39
|
+
*/
|
|
40
|
+
private changeTodos;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
declare class CliTodoIdCompletionProvider implements ICliCompletionProvider {
|
|
@@ -45,4 +49,5 @@ declare class CliTodoIdCompletionProvider implements ICliCompletionProvider {
|
|
|
45
49
|
|
|
46
50
|
declare const todoModule: ICliModule;
|
|
47
51
|
|
|
48
|
-
export { CliTodoCommandProcessor, CliTodoIdCompletionProvider,
|
|
52
|
+
export { CliTodoCommandProcessor, CliTodoIdCompletionProvider, formatRelativeDate, isOverdue, lineThroughText, migrateTodoItem, parseDueDate, todoModule };
|
|
53
|
+
export type { TodoItem };
|
package/public-api.js
CHANGED
|
@@ -89,7 +89,7 @@ function lineThroughText(text) {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
// src/lib/version.ts
|
|
92
|
-
var LIBRARY_VERSION = "2.0.0-beta.
|
|
92
|
+
var LIBRARY_VERSION = "2.0.0-beta.20";
|
|
93
93
|
var API_VERSION = 2;
|
|
94
94
|
|
|
95
95
|
// src/lib/processors/cli-todo-command-processor.ts
|
|
@@ -105,13 +105,28 @@ var CliTodoCommandProcessor = class {
|
|
|
105
105
|
requiredCoreVersion: ">=2.0.0 <3.0.0",
|
|
106
106
|
requiredCliVersion: ">=2.0.0 <3.0.0"
|
|
107
107
|
};
|
|
108
|
+
this.configurationOptions = [
|
|
109
|
+
{
|
|
110
|
+
key: "showCompletedFirst",
|
|
111
|
+
label: "Show Completed First",
|
|
112
|
+
description: "List completed tasks before pending ones",
|
|
113
|
+
type: "boolean",
|
|
114
|
+
defaultValue: false
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
key: "confirmBeforeDelete",
|
|
118
|
+
label: "Confirm Before Delete",
|
|
119
|
+
description: "Ask for confirmation before removing tasks",
|
|
120
|
+
type: "boolean",
|
|
121
|
+
defaultValue: false
|
|
122
|
+
}
|
|
123
|
+
];
|
|
108
124
|
this.stateConfiguration = {
|
|
109
125
|
initialState: {
|
|
110
126
|
todos: this.loadFromOldStorage() ?? []
|
|
111
127
|
}
|
|
112
128
|
};
|
|
113
129
|
this.todos = [];
|
|
114
|
-
this.nextId = 1;
|
|
115
130
|
this.registerSubProcessors();
|
|
116
131
|
}
|
|
117
132
|
getTodos() {
|
|
@@ -121,26 +136,26 @@ var CliTodoCommandProcessor = class {
|
|
|
121
136
|
context.executor.showHelp(command, context);
|
|
122
137
|
}
|
|
123
138
|
writeDescription(context) {
|
|
124
|
-
const { writer } = context;
|
|
125
|
-
writer.writeln(this.description);
|
|
139
|
+
const { writer, translator: t } = context;
|
|
140
|
+
writer.writeln(t.t("cli.todo.description", this.description));
|
|
126
141
|
writer.writeln();
|
|
127
|
-
writer.writeln(writer.wrapInColor("Commands:", cliCore.CliForegroundColor.Yellow));
|
|
128
|
-
writer.writeln(` ${writer.wrapInColor("todo ls", cliCore.CliForegroundColor.Cyan)} List all tasks`);
|
|
129
|
-
writer.writeln(` ${writer.wrapInColor("todo ls --pending", cliCore.CliForegroundColor.Cyan)} List pending tasks only`);
|
|
130
|
-
writer.writeln(` ${writer.wrapInColor("todo ls --completed", cliCore.CliForegroundColor.Cyan)} List completed tasks only`);
|
|
131
|
-
writer.writeln(` ${writer.wrapInColor("todo ls --overdue", cliCore.CliForegroundColor.Cyan)} List overdue tasks only`);
|
|
132
|
-
writer.writeln(` ${writer.wrapInColor("todo add <text>", cliCore.CliForegroundColor.Cyan)} Add a new task`);
|
|
133
|
-
writer.writeln(` ${writer.wrapInColor("todo add <text> --due <date>", cliCore.CliForegroundColor.Cyan)} Add with due date`);
|
|
134
|
-
writer.writeln(` ${writer.wrapInColor("todo edit <id> <new text>", cliCore.CliForegroundColor.Cyan)} Edit a task`);
|
|
135
|
-
writer.writeln(` ${writer.wrapInColor("todo done <id>", cliCore.CliForegroundColor.Cyan)} Mark a task as done`);
|
|
136
|
-
writer.writeln(` ${writer.wrapInColor("todo toggle <id>", cliCore.CliForegroundColor.Cyan)} Toggle done/undone`);
|
|
137
|
-
writer.writeln(` ${writer.wrapInColor("todo rm <id>", cliCore.CliForegroundColor.Cyan)} Remove a task`);
|
|
138
|
-
writer.writeln(` ${writer.wrapInColor("todo rm --all", cliCore.CliForegroundColor.Cyan)} Remove all tasks`);
|
|
142
|
+
writer.writeln(writer.wrapInColor(t.t("cli.todo.help.commands", "Commands:"), cliCore.CliForegroundColor.Yellow));
|
|
143
|
+
writer.writeln(` ${writer.wrapInColor("todo ls", cliCore.CliForegroundColor.Cyan)} ${t.t("cli.todo.help.list_all", "List all tasks")}`);
|
|
144
|
+
writer.writeln(` ${writer.wrapInColor("todo ls --pending", cliCore.CliForegroundColor.Cyan)} ${t.t("cli.todo.help.list_pending", "List pending tasks only")}`);
|
|
145
|
+
writer.writeln(` ${writer.wrapInColor("todo ls --completed", cliCore.CliForegroundColor.Cyan)} ${t.t("cli.todo.help.list_completed", "List completed tasks only")}`);
|
|
146
|
+
writer.writeln(` ${writer.wrapInColor("todo ls --overdue", cliCore.CliForegroundColor.Cyan)} ${t.t("cli.todo.help.list_overdue", "List overdue tasks only")}`);
|
|
147
|
+
writer.writeln(` ${writer.wrapInColor("todo add <text>", cliCore.CliForegroundColor.Cyan)} ${t.t("cli.todo.help.add", "Add a new task")}`);
|
|
148
|
+
writer.writeln(` ${writer.wrapInColor("todo add <text> --due <date>", cliCore.CliForegroundColor.Cyan)} ${t.t("cli.todo.help.add_due", "Add with due date")}`);
|
|
149
|
+
writer.writeln(` ${writer.wrapInColor("todo edit <id> <new text>", cliCore.CliForegroundColor.Cyan)} ${t.t("cli.todo.help.edit", "Edit a task")}`);
|
|
150
|
+
writer.writeln(` ${writer.wrapInColor("todo done <id>", cliCore.CliForegroundColor.Cyan)} ${t.t("cli.todo.help.done", "Mark a task as done")}`);
|
|
151
|
+
writer.writeln(` ${writer.wrapInColor("todo toggle <id>", cliCore.CliForegroundColor.Cyan)} ${t.t("cli.todo.help.toggle", "Toggle done/undone")}`);
|
|
152
|
+
writer.writeln(` ${writer.wrapInColor("todo rm <id>", cliCore.CliForegroundColor.Cyan)} ${t.t("cli.todo.help.remove", "Remove a task")}`);
|
|
153
|
+
writer.writeln(` ${writer.wrapInColor("todo rm --all", cliCore.CliForegroundColor.Cyan)} ${t.t("cli.todo.help.remove_all", "Remove all tasks")}`);
|
|
139
154
|
writer.writeln();
|
|
140
|
-
writer.writeln(writer.wrapInColor("Due date formats:", cliCore.CliForegroundColor.Yellow));
|
|
155
|
+
writer.writeln(writer.wrapInColor(t.t("cli.todo.help.due_formats", "Due date formats:"), cliCore.CliForegroundColor.Yellow));
|
|
141
156
|
writer.writeln(` today, tomorrow, monday..sunday, next week, next month, YYYY-MM-DD`);
|
|
142
157
|
writer.writeln();
|
|
143
|
-
writer.writeln(writer.wrapInColor("Examples:", cliCore.CliForegroundColor.Yellow));
|
|
158
|
+
writer.writeln(writer.wrapInColor(t.t("cli.common.examples", "Examples:"), cliCore.CliForegroundColor.Yellow));
|
|
144
159
|
writer.writeln(` todo add Buy groceries --due tomorrow`);
|
|
145
160
|
writer.writeln(` todo ls --pending`);
|
|
146
161
|
writer.writeln(` todo edit 3 Buy organic groceries`);
|
|
@@ -150,7 +165,6 @@ var CliTodoCommandProcessor = class {
|
|
|
150
165
|
async initialize(context) {
|
|
151
166
|
context.state.select((x) => x["todos"]).subscribe((todos) => {
|
|
152
167
|
this.todos = (todos || []).map(migrateTodoItem);
|
|
153
|
-
this.nextId = this.todos.length > 0 ? Math.max(...this.todos.map((t) => t.id)) + 1 : 1;
|
|
154
168
|
});
|
|
155
169
|
}
|
|
156
170
|
formatTodoLine(todo, writer) {
|
|
@@ -209,6 +223,10 @@ var CliTodoCommandProcessor = class {
|
|
|
209
223
|
} else if (args["overdue"]) {
|
|
210
224
|
filtered = filtered.filter((t) => isOverdue(t));
|
|
211
225
|
}
|
|
226
|
+
const showCompletedFirst = cliCore.getPluginConfigValue(context, "todo", "showCompletedFirst", false);
|
|
227
|
+
if (showCompletedFirst) {
|
|
228
|
+
filtered.sort((a, b) => a.completed === b.completed ? 0 : a.completed ? -1 : 1);
|
|
229
|
+
}
|
|
212
230
|
const doneCount = this.todos.filter((t) => t.completed).length;
|
|
213
231
|
context.writer.writeln(
|
|
214
232
|
context.writer.wrapInColor(
|
|
@@ -243,7 +261,7 @@ var CliTodoCommandProcessor = class {
|
|
|
243
261
|
}
|
|
244
262
|
],
|
|
245
263
|
processCommand: async (command, context) => {
|
|
246
|
-
const text = command.value;
|
|
264
|
+
const text = cliCore.joinShellWords(command.value ?? "");
|
|
247
265
|
if (!text) {
|
|
248
266
|
context.writer.writeError("Please provide a task description.");
|
|
249
267
|
return;
|
|
@@ -260,15 +278,17 @@ var CliTodoCommandProcessor = class {
|
|
|
260
278
|
}
|
|
261
279
|
dueDate = parsed;
|
|
262
280
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
281
|
+
let newItem;
|
|
282
|
+
await this.changeTodos(context, (todos) => {
|
|
283
|
+
newItem = {
|
|
284
|
+
id: nextIdOf(todos),
|
|
285
|
+
text,
|
|
286
|
+
completed: false,
|
|
287
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
288
|
+
dueDate
|
|
289
|
+
};
|
|
290
|
+
todos.push(newItem);
|
|
291
|
+
});
|
|
272
292
|
let msg = `Added: "${text}"`;
|
|
273
293
|
if (dueDate) {
|
|
274
294
|
msg += ` (${formatRelativeDate(dueDate)})`;
|
|
@@ -292,10 +312,8 @@ var CliTodoCommandProcessor = class {
|
|
|
292
312
|
}
|
|
293
313
|
],
|
|
294
314
|
processCommand: async (command, context) => {
|
|
295
|
-
const
|
|
296
|
-
const
|
|
297
|
-
const idStr = spaceIndex === -1 ? raw : raw.substring(0, spaceIndex);
|
|
298
|
-
const newText = spaceIndex === -1 ? void 0 : raw.substring(spaceIndex + 1).trim();
|
|
315
|
+
const [idStr = "", ...words] = command.positionals ?? [];
|
|
316
|
+
const newText = words.length ? words.join(" ") : void 0;
|
|
299
317
|
const id = parseInt(idStr, 10);
|
|
300
318
|
if (isNaN(id)) {
|
|
301
319
|
context.writer.writeError("Usage: todo edit <id> <new text> [--due <date>]");
|
|
@@ -307,32 +325,33 @@ var CliTodoCommandProcessor = class {
|
|
|
307
325
|
return;
|
|
308
326
|
}
|
|
309
327
|
const dueArg = command.args["due"];
|
|
310
|
-
|
|
328
|
+
const edit = {};
|
|
311
329
|
if (newText) {
|
|
312
|
-
|
|
313
|
-
changed = true;
|
|
330
|
+
edit.text = newText;
|
|
314
331
|
}
|
|
315
332
|
if (dueArg) {
|
|
316
333
|
if (dueArg === "none") {
|
|
317
|
-
|
|
318
|
-
changed = true;
|
|
334
|
+
edit.dueDate = void 0;
|
|
319
335
|
} else {
|
|
320
336
|
const parsed = parseDueDate(dueArg);
|
|
321
337
|
if (!parsed) {
|
|
322
338
|
context.writer.writeError(`Invalid due date: "${dueArg}".`);
|
|
323
339
|
return;
|
|
324
340
|
}
|
|
325
|
-
|
|
326
|
-
changed = true;
|
|
341
|
+
edit.dueDate = parsed;
|
|
327
342
|
}
|
|
328
343
|
}
|
|
329
|
-
if (
|
|
344
|
+
if (Object.keys(edit).length === 0) {
|
|
330
345
|
context.writer.writeError("Nothing to update. Provide new text or --due.");
|
|
331
346
|
return;
|
|
332
347
|
}
|
|
333
|
-
|
|
348
|
+
let updated;
|
|
349
|
+
await this.changeTodos(context, (todos) => {
|
|
350
|
+
const item = todos.find((t) => t.id === id);
|
|
351
|
+
if (item) updated = Object.assign(item, edit);
|
|
352
|
+
});
|
|
334
353
|
context.writer.writeSuccess(`Updated task #${id}.`);
|
|
335
|
-
context.process.output(todo);
|
|
354
|
+
context.process.output(updated ?? { ...todo, ...edit });
|
|
336
355
|
}
|
|
337
356
|
},
|
|
338
357
|
// ── done ────────────────────────────────────────────
|
|
@@ -343,7 +362,7 @@ var CliTodoCommandProcessor = class {
|
|
|
343
362
|
acceptsRawInput: true,
|
|
344
363
|
valueRequired: true,
|
|
345
364
|
processCommand: async (command, context) => {
|
|
346
|
-
const id = parseInt(command.
|
|
365
|
+
const id = parseInt(command.positionals?.[0] ?? "", 10);
|
|
347
366
|
if (isNaN(id)) {
|
|
348
367
|
context.writer.writeError("Please provide a valid task ID.");
|
|
349
368
|
return;
|
|
@@ -357,11 +376,16 @@ var CliTodoCommandProcessor = class {
|
|
|
357
376
|
context.writer.writeInfo(`Task #${id} is already done.`);
|
|
358
377
|
return;
|
|
359
378
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
379
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
380
|
+
await this.changeTodos(context, (todos) => {
|
|
381
|
+
const item = todos.find((t) => t.id === id);
|
|
382
|
+
if (item) {
|
|
383
|
+
item.completed = true;
|
|
384
|
+
item.completedAt = completedAt;
|
|
385
|
+
}
|
|
386
|
+
});
|
|
363
387
|
context.writer.writeSuccess(`Done: "${todo.text}"`);
|
|
364
|
-
context.process.output(todo);
|
|
388
|
+
context.process.output({ ...todo, completed: true, completedAt });
|
|
365
389
|
}
|
|
366
390
|
},
|
|
367
391
|
// ── toggle ──────────────────────────────────────────
|
|
@@ -371,7 +395,7 @@ var CliTodoCommandProcessor = class {
|
|
|
371
395
|
acceptsRawInput: true,
|
|
372
396
|
valueRequired: true,
|
|
373
397
|
processCommand: async (command, context) => {
|
|
374
|
-
const id = parseInt(command.
|
|
398
|
+
const id = parseInt(command.positionals?.[0] ?? "", 10);
|
|
375
399
|
if (isNaN(id)) {
|
|
376
400
|
context.writer.writeError("Please provide a valid task ID.");
|
|
377
401
|
return;
|
|
@@ -381,12 +405,18 @@ var CliTodoCommandProcessor = class {
|
|
|
381
405
|
context.writer.writeError(`Task #${id} not found.`);
|
|
382
406
|
return;
|
|
383
407
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
await this.
|
|
387
|
-
|
|
408
|
+
const completed = !todo.completed;
|
|
409
|
+
const completedAt = completed ? (/* @__PURE__ */ new Date()).toISOString() : void 0;
|
|
410
|
+
await this.changeTodos(context, (todos) => {
|
|
411
|
+
const item = todos.find((t) => t.id === id);
|
|
412
|
+
if (item) {
|
|
413
|
+
item.completed = completed;
|
|
414
|
+
item.completedAt = completedAt;
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
const status = completed ? "done" : "reopened";
|
|
388
418
|
context.writer.writeSuccess(`Task #${id} marked as ${status}.`);
|
|
389
|
-
context.process.output(todo);
|
|
419
|
+
context.process.output({ ...todo, completed, completedAt });
|
|
390
420
|
}
|
|
391
421
|
},
|
|
392
422
|
// ── rm ──────────────────────────────────────────────
|
|
@@ -419,12 +449,11 @@ var CliTodoCommandProcessor = class {
|
|
|
419
449
|
context.writer.writeInfo("Cancelled.");
|
|
420
450
|
return;
|
|
421
451
|
}
|
|
422
|
-
this.
|
|
423
|
-
await this.saveToStorage(context);
|
|
452
|
+
await this.changeTodos(context, () => []);
|
|
424
453
|
context.writer.writeSuccess("Removed all tasks.");
|
|
425
454
|
return;
|
|
426
455
|
}
|
|
427
|
-
const id = parseInt(command.
|
|
456
|
+
const id = parseInt(command.positionals?.[0] ?? "", 10);
|
|
428
457
|
if (isNaN(id)) {
|
|
429
458
|
context.writer.writeError("Please provide a valid task ID.");
|
|
430
459
|
return;
|
|
@@ -434,8 +463,22 @@ var CliTodoCommandProcessor = class {
|
|
|
434
463
|
context.writer.writeError(`Task #${id} not found.`);
|
|
435
464
|
return;
|
|
436
465
|
}
|
|
437
|
-
const
|
|
438
|
-
|
|
466
|
+
const confirmBeforeDelete = cliCore.getPluginConfigValue(context, "todo", "confirmBeforeDelete", false);
|
|
467
|
+
if (confirmBeforeDelete) {
|
|
468
|
+
const confirmed = await context.reader.readConfirm(
|
|
469
|
+
`Remove task #${id}: "${this.todos[index].text}"?`,
|
|
470
|
+
false
|
|
471
|
+
);
|
|
472
|
+
if (!confirmed) {
|
|
473
|
+
context.writer.writeInfo("Cancelled.");
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
const removed = this.todos[index];
|
|
478
|
+
await this.changeTodos(
|
|
479
|
+
context,
|
|
480
|
+
(todos) => todos.filter((t) => t.id !== id)
|
|
481
|
+
);
|
|
439
482
|
context.writer.writeSuccess(`Removed: "${removed.text}"`);
|
|
440
483
|
}
|
|
441
484
|
}
|
|
@@ -450,12 +493,24 @@ var CliTodoCommandProcessor = class {
|
|
|
450
493
|
return [];
|
|
451
494
|
}
|
|
452
495
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
496
|
+
/**
|
|
497
|
+
* Change the list and save it, atomically: `change` gets the latest saved
|
|
498
|
+
* list (another tab may have changed it) to edit in place, or returns a
|
|
499
|
+
* new one.
|
|
500
|
+
*/
|
|
501
|
+
async changeTodos(context, change) {
|
|
502
|
+
await context.state.update((state) => {
|
|
503
|
+
const todos = (state["todos"] ?? []).map(
|
|
504
|
+
(t) => ({ ...migrateTodoItem(t) })
|
|
505
|
+
);
|
|
506
|
+
return { todos: change(todos) ?? todos };
|
|
507
|
+
});
|
|
456
508
|
localStorage.removeItem("todo-items");
|
|
457
509
|
}
|
|
458
510
|
};
|
|
511
|
+
function nextIdOf(todos) {
|
|
512
|
+
return todos.length > 0 ? Math.max(...todos.map((t) => t.id)) + 1 : 1;
|
|
513
|
+
}
|
|
459
514
|
|
|
460
515
|
// src/lib/completion/cli-todo-id-completion-provider.ts
|
|
461
516
|
var TODO_ID_SUBCOMMANDS = /* @__PURE__ */ new Set(["rm", "done", "complete", "toggle", "edit"]);
|