@masslessai/push-todo 4.0.5 → 4.0.6

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.
Files changed (2) hide show
  1. package/lib/daemon.js +17 -11
  2. package/package.json +1 -1
package/lib/daemon.js CHANGED
@@ -13,6 +13,7 @@
13
13
  * Ported from: plugins/push-todo/scripts/daemon.py
14
14
  */
15
15
 
16
+ import { randomUUID } from 'crypto';
16
17
  import { spawn, execSync, execFileSync } from 'child_process';
17
18
  import { existsSync, readFileSync, writeFileSync, mkdirSync, appendFileSync, unlinkSync, statSync, renameSync } from 'fs';
18
19
  import { homedir, hostname, platform } from 'os';
@@ -547,7 +548,7 @@ async function updateTaskStatus(displayNumber, status, extra = {}, todoId = null
547
548
  }
548
549
  }
549
550
 
550
- async function claimTask(displayNumber, todoId) {
551
+ async function claimTask(displayNumber, todoId, sessionId) {
551
552
  const machineId = getMachineId();
552
553
  const machineName = getMachineName();
553
554
 
@@ -566,6 +567,7 @@ async function claimTask(displayNumber, todoId) {
566
567
  machineId,
567
568
  machineName,
568
569
  branch,
570
+ sessionId, // Pre-assigned session ID for reliable resume
569
571
  atomic: true,
570
572
  event: {
571
573
  type: 'started',
@@ -1450,8 +1452,11 @@ async function executeTask(task) {
1450
1452
  log(`Task #${displayNumber}: Project ${gitRemote} -> ${projectPath}`);
1451
1453
  }
1452
1454
 
1455
+ // Pre-assign session ID so we can store it at claim time (not rely on parsing stdout)
1456
+ const preAssignedSessionId = randomUUID();
1457
+
1453
1458
  // Atomic task claiming - must await to actually check the result
1454
- if (!(await claimTask(displayNumber, taskId))) {
1459
+ if (!(await claimTask(displayNumber, taskId, preAssignedSessionId))) {
1455
1460
  log(`Task #${displayNumber}: claim failed, skipping`);
1456
1461
  return null;
1457
1462
  }
@@ -1537,7 +1542,8 @@ async function executeTask(task) {
1537
1542
  '-p', prompt,
1538
1543
  '--allowedTools', allowedTools,
1539
1544
  '--output-format', 'json',
1540
- '--permission-mode', 'bypassPermissions'
1545
+ '--permission-mode', 'bypassPermissions',
1546
+ '--session-id', preAssignedSessionId
1541
1547
  ];
1542
1548
 
1543
1549
  try {
@@ -1557,7 +1563,8 @@ async function executeTask(task) {
1557
1563
  task,
1558
1564
  displayNumber,
1559
1565
  startTime: Date.now(),
1560
- projectPath
1566
+ projectPath,
1567
+ sessionId: preAssignedSessionId
1561
1568
  };
1562
1569
 
1563
1570
  runningTasks.set(displayNumber, taskInfo);
@@ -1652,17 +1659,16 @@ async function handleTaskCompletion(displayNumber, exitCode) {
1652
1659
 
1653
1660
  log(`Task #${displayNumber} completed with code ${exitCode} (${duration}s)`);
1654
1661
 
1655
- // Extract session ID for both success and failure (needed for AI summary)
1656
- const buffer = taskStdoutBuffer.get(displayNumber) || [];
1657
- const sessionId = extractSessionIdFromStdout(taskInfo.process, buffer);
1662
+ // Session ID: prefer pre-assigned ID (reliable), fall back to stdout extraction
1663
+ const sessionId = taskInfo.sessionId || extractSessionIdFromStdout(taskInfo.process, taskStdoutBuffer.get(displayNumber) || []);
1658
1664
  const worktreePath = getWorktreePath(displayNumber, projectPath);
1659
1665
  const durationStr = duration < 60 ? `${duration}s` : `${Math.floor(duration / 60)}m ${duration % 60}s`;
1660
1666
  const machineName = getMachineName() || 'Mac';
1661
1667
 
1662
1668
  if (sessionId) {
1663
- log(`Task #${displayNumber} session_id: ${sessionId}`);
1669
+ log(`Task #${displayNumber} session_id: ${sessionId}${taskInfo.sessionId ? ' (pre-assigned)' : ' (from stdout)'}`);
1664
1670
  } else {
1665
- log(`Task #${displayNumber} could not extract session_id`);
1671
+ log(`Task #${displayNumber} could not determine session_id`);
1666
1672
  }
1667
1673
 
1668
1674
  if (exitCode === 0) {
@@ -1798,7 +1804,7 @@ async function handleTaskCompletion(displayNumber, exitCode) {
1798
1804
  ? `${failureSummary}\nExit code ${exitCode}. Ran for ${durationStr} on ${machineName}.`
1799
1805
  : `Exit code ${exitCode}: ${stderr.slice(0, 200)}`;
1800
1806
 
1801
- await updateTaskStatus(displayNumber, 'failed', { error: errorMsg }, info.taskId);
1807
+ await updateTaskStatus(displayNumber, 'failed', { error: errorMsg, sessionId }, info.taskId);
1802
1808
 
1803
1809
  if (NOTIFY_ON_FAILURE) {
1804
1810
  sendMacNotification(
@@ -1942,7 +1948,7 @@ async function checkTimeouts() {
1942
1948
  runningTasks.delete(displayNumber);
1943
1949
 
1944
1950
  const timeoutError = `Task timed out after ${duration}s (limit: ${TASK_TIMEOUT_MS / 1000}s)`;
1945
- updateTaskStatus(displayNumber, 'failed', { error: timeoutError });
1951
+ updateTaskStatus(displayNumber, 'failed', { error: timeoutError, sessionId: taskInfo.sessionId });
1946
1952
 
1947
1953
  if (NOTIFY_ON_FAILURE) {
1948
1954
  sendMacNotification(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masslessai/push-todo",
3
- "version": "4.0.5",
3
+ "version": "4.0.6",
4
4
  "description": "Voice tasks from Push iOS app for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {