teamshare-bridge 0.22.1 → 0.22.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.
@@ -1,3 +1,4 @@
1
+ import { type SingletonDecision } from './singleton-policy';
1
2
  export interface DaemonInstance {
2
3
  pid: number;
3
4
  /** The port the daemon actually BOUND (may differ from config.port). */
@@ -35,6 +36,14 @@ export declare function updateDaemonLock(port: number, version: string): void;
35
36
  * again. Never overwrites a lock held by a different live pid.
36
37
  */
37
38
  export declare function adoptDaemonLock(found: DaemonInstance): void;
39
+ /**
40
+ * The raw lock file, with NO liveness check and NO side effects.
41
+ *
42
+ * `readLiveDaemonLock` clears an abandoned lock as it reads, which is right for
43
+ * deciding but wrong for explaining: `status` has to be able to say "the lock
44
+ * names pid 24148, which is dead" AFTER the read that cleaned it up.
45
+ */
46
+ export declare function readDaemonLockFile(): DaemonInstance | null;
38
47
  /**
39
48
  * Release the lock, but ONLY when this process owns it.
40
49
  *
@@ -42,6 +51,10 @@ export declare function adoptDaemonLock(found: DaemonInstance): void;
42
51
  * deliberately absent: an unreadable or empty lock is not evidence that we
43
52
  * hold it, and treating it as such let every transient daemon delete a live
44
53
  * daemon's file on `process.on('exit')`.
54
+ *
55
+ * This is the EXIT path only. Reclaiming an abandoned lock is
56
+ * `clearAbandonedLock`'s job - calling this one for that can never succeed,
57
+ * because the abandoned lock's pid is by definition not `process.pid`.
45
58
  */
46
59
  export declare function clearDaemonLock(): void;
47
60
  /** Clear the legacy pid file, same ownership rule. */
@@ -75,3 +88,82 @@ export declare function scanForBridge(): Promise<DaemonInstance | null>;
75
88
  export declare function resolveDaemonInstance(): Promise<DaemonInstance | null>;
76
89
  /** The live daemon, sync only. The watchdog uses this so its tick stays sync. */
77
90
  export declare function resolveDaemonInstanceSync(): DaemonInstance | null;
91
+ interface PidInfo {
92
+ /** Process image name (`node`, `GameInputSvc`, …) when queryable. */
93
+ name: string | null;
94
+ /** Full command line when queryable. */
95
+ cmdline: string | null;
96
+ }
97
+ /**
98
+ * Best-effort identity of a pid: image name + command line.
99
+ * null = process gone or unqueryable — never treat as "ours to kill".
100
+ *
101
+ * The NAME half matters: after a reboot Windows recycles pids, so a
102
+ * command-line-only probe returns null for protected processes and a stale
103
+ * pid file would "match" a system service.
104
+ */
105
+ export declare function pidInfo(pid: number): PidInfo | null;
106
+ /**
107
+ * true = verifiably one of OUR daemons (`node …/index.js daemon`).
108
+ * false = a foreign process (PID reuse) — NEVER kill it.
109
+ * null = unqueryable — callers treat it as "not ours", which fails safe.
110
+ *
111
+ * The watchdog supervisor is excluded by the same test: its argv says
112
+ * `supervisor`, not `daemon`. An upgrade stops daemons, never the watchdog that
113
+ * restarts them.
114
+ */
115
+ export declare function isOurDaemonProcess(pid: number): boolean | null;
116
+ /**
117
+ * Every pid on this machine that is VERIFIABLY a bridge daemon, ascending.
118
+ *
119
+ * `daemon.lock` is NOT good enough on its own: during the incident that
120
+ * motivated this, the lock held pid 24148 (already dead) while THREE real
121
+ * daemons ran on three different ports. Anything that trusts the lock alone
122
+ * concludes "daemon is not running" and starts another one.
123
+ *
124
+ * Unqueryable processes (access denied) are simply absent; callers treat
125
+ * "cannot enumerate" as "cannot confirm", which is the safe direction.
126
+ */
127
+ export declare function listOurDaemonPids(options?: {
128
+ exclude?: readonly number[];
129
+ }): number[];
130
+ /** Terminate one verified daemon pid: SIGTERM, then force on Windows. */
131
+ export declare function killDaemonPid(pid: number, timeoutMs?: number): boolean;
132
+ /** Sync `/ping` probe: does a bridge answer `ok:true` on this port? */
133
+ export declare function probePortAnswering(port: number, timeoutMs?: number): boolean;
134
+ /**
135
+ * Is a daemon healthy RIGHT NOW, and on which port?
136
+ *
137
+ * The lock/runtime ports are probed first because they are the answer ~always;
138
+ * the full candidate list is the fallback for a daemon whose files were lost.
139
+ * Probing costs one short-lived node process per port, so it runs on the repair
140
+ * path only — never inside the 30s watchdog tick.
141
+ */
142
+ export declare function findAnsweringDaemonPort(): number | null;
143
+ export interface ReconcileResult {
144
+ decision: SingletonDecision;
145
+ /** Log line for the caller: what happened and what it did about it. */
146
+ message: string;
147
+ /** Pids this call actually terminated. */
148
+ stopped: number[];
149
+ /** Pids it could NOT terminate — the caller must not pretend otherwise. */
150
+ survivors: number[];
151
+ }
152
+ /**
153
+ * Converge the machine on EXACTLY ONE daemon, then report what the caller
154
+ * should do (`singleton-policy.ts` owns the decision; this owns the effects).
155
+ *
156
+ * Effects, in order: enumerate verified daemon pids → probe for a live
157
+ * `/ping` → decide → terminate the losers → adopt the survivor into
158
+ * `daemon.lock`/`daemon.pid` so the NEXT watchdog tick reads a truthful file
159
+ * instead of spawning again.
160
+ *
161
+ * The adoption is the second half of the fix: without it the watchdog would
162
+ * re-derive the same "no daemon" answer every 30 seconds from a lock that
163
+ * describes a process nobody can find.
164
+ */
165
+ export declare function reconcileSingleton(options?: {
166
+ exclude?: readonly number[];
167
+ timeoutMs?: number;
168
+ }): ReconcileResult;
169
+ export {};
@@ -5,12 +5,20 @@ exports.readLiveDaemonLock = readLiveDaemonLock;
5
5
  exports.acquireDaemonLock = acquireDaemonLock;
6
6
  exports.updateDaemonLock = updateDaemonLock;
7
7
  exports.adoptDaemonLock = adoptDaemonLock;
8
+ exports.readDaemonLockFile = readDaemonLockFile;
8
9
  exports.clearDaemonLock = clearDaemonLock;
9
10
  exports.clearOwnPidFile = clearOwnPidFile;
10
11
  exports.probeBridgePort = probeBridgePort;
11
12
  exports.scanForBridge = scanForBridge;
12
13
  exports.resolveDaemonInstance = resolveDaemonInstance;
13
14
  exports.resolveDaemonInstanceSync = resolveDaemonInstanceSync;
15
+ exports.pidInfo = pidInfo;
16
+ exports.isOurDaemonProcess = isOurDaemonProcess;
17
+ exports.listOurDaemonPids = listOurDaemonPids;
18
+ exports.killDaemonPid = killDaemonPid;
19
+ exports.probePortAnswering = probePortAnswering;
20
+ exports.findAnsweringDaemonPort = findAnsweringDaemonPort;
21
+ exports.reconcileSingleton = reconcileSingleton;
14
22
  /**
15
23
  * daemon-instance: the ONE place that answers "is a bridge daemon already
16
24
  * running on this machine, and which process is it?".
@@ -58,14 +66,31 @@ exports.resolveDaemonInstanceSync = resolveDaemonInstanceSync;
58
66
  * RECOVERY path for a lost lock file, and it ADOPTS what it finds by writing
59
67
  * the lock back, so the synchronous path works from then on.
60
68
  *
69
+ * THE LIMIT OF A LOCK, AND WHAT REPLACED IT (2026-10)
70
+ * --------------------------------------------------
71
+ * Everything above still lets two daemons coexist, because a FILE cannot see a
72
+ * process: the lock expires after 24h, it is cleared by a half-written
73
+ * `npm i -g` or a cleanup sweep, and `pidAlive` reads false for a pid we
74
+ * cannot signal. This machine reached three live daemons that way — one
75
+ * serving, two stale — which is what made `npm i -g` fail with EBUSY on a
76
+ * mapped native DLL and left the install unusable.
77
+ *
78
+ * So PROCESS ENUMERATION (`listOurDaemonPids`, command-line verified) is now
79
+ * the authority for "is any daemon running", `daemon.lock` only names WHICH of
80
+ * the live pids is the incumbent, and `reconcileSingleton` enforces "at most
81
+ * one survives" on every start/stop path. The decision itself is the pure
82
+ * `decideSingleton` in `./singleton-policy`.
83
+ *
61
84
  * The lock is taken with direct fs calls, never through a PATH shim - the
62
85
  * same self-deadlock rule that `git-presence.ts` follows with
63
86
  * `envWithoutShims`. An arbiter-mediated singleton would deadlock itself.
64
87
  */
88
+ const node_child_process_1 = require("node:child_process");
65
89
  const node_fs_1 = require("node:fs");
66
90
  const node_os_1 = require("node:os");
67
91
  const node_path_1 = require("node:path");
68
92
  const config_1 = require("../lib/config");
93
+ const singleton_policy_1 = require("./singleton-policy");
69
94
  const STATE_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), '.teamshare');
