@masslessai/push-todo 3.4.6 → 3.4.7

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/SKILL.md CHANGED
@@ -91,6 +91,27 @@ Should I mark #701 and #427 as completed?
91
91
  push-todo --mark-completed TASK_UUID --completion-comment "Completed in Claude Code session"
92
92
  ```
93
93
 
94
+ ### Step 6: Learn Vocabulary (After Each Completion)
95
+
96
+ After marking a task complete, contribute vocabulary terms to improve future task routing:
97
+
98
+ 1. **Extract 3-8 keywords from the session context:**
99
+ - File names / class names touched (e.g., `SyncService`, `RealtimeManager`)
100
+ - Technical concepts implemented (e.g., `WebSocket`, `reconnection`, `caching`)
101
+ - Domain-specific terms from the conversation
102
+
103
+ 2. **Call learn-vocabulary:**
104
+ ```bash
105
+ push-todo --learn-vocabulary TASK_UUID --keywords 'term1,term2,term3'
106
+ ```
107
+
108
+ **Example:** After fixing a sync bug:
109
+ ```bash
110
+ push-todo --learn-vocabulary abc123 --keywords 'SyncService,RealtimeManager,WebSocket,reconnection,realtime'
111
+ ```
112
+
113
+ **Why this matters:** These keywords help the AI route future voice todos to the correct project. The more specific the terms, the better the matching.
114
+
94
115
  ### Key Principle
95
116
 
96
117
  **Session context is primary** - don't grep the entire codebase for every task. Use conversation history to identify what was actually worked on, then match against tasks semantically. This catches both:
package/lib/cli.js CHANGED
@@ -15,7 +15,7 @@ import { ensureDaemonRunning, getDaemonStatus, startDaemon, stopDaemon } from '.
15
15
  import { getScreenshotPath, screenshotExists, openScreenshot } from './utils/screenshots.js';
16
16
  import { bold, red, cyan, dim, green } from './utils/colors.js';
17
17
 
18
- const VERSION = '3.4.5';
18
+ const VERSION = '3.4.7';
19
19
 
20
20
  const HELP_TEXT = `
21
21
  ${bold('push-todo')} - Voice tasks from Push iOS app for Claude Code
package/lib/fetch.js CHANGED
@@ -8,7 +8,7 @@ import * as api from './api.js';
8
8
  import { getMachineId, getMachineName } from './machine-id.js';
9
9
  import { getRegistry } from './project-registry.js';
10
10
  import { getGitRemote, isGitRepo } from './utils/git.js';
11
- import { formatTaskForDisplay, formatTaskTable, formatSearchResult, formatBatchOffer } from './utils/format.js';
11
+ import { formatTaskForDisplay, formatSearchResult } from './utils/format.js';
12
12
  import { bold, green, yellow, red, cyan, dim, muted } from './utils/colors.js';
13
13
  import { decryptTodoField, isE2EEAvailable } from './encryption.js';
14
14
  import { getAutoCommitEnabled, getMaxBatchSize } from './config.js';
