fullcourtdefense-cli 1.7.11 → 1.7.13

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.
@@ -1096,7 +1096,7 @@ function compactScanHtml(args) {
1096
1096
  h1 { margin: 6px 0 8px; font-size: 26px; line-height: 1.15; }
1097
1097
  p { color: #475569; line-height: 1.55; }
1098
1098
  .grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
1099
- .menuShell { display: grid; grid-template-columns: minmax(180px, 1fr) minmax(0, 3fr) minmax(160px, .85fr); gap: 14px; margin-top: 18px; align-items: stretch; }
1099
+ .menuShell { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1.15fr) minmax(180px, .7fr); gap: 14px; margin-top: 18px; align-items: stretch; }
1100
1100
  .menuGroup { border: 1px solid #dbeafe; background: rgba(255,255,255,.7); border-radius: 20px; padding: 12px; }
1101
1101
  .menuGroup.run { border-color: #bbf7d0; background: #f0fdf4; }
1102
1102
  .menuLabel { color: #475569; font-size: 11px; font-weight: 900; letter-spacing: .08em; text-transform: uppercase; margin: 0 0 9px; }
@@ -1108,6 +1108,11 @@ function compactScanHtml(args) {
1108
1108
  .sectionTitle h2 { margin: 0; font-size: 18px; }
1109
1109
  .muted { color: #64748b; font-size: 13px; }
1110
1110
  .card { cursor: pointer; border: 2px solid #e2e8f0; background: white; border-radius: 18px; padding: 16px; text-align: left; transition: .15s ease; }
1111
+ .workflowCard { min-height: 118px; }
1112
+ .workflowCard b { font-size: 18px; }
1113
+ .workflowCard span { font-size: 13px; }
1114
+ .scanTypeGrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 12px 0; }
1115
+ .advancedScanGrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 8px 0 12px; }
1111
1116
  .card:hover, .card.active { border-color: #2563eb; background: #eff6ff; transform: translateY(-1px); }
1112
1117
  .card b { display: block; font-size: 14px; margin-bottom: 4px; }
1113
1118
  .card span { color: #64748b; font-size: 12px; line-height: 1.35; }
@@ -1157,8 +1162,8 @@ function compactScanHtml(args) {
1157
1162
  <main class="wrap">
1158
1163
  <section class="hero">
1159
1164
  <div class="eyebrow">Local Web Console</div>
1160
- <h1>Run local MCP tools or scan internal AI targets</h1>
1161
- <p>This compact browser UI is served by the CLI on 127.0.0.1. One-off MCP tool runs stay local in this page. Red-team scans run locally too, while Shield verdicts and saved reports go outbound to Full Court Defense.</p>
1165
+ <h1>Choose a local workflow</h1>
1166
+ <p>Pick one clear path. Run MCP Tool is a one-off tool call. Security Scan is a red-team scan against an internal endpoint, RAG target, or MCP server.</p>
1162
1167
  <div class="auth">
1163
1168
  <div class="eyebrow">${isConfigured ? 'Authenticated' : 'Authentication Required'}</div>
1164
1169
  <p id="authStatus">${isConfigured
@@ -1181,7 +1186,7 @@ function compactScanHtml(args) {
1181
1186
  </div>
1182
1187
  <div class="note" id="backendStatus">Backend status: not checked yet.</div>
1183
1188
  </div>
1184
- <div class="steps">
1189
+ <div class="steps" id="scanSteps">
1185
1190
  <div class="step active" id="step-dot-1">1. Connect target</div>
1186
1191
  <div class="step" id="step-dot-2">2. Select scan type</div>
1187
1192
  <div class="step" id="step-dot-3">3. Run red-team scan</div>
@@ -1189,19 +1194,15 @@ function compactScanHtml(args) {
1189
1194
  <div class="menuShell" id="cards">
1190
1195
  <div class="menuGroup run">
1191
1196
  <div class="menuLabel">Run, not a scan</div>
1192
- <button class="card active" data-target="runner"><b>Run MCP Tool</b><span>Call one tool through a local MCP server or protected gateway.</span></button>
1197
+ <button class="card workflowCard active" data-workflow="runner"><b>Run one MCP tool</b><span>Call exactly one local MCP tool through a direct server or protected gateway. Best for demos and policy checks.</span></button>
1193
1198
  </div>
1194
1199
  <div class="menuGroup">
1195
1200
  <div class="menuLabel">Security scans</div>
1196
- <div class="grid">
1197
- <button class="card" data-target="endpoint"><b>Endpoint Scan</b><span>Red-team an internal agent/chat API.</span></button>
1198
- <button class="card" data-target="rag"><b>RAG Scan</b><span>Test retrieval URL or local corpus path.</span></button>
1199
- <button class="card" data-target="mcp"><b>MCP Scan</b><span>Scan tool responses and tool-abuse paths.</span></button>
1200
- </div>
1201
+ <button class="card workflowCard" data-workflow="scan"><b>Start security scan</b><span>Run quick or full red-team tests against Endpoint, RAG, or MCP targets. Reports save to Full Court Defense.</span></button>
1201
1202
  </div>
1202
1203
  <div class="menuGroup">
1203
1204
  <div class="menuLabel">Help</div>
1204
- <button class="card" data-target="help"><b>Options</b><span>Modes, formats, and when to use each local workflow.</span></button>
1205
+ <button class="card workflowCard" data-workflow="help"><b>Options</b><span>Modes, formats, and when to use each local workflow.</span></button>
1205
1206
  </div>
1206
1207
  </div>
1207
1208
  </section>
@@ -1210,8 +1211,8 @@ function compactScanHtml(args) {
1210
1211
  <div id="step-1" class="stepSection">
1211
1212
  <div class="sectionTitle">
1212
1213
  <div>
1213
- <h2>Connect target</h2>
1214
- <div class="muted">Choose Run MCP Tool for a single action, or choose a scan target for red-team testing.</div>
1214
+ <h2 id="connectTitle">Run MCP Tool</h2>
1215
+ <div class="muted" id="connectSubtitle">Call one MCP tool from this machine. This is not a scan.</div>
1215
1216
  </div>
1216
1217
  </div>
1217
1218
  <div id="runner-fields">
@@ -1223,11 +1224,11 @@ function compactScanHtml(args) {
1223
1224
  <div class="two">
1224
1225
  <div>
1225
1226
  <label>Protected MCP HTTP/SSE URL</label>
1226
- <input id="runnerMcpUrl" placeholder="http://127.0.0.1:5066/mcp" />
1227
+ <input id="runnerMcpUrl" placeholder="Optional: http://127.0.0.1:5066/mcp" />
1227
1228
  </div>
1228
1229
  <div>
1229
1230
  <label>Tool name</label>
1230
- <input id="runnerTool" placeholder="lookup_customer" />
1231
+ <input id="runnerTool" placeholder="Example: lookup_customer_profile" />
1231
1232
  </div>
1232
1233
  </div>
1233
1234
  <div class="two">
@@ -1241,12 +1242,12 @@ function compactScanHtml(args) {
1241
1242
  </div>
1242
1243
  </div>
1243
1244
  <div class="two">
1244
- <div><label>Or stdio command</label><input id="runnerMcpCommand" placeholder="fullcourtdefense" /></div>
1245
- <div><label>Command args</label><input id="runnerMcpArgs" placeholder='mcp-gateway --mcp-command node --mcp-args "[&quot;./server.js&quot;]"' /></div>
1245
+ <div><label>Or stdio command</label><input id="runnerMcpCommand" placeholder="node" /></div>
1246
+ <div><label>Command args</label><input id="runnerMcpArgs" placeholder="C:\\path\\to\\mcp-server.js" /></div>
1246
1247
  </div>
1247
1248
  <label>Tool arguments JSON</label>
1248
1249
  <textarea id="runnerToolArgs" spellcheck="false">{
1249
- "customerId": "cus_123"
1250
+ "customerId": "RO-PB-10492"
1250
1251
  }</textarea>
1251
1252
  <div class="actions">
1252
1253
  <button class="primary" id="runMcpTool">Run MCP tool</button>
@@ -1265,6 +1266,19 @@ function compactScanHtml(args) {
1265
1266
  </div>
1266
1267
  </div>
1267
1268
 
1269
+ <div id="scan-picker" class="hidden">
1270
+ <div class="note">Security scans run red-team templates locally from this machine. First choose what you want to test.</div>
1271
+ <div class="scanTypeGrid">
1272
+ <button class="card scanTypeCard active" data-target="endpoint"><b>Bot Scan</b><span>Red-team an internal bot, agent, or chat API with prompt-injection templates.</span></button>
1273
+ <button class="card scanTypeCard" data-target="posture"><b>Security Posture Scan</b><span>Run the web-style checkup for HTTPS, headers, auth exposure, and endpoint posture.</span></button>
1274
+ </div>
1275
+ <div class="menuLabel">Advanced local targets</div>
1276
+ <div class="advancedScanGrid">
1277
+ <button class="card scanTypeCard" data-target="rag"><b>RAG Scan</b><span>Test retrieval URL or local corpus path.</span></button>
1278
+ <button class="card scanTypeCard" data-target="mcp"><b>MCP Scan</b><span>Scan tool responses and tool-abuse paths.</span></button>
1279
+ </div>
1280
+ </div>
1281
+
1268
1282
  <div id="endpoint-fields" class="hidden">
1269
1283
  <label>Internal endpoint URL</label>
1270
1284
  <input id="endpoint" placeholder="http://127.0.0.1:3000/chat" />
@@ -1274,6 +1288,30 @@ function compactScanHtml(args) {
1274
1288
  </div>
1275
1289
  </div>
1276
1290
 
1291
+ <div id="posture-fields" class="hidden">
1292
+ <div class="note">Security Posture Scan checks endpoint configuration, auth exposure, headers, transport, and operational security signals. This matches the web Security Checkup flow.</div>
1293
+ <div class="two">
1294
+ <div>
1295
+ <label>AI endpoint URL</label>
1296
+ <input id="postureUrl" placeholder="https://your-ai-endpoint.com/api/chat" />
1297
+ </div>
1298
+ <div>
1299
+ <label>HTTP method</label>
1300
+ <select id="postureMethod"><option value="POST" selected>POST</option><option value="GET">GET</option></select>
1301
+ </div>
1302
+ </div>
1303
+ <div class="two">
1304
+ <div>
1305
+ <label>Auth type</label>
1306
+ <select id="postureAuthType"><option value="none" selected>No Auth</option><option value="bearer">Bearer Token</option><option value="api-key">API Key</option></select>
1307
+ </div>
1308
+ <div>
1309
+ <label>Token / API key value</label>
1310
+ <input id="postureToken" type="password" placeholder="Optional" />
1311
+ </div>
1312
+ </div>
1313
+ </div>
1314
+
1277
1315
  <div id="rag-fields" class="hidden">
1278
1316
  <label>RAG retrieval URL</label>
1279
1317
  <input id="ragUrl" placeholder="http://127.0.0.1:8787/rag/retrieve" />
@@ -1361,25 +1399,42 @@ function compactScanHtml(args) {
1361
1399
  <b>Red-team console</b>
1362
1400
  <span class="pill" id="consoleStatus">Ready</span>
1363
1401
  </div>
1364
- <pre id="out">Full Court Defense Local Runner ready.
1402
+ <pre id="out">Full Court Defense Local Web Console ready.
1365
1403
 
1366
- Select Endpoint, RAG, or MCP above, then run a scan.
1367
- Quick uses the same critical/high attack selection as the web scanner.
1368
- Full uses the full web attack corpus bundled with the CLI.</pre>
1404
+ Choose Run MCP Tool for one live tool call.
1405
+ Choose Endpoint/RAG/MCP Scan for a local red-team scan.
1406
+ Local targets stay on this machine; saved scan reports go to Full Court Defense.</pre>
1369
1407
  </div>
1370
1408
  </div>
1371
1409
  </section>
1372
1410
  </main>
1373
1411
  <script>
1412
+ const scanTargets = ['endpoint','posture','rag','mcp'];
1374
1413
  let target = 'runner';
1375
1414
  let step = 1;
1376
1415
  const qs = new URLSearchParams(location.search);
1377
- if (['runner','endpoint','rag','mcp'].includes(qs.get('target'))) target = qs.get('target');
1416
+ if (['runner','endpoint','posture','rag','mcp','help'].includes(qs.get('target'))) target = qs.get('target');
1378
1417
  const byId = id => document.getElementById(id);
1418
+ const workflow = () => scanTargets.includes(target) ? 'scan' : target;
1379
1419
  const sync = () => {
1380
- document.querySelectorAll('.card').forEach(c => c.classList.toggle('active', c.dataset.target === target));
1381
- ['runner','endpoint','rag','mcp','help'].forEach(id => byId(id + '-fields').classList.toggle('hidden', id !== target));
1382
- byId('scanActions').classList.toggle('hidden', target === 'runner');
1420
+ document.querySelectorAll('.workflowCard').forEach(c => c.classList.toggle('active', c.dataset.workflow === workflow()));
1421
+ document.querySelectorAll('.scanTypeCard').forEach(c => c.classList.toggle('active', c.dataset.target === target));
1422
+ ['runner','endpoint','posture','rag','mcp','help'].forEach(id => byId(id + '-fields').classList.toggle('hidden', id !== target));
1423
+ const scanTarget = scanTargets.includes(target);
1424
+ byId('scan-picker').classList.toggle('hidden', !scanTarget);
1425
+ byId('scanSteps').classList.toggle('hidden', !scanTarget);
1426
+ byId('scanActions').classList.toggle('hidden', !scanTarget);
1427
+ byId('connectTitle').textContent = target === 'runner'
1428
+ ? 'Run MCP Tool'
1429
+ : target === 'help'
1430
+ ? 'Local workflow options'
1431
+ : 'Choose scan target';
1432
+ byId('connectSubtitle').textContent = target === 'runner'
1433
+ ? 'Call one MCP tool from this machine. This is not a scan.'
1434
+ : target === 'help'
1435
+ ? 'Choose one-off tool run or local red-team scan.'
1436
+ : 'Select Endpoint, RAG, or MCP, then connect the internal target.';
1437
+ if (!scanTarget) setStep(1);
1383
1438
  };
1384
1439
  const setStep = next => {
1385
1440
  step = next;
@@ -1389,7 +1444,14 @@ Full uses the full web attack corpus bundled with the CLI.</pre>
1389
1444
  byId('step-dot-' + n).classList.toggle('done', n < step);
1390
1445
  });
1391
1446
  };
1392
- document.querySelectorAll('.card').forEach(c => c.onclick = () => { target = c.dataset.target; sync(); });
1447
+ document.querySelectorAll('.workflowCard').forEach(c => c.onclick = () => {
1448
+ target = c.dataset.workflow === 'scan' ? 'endpoint' : c.dataset.workflow;
1449
+ sync();
1450
+ });
1451
+ document.querySelectorAll('.scanTypeCard').forEach(c => c.onclick = () => {
1452
+ target = c.dataset.target;
1453
+ sync();
1454
+ });
1393
1455
  sync();
1394
1456
  byId('ragUrl').value = qs.get('ragUrl') || '';
1395
1457
  byId('ragPath').value = qs.get('ragPath') || '';
@@ -1398,13 +1460,14 @@ Full uses the full web attack corpus bundled with the CLI.</pre>
1398
1460
  byId('mcpCommand').value = qs.get('mcpCommand') || '';
1399
1461
  byId('mcpArgs').value = qs.get('mcpArgs') || '';
1400
1462
  byId('runnerMcpUrl').value = qs.get('mcpUrl') || '';
1401
- byId('runnerMcpCommand').value = qs.get('mcpCommand') || 'fullcourtdefense';
1463
+ byId('runnerMcpCommand').value = qs.get('mcpCommand') || '';
1402
1464
  byId('runnerMcpArgs').value = qs.get('mcpArgs') || '';
1403
1465
  byId('runnerTool').value = qs.get('mcpTool') || '';
1404
1466
  byId('runnerOperation').value = qs.get('operation') || '';
1405
1467
  const payload = () => ({
1406
1468
  target, mode: byId('mode').value, format: byId('format').value,
1407
1469
  endpoint: byId('endpoint').value, inputField: byId('inputField').value, outputField: byId('outputField').value,
1470
+ postureUrl: byId('postureUrl').value, postureMethod: byId('postureMethod').value, postureAuthType: byId('postureAuthType').value, postureToken: byId('postureToken').value,
1408
1471
  ragUrl: byId('ragUrl').value, ragPath: byId('ragPath').value, ragInputField: byId('ragInputField').value, ragOutputField: byId('ragOutputField').value,
1409
1472
  mcpUrl: byId('mcpUrl').value, mcpCommand: byId('mcpCommand').value, mcpArgs: byId('mcpArgs').value, mcpTool: byId('mcpTool').value
1410
1473
  });
@@ -1440,6 +1503,7 @@ Full uses the full web attack corpus bundled with the CLI.</pre>
1440
1503
  const renderCommand = p => {
1441
1504
  const parts = ['fullcourtdefense scan --local --type', p.target, '--mode', p.mode, '--format', p.format, '--no-open'];
1442
1505
  if (p.target === 'endpoint') parts.push('--endpoint', JSON.stringify(p.endpoint), '--method POST --request-format custom --input-field', p.inputField || 'message', '--output-field', p.outputField || 'response');
1506
+ if (p.target === 'posture') return 'Security Posture Scan runs through this local web UI and calls the Full Court Defense posture checkup API for ' + (p.postureUrl || '<endpoint-url>');
1443
1507
  if (p.target === 'rag') { if (p.ragUrl) parts.push('--rag-url', JSON.stringify(p.ragUrl), '--method POST --request-format custom --input-field', p.ragInputField || 'query', '--output-field', p.ragOutputField || 'chunks'); else parts.push('--rag-path', JSON.stringify(p.ragPath || '.\\\\docs')); }
1444
1508
  if (p.target === 'mcp') { if (p.mcpUrl) parts.push('--mcp-url', JSON.stringify(p.mcpUrl)); else parts.push('--mcp-command', p.mcpCommand || 'node', '--mcp-args', JSON.stringify(p.mcpArgs || '.\\\\server.js')); parts.push('--mcp-tool', p.mcpTool || 'all'); }
1445
1509
  return parts.join(' ');
@@ -1495,6 +1559,10 @@ Full uses the full web attack corpus bundled with the CLI.</pre>
1495
1559
  sync();
1496
1560
  setStep(1);
1497
1561
  byId('endpoint').value = '';
1562
+ byId('postureUrl').value = '';
1563
+ byId('postureMethod').value = 'POST';
1564
+ byId('postureAuthType').value = 'none';
1565
+ byId('postureToken').value = '';
1498
1566
  byId('inputField').value = 'message';
1499
1567
  byId('outputField').value = 'response';
1500
1568
  byId('ragUrl').value = '';
@@ -1506,18 +1574,18 @@ Full uses the full web attack corpus bundled with the CLI.</pre>
1506
1574
  byId('mcpArgs').value = '';
1507
1575
  byId('mcpTool').value = 'all';
1508
1576
  byId('runnerMcpUrl').value = '';
1509
- byId('runnerMcpCommand').value = 'fullcourtdefense';
1577
+ byId('runnerMcpCommand').value = '';
1510
1578
  byId('runnerMcpArgs').value = '';
1511
1579
  byId('runnerTool').value = '';
1512
1580
  byId('runnerOperation').value = '';
1513
- byId('runnerToolArgs').value = '{\\n "customerId": "cus_123"\\n}';
1581
+ byId('runnerToolArgs').value = '{\\n "customerId": "RO-PB-10492"\\n}';
1514
1582
  byId('mcpResultCard').classList.add('hidden');
1515
1583
  byId('mcpResultJson').value = '';
1516
1584
  byId('mcpResultTable').innerHTML = '';
1517
1585
  byId('mode').value = 'quick';
1518
1586
  byId('format').value = 'report';
1519
1587
  clearScanSummary();
1520
- setConsole('Full Court Defense Local Runner ready.\\n\\nSelect Endpoint, RAG, or MCP above, then run a scan.\\nQuick uses the same critical/high attack selection as the web scanner.\\nFull uses the full web attack corpus bundled with the CLI.', 'Ready');
1588
+ setConsole('Full Court Defense Local Web Console ready.\\n\\nChoose Run MCP Tool for one live tool call.\\nChoose Endpoint/RAG/MCP Scan for a local red-team scan.', 'Ready');
1521
1589
  };
1522
1590
  byId('command').onclick = () => { setConsole(renderCommand(payload()), 'Command'); };
1523
1591
  byId('connectNext').onclick = () => setStep(2);
@@ -1699,6 +1767,20 @@ Full uses the full web attack corpus bundled with the CLI.</pre>
1699
1767
  byId('run').textContent = 'Run local scan';
1700
1768
  return;
1701
1769
  }
1770
+ if (target === 'posture') {
1771
+ try {
1772
+ setConsole('Starting Security Posture Scan...\\n', 'Running posture');
1773
+ const postureRes = await fetch('/posture/run', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload()) });
1774
+ const postureData = await postureRes.json();
1775
+ setConsole(JSON.stringify(postureData, null, 2), postureData.ok ? 'Posture complete' : 'Posture failed');
1776
+ } catch (error) {
1777
+ setConsole('Security Posture Scan failed: ' + (error && error.message ? error.message : String(error)), 'Posture failed');
1778
+ } finally {
1779
+ byId('run').disabled = false;
1780
+ byId('run').textContent = 'Run local scan';
1781
+ }
1782
+ return;
1783
+ }
1702
1784
  setConsole('Starting local red-team scan...\\n', 'Running');
1703
1785
  const res = await fetch('/run', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload()) });
1704
1786
  if (!res.body) {
@@ -1811,6 +1893,40 @@ async function runCliFromBrowser(body, onChunk) {
1811
1893
  });
1812
1894
  });
1813
1895
  }
1896
+ async function runPostureScanFromBrowser(args, body) {
1897
+ const auth = currentShieldConfig(args);
1898
+ const apiUrl = (auth.apiUrl || DEFAULT_API_URL).replace(/\/$/, '');
1899
+ const endpoint = typeof body.postureUrl === 'string' ? body.postureUrl.trim() : '';
1900
+ const method = body.postureMethod === 'GET' ? 'GET' : 'POST';
1901
+ const authType = typeof body.postureAuthType === 'string' ? body.postureAuthType : 'none';
1902
+ const token = typeof body.postureToken === 'string' ? body.postureToken.trim() : '';
1903
+ if (!endpoint)
1904
+ throw new Error('AI endpoint URL is required for Security Posture Scan.');
1905
+ const headers = {};
1906
+ if (authType === 'bearer' && token)
1907
+ headers.Authorization = `Bearer ${token}`;
1908
+ if (authType === 'api-key' && token)
1909
+ headers['X-API-Key'] = token;
1910
+ const response = await fetch(`${apiUrl}/api/posture/scan/public`, {
1911
+ method: 'POST',
1912
+ headers: { 'content-type': 'application/json' },
1913
+ body: JSON.stringify({
1914
+ endpoint,
1915
+ method,
1916
+ scanMode: 'passive',
1917
+ ...(Object.keys(headers).length ? { headers } : {}),
1918
+ }),
1919
+ signal: AbortSignal.timeout(60000),
1920
+ });
1921
+ const text = await response.text();
1922
+ return {
1923
+ ok: response.ok,
1924
+ status: response.status,
1925
+ endpoint,
1926
+ scanType: 'security_posture',
1927
+ result: text,
1928
+ };
1929
+ }
1814
1930
  function createMcpClient(options) {
1815
1931
  if (options.transport === 'sse')
1816
1932
  return new SseMcpClient(options);
@@ -1977,6 +2093,13 @@ function startCompactWebServer(args) {
1977
2093
  res.end(JSON.stringify(result));
1978
2094
  return;
1979
2095
  }
2096
+ if (req.method === 'POST' && url.pathname === '/posture/run') {
2097
+ const body = await readRequestBody(req);
2098
+ const result = await runPostureScanFromBrowser(args, body);
2099
+ res.writeHead(result.ok ? 200 : 400, { 'content-type': 'application/json; charset=utf-8' });
2100
+ res.end(JSON.stringify(result));
2101
+ return;
2102
+ }
1980
2103
  if (req.method === 'POST' && url.pathname === '/run') {
1981
2104
  const body = await readRequestBody(req);
1982
2105
  res.writeHead(200, {
package/dist/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "1.7.11"
2
+ "version": "1.7.13"
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fullcourtdefense-cli",
3
- "version": "1.7.11",
3
+ "version": "1.7.13",
4
4
  "description": "Full Court Defense CLI — security scanning for AI agents from your terminal",
5
5
  "main": "dist/index.js",
6
6
  "bin": {