blitzstrike 2.4.9 → 2.4.11
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 +28 -0
- package/dist/index.js +44 -33
- package/package.json +1 -1
- package/tools-catalog.json +5633 -5631
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,34 @@ 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.11] — 2026-09-14
|
|
9
|
+
|
|
10
|
+
### Fixed — bulk-install no longer pollutes the caller's cwd
|
|
11
|
+
|
|
12
|
+
- `install-tools` / `install_all_tools` now run every install command in a fixed
|
|
13
|
+
tools directory (`~/.blitzstrike/tools`, override `BLITZSTRIKE_TOOLS_DIR`), so
|
|
14
|
+
`git clone`-style tools (massdns, phpggc, radare2, testssl.sh, …) no longer
|
|
15
|
+
land in whatever directory you happened to run from.
|
|
16
|
+
- Added those cloned tool dirs to `.gitignore`.
|
|
17
|
+
- `blitzstrike install` now prints a hint pointing to `blitzstrike install-tools`
|
|
18
|
+
for the full 140-tool catalog.
|
|
19
|
+
|
|
20
|
+
## [2.4.10] — 2026-09-14
|
|
21
|
+
|
|
22
|
+
### Added — auto-install external MCP servers to every agent
|
|
23
|
+
|
|
24
|
+
- chrome-devtools-mcp is now flagged `installable` in the catalog: `install-tools`
|
|
25
|
+
/ `install_all_tools` provision it (npm i -g) instead of skipping all MCP
|
|
26
|
+
servers. burp-suite-mcp stays skipped (GUI/daemon — build + run manually).
|
|
27
|
+
- `blitzstrike install` (register to every agent) now also auto-installs
|
|
28
|
+
chrome-devtools-mcp so all agents can drive a real browser immediately.
|
|
29
|
+
|
|
30
|
+
### Fixed — doctor git stderr leak
|
|
31
|
+
|
|
32
|
+
- `validateRelease` suppresses git/npm stderr, so `blitzstrike doctor` no longer
|
|
33
|
+
prints a stray `fatal: not a git repository` / `No tags can describe` line when
|
|
34
|
+
run outside a git checkout.
|
|
35
|
+
|
|
8
36
|
## [2.4.9] — 2026-09-14
|
|
9
37
|
|
|
10
38
|
### Added — evidence-first enforcement (findings are never born empty)
|
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
|
-
|
|
7521
|
+
mkdirSync3(TOOLS_DIR, { recursive: true });
|
|
7522
|
+
const r = spawnSync(cmd, { shell: true, timeout: 120000, cwd: TOOLS_DIR });
|
|
7521
7523
|
const ok = r.status === 0;
|
|
7522
7524
|
return {
|
|
7523
7525
|
name: t.name,
|
|
@@ -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
|
-
|
|
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();
|
|
@@ -7633,9 +7636,9 @@ function ensureToolAsync(name, timeoutMs = 120000) {
|
|
|
7633
7636
|
}
|
|
7634
7637
|
async function installAllTools(opts = {}) {
|
|
7635
7638
|
const tools = loadTools();
|
|
7636
|
-
const
|
|
7639
|
+
const skippedMcp = tools.filter((t) => t.category === "mcp-server" && t.installable !== true).map((t) => t.name);
|
|
7637
7640
|
const cat = opts.category?.toLowerCase();
|
|
7638
|
-
const targets = tools.filter((t) => t.category !== "mcp-server" && (!cat || t.category === cat));
|
|
7641
|
+
const targets = tools.filter((t) => (t.category !== "mcp-server" || t.installable === true) && (!cat || t.category === cat));
|
|
7639
7642
|
const concurrency = Math.max(1, opts.concurrency ?? 4);
|
|
7640
7643
|
const results = [];
|
|
7641
7644
|
let idx = 0;
|
|
@@ -7657,14 +7660,15 @@ async function installAllTools(opts = {}) {
|
|
|
7657
7660
|
installed,
|
|
7658
7661
|
already_installed: already,
|
|
7659
7662
|
failed,
|
|
7660
|
-
skipped_mcp_servers:
|
|
7663
|
+
skipped_mcp_servers: skippedMcp,
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
15521
|
+
DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ?? join16(homedir6(), ".blitzstrike", "data");
|
|
15518
15522
|
});
|
|
15519
15523
|
|
|
15520
15524
|
// src/update.ts
|
|
@@ -15579,13 +15583,13 @@ function validateRelease() {
|
|
|
15579
15583
|
checks.push({ name: "CHANGELOG version", ok: false, detail: "CHANGELOG.md not found" });
|
|
15580
15584
|
}
|
|
15581
15585
|
try {
|
|
15582
|
-
const tag = execSync4("git describe --tags --abbrev=0", { cwd: ROOT8, encoding: "utf8" }).trim();
|
|
15586
|
+
const tag = execSync4("git describe --tags --abbrev=0", { cwd: ROOT8, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
15583
15587
|
checks.push({ name: "Git tag", ok: tag === `v${VERSION}`, detail: tag, soft: true });
|
|
15584
15588
|
} catch {
|
|
15585
|
-
checks.push({ name: "Git tag", ok: true, detail: "unavailable (no git)", soft: true });
|
|
15589
|
+
checks.push({ name: "Git tag", ok: true, detail: "unavailable (no git/tags)", soft: true });
|
|
15586
15590
|
}
|
|
15587
15591
|
try {
|
|
15588
|
-
const published = execSync4("npm view blitzstrike version", { encoding: "utf8", timeout: 8000 }).trim();
|
|
15592
|
+
const published = execSync4("npm view blitzstrike version", { encoding: "utf8", timeout: 8000, stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
15589
15593
|
checks.push({ name: "npm registry version", ok: published === VERSION, detail: published, soft: true });
|
|
15590
15594
|
} catch {
|
|
15591
15595
|
checks.push({ name: "npm registry version", ok: true, detail: "unavailable (offline)", soft: true });
|
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
15793
|
+
const dstDir = join19(homedir7(), ".config", "opencode", "agents");
|
|
15790
15794
|
if (!existsSync11(srcDir))
|
|
15791
15795
|
return;
|
|
15792
15796
|
if (!existsSync11(dstDir))
|
|
15793
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
15855
|
+
const home = homedir7();
|
|
15852
15856
|
const agents = [];
|
|
15853
15857
|
const claudeJson = join19(home, ".claude.json");
|
|
15854
15858
|
agents.push({
|
|
@@ -15958,6 +15962,13 @@ Agent-specific formats: see docs/installation.md`);
|
|
|
15958
15962
|
console.log(`
|
|
15959
15963
|
Registered with ${ok}/${installed.length} agent(s).`);
|
|
15960
15964
|
console.log("Restart your agent, then call `run_engagement` or any `blitzstrike` tool.");
|
|
15965
|
+
console.log(`
|
|
15966
|
+
External MCP servers:`);
|
|
15967
|
+
const devtools = ensureTool("chrome-devtools-mcp");
|
|
15968
|
+
console.log(` ${devtools.installed ? "OK " : "FAIL"} chrome-devtools-mcp ${devtools.installed ? "installed (browser MCP ready for all agents)" : devtools.command ?? "install failed"}`);
|
|
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`);
|
|
15961
15972
|
}
|
|
15962
15973
|
async function runInstallTools(args) {
|
|
15963
15974
|
const getArg = (flag) => {
|
|
@@ -15975,9 +15986,9 @@ async function runInstallTools(args) {
|
|
|
15975
15986
|
await Promise.resolve().then(() => init_catalog());
|
|
15976
15987
|
if (dryRun) {
|
|
15977
15988
|
const tools = loadTools();
|
|
15978
|
-
const mcp = tools.filter((t) => t.category === "mcp-server");
|
|
15979
|
-
const targets = tools.filter((t) => t.category !== "mcp-server" && (!category || t.category === category.toLowerCase()));
|
|
15980
|
-
console.log(`Dry run — would attempt ${targets.length} tool(s); ${mcp.length} MCP server(s) skipped (connect, not install):`);
|
|
15989
|
+
const mcp = tools.filter((t) => t.category === "mcp-server" && t.installable !== true);
|
|
15990
|
+
const targets = tools.filter((t) => (t.category !== "mcp-server" || t.installable === true) && (!category || t.category === category.toLowerCase()));
|
|
15991
|
+
console.log(`Dry run — would attempt ${targets.length} tool(s); ${mcp.length} MCP server(s) skipped (GUI/daemon — connect, not install):`);
|
|
15981
15992
|
for (const t of targets)
|
|
15982
15993
|
console.log(` ${t.category.padEnd(11)} ${t.name}`);
|
|
15983
15994
|
return;
|
|
@@ -31773,7 +31784,7 @@ async function browserValidate(check, target, payload) {
|
|
|
31773
31784
|
import { spawn as spawn2, spawnSync as spawnSync2 } from "node:child_process";
|
|
31774
31785
|
import { existsSync as existsSync4, readdirSync as readdirSync3 } from "node:fs";
|
|
31775
31786
|
import { join as join7 } from "node:path";
|
|
31776
|
-
import { homedir as
|
|
31787
|
+
import { homedir as homedir4 } from "node:os";
|
|
31777
31788
|
function mcpClient(command, args) {
|
|
31778
31789
|
const proc = spawn2(command, args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
31779
31790
|
let id = 0;
|
|
@@ -31849,7 +31860,7 @@ function findChromium() {
|
|
|
31849
31860
|
return p;
|
|
31850
31861
|
}
|
|
31851
31862
|
}
|
|
31852
|
-
const pw = join7(
|
|
31863
|
+
const pw = join7(homedir4(), ".cache", "ms-playwright");
|
|
31853
31864
|
if (existsSync4(pw)) {
|
|
31854
31865
|
for (const d of readdirSync3(pw)) {
|
|
31855
31866
|
if (!d.startsWith("chromium"))
|
|
@@ -32179,7 +32190,7 @@ import { readFileSync as readFileSync7, existsSync as existsSync5 } from "node:f
|
|
|
32179
32190
|
import { join as join8 } from "node:path";
|
|
32180
32191
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
32181
32192
|
import { readdirSync as readdirSync4 } from "node:fs";
|
|
32182
|
-
import { homedir as
|
|
32193
|
+
import { homedir as homedir5 } from "node:os";
|
|
32183
32194
|
var ROOT3 = join8(fileURLToPath4(new URL(".", import.meta.url)), "..");
|
|
32184
32195
|
var INTEL = join8(ROOT3, "intelligence");
|
|
32185
32196
|
function loadJson(name) {
|
|
@@ -32410,7 +32421,7 @@ function attackPlan(target, tech = [], params = []) {
|
|
|
32410
32421
|
}
|
|
32411
32422
|
var PACKAGE_PAYLOADS = join8(ROOT3, "payloads");
|
|
32412
32423
|
var PACKAGE_TEMPLATES = join8(ROOT3, "templates");
|
|
32413
|
-
var DATA_ROOT = process.env.BLITZSTRIKE_DATA ?? join8(
|
|
32424
|
+
var DATA_ROOT = process.env.BLITZSTRIKE_DATA ?? join8(homedir5(), ".blitzstrike", "data");
|
|
32414
32425
|
function payloadsDir() {
|
|
32415
32426
|
if (existsSync5(PACKAGE_PAYLOADS))
|
|
32416
32427
|
return PACKAGE_PAYLOADS;
|
|
@@ -34730,7 +34741,7 @@ function compactState(phase, findings) {
|
|
|
34730
34741
|
}
|
|
34731
34742
|
|
|
34732
34743
|
// src/tasks.ts
|
|
34733
|
-
import { mkdirSync as
|
|
34744
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync2 } from "node:fs";
|
|
34734
34745
|
import { join as join10 } from "node:path";
|
|
34735
34746
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
34736
34747
|
function tasksDir() {
|
|
@@ -34747,7 +34758,7 @@ function load(id) {
|
|
|
34747
34758
|
}
|
|
34748
34759
|
}
|
|
34749
34760
|
function save(t) {
|
|
34750
|
-
|
|
34761
|
+
mkdirSync4(tasksDir(), { recursive: true });
|
|
34751
34762
|
writeFileSync2(taskPath(t.task_id), JSON.stringify(t, null, 2));
|
|
34752
34763
|
}
|
|
34753
34764
|
function taskStart(id, objective, plan) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.11",
|
|
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": {
|