nightytidy 0.2.9 → 0.2.12
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/package.json +1 -1
- package/src/agent/cli-bridge.js +1 -1
- package/src/agent/index.js +42 -16
- package/src/checks.js +4 -3
package/package.json
CHANGED
package/src/agent/cli-bridge.js
CHANGED
|
@@ -2,7 +2,7 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { debug, warn, error as logError } from '../logger.js';
|
|
4
4
|
|
|
5
|
-
const INIT_TIMEOUT_MS =
|
|
5
|
+
const INIT_TIMEOUT_MS = 10 * 60_000; // 10 minutes — generous but not infinite
|
|
6
6
|
const FINISH_TIMEOUT_MS = 10 * 60_000; // 10 minutes — finish includes report generation
|
|
7
7
|
|
|
8
8
|
export class CliBridge {
|
package/src/agent/index.js
CHANGED
|
@@ -378,6 +378,12 @@ export async function startAgent() {
|
|
|
378
378
|
|
|
379
379
|
case 'cancel-queued': {
|
|
380
380
|
runQueue.cancel(msg.runId);
|
|
381
|
+
// Also notify Firestore — the run may exist there even if not in local queue
|
|
382
|
+
// (e.g. orphaned after a timeout/crash where the agent already discarded it)
|
|
383
|
+
dispatchWithQueue('run_failed', {
|
|
384
|
+
projectId: msg.projectId || '',
|
|
385
|
+
run: { id: msg.runId },
|
|
386
|
+
}, []);
|
|
381
387
|
wsServer.broadcast({ type: 'queue-updated', queue: runQueue.getQueue() });
|
|
382
388
|
reply({ type: 'queue-updated', queue: runQueue.getQueue() });
|
|
383
389
|
break;
|
|
@@ -527,6 +533,8 @@ export async function startAgent() {
|
|
|
527
533
|
? 'Initialization timed out — Claude Code may be unavailable. Restart the agent to retry.'
|
|
528
534
|
: (initResult.parsed?.error || initResult.stderr || 'Unknown init error');
|
|
529
535
|
info(` ✗ Init failed: ${errorMsg}`);
|
|
536
|
+
if (initResult.stdout) debug(` Init stdout: ${initResult.stdout.slice(-500)}`);
|
|
537
|
+
if (initResult.stderr) debug(` Init stderr: ${initResult.stderr.slice(-500)}`);
|
|
530
538
|
wsServer.broadcast({ type: 'run-failed', runId: run.id, error: errorMsg });
|
|
531
539
|
dispatchWithQueue('run_failed', {
|
|
532
540
|
project: project.name,
|
|
@@ -1080,22 +1088,35 @@ export async function startAgent() {
|
|
|
1080
1088
|
const progress = interrupted.lastProgress || {};
|
|
1081
1089
|
const completed = progress.completedCount || 0;
|
|
1082
1090
|
const total = interrupted.steps?.length || 0;
|
|
1083
|
-
info(`Found interrupted run: ${projName} (${completed}/${total} steps completed)`);
|
|
1084
|
-
info(` Run ID: ${interrupted.id}`);
|
|
1085
|
-
info(` Use the web app to Resume, Finish with Partial Results, or Discard`);
|
|
1086
1091
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
totalCost: progress.totalCost || 0,
|
|
1097
|
-
},
|
|
1092
|
+
if (completed === 0) {
|
|
1093
|
+
// Run never actually started (init timed out or crashed before any steps).
|
|
1094
|
+
// Auto-discard — there's nothing to resume or finish, and blocking the
|
|
1095
|
+
// queue for user action is pointless.
|
|
1096
|
+
info(`Auto-discarding interrupted run with 0 completed steps: ${projName} (${interrupted.id})`);
|
|
1097
|
+
runQueue.clearInterrupted();
|
|
1098
|
+
dispatchWithQueue('run_failed', {
|
|
1099
|
+
projectId: proj?.id || interrupted.projectId,
|
|
1100
|
+
run: { id: interrupted.id },
|
|
1098
1101
|
}, []);
|
|
1102
|
+
} else {
|
|
1103
|
+
info(`Found interrupted run: ${projName} (${completed}/${total} steps completed)`);
|
|
1104
|
+
info(` Run ID: ${interrupted.id}`);
|
|
1105
|
+
info(` Use the web app to Resume, Finish with Partial Results, or Discard`);
|
|
1106
|
+
|
|
1107
|
+
// Best-effort: notify Firestore that this run is interrupted
|
|
1108
|
+
// (in case the shutdown webhook didn't make it)
|
|
1109
|
+
if (proj) {
|
|
1110
|
+
dispatchWithQueue('run_interrupted', {
|
|
1111
|
+
projectId: proj.id,
|
|
1112
|
+
run: {
|
|
1113
|
+
id: interrupted.id,
|
|
1114
|
+
completedSteps: completed,
|
|
1115
|
+
failedSteps: progress.failedCount || 0,
|
|
1116
|
+
totalCost: progress.totalCost || 0,
|
|
1117
|
+
},
|
|
1118
|
+
}, []);
|
|
1119
|
+
}
|
|
1099
1120
|
}
|
|
1100
1121
|
}
|
|
1101
1122
|
|
|
@@ -1103,8 +1124,13 @@ export async function startAgent() {
|
|
|
1103
1124
|
// (agent died without graceful shutdown, so markInterrupted was never called)
|
|
1104
1125
|
const current = runQueue.getCurrent();
|
|
1105
1126
|
if (current && current.status === 'running' && !activeBridge) {
|
|
1106
|
-
|
|
1107
|
-
|
|
1127
|
+
// Orphaned run with no progress — auto-discard instead of blocking the queue
|
|
1128
|
+
info(`Found orphaned running run: ${current.id} — auto-discarding (0 steps completed)`);
|
|
1129
|
+
runQueue.completeCurrent({ success: false });
|
|
1130
|
+
dispatchWithQueue('run_failed', {
|
|
1131
|
+
projectId: current.projectId,
|
|
1132
|
+
run: { id: current.id },
|
|
1133
|
+
}, []);
|
|
1108
1134
|
}
|
|
1109
1135
|
|
|
1110
1136
|
// Process any queued runs left from a previous session
|
package/src/checks.js
CHANGED
|
@@ -203,18 +203,19 @@ async function checkClaudeAuthenticated() {
|
|
|
203
203
|
async function getFreeBytesWindows(projectDir) {
|
|
204
204
|
const driveLetter = projectDir.charAt(0).toUpperCase();
|
|
205
205
|
// Try PowerShell first (wmic is deprecated on newer Windows)
|
|
206
|
+
// 10s timeout — PowerShell can hang on OneDrive/network drive systems
|
|
206
207
|
const psResult = await runCommand('powershell', [
|
|
207
208
|
'-NoProfile', '-Command',
|
|
208
209
|
`(Get-PSDrive ${driveLetter}).Free`,
|
|
209
|
-
]);
|
|
210
|
+
], { timeoutMs: 10_000 });
|
|
210
211
|
const psMatch = psResult.stdout.trim().match(/^(\d+)$/);
|
|
211
212
|
if (psResult.code === 0 && psMatch) {
|
|
212
213
|
return parseInt(psMatch[1], 10);
|
|
213
214
|
}
|
|
214
|
-
// Fallback to wmic for older Windows
|
|
215
|
+
// Fallback to wmic for older Windows (also with timeout)
|
|
215
216
|
const result = await runCommand('wmic', [
|
|
216
217
|
'logicaldisk', 'where', `DeviceID='${driveLetter}:'`, 'get', 'FreeSpace',
|
|
217
|
-
]);
|
|
218
|
+
], { timeoutMs: 10_000 });
|
|
218
219
|
const match = result.stdout.match(/(\d+)/);
|
|
219
220
|
return match ? parseInt(match[1], 10) : null;
|
|
220
221
|
}
|