blitzstrike 1.0.14 → 1.0.15
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 +358 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7192,7 +7192,7 @@ var init_scanner = __esm(() => {
|
|
|
7192
7192
|
});
|
|
7193
7193
|
|
|
7194
7194
|
// src/sync.ts
|
|
7195
|
-
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync2, readFileSync as
|
|
7195
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync2, readFileSync as readFileSync10, readdirSync as readdirSync4, statSync as statSync3, rmSync } from "node:fs";
|
|
7196
7196
|
import { join as join8 } from "node:path";
|
|
7197
7197
|
import { homedir as homedir4 } from "node:os";
|
|
7198
7198
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
@@ -7288,7 +7288,7 @@ function manualCopy(src, dst) {
|
|
|
7288
7288
|
if (e.isDirectory())
|
|
7289
7289
|
manualCopy(s, d);
|
|
7290
7290
|
else
|
|
7291
|
-
writeFileSync2(d,
|
|
7291
|
+
writeFileSync2(d, readFileSync10(s));
|
|
7292
7292
|
}
|
|
7293
7293
|
}
|
|
7294
7294
|
var ROOT5, DATA_ROOT2, GITHUB_REPO = "https://github.com/shinthink/blitzstrike.git";
|
|
@@ -23318,6 +23318,326 @@ function groupVariants(results) {
|
|
|
23318
23318
|
return [...groups.values()].sort((a, b) => b.occurrences - a.occurrences);
|
|
23319
23319
|
}
|
|
23320
23320
|
|
|
23321
|
+
// src/taint.ts
|
|
23322
|
+
init_scanner();
|
|
23323
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
23324
|
+
function lineIndexOf(text, pos) {
|
|
23325
|
+
let n = 1;
|
|
23326
|
+
for (let i = 0;i < pos; i++)
|
|
23327
|
+
if (text.charCodeAt(i) === 10)
|
|
23328
|
+
n++;
|
|
23329
|
+
return n;
|
|
23330
|
+
}
|
|
23331
|
+
function extractVars(s) {
|
|
23332
|
+
const out = [];
|
|
23333
|
+
const re = /\$([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
23334
|
+
let m;
|
|
23335
|
+
while ((m = re.exec(s)) !== null) {
|
|
23336
|
+
if (!out.includes(m[1]))
|
|
23337
|
+
out.push(m[1]);
|
|
23338
|
+
}
|
|
23339
|
+
return out;
|
|
23340
|
+
}
|
|
23341
|
+
function parseFunctions(text, lines) {
|
|
23342
|
+
const scopes = [];
|
|
23343
|
+
const re = /function\s+&?([A-Za-z_][A-Za-z0-9_]*)\s*\(([^)]*)\)/g;
|
|
23344
|
+
let m;
|
|
23345
|
+
while ((m = re.exec(text)) !== null) {
|
|
23346
|
+
const name = m[1];
|
|
23347
|
+
const params = extractVars(m[2]);
|
|
23348
|
+
const brace = text.indexOf("{", m.index + m[0].length);
|
|
23349
|
+
if (brace === -1)
|
|
23350
|
+
continue;
|
|
23351
|
+
let depth = 0;
|
|
23352
|
+
let end = -1;
|
|
23353
|
+
for (let i = brace;i < text.length; i++) {
|
|
23354
|
+
if (text[i] === "{")
|
|
23355
|
+
depth++;
|
|
23356
|
+
else if (text[i] === "}") {
|
|
23357
|
+
depth--;
|
|
23358
|
+
if (depth === 0) {
|
|
23359
|
+
end = i;
|
|
23360
|
+
break;
|
|
23361
|
+
}
|
|
23362
|
+
}
|
|
23363
|
+
}
|
|
23364
|
+
if (end === -1)
|
|
23365
|
+
continue;
|
|
23366
|
+
const startLine = lineIndexOf(text, m.index) - 1;
|
|
23367
|
+
const endLine = lineIndexOf(text, end);
|
|
23368
|
+
scopes.push({ name, start: startLine, end: endLine, params, isGlobal: false });
|
|
23369
|
+
}
|
|
23370
|
+
return scopes;
|
|
23371
|
+
}
|
|
23372
|
+
function isSourceExpr(expr) {
|
|
23373
|
+
for (const token of Object.keys({ $_GET: 1, $_POST: 1, $_REQUEST: 1, $_COOKIE: 1, $_FILES: 1, $_SERVER: 1 })) {
|
|
23374
|
+
if (expr.includes(token))
|
|
23375
|
+
return token;
|
|
23376
|
+
}
|
|
23377
|
+
if (expr.includes("php://input") || expr.includes("file_get_contents('php://input')"))
|
|
23378
|
+
return "php://input";
|
|
23379
|
+
if (expr.includes("getallheaders"))
|
|
23380
|
+
return "getallheaders";
|
|
23381
|
+
return null;
|
|
23382
|
+
}
|
|
23383
|
+
function analyzeScope(text, lines, scope) {
|
|
23384
|
+
const vars = new Map;
|
|
23385
|
+
for (const p of scope.params)
|
|
23386
|
+
vars.set(p, { tainted: false, sanitizers: [] });
|
|
23387
|
+
const endLine = Math.min(scope.end, lines.length);
|
|
23388
|
+
for (let li = scope.start;li < endLine; li++) {
|
|
23389
|
+
const line = lines[li];
|
|
23390
|
+
const assignRe = /\$([A-Za-z_][A-Za-z0-9_]*)\s*(?:\.?=)\s*(.+)/;
|
|
23391
|
+
const am = assignRe.exec(line);
|
|
23392
|
+
if (!am)
|
|
23393
|
+
continue;
|
|
23394
|
+
const varName = am[1];
|
|
23395
|
+
const expr = am[2];
|
|
23396
|
+
const src = isSourceExpr(expr);
|
|
23397
|
+
if (src) {
|
|
23398
|
+
vars.set(varName, { tainted: true, sanitizers: [], source: src, sourceLine: li + 1 });
|
|
23399
|
+
continue;
|
|
23400
|
+
}
|
|
23401
|
+
const sanitizers = findSanitizers(expr);
|
|
23402
|
+
const innerVars = extractVars(expr);
|
|
23403
|
+
if (sanitizers.length > 0 && innerVars.length > 0) {
|
|
23404
|
+
const inner = vars.get(innerVars[0]);
|
|
23405
|
+
vars.set(varName, {
|
|
23406
|
+
tainted: inner?.tainted ?? false,
|
|
23407
|
+
sanitizers: [...inner?.sanitizers ?? [], ...sanitizers],
|
|
23408
|
+
source: inner?.source,
|
|
23409
|
+
sourceLine: inner?.sourceLine
|
|
23410
|
+
});
|
|
23411
|
+
continue;
|
|
23412
|
+
}
|
|
23413
|
+
let tainted = false;
|
|
23414
|
+
let mergedSanitizers = [];
|
|
23415
|
+
let source;
|
|
23416
|
+
let sourceLine;
|
|
23417
|
+
for (const v of innerVars) {
|
|
23418
|
+
const st = vars.get(v);
|
|
23419
|
+
if (st?.tainted) {
|
|
23420
|
+
tainted = true;
|
|
23421
|
+
mergedSanitizers = st.sanitizers;
|
|
23422
|
+
source = st.source;
|
|
23423
|
+
sourceLine = st.sourceLine;
|
|
23424
|
+
break;
|
|
23425
|
+
}
|
|
23426
|
+
}
|
|
23427
|
+
vars.set(varName, { tainted, sanitizers: mergedSanitizers, source, sourceLine });
|
|
23428
|
+
}
|
|
23429
|
+
return vars;
|
|
23430
|
+
}
|
|
23431
|
+
function buildSummaries(text, lines, scopes) {
|
|
23432
|
+
const summaries = new Map;
|
|
23433
|
+
for (const scope of scopes) {
|
|
23434
|
+
if (scope.isGlobal)
|
|
23435
|
+
continue;
|
|
23436
|
+
const sinkParams = new Map;
|
|
23437
|
+
const sanitizedParams = new Map;
|
|
23438
|
+
const vars = analyzeScope(text, lines, scope);
|
|
23439
|
+
const endLine = Math.min(scope.end, lines.length);
|
|
23440
|
+
for (let li = scope.start;li < endLine; li++) {
|
|
23441
|
+
const line = lines[li];
|
|
23442
|
+
const inlineSan = findSanitizers(line);
|
|
23443
|
+
if (inlineSan.length > 0) {
|
|
23444
|
+
for (const p of scope.params) {
|
|
23445
|
+
if (line.includes("$" + p)) {
|
|
23446
|
+
const existing = sanitizedParams.get(p) ?? [];
|
|
23447
|
+
sanitizedParams.set(p, [...existing, ...inlineSan]);
|
|
23448
|
+
}
|
|
23449
|
+
}
|
|
23450
|
+
}
|
|
23451
|
+
for (const sinkToken of Object.keys({
|
|
23452
|
+
"->query(": 1,
|
|
23453
|
+
"$wpdb->query": 1,
|
|
23454
|
+
"$wpdb->get_var": 1,
|
|
23455
|
+
"$wpdb->get_results": 1,
|
|
23456
|
+
"system(": 1,
|
|
23457
|
+
"exec(": 1,
|
|
23458
|
+
"shell_exec(": 1,
|
|
23459
|
+
"eval(": 1,
|
|
23460
|
+
"unserialize(": 1,
|
|
23461
|
+
"move_uploaded_file(": 1,
|
|
23462
|
+
"file_put_contents(": 1,
|
|
23463
|
+
include: 1,
|
|
23464
|
+
require: 1,
|
|
23465
|
+
"echo ": 1,
|
|
23466
|
+
"print ": 1,
|
|
23467
|
+
"header(": 1,
|
|
23468
|
+
"wp_redirect(": 1,
|
|
23469
|
+
"file_get_contents(": 1
|
|
23470
|
+
})) {
|
|
23471
|
+
if (!line.includes(sinkToken))
|
|
23472
|
+
continue;
|
|
23473
|
+
const varsInLine = extractVars(line);
|
|
23474
|
+
for (const v of varsInLine) {
|
|
23475
|
+
const st = vars.get(v);
|
|
23476
|
+
if (st?.tainted) {
|
|
23477
|
+
sinkParams.set(v, { sink: sinkToken, line: li + 1 });
|
|
23478
|
+
}
|
|
23479
|
+
}
|
|
23480
|
+
for (const p of scope.params) {
|
|
23481
|
+
if (line.includes("$" + p))
|
|
23482
|
+
sinkParams.set(p, { sink: sinkToken, line: li + 1 });
|
|
23483
|
+
}
|
|
23484
|
+
}
|
|
23485
|
+
}
|
|
23486
|
+
summaries.set(scope.name, { name: scope.name, sinkParams, sanitizedParams });
|
|
23487
|
+
}
|
|
23488
|
+
return summaries;
|
|
23489
|
+
}
|
|
23490
|
+
function analyzeTaint(path) {
|
|
23491
|
+
const result = { file: path, findings: [], suppressed: 0 };
|
|
23492
|
+
let text;
|
|
23493
|
+
try {
|
|
23494
|
+
text = readFileSync8(path, "utf8");
|
|
23495
|
+
} catch {
|
|
23496
|
+
return result;
|
|
23497
|
+
}
|
|
23498
|
+
const lines = text.split(`
|
|
23499
|
+
`);
|
|
23500
|
+
const scopes = parseFunctions(text, lines);
|
|
23501
|
+
const summaries = buildSummaries(text, lines, scopes);
|
|
23502
|
+
const globalScope = { name: "<global>", start: 0, end: lines.length, params: [], isGlobal: true };
|
|
23503
|
+
const allScopes = [...scopes, globalScope];
|
|
23504
|
+
for (const scope of allScopes) {
|
|
23505
|
+
const vars = analyzeScope(text, lines, scope);
|
|
23506
|
+
const endLine = Math.min(scope.end, lines.length);
|
|
23507
|
+
for (let li = scope.start;li < endLine; li++) {
|
|
23508
|
+
const line = lines[li];
|
|
23509
|
+
const calledFn = /([A-Za-z_][A-Za-z0-9_]*)\s*\(/.exec(line);
|
|
23510
|
+
if (calledFn && summaries.has(calledFn[1])) {
|
|
23511
|
+
const sum = summaries.get(calledFn[1]);
|
|
23512
|
+
const callVars = extractVars(line);
|
|
23513
|
+
const passedTainted = callVars.filter((v) => vars.get(v)?.tainted);
|
|
23514
|
+
if (passedTainted.length > 0 && sum.sinkParams.size > 0) {
|
|
23515
|
+
const firstSink = [...sum.sinkParams.values()][0];
|
|
23516
|
+
const cls = classifySink2(firstSink.sink);
|
|
23517
|
+
if (cls) {
|
|
23518
|
+
const st = vars.get(passedTainted[0]);
|
|
23519
|
+
const inline = findSanitizers(line);
|
|
23520
|
+
const helperSan = [...sum.sanitizedParams.values()].flat();
|
|
23521
|
+
const san = [...st.sanitizers, ...inline, ...helperSan];
|
|
23522
|
+
const authGated = AUTH_GATES.some((g) => line.includes(g) || (lines[li - 1] ?? "").includes(g));
|
|
23523
|
+
if (!isSanitized(san, cls.id) && !authGated) {
|
|
23524
|
+
result.findings.push({
|
|
23525
|
+
sink: firstSink.sink,
|
|
23526
|
+
sink_line: firstSink.line,
|
|
23527
|
+
category: cls.category,
|
|
23528
|
+
cwe: cls.cwe,
|
|
23529
|
+
variables: passedTainted.map((v) => vars.get(v).source ?? "var"),
|
|
23530
|
+
source: st.source,
|
|
23531
|
+
source_line: st.sourceLine,
|
|
23532
|
+
sanitized: false,
|
|
23533
|
+
sanitizers: san.map((s) => s.id),
|
|
23534
|
+
auth_gated: authGated,
|
|
23535
|
+
interprocedural: true
|
|
23536
|
+
});
|
|
23537
|
+
} else {
|
|
23538
|
+
result.suppressed += 1;
|
|
23539
|
+
}
|
|
23540
|
+
continue;
|
|
23541
|
+
}
|
|
23542
|
+
}
|
|
23543
|
+
}
|
|
23544
|
+
let sinkToken = null;
|
|
23545
|
+
let sinkClass = null;
|
|
23546
|
+
for (const tok of Object.keys({
|
|
23547
|
+
"->query(": 1,
|
|
23548
|
+
"$wpdb->query": 1,
|
|
23549
|
+
"$wpdb->get_var": 1,
|
|
23550
|
+
"$wpdb->get_results": 1,
|
|
23551
|
+
"->whereRaw": 1,
|
|
23552
|
+
"system(": 1,
|
|
23553
|
+
"exec(": 1,
|
|
23554
|
+
"shell_exec(": 1,
|
|
23555
|
+
"passthru(": 1,
|
|
23556
|
+
"popen(": 1,
|
|
23557
|
+
"proc_open(": 1,
|
|
23558
|
+
"eval(": 1,
|
|
23559
|
+
"assert(": 1,
|
|
23560
|
+
"unserialize(": 1,
|
|
23561
|
+
"maybe_unserialize(": 1,
|
|
23562
|
+
"move_uploaded_file(": 1,
|
|
23563
|
+
"file_put_contents(": 1,
|
|
23564
|
+
"fwrite(": 1,
|
|
23565
|
+
include: 1,
|
|
23566
|
+
require: 1,
|
|
23567
|
+
"echo ": 1,
|
|
23568
|
+
"print ": 1,
|
|
23569
|
+
"printf(": 1,
|
|
23570
|
+
"header(": 1,
|
|
23571
|
+
"wp_redirect(": 1,
|
|
23572
|
+
"file_get_contents(": 1,
|
|
23573
|
+
"wp_remote_get(": 1,
|
|
23574
|
+
"wp_remote_post(": 1
|
|
23575
|
+
})) {
|
|
23576
|
+
if (line.includes(tok)) {
|
|
23577
|
+
const cls = classifySink2(tok);
|
|
23578
|
+
if (cls) {
|
|
23579
|
+
sinkToken = tok;
|
|
23580
|
+
sinkClass = cls;
|
|
23581
|
+
break;
|
|
23582
|
+
}
|
|
23583
|
+
}
|
|
23584
|
+
}
|
|
23585
|
+
if (!sinkToken || !sinkClass)
|
|
23586
|
+
continue;
|
|
23587
|
+
const varsInLine = extractVars(line);
|
|
23588
|
+
const taintedVars = [];
|
|
23589
|
+
const allSanitizers = [];
|
|
23590
|
+
let source;
|
|
23591
|
+
let sourceLine;
|
|
23592
|
+
for (const v of varsInLine) {
|
|
23593
|
+
const st = vars.get(v);
|
|
23594
|
+
if (st?.tainted) {
|
|
23595
|
+
taintedVars.push(st);
|
|
23596
|
+
allSanitizers.push(...st.sanitizers);
|
|
23597
|
+
if (!source) {
|
|
23598
|
+
source = st.source;
|
|
23599
|
+
sourceLine = st.sourceLine;
|
|
23600
|
+
}
|
|
23601
|
+
}
|
|
23602
|
+
}
|
|
23603
|
+
const inlineSource = isSourceExpr(line);
|
|
23604
|
+
if (inlineSource && taintedVars.length === 0) {
|
|
23605
|
+
taintedVars.push({ tainted: true, sanitizers: [], source: inlineSource, sourceLine: li + 1 });
|
|
23606
|
+
source = inlineSource;
|
|
23607
|
+
sourceLine = li + 1;
|
|
23608
|
+
}
|
|
23609
|
+
if (taintedVars.length === 0)
|
|
23610
|
+
continue;
|
|
23611
|
+
const inlineSanitizers = findSanitizers(line);
|
|
23612
|
+
const sanitizers = [...allSanitizers, ...inlineSanitizers].filter((s, i, arr) => arr.indexOf(s) === i);
|
|
23613
|
+
const authGated = AUTH_GATES.some((g) => line.includes(g) || (lines[li - 1] ?? "").includes(g));
|
|
23614
|
+
const sanitized = isSanitized(sanitizers, sinkClass.id);
|
|
23615
|
+
if (sanitized || authGated) {
|
|
23616
|
+
result.suppressed += 1;
|
|
23617
|
+
continue;
|
|
23618
|
+
}
|
|
23619
|
+
result.findings.push({
|
|
23620
|
+
sink: sinkToken,
|
|
23621
|
+
sink_line: li + 1,
|
|
23622
|
+
category: sinkClass.category,
|
|
23623
|
+
cwe: sinkClass.cwe,
|
|
23624
|
+
variables: taintedVars.map((t) => t.source ?? "var").filter((v, i, a) => a.indexOf(v) === i),
|
|
23625
|
+
source,
|
|
23626
|
+
source_line: sourceLine,
|
|
23627
|
+
sanitized,
|
|
23628
|
+
sanitizers: sanitizers.map((s) => s.id),
|
|
23629
|
+
auth_gated: authGated,
|
|
23630
|
+
interprocedural: false
|
|
23631
|
+
});
|
|
23632
|
+
}
|
|
23633
|
+
}
|
|
23634
|
+
return result;
|
|
23635
|
+
}
|
|
23636
|
+
function taintTree(root, maxFiles = 2000) {
|
|
23637
|
+
const files = iterSourceFiles(root, maxFiles);
|
|
23638
|
+
return files.map((f) => analyzeTaint(f));
|
|
23639
|
+
}
|
|
23640
|
+
|
|
23321
23641
|
// src/server.ts
|
|
23322
23642
|
function createServer() {
|
|
23323
23643
|
const server = new McpServer({
|
|
@@ -23866,6 +24186,35 @@ function createServer() {
|
|
|
23866
24186
|
}]
|
|
23867
24187
|
};
|
|
23868
24188
|
});
|
|
24189
|
+
server.registerTool("taint_scan", {
|
|
24190
|
+
title: "Inter-procedural taint analysis",
|
|
24191
|
+
description: "EAGLE-EYE: real taint tracking — variable assignment, cross-function flow, and sanitizer awareness. Finds tainted data reaching sinks even across function boundaries.",
|
|
24192
|
+
inputSchema: { path: string2().describe("Source file path") }
|
|
24193
|
+
}, async ({ path }) => {
|
|
24194
|
+
const r = analyzeTaint(path);
|
|
24195
|
+
return { content: [{ type: "text", text: JSON.stringify(r) }] };
|
|
24196
|
+
});
|
|
24197
|
+
server.registerTool("taint_tree", {
|
|
24198
|
+
title: "Whole-tree taint scan",
|
|
24199
|
+
description: "EAGLE-EYE: run inter-procedural taint analysis across an entire source tree.",
|
|
24200
|
+
inputSchema: {
|
|
24201
|
+
path: string2().describe("Source directory path"),
|
|
24202
|
+
max_files: number2().int().optional().describe("Max files (default 2000)")
|
|
24203
|
+
}
|
|
24204
|
+
}, async ({ path, max_files }) => {
|
|
24205
|
+
const results = taintTree(path, max_files ?? 2000);
|
|
24206
|
+
return {
|
|
24207
|
+
content: [{
|
|
24208
|
+
type: "text",
|
|
24209
|
+
text: JSON.stringify({
|
|
24210
|
+
files_analyzed: results.length,
|
|
24211
|
+
total_findings: results.reduce((n, r) => n + r.findings.length, 0),
|
|
24212
|
+
total_suppressed: results.reduce((n, r) => n + r.suppressed, 0),
|
|
24213
|
+
findings: results.filter((r) => r.findings.length > 0).map((r) => ({ file: r.file, findings: r.findings }))
|
|
24214
|
+
})
|
|
24215
|
+
}]
|
|
24216
|
+
};
|
|
24217
|
+
});
|
|
23869
24218
|
return server;
|
|
23870
24219
|
}
|
|
23871
24220
|
async function serve() {
|
|
@@ -23875,7 +24224,7 @@ async function serve() {
|
|
|
23875
24224
|
}
|
|
23876
24225
|
|
|
23877
24226
|
// src/cli.ts
|
|
23878
|
-
import { readFileSync as
|
|
24227
|
+
import { readFileSync as readFileSync9, existsSync as existsSync6, writeFileSync, mkdirSync as mkdirSync2 } from "node:fs";
|
|
23879
24228
|
import { join as join7, dirname } from "node:path";
|
|
23880
24229
|
import { homedir as homedir3 } from "node:os";
|
|
23881
24230
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
@@ -23957,7 +24306,7 @@ function resolveCommand() {
|
|
|
23957
24306
|
}
|
|
23958
24307
|
function readJson(p) {
|
|
23959
24308
|
try {
|
|
23960
|
-
return JSON.parse(
|
|
24309
|
+
return JSON.parse(readFileSync9(p, "utf8"));
|
|
23961
24310
|
} catch {
|
|
23962
24311
|
return null;
|
|
23963
24312
|
}
|
|
@@ -24000,7 +24349,7 @@ function copyOpenCodeAgents() {
|
|
|
24000
24349
|
const src = join7(srcDir, f);
|
|
24001
24350
|
const dst = join7(dstDir, f);
|
|
24002
24351
|
if (existsSync6(src)) {
|
|
24003
|
-
writeFileSync(dst,
|
|
24352
|
+
writeFileSync(dst, readFileSync9(src, "utf8"));
|
|
24004
24353
|
}
|
|
24005
24354
|
}
|
|
24006
24355
|
}
|
|
@@ -24009,7 +24358,7 @@ function codexWrite(p) {
|
|
|
24009
24358
|
const dir = dirname(p);
|
|
24010
24359
|
if (!existsSync6(dir))
|
|
24011
24360
|
mkdirSync2(dir, { recursive: true });
|
|
24012
|
-
let existing = existsSync6(p) ?
|
|
24361
|
+
let existing = existsSync6(p) ? readFileSync9(p, "utf8") : "";
|
|
24013
24362
|
if (!existing.trimEnd().endsWith(`
|
|
24014
24363
|
`))
|
|
24015
24364
|
existing += `
|
|
@@ -24028,7 +24377,7 @@ function hermesWrite(p) {
|
|
|
24028
24377
|
const dir = dirname(p);
|
|
24029
24378
|
if (!existsSync6(dir))
|
|
24030
24379
|
mkdirSync2(dir, { recursive: true });
|
|
24031
|
-
let existing = existsSync6(p) ?
|
|
24380
|
+
let existing = existsSync6(p) ? readFileSync9(p, "utf8") : "";
|
|
24032
24381
|
existing = existing.replace(/^ blitzstrike:\n(?: .*\n?)*/m, "");
|
|
24033
24382
|
if (!existing.trimEnd().endsWith(`
|
|
24034
24383
|
`))
|
|
@@ -24166,7 +24515,7 @@ Registered with ${ok}/${installed.length} agent(s).`);
|
|
|
24166
24515
|
}
|
|
24167
24516
|
|
|
24168
24517
|
// src/index.ts
|
|
24169
|
-
import { readFileSync as
|
|
24518
|
+
import { readFileSync as readFileSync11, existsSync as existsSync8 } from "node:fs";
|
|
24170
24519
|
import { join as join9 } from "node:path";
|
|
24171
24520
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
24172
24521
|
var ROOT6 = join9(fileURLToPath7(new URL(".", import.meta.url)), "..");
|
|
@@ -24174,7 +24523,7 @@ function readVersion() {
|
|
|
24174
24523
|
try {
|
|
24175
24524
|
const p = join9(ROOT6, "package.json");
|
|
24176
24525
|
if (existsSync8(p))
|
|
24177
|
-
return JSON.parse(
|
|
24526
|
+
return JSON.parse(readFileSync11(p, "utf8")).version ?? "1.0.0";
|
|
24178
24527
|
} catch {}
|
|
24179
24528
|
return "1.0.0";
|
|
24180
24529
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15",
|
|
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": {
|