flowcollab 0.3.17 → 0.3.18

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.
Files changed (2) hide show
  1. package/bin/_client.mjs +26 -15
  2. package/package.json +1 -1
package/bin/_client.mjs CHANGED
@@ -9,6 +9,7 @@ import 'dotenv/config';
9
9
  import { homedir } from 'os';
10
10
  import { readFileSync, writeFileSync, mkdirSync, chmodSync, renameSync } from 'fs';
11
11
  import { join } from 'path';
12
+ import { get as httpsGet } from 'https';
12
13
 
13
14
  // On Windows, Node's bundled CA store doesn't include certs added by corporate/AV
14
15
  // TLS inspection software, causing fetch() to throw "fetch failed". Re-spawn with
@@ -44,21 +45,31 @@ process.on('exit', () => {
44
45
  });
45
46
 
46
47
  if (!_uc.checkedAt || (Date.now() - _uc.checkedAt) > 86_400_000) {
47
- // B21 (audit): AbortSignal.timeout keeps a 4s timer alive that pins the event loop open AFTER the
48
- // command is done (up to 4s of dead time on exit). Use a manual controller with an UNREF'd timer so
49
- // the process can exit as soon as the real work finishes the check is fire-and-forget either way.
50
- const _uctrl = new AbortController();
51
- const _utimer = setTimeout(() => _uctrl.abort(), 4000);
52
- _utimer.unref?.();
53
- fetch('https://registry.npmjs.org/flowcollab/latest', { signal: _uctrl.signal })
54
- .then(r => r.json())
55
- .then(({ version: latest }) => {
56
- mkdirSync(join(homedir(), '.flow'), { recursive: true });
57
- writeFileSync(_updateCache, JSON.stringify({ checkedAt: Date.now(), latest }));
58
- _uc = { checkedAt: Date.now(), latest };
59
- })
60
- .catch(() => {})
61
- .finally(() => clearTimeout(_utimer));
48
+ // B21/CLI-6 (audit): a pending network request pins the event loop open AFTER the command is done.
49
+ // fetch()'s undici socket can't be unref'd per-request, so use https.get + UNREF the socket the
50
+ // request never delays the CLI's exit. Stamp checkedAt SYNCHRONOUSLY first so the 24h gate holds
51
+ // even for instant commands that exit before the request finishes (else unref'ing would re-check
52
+ // every run); the request just updates `latest` in the background when it completes.
53
+ try {
54
+ mkdirSync(join(homedir(), '.flow'), { recursive: true });
55
+ writeFileSync(_updateCache, JSON.stringify({ checkedAt: Date.now(), latest: _uc.latest ?? null }));
56
+ } catch {}
57
+ try {
58
+ const _ureq = httpsGet('https://registry.npmjs.org/flowcollab/latest', { headers: { accept: 'application/json' } }, (res) => {
59
+ if (res.statusCode !== 200) { res.resume(); return; }
60
+ let buf = '';
61
+ res.on('data', d => { buf += d; });
62
+ res.on('end', () => {
63
+ try {
64
+ const { version: latest } = JSON.parse(buf);
65
+ if (latest) { writeFileSync(_updateCache, JSON.stringify({ checkedAt: Date.now(), latest })); _uc = { checkedAt: Date.now(), latest }; }
66
+ } catch {}
67
+ });
68
+ });
69
+ _ureq.on('socket', s => s.unref?.()); // don't let the update check hold the CLI's exit
70
+ _ureq.on('error', () => {});
71
+ _ureq.setTimeout(4000, () => _ureq.destroy());
72
+ } catch {}
62
73
  }
63
74
 
64
75
  function loadGlobalConfig() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowcollab",
3
- "version": "0.3.17",
3
+ "version": "0.3.18",
4
4
  "description": "Multi-Claude coordination layer — shared task board + CLI for teams running Claude Code",
5
5
  "type": "module",
6
6
  "files": [