blitzstrike 1.0.37 → 1.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,33 @@ 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.39] — 2026-09-13
9
+
10
+ ### Added
11
+
12
+ - **Phase 5 — Framework Intelligence** (`src/frameworks.ts` + `intelligence/frameworks.json`):
13
+ - Data-driven framework knowledge for 7 frameworks (361 patterns), extensible
14
+ without code changes: Laravel, WordPress (PHP); Express, Next.js (JS/TS);
15
+ Django, FastAPI (Python); Spring (Java). Rails (Ruby) deferred until Ruby support.
16
+ - Each framework defines sources, sinks, sanitizers, auth gates, routing, ORM,
17
+ and middleware patterns (with CWE tags on sinks).
18
+ - `detectFramework(code, language)` — heuristic detection via scored signals.
19
+ - `scanFramework(code, framework)` — framework-aware source/sink/sanitizer/auth hits.
20
+ - New MCP tools: `list_frameworks`, `detect_framework`, `framework_intel`.
21
+
22
+ ## [1.0.38] — 2026-09-13
23
+
24
+ ### Fixed (Phase 4 review)
25
+
26
+ - `diff_analyze` ignored the `language` argument for non-PHP code (bare `file`
27
+ without an extension resolved to `unknown`, silently returning 0 findings).
28
+ The engine now derives a probe extension from the declared language.
29
+ - `eagle_eye2` now surfaces `entry_points` (uncalled functions = potential unauth
30
+ entry points) and `unreachable` (dead code) — previously computed but hidden.
31
+ - Removed the unused `call_graph` field from `Eagle2Result.summary` (Map/Set-based,
32
+ not JSON-safe, never consumed).
33
+ - Removed the dead `nextCorrelationId` export from `audit.ts`.
34
+
8
35
  ## [1.0.37] — 2026-09-13
9
36
 
10
37
  ### Added
package/dist/index.js CHANGED
@@ -14820,10 +14820,10 @@ var require_src = __commonJS(function(exports, module) {
14820
14820
  });
14821
14821
 
14822
14822
  // src/sync.ts
14823
- import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync15, readdirSync as readdirSync5, statSync as statSync3, rmSync as rmSync3 } from "node:fs";
14824
- import { join as join11 } from "node:path";
14823
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync16, readdirSync as readdirSync5, statSync as statSync3, rmSync as rmSync3 } from "node:fs";
14824
+ import { join as join12 } from "node:path";
14825
14825
  import { homedir as homedir4 } from "node:os";
14826
- import { fileURLToPath as fileURLToPath7 } from "node:url";
14826
+ import { fileURLToPath as fileURLToPath8 } from "node:url";
14827
14827
  import { spawnSync as spawnSync2 } from "node:child_process";
