blitzstrike 2.4.10 → 2.4.12

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/CHANGELOG.md CHANGED
@@ -5,6 +5,30 @@ All notable changes to Blitz Strike are documented here.
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [2.4.12] — 2026-09-14
9
+
10
+ ### Improved — install-tools failure diagnostics
11
+
12
+ - `install-tools` now reports the REASON for every failed tool (last stderr/stdout
13
+ lines) instead of a bare `Failed: …` list.
14
+ - Preflight reports missing toolchains (go/java/python/cargo/meson/ninja/make/gcc)
15
+ + the `apt install` line to fix them before the mass install.
16
+ - Per-tool install budget raised 120s → 300s so cold-cache `go install` /
17
+ `pip install` of large tools (nuclei, amass, httpx, metasploit, …) no longer
18
+ time out.
19
+
20
+ ## [2.4.11] — 2026-09-14
21
+
22
+ ### Fixed — bulk-install no longer pollutes the caller's cwd
23
+
24
+ - `install-tools` / `install_all_tools` now run every install command in a fixed
25
+ tools directory (`~/.blitzstrike/tools`, override `BLITZSTRIKE_TOOLS_DIR`), so
26
+ `git clone`-style tools (massdns, phpggc, radare2, testssl.sh, …) no longer
27
+ land in whatever directory you happened to run from.
28
+ - Added those cloned tool dirs to `.gitignore`.
29
+ - `blitzstrike install` now prints a hint pointing to `blitzstrike install-tools`
30
+ for the full 140-tool catalog.
31
+
8
32
  ## [2.4.10] — 2026-09-14
9
33
 
10
34
  ### Added — auto-install external MCP servers to every agent
package/dist/index.js CHANGED
@@ -7398,9 +7398,10 @@ function h1Username() {
7398
7398
  }
7399
7399
 
7400
7400
  // src/catalog.ts
7401
- import { readFileSync as readFileSync6, readdirSync as readdirSync2 } from "node:fs";
7401
+ import { readFileSync as readFileSync6, readdirSync as readdirSync2, mkdirSync as mkdirSync3 } from "node:fs";
7402
7402
  import { join as join6 } from "node:path";
7403
7403
  import { fileURLToPath as fileURLToPath3 } from "node:url";
7404
+ import { homedir as homedir3 } from "node:os";
7404
7405
  import { spawnSync, spawn } from "node:child_process";