70
95
  const LOCK_PATH = (0, node_path_1.join)(STATE_DIR, 'daemon.lock');
71
96
  const PID_PATH = (0, node_path_1.join)(STATE_DIR, 'daemon.pid');
@@ -107,6 +132,46 @@ function readLockFile() {
107
132
  return null;
108
133
  }
109
134
  }
135
+ /** True when the lock's holder is a process that could still be serving. */
136
+ function isLiveLockHolder(lock) {
137
+ return lock !== null && pidAlive(lock.pid) && !isExpired(lock.startedAt);
138
+ }
139
+ /**
140
+ * Remove a lock whose holder is PROVABLY gone (dead pid, or older than
141
+ * LOCK_STALE_MS). This is NOT `clearDaemonLock`, and the difference is the whole
142
+ * bug this fixes.
143
+ *
144
+ * `clearDaemonLock` is the exit path: "release MY lock". Its ownership guard is
145
+ * right there — a transient daemon must never delete a live daemon's file on the
146
+ * way out. But the acquire path reused it for "clear the ABANDONED lock", and
147
+ * the guard makes that a silent no-op: the file's pid is not `process.pid`, so
148
+ * nothing is removed, the following `wx` write hits EEXIST, `acquireDaemonLock`
149
+ * returns false, and the daemon starts anyway with a comment about not being able
150
+ * to claim the lock.
151
+ *
152
+ * The result is a machine that serves perfectly while every lock reader says
153
+ * "stopped" — observed here: a healthy 0.22.2 daemon on pid 26380 answering
154
+ * `/ping`, and `daemon.lock` still naming pid 24148, dead since 07:08. Because
155
+ * `readLiveDaemonLock` cleans up through the same guarded call, the stale file
156
+ * also survived every subsequent read, so nothing ever self-healed.
157
+ *
158
+ * So the two operations are now separate on purpose: this one is for a holder
159
+ * that cannot be alive, and it still refuses to touch a live one.
160
+ */
161
+ function clearAbandonedLock() {
162
+ const current = readLockFile();
163
+ if (current === null)
164
+ return true; // nothing to clear
165
+ if (isLiveLockHolder(current))
166
+ return false; // a live daemon owns it
167
+ try {
168
+ (0, node_fs_1.rmSync)(LOCK_PATH, { force: true });
169
+ return true;
170
+ }
171
+ catch {
172
+ return false;
173
+ }
174
+ }
110
175
  /**
111
176
  * The live daemon according to `daemon.lock`, or null.
112
177
  *
@@ -118,8 +183,8 @@ function readLiveDaemonLock() {
118
183
  const lock = readLockFile();
119
184
  if (!lock)
120
185
  return null;
121
- if (!pidAlive(lock.pid) || isExpired(lock.startedAt)) {
122
- clearDaemonLock();
186
+ if (!isLiveLockHolder(lock)) {
187
+ clearAbandonedLock();
123
188
  return null;
124
189
  }
125
190
  return lock;
@@ -136,9 +201,13 @@ function acquireDaemonLock() {
136
201
  (0, node_fs_1.mkdirSync)(STATE_DIR, { recursive: true });
137
202
  // A dead holder must not block a legitimate restart.
138
203
  const existing = readLockFile();
139
- if (existing && pidAlive(existing.pid) && !isExpired(existing.startedAt))
204
+ if (isLiveLockHolder(existing))
140
205
  return false;
141
- clearDaemonLock();
206
+ // `wx` alone is not enough: an ABANDONED file still exists, so the exclusive
207
+ // create would fail with EEXIST and this function would report "not owner"
208
+ // for a machine nobody is using. Remove the dead holder's file first - and
209
+ // only a dead holder's, see `clearAbandonedLock`.
210
+ clearAbandonedLock();
142
211
  (0, node_fs_1.writeFileSync)(LOCK_PATH, JSON.stringify({ pid: process.pid, port: 0, version: '', startedAt: new Date().toISOString() }, null, 2), { flag: 'wx' });
143
212
  return true;
144
213
  }
@@ -156,8 +225,12 @@ function acquireDaemonLock() {
156
225
  function updateDaemonLock(port, version) {
157
226
  try {
158
227
  const current = readLockFile();
159
- // Never stamp over another process's lock.
160
- if (current && current.pid !== process.pid)
228
+ // Never stamp over another LIVE daemon's lock - but DO take it over from a
229
+ // dead one. Comparing pids alone (the old `current.pid !== process.pid`)
230
+ // meant a daemon that had booted past a stale lock could never record its
231
+ // own, so it served for the rest of its life with someone else's pid in
232
+ // `daemon.lock` and every lock reader reported "stopped".
233
+ if (current && current.pid !== process.pid && isLiveLockHolder(current))
161
234
  return;
162
235
  const payload = {
163
236
  pid: process.pid,
@@ -189,6 +262,16 @@ function adoptDaemonLock(found) {
189
262
  /* best-effort */
