gitdone-agent 0.6.15 → 0.6.16
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/index.js +52 -5
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -27,7 +27,7 @@ import { randomUUID } from 'node:crypto'
|
|
|
27
27
|
// Reported to the server on every sync so the web UI can flag outdated agents.
|
|
28
28
|
// Keep in lockstep with packages/agent/package.json "version" AND
|
|
29
29
|
// src/lib/agentVersion.ts LATEST_AGENT_VERSION.
|
|
30
|
-
const AGENT_VERSION = '0.6.
|
|
30
|
+
const AGENT_VERSION = '0.6.16'
|
|
31
31
|
|
|
32
32
|
const AGENT_DIR = join(homedir(), '.gitdone-agent')
|
|
33
33
|
const CONFIG_PATH = join(AGENT_DIR, 'config.json')
|
|
@@ -186,10 +186,52 @@ function findClaude() {
|
|
|
186
186
|
return { path: 'claude', shell: true, found: false }
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
// ─── Single instance (gd-407) ─────────────────────────────────────────────────
|
|
190
|
+
// Two agents on one machine (an old one surviving an update, or a manual
|
|
191
|
+
// `npx gitdone-agent` next to the autostarted one) flap the machine's online
|
|
192
|
+
// state and race dispatches. The running agent claims the machine via a pid
|
|
193
|
+
// file; a newcomer that finds a LIVE agent behind it exits with EXIT_DUPLICATE,
|
|
194
|
+
// which the supervisor treats as "do not restart me". First one wins.
|
|
195
|
+
// 86 is outside node's own exit-code range (1-13) — keep in lockstep with the
|
|
196
|
+
// run-agent.cmd template in installStartup().
|
|
197
|
+
const EXIT_DUPLICATE = 86
|
|
198
|
+
const PID_PATH = join(AGENT_DIR, 'agent.pid')
|
|
199
|
+
|
|
200
|
+
// Command line of a live process, '' when unreadable (dead process, no rights).
|
|
201
|
+
function processCmdline(pid) {
|
|
202
|
+
try {
|
|
203
|
+
if (process.platform === 'win32') {
|
|
204
|
+
return execSync(
|
|
205
|
+
`powershell -NoProfile -NonInteractive -Command "(Get-CimInstance Win32_Process -Filter 'ProcessId=${pid}').CommandLine"`,
|
|
206
|
+
{ encoding: 'utf8' },
|
|
207
|
+
).trim()
|
|
208
|
+
}
|
|
209
|
+
return execSync(`ps -p ${pid} -o command=`, { encoding: 'utf8' }).trim()
|
|
210
|
+
} catch { return '' }
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function ensureSingleInstance() {
|
|
214
|
+
try {
|
|
215
|
+
const pid = parseInt(readFileSync(PID_PATH, 'utf8'), 10)
|
|
216
|
+
if (pid && pid !== process.pid) {
|
|
217
|
+
process.kill(pid, 0) // throws when that pid is no longer alive
|
|
218
|
+
// PID reuse guard: only defer to a process that really looks like an
|
|
219
|
+
// agent (stable copy agent.mjs, or any gitdone-agent npx/global run).
|
|
220
|
+
if (/gitdone-agent|agent\.mjs/i.test(processCmdline(pid))) {
|
|
221
|
+
log(`✗ друг gitdone-agent вече върви (PID ${pid}) — този процес излиза, за да няма два агента на машината`)
|
|
222
|
+
process.exit(EXIT_DUPLICATE)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} catch { /* no/stale pid file → the machine is free, we take over */ }
|
|
226
|
+
try { ensureAgentDir(); writeFileSync(PID_PATH, String(process.pid)) } catch { /* best-effort */ }
|
|
227
|
+
}
|
|
228
|
+
|
|
189
229
|
// Kill any previously-running agent processes so an update applies WITHOUT a
|
|
190
|
-
// Windows re-login. Targets node processes
|
|
191
|
-
//
|
|
192
|
-
// npx cache
|
|
230
|
+
// Windows re-login. Targets node processes that look like a gitdone agent —
|
|
231
|
+
// both the stable copy in ~/.gitdone-agent AND one running straight from the
|
|
232
|
+
// npx cache / global install (its command line contains "gitdone-agent") —
|
|
233
|
+
// excluding ourselves and our parent (the npx wrapper that launched us).
|
|
234
|
+
// Best-effort; failures are non-fatal.
|
|
193
235
|
function stopRunningAgents() {
|
|
194
236
|
// Kill the supervisor loops (cmd.exe running run-agent.cmd) FIRST, then the
|
|
195
237
|
// agents — the other order lets a still-alive supervisor immediately respawn
|
|
@@ -200,7 +242,7 @@ function stopRunningAgents() {
|
|
|
200
242
|
" Where-Object { $_.CommandLine -like '*run-agent.cmd*' } |",
|
|
201
243
|
' ForEach-Object { Stop-Process -Id $_.ProcessId -Force }',
|
|
202
244
|
"Get-CimInstance Win32_Process -Filter \"Name='node.exe'\" |",
|
|
203
|
-
` Where-Object { $_.CommandLine -like '
|
|
245
|
+
` Where-Object { ($_.CommandLine -like '*gitdone-agent*' -or $_.CommandLine -like '*agent.mjs*') -and $_.ProcessId -ne ${process.pid} -and $_.ProcessId -ne ${process.ppid || 0} } |`,
|
|
204
246
|
' ForEach-Object { Stop-Process -Id $_.ProcessId -Force }',
|
|
205
247
|
].join('\n')
|
|
206
248
|
try {
|
|
@@ -254,12 +296,16 @@ function installStartup() {
|
|
|
254
296
|
`"%NODE%" "${agentPath}" 2>> "${crashLog}"`,
|
|
255
297
|
'set CODE=%errorlevel%',
|
|
256
298
|
`echo [%date% %time%] agent exited (code %CODE%) - restart in 10s >> "${crashLog}"`,
|
|
299
|
+
'if "%CODE%"=="86" goto duplicate',
|
|
257
300
|
'if "%CODE%"=="-1073741502" goto dead',
|
|
258
301
|
'if "%CODE%"=="-1073741515" goto dead',
|
|
259
302
|
'ping -n 11 127.0.0.1 >nul 2>nul || goto dead',
|
|
260
303
|
'goto loop',
|
|
261
304
|
':dead',
|
|
262
305
|
`echo [%date% %time%] node cannot start (code %CODE%) - supervisor giving up until next login >> "${crashLog}"`,
|
|
306
|
+
'exit /b',
|
|
307
|
+
':duplicate',
|
|
308
|
+
`echo [%date% %time%] another agent already runs this machine (code 86) - this supervisor exits >> "${crashLog}"`,
|
|
263
309
|
].join('\r\n')
|
|
264
310
|
const cmdPath = join(AGENT_DIR, 'run-agent.cmd')
|
|
265
311
|
writeFileSync(cmdPath, cmd, 'utf8')
|
|
@@ -1603,6 +1649,7 @@ async function streamCommands(cfg) {
|
|
|
1603
1649
|
// ─── Main ────────────────────────────────────────────────────────────────────
|
|
1604
1650
|
|
|
1605
1651
|
async function runLoop(cfg) {
|
|
1652
|
+
ensureSingleInstance()
|
|
1606
1653
|
log(`gitdone-agent started — machine: ${cfg.hostname}, server: ${cfg.url}, interval: ${cfg.interval}s`)
|
|
1607
1654
|
log(` roots: ${cfg.roots.join(', ') || '(none — add one with --root)'}`)
|
|
1608
1655
|
|