7405
7406
  function loadTools() {
7406
7407
  if (_toolsCache)
@@ -7517,7 +7518,8 @@ function ensureTool(name) {
7517
7518
  if (!cmd) {
7518
7519
  return { name: t.name, installed: false, action: "none", note: `no install command for ${platform}` };
7519
7520
  }
7520
- const r = spawnSync(cmd, { shell: true, timeout: 120000 });
7521
+ mkdirSync3(TOOLS_DIR, { recursive: true });
7522
+ const r = spawnSync(cmd, { shell: true, timeout: 300000, cwd: TOOLS_DIR });
7521
7523
  const ok = r.status === 0;
7522
7524
  return {
7523
7525
  name: t.name,
@@ -7597,7 +7599,7 @@ function runCatalogTool(hint, target, extraFlags = []) {
7597
7599
  output: out.slice(0, 6000)
7598
7600
  };
7599
7601
  }
7600
- function ensureToolAsync(name, timeoutMs = 120000) {
7602
+ function ensureToolAsync(name, timeoutMs = 300000) {
7601
7603
  return new Promise((resolve) => {
7602
7604
  const t = loadTools().find((x) => x.name.toLowerCase() === name.toLowerCase());
7603
7605
  if (!t) {
@@ -7616,7 +7618,8 @@ function ensureToolAsync(name, timeoutMs = 120000) {
7616
7618
  resolve({ name: t.name, installed: false, action: "none", note: "no install command for this platform" });
7617
7619
  return;
7618
7620
  }
7619
- const inst = spawn(cmd, { shell: true, timeout: timeoutMs });
7621
+ mkdirSync3(TOOLS_DIR, { recursive: true });
7622
+ const inst = spawn(cmd, { shell: true, timeout: timeoutMs, cwd: TOOLS_DIR });
7620
7623
  let out = "";
7621
7624
  inst.stdout?.on("data", (d) => {
7622
7625
  out += d.toString();
@@ -7661,10 +7664,11 @@ async function installAllTools(opts = {}) {
7661
7664
  results
7662
7665
  };
7663
7666
  }
7664
- var ROOT2, _toolsCache = null, _skillsCache = null;
7667
+ var ROOT2, TOOLS_DIR, _toolsCache = null, _skillsCache = null;
7665
7668
  var init_catalog = __esm(() => {
7666
7669
  init_manuals();
7667
7670
  ROOT2 = join6(fileURLToPath3(new URL(".", import.meta.url)), "..");
7671
+ TOOLS_DIR = process.env.BLITZSTRIKE_TOOLS_DIR ?? join6(homedir3(), ".blitzstrike", "tools");
7668
7672
  });
7669
7673
 
7670
7674
  // src/burp-mcp.ts
@@ -15412,9 +15416,9 @@ async function checkMcpServers() {
15412
15416
  var init_mcp_status = () => {};
15413
15417
 
15414
15418
  // src/sync.ts
15415
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync6, readFileSync as readFileSync18, readdirSync as readdirSync7, statSync as statSync4, rmSync as rmSync4 } from "node:fs";
15419
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6, readFileSync as readFileSync18, readdirSync as readdirSync7, statSync as statSync4, rmSync as rmSync4 } from "node:fs";
15416
15420
  import { join as join16 } from "node:path";
15417
- import { homedir as homedir5 } from "node:os";
15421
+ import { homedir as homedir6 } from "node:os";
15418
15422
  import { fileURLToPath as fileURLToPath9 } from "node:url";
15419
15423
  import { spawnSync as spawnSync4 } from "node:child_process";
15420
15424
  function dirExists(p) {
@@ -15443,7 +15447,7 @@ function countFiles(dir) {
15443
15447
  }
15444
15448
  function syncData() {
15445
15449
  if (!dirExists(DATA_ROOT2))
15446
- mkdirSync4(DATA_ROOT2, { recursive: true });
15450
+ mkdirSync5(DATA_ROOT2, { recursive: true });
15447
15451
  const payloadsPath = join16(DATA_ROOT2, "payloads");
15448
15452
  const templatesPath = join16(DATA_ROOT2, "templates");
15449
15453
  const hasPayloads = dirExists(payloadsPath) && countFiles(payloadsPath) > 0;
@@ -15501,7 +15505,7 @@ function copyDir(src, dst) {
15501
15505
  }
15502
15506
  }
15503
15507
  function manualCopy(src, dst) {
15504
- mkdirSync4(dst, { recursive: true });
15508
+ mkdirSync5(dst, { recursive: true });
15505
15509
  for (const e of readdirSync7(src, { withFileTypes: true })) {
15506
15510
  const s = join16(src, e.name);
15507
15511
  const d = join16(dst, e.name);
@@ -15514,7 +15518,7 @@ function manualCopy(src, dst) {
15514
15518
  var ROOT7, DATA_ROOT2, GITHUB_REPO = "https://github.com/shinthink/blitzstrike.git";
15515
15519
  var init_sync = __esm(() => {
15516
15520
  ROOT7 = join16(fileURLToPath9(new URL(".", import.meta.url)), "..");
15517
- DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ?? join16(homedir5(), ".blitzstrike", "data");
15521
+ DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ?? join16(homedir6(), ".blitzstrike", "data");
15518
15522
  });
15519
15523
 
15520
15524
  // src/update.ts
@@ -15641,9 +15645,9 @@ var init_dependency = __esm(() => {
15641
15645
  });
15642
15646
 
15643
15647
  // src/cli.ts
15644
- import { readFileSync as readFileSync22, existsSync as existsSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync5 } from "node:fs";
15648
+ import { readFileSync as readFileSync22, existsSync as existsSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6 } from "node:fs";
15645
15649
  import { join as join19, dirname as dirname2 } from "node:path";
15646
- import { homedir as homedir6 } from "node:os";
15650
+ import { homedir as homedir7 } from "node:os";
15647
15651
  import { fileURLToPath as fileURLToPath12 } from "node:url";
15648
15652
  import { spawnSync as spawnSync5 } from "node:child_process";
15649
15653
  function which(cmd) {
@@ -15761,7 +15765,7 @@ function jsonMcpServersWrite(p) {
15761
15765
  return (command, args) => {
15762
15766
  const dir = dirname2(p);
15763
15767
  if (!existsSync11(dir))
15764
- mkdirSync5(dir, { recursive: true });
15768
+ mkdirSync6(dir, { recursive: true });
15765
15769
  const existing = readJson(p) ?? {};
15766
15770
  existing.mcpServers = {
15767
15771
  ...existing.mcpServers ?? {},
@@ -15774,7 +15778,7 @@ function opencodeWrite(p) {
15774
15778
  return (command, args) => {
15775
15779
  const dir = dirname2(p);
15776
15780
  if (!existsSync11(dir))
15777
- mkdirSync5(dir, { recursive: true });
15781
+ mkdirSync6(dir, { recursive: true });
15778
15782
  const existing = readJson(p) ?? {};
15779
15783
  existing.mcp = {
15780
15784
  ...existing.mcp ?? {},
@@ -15786,11 +15790,11 @@ function opencodeWrite(p) {
15786
15790
  }
15787
15791
  function copyOpenCodeAgents() {
15788
15792
  const srcDir = join19(ROOT10, "opencode-agents");
15789
- const dstDir = join19(homedir6(), ".config", "opencode", "agents");
15793
+ const dstDir = join19(homedir7(), ".config", "opencode", "agents");
15790
15794
  if (!existsSync11(srcDir))
15791
15795
  return;
15792
15796
  if (!existsSync11(dstDir))
15793
- mkdirSync5(dstDir, { recursive: true });
15797
+ mkdirSync6(dstDir, { recursive: true });
15794
15798
  for (const f of ["Blitz Strike.md", "Blitz.md", "Eagle Eye.md", "Strike.md"]) {
15795
15799
  const src = join19(srcDir, f);
15796
15800
  const dst = join19(dstDir, f);
@@ -15803,7 +15807,7 @@ function codexWrite(p) {
15803
15807
  return (command, args) => {
15804
15808
  const dir = dirname2(p);
15805
15809
  if (!existsSync11(dir))
15806
- mkdirSync5(dir, { recursive: true });
15810
+ mkdirSync6(dir, { recursive: true });
15807
15811
  let existing = existsSync11(p) ? readFileSync22(p, "utf8") : "";
15808
15812
  if (!existing.trimEnd().endsWith(`
15809
15813
  `))
@@ -15822,7 +15826,7 @@ function hermesWrite(p) {
15822
15826
  return (command, args) => {
15823
15827
  const dir = dirname2(p);
15824
15828
  if (!existsSync11(dir))
15825
- mkdirSync5(dir, { recursive: true });
15829
+ mkdirSync6(dir, { recursive: true });
15826
15830
  let existing = existsSync11(p) ? readFileSync22(p, "utf8") : "";
15827
15831
  existing = existing.replace(/^ blitzstrike:\n(?: .*\n?)*/m, "");
15828
15832
  if (!existing.trimEnd().endsWith(`
@@ -15848,7 +15852,7 @@ mcp_servers:
15848
15852
  };
15849
15853
  }
15850
15854
  function detectAgents() {
15851
- const home = homedir6();
15855
+ const home = homedir7();
15852
15856
  const agents = [];
15853
15857
  const claudeJson = join19(home, ".claude.json");
15854
15858
  agents.push({
@@ -15963,6 +15967,8 @@ External MCP servers:`);
15963
15967
  const devtools = ensureTool("chrome-devtools-mcp");
15964
15968
  console.log(` ${devtools.installed ? "OK " : "FAIL"} chrome-devtools-mcp ${devtools.installed ? "installed (browser MCP ready for all agents)" : devtools.command ?? "install failed"}`);
15965
15969
  console.log(` SKIP burp-suite-mcp GUI/daemon — build manually (PortSwigger/mcp-server) + load in Burp (connect, not install)`);
15970
+ console.log(`
15971
+ To install ALL 140 catalog tools (139 CLI + chrome-devtools-mcp), run: blitzstrike install-tools`);
15966
15972
  }
15967
15973
  async function runInstallTools(args) {
15968
15974
  const getArg = (flag) => {
@@ -15989,15 +15995,32 @@ async function runInstallTools(args) {
15989
15995
  }
15990
15996
  console.log(`Installing catalog tools${category ? ` (category: ${category})` : ""} — concurrency ${concurrency}
15991
15997
  `);
15998
+ const chainMap = { go: "golang", java: "default-jdk", python3: "python3", pip3: "python3-pip", cargo: "cargo", make: "build-essential", meson: "meson", ninja: "ninja-build", gcc: "build-essential", git: "git" };
15999
+ const missingChains = Object.keys(chainMap).filter((c) => spawnSync5(`command -v ${c}`, { shell: true }).status !== 0);
16000
+ if (missingChains.length) {
16001
+ console.log(`⚠ Missing toolchains: ${missingChains.join(", ")} (${missingChains.map((c) => chainMap[c]).join(", ")})`);
16002
+ console.log(` Tools that need them will FAIL below. Install first, e.g.:
16003
+ apt install -y ${missingChains.map((c) => chainMap[c]).join(" ")}
16004
+ `);
16005
+ }
15992
16006
  const r = await installAllTools({ category, concurrency, onProgress: (name, ok) => console.log(` ${ok ? "OK " : "FAIL"} ${name}`) });
15993
16007
  console.log(`
15994
16008
  Summary: ${r.target_count} targets · ${r.installed} newly installed · ${r.already_installed} already present · ${r.failed} failed`);
15995
16009
  const mcp = r.skipped_mcp_servers;
15996
16010
  if (mcp.length)
15997
16011
  console.log(`Skipped MCP servers (connect them): ${mcp.join(", ")}`);
15998
- const failedList = r.results.filter((x) => x.installed !== true).map((x) => x.name);
15999
- if (failedList.length)
16000
- console.log(`Failed: ${failedList.join(", ")}`);
16012
+ const failedList = r.results.filter((x) => x.installed !== true);
16013
+ if (failedList.length) {
16014
+ console.log(`
16015
+ Failed (${failedList.length}) — reason per tool:`);
16016
+ for (const f of failedList) {
16017
+ const reason = String(f.output ?? f.note ?? "unknown error").split(`
16018
+ `).map((s) => s.trim()).filter(Boolean).slice(-2).join(" | ").slice(-160);
16019
+ console.log(` - ${f.name}: ${reason}`);
16020
+ }
16021
+ console.log(`
16022
+ Common causes: missing Go/Java/Rust toolchain, build tools (meson/ninja/make), pip/git network failures, or heavy builds that exceed the 120s per-tool budget. Re-run after installing the missing toolchain; failed tools are skipped, not fatal.`);
16023
+ }
16001
16024
  }
16002
16025
  var ROOT10;
16003
16026
  var init_cli = __esm(() => {
@@ -31778,7 +31801,7 @@ async function browserValidate(check, target, payload) {
31778
31801
  import { spawn as spawn2, spawnSync as spawnSync2 } from "node:child_process";
31779
31802
  import { existsSync as existsSync4, readdirSync as readdirSync3 } from "node:fs";
31780
31803
  import { join as join7 } from "node:path";
31781
- import { homedir as homedir3 } from "node:os";
31804
+ import { homedir as homedir4 } from "node:os";
31782
31805
  function mcpClient(command, args) {
31783
31806
  const proc = spawn2(command, args, { stdio: ["pipe", "pipe", "pipe"] });
31784
31807
  let id = 0;
@@ -31854,7 +31877,7 @@ function findChromium() {
31854
31877
  return p;
31855
31878
  }
31856
31879
  }
31857
- const pw = join7(homedir3(), ".cache", "ms-playwright");
31880
+ const pw = join7(homedir4(), ".cache", "ms-playwright");
31858
31881
  if (existsSync4(pw)) {
31859
31882
  for (const d of readdirSync3(pw)) {
31860
31883
  if (!d.startsWith("chromium"))
@@ -32184,7 +32207,7 @@ import { readFileSync as readFileSync7, existsSync as existsSync5 } from "node:f
32184
32207
  import { join as join8 } from "node:path";
32185
32208
  import { fileURLToPath as fileURLToPath4 } from "node:url";
32186
32209
  import { readdirSync as readdirSync4 } from "node:fs";
32187
- import { homedir as homedir4 } from "node:os";
32210
+ import { homedir as homedir5 } from "node:os";
32188
32211
  var ROOT3 = join8(fileURLToPath4(new URL(".", import.meta.url)), "..");
32189
32212
  var INTEL = join8(ROOT3, "intelligence");
32190
32213
  function loadJson(name) {
@@ -32415,7 +32438,7 @@ function attackPlan(target, tech = [], params = []) {
32415
32438
  }
32416
32439
  var PACKAGE_PAYLOADS = join8(ROOT3, "payloads");
32417
32440
  var PACKAGE_TEMPLATES = join8(ROOT3, "templates");
32418
- var DATA_ROOT = process.env.BLITZSTRIKE_DATA ?? join8(homedir4(), ".blitzstrike", "data");
32441
+ var DATA_ROOT = process.env.BLITZSTRIKE_DATA ?? join8(homedir5(), ".blitzstrike", "data");
32419
32442
  function payloadsDir() {
32420
32443
  if (existsSync5(PACKAGE_PAYLOADS))
32421
32444
  return PACKAGE_PAYLOADS;
@@ -34735,7 +34758,7 @@ function compactState(phase, findings) {
34735
34758
  }
34736
34759
 
34737
34760
  // src/tasks.ts
34738
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync9, writeFileSync as writeFileSync2 } from "node:fs";
34761
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync2 } from "node:fs";
34739
34762
  import { join as join10 } from "node:path";
34740
34763
  import { fileURLToPath as fileURLToPath6 } from "node:url";
34741
34764
  function tasksDir() {
@@ -34752,7 +34775,7 @@ function load(id) {
34752
34775
  }
34753
34776
  }
34754
34777
  function save(t) {
34755
- mkdirSync3(tasksDir(), { recursive: true });
34778
+ mkdirSync4(tasksDir(), { recursive: true });
34756
34779
  writeFileSync2(taskPath(t.task_id), JSON.stringify(t, null, 2));
34757
34780
  }
34758
34781
  function taskStart(id, objective, plan) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blitzstrike",
3
- "version": "2.4.10",
3
+ "version": "2.4.12",
4
4
  "description": "Blitz Strike — a universal MCP security-audit toolbelt. BLITZ sweeps the attack surface, EAGLE-EYE traces source-to-sink, STRIKE verifies live. 57 attack chains, 130-tool catalog, intelligence data layer. One server, every agent.",
5
5
  "type": "module",
6
6
  "bin": {