190
263
  }
191
264
  }
265
+ /**
266
+ * The raw lock file, with NO liveness check and NO side effects.
267
+ *
268
+ * `readLiveDaemonLock` clears an abandoned lock as it reads, which is right for
269
+ * deciding but wrong for explaining: `status` has to be able to say "the lock
270
+ * names pid 24148, which is dead" AFTER the read that cleaned it up.
271
+ */
272
+ function readDaemonLockFile() {
273
+ return readLockFile();
274
+ }
192
275
  /**
193
276
  * Release the lock, but ONLY when this process owns it.
194
277
  *
@@ -196,6 +279,10 @@ function adoptDaemonLock(found) {
196
279
  * deliberately absent: an unreadable or empty lock is not evidence that we
197
280
  * hold it, and treating it as such let every transient daemon delete a live
198
281
  * daemon's file on `process.on('exit')`.
282
+ *
283
+ * This is the EXIT path only. Reclaiming an abandoned lock is
284
+ * `clearAbandonedLock`'s job - calling this one for that can never succeed,
285
+ * because the abandoned lock's pid is by definition not `process.pid`.
199
286
  */
200
287
  function clearDaemonLock() {
201
288
  try {
@@ -316,4 +403,253 @@ function atomicWrite(target, contents) {
316
403
  throw new Error(`could not publish ${target}`);
317
404
  }
318
405
  }
406
+ /**
407
+ * Best-effort identity of a pid: image name + command line.
408
+ * null = process gone or unqueryable — never treat as "ours to kill".
409
+ *
410
+ * The NAME half matters: after a reboot Windows recycles pids, so a
411
+ * command-line-only probe returns null for protected processes and a stale
412
+ * pid file would "match" a system service.
413
+ */
414
+ function pidInfo(pid) {
415
+ try {
416
+ if (process.platform === 'win32') {
417
+ const res = (0, node_child_process_1.spawnSync)('powershell.exe', [
418
+ '-NoProfile',
419
+ '-NonInteractive',
420
+ '-Command',
421
+ '$n=(Get-Process -Id ' +
422
+ pid +
423
+ ' -ErrorAction SilentlyContinue).ProcessName; ' +
424
+ '$c=(Get-CimInstance Win32_Process -Filter "ProcessId=' +
425
+ pid +
426
+ '" -ErrorAction SilentlyContinue).CommandLine; ' +
427
+ '"$n`t$c"',
428
+ ], { stdio: 'pipe', encoding: 'utf8', timeout: 5_000, windowsHide: true });
429
+ const out = (res.stdout ?? '').trim();
430
+ if (!out)
431
+ return null;
432
+ const tab = out.indexOf('\t');
433
+ const name = (tab >= 0 ? out.slice(0, tab) : out).trim();
434
+ const cmdline = tab >= 0 ? out.slice(tab + 1).trim() : '';
435
+ return { name: name || null, cmdline: cmdline || null };
436
+ }
437
+ const res = (0, node_child_process_1.spawnSync)('ps', ['-p', String(pid), '-o', 'args='], {
438
+ stdio: 'pipe',
439
+ encoding: 'utf8',
440
+ timeout: 5_000,
441
+ });
442
+ const out = (res.stdout ?? '').trim();
443
+ if (!out || out === 'args=')
444
+ return null;
445
+ return { name: null, cmdline: out };
446
+ }
447
+ catch {
448
+ return null;
449
+ }
450
+ }
451
+ /**
452
+ * true = verifiably one of OUR daemons (`node …/index.js daemon`).
453
+ * false = a foreign process (PID reuse) — NEVER kill it.
454
+ * null = unqueryable — callers treat it as "not ours", which fails safe.
455
+ *
456
+ * The watchdog supervisor is excluded by the same test: its argv says
457
+ * `supervisor`, not `daemon`. An upgrade stops daemons, never the watchdog that
458
+ * restarts them.
459
+ */
460
+ function isOurDaemonProcess(pid) {
461
+ const info = pidInfo(pid);
462
+ if (!info)
463
+ return null;
464
+ if (info.name && !/^node(?:\.exe)?$/i.test(info.name))
465
+ return false;
466
+ if (info.cmdline) {
467
+ return /(index\.js|teamshare)/i.test(info.cmdline) && /\bdaemon\b/i.test(info.cmdline);
468
+ }
469
+ return null;
470
+ }
471
+ /**
472
+ * Every pid on this machine that is VERIFIABLY a bridge daemon, ascending.
473
+ *
474
+ * `daemon.lock` is NOT good enough on its own: during the incident that
475
+ * motivated this, the lock held pid 24148 (already dead) while THREE real
476
+ * daemons ran on three different ports. Anything that trusts the lock alone
477
+ * concludes "daemon is not running" and starts another one.
478
+ *
479
+ * Unqueryable processes (access denied) are simply absent; callers treat
480
+ * "cannot enumerate" as "cannot confirm", which is the safe direction.
481
+ */
482
+ function listOurDaemonPids(options = {}) {
483
+ const exclude = new Set(options.exclude ?? []);
484
+ const out = (() => {
485
+ if (process.platform === 'win32') {
486
+ const res = (0, node_child_process_1.spawnSync)('powershell.exe', [
487
+ '-NoProfile',
488
+ '-NonInteractive',
489
+ '-Command',
490
+ 'Get-CimInstance Win32_Process -Filter "Name=\'node.exe\'" | ' +
491
+ 'ForEach-Object { "$($_.ProcessId)`t$($_.CommandLine)" }',
492
+ ], { stdio: 'pipe', encoding: 'utf8', timeout: 10_000, windowsHide: true });
493
+ return res.stdout ?? '';
494
+ }
495
+ const res = (0, node_child_process_1.spawnSync)('ps', ['-eo', 'pid=,args='], {
496
+ stdio: 'pipe',
497
+ encoding: 'utf8',
498
+ timeout: 10_000,
499
+ });
500
+ return res.stdout ?? '';
501
+ })();
502
+ const pids = [];
503
+ for (const line of out.split(/\r?\n/)) {
504
+ const tab = line.indexOf('\t');
505
+ const pid = Number(tab >= 0 ? line.slice(0, tab) : line.slice(0, line.indexOf(' ')).trim());
506
+ if (!Number.isInteger(pid) || pid <= 0 || exclude.has(pid))
507
+ continue;
508
+ // Re-use the single identity test so "verified" means the same thing here as
509
+ // everywhere else a pid is about to be killed.
510
+ if (isOurDaemonProcess(pid) === true)
511
+ pids.push(pid);
512
+ }
513
+ return [...new Set(pids)].sort((a, b) => a - b);
514
+ }
515
+ /** Terminate one verified daemon pid: SIGTERM, then force on Windows. */
516
+ function killDaemonPid(pid, timeoutMs = 5000) {
517
+ try {
518
+ process.kill(pid);
519
+ }
520
+ catch {
521
+ /* already gone */
522
+ }
523
+ const deadline = Date.now() + timeoutMs;
524
+ while (pidAlive(pid) && Date.now() < deadline) {
525
+ /* brief wait for a clean exit */
526
+ }
527
+ if (!pidAlive(pid))
528
+ return true;
529
+ if (process.platform === 'win32') {
530
+ // Windows: a detached console node.exe has no window to close politely, so
531
+ // WM_CLOSE is not an option and /F is the only way.
532
+ (0, node_child_process_1.spawnSync)('taskkill', ['/pid', String(pid), '/f'], {
533
+ stdio: 'ignore',
534
+ windowsHide: true,
535
+ });
536
+ }
537
+ else {
538
+ try {
539
+ process.kill(pid, 'SIGKILL');
540
+ }
541
+ catch {
542
+ /* best-effort */
543
+ }
544
+ }
545
+ const hard = Date.now() + 3000;
546
+ while (pidAlive(pid) && Date.now() < hard) {
547
+ /* wait for the kill to land */
548
+ }
549
+ return !pidAlive(pid);
550
+ }
551
+ /** Sync `/ping` probe: does a bridge answer `ok:true` on this port? */
552
+ function probePortAnswering(port, timeoutMs = 2000) {
553
+ const res = (0, node_child_process_1.spawnSync)(process.execPath, [
554
+ '-e',
555
+ `fetch('http://127.0.0.1:${port}/ping',{signal:AbortSignal.timeout(${timeoutMs})})` +
556
+ '.then(async r=>{try{const b=await r.json();process.exit(b&&b.ok===true?0:1)}catch{process.exit(1)}})' +
557
+ '.catch(()=>process.exit(1))',
558
+ ], { stdio: 'ignore', timeout: timeoutMs + 3000, windowsHide: true });
559
+ return res.status === 0;
560
+ }
561
+ /**
562
+ * Is a daemon healthy RIGHT NOW, and on which port?
563
+ *
564
+ * The lock/runtime ports are probed first because they are the answer ~always;
565
+ * the full candidate list is the fallback for a daemon whose files were lost.
566
+ * Probing costs one short-lived node process per port, so it runs on the repair
567
+ * path only — never inside the 30s watchdog tick.
568
+ */
569
+ function findAnsweringDaemonPort() {
570
+ const lock = readLiveDaemonLock();
571
+ const lockPort = lock && lock.port > 0 ? lock.port : null;
572
+ if (lockPort !== null && probePortAnswering(lockPort))
573
+ return lockPort;
574
+ const runtimePort = runtimePortOrNull();
575
+ if (runtimePort !== null && runtimePort !== lockPort && probePortAnswering(runtimePort)) {
576
+ return runtimePort;
577
+ }
578
+ for (const port of config_1.BRIDGE_CANDIDATE_PORTS) {
579
+ if (port === lockPort || port === runtimePort)
580
+ continue;
581
+ if (probePortAnswering(port))
582
+ return port;
583
+ }
584
+ return null;
585
+ }
586
+ function runtimePortOrNull() {
587
+ const port = readRuntimeJson()?.port;
588
+ return typeof port === 'number' && port > 0 ? port : null;
589
+ }
590
+ function readRuntimeJson() {
591
+ try {
592
+ return JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(STATE_DIR, 'runtime.json'), 'utf8'));
593
+ }
594
+ catch {
595
+ return null;
596
+ }
597
+ }
598
+ /**
599
+ * Converge the machine on EXACTLY ONE daemon, then report what the caller
600
+ * should do (`singleton-policy.ts` owns the decision; this owns the effects).
601
+ *
602
+ * Effects, in order: enumerate verified daemon pids → probe for a live
603
+ * `/ping` → decide → terminate the losers → adopt the survivor into
604
+ * `daemon.lock`/`daemon.pid` so the NEXT watchdog tick reads a truthful file
605
+ * instead of spawning again.
606
+ *
607
+ * The adoption is the second half of the fix: without it the watchdog would
608
+ * re-derive the same "no daemon" answer every 30 seconds from a lock that
609
+ * describes a process nobody can find.
610
+ */
611
+ function reconcileSingleton(options = {}) {
612
+ const exclude = options.exclude ?? [];
613
+ const timeoutMs = options.timeoutMs ?? 5000;
614
+ const live = listOurDaemonPids({ exclude });
615
+ const lock = readLiveDaemonLock();
616
+ const runtime = readRuntimeJson();
617
+ const answeringPort = findAnsweringDaemonPort();
618
+ const decision = (0, singleton_policy_1.decideSingleton)({
619
+ live,
620
+ lockPid: lock && live.includes(lock.pid) ? lock.pid : null,
621
+ runtimePid: typeof runtime?.pid === 'number' && live.includes(runtime.pid) ? runtime.pid : null,
622
+ anyAnswering: answeringPort !== null,
623
+ });
624
+ const stopped = [];
625
+ const survivors = [];
626
+ for (const pid of decision.stop) {
627
+ if (killDaemonPid(pid, timeoutMs))
628
+ stopped.push(pid);
629
+ else
630
+ survivors.push(pid);
631
+ }
632
+ // A survivor we could not kill must keep its claim: clearing the lock here is
633
+ // what let a live daemon become invisible and a second one start on top of it.
634
+ if (decision.action === 'keep' && decision.keep !== null && !survivors.includes(decision.keep)) {
635
+ adoptDaemonLock({
636
+ pid: decision.keep,
637
+ port: answeringPort ?? 0,
638
+ version: lock?.version ?? 'unknown',
639
+ startedAt: lock?.startedAt || new Date().toISOString(),
640
+ source: 'lock',
641
+ });
642
+ }
643
+ const stoppedNote = stopped.length > 0
644
+ ? ` stopped ${stopped.join(', ')}.`
645
+ : survivors.length > 0
646
+ ? ` COULD NOT STOP ${survivors.join(', ')} - do not treat this machine as clean.`
647
+ : '';
648
+ return {
649
+ decision,
650
+ message: decision.reason + stoppedNote,
651
+ stopped,
652
+ survivors,
653
+ };
654
+ }
319
655
  //# sourceMappingURL=daemon-instance.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"daemon-instance.js","sourceRoot":"","sources":["../../src/bridge/daemon-instance.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"daemon-instance.js","sourceRoot":"","sources":["../../src/bridge/daemon-instance.ts"],"names":[],"mappings":"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"}
