@adhdev/daemon-core 1.0.6-rc.5 → 1.0.7-rc.1

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": "@adhdev/daemon-core",
3
- "version": "1.0.6-rc.5",
3
+ "version": "1.0.7-rc.1",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -47,8 +47,8 @@
47
47
  "author": "vilmire",
48
48
  "license": "AGPL-3.0-or-later",
49
49
  "dependencies": {
50
- "@adhdev/mesh-shared": "1.0.6-rc.5",
51
- "@adhdev/session-host-core": "1.0.6-rc.5",
50
+ "@adhdev/mesh-shared": "1.0.7-rc.1",
51
+ "@adhdev/session-host-core": "1.0.7-rc.1",
52
52
  "@agentclientprotocol/sdk": "^0.16.1",
53
53
  "ajv": "^8.20.0",
54
54
  "ajv-formats": "^3.0.1",
@@ -1706,12 +1706,26 @@ export class ProviderLoader {
1706
1706
  }
1707
1707
  } catch { }
1708
1708
 
1709
- // Minimum 30-minute interval (prevent excessive checks)
1709
+ // Minimum 30-minute interval (prevent excessive checks). BUT the cooldown must
1710
+ // never strand a clean machine with zero providers: fetchLatest() stamps the
1711
+ // timestamp even on a failed/ETag-unchanged attempt (to avoid retry storms), so
1712
+ // if the very first attempt hiccups the upstream dir stays empty yet every later
1713
+ // boot within 30min is skipped — leaving "Total: 0 providers" forever. When the
1714
+ // upstream currently has NO providers we bypass the cooldown and force a fetch;
1715
+ // the normal 30min throttle still applies once at least one provider is present.
1710
1716
  const MIN_INTERVAL_MS = 30 * 60 * 1000;
1711
- if (prevTimestamp && (Date.now() - prevTimestamp) < MIN_INTERVAL_MS) {
1717
+ const upstreamProviderCount = this.countProviders(this.upstreamDir);
1718
+ if (
1719
+ upstreamProviderCount > 0 &&
1720
+ prevTimestamp &&
1721
+ (Date.now() - prevTimestamp) < MIN_INTERVAL_MS
1722
+ ) {
1712
1723
  this.log('Upstream check skipped (last check < 30min ago)');
1713
1724
  return { updated: false };
1714
1725
  }
1726
+ if (upstreamProviderCount === 0 && prevTimestamp && (Date.now() - prevTimestamp) < MIN_INTERVAL_MS) {
1727
+ this.log('Upstream empty (0 providers) — forcing fetch despite <30min cooldown');
1728
+ }
1715
1729
 
1716
1730
  // Resolve the tarball target (config → env → vendor default) once so the
1717
1731
  // HEAD probe and the download below hit the same (possibly self-hosted) URL.
@@ -1753,8 +1767,11 @@ export class ProviderLoader {
1753
1767
  req.end();
1754
1768
  });
1755
1769
 
1756
- // Compare ETag — skip if unchanged
1757
- if (etag && etag === prevEtag) {
1770
+ // Compare ETag — skip if unchanged, but only when providers are actually on
1771
+ // disk. A stale .meta.json etag can match while .upstream is empty (first-boot
1772
+ // hiccup, or the dir was cleared under a persisted meta); short-circuiting then
1773
+ // would leave the machine at 0 providers, so fall through to a real download.
1774
+ if (etag && etag === prevEtag && upstreamProviderCount > 0) {
1758
1775
  // Update timestamp only
1759
1776
  this.writeMeta(metaPath, prevEtag, Date.now());
1760
1777
  this.log('Upstream unchanged (ETag match)');