diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 6483b1dd7..8617c9601 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,3 +4,4 @@ updates:
directory: "/"
schedule:
interval: "weekly"
+ target-branch: "beta/next"
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 94e83a424..0ec3bf8a7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,33 @@
# Changelog
+## 1.9.0 (2026-08-20)
+
+### Run page
+- Boolean params (e.g. `exploit`, `dump_all`) now render as toggle switches instead of free-text true/false fields.
+
+### Payload workbench
+- New "Payload Workbench" — generate and test payloads (SQLi, XSS, etc.) without leaving the UI.
+
+### HTTP framework
+- `http_spider` now runs on the `commonhuman-core` crawler — threaded discovery, richer form parsing (select/hidden/required-field handling), and correct handling of redirects and off-origin filtering.
+- New `http_authenticate` tool — logs the shared session into a target via form login, OAuth2 client-credentials, or Basic/Digest/NTLM, so subsequent `http_request`/`http_spider`/`http_intruder` calls run authenticated.
+- New `js_api_discover` tool — extracts REST/JSON API endpoints straight out of a SPA's JavaScript bundles (React/Vue/Angular), catching `fetch`/`axios` calls a plain crawl never sees.
+- New `source_map_recover` tool — recovers original pre-minified JS/TS source via `sourceMappingURL`/`.map` files, for real source instead of minified bundles when reviewing DOM-XSS sinks.
+- New `ws_discover`/`ws_inject` tools — find WebSocket endpoints referenced in a page's HTML/JS, then send payloads over them and check responses for reflection (chat, real-time features).
+
+### API scanning
+- `api_schema_analyzer` now parses OpenAPI/Swagger specs (JSON or YAML, v2 or v3, `$ref`-resolving) via `commonhuman-core` instead of a bare JSON fetch — every endpoint comes back with a real, scannable URL (path params filled, base URL resolved) ready to hand to breachsql/phaseaccess.
+- New `openapi_discover` tool — probes a target's common paths (`/openapi.json`, Swagger UI, ReDoc, ...) to locate its spec automatically.
+
+### Recon
+- New `dork_search` tool — queries DuckDuckGo/Bing/Yahoo for URLs matching a dork query (e.g. `site:target.com inurl:search`), returning only parameter-bearing candidates. No API keys required.
+
+### Hardening
+- Smart-scan now re-scores remaining tool candidates between small batches instead of committing to one fixed list up front, so a failure can down-rank a tool before the next round fires.
+- Fixed a shared-driver race in the browser agent — concurrent requests now queue instead of racing on the same Selenium session.
+- Harvested credentials are now encrypted at rest.
+- Plugin loading now logs before executing third-party code, with an opt-in allowlist mode.
+
## 1.8.0 - exploitotter (2026-08-13)
### Workbench
diff --git a/README.md b/README.md
index 990f811a7..530702156 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,8 @@
NyxStrike connects LLM agents to real offensive security tools and executes full attack chains — from recon to exploitation.
+**200+ tools · 50+ categories · AI decision engine · Tamper-evident evidence chain**
+
---
## 🚀 Quick Start (Installation)
@@ -81,12 +83,13 @@ Connect NyxStrike to any MCP-compatible AI client — OpenCode, Cursor, Claude D
NyxStrike does not just run tools — it orchestrates full attack chains using AI decision-making.
-- AI agents that chain tools automatically
-- 185+ offensive security tools, all agent-controllable
+- AI agents that chain tools automatically, guided by a decision engine that ranks and re-scores tools mid-scan
+- 200+ offensive security tools, all agent-controllable
- Full attack workflow: recon → enumeration → exploitation → reporting
-- Modular tool registry — add or remove tools without touching agent logic
+- Local payload & data workbench — 40+ crypto, encoding, and analysis operations, no target required
+- Every tool run hash-chained for tamper-evident, verifiable evidence
+- Real-time dashboard — live output, network topology maps
- MCP-compatible — plug into any AI client you already use
-- Real-time session dashboard with live command output and logs
> [Full feature breakdown](https://github.com/CommonHuman-Lab/nyxstrike/wiki/Features) · [Session & workbench docs](https://github.com/CommonHuman-Lab/nyxstrike/wiki/Dashboard-and-Sessions)
@@ -94,14 +97,15 @@ NyxStrike does not just run tools — it orchestrates full attack chains using A
## 🧰 Tool Arsenal
-185+ offensive security tools across 12 categories — all dynamically orchestrated by AI agents in real time.
+200+ offensive security tools across 50+ categories — all dynamically orchestrated by AI agents in real time.
-- Network reconnaissance
-- Web exploitation
-- Wireless security
+- Network & wireless reconnaissance
+- Web & API exploitation
- OSINT & intelligence gathering
-- Password attacks
-- Cloud & API security
+- Password & credential attacks
+- Binary exploitation & reverse engineering
+- Cloud, container & IaC security
+- Digital forensics & incident response
> [Full tool list by category](https://github.com/CommonHuman-Lab/nyxstrike/wiki/Tool-Arsenal)
diff --git a/backend/server_api/__init__.py b/backend/server_api/__init__.py
index 3c8a31ccd..d2356fd64 100644
--- a/backend/server_api/__init__.py
+++ b/backend/server_api/__init__.py
@@ -1,6 +1,5 @@
from backend.server_api._generic.autoload import register_all_toolspec_blueprints
from .ai_assist import *
-from .ai_payload import *
from .tools_catalog import *
from .ui_blueprint import *
from .settings import *
@@ -10,9 +9,9 @@
from .error_handling import *
from .ops import *
from .vuln_intel import *
-from .web_framework import *
from .burp_agent import *
from .workbench import *
+from .payload_workbench import *
def register_blueprints(app):
"""Register all API blueprints with the Flask app."""
@@ -33,7 +32,6 @@ def register_blueprints(app):
app.register_blueprint(api_topology_bp)
# OPS — General
- app.register_blueprint(api_visual_bp)
app.register_blueprint(api_process_management_bp)
app.register_blueprint(api_process_execute_async_bp)
app.register_blueprint(api_process_get_task_result_bp)
@@ -47,9 +45,6 @@ def register_blueprints(app):
app.register_blueprint(api_process_scale_pool_bp)
app.register_blueprint(api_process_health_check_bp)
- # Web Framework
- app.register_blueprint(api_web_framework_http_framework_bp)
-
# Vulnerability Intelligence
app.register_blueprint(api_vulnerability_intelligence_bp)
app.register_blueprint(api_vuln_intel_cve_exploit_chain_bp)
@@ -96,3 +91,6 @@ def register_blueprints(app):
# Workbench
app.register_blueprint(api_workbench_bp)
+
+ # Payload Workbench
+ app.register_blueprint(api_payload_workbench_bp)
diff --git a/backend/server_api/ai_payload/__init__.py b/backend/server_api/ai_payload/__init__.py
deleted file mode 100644
index 4e9aba4d4..000000000
--- a/backend/server_api/ai_payload/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from .generate_payload import *
diff --git a/backend/server_api/ops/__init__.py b/backend/server_api/ops/__init__.py
index b5ca725b4..badb8ee59 100644
--- a/backend/server_api/ops/__init__.py
+++ b/backend/server_api/ops/__init__.py
@@ -1,5 +1,4 @@
from .process_management import *
-from .visual import *
from .system_monitoring import *
from .vulnerability_intelligence import *
from .logs import *
diff --git a/backend/server_api/ops/system_monitoring.py b/backend/server_api/ops/system_monitoring.py
index bd008d524..da41ea210 100644
--- a/backend/server_api/ops/system_monitoring.py
+++ b/backend/server_api/ops/system_monitoring.py
@@ -9,10 +9,8 @@
import sys
import threading
import time
-import traceback
import backend.server_core.config_core as config_core
-from backend.server_core.command_executor import execute_command
from backend.server_core.modern_visual_engine import ModernVisualEngine
from backend.server_core.tool_constants import (
@@ -219,31 +217,6 @@ def ping():
})
-@api_system_monitoring_bp.route("/api/command", methods=["POST"])
-def generic_command():
- """Execute any command provided in the request with enhanced logging"""
- try:
- params = request.json
- command = params.get("command", "")
- use_cache = params.get("use_cache", True)
- timeout = params.get("timeout")
-
- if not command:
- logger.warning("Command endpoint called without command parameter")
- return jsonify({
- "error": "Command parameter is required"
- }), 400
-
- result = execute_command(command, use_cache=use_cache, timeout=timeout)
- return jsonify(result)
- except Exception as e:
- logger.error(f"Error in command endpoint: {str(e)}")
- logger.error(traceback.format_exc())
- return jsonify({
- "error": f"Server error: {str(e)}"
- }), 500
-
-
@api_system_monitoring_bp.route("/api/tools/categories", methods=["GET"])
def get_tool_categories():
"""Get the list of tool categories and their tools"""
diff --git a/backend/server_api/ops/visual.py b/backend/server_api/ops/visual.py
deleted file mode 100644
index ca0335303..000000000
--- a/backend/server_api/ops/visual.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from flask import Blueprint, jsonify, request
-from datetime import datetime
-from backend.server_core.intelligence.cve_intelligence_manager import CVEIntelligenceManager
-
-import logging
-logger = logging.getLogger(__name__)
-
-
-api_visual_bp = Blueprint("visual", __name__)
-
-@api_visual_bp.route("/api/visual/vulnerability-card", methods=["POST"])
-def create_vulnerability_card():
- """Create a beautiful vulnerability card using CVEIntelligenceManager"""
- try:
- data = request.get_json()
- if not data:
- return jsonify({"error": "No data provided"}), 400
-
- # Create vulnerability card
- cve_intelligence = CVEIntelligenceManager()
- card = cve_intelligence.render_vulnerability_card(data)
-
- return jsonify({
- "success": True,
- "vulnerability_card": card,
- "timestamp": datetime.now().isoformat()
- })
-
- except Exception as e:
- logger.error(f"💥 Error creating vulnerability card: {str(e)}")
- return jsonify({"error": f"Server error: {str(e)}"}), 500
-
diff --git a/backend/server_api/ops/vulnerability_intelligence.py b/backend/server_api/ops/vulnerability_intelligence.py
index 63fc005b7..9dde87de7 100644
--- a/backend/server_api/ops/vulnerability_intelligence.py
+++ b/backend/server_api/ops/vulnerability_intelligence.py
@@ -3,8 +3,10 @@
from datetime import datetime
import json
import logging
+import math
import time
import uuid
+from typing import Optional
from werkzeug.local import LocalProxy
from backend.server_core.singletons import decision_engine, wordlist_store, enhanced_process_manager
@@ -159,16 +161,29 @@ def execute_tool_via_registered_endpoint(app, tool_name, params):
return body
-def _run_smart_scan(target: str, objective: str, planner_mode, session_id, max_tools: int) -> dict:
- """Select and run optimal tools for a target in parallel, aggregating results.
+def _run_smart_scan(
+ target: str,
+ objective: str,
+ planner_mode,
+ session_id,
+ max_tools: int,
+ batch_size: int = 3,
+ max_rounds: Optional[int] = None,
+) -> dict:
+ """Select and run optimal tools for a target in small concurrent batches,
+ re-scoring the remaining candidates against updated session/tool-stats
+ data between batches instead of committing to one fixed list up front.
Used by the decision_engine smart_scan/ai_reconnaissance_workflow/
ai_vulnerability_assessment tool handlers.
"""
profile = decision_engine.analyze_target(target)
- selected_tools = decision_engine.select_optimal_tools(
- profile, objective, planner_mode=planner_mode, session_id=session_id
- )[:max_tools]
+
+ owns_session = not session_id
+ if owns_session:
+ session_id = create_session(
+ target=target, steps=[], source="smart_scan_iterative", objective=objective,
+ )["session_id"]
scan_results = {
"target": target,
@@ -188,18 +203,16 @@ def _run_smart_scan(target: str, objective: str, planner_mode, session_id, max_t
"combined_output": "",
}
- if not selected_tools:
- return scan_results
-
combined_output_parts = []
app = current_app._get_current_object() if isinstance(current_app, LocalProxy) else current_app
- def execute_single_tool(tool_name, target, profile):
+ def execute_single_tool(tool_name, target, profile, session_id):
try:
logger.info(f"Executing {tool_name} with optimized parameters")
optimized_params = decision_engine.optimize_parameters(tool_name, profile)
optimized_params.setdefault("target", target)
+ optimized_params["session_id"] = session_id
result = execute_tool_via_registered_endpoint(app, tool_name, optimized_params)
vuln_count = 0
@@ -230,38 +243,60 @@ def execute_single_tool(tool_name, target, profile):
"success": False,
}
- with ThreadPoolExecutor(max_workers=min(len(selected_tools), 5)) as executor:
- future_to_tool = {
- executor.submit(execute_single_tool, tool, target, profile): tool
- for tool in selected_tools
- }
+ executed_tools = set()
+ remaining = max_tools
+ rounds_cap = max_rounds or math.ceil(max_tools / batch_size)
+ round_num = 0
+
+ while remaining > 0 and round_num < rounds_cap:
+ round_num += 1
+ ranked = decision_engine.select_optimal_tools(
+ profile, objective, planner_mode=planner_mode, session_id=session_id
+ )
+ candidates = [t for t in ranked if t not in executed_tools]
+ if not candidates:
+ break
+ batch = candidates[: min(batch_size, remaining)]
+
+ with ThreadPoolExecutor(max_workers=len(batch)) as executor:
+ future_to_tool = {
+ executor.submit(execute_single_tool, tool, target, profile, session_id): tool
+ for tool in batch
+ }
- for future in as_completed(future_to_tool):
- tool_result = future.result()
- scan_results["tools_executed"].append(tool_result)
+ for future in as_completed(future_to_tool):
+ tool_result = future.result()
+ scan_results["tools_executed"].append(tool_result)
+ executed_tools.add(tool_result["tool"])
- if tool_result.get("vulnerabilities_found"):
- scan_results["total_vulnerabilities"] += tool_result["vulnerabilities_found"]
+ if tool_result.get("vulnerabilities_found"):
+ scan_results["total_vulnerabilities"] += tool_result["vulnerabilities_found"]
- if tool_result.get("stdout"):
- combined_output_parts.append(f"\n=== {tool_result['tool'].upper()} OUTPUT ===\n")
- combined_output_parts.append(tool_result["stdout"])
- combined_output_parts.append("\n" + "=" * 50 + "\n")
+ if tool_result.get("stdout"):
+ combined_output_parts.append(f"\n=== {tool_result['tool'].upper()} OUTPUT ===\n")
+ combined_output_parts.append(tool_result["stdout"])
+ combined_output_parts.append("\n" + "=" * 50 + "\n")
+
+ remaining -= len(batch)
scan_results["combined_output"] = "".join(combined_output_parts)
- successful_tools = [t for t in scan_results["tools_executed"] if t.get("success")]
- failed_tools = [t for t in scan_results["tools_executed"] if not t.get("success")]
+ executed = scan_results["tools_executed"]
+ successful_tools = [t for t in executed if t.get("success")]
+ failed_tools = [t for t in executed if not t.get("success")]
scan_results["execution_summary"] = {
- "total_tools": len(selected_tools),
+ "total_tools": len(executed),
"successful_tools": len(successful_tools),
"failed_tools": len(failed_tools),
- "success_rate": len(successful_tools) / len(selected_tools) * 100 if selected_tools else 0,
- "total_execution_time": sum(t.get("execution_time", 0) for t in scan_results["tools_executed"]),
+ "success_rate": len(successful_tools) / len(executed) * 100 if executed else 0,
+ "total_execution_time": sum(t.get("execution_time", 0) for t in executed),
"tools_used": [t["tool"] for t in successful_tools],
}
+ if owns_session:
+ scan_results["session_id"] = session_id
+
return scan_results
diff --git a/backend/server_api/payload_workbench/__init__.py b/backend/server_api/payload_workbench/__init__.py
new file mode 100644
index 000000000..eb4251bbb
--- /dev/null
+++ b/backend/server_api/payload_workbench/__init__.py
@@ -0,0 +1 @@
+from .routes import *
diff --git a/backend/server_api/payload_workbench/routes.py b/backend/server_api/payload_workbench/routes.py
new file mode 100644
index 000000000..521b89e37
--- /dev/null
+++ b/backend/server_api/payload_workbench/routes.py
@@ -0,0 +1,148 @@
+from flask import Blueprint, jsonify, request
+
+from backend.server_core.singletons import db
+from backend.server_core.payload_workbench.registry import CATEGORIES, get_operation, list_operations
+
+api_payload_workbench_bp = Blueprint("api_payload_workbench", __name__)
+
+
+@api_payload_workbench_bp.route("/api/payload-workbench/operations", methods=["GET"])
+def payload_workbench_operations():
+ return jsonify(
+ {
+ "success": True,
+ "categories": CATEGORIES,
+ "operations": [op.to_dict() for op in list_operations()],
+ }
+ )
+
+
+@api_payload_workbench_bp.route("/api/payload-workbench/run/",
- "
`+_(r.message+``,!0)+``;if(t)return Promise.resolve(i);if(n){n(null,i);return}return i}if(t)return Promise.reject(r);if(n){n(r);return}throw r}}function ce(e,t){return function(n,i,a){typeof i==`function`&&(a=i,i=null);var o=r({},i);i=r({},H.defaults,o);var s=se(i.silent,i.async,a);if(n==null)return s(Error(`marked(): input parameter is undefined or null`));if(typeof n!=`string`)return s(Error(`marked(): input parameter is of type `+Object.prototype.toString.call(n)+`, string expected`));if(N(i),i.hooks&&(i.hooks.options=i),a){var c=i.highlight,l;try{i.hooks&&(n=i.hooks.preprocess(n)),l=e(n,i)}catch(e){return s(e)}var u=function(e){var n;if(!e)try{i.walkTokens&&H.walkTokens(l,i.walkTokens),n=t(l,i),i.hooks&&(n=i.hooks.postprocess(n))}catch(t){e=t}return i.highlight=c,e?s(e):a(null,n)};if(!c||c.length<3||(delete i.highlight,!l.length))return u();var d=0;H.walkTokens(l,function(e){e.type===`code`&&(d++,setTimeout(function(){c(e.text,e.lang,function(t,n){if(t)return u(t);n!=null&&n!==e.text&&(e.text=n,e.escaped=!0),d--,d===0&&u()})},0))}),d===0&&u();return}if(i.async)return Promise.resolve(i.hooks?i.hooks.preprocess(n):n).then(function(t){return e(t,i)}).then(function(e){return i.walkTokens?Promise.all(H.walkTokens(e,i.walkTokens)).then(function(){return e}):e}).then(function(e){return t(e,i)}).then(function(e){return i.hooks?i.hooks.postprocess(e):e}).catch(s);try{i.hooks&&(n=i.hooks.preprocess(n));var f=e(n,i);i.walkTokens&&H.walkTokens(f,i.walkTokens);var p=t(f,i);return i.hooks&&(p=i.hooks.postprocess(p)),p}catch(e){return s(e)}}}function H(e,t,n){return ce(B.lex,ae.parse)(e,t,n)}H.options=H.setOptions=function(e){return H.defaults=r({},H.defaults,e),u(H.defaults),H},H.getDefaults=l,H.defaults=e.defaults,H.use=function(){var e=H.defaults.extensions||{renderers:{},childTokens:{}};[...arguments].forEach(function(t){var n=r({},t);if(n.async=H.defaults.async||n.async||!1,t.extensions&&(t.extensions.forEach(function(t){if(!t.name)throw Error(`extension name required`);if(t.renderer){var n=e.renderers[t.name];n?e.renderers[t.name]=function(){var e=[...arguments],r=t.renderer.apply(this,e);return r===!1&&(r=n.apply(this,e)),r}:e.renderers[t.name]=t.renderer}if(t.tokenizer){if(!t.level||t.level!==`block`&&t.level!==`inline`)throw Error(`extension level must be 'block' or 'inline'`);e[t.level]?e[t.level].unshift(t.tokenizer):e[t.level]=[t.tokenizer],t.start&&(t.level===`block`?e.startBlock?e.startBlock.push(t.start):e.startBlock=[t.start]:t.level===`inline`&&(e.startInline?e.startInline.push(t.start):e.startInline=[t.start]))}t.childTokens&&(e.childTokens[t.name]=t.childTokens)}),n.extensions=e),t.renderer&&(function(){var e=H.defaults.renderer||new re,r=function(n){var r=e[n];e[n]=function(){var i=[...arguments],a=t.renderer[n].apply(e,i);return a===!1&&(a=r.apply(e,i)),a}};for(var i in t.renderer)r(i);n.renderer=e})(),t.tokenizer&&(function(){var e=H.defaults.tokenizer||new ne,r=function(n){var r=e[n];e[n]=function(){var i=[...arguments],a=t.tokenizer[n].apply(e,i);return a===!1&&(a=r.apply(e,i)),a}};for(var i in t.tokenizer)r(i);n.tokenizer=e})(),t.hooks&&(function(){var e=H.defaults.hooks||new oe,r=function(n){var r=e[n];e[n]=oe.passThroughHooks.has(n)?function(i){if(H.defaults.async)return Promise.resolve(t.hooks[n].call(e,i)).then(function(t){return r.call(e,t)});var a=t.hooks[n].call(e,i);return r.call(e,a)}:function(){var i=[...arguments],a=t.hooks[n].apply(e,i);return a===!1&&(a=r.apply(e,i)),a}};for(var i in t.hooks)r(i);n.hooks=e})(),t.walkTokens){var i=H.defaults.walkTokens;n.walkTokens=function(e){var n=[];return n.push(t.walkTokens.call(this,e)),i&&(n=n.concat(i.call(this,e))),n}}H.setOptions(n)})},H.walkTokens=function(e,t){for(var n=[],r=function(){var e=a.value;switch(n=n.concat(t.call(H,e)),e.type){case`table`:for(var r=o(e.header),i;!(i=r()).done;){var s=i.value;n=n.concat(H.walkTokens(s.tokens,t))}for(var c=o(e.rows),l;!(l=c()).done;)for(var u=l.value,d=o(u),f;!(f=d()).done;){var p=f.value;n=n.concat(H.walkTokens(p.tokens,t))}break;case`list`:n=n.concat(H.walkTokens(e.items,t));break;default:H.defaults.extensions&&H.defaults.extensions.childTokens&&H.defaults.extensions.childTokens[e.type]?H.defaults.extensions.childTokens[e.type].forEach(function(r){n=n.concat(H.walkTokens(e[r],t))}):e.tokens&&(n=n.concat(H.walkTokens(e.tokens,t)))}},i=o(e),a;!(a=i()).done;)r();return n},H.parseInline=ce(B.lexInline,ae.parseInline),H.Parser=ae,H.parser=ae.parse,H.Renderer=re,H.TextRenderer=V,H.Lexer=B,H.lexer=B.lex,H.Tokenizer=ne,H.Slugger=ie,H.Hooks=oe,H.parse=H;var le=H.options,ue=H.setOptions,U=H.use,de=H.walkTokens,fe=H.parseInline,pe=H,me=ae.parse,he=B.lex;e.Hooks=oe,e.Lexer=B,e.Parser=ae,e.Renderer=re,e.Slugger=ie,e.TextRenderer=V,e.Tokenizer=ne,e.getDefaults=l,e.lexer=he,e.marked=H,e.options=le,e.parse=pe,e.parseInline=fe,e.parser=me,e.setOptions=ue,e.use=U,e.walkTokens=de})),ee=n(((e,t)=>{var n=g();_(),v(),y(),S(),C(),w(),T(),E(),D(),O(),b();var r=j(),i=M().marked,a=/Mac/.test(navigator.platform),o=new RegExp(/(
`+(n?e:_(e,!0))+`
-`:``+(n?e:_(e,!0))+`
-`},n.blockquote=function(e){return`-`+e+`-`},n.html=function(e){return e},n.heading=function(e,t,n,r){if(this.options.headerIds){var i=this.options.headerPrefix+r.slug(n);return`
`+e+`
-`},n.table=function(e,t){return t&&=``+t+``,``+e+``},n.br=function(){return this.options.xhtml?``+_(r.message+``,!0)+``;if(t)return Promise.resolve(i);if(n){n(null,i);return}return i}if(t)return Promise.reject(r);if(n){n(r);return}throw r}}function ce(e,t){return function(n,i,a){typeof i==`function`&&(a=i,i=null);var o=r({},i);i=r({},H.defaults,o);var s=se(i.silent,i.async,a);if(n==null)return s(Error(`marked(): input parameter is undefined or null`));if(typeof n!=`string`)return s(Error(`marked(): input parameter is of type `+Object.prototype.toString.call(n)+`, string expected`));if(N(i),i.hooks&&(i.hooks.options=i),a){var c=i.highlight,l;try{i.hooks&&(n=i.hooks.preprocess(n)),l=e(n,i)}catch(e){return s(e)}var u=function(e){var n;if(!e)try{i.walkTokens&&H.walkTokens(l,i.walkTokens),n=t(l,i),i.hooks&&(n=i.hooks.postprocess(n))}catch(t){e=t}return i.highlight=c,e?s(e):a(null,n)};if(!c||c.length<3||(delete i.highlight,!l.length))return u();var d=0;H.walkTokens(l,function(e){e.type===`code`&&(d++,setTimeout(function(){c(e.text,e.lang,function(t,n){if(t)return u(t);n!=null&&n!==e.text&&(e.text=n,e.escaped=!0),d--,d===0&&u()})},0))}),d===0&&u();return}if(i.async)return Promise.resolve(i.hooks?i.hooks.preprocess(n):n).then(function(t){return e(t,i)}).then(function(e){return i.walkTokens?Promise.all(H.walkTokens(e,i.walkTokens)).then(function(){return e}):e}).then(function(e){return t(e,i)}).then(function(e){return i.hooks?i.hooks.postprocess(e):e}).catch(s);try{i.hooks&&(n=i.hooks.preprocess(n));var f=e(n,i);i.walkTokens&&H.walkTokens(f,i.walkTokens);var p=t(f,i);return i.hooks&&(p=i.hooks.postprocess(p)),p}catch(e){return s(e)}}}function H(e,t,n){return ce(B.lex,ae.parse)(e,t,n)}H.options=H.setOptions=function(e){return H.defaults=r({},H.defaults,e),u(H.defaults),H},H.getDefaults=l,H.defaults=e.defaults,H.use=function(){var e=H.defaults.extensions||{renderers:{},childTokens:{}};[...arguments].forEach(function(t){var n=r({},t);if(n.async=H.defaults.async||n.async||!1,t.extensions&&(t.extensions.forEach(function(t){if(!t.name)throw Error(`extension name required`);if(t.renderer){var n=e.renderers[t.name];n?e.renderers[t.name]=function(){var e=[...arguments],r=t.renderer.apply(this,e);return r===!1&&(r=n.apply(this,e)),r}:e.renderers[t.name]=t.renderer}if(t.tokenizer){if(!t.level||t.level!==`block`&&t.level!==`inline`)throw Error(`extension level must be 'block' or 'inline'`);e[t.level]?e[t.level].unshift(t.tokenizer):e[t.level]=[t.tokenizer],t.start&&(t.level===`block`?e.startBlock?e.startBlock.push(t.start):e.startBlock=[t.start]:t.level===`inline`&&(e.startInline?e.startInline.push(t.start):e.startInline=[t.start]))}t.childTokens&&(e.childTokens[t.name]=t.childTokens)}),n.extensions=e),t.renderer&&(function(){var e=H.defaults.renderer||new re,r=function(n){var r=e[n];e[n]=function(){var i=[...arguments],a=t.renderer[n].apply(e,i);return a===!1&&(a=r.apply(e,i)),a}};for(var i in t.renderer)r(i);n.renderer=e})(),t.tokenizer&&(function(){var e=H.defaults.tokenizer||new ne,r=function(n){var r=e[n];e[n]=function(){var i=[...arguments],a=t.tokenizer[n].apply(e,i);return a===!1&&(a=r.apply(e,i)),a}};for(var i in t.tokenizer)r(i);n.tokenizer=e})(),t.hooks&&(function(){var e=H.defaults.hooks||new oe,r=function(n){var r=e[n];oe.passThroughHooks.has(n)?e[n]=function(i){if(H.defaults.async)return Promise.resolve(t.hooks[n].call(e,i)).then(function(t){return r.call(e,t)});var a=t.hooks[n].call(e,i);return r.call(e,a)}:e[n]=function(){var i=[...arguments],a=t.hooks[n].apply(e,i);return a===!1&&(a=r.apply(e,i)),a}};for(var i in t.hooks)r(i);n.hooks=e})(),t.walkTokens){var i=H.defaults.walkTokens;n.walkTokens=function(e){var n=[];return n.push(t.walkTokens.call(this,e)),i&&(n=n.concat(i.call(this,e))),n}}H.setOptions(n)})},H.walkTokens=function(e,t){for(var n=[],r=function(){var e=a.value;switch(n=n.concat(t.call(H,e)),e.type){case`table`:for(var r=o(e.header),i;!(i=r()).done;){var s=i.value;n=n.concat(H.walkTokens(s.tokens,t))}for(var c=o(e.rows),l;!(l=c()).done;)for(var u=l.value,d=o(u),f;!(f=d()).done;){var p=f.value;n=n.concat(H.walkTokens(p.tokens,t))}break;case`list`:n=n.concat(H.walkTokens(e.items,t));break;default:H.defaults.extensions&&H.defaults.extensions.childTokens&&H.defaults.extensions.childTokens[e.type]?H.defaults.extensions.childTokens[e.type].forEach(function(r){n=n.concat(H.walkTokens(e[r],t))}):e.tokens&&(n=n.concat(H.walkTokens(e.tokens,t)))}},i=o(e),a;!(a=i()).done;)r();return n},H.parseInline=ce(B.lexInline,ae.parseInline),H.Parser=ae,H.parser=ae.parse,H.Renderer=re,H.TextRenderer=V,H.Lexer=B,H.lexer=B.lex,H.Tokenizer=ne,H.Slugger=ie,H.Hooks=oe,H.parse=H;var le=H.options,ue=H.setOptions,U=H.use,de=H.walkTokens,fe=H.parseInline,pe=H,me=ae.parse,he=B.lex;e.Hooks=oe,e.Lexer=B,e.Parser=ae,e.Renderer=re,e.Slugger=ie,e.TextRenderer=V,e.Tokenizer=ne,e.getDefaults=l,e.lexer=he,e.marked=H,e.options=le,e.parse=pe,e.parseInline=fe,e.parser=me,e.setOptions=ue,e.use=U,e.walkTokens=de})),ee=n(((e,t)=>{var n=g();_(),v(),y(),S(),C(),w(),T(),E(),D(),O(),b();var r=j(),i=M().marked,a=/Mac/.test(navigator.platform),o=new RegExp(/(
t.length,o;r&&t.push(i);try{o=e.apply(this,t)}catch(e){let t=e;if(r&&n)throw t;return i(t)}r||(o&&o.then&&typeof o.then==`function`?o.then(a,i):o instanceof Error?i(o):a(o))}function i(e,...r){n||(n=!0,t(e,...r))}function a(e){i(null,e)}}var X={basename:da,dirname:fa,extname:pa,join:ma,sep:`/`};function da(e,t){if(t!==void 0&&typeof t!=`string`)throw TypeError(`"ext" argument must be a string`);_a(e);let n=0,r=-1,i=e.length,a;if(t===void 0||t.length===0||t.length>e.length){for(;i--;)if(e.codePointAt(i)===47){if(a){n=i+1;break}}else r<0&&(a=!0,r=i+1);return r<0?``:e.slice(n,r)}if(t===e)return``;let o=-1,s=t.length-1;for(;i--;)if(e.codePointAt(i)===47){if(a){n=i+1;break}}else o<0&&(a=!0,o=i+1),s>-1&&(e.codePointAt(i)===t.codePointAt(s--)?s<0&&(r=i):(s=-1,r=o));return n===r?r=o:r<0&&(r=e.length),e.slice(n,r)}function fa(e){if(_a(e),e.length===0)return`.`;let t=-1,n=e.length,r;for(;--n;)if(e.codePointAt(n)===47){if(r){t=n;break}}else r||=!0;return t<0?e.codePointAt(0)===47?`/`:`.`:t===1&&e.codePointAt(0)===47?`//`:e.slice(0,t)}function pa(e){_a(e);let t=e.length,n=-1,r=0,i=-1,a=0,o;for(;t--;){let s=e.codePointAt(t);if(s===47){if(o){r=t+1;break}continue}n<0&&(o=!0,n=t+1),s===46?i<0?i=t:a!==1&&(a=1):i>-1&&(a=-1)}return i<0||n<0||a===0||a===1&&i===n-1&&i===r+1?``:e.slice(i,n)}function ma(...e){let t=-1,n;for(;++t