nightytidy 0.3.1 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nightytidy",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Automated overnight codebase improvement through Claude Code",
5
5
  "license": "MIT",
6
6
  "author": "Dorian Spitz",
@@ -33,7 +33,7 @@ export class CliBridge {
33
33
  const pid = this.activeProcess.pid;
34
34
  debug(`Killing CLI process ${pid}`);
35
35
  if (process.platform === 'win32') {
36
- spawn('taskkill', ['/F', '/T', '/PID', String(pid)]);
36
+ spawn('taskkill', ['/F', '/T', '/PID', String(pid)], { windowsHide: true });
37
37
  } else {
38
38
  this.activeProcess.kill('SIGTERM');
39
39
  }
@@ -81,6 +81,7 @@ export class CliBridge {
81
81
  const proc = spawn('node', [binPath, ...args], {
82
82
  cwd: this.projectDir,
83
83
  stdio: ['pipe', 'pipe', 'pipe'],
84
+ windowsHide: true,
84
85
  });
85
86
  this.activeProcess = proc;
86
87
 
@@ -1,6 +1,7 @@
1
1
  // src/agent/index.js
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
+ import os from 'node:os';
4
5
  import { fileURLToPath } from 'node:url';
5
6
  import { info, warn, debug } from '../logger.js';
6
7
  import { getConfigDir, readConfig, writeConfig, ensureConfigDir } from './config.js';
@@ -1075,6 +1076,44 @@ export async function startAgent() {
1075
1076
  currentProjectId = null;
1076
1077
  }
1077
1078
 
1079
+ // ── Idle heartbeat: keeps Firestore agentStatus/current fresh ──────────
1080
+ // Sends agent_heartbeat to webhookIngest every 60s regardless of run state.
1081
+ // This powers the "Agent online" badge in the web app.
1082
+ let idleHeartbeatInterval = null;
1083
+ const IDLE_HEARTBEAT_MS = 60_000;
1084
+
1085
+ function startIdleHeartbeat() {
1086
+ // Send one immediately so the web app sees "online" within seconds
1087
+ sendIdleHeartbeat();
1088
+ idleHeartbeatInterval = setInterval(sendIdleHeartbeat, IDLE_HEARTBEAT_MS);
1089
+ }
1090
+
1091
+ function sendIdleHeartbeat() {
1092
+ if (!firebaseAuth.isAuthenticated()) return;
1093
+ const projects = projectManager.listProjects().map(p => ({
1094
+ id: p.id, name: p.name, path: p.path,
1095
+ }));
1096
+ const isRunning = !!activeBridge;
1097
+ webhookDispatcher.dispatch('agent_heartbeat', {
1098
+ machineName: os.hostname(),
1099
+ version: AGENT_VERSION,
1100
+ state: isRunning ? 'running' : 'idle',
1101
+ agentStartedAt: Date.now() - (process.uptime() * 1000),
1102
+ projects,
1103
+ }, [{
1104
+ url: FIREBASE_WEBHOOK_URL,
1105
+ label: 'nightytidy.com',
1106
+ headers: firebaseAuth.getAuthHeader(),
1107
+ }]);
1108
+ }
1109
+
1110
+ function stopIdleHeartbeat() {
1111
+ if (idleHeartbeatInterval) {
1112
+ clearInterval(idleHeartbeatInterval);
1113
+ idleHeartbeatInterval = null;
1114
+ }
1115
+ }
1116
+
1078
1117
  // Preserve interrupted run state on shutdown
1079
1118
  function saveInterruptedState() {
1080
1119
  const current = runQueue.getCurrent();
@@ -1110,6 +1149,7 @@ export async function startAgent() {
1110
1149
  const shutdown = async () => {
1111
1150
  info('Agent shutting down...');
1112
1151
  releaseKeepAwake();
1152
+ stopIdleHeartbeat();
1113
1153
  saveInterruptedState();
1114
1154
  poller.stop();
1115
1155
  scheduler.stopAll();
@@ -1197,6 +1237,9 @@ export async function startAgent() {
1197
1237
  }
1198
1238
  }
1199
1239
 
1240
+ // Start idle heartbeat — keeps Firestore agentStatus/current fresh
1241
+ startIdleHeartbeat();
1242
+
1200
1243
  // Print startup info
1201
1244
  console.log(`\nNightyTidy Agent v${AGENT_VERSION}`);
1202
1245
  console.log(`WebSocket: ws://127.0.0.1:${actualPort}`);