blitzstrike 1.0.51 → 1.0.53
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 +30 -0
- package/dist/index.js +346 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,36 @@ 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
|
+
## [1.0.53] — 2026-09-13
|
|
9
|
+
|
|
10
|
+
### Added — Autonomous Security Engine (phase 13: model router)
|
|
11
|
+
|
|
12
|
+
- **Model Router** (`src/mission/router.ts`, §21):
|
|
13
|
+
- Pure routing layer — never calls a model. Deterministic by default.
|
|
14
|
+
- `routeTask()` — maps an agent type to a model tier (`large`/`medium`/`small`)
|
|
15
|
+
only when a provider is configured; otherwise routes to `none`.
|
|
16
|
+
- `AGENT_TIER` — §21 mapping (planning/source/review → large; attack execution
|
|
17
|
+
→ medium; verification → small).
|
|
18
|
+
- `loadRouterConfig()` — reads `BLITZSTRIKE_MODEL_PROVIDER` / `_LARGE` /
|
|
19
|
+
`_MEDIUM` / `_SMALL` env vars.
|
|
20
|
+
- `routingPlan()` — full plan (all `none` when deterministic).
|
|
21
|
+
- Mission Control records the routing decision (tier) per task and the overall
|
|
22
|
+
routing plan in the mission `decision_log`.
|
|
23
|
+
|
|
24
|
+
## [1.0.52] — 2026-09-13
|
|
25
|
+
|
|
26
|
+
### Added — Autonomous Security Engine (phase 12: browser automation agent)
|
|
27
|
+
|
|
28
|
+
- **Browser Automation Agent** (`src/browser-agent.ts`, §16):
|
|
29
|
+
- Session-based (one persistent page) so multi-step flows work.
|
|
30
|
+
- Ops: `open`/`navigate`/`click`/`type`/`evaluate`/`screenshot`/`back`/`forward`/
|
|
31
|
+
`get_cookie`/`set_cookie`, plus `detectAuthForm()` and `browserDiagnostics()`.
|
|
32
|
+
- Graceful degradation — every op reports `unavailable` when `playwright-core`
|
|
33
|
+
(optional peer) is missing, never throws.
|
|
34
|
+
- New `@browser` mission agent (URL-scope-gated) — detects login forms and JS
|
|
35
|
+
runtime errors and emits auth-flow hypotheses.
|
|
36
|
+
- New MCP tool `browser_agent` (session ops + detect_auth_form + diagnostics + close).
|
|
37
|
+
|
|
8
38
|
## [1.0.51] — 2026-09-13
|
|
9
39
|
|
|
10
40
|
### Added — Autonomous Security Engine (phase 11: adversarial reviewer)
|
package/dist/index.js
CHANGED
|
@@ -17722,6 +17722,219 @@ var init_universal_taint = __esm(() => {
|
|
|
17722
17722
|
extensionMap = new Map;
|
|
17723
17723
|
});
|
|
17724
17724
|
|
|
17725
|
+
// src/browser-agent.ts
|
|
17726
|
+
async function ensureChromium2() {
|
|
17727
|
+
if (chromiumCache2)
|
|
17728
|
+
return chromiumCache2;
|
|
17729
|
+
try {
|
|
17730
|
+
chromiumCache2 = await import("playwright-core");
|
|
17731
|
+
return chromiumCache2;
|
|
17732
|
+
} catch {
|
|
17733
|
+
return null;
|
|
17734
|
+
}
|
|
17735
|
+
}
|
|
17736
|
+
async function ensureSession() {
|
|
17737
|
+
if (page)
|
|
17738
|
+
return { available: true };
|
|
17739
|
+
const chr = await ensureChromium2();
|
|
17740
|
+
if (!chr)
|
|
17741
|
+
return { available: false, reason: "playwright-core not installed (optional peer dependency)" };
|
|
17742
|
+
try {
|
|
17743
|
+
browser = await chr.chromium.launch({ headless: true });
|
|
17744
|
+
page = await browser.newPage();
|
|
17745
|
+
page.on("console", (m) => {
|
|
17746
|
+
const msg = m;
|
|
17747
|
+
if (msg.type() === "error")
|
|
17748
|
+
consoleErrors.push(msg.text());
|
|
17749
|
+
});
|
|
17750
|
+
page.on("pageerror", (e) => pageErrors.push(String(e)));
|
|
17751
|
+
return { available: true };
|
|
17752
|
+
} catch (e) {
|
|
17753
|
+
return { available: false, reason: e instanceof Error ? e.message : String(e) };
|
|
17754
|
+
}
|
|
17755
|
+
}
|
|
17756
|
+
function unavailable2(op, reason) {
|
|
17757
|
+
return { op, ok: false, unavailable: true, detail: reason };
|
|
17758
|
+
}
|
|
17759
|
+
function fail(op, e) {
|
|
17760
|
+
return { op, ok: false, unavailable: false, detail: e instanceof Error ? e.message : String(e) };
|
|
17761
|
+
}
|
|
17762
|
+
async function browserOpen(url) {
|
|
17763
|
+
const s = await ensureSession();
|
|
17764
|
+
if (!s.available || !page)
|
|
17765
|
+
return unavailable2("open", s.reason ?? "unavailable");
|
|
17766
|
+
try {
|
|
17767
|
+
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 20000 });
|
|
17768
|
+
return { op: "open", ok: true, unavailable: false, detail: `opened ${redactSecrets(page.url())}` };
|
|
17769
|
+
} catch (e) {
|
|
17770
|
+
return fail("open", e);
|
|
17771
|
+
}
|
|
17772
|
+
}
|
|
17773
|
+
async function browserNavigate(url) {
|
|
17774
|
+
return browserOpen(url);
|
|
17775
|
+
}
|
|
17776
|
+
async function browserClick(selector) {
|
|
17777
|
+
const s = await ensureSession();
|
|
17778
|
+
if (!s.available || !page)
|
|
17779
|
+
return unavailable2("click", s.reason ?? "unavailable");
|
|
17780
|
+
try {
|
|
17781
|
+
await page.click(selector);
|
|
17782
|
+
return { op: "click", ok: true, unavailable: false, detail: `clicked ${selector}` };
|
|
17783
|
+
} catch (e) {
|
|
17784
|
+
return fail("click", e);
|
|
17785
|
+
}
|
|
17786
|
+
}
|
|
17787
|
+
async function browserType(selector, text) {
|
|
17788
|
+
const s = await ensureSession();
|
|
17789
|
+
if (!s.available || !page)
|
|
17790
|
+
return unavailable2("type", s.reason ?? "unavailable");
|
|
17791
|
+
try {
|
|
17792
|
+
await page.fill(selector, text);
|
|
17793
|
+
return { op: "type", ok: true, unavailable: false, detail: `typed into ${selector}` };
|
|
17794
|
+
} catch (e) {
|
|
17795
|
+
return fail("type", e);
|
|
17796
|
+
}
|
|
17797
|
+
}
|
|
17798
|
+
async function browserEvaluate(js) {
|
|
17799
|
+
const s = await ensureSession();
|
|
17800
|
+
if (!s.available || !page)
|
|
17801
|
+
return unavailable2("evaluate", s.reason ?? "unavailable");
|
|
17802
|
+
try {
|
|
17803
|
+
const value = await page.evaluate((code) => {
|
|
17804
|
+
const fn = new Function(`"use strict"; return (${code})`)();
|
|
17805
|
+
return typeof fn === "function" ? fn() : fn;
|
|
17806
|
+
}, js);
|
|
17807
|
+
return { op: "evaluate", ok: true, unavailable: false, detail: "evaluated", value };
|
|
17808
|
+
} catch (e) {
|
|
17809
|
+
return fail("evaluate", e);
|
|
17810
|
+
}
|
|
17811
|
+
}
|
|
17812
|
+
async function browserScreenshot(path) {
|
|
17813
|
+
const s = await ensureSession();
|
|
17814
|
+
if (!s.available || !page)
|
|
17815
|
+
return unavailable2("screenshot", s.reason ?? "unavailable");
|
|
17816
|
+
try {
|
|
17817
|
+
const buf = await page.screenshot(path ? { path } : {});
|
|
17818
|
+
return { op: "screenshot", ok: true, unavailable: false, detail: path ? `saved ${path}` : "captured (in-memory)", value: path ? undefined : buf.byteLength };
|
|
17819
|
+
} catch (e) {
|
|
17820
|
+
return fail("screenshot", e);
|
|
17821
|
+
}
|
|
17822
|
+
}
|
|
17823
|
+
async function browserBack() {
|
|
17824
|
+
const s = await ensureSession();
|
|
17825
|
+
if (!s.available || !page)
|
|
17826
|
+
return unavailable2("back", s.reason ?? "unavailable");
|
|
17827
|
+
try {
|
|
17828
|
+
await page.goBack();
|
|
17829
|
+
return { op: "back", ok: true, unavailable: false, detail: `back to ${redactSecrets(page.url())}` };
|
|
17830
|
+
} catch (e) {
|
|
17831
|
+
return fail("back", e);
|
|
17832
|
+
}
|
|
17833
|
+
}
|
|
17834
|
+
async function browserForward() {
|
|
17835
|
+
const s = await ensureSession();
|
|
17836
|
+
if (!s.available || !page)
|
|
17837
|
+
return unavailable2("forward", s.reason ?? "unavailable");
|
|
17838
|
+
try {
|
|
17839
|
+
await page.goForward();
|
|
17840
|
+
return { op: "forward", ok: true, unavailable: false, detail: `forward to ${redactSecrets(page.url())}` };
|
|
17841
|
+
} catch (e) {
|
|
17842
|
+
return fail("forward", e);
|
|
17843
|
+
}
|
|
17844
|
+
}
|
|
17845
|
+
async function browserGetCookie(name) {
|
|
17846
|
+
const s = await ensureSession();
|
|
17847
|
+
if (!s.available || !page)
|
|
17848
|
+
return unavailable2("get_cookie", s.reason ?? "unavailable");
|
|
17849
|
+
try {
|
|
17850
|
+
const cookies = await page.context().cookies();
|
|
17851
|
+
const hit = cookies.filter((c) => c.name === name);
|
|
17852
|
+
return { op: "get_cookie", ok: true, unavailable: false, detail: hit.length ? "found" : "not found", value: hit };
|
|
17853
|
+
} catch (e) {
|
|
17854
|
+
return fail("get_cookie", e);
|
|
17855
|
+
}
|
|
17856
|
+
}
|
|
17857
|
+
async function browserSetCookie(name, value) {
|
|
17858
|
+
const s = await ensureSession();
|
|
17859
|
+
if (!s.available || !page)
|
|
17860
|
+
return unavailable2("set_cookie", s.reason ?? "unavailable");
|
|
17861
|
+
try {
|
|
17862
|
+
const url = page.url();
|
|
17863
|
+
await page.context().addCookies([{ name, value, url }]);
|
|
17864
|
+
return { op: "set_cookie", ok: true, unavailable: false, detail: `set ${name}` };
|
|
17865
|
+
} catch (e) {
|
|
17866
|
+
return fail("set_cookie", e);
|
|
17867
|
+
}
|
|
17868
|
+
}
|
|
17869
|
+
async function browserClose() {
|
|
17870
|
+
if (browser) {
|
|
17871
|
+
await browser.close().catch(() => {
|
|
17872
|
+
return;
|
|
17873
|
+
});
|
|
17874
|
+
browser = null;
|
|
17875
|
+
page = null;
|
|
17876
|
+
}
|
|
17877
|
+
}
|
|
17878
|
+
async function detectAuthForm() {
|
|
17879
|
+
const s = await ensureSession();
|
|
17880
|
+
if (!s.available || !page)
|
|
17881
|
+
return unavailable2("evaluate", s.reason ?? "unavailable");
|
|
17882
|
+
try {
|
|
17883
|
+
const value = await page.evaluate(() => {
|
|
17884
|
+
const forms = Array.from(document.querySelectorAll("form"));
|
|
17885
|
+
const loginForm = forms.find((f) => /login|signin|auth/i.test(f.action || "") || f.querySelector('input[type="password"]'));
|
|
17886
|
+
if (!loginForm)
|
|
17887
|
+
return { found: false };
|
|
17888
|
+
const userField = loginForm.querySelector('input[type="email"], input[type="text"], input[name*="user"], input[name*="email"], input[name*="login"]');
|
|
17889
|
+
const passField = loginForm.querySelector('input[type="password"]');
|
|
17890
|
+
return {
|
|
17891
|
+
found: true,
|
|
17892
|
+
action: loginForm.action || "(self)",
|
|
17893
|
+
has_user: Boolean(userField),
|
|
17894
|
+
has_pass: Boolean(passField),
|
|
17895
|
+
user_selector: userField ? `input[name="${userField.name || ""}"], input[type="${userField.type}"]` : null,
|
|
17896
|
+
pass_selector: passField ? 'input[type="password"]' : null
|
|
17897
|
+
};
|
|
17898
|
+
});
|
|
17899
|
+
return { op: "evaluate", ok: true, unavailable: false, detail: value.found ? "login form detected" : "no login form", value };
|
|
17900
|
+
} catch (e) {
|
|
17901
|
+
return fail("evaluate", e);
|
|
17902
|
+
}
|
|
17903
|
+
}
|
|
17904
|
+
async function browserAgent(op, args = []) {
|
|
17905
|
+
switch (op) {
|
|
17906
|
+
case "open":
|
|
17907
|
+
return browserOpen(args[0] ?? "");
|
|
17908
|
+
case "navigate":
|
|
17909
|
+
return browserNavigate(args[0] ?? "");
|
|
17910
|
+
case "click":
|
|
17911
|
+
return browserClick(args[0] ?? "");
|
|
17912
|
+
case "type":
|
|
17913
|
+
return browserType(args[0] ?? "", args[1] ?? "");
|
|
17914
|
+
case "evaluate":
|
|
17915
|
+
return browserEvaluate(args[0] ?? "");
|
|
17916
|
+
case "screenshot":
|
|
17917
|
+
return browserScreenshot(args[0] || undefined);
|
|
17918
|
+
case "back":
|
|
17919
|
+
return browserBack();
|
|
17920
|
+
case "forward":
|
|
17921
|
+
return browserForward();
|
|
17922
|
+
case "get_cookie":
|
|
17923
|
+
return browserGetCookie(args[0] ?? "");
|
|
17924
|
+
case "set_cookie":
|
|
17925
|
+
return browserSetCookie(args[0] ?? "", args[1] ?? "");
|
|
17926
|
+
}
|
|
17927
|
+
}
|
|
17928
|
+
function browserDiagnostics() {
|
|
17929
|
+
return { console_errors: [...consoleErrors], page_errors: [...pageErrors] };
|
|
17930
|
+
}
|
|
17931
|
+
var chromiumCache2 = null, browser = null, page = null, consoleErrors, pageErrors;
|
|
17932
|
+
var init_browser_agent = __esm(() => {
|
|
17933
|
+
init_evidence();
|
|
17934
|
+
consoleErrors = [];
|
|
17935
|
+
pageErrors = [];
|
|
17936
|
+
});
|
|
17937
|
+
|
|
17725
17938
|
// src/sync.ts
|
|
17726
17939
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync16, readdirSync as readdirSync5, statSync as statSync3, rmSync as rmSync3 } from "node:fs";
|
|
17727
17940
|
import { join as join12 } from "node:path";
|
|
@@ -18359,7 +18572,7 @@ function sourceFiles(root, max = 500) {
|
|
|
18359
18572
|
function agentFor(type) {
|
|
18360
18573
|
return AGENTS[type];
|
|
18361
18574
|
}
|
|
18362
|
-
var reconAgent, webAgent, sourceAgent, analysisAgent, authAgent, validatorAgent, reviewerAgent, reporterAgent, mobileAgent, cloudAgent, commanderAgent, apiAgent, AGENTS;
|
|
18575
|
+
var reconAgent, webAgent, sourceAgent, analysisAgent, authAgent, validatorAgent, reviewerAgent, browserAgent2, reporterAgent, mobileAgent, cloudAgent, commanderAgent, apiAgent, AGENTS;
|
|
18363
18576
|
var init_agents = __esm(() => {
|
|
18364
18577
|
init_planner();
|
|
18365
18578
|
init_reviewer();
|
|
@@ -18556,6 +18769,52 @@ var init_agents = __esm(() => {
|
|
|
18556
18769
|
return { ok: true, output: { outcomes: results.map((r) => ({ id: r.hypothesis_id, outcome: r.outcome })) }, hypotheses, graph: emptyGraph() };
|
|
18557
18770
|
}
|
|
18558
18771
|
};
|
|
18772
|
+
browserAgent2 = {
|
|
18773
|
+
type: "browser",
|
|
18774
|
+
responsibility: "Drive a real browser to detect DOM issues and auth flows.",
|
|
18775
|
+
tools: ["browser_open", "browser_click", "browser_type", "browser_evaluate", "browser_screenshot", "browser_navigate", "browser_back", "browser_forward", "browser_get_cookie", "browser_set_cookie"],
|
|
18776
|
+
async execute(_task, ctx) {
|
|
18777
|
+
if (!/^https?:\/\//i.test(ctx.mission.target) || !ctx.scopeAllowed) {
|
|
18778
|
+
return { ok: false, output: {}, hypotheses: [], graph: emptyGraph(), error: "browser agent requires an authorized URL target" };
|
|
18779
|
+
}
|
|
18780
|
+
await Promise.resolve().then(() => init_browser_agent());
|
|
18781
|
+
const opened = await browserOpen(ctx.mission.target);
|
|
18782
|
+
if (opened.unavailable) {
|
|
18783
|
+
return { ok: false, output: {}, hypotheses: [], graph: emptyGraph(), error: opened.detail };
|
|
18784
|
+
}
|
|
18785
|
+
const auth = await detectAuthForm();
|
|
18786
|
+
const diag = browserDiagnostics();
|
|
18787
|
+
await browserClose();
|
|
18788
|
+
const hypotheses = [];
|
|
18789
|
+
const authInfo = auth.value ?? {};
|
|
18790
|
+
if (authInfo.found) {
|
|
18791
|
+
hypotheses.push(makeHypothesis({
|
|
18792
|
+
type: "auth_flow_detected",
|
|
18793
|
+
target: ctx.mission.target,
|
|
18794
|
+
evidence: `login form detected (user_field=${authInfo.has_user}, pass_field=${authInfo.has_pass})`,
|
|
18795
|
+
confidence: 0.6,
|
|
18796
|
+
required_validation: "login flow",
|
|
18797
|
+
potential_impact: "auth boundary"
|
|
18798
|
+
}));
|
|
18799
|
+
}
|
|
18800
|
+
if (diag.console_errors.length > 0 || diag.page_errors.length > 0) {
|
|
18801
|
+
hypotheses.push(makeHypothesis({
|
|
18802
|
+
type: "js_runtime_error",
|
|
18803
|
+
target: ctx.mission.target,
|
|
18804
|
+
evidence: `console_errors=${diag.console_errors.length} page_errors=${diag.page_errors.length}`,
|
|
18805
|
+
confidence: 0.4,
|
|
18806
|
+
required_validation: "review",
|
|
18807
|
+
potential_impact: "unspecified"
|
|
18808
|
+
}));
|
|
18809
|
+
}
|
|
18810
|
+
return {
|
|
18811
|
+
ok: true,
|
|
18812
|
+
output: { opened: opened.ok, auth_form: authInfo.found ?? false, console_errors: diag.console_errors.length, page_errors: diag.page_errors.length },
|
|
18813
|
+
hypotheses,
|
|
18814
|
+
graph: emptyGraph()
|
|
18815
|
+
};
|
|
18816
|
+
}
|
|
18817
|
+
};
|
|
18559
18818
|
reporterAgent = {
|
|
18560
18819
|
type: "reporter",
|
|
18561
18820
|
responsibility: "Produce the final structured mission report.",
|
|
@@ -18666,7 +18925,8 @@ ${m.hypotheses.map((h) => `- [${h.status}] ${h.type} @ ${h.target} (confidence $
|
|
|
18666
18925
|
analysis: analysisAgent,
|
|
18667
18926
|
validator: validatorAgent,
|
|
18668
18927
|
reviewer: reviewerAgent,
|
|
18669
|
-
reporter: reporterAgent
|
|
18928
|
+
reporter: reporterAgent,
|
|
18929
|
+
browser: browserAgent2
|
|
18670
18930
|
};
|
|
18671
18931
|
});
|
|
18672
18932
|
|
|
@@ -18792,7 +19052,8 @@ var init_recovery = __esm(() => {
|
|
|
18792
19052
|
analysis: ["source"],
|
|
18793
19053
|
validator: ["reviewer"],
|
|
18794
19054
|
reviewer: ["validator"],
|
|
18795
|
-
reporter: []
|
|
19055
|
+
reporter: [],
|
|
19056
|
+
browser: ["web"]
|
|
18796
19057
|
};
|
|
18797
19058
|
});
|
|
18798
19059
|
|
|
@@ -18824,6 +19085,55 @@ var init_memory2 = __esm(() => {
|
|
|
18824
19085
|
init_memory();
|
|
18825
19086
|
});
|
|
18826
19087
|
|
|
19088
|
+
// src/mission/router.ts
|
|
19089
|
+
function isModelConfigured(config) {
|
|
19090
|
+
return Boolean(config?.provider);
|
|
19091
|
+
}
|
|
19092
|
+
function routeTask(agent, config) {
|
|
19093
|
+
if (!isModelConfigured(config)) {
|
|
19094
|
+
return { agent, tier: "none", model: null, deterministic: true };
|
|
19095
|
+
}
|
|
19096
|
+
const tier = AGENT_TIER[agent] ?? "medium";
|
|
19097
|
+
const key = `model_${tier}`;
|
|
19098
|
+
const model = config?.[key] ?? null;
|
|
19099
|
+
return { agent, tier, model, deterministic: model === null };
|
|
19100
|
+
}
|
|
19101
|
+
function loadRouterConfig(env = process.env) {
|
|
19102
|
+
return {
|
|
19103
|
+
provider: env.BLITZSTRIKE_MODEL_PROVIDER || undefined,
|
|
19104
|
+
model_large: env.BLITZSTRIKE_MODEL_LARGE || undefined,
|
|
19105
|
+
model_medium: env.BLITZSTRIKE_MODEL_MEDIUM || undefined,
|
|
19106
|
+
model_small: env.BLITZSTRIKE_MODEL_SMALL || undefined
|
|
19107
|
+
};
|
|
19108
|
+
}
|
|
19109
|
+
function routingPlan(config) {
|
|
19110
|
+
if (!isModelConfigured(config)) {
|
|
19111
|
+
const out = {};
|
|
19112
|
+
for (const k of Object.keys(AGENT_TIER))
|
|
19113
|
+
out[k] = "none";
|
|
19114
|
+
return out;
|
|
19115
|
+
}
|
|
19116
|
+
return { ...AGENT_TIER };
|
|
19117
|
+
}
|
|
19118
|
+
var AGENT_TIER;
|
|
19119
|
+
var init_router = __esm(() => {
|
|
19120
|
+
AGENT_TIER = {
|
|
19121
|
+
commander: "large",
|
|
19122
|
+
source: "large",
|
|
19123
|
+
analysis: "large",
|
|
19124
|
+
reviewer: "large",
|
|
19125
|
+
recon: "medium",
|
|
19126
|
+
web: "medium",
|
|
19127
|
+
api: "medium",
|
|
19128
|
+
auth: "medium",
|
|
19129
|
+
mobile: "medium",
|
|
19130
|
+
cloud: "medium",
|
|
19131
|
+
reporter: "medium",
|
|
19132
|
+
validator: "small",
|
|
19133
|
+
browser: "small"
|
|
19134
|
+
};
|
|
19135
|
+
});
|
|
19136
|
+
|
|
18827
19137
|
// src/mission/control.ts
|
|
18828
19138
|
import { existsSync as existsSync8, statSync as statSync4 } from "node:fs";
|
|
18829
19139
|
function scopeAllowed(mission) {
|
|
@@ -18903,6 +19213,11 @@ async function runMission(mission) {
|
|
|
18903
19213
|
let m = { ...mission, status: "running" };
|
|
18904
19214
|
m.tasks = buildInitialTasks(m);
|
|
18905
19215
|
m.graph = loadEscalationGraph(m.graph);
|
|
19216
|
+
const routerCfg = loadRouterConfig();
|
|
19217
|
+
m.decision_log = [
|
|
19218
|
+
...m.decision_log,
|
|
19219
|
+
{ at: new Date().toISOString(), agent: "router", decision: isModelConfigured(routerCfg) ? `model routing active: ${JSON.stringify(routingPlan(routerCfg))}` : "deterministic (no model provider configured)" }
|
|
19220
|
+
];
|
|
18906
19221
|
m = saveMission(m);
|
|
18907
19222
|
const scope = m.scope.join(",");
|
|
18908
19223
|
let iterations = 0;
|
|
@@ -18932,20 +19247,22 @@ async function runMission(mission) {
|
|
|
18932
19247
|
const results = await Promise.all(batch.map((t) => executeTask(t, m, scope)));
|
|
18933
19248
|
for (const r of results) {
|
|
18934
19249
|
const decision = r.ok ? `${r.task.agent_type} completed (${Object.keys(r.output).length} output fields, ${r.hypotheses.length} hypotheses)` : `${r.task.agent_type} failed: ${r.error ?? "unknown"}`;
|
|
19250
|
+
const route = routeTask(r.task.agent_type, routerCfg);
|
|
19251
|
+
const logEntry = (entryDecision) => ({ at: new Date().toISOString(), agent: r.task.agent_type, decision: entryDecision, tier: route.tier });
|
|
18935
19252
|
if (r.ok) {
|
|
18936
19253
|
m = {
|
|
18937
19254
|
...m,
|
|
18938
19255
|
tasks: setTask(m.tasks, r.task.task_id, { status: "success", result: r.output }),
|
|
18939
19256
|
hypotheses: mergeHypotheses(m.hypotheses, r.hypotheses),
|
|
18940
19257
|
graph: mergeGraphs(m.graph, r.graph),
|
|
18941
|
-
decision_log: [...m.decision_log,
|
|
19258
|
+
decision_log: [...m.decision_log, logEntry(decision)]
|
|
18942
19259
|
};
|
|
18943
19260
|
if (r.task.agent_type === "reporter") {
|
|
18944
19261
|
m = { ...m, report: r.output };
|
|
18945
19262
|
}
|
|
18946
19263
|
} else {
|
|
18947
19264
|
const rec = recoveryDecision(r.task, r.error ?? "unknown error");
|
|
18948
|
-
const stamp =
|
|
19265
|
+
const stamp = logEntry(decision);
|
|
18949
19266
|
if (rec.action === "retry") {
|
|
18950
19267
|
const retried = setTask(m.tasks, r.task.task_id, { status: "retry", error: r.error ?? null });
|
|
18951
19268
|
m = { ...m, tasks: retried, decision_log: [...m.decision_log, stamp] };
|
|
@@ -19013,6 +19330,7 @@ var init_control = __esm(() => {
|
|
|
19013
19330
|
init_coverage();
|
|
19014
19331
|
init_recovery();
|
|
19015
19332
|
init_memory2();
|
|
19333
|
+
init_router();
|
|
19016
19334
|
MODE_PROFILES = {
|
|
19017
19335
|
web: { agents: ["recon", "web", "api", "auth", "validator", "reviewer", "reporter"], verify: true, risk: "medium" },
|
|
19018
19336
|
api: { agents: ["recon", "api", "auth", "validator", "reviewer", "reporter"], verify: true, risk: "medium" },
|
|
@@ -53121,6 +53439,7 @@ async function browserValidate(check, target, payload) {
|
|
|
53121
53439
|
}
|
|
53122
53440
|
|
|
53123
53441
|
// src/server.ts
|
|
53442
|
+
init_browser_agent();
|
|
53124
53443
|
init_universal_taint();
|
|
53125
53444
|
|
|
53126
53445
|
// src/guidance.ts
|
|
@@ -54684,6 +55003,28 @@ function createServer() {
|
|
|
54684
55003
|
const result = await browserValidate(check, target, payload);
|
|
54685
55004
|
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
54686
55005
|
});
|
|
55006
|
+
server.registerTool("browser_agent", {
|
|
55007
|
+
title: "Browser automation agent (session)",
|
|
55008
|
+
description: "PHASE 12: drive a real headless-Chromium session. Ops: open, navigate, click, type, evaluate, screenshot, back, forward, get_cookie, set_cookie, plus detect_auth_form, diagnostics, close. Enables multi-step flows (login/MFA) and DOM issue detection. Requires playwright-core (optional peer dependency).",
|
|
55009
|
+
inputSchema: {
|
|
55010
|
+
op: _enum(["open", "navigate", "click", "type", "evaluate", "screenshot", "back", "forward", "get_cookie", "set_cookie", "detect_auth_form", "diagnostics", "close"]),
|
|
55011
|
+
args: array(string2()).optional().describe("Positional args (url, selector, text, js, cookie name/value, screenshot path)")
|
|
55012
|
+
}
|
|
55013
|
+
}, async ({ op, args }) => {
|
|
55014
|
+
if (op === "detect_auth_form") {
|
|
55015
|
+
const r = await detectAuthForm();
|
|
55016
|
+
return { content: [{ type: "text", text: JSON.stringify(r) }] };
|
|
55017
|
+
}
|
|
55018
|
+
if (op === "diagnostics") {
|
|
55019
|
+
return { content: [{ type: "text", text: JSON.stringify(browserDiagnostics()) }] };
|
|
55020
|
+
}
|
|
55021
|
+
if (op === "close") {
|
|
55022
|
+
await browserClose();
|
|
55023
|
+
return { content: [{ type: "text", text: JSON.stringify({ ok: true, detail: "session closed" }) }] };
|
|
55024
|
+
}
|
|
55025
|
+
const r = await browserAgent(op, args ?? []);
|
|
55026
|
+
return { content: [{ type: "text", text: JSON.stringify(r) }] };
|
|
55027
|
+
});
|
|
54687
55028
|
server.registerTool("taint_tree", {
|
|
54688
55029
|
title: "Whole-tree taint scan",
|
|
54689
55030
|
description: "EAGLE-EYE: run inter-procedural taint analysis across an entire source tree.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.53",
|
|
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": {
|