14828
14828
  function dirExists(p) {
14829
14829
  try {
@@ -14838,7 +14838,7 @@ function countFiles(dir) {
14838
14838
  const walk = (d) => {
14839
14839
  for (const e of readdirSync5(d, { withFileTypes: true })) {
14840
14840
  if (e.isDirectory())
14841
- walk(join11(d, e.name));
14841
+ walk(join12(d, e.name));
14842
14842
  else
14843
14843
  n++;
14844
14844
  }
@@ -14852,8 +14852,8 @@ function countFiles(dir) {
14852
14852
  function syncData() {
14853
14853
  if (!dirExists(DATA_ROOT2))
14854
14854
  mkdirSync3(DATA_ROOT2, { recursive: true });
14855
- const payloadsPath = join11(DATA_ROOT2, "payloads");
14856
- const templatesPath = join11(DATA_ROOT2, "templates");
14855
+ const payloadsPath = join12(DATA_ROOT2, "payloads");
14856
+ const templatesPath = join12(DATA_ROOT2, "templates");
14857
14857
  const hasPayloads = dirExists(payloadsPath) && countFiles(payloadsPath) > 0;
14858
14858
  const hasTemplates = dirExists(templatesPath) && countFiles(templatesPath) > 0;
14859
14859
  if (hasPayloads && hasTemplates) {
@@ -14863,8 +14863,8 @@ function syncData() {
14863
14863
  data_root: DATA_ROOT2
14864
14864
  };
14865
14865
  }
14866
- const localPayloads = join11(ROOT5, "payloads");
14867
- const localTemplates = join11(ROOT5, "templates");
14866
+ const localPayloads = join12(ROOT6, "payloads");
14867
+ const localTemplates = join12(ROOT6, "templates");
14868
14868
  let payloadsSynced = false;
14869
14869
  let templatesSynced = false;
14870
14870
  if (!hasPayloads && dirExists(localPayloads)) {
@@ -14877,7 +14877,7 @@ function syncData() {
14877
14877
  }
14878
14878
  const gitOk = spawnSync2("git", ["--version"]).status === 0;
14879
14879
  if (gitOk && (!dirExists(payloadsPath) || countFiles(payloadsPath) === 0 || !dirExists(templatesPath) || countFiles(templatesPath) === 0)) {
14880
- const tmp = join11(DATA_ROOT2, ".tmp-clone");
14880
+ const tmp = join12(DATA_ROOT2, ".tmp-clone");
14881
14881
  if (dirExists(tmp))
14882
14882
  rmSync3(tmp, { recursive: true, force: true });
14883
14883
  const r = spawnSync2("git", ["clone", "--depth", "1", "--filter=blob:none", "--sparse", GITHUB_REPO, tmp], { timeout: 120000 });
@@ -14885,11 +14885,11 @@ function syncData() {
14885
14885
  const sparse = spawnSync2("git", ["-C", tmp, "sparse-checkout", "set", "payloads", "templates"], { timeout: 120000 });
14886
14886
  if (sparse.status === 0) {
14887
14887
  if (!dirExists(payloadsPath) || countFiles(payloadsPath) === 0) {
14888
- copyDir(join11(tmp, "payloads"), payloadsPath);
14888
+ copyDir(join12(tmp, "payloads"), payloadsPath);
14889
14889
  payloadsSynced = true;
14890
14890
  }
14891
14891
  if (!dirExists(templatesPath) || countFiles(templatesPath) === 0) {
14892
- copyDir(join11(tmp, "templates"), templatesPath);
14892
+ copyDir(join12(tmp, "templates"), templatesPath);
14893
14893
  templatesSynced = true;
14894
14894
  }
14895
14895
  }
@@ -14911,18 +14911,18 @@ function copyDir(src, dst) {
14911
14911
  function manualCopy(src, dst) {
14912
14912
  mkdirSync3(dst, { recursive: true });
14913
14913
  for (const e of readdirSync5(src, { withFileTypes: true })) {
14914
- const s = join11(src, e.name);
14915
- const d = join11(dst, e.name);
14914
+ const s = join12(src, e.name);
14915
+ const d = join12(dst, e.name);
14916
14916
  if (e.isDirectory())
14917
14917
  manualCopy(s, d);
14918
14918
  else
14919
- writeFileSync4(d, readFileSync15(s));
14919
+ writeFileSync4(d, readFileSync16(s));
14920
14920
  }
14921
14921
  }
14922
- var ROOT5, DATA_ROOT2, GITHUB_REPO = "https://github.com/shinthink/blitzstrike.git";
14922
+ var ROOT6, DATA_ROOT2, GITHUB_REPO = "https://github.com/shinthink/blitzstrike.git";
14923
14923
  var init_sync = __esm(() => {
14924
- ROOT5 = join11(fileURLToPath7(new URL(".", import.meta.url)), "..");
14925
- DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ?? join11(homedir4(), ".blitzstrike", "data");
14924
+ ROOT6 = join12(fileURLToPath8(new URL(".", import.meta.url)), "..");
14925
+ DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ?? join12(homedir4(), ".blitzstrike", "data");
14926
14926
  });
14927
14927
 
14928
14928
  // src/update.ts
@@ -29601,6 +29601,7 @@ class StdioServerTransport {
29601
29601
 
29602
29602
  // src/server.ts
29603
29603
  init_scanner();
29604
+ import { readFileSync as readFileSync17 } from "node:fs";
29604
29605
 
29605
29606
  // src/recon.ts
29606
29607
  var TIMEOUT_MS = 25000;
@@ -31777,6 +31778,30 @@ function resolveCall(g, call, callerId, ctx, file, line) {
31777
31778
  return;
31778
31779
  }
31779
31780
  }
31781
+ function reachableFrom(g, entry) {
31782
+ const seen = new Set;
31783
+ const stack = [entry];
31784
+ while (stack.length) {
31785
+ const cur = stack.pop();
31786
+ if (seen.has(cur))
31787
+ continue;
31788
+ seen.add(cur);
31789
+ const n = g.nodes.get(cur);
31790
+ if (!n)
31791
+ continue;
31792
+ for (const c of n.callees)
31793
+ stack.push(c);
31794
+ }
31795
+ return seen;
31796
+ }
31797
+ function entryPoints(g) {
31798
+ const entries = [];
31799
+ for (const [id, n] of g.nodes) {
31800
+ if (n.callers.size === 0)
31801
+ entries.push(id);
31802
+ }
31803
+ return entries;
31804
+ }
31780
31805
 
31781
31806
  // src/eagle2.ts
31782
31807
  var parser3 = new import_php_parser3.Engine({
@@ -32206,11 +32231,17 @@ function resolveFuncId(name, summaries) {
32206
32231
  }
32207
32232
  function analyzeDataFlow2(path) {
32208
32233
  const cg = buildCallGraph(path);
32234
+ const entries = entryPoints(cg);
32235
+ const reachable = new Set;
32236
+ for (const e of entries)
32237
+ for (const n of reachableFrom(cg, e))
32238
+ reachable.add(n);
32239
+ const unreachable = [...cg.nodes.keys()].filter((id) => !reachable.has(id));
32209
32240
  const result = {
32210
32241
  file: path,
32211
32242
  findings: [],
32212
32243
  suppressed: 0,
32213
- summary: { functions: 0, methods: 0, edges: cg.edges.length, call_graph: cg }
32244
+ summary: { functions: 0, methods: 0, edges: cg.edges.length, entry_points: entries, unreachable }
32214
32245
  };
32215
32246
  let code;
32216
32247
  try {
@@ -50732,7 +50763,9 @@ function runEngine(code, language, file) {
50732
50763
  rmSync(dir, { recursive: true, force: true });
50733
50764
  }
50734
50765
  }
50735
- const r = analyzeTaintUniversal(code, file);
50766
+ const extMap = { javascript: ".js", typescript: ".ts", python: ".py", java: ".java" };
50767
+ const probe = file.includes(".") ? file : `target${extMap[language] ?? ""}`;
50768
+ const r = analyzeTaintUniversal(code, probe);
50736
50769
  return r.findings.map((f) => ({ sink: f.sink, sink_line: f.sink_line, category: f.sink, source: f.source_kind, cwe: f.cwe }));
50737
50770
  }
50738
50771
  function diffLines(oldText, newText) {
@@ -50905,6 +50938,98 @@ function analyzeGitDiff(repo, base = "HEAD~1", head = "HEAD") {
50905
50938
  return { repo, base, head, files, total_changes, security_sensitive };
50906
50939
  }
50907
50940
 
50941
+ // src/frameworks.ts
50942
+ import { readFileSync as readFileSync14, existsSync as existsSync6 } from "node:fs";
50943
+ import { join as join10 } from "node:path";
50944
+ import { fileURLToPath as fileURLToPath6 } from "node:url";
50945
+ var ROOT4 = join10(fileURLToPath6(new URL(".", import.meta.url)), "..");
50946
+ var INTEL2 = join10(ROOT4, "intelligence");
50947
+ var cache = null;
50948
+ function load() {
50949
+ if (cache)
50950
+ return cache;
50951
+ const p = join10(INTEL2, "frameworks.json");
50952
+ if (!existsSync6(p))
50953
+ return null;
50954
+ try {
50955
+ cache = JSON.parse(readFileSync14(p, "utf8"));
50956
+ return cache;
50957
+ } catch {
50958
+ return null;
50959
+ }
50960
+ }
50961
+ function listFrameworks() {
50962
+ const data = load();
50963
+ if (!data)
50964
+ return [];
50965
+ return data.frameworks.map((f) => ({ id: f.id, name: f.name, language: f.language }));
50966
+ }
50967
+ function frameworkProfile(id) {
50968
+ const data = load();
50969
+ if (!data)
50970
+ return null;
50971
+ return data.frameworks.find((f) => f.id === id) ?? null;
50972
+ }
50973
+ function detectFramework(code, language) {
50974
+ const data = load();
50975
+ const hay = code.toLowerCase();
50976
+ const candidates = [];
50977
+ if (data) {
50978
+ for (const f of data.frameworks) {
50979
+ if (f.language !== language)
50980
+ continue;
50981
+ const score = f.detect.reduce((n, sig) => hay.includes(sig.toLowerCase()) ? n + 1 : n, 0);
50982
+ if (score > 0)
50983
+ candidates.push({ id: f.id, name: f.name, score });
50984
+ }
50985
+ }
50986
+ candidates.sort((a, b) => b.score - a.score);
50987
+ return { framework: candidates[0]?.id ?? null, language, candidates };
50988
+ }
50989
+ function scanFramework(code, frameworkId) {
50990
+ const profile = frameworkProfile(frameworkId);
50991
+ const empty = {
50992
+ framework: frameworkId,
50993
+ language: profile?.language ?? "unknown",
50994
+ detected: false,
50995
+ sources: [],
50996
+ sinks: [],
50997
+ sanitizers: [],
50998
+ auth: [],
50999
+ summary: { sources: 0, sinks: 0, sanitizers: 0, auth: 0 }
51000
+ };
51001
+ if (!profile)
51002
+ return empty;
51003
+ const lines = code.split(`
51004
+ `);
51005
+ const scan = (patterns) => {
51006
+ const hits = [];
51007
+ for (let i = 0;i < lines.length; i++) {
51008
+ const line = lines[i].toLowerCase();
51009
+ for (const p of patterns) {
51010
+ if (line.includes(p.pattern.toLowerCase())) {
51011
+ hits.push({ line: i + 1, pattern: p.pattern, label: p.label, cwe: p.cwe });
51012
+ }
51013
+ }
51014
+ }
51015
+ return hits;
51016
+ };
51017
+ const sources = scan(profile.sources);
51018
+ const sinks = scan(profile.sinks);
51019
+ const sanitizers = scan(profile.sanitizers);
51020
+ const auth = scan(profile.auth);
51021
+ return {
51022
+ framework: frameworkId,
51023
+ language: profile.language,
51024
+ detected: true,
51025
+ sources,
51026
+ sinks,
51027
+ sanitizers,
51028
+ auth,
51029
+ summary: { sources: sources.length, sinks: sinks.length, sanitizers: sanitizers.length, auth: auth.length }
51030
+ };
51031
+ }
51032
+
50908
51033
  // src/guidance.ts
50909
51034
  var SINK_DIRECTIVES = {
50910
51035
  sql_execution: "Validate the SQL injection live with strike_verify (use a unique MARKER and a NEGATIVE CONTROL that stays inert), or read_tool_manual for sqlmap. Only a reflected marker + inert control = confirmed.",
@@ -51718,16 +51843,16 @@ function reportJson(findings, opts = {}) {
51718
51843
  }
51719
51844
 
51720
51845
  // src/benchmark.ts
51721
- import { readFileSync as readFileSync14, readdirSync as readdirSync4, writeFileSync as writeFileSync3, rmSync as rmSync2 } from "node:fs";
51722
- import { join as join10 } from "node:path";
51723
- import { fileURLToPath as fileURLToPath6 } from "node:url";
51846
+ import { readFileSync as readFileSync15, readdirSync as readdirSync4, writeFileSync as writeFileSync3, rmSync as rmSync2 } from "node:fs";
51847
+ import { join as join11 } from "node:path";
51848
+ import { fileURLToPath as fileURLToPath7 } from "node:url";
51724
51849
  import { tmpdir as tmpdir2 } from "node:os";
51725
- var ROOT4 = join10(fileURLToPath6(new URL(".", import.meta.url)), "..");
51726
- var CORPUS = join10(ROOT4, "bench", "corpus");
51850
+ var ROOT5 = join11(fileURLToPath7(new URL(".", import.meta.url)), "..");
51851
+ var CORPUS = join11(ROOT5, "bench", "corpus");
51727
51852
  function parseCorpusFile(path) {
51728
51853
  let text;
51729
51854
  try {
51730
- text = readFileSync14(path, "utf8");
51855
+ text = readFileSync15(path, "utf8");
51731
51856
  } catch {
51732
51857
  return null;
51733
51858
  }
@@ -51777,7 +51902,7 @@ function loadCorpus() {
51777
51902
  for (const f of readdirSync4(CORPUS)) {
51778
51903
  if (!f.endsWith(".md"))
51779
51904
  continue;
51780
- const e = parseCorpusFile(join10(CORPUS, f));
51905
+ const e = parseCorpusFile(join11(CORPUS, f));
51781
51906
  if (e)
51782
51907
  entries.push(e);
51783
51908
  }
@@ -51789,7 +51914,7 @@ function loadCorpus() {
51789
51914
  function detect(entry) {
51790
51915
  const lang = entry.language;
51791
51916
  if (lang === "php") {
51792
- const tmp = join10(tmpdir2(), `blitzstrike-bench-${entry.id}-${process.pid}.php`);
51917
+ const tmp = join11(tmpdir2(), `blitzstrike-bench-${entry.id}-${process.pid}.php`);
51793
51918
  writeFileSync3(tmp, entry.code);
51794
51919
  const r = analyzeDataFlow2(tmp);
51795
51920
  rmSync2(tmp, { force: true });
@@ -52601,6 +52726,8 @@ function createServer() {
52601
52726
  functions: r.summary.functions,
52602
52727
  methods: r.summary.methods,
52603
52728
  call_edges: r.summary.edges,
52729
+ entry_points: r.summary.entry_points,
52730
+ unreachable: r.summary.unreachable,
52604
52731
  results: r.findings,
52605
52732
  next_steps: guidance
52606
52733
  })
@@ -52635,6 +52762,62 @@ function createServer() {
52635
52762
  }
52636
52763
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
52637
52764
  });
52765
+ server.registerTool("list_frameworks", {
52766
+ title: "List supported frameworks",
52767
+ description: "PHASE 5: list the web frameworks Blitz Strike understands for framework-aware security analysis (Laravel, WordPress, Express, Next.js, Django, FastAPI, Spring)."
52768
+ }, async () => {
52769
+ return { content: [{ type: "text", text: JSON.stringify({ frameworks: listFrameworks() }) }] };
52770
+ });
52771
+ server.registerTool("detect_framework", {
52772
+ title: "Detect web framework",
52773
+ description: "PHASE 5: detect the web framework used by a source file (reads the file, then scores each framework's detection signals for the file's language).",
52774
+ inputSchema: {
52775
+ path: string2().optional().describe("Source file path (alternative: code)"),
52776
+ code: string2().optional().describe("Source code directly (alternative to path)"),
52777
+ language: string2().optional().describe("Language (auto-detected from path if omitted)")
52778
+ }
52779
+ }, async ({ path, code, language }) => {
52780
+ let src = code ?? "";
52781
+ let lang = language;
52782
+ if (path && !code) {
52783
+ try {
52784
+ src = readFileSync17(path, "utf8");
52785
+ } catch {
52786
+ return { content: [{ type: "text", text: JSON.stringify({ error: `cannot read ${path}` }) }] };
52787
+ }
52788
+ lang = lang ?? detectLanguage(path)?.language ?? "php";
52789
+ }
52790
+ const d = detectFramework(src, lang ?? "php");
52791
+ const scan = d.framework ? scanFramework(src, d.framework) : null;
52792
+ return {
52793
+ content: [{
52794
+ type: "text",
52795
+ text: JSON.stringify({
52796
+ framework: d.framework,
52797
+ language: d.language,
52798
+ candidates: d.candidates,
52799
+ scan
52800
+ })
52801
+ }]
52802
+ };
52803
+ });
52804
+ server.registerTool("framework_intel", {
52805
+ title: "Framework security knowledge",
52806
+ description: "PHASE 5: return a framework's security knowledge (sources, sinks, sanitizers, auth gates, routing, ORM, middleware) and optionally scan code with those patterns.",
52807
+ inputSchema: {
52808
+ framework: string2().describe("Framework id (see list_frameworks)"),
52809
+ code: string2().optional().describe("Optional source code to scan with the framework's patterns")
52810
+ }
52811
+ }, async ({ framework, code }) => {
52812
+ const profile = frameworkProfile(framework);
52813
+ if (!profile) {
52814
+ return { content: [{ type: "text", text: JSON.stringify({ error: `unknown framework: ${framework}` }) }] };
52815
+ }
52816
+ const out = { profile };
52817
+ if (code !== undefined)
52818
+ out.scan = scanFramework(code, framework);
52819
+ return { content: [{ type: "text", text: JSON.stringify(out) }] };
52820
+ });
52638
52821
  server.registerTool("taint_tree", {
52639
52822
  title: "Whole-tree taint scan",
52640
52823
  description: "EAGLE-EYE: run inter-procedural taint analysis across an entire source tree.",
@@ -52788,12 +52971,12 @@ async function serve() {
52788
52971
  }
52789
52972
 
52790
52973
  // src/cli.ts
52791
- import { readFileSync as readFileSync16, existsSync as existsSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4 } from "node:fs";
52792
- import { join as join12, dirname as dirname2 } from "node:path";
52974
+ import { readFileSync as readFileSync18, existsSync as existsSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4 } from "node:fs";
52975
+ import { join as join13, dirname as dirname2 } from "node:path";
52793
52976
  import { homedir as homedir5 } from "node:os";
52794
- import { fileURLToPath as fileURLToPath8 } from "node:url";
52977
+ import { fileURLToPath as fileURLToPath9 } from "node:url";
52795
52978
  import { spawnSync as spawnSync3 } from "node:child_process";
52796
- var ROOT6 = join12(fileURLToPath8(new URL(".", import.meta.url)), "..");
52979
+ var ROOT7 = join13(fileURLToPath9(new URL(".", import.meta.url)), "..");
52797
52980
  function which(cmd) {
52798
52981
  return spawnSync3(`command -v ${cmd}`, { shell: true }).status === 0;
52799
52982
  }
@@ -52828,7 +53011,7 @@ function runDoctor() {
52828
53011
  detail: fofa ? "set" : "FOFA_EMAIL/FOFA_KEY not set",
52829
53012
  fix: fofa ? undefined : "export FOFA_EMAIL=... && export FOFA_KEY=... (enables fofa_search)"
52830
53013
  });
52831
- const dataOk = existsSync6(join12(ROOT6, "chains.json")) && existsSync6(join12(ROOT6, "tools-catalog.json"));
53014
+ const dataOk = existsSync7(join13(ROOT7, "chains.json")) && existsSync7(join13(ROOT7, "tools-catalog.json"));
52832
53015
  issues.push({
52833
53016
  name: "Data layers (chains + tools-catalog)",
52834
53017
  status: dataOk ? "ok" : "fail",
@@ -52856,21 +53039,21 @@ BlitzStrike — ${verdict}`);
52856
53039
  function resolveCommand() {
52857
53040
  if (which("blitzstrike"))
52858
53041
  return { command: "blitzstrike", args: ["serve", "--mcp"] };
52859
- const src = join12(ROOT6, "src", "index.ts");
52860
- if (which("bun") && existsSync6(src))
53042
+ const src = join13(ROOT7, "src", "index.ts");
53043
+ if (which("bun") && existsSync7(src))
52861
53044
  return { command: "bun", args: ["run", src, "serve", "--mcp"] };
52862
53045
  if (which("npx"))
52863
53046
  return { command: "npx", args: ["-y", "blitzstrike", "serve", "--mcp"] };
52864
53047
  if (which("bunx"))
52865
53048
  return { command: "bunx", args: ["blitzstrike", "serve", "--mcp"] };
52866
- const dist = join12(ROOT6, "dist", "index.js");
52867
- if (existsSync6(dist))
53049
+ const dist = join13(ROOT7, "dist", "index.js");
53050
+ if (existsSync7(dist))
52868
53051
  return { command: "bun", args: [dist, "serve", "--mcp"] };
52869
53052
  return { command: "npx", args: ["-y", "blitzstrike", "serve", "--mcp"] };
52870
53053
  }
52871
53054
  function readJson(p) {
52872
53055
  try {
52873
- return JSON.parse(readFileSync16(p, "utf8"));
53056
+ return JSON.parse(readFileSync18(p, "utf8"));
52874
53057
  } catch {
52875
53058
  return null;
52876
53059
  }
@@ -52878,7 +53061,7 @@ function readJson(p) {
52878
53061
  function jsonMcpServersWrite(p) {
52879
53062
  return (command, args) => {
52880
53063
  const dir = dirname2(p);
52881
- if (!existsSync6(dir))
53064
+ if (!existsSync7(dir))
52882
53065
  mkdirSync4(dir, { recursive: true });
52883
53066
  const existing = readJson(p) ?? {};
52884
53067
  existing.mcpServers = {
@@ -52891,7 +53074,7 @@ function jsonMcpServersWrite(p) {
52891
53074
  function opencodeWrite(p) {
52892
53075
  return (_command, _args) => {
52893
53076
  const dir = dirname2(p);
52894
- if (!existsSync6(dir))
53077
+ if (!existsSync7(dir))
52895
53078
  mkdirSync4(dir, { recursive: true });
52896
53079
  const existing = readJson(p) ?? {};
52897
53080
  existing.mcp = {
@@ -52903,26 +53086,26 @@ function opencodeWrite(p) {
52903
53086
  };
52904
53087
  }
52905
53088
  function copyOpenCodeAgents() {
52906
- const srcDir = join12(ROOT6, "opencode-agents");
52907
- const dstDir = join12(homedir5(), ".config", "opencode", "agents");
52908
- if (!existsSync6(srcDir))
53089
+ const srcDir = join13(ROOT7, "opencode-agents");
53090
+ const dstDir = join13(homedir5(), ".config", "opencode", "agents");
53091
+ if (!existsSync7(srcDir))
52909
53092
  return;
52910
- if (!existsSync6(dstDir))
53093
+ if (!existsSync7(dstDir))
52911
53094
  mkdirSync4(dstDir, { recursive: true });
52912
53095
  for (const f of ["Blitz Strike.md", "Blitz.md", "Eagle Eye.md", "Strike.md"]) {
52913
- const src = join12(srcDir, f);
52914
- const dst = join12(dstDir, f);
52915
- if (existsSync6(src)) {
52916
- writeFileSync5(dst, readFileSync16(src, "utf8"));
53096
+ const src = join13(srcDir, f);
53097
+ const dst = join13(dstDir, f);
53098
+ if (existsSync7(src)) {
53099
+ writeFileSync5(dst, readFileSync18(src, "utf8"));
52917
53100
  }
52918
53101
  }
52919
53102
  }
52920
53103
  function codexWrite(p) {
52921
53104
  return (command, args) => {
52922
53105
  const dir = dirname2(p);
52923
- if (!existsSync6(dir))
53106
+ if (!existsSync7(dir))
52924
53107
  mkdirSync4(dir, { recursive: true });
52925
- let existing = existsSync6(p) ? readFileSync16(p, "utf8") : "";
53108
+ let existing = existsSync7(p) ? readFileSync18(p, "utf8") : "";
52926
53109
  if (!existing.trimEnd().endsWith(`
52927
53110
  `))
52928
53111
  existing += `
@@ -52939,9 +53122,9 @@ args = ${JSON.stringify(args)}
52939
53122
  function hermesWrite(p) {
52940
53123
  return (command, args) => {
52941
53124
  const dir = dirname2(p);
52942
- if (!existsSync6(dir))
53125
+ if (!existsSync7(dir))
52943
53126
  mkdirSync4(dir, { recursive: true });
52944
- let existing = existsSync6(p) ? readFileSync16(p, "utf8") : "";
53127
+ let existing = existsSync7(p) ? readFileSync18(p, "utf8") : "";
52945
53128
  existing = existing.replace(/^ blitzstrike:\n(?: .*\n?)*/m, "");
52946
53129
  if (!existing.trimEnd().endsWith(`
52947
53130
  `))
@@ -52968,74 +53151,74 @@ mcp_servers:
52968
53151
  function detectAgents() {
52969
53152
  const home = homedir5();
52970
53153
  const agents = [];
52971
- const claudeJson = join12(home, ".claude.json");
53154
+ const claudeJson = join13(home, ".claude.json");
52972
53155
  agents.push({
52973
53156
  name: "Claude Code",
52974
53157
  detectPath: claudeJson,
52975
- installed: () => existsSync6(claudeJson) || which("claude"),
53158
+ installed: () => existsSync7(claudeJson) || which("claude"),
52976
53159
  write: jsonMcpServersWrite(claudeJson)
52977
53160
  });
52978
- const claudeDesktop = join12(home, ".config", "Claude", "claude_desktop_config.json");
53161
+ const claudeDesktop = join13(home, ".config", "Claude", "claude_desktop_config.json");
52979
53162
  agents.push({
52980
53163
  name: "Claude Desktop",
52981
53164
  detectPath: claudeDesktop,
52982
- installed: () => existsSync6(claudeDesktop),
53165
+ installed: () => existsSync7(claudeDesktop),
52983
53166
  write: jsonMcpServersWrite(claudeDesktop)
52984
53167
  });
52985
- const cursor = join12(home, ".cursor", "mcp.json");
53168
+ const cursor = join13(home, ".cursor", "mcp.json");
52986
53169
  agents.push({
52987
53170
  name: "Cursor",
52988
53171
  detectPath: cursor,
52989
- installed: () => existsSync6(join12(home, ".cursor")) || which("cursor"),
53172
+ installed: () => existsSync7(join13(home, ".cursor")) || which("cursor"),
52990
53173
  write: jsonMcpServersWrite(cursor)
52991
53174
  });
52992
- const opencode = join12(home, ".config", "opencode", "opencode.jsonc");
53175
+ const opencode = join13(home, ".config", "opencode", "opencode.jsonc");
52993
53176
  agents.push({
52994
53177
  name: "OpenCode",
52995
53178
  detectPath: opencode,
52996
- installed: () => existsSync6(join12(home, ".config", "opencode")) || which("opencode"),
53179
+ installed: () => existsSync7(join13(home, ".config", "opencode")) || which("opencode"),
52997
53180
  write: opencodeWrite(opencode)
52998
53181
  });
52999
- const codex = join12(home, ".codex", "config.toml");
53182
+ const codex = join13(home, ".codex", "config.toml");
53000
53183
  agents.push({
53001
53184
  name: "Codex",
53002
53185
  detectPath: codex,
53003
- installed: () => existsSync6(join12(home, ".codex")) || which("codex"),
53186
+ installed: () => existsSync7(join13(home, ".codex")) || which("codex"),
53004
53187
  write: codexWrite(codex)
53005
53188
  });
53006
- const hermes = join12(home, ".hermes", "config.yaml");
53189
+ const hermes = join13(home, ".hermes", "config.yaml");
53007
53190
  agents.push({
53008
53191
  name: "Hermes",
53009
53192
  detectPath: hermes,
53010
- installed: () => existsSync6(join12(home, ".hermes")) || which("hermes"),
53193
+ installed: () => existsSync7(join13(home, ".hermes")) || which("hermes"),
53011
53194
  write: hermesWrite(hermes)
53012
53195
  });
53013
- const gemini = join12(home, ".gemini", "settings.json");
53196
+ const gemini = join13(home, ".gemini", "settings.json");
53014
53197
  agents.push({
53015
53198
  name: "Gemini CLI",
53016
53199
  detectPath: gemini,
53017
- installed: () => existsSync6(join12(home, ".gemini")) || which("gemini"),
53200
+ installed: () => existsSync7(join13(home, ".gemini")) || which("gemini"),
53018
53201
  write: jsonMcpServersWrite(gemini)
53019
53202
  });
53020
- const windsurf = join12(home, ".codeium", "windsurf", "mcp_config.json");
53203
+ const windsurf = join13(home, ".codeium", "windsurf", "mcp_config.json");
53021
53204
  agents.push({
53022
53205
  name: "Windsurf",
53023
53206
  detectPath: windsurf,
53024
- installed: () => existsSync6(join12(home, ".codeium")) || which("windsurf"),
53207
+ installed: () => existsSync7(join13(home, ".codeium")) || which("windsurf"),
53025
53208
  write: jsonMcpServersWrite(windsurf)
53026
53209
  });
53027
- const copilot = join12(home, ".copilot", "mcp.json");
53210
+ const copilot = join13(home, ".copilot", "mcp.json");
53028
53211
  agents.push({
53029
53212
  name: "Copilot",
53030
53213
  detectPath: copilot,
53031
- installed: () => existsSync6(join12(home, ".copilot")),
53214
+ installed: () => existsSync7(join13(home, ".copilot")),
53032
53215
  write: jsonMcpServersWrite(copilot)
53033
53216
  });
53034
- const cline = join12(home, ".cline", "mcp_settings.json");
53217
+ const cline = join13(home, ".cline", "mcp_settings.json");
53035
53218
  agents.push({
53036
53219
  name: "Cline",
53037
53220
  detectPath: cline,
53038
- installed: () => existsSync6(join12(home, ".cline")),
53221
+ installed: () => existsSync7(join13(home, ".cline")),
53039
53222
  write: jsonMcpServersWrite(cline)
53040
53223
  });
53041
53224
  return agents;
@@ -53079,15 +53262,15 @@ Registered with ${ok}/${installed.length} agent(s).`);
53079
53262
  }
53080
53263
 
53081
53264
  // src/index.ts
53082
- import { readFileSync as readFileSync17, existsSync as existsSync7 } from "node:fs";
53083
- import { join as join13 } from "node:path";
53084
- import { fileURLToPath as fileURLToPath9 } from "node:url";
53085
- var ROOT7 = join13(fileURLToPath9(new URL(".", import.meta.url)), "..");
53265
+ import { readFileSync as readFileSync19, existsSync as existsSync8 } from "node:fs";
53266
+ import { join as join14 } from "node:path";
53267
+ import { fileURLToPath as fileURLToPath10 } from "node:url";
53268
+ var ROOT8 = join14(fileURLToPath10(new URL(".", import.meta.url)), "..");
53086
53269
  function readVersion() {
53087
53270
  try {
53088
- const p = join13(ROOT7, "package.json");
53089
- if (existsSync7(p))
53090
- return JSON.parse(readFileSync17(p, "utf8")).version ?? "1.0.0";
53271
+ const p = join14(ROOT8, "package.json");
53272
+ if (existsSync8(p))
53273
+ return JSON.parse(readFileSync19(p, "utf8")).version ?? "1.0.0";
53091
53274
  } catch {}
53092
53275
  return "1.0.0";
53093
53276
  }