@@ -154,6 +154,21 @@ async function runDaemon(portOverride) {
154
154
  (0, daemon_support_1.log)('use `teamshare-bridge restart` to replace it');
155
155
  return;
156
156
  }
157
+ // LAST LINE, AND IT MUST NOT BE "CARRY ON" (2026-10). Neither the lock nor
158
+ // the port scan can see a daemon whose files were lost under it: the lock
159
+ // expires after 24h, is cleared by a half-written `npm i -g` or a cleanup
160
+ // sweep, and a pid we cannot signal reads as dead. Asking the OS is the
161
+ // only way to honour "at most one daemon per machine" - and the old
162
+ // "could not claim daemon.lock - continuing" branch is how this machine
163
+ // ended up with three at once, each holding native DLLs that then broke the
164
+ // next `npm i -g` with EBUSY.
165
+ const others = (0, daemon_instance_1.listOurDaemonPids)({ exclude: [process.pid] });
166
+ if (others.length > 0) {
167
+ (0, daemon_support_1.log)(`another TeamShare daemon process is running (pid ${others.join(', ')}) but owns no ` +
168
+ `lock and answers no port - refusing to start a second daemon`);
169
+ (0, daemon_support_1.log)('use `teamshare-bridge restart` to replace it');
170
+ return;
171
+ }
157
172
  // Genuinely free, but we could not take the lock (unwritable home?). Carry
158
173
  // on: the bind-time occupant check in startProbeServer is the last guard.
159
174
  (0, daemon_support_1.log)('could not claim daemon.lock - continuing with port checks only');