@masslessai/push-todo 3.5.1 → 3.5.3
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/daemon-health.js +34 -2
- package/lib/fetch.js +22 -3
- package/lib/utils/format.js +27 -0
- package/package.json +1 -1
package/lib/daemon-health.js
CHANGED
|
@@ -180,14 +180,46 @@ export function stopDaemon() {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
/**
|
|
183
|
-
*
|
|
184
|
-
|
|
183
|
+
* Get the installed package version (npm package version).
|
|
184
|
+
*/
|
|
185
|
+
function getInstalledVersion() {
|
|
186
|
+
try {
|
|
187
|
+
const pkgPath = join(__dirname, '..', 'package.json');
|
|
188
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
189
|
+
return pkg.version || null;
|
|
190
|
+
} catch {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Ensure daemon is running with correct version - called on every /push-todo command.
|
|
197
|
+
* Auto-restarts daemon if version mismatch detected.
|
|
198
|
+
*
|
|
199
|
+
* This prevents stale daemons from running after npm package updates.
|
|
200
|
+
* See: /docs/20260204_daemon_heartbeat_status_indicator_implementation_plan.md
|
|
185
201
|
*/
|
|
186
202
|
export function ensureDaemonRunning() {
|
|
187
203
|
const status = getDaemonStatus();
|
|
204
|
+
const installedVersion = getInstalledVersion();
|
|
205
|
+
|
|
206
|
+
// Case 1: Daemon not running - start it
|
|
188
207
|
if (!status.running) {
|
|
189
208
|
startDaemon();
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Case 2: Daemon running but version mismatch - restart it
|
|
213
|
+
if (installedVersion && status.version && status.version !== installedVersion) {
|
|
214
|
+
// Version mismatch - restart daemon with new version
|
|
215
|
+
stopDaemon();
|
|
216
|
+
// Brief delay to ensure clean shutdown
|
|
217
|
+
const start = Date.now();
|
|
218
|
+
while (Date.now() - start < 500) {} // 500ms busy wait
|
|
219
|
+
startDaemon();
|
|
190
220
|
}
|
|
221
|
+
|
|
222
|
+
// Case 3: Daemon running with correct version - do nothing
|
|
191
223
|
}
|
|
192
224
|
|
|
193
225
|
export { PID_FILE, LOG_FILE, STATUS_FILE, PUSH_DIR };
|
package/lib/fetch.js
CHANGED
|
@@ -88,8 +88,15 @@ export async function listTasks(options = {}) {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// Group by status for display
|
|
91
|
-
|
|
92
|
-
const
|
|
91
|
+
// Execution status tasks (queued/running) are separated from regular active tasks
|
|
92
|
+
const getExecStatus = t => t.executionStatus || t.execution_status;
|
|
93
|
+
const isRunningOrQueued = t => {
|
|
94
|
+
const es = getExecStatus(t);
|
|
95
|
+
return es === 'queued' || es === 'running';
|
|
96
|
+
};
|
|
97
|
+
const running = decryptedTasks.filter(t => !t.isCompleted && !t.is_completed && isRunningOrQueued(t));
|
|
98
|
+
const active = decryptedTasks.filter(t => !t.isCompleted && !t.is_completed && !t.isBacklog && !t.is_backlog && !isRunningOrQueued(t));
|
|
99
|
+
const backlog = decryptedTasks.filter(t => !t.isCompleted && !t.is_completed && (t.isBacklog || t.is_backlog) && !isRunningOrQueued(t));
|
|
93
100
|
const completed = decryptedTasks.filter(t => t.isCompleted || t.is_completed);
|
|
94
101
|
|
|
95
102
|
// Build scope description
|
|
@@ -110,8 +117,20 @@ export async function listTasks(options = {}) {
|
|
|
110
117
|
}
|
|
111
118
|
}
|
|
112
119
|
|
|
120
|
+
// Show running/queued section first (always, unless viewing backlog/completed only)
|
|
121
|
+
if (!options.backlog && !options.completed && running.length > 0) {
|
|
122
|
+
console.log(`# ${running.length} Running/Queued Tasks (${scope})\n`);
|
|
123
|
+
for (const task of running) {
|
|
124
|
+
const displayNum = task.displayNumber || task.display_number;
|
|
125
|
+
console.log(`---\n### #${displayNum}\n`);
|
|
126
|
+
console.log(formatTaskForDisplay(task));
|
|
127
|
+
console.log('');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
113
131
|
// Header
|
|
114
|
-
|
|
132
|
+
const totalCount = tasksToShow.length;
|
|
133
|
+
console.log(`# ${totalCount} Active Tasks (${scope}${backlogSuffix}${includeSuffix})\n`);
|
|
115
134
|
|
|
116
135
|
// Show full details for each task (matching Python behavior)
|
|
117
136
|
for (const task of tasksToShow) {
|
package/lib/utils/format.js
CHANGED
|
@@ -50,9 +50,18 @@ export function formatTaskForDisplay(task) {
|
|
|
50
50
|
const displayNum = task.displayNumber || task.display_number;
|
|
51
51
|
|
|
52
52
|
// Determine status prefix
|
|
53
|
+
const execStatus = task.executionStatus || task.execution_status;
|
|
53
54
|
let statusPrefix = '';
|
|
54
55
|
if (task.isCompleted || task.is_completed) {
|
|
55
56
|
statusPrefix = '✅ '; // Completed
|
|
57
|
+
} else if (execStatus === 'running') {
|
|
58
|
+
statusPrefix = '🔄 '; // Running on Mac
|
|
59
|
+
} else if (execStatus === 'queued') {
|
|
60
|
+
statusPrefix = '⚡ '; // Queued for Mac
|
|
61
|
+
} else if (execStatus === 'failed') {
|
|
62
|
+
statusPrefix = '❌ '; // Failed
|
|
63
|
+
} else if (execStatus === 'needs_clarification') {
|
|
64
|
+
statusPrefix = '❓ '; // Needs clarification
|
|
56
65
|
} else if (task.isBacklog || task.is_backlog) {
|
|
57
66
|
statusPrefix = '📦 '; // Backlog
|
|
58
67
|
}
|
|
@@ -127,6 +136,17 @@ export function formatTaskForDisplay(task) {
|
|
|
127
136
|
if (sessionId) {
|
|
128
137
|
lines.push(`**Session:** Available (\`push-todo resume ${displayNum}\`)`);
|
|
129
138
|
}
|
|
139
|
+
} else if (execStatus === 'running') {
|
|
140
|
+
const machineName = task.executionMachineName || task.execution_machine_name;
|
|
141
|
+
const machineHint = machineName ? ` on ${machineName}` : '';
|
|
142
|
+
lines.push(`**Status:** 🔄 Running${machineHint}`);
|
|
143
|
+
} else if (execStatus === 'queued') {
|
|
144
|
+
lines.push('**Status:** ⚡ Queued for Mac execution');
|
|
145
|
+
} else if (execStatus === 'failed') {
|
|
146
|
+
const error = task.executionError || task.execution_error || 'Unknown error';
|
|
147
|
+
lines.push(`**Status:** ❌ Failed: ${error}`);
|
|
148
|
+
} else if (execStatus === 'needs_clarification') {
|
|
149
|
+
lines.push('**Status:** ❓ Needs clarification');
|
|
130
150
|
} else if (task.isBacklog || task.is_backlog) {
|
|
131
151
|
lines.push('**Status:** 📦 Backlog');
|
|
132
152
|
} else {
|
|
@@ -198,9 +218,16 @@ export function formatTaskTable(tasks) {
|
|
|
198
218
|
summary = summary.slice(0, 27) + '…';
|
|
199
219
|
}
|
|
200
220
|
|
|
221
|
+
const taskExecStatus = task.executionStatus || task.execution_status;
|
|
201
222
|
let status = 'Active';
|
|
202
223
|
if (task.isCompleted || task.is_completed) {
|
|
203
224
|
status = '✅ Done';
|
|
225
|
+
} else if (taskExecStatus === 'running') {
|
|
226
|
+
status = '🔄 Running';
|
|
227
|
+
} else if (taskExecStatus === 'queued') {
|
|
228
|
+
status = '⚡ Queued';
|
|
229
|
+
} else if (taskExecStatus === 'failed') {
|
|
230
|
+
status = '❌ Failed';
|
|
204
231
|
} else if (task.isBacklog || task.is_backlog) {
|
|
205
232
|
status = '📦 Later';
|
|
206
233
|
}
|