@masslessai/push-todo 3.4.5 → 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 +157 -119
- package/lib/cli.js +1 -1
- package/lib/fetch.js +61 -26
- package/package.json +2 -4
- package/scripts/postinstall.js +43 -40
- package/.claude-plugin/plugin.json +0 -5
- package/commands/push-todo.md +0 -78
package/SKILL.md
CHANGED
|
@@ -1,180 +1,218 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
description: Show active voice tasks from Push iOS app
|
|
3
|
+
allowed-tools: Bash, Read, Edit, Write, Glob, Grep
|
|
4
|
+
---
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
# Push Voice Tasks
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
This command fetches and displays your active voice tasks from the Push iOS app.
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
2. Run `push-todo` to list active tasks
|
|
9
|
-
3. Run `push-todo <number>` to view and work on a specific task
|
|
10
|
+
## Usage
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
- `/push-todo` - Show active tasks for current project
|
|
13
|
+
- `/push-todo #427` - Jump directly to task #427
|
|
14
|
+
- `/push-todo review` - Review existing tasks and mark completed ones
|
|
15
|
+
- `/push-todo setup` - Configure your Push connection
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
> **Note:** To see tasks from all projects, ask explicitly: "show tasks from all projects"
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
push-todo # Active tasks for current project
|
|
17
|
-
push-todo --all-projects # Tasks from all projects
|
|
18
|
-
push-todo --backlog # Backlog items only
|
|
19
|
-
push-todo --include-backlog # Active + backlog
|
|
20
|
-
push-todo --completed # Completed items only
|
|
21
|
-
push-todo --json # Output as JSON
|
|
22
|
-
```
|
|
19
|
+
## Instructions
|
|
23
20
|
|
|
24
|
-
|
|
21
|
+
When this command is invoked:
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
```
|
|
23
|
+
1. **Check for setup**: First verify the config exists:
|
|
24
|
+
```bash
|
|
25
|
+
test -f ~/.config/push/config && echo "configured" || echo "not configured"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
2. **If not configured**: Run the setup flow (see [Setup Mode](#setup-mode) below)
|
|
29
|
+
|
|
30
|
+
3. **If configured**: Fetch tasks:
|
|
31
|
+
```bash
|
|
32
|
+
push-todo
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
4. Present the tasks and ask which one to work on
|
|
36
|
+
|
|
37
|
+
5. When user selects a task, mark it as started and begin working
|
|
38
|
+
|
|
39
|
+
## Review Mode
|
|
30
40
|
|
|
31
|
-
|
|
41
|
+
When `/push-todo review` is invoked, use **session context** to identify completed tasks:
|
|
42
|
+
|
|
43
|
+
### Step 1: Analyze Session Context
|
|
44
|
+
|
|
45
|
+
First, recall what was worked on in this session (or the previous compacted session):
|
|
46
|
+
- What tasks were explicitly mentioned? (e.g., "work on #701")
|
|
47
|
+
- What features were implemented or bugs fixed?
|
|
48
|
+
- What files were edited and why?
|
|
49
|
+
|
|
50
|
+
### Step 2: Fetch Pending Tasks
|
|
32
51
|
|
|
33
52
|
```bash
|
|
34
|
-
push-todo
|
|
35
|
-
push-todo --search "fix" # Alternative syntax
|
|
53
|
+
push-todo --all-projects --json
|
|
36
54
|
```
|
|
37
55
|
|
|
38
|
-
###
|
|
56
|
+
### Step 3: Match Session Work Against Tasks
|
|
57
|
+
|
|
58
|
+
For each pending task, check if it matches work done in this session:
|
|
59
|
+
|
|
60
|
+
**Explicit Match**: Task number was mentioned (e.g., "worked on #701")
|
|
61
|
+
- These should be marked complete unless work is clearly unfinished
|
|
62
|
+
|
|
63
|
+
**Implicit Match**: Work done aligns with task content semantically
|
|
64
|
+
- Compare task summary/content against session work
|
|
65
|
+
- Example: Task says "add review parameter to slash command" and we just added that feature
|
|
66
|
+
|
|
67
|
+
**No Match**: Task wasn't worked on this session
|
|
68
|
+
- Skip these (don't search codebase unnecessarily)
|
|
69
|
+
|
|
70
|
+
### Step 4: Present Findings
|
|
39
71
|
|
|
40
|
-
```bash
|
|
41
|
-
push-todo --queue 427,428 # Queue tasks for daemon
|
|
42
|
-
push-todo --queue-batch # Auto-queue a batch
|
|
43
|
-
push-todo --mark-completed <uuid> --completion-comment "Fixed the bug"
|
|
44
72
|
```
|
|
73
|
+
## Session Review
|
|
45
74
|
|
|
46
|
-
|
|
75
|
+
Based on this session, I found:
|
|
47
76
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
77
|
+
### Completed This Session
|
|
78
|
+
- #701 "Add review parameter" - We implemented this feature (explicit)
|
|
79
|
+
- #427 "Fix login bug" - We fixed the auth issue in LoginView.swift (implicit match)
|
|
80
|
+
|
|
81
|
+
### Not Worked On
|
|
82
|
+
- #351 "Test on smaller phone" - No related work this session
|
|
83
|
+
- #682 "Rework recording overlay" - No related work this session
|
|
84
|
+
|
|
85
|
+
Should I mark #701 and #427 as completed?
|
|
53
86
|
```
|
|
54
87
|
|
|
55
|
-
###
|
|
88
|
+
### Step 5: Mark Confirmed Tasks
|
|
56
89
|
|
|
57
90
|
```bash
|
|
58
|
-
push-todo --
|
|
59
|
-
push-todo --watch --json # JSON status output
|
|
91
|
+
push-todo --mark-completed TASK_UUID --completion-comment "Completed in Claude Code session"
|
|
60
92
|
```
|
|
61
93
|
|
|
62
|
-
|
|
94
|
+
### Step 6: Learn Vocabulary (After Each Completion)
|
|
63
95
|
|
|
64
|
-
|
|
96
|
+
After marking a task complete, contribute vocabulary terms to improve future task routing:
|
|
65
97
|
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
- **projectHint**: Associated project (git remote)
|
|
71
|
-
- **screenshotAttachments**: Any attached screenshots
|
|
72
|
-
- **linkAttachments**: Any attached links
|
|
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
|
|
73
102
|
|
|
74
|
-
|
|
103
|
+
2. **Call learn-vocabulary:**
|
|
104
|
+
```bash
|
|
105
|
+
push-todo --learn-vocabulary TASK_UUID --keywords 'term1,term2,term3'
|
|
106
|
+
```
|
|
75
107
|
|
|
76
|
-
|
|
108
|
+
**Example:** After fixing a sync bug:
|
|
109
|
+
```bash
|
|
110
|
+
push-todo --learn-vocabulary abc123 --keywords 'SyncService,RealtimeManager,WebSocket,reconnection,realtime'
|
|
111
|
+
```
|
|
77
112
|
|
|
78
|
-
|
|
79
|
-
2. Tasks marked for batch will show `BATCH_OFFER` format
|
|
80
|
-
3. Use `--queue` to add tasks to the daemon queue
|
|
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.
|
|
81
114
|
|
|
82
|
-
|
|
115
|
+
### Key Principle
|
|
83
116
|
|
|
84
|
-
|
|
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:
|
|
118
|
+
- Explicit: User said "work on #701" but forgot to mark complete
|
|
119
|
+
- Implicit: User fixed something that matches a task they didn't mention
|
|
85
120
|
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
[Push] You have 5 active tasks from your iPhone. Say 'push-todo' to see them.
|
|
89
|
-
```
|
|
121
|
+
## Setup Mode
|
|
90
122
|
|
|
91
|
-
|
|
123
|
+
When `/push-todo setup` is invoked, generate project-specific keywords BEFORE running the setup script.
|
|
92
124
|
|
|
93
|
-
|
|
125
|
+
### Why Keywords Matter
|
|
94
126
|
|
|
95
|
-
|
|
127
|
+
Keywords help the AI route voice todos to the correct project. Generic keywords like "coding" or "programming" don't differentiate between projects. We need UNIQUE keywords that identify THIS specific project.
|
|
96
128
|
|
|
97
|
-
|
|
98
|
-
- `/push-todo` - List tasks
|
|
99
|
-
- `/push-todo 427` - Work on task #427
|
|
100
|
-
- `/push-todo connect` - Run diagnostics
|
|
129
|
+
### Step 1: Understand the Project
|
|
101
130
|
|
|
102
|
-
|
|
131
|
+
Read the project context to generate meaningful keywords:
|
|
103
132
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
133
|
+
1. **Check for CLAUDE.md**:
|
|
134
|
+
```bash
|
|
135
|
+
test -f CLAUDE.md && echo "found" || echo "not found"
|
|
136
|
+
```
|
|
108
137
|
|
|
109
|
-
|
|
138
|
+
2. **If CLAUDE.md exists**, read the header section:
|
|
139
|
+
```bash
|
|
140
|
+
head -80 CLAUDE.md
|
|
141
|
+
```
|
|
110
142
|
|
|
111
|
-
|
|
143
|
+
3. **If no CLAUDE.md**, check for README.md:
|
|
144
|
+
```bash
|
|
145
|
+
test -f README.md && head -50 README.md
|
|
146
|
+
```
|
|
112
147
|
|
|
113
|
-
|
|
148
|
+
### Step 2: Generate Unique Keywords
|
|
114
149
|
|
|
115
|
-
|
|
116
|
-
push-todo connect
|
|
117
|
-
```
|
|
150
|
+
Based on the project context, generate 5-10 keywords.
|
|
118
151
|
|
|
119
|
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
152
|
+
**MUST include:**
|
|
153
|
+
- Project name and common nicknames users would say
|
|
154
|
+
- Domain-specific terms (e.g., "voice todo" for a voice app)
|
|
155
|
+
- Distinctive tech if relevant (e.g., "whisper" for speech recognition)
|
|
123
156
|
|
|
124
|
-
|
|
157
|
+
**MUST NOT include (these are useless for differentiation):**
|
|
158
|
+
- Generic terms: "coding", "programming", "development"
|
|
159
|
+
- Tool terms: "mac", "terminal", "cli", "ai", "task"
|
|
160
|
+
- Any term that applies to ALL code projects
|
|
125
161
|
|
|
126
|
-
|
|
127
|
-
- Tasks are encrypted on device
|
|
128
|
-
- Decryption uses iCloud Keychain
|
|
129
|
-
- Requires macOS with keychain access
|
|
162
|
+
**Think:** "What would the user SAY when creating a task for THIS project?"
|
|
130
163
|
|
|
131
|
-
|
|
164
|
+
### Step 3: Generate Description
|
|
132
165
|
|
|
133
|
-
|
|
166
|
+
Generate a short (5-15 words) description that captures what makes this project unique. NOT generic like "coding tasks" or "development work".
|
|
134
167
|
|
|
135
|
-
|
|
168
|
+
### Step 4: Run Setup with Keywords
|
|
136
169
|
|
|
137
170
|
```bash
|
|
138
|
-
|
|
139
|
-
export PUSH_USER_ID="user-uuid"
|
|
140
|
-
export AUTO_COMMIT="true"
|
|
141
|
-
export MAX_BATCH_SIZE="5"
|
|
171
|
+
push-todo connect --keywords "keyword1,keyword2,keyword3,..." --description "Short unique description"
|
|
142
172
|
```
|
|
143
173
|
|
|
144
|
-
|
|
174
|
+
### Examples
|
|
145
175
|
|
|
146
|
-
|
|
147
|
-
|
|
176
|
+
**For a voice todo app (Push):**
|
|
177
|
+
```bash
|
|
178
|
+
push-todo connect --keywords "push,voice,todo,whisper,ios,swiftui,recording,speech,transcription" --description "Voice-powered todo app for iOS with whisper speech recognition"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**For a web scraping project:**
|
|
182
|
+
```bash
|
|
183
|
+
push-todo connect --keywords "scraper,crawler,beautifulsoup,selenium,extraction,parsing" --description "Web scraping tool for data extraction"
|
|
184
|
+
```
|
|
148
185
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
-
|
|
152
|
-
|
|
186
|
+
**For a game engine:**
|
|
187
|
+
```bash
|
|
188
|
+
push-todo connect --keywords "engine,graphics,rendering,physics,ecs,vulkan,gamedev" --description "Custom game engine with Vulkan renderer"
|
|
189
|
+
```
|
|
153
190
|
|
|
154
|
-
###
|
|
155
|
-
Your key may have expired. Run `push-todo connect` to re-authenticate.
|
|
191
|
+
### Fallback (No Documentation)
|
|
156
192
|
|
|
157
|
-
|
|
158
|
-
|
|
193
|
+
If no CLAUDE.md or README.md exists, generate minimal keywords from:
|
|
194
|
+
- Folder name
|
|
195
|
+
- Git repo name
|
|
196
|
+
- Primary file extensions (`.swift` -> iOS, `.py` -> Python, `.rs` -> Rust)
|
|
159
197
|
|
|
160
|
-
##
|
|
198
|
+
## CLI Reference
|
|
161
199
|
|
|
162
|
-
The CLI
|
|
200
|
+
The `push-todo` CLI supports these commands:
|
|
163
201
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
202
|
+
| Command | Description |
|
|
203
|
+
|---------|-------------|
|
|
204
|
+
| `push-todo` | List active tasks for current project |
|
|
205
|
+
| `push-todo <number>` | Show specific task (e.g., `push-todo 427`) |
|
|
206
|
+
| `push-todo --all-projects` | List tasks from all projects |
|
|
207
|
+
| `push-todo --backlog` | Show backlog items |
|
|
208
|
+
| `push-todo connect` | Run connection diagnostics and setup |
|
|
209
|
+
| `push-todo search <query>` | Search tasks |
|
|
210
|
+
| `push-todo --status` | Show connection status |
|
|
211
|
+
| `push-todo --mark-completed <uuid>` | Mark task as completed |
|
|
212
|
+
| `push-todo --json` | Output as JSON |
|
|
171
213
|
|
|
172
|
-
|
|
173
|
-
const tasks = await listTasks({ allProjects: true });
|
|
214
|
+
## What is Push?
|
|
174
215
|
|
|
175
|
-
|
|
176
|
-
const results = await searchTasks('bug fix');
|
|
216
|
+
Push is a voice-powered todo app for iOS. Users capture tasks by speaking on their phone, and those tasks sync to Claude Code for implementation.
|
|
177
217
|
|
|
178
|
-
|
|
179
|
-
await markComplete(taskId, 'Fixed the issue');
|
|
180
|
-
```
|
|
218
|
+
Learn more: https://pushto.do
|
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.
|
|
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,
|
|
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
|
-
//
|
|
96
|
-
const scope = gitRemote ?
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
//
|
|
107
|
-
|
|
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
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
console.log(
|
|
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
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
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(
|
|
385
|
-
|
|
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.
|
|
3
|
+
"version": "3.4.7",
|
|
4
4
|
"description": "Voice tasks from Push iOS app for Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,10 +17,8 @@
|
|
|
17
17
|
"bin/",
|
|
18
18
|
"lib/",
|
|
19
19
|
"hooks/",
|
|
20
|
-
"commands/",
|
|
21
20
|
"natives/",
|
|
22
21
|
"scripts/",
|
|
23
|
-
".claude-plugin/",
|
|
24
22
|
"SKILL.md",
|
|
25
23
|
"LICENSE"
|
|
26
24
|
],
|
|
@@ -35,7 +33,7 @@
|
|
|
35
33
|
},
|
|
36
34
|
"keywords": [
|
|
37
35
|
"claude-code",
|
|
38
|
-
"claude-code-
|
|
36
|
+
"claude-code-skill",
|
|
39
37
|
"push",
|
|
40
38
|
"voice",
|
|
41
39
|
"todo",
|
package/scripts/postinstall.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Post-install script for Push CLI.
|
|
4
4
|
*
|
|
5
5
|
* Sets up integrations for ALL detected AI coding clients:
|
|
6
|
-
* 1. Claude Code - symlink to ~/.claude/
|
|
6
|
+
* 1. Claude Code - symlink to ~/.claude/skills/ (gives clean /push-todo command)
|
|
7
7
|
* 2. OpenAI Codex - AGENTS.md in ~/.codex/
|
|
8
8
|
* 3. Clawdbot - SKILL.md in ~/.clawdbot/skills/
|
|
9
9
|
* 4. Downloads native keychain helper binary (macOS)
|
|
@@ -24,10 +24,10 @@ const PACKAGE_ROOT = join(__dirname, '..');
|
|
|
24
24
|
|
|
25
25
|
// Claude Code locations
|
|
26
26
|
const CLAUDE_DIR = join(homedir(), '.claude');
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const
|
|
27
|
+
const SKILL_DIR = join(CLAUDE_DIR, 'skills');
|
|
28
|
+
const SKILL_LINK = join(SKILL_DIR, 'push-todo');
|
|
29
|
+
const LEGACY_PLUGIN_DIR = join(CLAUDE_DIR, 'plugins');
|
|
30
|
+
const LEGACY_PLUGIN_LINK = join(LEGACY_PLUGIN_DIR, 'push-todo');
|
|
31
31
|
|
|
32
32
|
// OpenAI Codex locations
|
|
33
33
|
const CODEX_DIR = join(homedir(), '.codex');
|
|
@@ -51,81 +51,84 @@ const BINARY_URL = `https://github.com/MasslessAI/push-todo-cli/releases/downloa
|
|
|
51
51
|
const BINARY_URL_X64 = `https://github.com/MasslessAI/push-todo-cli/releases/download/v${VERSION}/${BINARY_NAME}-darwin-x64`;
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
|
-
* Set up Claude Code
|
|
54
|
+
* Set up Claude Code skill by creating symlink.
|
|
55
55
|
*
|
|
56
|
-
* Creates: ~/.claude/
|
|
56
|
+
* Creates: ~/.claude/skills/push-todo -> <npm-package-location>
|
|
57
|
+
*
|
|
58
|
+
* Skills give clean slash commands like /push-todo (no namespace prefix).
|
|
57
59
|
*
|
|
58
60
|
* @returns {boolean} True if successful
|
|
59
61
|
*/
|
|
60
|
-
function
|
|
62
|
+
function setupClaudeSkill() {
|
|
61
63
|
try {
|
|
62
|
-
// Ensure ~/.claude/
|
|
63
|
-
if (!existsSync(
|
|
64
|
-
mkdirSync(
|
|
65
|
-
console.log('[push-todo] Created ~/.claude/
|
|
64
|
+
// Ensure ~/.claude/skills/ directory exists
|
|
65
|
+
if (!existsSync(SKILL_DIR)) {
|
|
66
|
+
mkdirSync(SKILL_DIR, { recursive: true });
|
|
67
|
+
console.log('[push-todo] Created ~/.claude/skills/ directory');
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
// Check if symlink already exists
|
|
69
|
-
if (existsSync(
|
|
71
|
+
if (existsSync(SKILL_LINK)) {
|
|
70
72
|
try {
|
|
71
|
-
const stats = lstatSync(
|
|
73
|
+
const stats = lstatSync(SKILL_LINK);
|
|
72
74
|
if (stats.isSymbolicLink()) {
|
|
73
|
-
const currentTarget = readlinkSync(
|
|
75
|
+
const currentTarget = readlinkSync(SKILL_LINK);
|
|
74
76
|
if (currentTarget === PACKAGE_ROOT) {
|
|
75
|
-
console.log('[push-todo] Claude Code
|
|
77
|
+
console.log('[push-todo] Claude Code skill symlink already configured.');
|
|
76
78
|
return true;
|
|
77
79
|
}
|
|
78
80
|
// Different target - remove and recreate
|
|
79
81
|
console.log('[push-todo] Updating existing symlink...');
|
|
80
|
-
unlinkSync(
|
|
82
|
+
unlinkSync(SKILL_LINK);
|
|
81
83
|
} else {
|
|
82
84
|
// It's a directory or file, not a symlink - back it up
|
|
83
|
-
console.log('[push-todo] Found existing
|
|
84
|
-
const backupPath = `${
|
|
85
|
-
rmSync(
|
|
85
|
+
console.log('[push-todo] Found existing skill directory, backing up...');
|
|
86
|
+
const backupPath = `${SKILL_LINK}.backup.${Date.now()}`;
|
|
87
|
+
rmSync(SKILL_LINK, { recursive: true });
|
|
86
88
|
console.log(`[push-todo] Backed up to ${backupPath}`);
|
|
87
89
|
}
|
|
88
90
|
} catch (err) {
|
|
89
|
-
console.log(`[push-todo] Warning: Could not check existing
|
|
91
|
+
console.log(`[push-todo] Warning: Could not check existing skill: ${err.message}`);
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
// Create the symlink
|
|
94
|
-
symlinkSync(PACKAGE_ROOT,
|
|
95
|
-
console.log('[push-todo] Claude Code
|
|
96
|
-
console.log(`[push-todo] ~/.claude/
|
|
96
|
+
symlinkSync(PACKAGE_ROOT, SKILL_LINK);
|
|
97
|
+
console.log('[push-todo] Claude Code skill installed:');
|
|
98
|
+
console.log(`[push-todo] ~/.claude/skills/push-todo -> ${PACKAGE_ROOT}`);
|
|
97
99
|
return true;
|
|
98
100
|
} catch (error) {
|
|
99
|
-
console.error(`[push-todo] Failed to set up Claude Code
|
|
101
|
+
console.error(`[push-todo] Failed to set up Claude Code skill: ${error.message}`);
|
|
100
102
|
console.log('[push-todo] You can manually create the symlink:');
|
|
101
|
-
console.log(`[push-todo] ln -s "${PACKAGE_ROOT}" "${
|
|
103
|
+
console.log(`[push-todo] ln -s "${PACKAGE_ROOT}" "${SKILL_LINK}"`);
|
|
102
104
|
return false;
|
|
103
105
|
}
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
/**
|
|
107
|
-
* Clean up legacy installation (
|
|
109
|
+
* Clean up legacy plugin installation (in ~/.claude/plugins/).
|
|
110
|
+
* We migrated from plugins to skills for cleaner /push-todo command.
|
|
108
111
|
*/
|
|
109
112
|
function cleanupLegacyInstallation() {
|
|
110
|
-
if (!existsSync(
|
|
113
|
+
if (!existsSync(LEGACY_PLUGIN_LINK)) {
|
|
111
114
|
return;
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
try {
|
|
115
|
-
const stats = lstatSync(
|
|
118
|
+
const stats = lstatSync(LEGACY_PLUGIN_LINK);
|
|
116
119
|
|
|
117
120
|
if (stats.isSymbolicLink()) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
console.log('[push-todo] Removing legacy plugin symlink at ~/.claude/plugins/push-todo');
|
|
122
|
+
unlinkSync(LEGACY_PLUGIN_LINK);
|
|
123
|
+
console.log('[push-todo] Legacy plugin symlink removed.');
|
|
124
|
+
} else if (stats.isDirectory()) {
|
|
125
|
+
console.log('[push-todo] Removing legacy plugin directory at ~/.claude/plugins/push-todo');
|
|
126
|
+
rmSync(LEGACY_PLUGIN_LINK, { recursive: true });
|
|
127
|
+
console.log('[push-todo] Legacy plugin directory removed.');
|
|
125
128
|
}
|
|
126
129
|
} catch (error) {
|
|
127
130
|
// Ignore errors - this is best-effort cleanup
|
|
128
|
-
console.log(`[push-todo] Note: Could not clean up legacy
|
|
131
|
+
console.log(`[push-todo] Note: Could not clean up legacy plugin: ${error.message}`);
|
|
129
132
|
}
|
|
130
133
|
}
|
|
131
134
|
|
|
@@ -331,9 +334,9 @@ async function main() {
|
|
|
331
334
|
// Step 2: Clean up legacy installation
|
|
332
335
|
cleanupLegacyInstallation();
|
|
333
336
|
|
|
334
|
-
// Step 3: Set up Claude Code
|
|
335
|
-
console.log('[push-todo] Setting up Claude Code
|
|
336
|
-
const claudeSuccess =
|
|
337
|
+
// Step 3: Set up Claude Code skill symlink
|
|
338
|
+
console.log('[push-todo] Setting up Claude Code skill...');
|
|
339
|
+
const claudeSuccess = setupClaudeSkill();
|
|
337
340
|
console.log('');
|
|
338
341
|
|
|
339
342
|
// Step 4: Set up OpenAI Codex (if installed)
|
package/commands/push-todo.md
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
# Push Todo - Voice Tasks from iPhone
|
|
2
|
-
|
|
3
|
-
Fetch and work on voice tasks captured via the Push iOS app.
|
|
4
|
-
|
|
5
|
-
## How to Use
|
|
6
|
-
|
|
7
|
-
Run `/push-todo` to see your active tasks, or `/push-todo <number>` to work on a specific task.
|
|
8
|
-
|
|
9
|
-
## Commands
|
|
10
|
-
|
|
11
|
-
| Command | Description |
|
|
12
|
-
|---------|-------------|
|
|
13
|
-
| `/push-todo` | List all active tasks for current project |
|
|
14
|
-
| `/push-todo <number>` | Work on specific task (e.g., `/push-todo 427`) |
|
|
15
|
-
| `/push-todo --all-projects` | List tasks from all projects |
|
|
16
|
-
| `/push-todo --backlog` | Show backlog items |
|
|
17
|
-
| `/push-todo connect` | Run connection diagnostics |
|
|
18
|
-
| `/push-todo search <query>` | Search tasks |
|
|
19
|
-
| `/push-todo status` | Show connection status |
|
|
20
|
-
|
|
21
|
-
## Task Output Format
|
|
22
|
-
|
|
23
|
-
When you fetch a task, you'll see:
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
## Task: #427 Fix authentication bug
|
|
27
|
-
|
|
28
|
-
**Project:** github.com/user/repo
|
|
29
|
-
|
|
30
|
-
### Content
|
|
31
|
-
Users are getting logged out randomly. Need to investigate the session token expiration logic.
|
|
32
|
-
|
|
33
|
-
### Original Voice Transcript
|
|
34
|
-
> "There's a bug where users get logged out randomly, I think it's the session token expiration"
|
|
35
|
-
|
|
36
|
-
**Task ID:** `550e8400-e29b-41d4-a716-446655440000`
|
|
37
|
-
**Display Number:** #427
|
|
38
|
-
**Status:** Active
|
|
39
|
-
**Created:** 2026-01-15T10:30:00Z
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Batch Offer Format
|
|
43
|
-
|
|
44
|
-
When multiple tasks are available, you may see a batch offer:
|
|
45
|
-
|
|
46
|
-
```
|
|
47
|
-
==================================================
|
|
48
|
-
BATCH_OFFER: 3
|
|
49
|
-
BATCH_TASKS: 427,428,429
|
|
50
|
-
#427 - Fix authentication bug
|
|
51
|
-
#428 - Add dark mode support
|
|
52
|
-
#429 - Update API documentation
|
|
53
|
-
==================================================
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Working on Tasks
|
|
57
|
-
|
|
58
|
-
When you fetch a specific task:
|
|
59
|
-
|
|
60
|
-
1. Read the **Content** section for the full task description
|
|
61
|
-
2. Check the **Original Voice Transcript** for additional context
|
|
62
|
-
3. Implement the requested changes
|
|
63
|
-
4. Mark the task as completed when done
|
|
64
|
-
|
|
65
|
-
## Completion
|
|
66
|
-
|
|
67
|
-
After completing a task, the task will be marked as done and synced back to the Push app on your iPhone.
|
|
68
|
-
|
|
69
|
-
## Project Context
|
|
70
|
-
|
|
71
|
-
Tasks are associated with git repositories. The CLI automatically detects your current project and shows only relevant tasks.
|
|
72
|
-
|
|
73
|
-
- Use `--all-projects` to see tasks from all registered projects
|
|
74
|
-
- Run `push-todo connect` to register the current project
|
|
75
|
-
|
|
76
|
-
## E2EE Support
|
|
77
|
-
|
|
78
|
-
If you have End-to-End Encryption enabled on the Push app, the CLI will automatically decrypt task content using your iCloud Keychain.
|