@@ -92,34 +92,52 @@ export async function listTasks(options = {}) {
92
92
  const backlog = decryptedTasks.filter(t => !t.isCompleted && !t.is_completed && (t.isBacklog || t.is_backlog));
93
93
  const completed = decryptedTasks.filter(t => t.isCompleted || t.is_completed);
94
94
 
95
- // Header
96
- const scope = gitRemote ? gitRemote : 'All Projects';
97
- console.log(bold(`\nPush Tasks - ${scope}\n`));
98
-
99
- // Active tasks
100
- if (active.length > 0) {
101
- console.log(green(`Active (${active.length}):`));
102
- console.log(formatTaskTable(active));
103
- console.log('');
95
+ // Build scope description
96
+ const scope = gitRemote ? 'this project' : 'all projects';
97
+ const backlogSuffix = options.backlog ? ', backlog only' : '';
98
+ const includeSuffix = options.includeBacklog ? ', including backlog' : '';
99
+
100
+ // Determine which tasks to show
101
+ let tasksToShow = [];
102
+ if (options.backlog) {
103
+ tasksToShow = backlog;
104
+ } else if (options.completed) {
105
+ tasksToShow = completed;
106
+ } else {
107
+ tasksToShow = active;
108
+ if (options.includeBacklog) {
109
+ tasksToShow = [...active, ...backlog];
110
+ }
104
111
  }
105
112
 
106
- // Backlog tasks (if requested)
107
- if (backlog.length > 0 && (options.backlog || options.includeBacklog)) {
108
- console.log(yellow(`Backlog (${backlog.length}):`));
109
- console.log(formatTaskTable(backlog));
110
- console.log('');
111
- }
113
+ // Header
114
+ console.log(`# ${tasksToShow.length} Active Tasks (${scope}${backlogSuffix}${includeSuffix})\n`);
112
115
 
113
- // Completed tasks (if requested)
114
- if (completed.length > 0 && (options.completed || options.includeCompleted)) {
115
- console.log(dim(`Completed (${completed.length}):`));
116
- console.log(formatTaskTable(completed));
116
+ // Show full details for each task (matching Python behavior)
117
+ for (const task of tasksToShow) {
118
+ const displayNum = task.displayNumber || task.display_number;
119
+ console.log(`---\n### #${displayNum}\n`);
120
+ console.log(formatTaskForDisplay(task));
117
121
  console.log('');
118
122
  }
119
123
 
120
- // Summary
121
- const total = active.length + (options.includeBacklog ? backlog.length : 0);
122
- console.log(muted(`Showing ${total} task(s). Use --include-backlog or --completed for more.`));
124
+ // Batch queue offer (only for active tasks, not backlog view)
125
+ if (!options.backlog && tasksToShow.length > 0) {
126
+ const maxBatch = 5; // Default batch size
127
+ const batchCount = Math.min(tasksToShow.length, maxBatch);
128
+ const batchTasks = tasksToShow.slice(0, batchCount);
129
+ const batchNumbers = batchTasks.map(t => String(t.displayNumber || t.display_number));
130
+
131
+ console.log('='.repeat(50));
132
+ console.log(`BATCH_OFFER: ${batchCount}`);
133
+ console.log(`BATCH_TASKS: ${batchNumbers.join(',')}`);
134
+ for (const t of batchTasks) {
135
+ const num = t.displayNumber || t.display_number;
136
+ const summary = (t.summary || 'No summary').slice(0, 50);
137
+ console.log(` #${num} - ${summary}`);
138
+ }
139
+ console.log('='.repeat(50));
140
+ }
123
141
  }
124
142
 
125
143
  /**
@@ -353,7 +371,17 @@ export async function offerBatch(options = {}) {
353
371
  return;
354
372
  }
355
373
 
356
- console.log(formatBatchOffer(batch));
374
+ // Format batch offer inline (matching Python style)
375
+ const batchNumbers = batch.map(t => String(t.displayNumber || t.display_number));
376
+ console.log('='.repeat(50));
377
+ console.log(`BATCH_OFFER: ${batch.length}`);
378
+ console.log(`BATCH_TASKS: ${batchNumbers.join(',')}`);
379
+ for (const t of batch) {
380
+ const num = t.displayNumber || t.display_number;
381
+ const summary = (t.summary || 'No summary').slice(0, 50);
382
+ console.log(` #${num} - ${summary}`);
383
+ }
384
+ console.log('='.repeat(50));
357
385
  }
358
386
 
359
387
  /**
@@ -381,6 +409,13 @@ export async function runReview(options = {}) {
381
409
  return;
382
410
  }
383
411
 
384
- console.log(bold(`\nCompleted Tasks for Review (${decrypted.length}):\n`));
385
- console.log(formatTaskTable(decrypted));
412
+ console.log(`# ${decrypted.length} Completed Tasks for Review\n`);
413
+
414
+ // Show full details for each task (matching Python behavior)
415
+ for (const task of decrypted) {
416
+ const displayNum = task.displayNumber || task.display_number;
417
+ console.log(`---\n### #${displayNum}\n`);
418
+ console.log(formatTaskForDisplay(task));
419
+ console.log('');
420
+ }
386
421
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masslessai/push-todo",
3
- "version": "3.4.6",
3
+ "version": "3.4.7",
4
4
  "description": "Voice tasks from Push iOS app for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {