blitzstrike 2.4.71 → 2.4.73

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/index.js CHANGED
@@ -15584,11 +15584,11 @@ var require_src = __commonJS(function(exports, module) {
15584
15584
  });
15585
15585
 
15586
15586
  // src/mcp-status.ts
15587
- import { existsSync as existsSync9 } from "node:fs";
15587
+ import { existsSync as existsSync10 } from "node:fs";
15588
15588
  import { spawnSync as spawnSync3 } from "node:child_process";
15589
15589
  async function checkMcpServers() {
15590
15590
  const out = [];
15591
- const bin = ["/usr/bin/chrome-devtools-mcp", "/usr/local/bin/chrome-devtools-mcp"].find((p) => existsSync9(p));
15591
+ const bin = ["/usr/bin/chrome-devtools-mcp", "/usr/local/bin/chrome-devtools-mcp"].find((p) => existsSync10(p));
15592
15592
  const npxOk = spawnSync3("npx", ["--version"], { timeout: 8000 }).error === undefined;
15593
15593
  const devtoolsOk = Boolean(bin) || npxOk;
15594
15594
  out.push({
@@ -17009,12 +17009,12 @@ $r = openai.chat.completions.create(['messages' => [['role' => 'user', 'content'
17009
17009
  });
17010
17010
 
17011
17011
  // src/variants.ts
17012
- import { readFileSync as readFileSync19 } from "node:fs";
17013
- import { join as join19, dirname as dirname4 } from "node:path";
17014
- import { fileURLToPath as fileURLToPath10 } from "node:url";
17012
+ import { readFileSync as readFileSync20 } from "node:fs";
17013
+ import { join as join20, dirname as dirname5 } from "node:path";
17014
+ import { fileURLToPath as fileURLToPath11 } from "node:url";
17015
17015
  function loadVariants() {
17016
17016
  try {
17017
- const doc = JSON.parse(readFileSync19(join19(__dirname4, "..", "intelligence", "variants.json"), "utf8"));
17017
+ const doc = JSON.parse(readFileSync20(join20(__dirname5, "..", "intelligence", "variants.json"), "utf8"));
17018
17018
  return doc.variants ?? [];
17019
17019
  } catch {
17020
17020
  return [];
@@ -17065,18 +17065,18 @@ function variantCoverageText() {
17065
17065
  return lines.join(`
17066
17066
  `);
17067
17067
  }
17068
- var __dirname4, CROSS_FILE_ONLY;
17068
+ var __dirname5, CROSS_FILE_ONLY;
17069
17069
  var init_variants = __esm(() => {
17070
17070
  init_complex_bugs();
17071
- __dirname4 = dirname4(fileURLToPath10(import.meta.url));
17071
+ __dirname5 = dirname5(fileURLToPath11(import.meta.url));
17072
17072
  CROSS_FILE_ONLY = new Set(["priv_esc"]);
17073
17073
  });
17074
17074
 
17075
17075
  // src/sync.ts
17076
- import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync25, readdirSync as readdirSync7, statSync as statSync4, rmSync as rmSync4 } from "node:fs";
17077
- import { join as join23 } from "node:path";
17076
+ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync26, readdirSync as readdirSync7, statSync as statSync4, rmSync as rmSync4 } from "node:fs";
17077
+ import { join as join24 } from "node:path";
17078
17078
  import { homedir as homedir10 } from "node:os";
17079
- import { fileURLToPath as fileURLToPath12 } from "node:url";
17079
+ import { fileURLToPath as fileURLToPath13 } from "node:url";
17080
17080
  import { spawnSync as spawnSync4 } from "node:child_process";
17081
17081
  function dirExists(p) {
17082
17082
  try {
@@ -17091,7 +17091,7 @@ function countFiles(dir) {
17091
17091
  const walk = (d) => {
17092
17092
  for (const e of readdirSync7(d, { withFileTypes: true })) {
17093
17093
  if (e.isDirectory())
17094
- walk(join23(d, e.name));
17094
+ walk(join24(d, e.name));
17095
17095
  else
17096
17096
  n++;
17097
17097
  }
@@ -17105,8 +17105,8 @@ function countFiles(dir) {
17105
17105
  function syncData() {
17106
17106
  if (!dirExists(DATA_ROOT2))
17107
17107
  mkdirSync9(DATA_ROOT2, { recursive: true });
17108
- const payloadsPath = join23(DATA_ROOT2, "payloads");
17109
- const templatesPath = join23(DATA_ROOT2, "templates");
17108
+ const payloadsPath = join24(DATA_ROOT2, "payloads");
17109
+ const templatesPath = join24(DATA_ROOT2, "templates");
17110
17110
  const hasPayloads = dirExists(payloadsPath) && countFiles(payloadsPath) > 0;
17111
17111
  const hasTemplates = dirExists(templatesPath) && countFiles(templatesPath) > 0;
17112
17112
  if (hasPayloads && hasTemplates) {
@@ -17116,8 +17116,8 @@ function syncData() {
17116
17116
  data_root: DATA_ROOT2
17117
17117
  };
17118
17118
  }
17119
- const localPayloads = join23(ROOT7, "payloads");
17120
- const localTemplates = join23(ROOT7, "templates");
17119
+ const localPayloads = join24(ROOT7, "payloads");
17120
+ const localTemplates = join24(ROOT7, "templates");
17121
17121
  let payloadsSynced = false;
17122
17122
  let templatesSynced = false;
17123
17123
  if (!hasPayloads && dirExists(localPayloads)) {
@@ -17130,7 +17130,7 @@ function syncData() {
17130
17130
  }
17131
17131
  const gitOk = spawnSync4("git", ["--version"]).status === 0;
17132
17132
  if (gitOk && (!dirExists(payloadsPath) || countFiles(payloadsPath) === 0 || !dirExists(templatesPath) || countFiles(templatesPath) === 0)) {
17133
- const tmp = join23(DATA_ROOT2, ".tmp-clone");
17133
+ const tmp = join24(DATA_ROOT2, ".tmp-clone");
17134
17134
  if (dirExists(tmp))
17135
17135
  rmSync4(tmp, { recursive: true, force: true });
17136
17136
  const r = spawnSync4("git", ["clone", "--depth", "1", "--filter=blob:none", "--sparse", GITHUB_REPO, tmp], { timeout: 120000 });
@@ -17138,11 +17138,11 @@ function syncData() {
17138
17138
  const sparse = spawnSync4("git", ["-C", tmp, "sparse-checkout", "set", "payloads", "templates"], { timeout: 120000 });
17139
17139
  if (sparse.status === 0) {
17140
17140
  if (!dirExists(payloadsPath) || countFiles(payloadsPath) === 0) {
17141
- copyDir(join23(tmp, "payloads"), payloadsPath);
17141
+ copyDir(join24(tmp, "payloads"), payloadsPath);
17142
17142
  payloadsSynced = true;
17143
17143
  }
17144
17144
  if (!dirExists(templatesPath) || countFiles(templatesPath) === 0) {
17145
- copyDir(join23(tmp, "templates"), templatesPath);
17145
+ copyDir(join24(tmp, "templates"), templatesPath);
17146
17146
  templatesSynced = true;
17147
17147
  }
17148
17148
  }
@@ -17164,18 +17164,18 @@ function copyDir(src, dst) {
17164
17164
  function manualCopy(src, dst) {
17165
17165
  mkdirSync9(dst, { recursive: true });
17166
17166
  for (const e of readdirSync7(src, { withFileTypes: true })) {
17167
- const s = join23(src, e.name);
17168
- const d = join23(dst, e.name);
17167
+ const s = join24(src, e.name);
17168
+ const d = join24(dst, e.name);
17169
17169
  if (e.isDirectory())
17170
17170
  manualCopy(s, d);
17171
17171
  else
17172
- writeFileSync8(d, readFileSync25(s));
17172
+ writeFileSync8(d, readFileSync26(s));
17173
17173
  }
17174
17174
  }
17175
17175
  var ROOT7, DATA_ROOT2, GITHUB_REPO = "https://github.com/shinthink/blitzstrike.git";
17176
17176
  var init_sync = __esm(() => {
17177
- ROOT7 = join23(fileURLToPath12(new URL(".", import.meta.url)), "..");
17178
- DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ?? join23(homedir10(), ".blitzstrike", "data");
17177
+ ROOT7 = join24(fileURLToPath13(new URL(".", import.meta.url)), "..");
17178
+ DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ?? join24(homedir10(), ".blitzstrike", "data");
17179
17179
  });
17180
17180
 
17181
17181
  // src/update.ts
@@ -17220,15 +17220,15 @@ var init_update = __esm(() => {
17220
17220
  });
17221
17221
 
17222
17222
  // src/release.ts
17223
- import { readFileSync as readFileSync27, existsSync as existsSync13 } from "node:fs";
17224
- import { join as join24 } from "node:path";
17225
- import { fileURLToPath as fileURLToPath13 } from "node:url";
17223
+ import { readFileSync as readFileSync28, existsSync as existsSync14 } from "node:fs";
17224
+ import { join as join25 } from "node:path";
17225
+ import { fileURLToPath as fileURLToPath14 } from "node:url";
17226
17226
  import { execSync as execSync2 } from "node:child_process";
17227
17227
  function validateRelease() {
17228
17228
  const checks = [];
17229
17229
  checks.push({ name: "package.json version", ok: true, detail: VERSION });
17230
17230
  try {
17231
- const changelog = readFileSync27(join24(ROOT8, "CHANGELOG.md"), "utf8");
17231
+ const changelog = readFileSync28(join25(ROOT8, "CHANGELOG.md"), "utf8");
17232
17232
  const m = changelog.match(/^##\s+\[([0-9]+\.[0-9]+\.[0-9]+)\]/m);
17233
17233
  const changelogVersion = m?.[1] ?? null;
17234
17234
  checks.push({
@@ -17260,22 +17260,22 @@ function validateRelease() {
17260
17260
  return { version: VERSION, checks, consistent: checks.filter((c) => !c.soft).every((c) => c.ok) };
17261
17261
  }
17262
17262
  function lockfilePresent() {
17263
- return existsSync13(join24(ROOT8, "package-lock.json")) || existsSync13(join24(ROOT8, "bun.lock")) || existsSync13(join24(ROOT8, "bun.lockb"));
17263
+ return existsSync14(join25(ROOT8, "package-lock.json")) || existsSync14(join25(ROOT8, "bun.lock")) || existsSync14(join25(ROOT8, "bun.lockb"));
17264
17264
  }
17265
17265
  var ROOT8;
17266
17266
  var init_release = __esm(() => {
17267
17267
  init_version();
17268
- ROOT8 = join24(fileURLToPath13(new URL(".", import.meta.url)), "..");
17268
+ ROOT8 = join25(fileURLToPath14(new URL(".", import.meta.url)), "..");
17269
17269
  });
17270
17270
 
17271
17271
  // src/dependency.ts
17272
- import { readFileSync as readFileSync28 } from "node:fs";
17273
- import { join as join25 } from "node:path";
17274
- import { fileURLToPath as fileURLToPath14 } from "node:url";
17272
+ import { readFileSync as readFileSync29 } from "node:fs";
17273
+ import { join as join26 } from "node:path";
17274
+ import { fileURLToPath as fileURLToPath15 } from "node:url";
17275
17275
  function checkDependencies() {
17276
17276
  let pkg = {};
17277
17277
  try {
17278
- pkg = JSON.parse(readFileSync28(join25(ROOT9, "package.json"), "utf8"));
17278
+ pkg = JSON.parse(readFileSync29(join26(ROOT9, "package.json"), "utf8"));
17279
17279
  } catch {
17280
17280
  return { install_scripts: [], git_dependencies: [], total_dependencies: 0, safe: false };
17281
17281
  }
@@ -17298,14 +17298,14 @@ function checkDependencies() {
17298
17298
  }
17299
17299
  var ROOT9;
17300
17300
  var init_dependency = __esm(() => {
17301
- ROOT9 = join25(fileURLToPath14(new URL(".", import.meta.url)), "..");
17301
+ ROOT9 = join26(fileURLToPath15(new URL(".", import.meta.url)), "..");
17302
17302
  });
17303
17303
 
17304
17304
  // src/cli.ts
17305
- import { readFileSync as readFileSync29, existsSync as existsSync14, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10 } from "node:fs";
17306
- import { join as join26, dirname as dirname5 } from "node:path";
17305
+ import { readFileSync as readFileSync30, existsSync as existsSync15, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10 } from "node:fs";
17306
+ import { join as join27, dirname as dirname6 } from "node:path";
17307
17307
  import { homedir as homedir11 } from "node:os";
17308
- import { fileURLToPath as fileURLToPath15 } from "node:url";
17308
+ import { fileURLToPath as fileURLToPath16 } from "node:url";
17309
17309
  import { spawnSync as spawnSync5 } from "node:child_process";
17310
17310
  function which(cmd) {
17311
17311
  return spawnSync5("sh", ["-c", 'command -v "$1" >/dev/null 2>&1', "sh", cmd]).status === 0;
@@ -17348,7 +17348,7 @@ async function runDoctor() {
17348
17348
  detail: h1 ? `X-HackerOne-Research: ${h1}` : "H1_USERNAME not set",
17349
17349
  fix: h1 ? undefined : "export H1_USERNAME=<your-hackerone-username> (adds X-HackerOne-Research to outbound requests)"
17350
17350
  });
17351
- const dataOk = existsSync14(join26(ROOT10, "chains.json")) && existsSync14(join26(ROOT10, "tools-catalog.json"));
17351
+ const dataOk = existsSync15(join27(ROOT10, "chains.json")) && existsSync15(join27(ROOT10, "tools-catalog.json"));
17352
17352
  issues.push({
17353
17353
  name: "Data layers (chains + tools-catalog)",
17354
17354
  status: dataOk ? "ok" : "fail",
@@ -17399,29 +17399,29 @@ BlitzStrike — ${verdict}`);
17399
17399
  function resolveCommand() {
17400
17400
  if (which("blitzstrike"))
17401
17401
  return { command: "blitzstrike", args: ["serve", "--mcp"] };
17402
- const src = join26(ROOT10, "src", "index.ts");
17403
- if (which("bun") && existsSync14(src))
17402
+ const src = join27(ROOT10, "src", "index.ts");
17403
+ if (which("bun") && existsSync15(src))
17404
17404
  return { command: "bun", args: ["run", src, "serve", "--mcp"] };
17405
17405
  if (which("npx"))
17406
17406
  return { command: "npx", args: ["-y", "blitzstrike", "serve", "--mcp"] };
17407
17407
  if (which("bunx"))
17408
17408
  return { command: "bunx", args: ["blitzstrike", "serve", "--mcp"] };
17409
- const dist = join26(ROOT10, "dist", "index.js");
17410
- if (existsSync14(dist))
17409
+ const dist = join27(ROOT10, "dist", "index.js");
17410
+ if (existsSync15(dist))
17411
17411
  return { command: "bun", args: [dist, "serve", "--mcp"] };
17412
17412
  return { command: "npx", args: ["-y", "blitzstrike", "serve", "--mcp"] };
17413
17413
  }
17414
17414
  function readJson(p) {
17415
17415
  try {
17416
- return JSON.parse(readFileSync29(p, "utf8"));
17416
+ return JSON.parse(readFileSync30(p, "utf8"));
17417
17417
  } catch {
17418
17418
  return null;
17419
17419
  }
17420
17420
  }
17421
17421
  function jsonMcpServersWrite(p) {
17422
17422
  return (command, args) => {
17423
- const dir = dirname5(p);
17424
- if (!existsSync14(dir))
17423
+ const dir = dirname6(p);
17424
+ if (!existsSync15(dir))
17425
17425
  mkdirSync10(dir, { recursive: true });
17426
17426
  const existing = readJson(p) ?? {};
17427
17427
  existing.mcpServers = {
@@ -17433,8 +17433,8 @@ function jsonMcpServersWrite(p) {
17433
17433
  }
17434
17434
  function opencodeWrite(p) {
17435
17435
  return (command, args) => {
17436
- const dir = dirname5(p);
17437
- if (!existsSync14(dir))
17436
+ const dir = dirname6(p);
17437
+ if (!existsSync15(dir))
17438
17438
  mkdirSync10(dir, { recursive: true });
17439
17439
  const existing = readJson(p) ?? {};
17440
17440
  existing.mcp = {
@@ -17446,26 +17446,26 @@ function opencodeWrite(p) {
17446
17446
  };
17447
17447
  }
17448
17448
  function copyOpenCodeAgents() {
17449
- const srcDir = join26(ROOT10, "opencode-agents");
17450
- const dstDir = join26(homedir11(), ".config", "opencode", "agents");
17451
- if (!existsSync14(srcDir))
17449
+ const srcDir = join27(ROOT10, "opencode-agents");
17450
+ const dstDir = join27(homedir11(), ".config", "opencode", "agents");
17451
+ if (!existsSync15(srcDir))
17452
17452
  return;
17453
- if (!existsSync14(dstDir))
17453
+ if (!existsSync15(dstDir))
17454
17454
  mkdirSync10(dstDir, { recursive: true });
17455
17455
  for (const f of ["Blitz Strike.md", "Blitz.md", "Eagle Eye.md", "Strike.md"]) {
17456
- const src = join26(srcDir, f);
17457
- const dst = join26(dstDir, f);
17458
- if (existsSync14(src)) {
17459
- writeFileSync9(dst, readFileSync29(src, "utf8"));
17456
+ const src = join27(srcDir, f);
17457
+ const dst = join27(dstDir, f);
17458
+ if (existsSync15(src)) {
17459
+ writeFileSync9(dst, readFileSync30(src, "utf8"));
17460
17460
  }
17461
17461
  }
17462
17462
  }
17463
17463
  function codexWrite(p) {
17464
17464
  return (command, args) => {
17465
- const dir = dirname5(p);
17466
- if (!existsSync14(dir))
17465
+ const dir = dirname6(p);
17466
+ if (!existsSync15(dir))
17467
17467
  mkdirSync10(dir, { recursive: true });
17468
- let existing = existsSync14(p) ? readFileSync29(p, "utf8") : "";
17468
+ let existing = existsSync15(p) ? readFileSync30(p, "utf8") : "";
17469
17469
  if (!existing.trimEnd().endsWith(`
17470
17470
  `))
17471
17471
  existing += `
@@ -17481,10 +17481,10 @@ args = ${JSON.stringify(args)}
17481
17481
  }
17482
17482
  function hermesWrite(p) {
17483
17483
  return (command, args) => {
17484
- const dir = dirname5(p);
17485
- if (!existsSync14(dir))
17484
+ const dir = dirname6(p);
17485
+ if (!existsSync15(dir))
17486
17486
  mkdirSync10(dir, { recursive: true });
17487
- let existing = existsSync14(p) ? readFileSync29(p, "utf8") : "";
17487
+ let existing = existsSync15(p) ? readFileSync30(p, "utf8") : "";
17488
17488
  existing = existing.replace(/^ blitzstrike:\n(?: .*\n?)*/m, "");
17489
17489
  if (!existing.trimEnd().endsWith(`
17490
17490
  `))
@@ -17511,74 +17511,74 @@ mcp_servers:
17511
17511
  function detectAgents() {
17512
17512
  const home = homedir11();
17513
17513
  const agents = [];
17514
- const claudeJson = join26(home, ".claude.json");
17514
+ const claudeJson = join27(home, ".claude.json");
17515
17515
  agents.push({
17516
17516
  name: "Claude Code",
17517
17517
  detectPath: claudeJson,
17518
- installed: () => existsSync14(claudeJson) || which("claude"),
17518
+ installed: () => existsSync15(claudeJson) || which("claude"),
17519
17519
  write: jsonMcpServersWrite(claudeJson)
17520
17520
  });
17521
- const claudeDesktop = join26(home, ".config", "Claude", "claude_desktop_config.json");
17521
+ const claudeDesktop = join27(home, ".config", "Claude", "claude_desktop_config.json");
17522
17522
  agents.push({
17523
17523
  name: "Claude Desktop",
17524
17524
  detectPath: claudeDesktop,
17525
- installed: () => existsSync14(claudeDesktop),
17525
+ installed: () => existsSync15(claudeDesktop),
17526
17526
  write: jsonMcpServersWrite(claudeDesktop)
17527
17527
  });
17528
- const cursor = join26(home, ".cursor", "mcp.json");
17528
+ const cursor = join27(home, ".cursor", "mcp.json");
17529
17529
  agents.push({
17530
17530
  name: "Cursor",
17531
17531
  detectPath: cursor,
17532
- installed: () => existsSync14(join26(home, ".cursor")) || which("cursor"),
17532
+ installed: () => existsSync15(join27(home, ".cursor")) || which("cursor"),
17533
17533
  write: jsonMcpServersWrite(cursor)
17534
17534
  });
17535
- const opencode = join26(home, ".config", "opencode", "opencode.jsonc");
17535
+ const opencode = join27(home, ".config", "opencode", "opencode.jsonc");
17536
17536
  agents.push({
17537
17537
  name: "OpenCode",
17538
17538
  detectPath: opencode,
17539
- installed: () => existsSync14(join26(home, ".config", "opencode")) || which("opencode"),
17539
+ installed: () => existsSync15(join27(home, ".config", "opencode")) || which("opencode"),
17540
17540
  write: opencodeWrite(opencode)
17541
17541
  });
17542
- const codex = join26(home, ".codex", "config.toml");
17542
+ const codex = join27(home, ".codex", "config.toml");
17543
17543
  agents.push({
17544
17544
  name: "Codex",
17545
17545
  detectPath: codex,
17546
- installed: () => existsSync14(join26(home, ".codex")) || which("codex"),
17546
+ installed: () => existsSync15(join27(home, ".codex")) || which("codex"),
17547
17547
  write: codexWrite(codex)
17548
17548
  });
17549
- const hermes = join26(home, ".hermes", "config.yaml");
17549
+ const hermes = join27(home, ".hermes", "config.yaml");
17550
17550
  agents.push({
17551
17551
  name: "Hermes",
17552
17552
  detectPath: hermes,
17553
- installed: () => existsSync14(join26(home, ".hermes")) || which("hermes"),
17553
+ installed: () => existsSync15(join27(home, ".hermes")) || which("hermes"),
17554
17554
  write: hermesWrite(hermes)
17555
17555
  });
17556
- const gemini = join26(home, ".gemini", "settings.json");
17556
+ const gemini = join27(home, ".gemini", "settings.json");
17557
17557
  agents.push({
17558
17558
  name: "Gemini CLI",
17559
17559
  detectPath: gemini,
17560
- installed: () => existsSync14(join26(home, ".gemini")) || which("gemini"),
17560
+ installed: () => existsSync15(join27(home, ".gemini")) || which("gemini"),
17561
17561
  write: jsonMcpServersWrite(gemini)
17562
17562
  });
17563
- const windsurf = join26(home, ".codeium", "windsurf", "mcp_config.json");
17563
+ const windsurf = join27(home, ".codeium", "windsurf", "mcp_config.json");
17564
17564
  agents.push({
17565
17565
  name: "Windsurf",
17566
17566
  detectPath: windsurf,
17567
- installed: () => existsSync14(join26(home, ".codeium")) || which("windsurf"),
17567
+ installed: () => existsSync15(join27(home, ".codeium")) || which("windsurf"),
17568
17568
  write: jsonMcpServersWrite(windsurf)
17569
17569
  });
17570
- const copilot = join26(home, ".copilot", "mcp.json");
17570
+ const copilot = join27(home, ".copilot", "mcp.json");
17571
17571
  agents.push({
17572
17572
  name: "Copilot",
17573
17573
  detectPath: copilot,
17574
- installed: () => existsSync14(join26(home, ".copilot")),
17574
+ installed: () => existsSync15(join27(home, ".copilot")),
17575
17575
  write: jsonMcpServersWrite(copilot)
17576
17576
  });
17577
- const cline = join26(home, ".cline", "mcp_settings.json");
17577
+ const cline = join27(home, ".cline", "mcp_settings.json");
17578
17578
  agents.push({
17579
17579
  name: "Cline",
17580
17580
  detectPath: cline,
17581
- installed: () => existsSync14(join26(home, ".cline")),
17581
+ installed: () => existsSync15(join27(home, ".cline")),
17582
17582
  write: jsonMcpServersWrite(cline)
17583
17583
  });
17584
17584
  return agents;
@@ -17696,7 +17696,7 @@ var init_cli = __esm(() => {
17696
17696
  init_release();
17697
17697
  init_dependency();
17698
17698
  init_mcp_status();
17699
- ROOT10 = join26(fileURLToPath15(new URL(".", import.meta.url)), "..");
17699
+ ROOT10 = join27(fileURLToPath16(new URL(".", import.meta.url)), "..");
17700
17700
  });
17701
17701
 
17702
17702
  // node_modules/zod/v3/helpers/util.js
@@ -32334,7 +32334,7 @@ class StdioServerTransport {
32334
32334
 
32335
32335
  // src/server.ts
32336
32336
  init_scanner();
32337
- import { readFileSync as readFileSync26 } from "node:fs";
32337
+ import { readFileSync as readFileSync27 } from "node:fs";
32338
32338
 
32339
32339
  // src/recon.ts
32340
32340
  var TIMEOUT_MS = 25000;
@@ -32417,7 +32417,7 @@ async function nvdLookup(cveId) {
32417
32417
 
32418
32418
  // src/orchestrator.ts
32419
32419
  init_scanner();
32420
- import { readFileSync as readFileSync9, existsSync as existsSync7, statSync as statSync2 } from "node:fs";
32420
+ import { readFileSync as readFileSync9, existsSync as existsSync8, statSync as statSync2 } from "node:fs";
32421
32421
  import { join as join11 } from "node:path";
32422
32422
  import { fileURLToPath as fileURLToPath5 } from "node:url";
32423
32423
 
@@ -33181,6 +33181,8 @@ function resolveFinding(finding, verdict) {
33181
33181
 
33182
33182
  // src/hash.ts
33183
33183
  import { createHash as createHash3 } from "node:crypto";
33184
+ import { createReadStream, existsSync as existsSync4 } from "node:fs";
33185
+ import { createInterface } from "node:readline";
33184
33186
  var COMMON_PASSWORDS = [
33185
33187
  "password",
33186
33188
  "123456",
@@ -33211,6 +33213,14 @@ var COMMON_PASSWORDS = [
33211
33213
  "P@ssw0rd",
33212
33214
  "qwertyuiop"
33213
33215
  ];
33216
+ var AUTOLOAD_WORDLISTS = [
33217
+ "/usr/share/wordlists/rockyou.txt",
33218
+ "/opt/seclists/Passwords/Leaked-Databases/rockyou-70.txt",
33219
+ "/opt/seclists/Passwords/Leaked-Databases/rockyou-35.txt",
33220
+ "/opt/seclists/Passwords/Leaked-Databases/rockyou-40.txt",
33221
+ "/opt/seclists/Passwords/Common-Credentials/100k-most-used-passwords-NCSC.txt",
33222
+ "/opt/seclists/Passwords/Common-Credentials/10k-most-common.txt"
33223
+ ];
33214
33224
  function identifyHash(hash) {
33215
33225
  if (/^\$2[aby]\$\d+\$/.test(hash))
33216
33226
  return "bcrypt";
@@ -33243,31 +33253,141 @@ var HASHCAT_MODE = {
33243
33253
  sha512crypt: "1800",
33244
33254
  ntlm: "1000"
33245
33255
  };
33246
- async function crackHash(hash, extra = []) {
33256
+ function hashMatches(type, pw, hash) {
33257
+ const target = hash.toLowerCase();
33258
+ if (type === "md5")
33259
+ return createHash3("md5").update(pw).digest("hex") === target;
33260
+ if (type === "sha1")
33261
+ return createHash3("sha1").update(pw).digest("hex") === target;
33262
+ if (type === "sha256")
33263
+ return createHash3("sha256").update(pw).digest("hex") === target;
33264
+ if (type === "sha512")
33265
+ return createHash3("sha512").update(pw).digest("hex") === target;
33266
+ if (type === "ntlm") {
33267
+ const md4 = (buf) => {
33268
+ const pad = (s) => {
33269
+ const len = s.length;
33270
+ const bitLen = len * 8;
33271
+ const out = Buffer.concat([s, Buffer.from([128])]);
33272
+ const mod = out.length % 64;
33273
+ const padLen = mod < 56 ? 56 - mod : 120 - mod;
33274
+ const padded = Buffer.concat([out, Buffer.alloc(padLen)]);
33275
+ const lenBuf = Buffer.alloc(8);
33276
+ lenBuf.writeUInt32LE(bitLen >>> 0, 0);
33277
+ lenBuf.writeUInt32LE(Math.floor(bitLen / 4294967296), 4);
33278
+ return Buffer.concat([padded, lenBuf]);
33279
+ };
33280
+ const rotl = (x, n) => (x << n | x >>> 32 - n) >>> 0;
33281
+ const F = (x, y, z) => x & y | ~x & z;
33282
+ const G = (x, y, z) => x & y | x & z | y & z;
33283
+ const H = (x, y, z) => x ^ y ^ z;
33284
+ const msg = pad(buf);
33285
+ let a0 = 1732584193, b0 = 4023233417, c0 = 2562383102, d0 = 271733878;
33286
+ for (let i = 0;i < msg.length; i += 64) {
33287
+ const X = [];
33288
+ for (let j = 0;j < 16; j++)
33289
+ X[j] = msg.readUInt32LE(i + j * 4);
33290
+ let A = a0, B = b0, C = c0, D = d0;
33291
+ for (let r = 0;r < 16; r++) {
33292
+ const k = r;
33293
+ const s = [3, 7, 11, 19][r % 4];
33294
+ const order = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
33295
+ A = rotl(A + F(B, C, D) + X[order[k]] + 0 >>> 0, s);
33296
+ [A, B, C, D] = [D, A, B, C];
33297
+ }
33298
+ for (let r = 0;r < 16; r++) {
33299
+ const order = [0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15];
33300
+ const s = [3, 5, 9, 13][r % 4];
33301
+ A = rotl(A + G(B, C, D) + X[order[r]] + 1518500249 >>> 0, s);
33302
+ [A, B, C, D] = [D, A, B, C];
33303
+ }
33304
+ for (let r = 0;r < 16; r++) {
33305
+ const order = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15];
33306
+ const s = [3, 9, 11, 15][r % 4];
33307
+ A = rotl(A + H(B, C, D) + X[order[r]] + 1859775393 >>> 0, s);
33308
+ [A, B, C, D] = [D, A, B, C];
33309
+ }
33310
+ a0 = a0 + A >>> 0;
33311
+ b0 = b0 + B >>> 0;
33312
+ c0 = c0 + C >>> 0;
33313
+ d0 = d0 + D >>> 0;
33314
+ }
33315
+ const le = (x) => Buffer.from([x & 255, x >>> 8 & 255, x >>> 16 & 255, x >>> 24 & 255]);
33316
+ return Buffer.concat([le(a0), le(b0), le(c0), le(d0)]).toString("hex");
33317
+ };
33318
+ const utf16le = Buffer.from(pw, "utf16le");
33319
+ return md4(utf16le) === target;
33320
+ }
33321
+ return false;
33322
+ }
33323
+ async function crackWordlists(hash, type, paths, maxCandidates) {
33324
+ let checked = 0;
33325
+ for (const p of paths) {
33326
+ if (!existsSync4(p))
33327
+ continue;
33328
+ const stream = createReadStream(p, { encoding: "utf8" });
33329
+ const rl = createInterface({ input: stream, crlfDelay: Infinity });
33330
+ let found = null;
33331
+ for await (const line of rl) {
33332
+ if (found)
33333
+ break;
33334
+ const pw = line.endsWith("\r") ? line.slice(0, -1) : line;
33335
+ if (!pw)
33336
+ continue;
33337
+ checked += 1;
33338
+ if (checked > maxCandidates)
33339
+ break;
33340
+ if (hashMatches(type, pw, hash))
33341
+ found = pw;
33342
+ }
33343
+ stream.destroy();
33344
+ if (found)
33345
+ return { password: found, checked };
33346
+ if (checked > maxCandidates)
33347
+ break;
33348
+ }
33349
+ return { password: null, checked };
33350
+ }
33351
+ async function crackHash(hash, extra = [], opts = {}) {
33247
33352
  const type = identifyHash(hash);
33248
- const wordlist = [...new Set([...extra, ...COMMON_PASSWORDS])];
33249
- const matches = [];
33250
- for (const pw of wordlist) {
33251
- try {
33252
- if (type === "bcrypt") {
33253
- const verify = globalThis.Bun;
33254
- if (verify?.password?.verifySync?.(pw, hash))
33255
- matches.push(pw);
33256
- } else {
33257
- const algo = type === "md5" ? "md5" : type === "sha1" ? "sha1" : type === "sha256" ? "sha256" : "sha512";
33258
- if (["md5", "sha1", "sha256", "sha512"].includes(type)) {
33259
- if (createHash3(algo).update(pw).digest("hex").toLowerCase() === hash.toLowerCase())
33260
- matches.push(pw);
33261
- }
33262
- }
33263
- } catch {}
33353
+ const maxCandidates = opts.maxCandidates ?? 5000000;
33354
+ const fast = [...new Set([...extra, ...COMMON_PASSWORDS])];
33355
+ let matched = "";
33356
+ for (const pw of fast) {
33357
+ if (hashMatches(type, pw, hash)) {
33358
+ matched = pw;
33359
+ break;
33360
+ }
33361
+ }
33362
+ if (matched) {
33363
+ return {
33364
+ type,
33365
+ cracked: true,
33366
+ matches: [matched],
33367
+ source: "common",
33368
+ recommendation: `CRACKED — authenticate with '${matched}' and continue the chain (login → dashboard → privileged actions).`
33369
+ };
33370
+ }
33371
+ const explicit = opts.wordlist ? Array.isArray(opts.wordlist) ? opts.wordlist : [opts.wordlist] : [];
33372
+ const paths = [...new Set([...explicit, ...AUTOLOAD_WORDLISTS])];
33373
+ const { password, checked } = await crackWordlists(hash, type, paths, maxCandidates);
33374
+ if (password) {
33375
+ return {
33376
+ type,
33377
+ cracked: true,
33378
+ matches: [password],
33379
+ source: "wordlist",
33380
+ candidates_checked: checked,
33381
+ recommendation: `CRACKED from wordlist — authenticate with '${password}' and continue the chain (login → dashboard → privileged actions).`
33382
+ };
33264
33383
  }
33265
33384
  const mode = HASHCAT_MODE[type];
33266
33385
  return {
33267
33386
  type,
33268
- cracked: matches.length > 0,
33269
- matches,
33270
- recommendation: matches.length > 0 ? `CRACKED — authenticate with '${matches[0]}' and continue the chain (login → dashboard → privileged actions).` : mode ? `Not in the built-in common list. Full crack: hashcat -m ${mode} -a 0 <hashes.txt> <wordlist> (bcrypt cost 12 needs GPU + time). Reuse the credential if it matches another account's hash (password reuse).` : "Unknown hash format — save it and identify manually before cracking."
33387
+ cracked: false,
33388
+ matches: [],
33389
+ candidates_checked: checked,
33390
+ recommendation: mode ? `Not in the built-in common list or ${checked} wordlist candidates. Full crack: hashcat -m ${mode} -a 0 <hashes.txt> <wordlist> (bcrypt cost 12 needs GPU + time). Pass a target-specific wordlist via the wordlist arg (e.g. company names, usernames, pattern guesses). Reuse the credential if it matches another account's hash (password reuse).` : "Unknown hash format — save it and identify manually before cracking."
33271
33391
  };
33272
33392
  }
33273
33393
 
@@ -33447,7 +33567,7 @@ async function browserValidate(check, target, payload) {
33447
33567
 
33448
33568
  // src/devtools.ts
33449
33569
  import { spawn as spawn2, spawnSync as spawnSync2 } from "node:child_process";
33450
- import { existsSync as existsSync4, readdirSync as readdirSync3 } from "node:fs";
33570
+ import { existsSync as existsSync5, readdirSync as readdirSync3 } from "node:fs";
33451
33571
  import { join as join7 } from "node:path";
33452
33572
  import { homedir as homedir4 } from "node:os";
33453
33573
  function mcpClient(command, args) {
@@ -33521,17 +33641,17 @@ function findChromium() {
33521
33641
  for (const c of candidates) {
33522
33642
  for (const dir of ["/usr/bin", "/usr/local/bin", "/opt/google/chrome"]) {
33523
33643
  const p = join7(dir, c);
33524
- if (existsSync4(p))
33644
+ if (existsSync5(p))
33525
33645
  return p;
33526
33646
  }
33527
33647
  }
33528
33648
  const pw = join7(homedir4(), ".cache", "ms-playwright");
33529
- if (existsSync4(pw)) {
33649
+ if (existsSync5(pw)) {
33530
33650
  for (const d of readdirSync3(pw)) {
33531
33651
  if (!d.startsWith("chromium"))
33532
33652
  continue;
33533
33653
  const full = join7(pw, d, "chrome-linux64", "chrome");
33534
- if (existsSync4(full))
33654
+ if (existsSync5(full))
33535
33655
  return full;
33536
33656
  }
33537
33657
  }
@@ -33539,7 +33659,7 @@ function findChromium() {
33539
33659
  }
33540
33660
  function chromeDevtoolsCommand() {
33541
33661
  for (const c of ["/usr/bin/chrome-devtools-mcp", "/usr/local/bin/chrome-devtools-mcp"]) {
33542
- if (existsSync4(c))
33662
+ if (existsSync5(c))
33543
33663
  return { command: c, args: [] };
33544
33664
  }
33545
33665
  const npx = spawnSync2("npx", ["--version"], { timeout: 8000 });
@@ -33851,12 +33971,12 @@ function uniqueFindings(findings) {
33851
33971
  }
33852
33972
 
33853
33973
  // src/intel.ts
33854
- import { readFileSync as readFileSync8, existsSync as existsSync6 } from "node:fs";
33974
+ import { readFileSync as readFileSync8, existsSync as existsSync7 } from "node:fs";
33855
33975
  import { join as join9 } from "node:path";
33856
33976
  import { fileURLToPath as fileURLToPath4 } from "node:url";
33857
33977
 
33858
33978
  // src/intelligence.ts
33859
- import { readFileSync as readFileSync7, appendFileSync as appendFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync5 } from "node:fs";
33979
+ import { readFileSync as readFileSync7, appendFileSync as appendFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync6 } from "node:fs";
33860
33980
  import { join as join8 } from "node:path";
33861
33981
  import { createHash as createHash4 } from "node:crypto";
33862
33982
  import { homedir as homedir5 } from "node:os";
@@ -33882,14 +34002,14 @@ function sinkToVector(sinkType) {
33882
34002
  return SINK_TO_VECTOR[sinkType.toLowerCase()] ?? sinkType.toLowerCase();
33883
34003
  }
33884
34004
  function ensureDir2() {
33885
- if (!existsSync5(HOME_DIR3))
34005
+ if (!existsSync6(HOME_DIR3))
33886
34006
  mkdirSync4(HOME_DIR3, { recursive: true });
33887
34007
  }
33888
34008
  function dedupHash2(vector, tech, target, outcome) {
33889
34009
  return createHash4("sha256").update(`${vector}\x00${tech}\x00${target}\x00${outcome}`).digest("hex").slice(0, 16);
33890
34010
  }
33891
34011
  function loadIntel() {
33892
- if (!existsSync5(INTEL_PATH))
34012
+ if (!existsSync6(INTEL_PATH))
33893
34013
  return [];
33894
34014
  try {
33895
34015
  const out = [];
@@ -34041,7 +34161,7 @@ var ROOT3 = join9(fileURLToPath4(new URL(".", import.meta.url)), "..");
34041
34161
  var INTEL = join9(ROOT3, "intelligence");
34042
34162
  function loadJson(name) {
34043
34163
  const p = join9(INTEL, `${name}.json`);
34044
- if (!existsSync6(p))
34164
+ if (!existsSync7(p))
34045
34165
  return null;
34046
34166
  try {
34047
34167
  return JSON.parse(readFileSync8(p, "utf8"));
@@ -34328,12 +34448,12 @@ var PACKAGE_PAYLOADS = join9(ROOT3, "payloads");
34328
34448
  var PACKAGE_TEMPLATES = join9(ROOT3, "templates");
34329
34449
  var DATA_ROOT = process.env.BLITZSTRIKE_DATA ?? join9(homedir6(), ".blitzstrike", "data");
34330
34450
  function payloadsDir() {
34331
- if (existsSync6(PACKAGE_PAYLOADS))
34451
+ if (existsSync7(PACKAGE_PAYLOADS))
34332
34452
  return PACKAGE_PAYLOADS;
34333
34453
  return join9(DATA_ROOT, "payloads");
34334
34454
  }
34335
34455
  function templatesDir() {
34336
- if (existsSync6(PACKAGE_TEMPLATES))
34456
+ if (existsSync7(PACKAGE_TEMPLATES))
34337
34457
  return PACKAGE_TEMPLATES;
34338
34458
  return join9(DATA_ROOT, "templates");
34339
34459
  }
@@ -35941,7 +36061,7 @@ function classifyTarget(target) {
35941
36061
  if (/^https?:\/\//i.test(target))
35942
36062
  return { kind: "live", target };
35943
36063
  try {
35944
- if (existsSync7(target) && (statSync2(target).isDirectory() || statSync2(target).isFile())) {
36064
+ if (existsSync8(target) && (statSync2(target).isDirectory() || statSync2(target).isFile())) {
35945
36065
  return { kind: "source", target };
35946
36066
  }
35947
36067
  } catch {}
@@ -36082,7 +36202,7 @@ function runEngagement(target, scope = "", mode = "bug-bounty", maxFiles = 2000,
36082
36202
  };
36083
36203
  const isPath = (() => {
36084
36204
  try {
36085
- return existsSync7(target) && (statSync2(target).isDirectory() || statSync2(target).isFile());
36205
+ return existsSync8(target) && (statSync2(target).isDirectory() || statSync2(target).isFile());
36086
36206
  } catch {
36087
36207
  return false;
36088
36208
  }
@@ -57558,7 +57678,7 @@ function analyzePatchFiles(oldPath, newPath, language) {
57558
57678
  }
57559
57679
 
57560
57680
  // src/frameworks.ts
57561
- import { readFileSync as readFileSync16, existsSync as existsSync8 } from "node:fs";
57681
+ import { readFileSync as readFileSync16, existsSync as existsSync9 } from "node:fs";
57562
57682
  import { join as join15 } from "node:path";
57563
57683
  import { fileURLToPath as fileURLToPath7 } from "node:url";
57564
57684
  var ROOT4 = join15(fileURLToPath7(new URL(".", import.meta.url)), "..");
@@ -57568,7 +57688,7 @@ function load2() {
57568
57688
  if (cache)
57569
57689
  return cache;
57570
57690
  const p = join15(INTEL2, "frameworks.json");
57571
- if (!existsSync8(p))
57691
+ if (!existsSync9(p))
57572
57692
  return null;
57573
57693
  try {
57574
57694
  cache = JSON.parse(readFileSync16(p, "utf8"));
@@ -58253,7 +58373,7 @@ function submissionGate(input) {
58253
58373
  // src/git-history.ts
58254
58374
  init_complex_bugs();
58255
58375
  import { execFileSync as execFileSync4 } from "node:child_process";
58256
- import { existsSync as existsSync10 } from "node:fs";
58376
+ import { existsSync as existsSync11 } from "node:fs";
58257
58377
  import { join as join17 } from "node:path";
58258
58378
  function parseDeletions(output) {
58259
58379
  const out = [];
@@ -58283,7 +58403,7 @@ function blobBeforeDeletion(root, commit, path) {
58283
58403
  function scanGitHistory(root, opts) {
58284
58404
  const limit = opts?.limit ?? 30;
58285
58405
  const findings = [];
58286
- if (!existsSync10(join17(root, ".git"))) {
58406
+ if (!existsSync11(join17(root, ".git"))) {
58287
58407
  return { root, is_git_repo: false, total: 0, findings: [], error: "not a git repository (no .git dir)" };
58288
58408
  }
58289
58409
  if (opts?.secretPattern) {
@@ -58429,6 +58549,103 @@ async function validateLeakedKey(input) {
58429
58549
  };
58430
58550
  }
58431
58551
 
58552
+ // src/hackbot-arena.ts
58553
+ import { readFileSync as readFileSync18 } from "node:fs";
58554
+ import { join as join18, dirname as dirname3 } from "node:path";
58555
+ import { fileURLToPath as fileURLToPath9 } from "node:url";
58556
+ var __dirname3 = dirname3(fileURLToPath9(import.meta.url));
58557
+ function load4() {
58558
+ try {
58559
+ return JSON.parse(readFileSync18(join18(__dirname3, "..", "intelligence", "hackbot-arena.json"), "utf8"));
58560
+ } catch {
58561
+ return { total: 0, flag_format: "FLAG{nusasec-<32 hex>}", labs: [] };
58562
+ }
58563
+ }
58564
+ var VECTOR_MAP = [
58565
+ { re: /jwt|algorithm confusion|rs256|hs256/i, vectors: ["jwt"], detectors: ["missing_authz"], chains: ["jwt"], tools: ["jwt_analyze", "live_recon"] },
58566
+ { re: /ssrf|server-side request/i, vectors: ["ssrf"], detectors: ["ssrf"], chains: ["ssrf"], tools: ["live_recon", "blind_oracle", "active_scan"] },
58567
+ { re: /sql injection|sqli|postgresql|sql/i, vectors: ["sql_injection"], detectors: ["sql_injection"], chains: ["sql_injection"], tools: ["live_recon", "blind_oracle", "active_scan"] },
58568
+ { re: /ssti|template injection|liquid|jinja|twig/i, vectors: ["ssti"], detectors: ["ssti"], chains: ["ssti"], tools: ["live_recon", "blind_oracle"] },
58569
+ { re: /command injection|os command|command execution/i, vectors: ["command_injection"], detectors: ["command_injection"], chains: ["command_injection"], tools: ["live_recon", "blind_oracle"] },
58570
+ { re: /idor|bola|authorization|broken function|role|membership|ownership|entitlement|directory search|excessive data|data exposure|harvest/i, vectors: ["broken_object_level_authorization"], detectors: ["missing_authz"], chains: ["idor"], tools: ["live_recon", "active_scan", "param_precedence"] },
58571
+ { re: /graphql/i, vectors: ["graphql_exposure"], detectors: ["graphql_exposure", "sql_injection"], chains: ["graphql"], tools: ["live_recon", "active_scan"] },
58572
+ { re: /cache/i, vectors: ["web_cache_deception"], detectors: [], chains: ["cache_deception"], tools: ["cache_gap", "live_recon"] },
58573
+ { re: /credential|key|token|bearer|secret|leak|websocket|rum|api key/i, vectors: ["hardcoded_secret"], detectors: ["hardcoded_secret"], chains: ["secret_leak"], tools: ["live_recon", "drive_devtools", "scan_git_history"] },
58574
+ { re: /rate.limit|batching|otp/i, vectors: ["business_logic"], detectors: [], chains: ["rate_limit_bypass"], tools: ["race_test", "active_scan"] },
58575
+ { re: /mass assignment|self.regist|admin account|user creation|scope/i, vectors: ["mass_assignment"], detectors: ["mass_assignment", "missing_authz"], chains: ["mass_assignment"], tools: ["live_recon", "active_scan"] },
58576
+ { re: /deserialization|rce|workflow|execution/i, vectors: ["code_execution"], detectors: ["deserialization"], chains: ["deserialization"], tools: ["live_recon", "active_scan"] }
58577
+ ];
58578
+ function mapLab(lab) {
58579
+ const out = { vectors: [], detectors: [], chains: [], tools: [] };
58580
+ for (const m of VECTOR_MAP) {
58581
+ if (m.re.test(lab.vuln_class)) {
58582
+ out.vectors.push(...m.vectors);
58583
+ out.detectors.push(...m.detectors);
58584
+ out.chains.push(...m.chains);
58585
+ out.tools.push(...m.tools);
58586
+ }
58587
+ }
58588
+ out.vectors = [...new Set(out.vectors)];
58589
+ out.detectors = [...new Set(out.detectors)];
58590
+ out.chains = [...new Set(out.chains)];
58591
+ out.tools = [...new Set(out.tools)];
58592
+ return out;
58593
+ }
58594
+ function findByLab(labId) {
58595
+ const id = labId.toLowerCase().replace(/[^a-z0-9]/g, "");
58596
+ return load4().labs.find((l) => l.id.toLowerCase() === id || l.id.toLowerCase() === `labs${id}`) ?? null;
58597
+ }
58598
+ function hackbotArenaList() {
58599
+ const doc = load4();
58600
+ return {
58601
+ arena: "Hackbot-Arena (NusaSec)",
58602
+ total: doc.total,
58603
+ flag_format: doc.flag_format,
58604
+ note: "Port = 8080 + lab number (labs01 -> 8081 … labs30 -> 8110). Each lab has a solver/ reference exploit + judge.success_when solve criteria.",
58605
+ labs: doc.labs.map((l) => ({ id: l.id, name: l.name, difficulty: l.difficulty, port: l.port, vuln_class: l.vuln_class, stack: l.stack }))
58606
+ };
58607
+ }
58608
+ function hackbotArenaBrief(labId) {
58609
+ const lab = findByLab(labId);
58610
+ if (!lab)
58611
+ return { error: `unknown lab '${labId}'`, hint: "use hackbot_arena_list() to see all 30 labs" };
58612
+ const plan = mapLab(lab);
58613
+ return {
58614
+ id: lab.id,
58615
+ name: lab.name,
58616
+ difficulty: lab.difficulty,
58617
+ target: `http://localhost:${lab.port}`,
58618
+ vuln_class: lab.vuln_class,
58619
+ stack: lab.stack,
58620
+ flag_format: load4().flag_format,
58621
+ attack_plan: {
58622
+ vectors: plan.vectors,
58623
+ detectors: plan.detectors,
58624
+ chains: plan.chains,
58625
+ tools: plan.tools
58626
+ },
58627
+ hint: `Start with live_recon(target) to fingerprint, then drive the ${plan.chains.join(" + ") || "detected"} chain. Verify every step live (strike_verify / browser_validate) and recover the flag. Flag format: ${load4().flag_format}.`
58628
+ };
58629
+ }
58630
+ function hackbotArenaCoverage() {
58631
+ const doc = load4();
58632
+ const rows = doc.labs.map((l) => {
58633
+ const plan = mapLab(l);
58634
+ return { id: l.id, name: l.name, vuln_class: l.vuln_class, vectors: plan.vectors, detectors: plan.detectors, chains: plan.chains };
58635
+ });
58636
+ const withVector = rows.filter((r) => r.vectors.length > 0).length;
58637
+ const withDetector = rows.filter((r) => r.detectors.length > 0).length;
58638
+ return {
58639
+ arena: "Hackbot-Arena (NusaSec)",
58640
+ total_labs: doc.total,
58641
+ labs_with_mapped_vector: withVector,
58642
+ labs_with_detector_coverage: withDetector,
58643
+ coverage_ratio: Number((withVector / doc.total).toFixed(2)),
58644
+ note: "A mapped vector/detector means Blitz Strike has the deterministic tooling to drive that vuln class; the agent still has to execute the chain + recover the flag.",
58645
+ rows
58646
+ };
58647
+ }
58648
+
58432
58649
  // src/severity.ts
58433
58650
  var VRT_MAP = {
58434
58651
  sql_injection: { vrt: "injection > sql_injection", priority: "P1", severity: "critical", rationale: "SQL injection reaches sensitive data or enables admin takeover." },
@@ -58493,13 +58710,13 @@ function listSeverityMap() {
58493
58710
  }
58494
58711
 
58495
58712
  // src/datarefresh.ts
58496
- import { readFileSync as readFileSync18 } from "node:fs";
58497
- import { join as join18, dirname as dirname3 } from "node:path";
58498
- import { fileURLToPath as fileURLToPath9 } from "node:url";
58499
- var __dirname3 = dirname3(fileURLToPath9(import.meta.url));
58713
+ import { readFileSync as readFileSync19 } from "node:fs";
58714
+ import { join as join19, dirname as dirname4 } from "node:path";
58715
+ import { fileURLToPath as fileURLToPath10 } from "node:url";
58716
+ var __dirname4 = dirname4(fileURLToPath10(import.meta.url));
58500
58717
  function loadJson2(rel) {
58501
58718
  try {
58502
- return JSON.parse(readFileSync18(join18(__dirname3, "..", rel), "utf8"));
58719
+ return JSON.parse(readFileSync19(join19(__dirname4, "..", rel), "utf8"));
58503
58720
  } catch {
58504
58721
  return null;
58505
58722
  }
@@ -58534,18 +58751,18 @@ init_verify_harness();
58534
58751
  init_variants();
58535
58752
 
58536
58753
  // src/benchmark.ts
58537
- import { readFileSync as readFileSync20, readdirSync as readdirSync5, writeFileSync as writeFileSync6, rmSync as rmSync3, mkdirSync as mkdirSync7 } from "node:fs";
58538
- import { join as join20 } from "node:path";
58539
- import { fileURLToPath as fileURLToPath11 } from "node:url";
58754
+ import { readFileSync as readFileSync21, readdirSync as readdirSync5, writeFileSync as writeFileSync6, rmSync as rmSync3, mkdirSync as mkdirSync7 } from "node:fs";
58755
+ import { join as join21 } from "node:path";
58756
+ import { fileURLToPath as fileURLToPath12 } from "node:url";
58540
58757
  import { tmpdir as tmpdir3, homedir as homedir8 } from "node:os";
58541
58758
  init_complex_bugs();
58542
- var ROOT5 = join20(fileURLToPath11(new URL(".", import.meta.url)), "..");
58543
- var CORPUS = join20(ROOT5, "bench", "corpus");
58544
- var CAPTURED_CORPUS_DIR = process.env.BLITZSTRIKE_CORPUS_DIR ?? join20(homedir8(), ".blitzstrike", "corpus");
58759
+ var ROOT5 = join21(fileURLToPath12(new URL(".", import.meta.url)), "..");
58760
+ var CORPUS = join21(ROOT5, "bench", "corpus");
58761
+ var CAPTURED_CORPUS_DIR = process.env.BLITZSTRIKE_CORPUS_DIR ?? join21(homedir8(), ".blitzstrike", "corpus");
58545
58762
  function parseCorpusFile(path) {
58546
58763
  let text;
58547
58764
  try {
58548
- text = readFileSync20(path, "utf8");
58765
+ text = readFileSync21(path, "utf8");
58549
58766
  } catch {
58550
58767
  return null;
58551
58768
  }
@@ -58601,7 +58818,7 @@ function loadDir(dir) {
58601
58818
  for (const f of readdirSync5(dir)) {
58602
58819
  if (!f.endsWith(".md"))
58603
58820
  continue;
58604
- const e = parseCorpusFile(join20(dir, f));
58821
+ const e = parseCorpusFile(join21(dir, f));
58605
58822
  if (e)
58606
58823
  entries.push(e);
58607
58824
  }
@@ -58628,7 +58845,7 @@ function captureFalsePositive(input) {
58628
58845
  input.code,
58629
58846
  "```"
58630
58847
  ].filter((l) => l !== null);
58631
- const path = join20(CAPTURED_CORPUS_DIR, `${id}.md`);
58848
+ const path = join21(CAPTURED_CORPUS_DIR, `${id}.md`);
58632
58849
  writeFileSync6(path, lines.join(`
58633
58850
  `) + `
58634
58851
  `, "utf8");
@@ -58650,7 +58867,7 @@ function detect(entry) {
58650
58867
  }
58651
58868
  const lang = entry.language;
58652
58869
  if (lang === "php") {
58653
- const tmp = join20(tmpdir3(), `blitzstrike-bench-${entry.id}-${process.pid}.php`);
58870
+ const tmp = join21(tmpdir3(), `blitzstrike-bench-${entry.id}-${process.pid}.php`);
58654
58871
  writeFileSync6(tmp, entry.code);
58655
58872
  const r = analyzeDataFlow2(tmp);
58656
58873
  rmSync3(tmp, { force: true });
@@ -58719,25 +58936,25 @@ function runBenchmark() {
58719
58936
  }
58720
58937
 
58721
58938
  // src/obligations.ts
58722
- import { readFileSync as readFileSync21, appendFileSync as appendFileSync4, mkdirSync as mkdirSync8, existsSync as existsSync11, writeFileSync as writeFileSync7 } from "node:fs";
58723
- import { join as join21 } from "node:path";
58939
+ import { readFileSync as readFileSync22, appendFileSync as appendFileSync4, mkdirSync as mkdirSync8, existsSync as existsSync12, writeFileSync as writeFileSync7 } from "node:fs";
58940
+ import { join as join22 } from "node:path";
58724
58941
  import { createHash as createHash6 } from "node:crypto";
58725
58942
  import { homedir as homedir9 } from "node:os";
58726
- var HOME_DIR4 = process.env.BLITZSTRIKE_HOME ?? join21(homedir9(), ".blitzstrike");
58727
- var OBLIGATION_PATH = join21(HOME_DIR4, "obligations.jsonl");
58943
+ var HOME_DIR4 = process.env.BLITZSTRIKE_HOME ?? join22(homedir9(), ".blitzstrike");
58944
+ var OBLIGATION_PATH = join22(HOME_DIR4, "obligations.jsonl");
58728
58945
  function ensureDir3() {
58729
- if (!existsSync11(HOME_DIR4))
58946
+ if (!existsSync12(HOME_DIR4))
58730
58947
  mkdirSync8(HOME_DIR4, { recursive: true });
58731
58948
  }
58732
58949
  function shortId2(claim) {
58733
58950
  return `obl-${createHash6("sha256").update(`${claim}\x00${Date.now()}`).digest("hex").slice(0, 12)}`;
58734
58951
  }
58735
58952
  function loadObligations() {
58736
- if (!existsSync11(OBLIGATION_PATH))
58953
+ if (!existsSync12(OBLIGATION_PATH))
58737
58954
  return [];
58738
58955
  try {
58739
58956
  const out = [];
58740
- for (const line of readFileSync21(OBLIGATION_PATH, "utf8").split(`
58957
+ for (const line of readFileSync22(OBLIGATION_PATH, "utf8").split(`
58741
58958
  `)) {
58742
58959
  const t = line.trim();
58743
58960
  if (!t)
@@ -58841,11 +59058,11 @@ init_framework_security();
58841
59058
  // src/variant-scan.ts
58842
59059
  init_scanner();
58843
59060
  init_complex_bugs();
58844
- import { readFileSync as readFileSync23 } from "node:fs";
59061
+ import { readFileSync as readFileSync24 } from "node:fs";
58845
59062
 
58846
59063
  // src/cross-file.ts
58847
59064
  init_scanner();
58848
- import { readFileSync as readFileSync22 } from "node:fs";
59065
+ import { readFileSync as readFileSync23 } from "node:fs";
58849
59066
  var PUBLIC_HOOK_RE = /(?:wp_ajax_nopriv_\w+|admin_post_nopriv_\w+|init|template_redirect|wp_loaded|parse_request|user_register|um_user_register|register_new_user|authenticate)/;
58850
59067
  var PRIV_SINK_RE = /\b(set_role|add_role|remove_role|set_user_role|wp_set_current_user|wp_set_auth_cookie|wp_insert_user|wp_create_user|wp_update_user)\s*\(/;
58851
59068
  var ROLE_META_RE = /update_user_meta\s*\(\s*[^,]+,\s*['"](wp_capabilities|role|roles|capabilities|wp_user_level)['"]/;
@@ -58897,7 +59114,7 @@ function detectCrossFilePrivesc(root) {
58897
59114
  for (const file of files) {
58898
59115
  let code;
58899
59116
  try {
58900
- code = stripComments(readFileSync22(file, "utf8"));
59117
+ code = stripComments(readFileSync23(file, "utf8"));
58901
59118
  } catch {
58902
59119
  continue;
58903
59120
  }
@@ -58938,7 +59155,7 @@ function detectCrossFilePrivesc(root) {
58938
59155
  for (const file of files) {
58939
59156
  let code;
58940
59157
  try {
58941
- code = stripComments(readFileSync22(file, "utf8"));
59158
+ code = stripComments(readFileSync23(file, "utf8"));
58942
59159
  } catch {
58943
59160
  continue;
58944
59161
  }
@@ -58961,7 +59178,7 @@ function detectCrossFilePrivesc(root) {
58961
59178
  for (const file of files) {
58962
59179
  let code;
58963
59180
  try {
58964
- code = stripComments(readFileSync22(file, "utf8"));
59181
+ code = stripComments(readFileSync23(file, "utf8"));
58965
59182
  } catch {
58966
59183
  continue;
58967
59184
  }
@@ -59076,7 +59293,7 @@ function variantScan(root, opts = {}) {
59076
59293
  for (const file of files) {
59077
59294
  let code;
59078
59295
  try {
59079
- code = readFileSync23(file, "utf8");
59296
+ code = readFileSync24(file, "utf8");
59080
59297
  } catch {
59081
59298
  continue;
59082
59299
  }
@@ -59736,17 +59953,17 @@ function analyzeJwt(token, opts = {}) {
59736
59953
  }
59737
59954
 
59738
59955
  // src/enterprise-benchmark.ts
59739
- import { existsSync as existsSync12, readFileSync as readFileSync24, readdirSync as readdirSync6, statSync as statSync3 } from "node:fs";
59740
- import { join as join22, resolve } from "node:path";
59956
+ import { existsSync as existsSync13, readFileSync as readFileSync25, readdirSync as readdirSync6, statSync as statSync3 } from "node:fs";
59957
+ import { join as join23, resolve } from "node:path";
59741
59958
  init_complex_bugs();
59742
59959
  var ROOT6 = resolve(process.cwd(), "bench", "enterprise");
59743
59960
  var ENTERPRISE_FIXTURES = [
59744
- { id: "php-laravel", dir: join22(ROOT6, "php-laravel"), expected_vulns: 4 },
59745
- { id: "js-express", dir: join22(ROOT6, "js-express"), expected_vulns: 2 },
59746
- { id: "py-django", dir: join22(ROOT6, "py-django"), expected_vulns: 2 },
59747
- { id: "java-spring", dir: join22(ROOT6, "java-spring"), expected_vulns: 2 },
59748
- { id: "wp-batch-route", dir: join22(ROOT6, "wp-batch-route"), expected_vulns: 3 },
59749
- { id: "php-complex", dir: join22(ROOT6, "php-complex"), expected_vulns: 4 }
59961
+ { id: "php-laravel", dir: join23(ROOT6, "php-laravel"), expected_vulns: 4 },
59962
+ { id: "js-express", dir: join23(ROOT6, "js-express"), expected_vulns: 2 },
59963
+ { id: "py-django", dir: join23(ROOT6, "py-django"), expected_vulns: 2 },
59964
+ { id: "java-spring", dir: join23(ROOT6, "java-spring"), expected_vulns: 2 },
59965
+ { id: "wp-batch-route", dir: join23(ROOT6, "wp-batch-route"), expected_vulns: 3 },
59966
+ { id: "php-complex", dir: join23(ROOT6, "php-complex"), expected_vulns: 4 }
59750
59967
  ];
59751
59968
  function sourceFiles(root) {
59752
59969
  const out = [];
@@ -59758,7 +59975,7 @@ function sourceFiles(root) {
59758
59975
  return;
59759
59976
  }
59760
59977
  for (const e of entries) {
59761
- const p = join22(dir, e);
59978
+ const p = join23(dir, e);
59762
59979
  let st;
59763
59980
  try {
59764
59981
  st = statSync3(p);
@@ -59779,7 +59996,7 @@ function detectFixture(dir) {
59779
59996
  for (const f of sourceFiles(dir)) {
59780
59997
  let code;
59781
59998
  try {
59782
- code = readFileSync24(f, "utf8");
59999
+ code = readFileSync25(f, "utf8");
59783
60000
  } catch {
59784
60001
  continue;
59785
60002
  }
@@ -59797,7 +60014,7 @@ function detectFixture(dir) {
59797
60014
  function runEnterpriseBenchmark() {
59798
60015
  const fixtures = [];
59799
60016
  for (const fx of ENTERPRISE_FIXTURES) {
59800
- if (!existsSync12(fx.dir)) {
60017
+ if (!existsSync13(fx.dir)) {
59801
60018
  fixtures.push({ id: fx.id, available: false, detected: 0, expected: fx.expected_vulns, recall: 0 });
59802
60019
  continue;
59803
60020
  }
@@ -60221,16 +60438,19 @@ function createServer() {
60221
60438
  });
60222
60439
  server.registerTool("crack_hash", {
60223
60440
  title: "Identify + crack a dumped credential hash",
60224
- description: "CREDENTIAL: when you dump password hashes, EXECUTE this instead of leaving 'crack the hashes' as a recommendation. Identifies the hash type (bcrypt/md5/sha1/sha256/sha512/ntlm) and immediately tries a built-in common-password list offline, then returns the exact hashcat/john command for the full crack. Pass one hash string or a list.",
60441
+ description: "CREDENTIAL: when you dump password hashes, EXECUTE this instead of leaving 'crack the hashes' as a recommendation. Identifies the hash type (bcrypt/md5/sha1/sha256/sha512/ntlm) and immediately tries a built-in common-password list offline, then streams any supplied wordlist (and autoloads seclists/rockyou when present), then returns the exact hashcat/john command for the full crack. Pass one hash string or a list.",
60225
60442
  inputSchema: {
60226
60443
  hash: string2().describe("The hash string (or a list of hashes, one per line)"),
60227
- extra: array(string2()).optional().describe("Extra candidate passwords to try (e.g. usernames, target-specific words)")
60444
+ extra: array(string2()).optional().describe("Extra candidate passwords to try (e.g. usernames, target-specific words)"),
60445
+ wordlist: string2().optional().describe("Optional wordlist file path(s) to stream (comma-separated). Autoloads rockyou/seclists if present."),
60446
+ maxCandidates: number2().int().optional().describe("Max wordlist candidates to stream (default 5,000,000)")
60228
60447
  }
60229
- }, async ({ hash, extra }) => {
60448
+ }, async ({ hash, extra, wordlist, maxCandidates }) => {
60230
60449
  const hashes = hash.split(/\r?\n/).map((h) => h.trim()).filter(Boolean).slice(0, 50);
60450
+ const wl = wordlist ? wordlist.split(",").map((s) => s.trim()).filter(Boolean) : undefined;
60231
60451
  const results = [];
60232
60452
  for (const h of hashes) {
60233
- results.push({ hash: h.slice(0, 24) + (h.length > 24 ? "…" : ""), ...await crackHash(h, extra ?? []) });
60453
+ results.push({ hash: h.slice(0, 24) + (h.length > 24 ? "…" : ""), ...await crackHash(h, extra ?? [], { wordlist: wl, maxCandidates }) });
60234
60454
  }
60235
60455
  return { content: [{ type: "text", text: JSON.stringify({ hashes_scanned: results.length, results }) }] };
60236
60456
  });
@@ -60462,6 +60682,29 @@ ${statusLine}` : statusLine },
60462
60682
  }, async (input) => {
60463
60683
  return { content: [{ type: "text", text: JSON.stringify(await validateLeakedKey(input)) }] };
60464
60684
  });
60685
+ server.registerTool("hackbot_arena_list", {
60686
+ title: "List Hackbot Arena benchmark labs",
60687
+ description: "BENCHMARK: list the 30 Hackbot Arena (NusaSec) dockerized web-security labs — a local benchmark of realistic vulnerability chains with deterministic flags. Returns id/name/difficulty/port/vuln_class per lab (evaluator view; no flags or solutions).",
60688
+ inputSchema: {}
60689
+ }, async () => {
60690
+ return { content: [{ type: "text", text: JSON.stringify(hackbotArenaList()) }] };
60691
+ });
60692
+ server.registerTool("hackbot_arena_brief", {
60693
+ title: "Attack-plan brief for one Hackbot Arena lab",
60694
+ description: "BENCHMARK: given a lab id (e.g. labs03), return the target URL, vuln class, stack, flag format, and the DERIVED Blitz Strike attack plan (vectors/detectors/chains/tools) to solve it. This is the agent brief — it never contains the flag, judge criteria, or reference solution.",
60695
+ inputSchema: {
60696
+ labId: string2().describe("Lab id (e.g. labs03, labs20)")
60697
+ }
60698
+ }, async ({ labId }) => {
60699
+ return { content: [{ type: "text", text: JSON.stringify(hackbotArenaBrief(labId)) }] };
60700
+ });
60701
+ server.registerTool("hackbot_arena_coverage", {
60702
+ title: "Blitz Strike coverage vs Hackbot Arena",
60703
+ description: "BENCHMARK: map all 30 Hackbot Arena labs against Blitz Strike's detector/vector coverage — which vuln classes Blitz Strike has deterministic tooling for, per lab, plus the derived chains.",
60704
+ inputSchema: {}
60705
+ }, async () => {
60706
+ return { content: [{ type: "text", text: JSON.stringify(hackbotArenaCoverage()) }] };
60707
+ });
60465
60708
  server.registerTool("fofa_search", {
60466
60709
  title: "FOFA asset search",
60467
60710
  description: "STRIKE: search the FOFA asset index (needs FOFA_EMAIL + FOFA_KEY).",
@@ -60847,7 +61090,7 @@ ${statusLine}` : statusLine },
60847
61090
  let src = code;
60848
61091
  if (!src && path) {
60849
61092
  try {
60850
- src = readFileSync26(path, "utf8");
61093
+ src = readFileSync27(path, "utf8");
60851
61094
  } catch {
60852
61095
  return { content: [{ type: "text", text: JSON.stringify({ error: "unreadable path" }) }] };
60853
61096
  }
@@ -61465,7 +61708,7 @@ ${statusLine}` : statusLine },
61465
61708
  description: "Route confusion (separate class from source→sink taint): detect attacker-controlled dispatch (call_user_func/forward/dispatch), dynamic method calls ($obj->$m()), dynamic include (LFI), batch/proxy forwarding without per-route auth re-check, and route matching without path normalization.",
61466
61709
  inputSchema: { path: string2().describe("Source file path (PHP)") }
61467
61710
  }, async ({ path }) => {
61468
- const code = readFileSync26(path, "utf8");
61711
+ const code = readFileSync27(path, "utf8");
61469
61712
  const findings = detectRouteConfusion(code, path);
61470
61713
  return {
61471
61714
  content: [{
@@ -61479,7 +61722,7 @@ ${statusLine}` : statusLine },
61479
61722
  description: "Complex-bug detection beyond taint: deserialization→POP gadget chain (unserialize + magic method), type juggling (loose ==/!= vs hash/secret), mass assignment (extract/parse_str without a safe flag), prototype pollution (unsafe merge of request data), CRLF/header injection (user input into a header), path confusion (user input into a file path without canonicalization), SSRF (user-controlled URL with no host allowlist), XXE (user XML parsed without disabling entities), SSTI (user input into a template render with no sandbox), wrong-context sanitization (sanitize_text_field() into a SQL query), and missing authorization/nonce on WordPress entry points (wp_ajax_* / admin_post_* / register_rest_route without current_user_can, nonce verification, or permission_callback).",
61480
61723
  inputSchema: { path: string2().describe("Source file path") }
61481
61724
  }, async ({ path }) => {
61482
- const code = readFileSync26(path, "utf8");
61725
+ const code = readFileSync27(path, "utf8");
61483
61726
  const findings = detectComplexBugs(code, path);
61484
61727
  return {
61485
61728
  content: [{
@@ -61565,7 +61808,7 @@ ${statusLine}` : statusLine },
61565
61808
  let lang = language;
61566
61809
  if (path && !code) {
61567
61810
  try {
61568
- src = readFileSync26(path, "utf8");
61811
+ src = readFileSync27(path, "utf8");
61569
61812
  } catch {
61570
61813
  return { content: [{ type: "text", text: JSON.stringify({ error: `cannot read ${path}` }) }] };
61571
61814
  }
@@ -61814,15 +62057,15 @@ async function serve() {
61814
62057
 
61815
62058
  // src/index.ts
61816
62059
  init_cli();
61817
- import { readFileSync as readFileSync30, existsSync as existsSync15 } from "node:fs";
61818
- import { join as join27 } from "node:path";
61819
- import { fileURLToPath as fileURLToPath16 } from "node:url";
61820
- var ROOT11 = join27(fileURLToPath16(new URL(".", import.meta.url)), "..");
62060
+ import { readFileSync as readFileSync31, existsSync as existsSync16 } from "node:fs";
62061
+ import { join as join28 } from "node:path";
62062
+ import { fileURLToPath as fileURLToPath17 } from "node:url";
62063
+ var ROOT11 = join28(fileURLToPath17(new URL(".", import.meta.url)), "..");
61821
62064
  function readVersion() {
61822
62065
  try {
61823
- const p = join27(ROOT11, "package.json");
61824
- if (existsSync15(p))
61825
- return JSON.parse(readFileSync30(p, "utf8")).version ?? "1.0.0";
62066
+ const p = join28(ROOT11, "package.json");
62067
+ if (existsSync16(p))
62068
+ return JSON.parse(readFileSync31(p, "utf8")).version ?? "1.0.0";
61826
62069
  } catch {}
61827
62070
  return "1.0.0";
61828
62071
  }