fullcourtdefense-cli 1.36.2 → 1.36.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/dist/telemetry.js CHANGED
@@ -43,6 +43,7 @@ exports.setVerdictIdentity = setVerdictIdentity;
43
43
  exports.setVerdictToolArgs = setVerdictToolArgs;
44
44
  exports.restartVerdictTiming = restartVerdictTiming;
45
45
  exports.spoolEvent = spoolEvent;
46
+ exports.getLastFlushFailure = getLastFlushFailure;
46
47
  exports.flushSpool = flushSpool;
47
48
  exports.triggerFlush = triggerFlush;
48
49
  const async_hooks_1 = require("async_hooks");
@@ -360,10 +361,17 @@ function releaseFlushLock() {
360
361
  }
361
362
  catch { /* already gone */ }
362
363
  }
364
+ let lastFlushFailure;
365
+ function getLastFlushFailure() {
366
+ return lastFlushFailure;
367
+ }
363
368
  /** Drain the spool to the backend in one batch (+ optional heartbeat). Returns accepted count. */
364
369
  async function flushSpool(input) {
365
- if (!acquireFlushLock())
366
- return null; // another flusher is draining — its batch covers these events
370
+ lastFlushFailure = undefined;
371
+ if (!acquireFlushLock()) { // another flusher is draining — its batch covers these events
372
+ lastFlushFailure = { kind: 'locked' };
373
+ return null;
374
+ }
367
375
  try {
368
376
  return await flushSpoolLocked(input);
369
377
  }
@@ -388,8 +396,10 @@ async function flushSpoolLocked(input) {
388
396
  const all = readSpool();
389
397
  const batch = all.slice(0, MAX_BATCH);
390
398
  const overflow = all.slice(MAX_BATCH);
391
- if (batch.length === 0 && !input.heartbeat)
399
+ if (batch.length === 0 && !input.heartbeat) {
400
+ lastFlushFailure = { kind: 'empty' };
392
401
  return null;
402
+ }
393
403
  const identity = (0, machineIdentity_1.getMachineIdentity)();
394
404
  const headers = { 'Content-Type': 'application/json' };
395
405
  if (input.shieldKey)
@@ -443,11 +453,22 @@ async function flushSpoolLocked(input) {
443
453
  }),
444
454
  signal: AbortSignal.timeout(input.timeoutMs ?? 8000),
445
455
  });
446
- if (!resp.ok)
447
- return null;
448
456
  const body = await resp.json().catch(() => ({}));
449
- if (!body.success)
457
+ if (!resp.ok || !body.success) {
458
+ lastFlushFailure = {
459
+ kind: 'http',
460
+ status: resp.status,
461
+ ...(typeof body.code === 'string' ? { code: body.code.slice(0, 60) } : {}),
462
+ ...(typeof body.error === 'string' ? { error: body.error.slice(0, 200) } : {}),
463
+ };
450
464
  return null;
465
+ }
466
+ // A 200 means the backend found this machine id enrolled under this
467
+ // shield: the id is now backend-confirmed and never silently replaced.
468
+ try {
469
+ (0, machineIdentity_1.confirmMachineIdentity)(identity.machineId, 'heartbeat');
470
+ }
471
+ catch { /* never lose a delivered batch over the pin */ }
451
472
  // Successfully delivered → drop ONLY the events we actually sent. The spool
452
473
  // may have gained new events while the POST was in flight (e.g. a terminal
453
474
  // guard block landing mid-flush) — rewriting with the pre-flush snapshot
@@ -456,7 +477,8 @@ async function flushSpoolLocked(input) {
456
477
  rewriteSpool(readSpool().filter(e => !flushedIds.has(e.eventId)));
457
478
  return body.data || { accepted: batch.length, deduped: 0 };
458
479
  }
459
- catch {
480
+ catch (error) {
481
+ lastFlushFailure = { kind: 'network', error: error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200) };
460
482
  return null; // keep the spool intact for the next attempt (offline-safe)
461
483
  }
462
484
  }
package/dist/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "1.36.2"
2
+ "version": "1.36.3"
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fullcourtdefense-cli",
3
- "version": "1.36.2",
3
+ "version": "1.36.3",
4
4
  "description": "Full Court Defense CLI — security scanning for AI agents from your terminal",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -72,6 +72,7 @@
72
72
  "test:scan-root-compaction": "npm run build && node scripts/test-scan-root-compaction.js",
73
73
  "test:dpapi-config": "npm run build && node scripts/test-dpapi-config.js",
74
74
  "test:distress-ledger": "npm run build && node scripts/test-distress-ledger.js",
75
+ "test:machine-identity": "npm run build && node scripts/test-machine-identity.js",
75
76
  "test:poll-loop": "npm run build && node scripts/test-poll-loop-resilience.js && node scripts/test-background-bundle.js && node scripts/test-policy-refresh.js",
76
77
  "test:slim-hook": "npm run build && node scripts/test-slim-hook.js",
77
78
  "test:killswitch": "npm run build && node scripts/test-killswitch-integrity.js",