@masslessai/push-todo 4.0.3 → 4.0.5
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/lib/api.js +33 -0
- package/lib/cli.js +35 -0
- package/lib/daemon.js +54 -0
- package/package.json +1 -1
package/lib/api.js
CHANGED
|
@@ -147,6 +147,39 @@ export async function markTaskCompleted(taskId, comment = '') {
|
|
|
147
147
|
return true;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Create a new todo.
|
|
152
|
+
*
|
|
153
|
+
* @param {Object} options - Todo creation options
|
|
154
|
+
* @param {string} options.title - Todo title (required)
|
|
155
|
+
* @param {string|null} options.content - Detailed content (optional)
|
|
156
|
+
* @param {boolean} options.backlog - Whether to create as backlog item
|
|
157
|
+
* @returns {Promise<Object>} Created todo with { id, displayNumber, title, createdAt }
|
|
158
|
+
*/
|
|
159
|
+
export async function createTodo({ title, content = null, backlog = false }) {
|
|
160
|
+
const response = await apiRequest('create-todo', {
|
|
161
|
+
method: 'POST',
|
|
162
|
+
body: JSON.stringify({
|
|
163
|
+
title,
|
|
164
|
+
normalizedContent: content || null,
|
|
165
|
+
isBacklog: backlog,
|
|
166
|
+
createdByClient: 'cli',
|
|
167
|
+
}),
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
if (!response.ok) {
|
|
171
|
+
const text = await response.text();
|
|
172
|
+
throw new Error(`Failed to create todo: ${text}`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const data = await response.json();
|
|
176
|
+
if (!data.success) {
|
|
177
|
+
throw new Error(data.error || 'Unknown error creating todo');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return data.todo;
|
|
181
|
+
}
|
|
182
|
+
|
|
150
183
|
/**
|
|
151
184
|
* Queue a task for daemon execution.
|
|
152
185
|
*
|
package/lib/cli.js
CHANGED
|
@@ -43,6 +43,7 @@ ${bold('push-todo')} - Voice tasks from Push iOS app for Claude Code
|
|
|
43
43
|
${bold('USAGE:')}
|
|
44
44
|
push-todo [options] List active tasks
|
|
45
45
|
push-todo <number> Show specific task
|
|
46
|
+
push-todo create <title> Create a new todo
|
|
46
47
|
push-todo connect Run connection doctor
|
|
47
48
|
push-todo search <query> Search tasks
|
|
48
49
|
push-todo review Review completed tasks
|
|
@@ -78,6 +79,8 @@ ${bold('OPTIONS:')}
|
|
|
78
79
|
${bold('EXAMPLES:')}
|
|
79
80
|
push-todo List active tasks for current project
|
|
80
81
|
push-todo 427 Show task #427
|
|
82
|
+
push-todo create "Fix auth bug" Create a new todo
|
|
83
|
+
push-todo create "Item" --backlog Create as backlog item
|
|
81
84
|
push-todo -a List all tasks across projects
|
|
82
85
|
push-todo --queue 1,2,3 Queue tasks 1, 2, 3 for daemon
|
|
83
86
|
push-todo search "auth bug" Search for tasks matching "auth bug"
|
|
@@ -505,6 +508,38 @@ export async function run(argv) {
|
|
|
505
508
|
return requestConfirmation(values, positionals);
|
|
506
509
|
}
|
|
507
510
|
|
|
511
|
+
// Create command - create a new todo
|
|
512
|
+
if (command === 'create') {
|
|
513
|
+
const title = positionals.slice(1).join(' ');
|
|
514
|
+
if (!title) {
|
|
515
|
+
console.error(red('Error: Title is required.'));
|
|
516
|
+
console.error('');
|
|
517
|
+
console.error('Usage:');
|
|
518
|
+
console.error(' push-todo create "Fix the auth bug"');
|
|
519
|
+
console.error(' push-todo create "Fix the auth bug" --backlog');
|
|
520
|
+
console.error(' push-todo create "Fix the auth bug" --content "Detailed description"');
|
|
521
|
+
process.exit(1);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
try {
|
|
525
|
+
const todo = await api.createTodo({
|
|
526
|
+
title,
|
|
527
|
+
content: values.content || null,
|
|
528
|
+
backlog: values.backlog || false,
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
if (values.json) {
|
|
532
|
+
console.log(JSON.stringify(todo, null, 2));
|
|
533
|
+
} else {
|
|
534
|
+
console.log(green(`Created todo #${todo.displayNumber}: ${todo.title}`));
|
|
535
|
+
}
|
|
536
|
+
} catch (error) {
|
|
537
|
+
console.error(red(`Failed to create todo: ${error.message}`));
|
|
538
|
+
process.exit(1);
|
|
539
|
+
}
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
|
|
508
543
|
// Cron command - scheduled jobs
|
|
509
544
|
if (command === 'cron') {
|
|
510
545
|
const { addJob, removeJob, listJobs } = await import('./cron.js');
|
package/lib/daemon.js
CHANGED
|
@@ -443,6 +443,52 @@ async function fetchQueuedTasks() {
|
|
|
443
443
|
}
|
|
444
444
|
}
|
|
445
445
|
|
|
446
|
+
// ==================== Scheduled Reminder Bridge ====================
|
|
447
|
+
|
|
448
|
+
async function fetchScheduledTodos() {
|
|
449
|
+
try {
|
|
450
|
+
const params = new URLSearchParams();
|
|
451
|
+
params.set('scheduled_before', new Date().toISOString());
|
|
452
|
+
|
|
453
|
+
const response = await apiRequest(`synced-todos?${params}`);
|
|
454
|
+
if (!response.ok) return [];
|
|
455
|
+
|
|
456
|
+
const data = await response.json();
|
|
457
|
+
return data.todos || [];
|
|
458
|
+
} catch (error) {
|
|
459
|
+
logError(`Failed to fetch scheduled todos: ${error.message}`);
|
|
460
|
+
return [];
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
async function checkAndQueueScheduledTodos() {
|
|
465
|
+
const scheduledTodos = await fetchScheduledTodos();
|
|
466
|
+
if (scheduledTodos.length === 0) return;
|
|
467
|
+
|
|
468
|
+
for (const todo of scheduledTodos) {
|
|
469
|
+
const dn = todo.displayNumber;
|
|
470
|
+
const todoId = todo.id;
|
|
471
|
+
|
|
472
|
+
log(`Schedule triggered for #${dn} (reminder_date: ${todo.reminderDate})`);
|
|
473
|
+
|
|
474
|
+
try {
|
|
475
|
+
await updateTaskStatus(dn, 'queued', {
|
|
476
|
+
event: {
|
|
477
|
+
type: 'scheduled_trigger',
|
|
478
|
+
timestamp: new Date().toISOString(),
|
|
479
|
+
summary: 'Auto-queued: reminder time reached',
|
|
480
|
+
}
|
|
481
|
+
}, todoId);
|
|
482
|
+
|
|
483
|
+
log(`Queued #${dn} via schedule trigger`);
|
|
484
|
+
} catch (error) {
|
|
485
|
+
logError(`Failed to queue scheduled todo #${dn}: ${error.message}`);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// ==================== Task Status Updates ====================
|
|
491
|
+
|
|
446
492
|
async function updateTaskStatus(displayNumber, status, extra = {}, todoId = null) {
|
|
447
493
|
try {
|
|
448
494
|
const payload = {
|
|
@@ -2125,6 +2171,14 @@ async function mainLoop() {
|
|
|
2125
2171
|
const poll = async () => {
|
|
2126
2172
|
try {
|
|
2127
2173
|
await checkTimeouts();
|
|
2174
|
+
|
|
2175
|
+
// Schedule bridge: auto-queue todos whose reminder time has arrived
|
|
2176
|
+
try {
|
|
2177
|
+
await checkAndQueueScheduledTodos();
|
|
2178
|
+
} catch (error) {
|
|
2179
|
+
logError(`Scheduled todo check error: ${error.message}`);
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2128
2182
|
await pollAndExecute();
|
|
2129
2183
|
|
|
2130
2184
|
// Cron jobs (check every poll cycle, execution throttled by nextRunAt)
|