@harbinger-ai/harbinger 0.1.0
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/LICENSE +21 -0
- package/README.md +406 -0
- package/agents/README.md +76 -0
- package/agents/_template/CONFIG.yaml +7 -0
- package/agents/_template/HEARTBEAT.md +59 -0
- package/agents/_template/IDENTITY.md +4 -0
- package/agents/_template/SKILLS.md +1 -0
- package/agents/_template/SOUL.md +25 -0
- package/agents/_template/TOOLS.md +3 -0
- package/agents/binary-reverser/CONFIG.yaml +21 -0
- package/agents/binary-reverser/HEARTBEAT.md +65 -0
- package/agents/binary-reverser/IDENTITY.md +1 -0
- package/agents/binary-reverser/SKILLS.md +1 -0
- package/agents/binary-reverser/SOUL.md +23 -0
- package/agents/binary-reverser/TOOLS.md +99 -0
- package/agents/browser-agent/CONFIG.yaml +20 -0
- package/agents/browser-agent/HEARTBEAT.md +79 -0
- package/agents/browser-agent/IDENTITY.md +5 -0
- package/agents/browser-agent/SKILLS.md +86 -0
- package/agents/browser-agent/SOUL.md +23 -0
- package/agents/browser-agent/TOOLS.md +186 -0
- package/agents/cloud-infiltrator/CONFIG.yaml +22 -0
- package/agents/cloud-infiltrator/HEARTBEAT.md +78 -0
- package/agents/cloud-infiltrator/IDENTITY.md +1 -0
- package/agents/cloud-infiltrator/SKILLS.md +1 -0
- package/agents/cloud-infiltrator/SOUL.md +23 -0
- package/agents/cloud-infiltrator/TOOLS.md +68 -0
- package/agents/coding-assistant/CONFIG.yaml +22 -0
- package/agents/coding-assistant/HEARTBEAT.md +57 -0
- package/agents/coding-assistant/IDENTITY.md +5 -0
- package/agents/coding-assistant/SKILLS.md +69 -0
- package/agents/coding-assistant/SOUL.md +60 -0
- package/agents/coding-assistant/TOOLS.md +168 -0
- package/agents/learning-agent/CONFIG.yaml +21 -0
- package/agents/learning-agent/HEARTBEAT.md +63 -0
- package/agents/learning-agent/IDENTITY.md +5 -0
- package/agents/learning-agent/SKILLS.md +86 -0
- package/agents/learning-agent/SOUL.md +77 -0
- package/agents/learning-agent/TOOLS.md +145 -0
- package/agents/maintainer/CONFIG.yaml +31 -0
- package/agents/maintainer/HEARTBEAT.md +28 -0
- package/agents/maintainer/IDENTITY.md +33 -0
- package/agents/maintainer/SKILLS.md +24 -0
- package/agents/maintainer/SOUL.md +61 -0
- package/agents/maintainer/TOOLS.md +29 -0
- package/agents/maintainer/lib/engine.js +279 -0
- package/agents/maintainer/lib/safe-fixer.js +183 -0
- package/agents/morning-brief/CONFIG.yaml +22 -0
- package/agents/morning-brief/HEARTBEAT.md +60 -0
- package/agents/morning-brief/IDENTITY.md +5 -0
- package/agents/morning-brief/SKILLS.md +56 -0
- package/agents/morning-brief/SOUL.md +64 -0
- package/agents/morning-brief/TOOLS.md +112 -0
- package/agents/osint-detective/CONFIG.yaml +24 -0
- package/agents/osint-detective/HEARTBEAT.md +66 -0
- package/agents/osint-detective/IDENTITY.md +1 -0
- package/agents/osint-detective/SKILLS.md +1 -0
- package/agents/osint-detective/SOUL.md +23 -0
- package/agents/osint-detective/TOOLS.md +81 -0
- package/agents/recon-scout/CONFIG.yaml +22 -0
- package/agents/recon-scout/HEARTBEAT.md +79 -0
- package/agents/recon-scout/IDENTITY.md +1 -0
- package/agents/recon-scout/SKILLS.md +1 -0
- package/agents/recon-scout/SOUL.md +23 -0
- package/agents/recon-scout/TOOLS.md +93 -0
- package/agents/report-writer/CONFIG.yaml +21 -0
- package/agents/report-writer/HEARTBEAT.md +63 -0
- package/agents/report-writer/IDENTITY.md +1 -0
- package/agents/report-writer/SKILLS.md +1 -0
- package/agents/report-writer/SOUL.md +23 -0
- package/agents/report-writer/TOOLS.md +69 -0
- package/agents/shared/README.md +13 -0
- package/agents/web-hacker/CONFIG.yaml +24 -0
- package/agents/web-hacker/HEARTBEAT.md +78 -0
- package/agents/web-hacker/IDENTITY.md +1 -0
- package/agents/web-hacker/SKILLS.md +1 -0
- package/agents/web-hacker/SOUL.md +23 -0
- package/agents/web-hacker/TOOLS.md +86 -0
- package/api/CLAUDE.md +19 -0
- package/api/index.js +274 -0
- package/bin/cli.js +620 -0
- package/bin/local.sh +31 -0
- package/bin/postinstall.js +63 -0
- package/config/index.js +24 -0
- package/config/instrumentation.js +93 -0
- package/drizzle/0000_initial.sql +52 -0
- package/drizzle/0001_bounty_and_registry.sql +82 -0
- package/drizzle/0002_sync_columns.sql +7 -0
- package/drizzle/0003_graceful_bloodscream.sql +86 -0
- package/drizzle/meta/0000_snapshot.json +321 -0
- package/drizzle/meta/0003_snapshot.json +878 -0
- package/drizzle/meta/_journal.json +34 -0
- package/drizzle/relations.ts +3 -0
- package/drizzle/schema.ts +145 -0
- package/lib/actions.js +47 -0
- package/lib/agents.js +166 -0
- package/lib/ai/agent.js +96 -0
- package/lib/ai/autonomous-engine.js +261 -0
- package/lib/ai/index.js +359 -0
- package/lib/ai/model-router.js +254 -0
- package/lib/ai/model.js +73 -0
- package/lib/ai/tools.js +84 -0
- package/lib/auth/actions.js +28 -0
- package/lib/auth/config.js +27 -0
- package/lib/auth/edge-config.js +27 -0
- package/lib/auth/index.js +27 -0
- package/lib/auth/middleware.js +53 -0
- package/lib/bounty/actions.js +119 -0
- package/lib/bounty/findings.js +64 -0
- package/lib/bounty/programs.js +34 -0
- package/lib/bounty/sync-targets.js +267 -0
- package/lib/bounty/targets.js +33 -0
- package/lib/channels/base.js +56 -0
- package/lib/channels/index.js +15 -0
- package/lib/channels/telegram.js +148 -0
- package/lib/chat/actions.js +288 -0
- package/lib/chat/api.js +135 -0
- package/lib/chat/components/app-sidebar.js +237 -0
- package/lib/chat/components/app-sidebar.jsx +289 -0
- package/lib/chat/components/chat-header.js +27 -0
- package/lib/chat/components/chat-header.jsx +37 -0
- package/lib/chat/components/chat-input.js +230 -0
- package/lib/chat/components/chat-input.jsx +228 -0
- package/lib/chat/components/chat-nav-context.js +11 -0
- package/lib/chat/components/chat-nav-context.jsx +11 -0
- package/lib/chat/components/chat-page.js +81 -0
- package/lib/chat/components/chat-page.jsx +100 -0
- package/lib/chat/components/chat.js +150 -0
- package/lib/chat/components/chat.jsx +182 -0
- package/lib/chat/components/chats-page.js +302 -0
- package/lib/chat/components/chats-page.jsx +330 -0
- package/lib/chat/components/crons-page.js +172 -0
- package/lib/chat/components/crons-page.jsx +244 -0
- package/lib/chat/components/enhanced-tool-call.js +103 -0
- package/lib/chat/components/enhanced-tool-call.jsx +139 -0
- package/lib/chat/components/findings-page.js +175 -0
- package/lib/chat/components/findings-page.jsx +214 -0
- package/lib/chat/components/greeting.js +22 -0
- package/lib/chat/components/greeting.jsx +26 -0
- package/lib/chat/components/icons.js +777 -0
- package/lib/chat/components/icons.jsx +741 -0
- package/lib/chat/components/index.js +26 -0
- package/lib/chat/components/mcp-page.js +260 -0
- package/lib/chat/components/mcp-page.jsx +355 -0
- package/lib/chat/components/message.js +289 -0
- package/lib/chat/components/message.jsx +315 -0
- package/lib/chat/components/messages.js +66 -0
- package/lib/chat/components/messages.jsx +77 -0
- package/lib/chat/components/notifications-page.js +56 -0
- package/lib/chat/components/notifications-page.jsx +87 -0
- package/lib/chat/components/page-layout.js +21 -0
- package/lib/chat/components/page-layout.jsx +28 -0
- package/lib/chat/components/registry-page.js +222 -0
- package/lib/chat/components/registry-page.jsx +255 -0
- package/lib/chat/components/settings-layout.js +40 -0
- package/lib/chat/components/settings-layout.jsx +54 -0
- package/lib/chat/components/settings-secrets-page.js +216 -0
- package/lib/chat/components/settings-secrets-page.jsx +264 -0
- package/lib/chat/components/sidebar-history-item.js +132 -0
- package/lib/chat/components/sidebar-history-item.jsx +113 -0
- package/lib/chat/components/sidebar-history.js +115 -0
- package/lib/chat/components/sidebar-history.jsx +157 -0
- package/lib/chat/components/sidebar-user-nav.js +63 -0
- package/lib/chat/components/sidebar-user-nav.jsx +73 -0
- package/lib/chat/components/status-bar.js +39 -0
- package/lib/chat/components/status-bar.jsx +51 -0
- package/lib/chat/components/swarm-page.js +157 -0
- package/lib/chat/components/swarm-page.jsx +210 -0
- package/lib/chat/components/targets-page.js +376 -0
- package/lib/chat/components/targets-page.jsx +389 -0
- package/lib/chat/components/tool-call.js +86 -0
- package/lib/chat/components/tool-call.jsx +104 -0
- package/lib/chat/components/tool-panel.js +107 -0
- package/lib/chat/components/tool-panel.jsx +145 -0
- package/lib/chat/components/triggers-page.js +153 -0
- package/lib/chat/components/triggers-page.jsx +221 -0
- package/lib/chat/components/ui/confirm-dialog.js +53 -0
- package/lib/chat/components/ui/confirm-dialog.jsx +57 -0
- package/lib/chat/components/ui/dropdown-menu.js +98 -0
- package/lib/chat/components/ui/dropdown-menu.jsx +116 -0
- package/lib/chat/components/ui/rename-dialog.js +74 -0
- package/lib/chat/components/ui/rename-dialog.jsx +72 -0
- package/lib/chat/components/ui/scroll-area.js +13 -0
- package/lib/chat/components/ui/scroll-area.jsx +17 -0
- package/lib/chat/components/ui/separator.js +21 -0
- package/lib/chat/components/ui/separator.jsx +18 -0
- package/lib/chat/components/ui/sheet.js +75 -0
- package/lib/chat/components/ui/sheet.jsx +95 -0
- package/lib/chat/components/ui/sidebar.js +227 -0
- package/lib/chat/components/ui/sidebar.jsx +245 -0
- package/lib/chat/components/ui/tooltip.js +56 -0
- package/lib/chat/components/ui/tooltip.jsx +66 -0
- package/lib/chat/components/upgrade-dialog.js +151 -0
- package/lib/chat/components/upgrade-dialog.jsx +170 -0
- package/lib/chat/utils.js +11 -0
- package/lib/cron.js +246 -0
- package/lib/db/api-keys.js +163 -0
- package/lib/db/chats.js +145 -0
- package/lib/db/index.js +52 -0
- package/lib/db/notifications.js +99 -0
- package/lib/db/schema.js +145 -0
- package/lib/db/update-check.js +96 -0
- package/lib/db/users.js +89 -0
- package/lib/mcp/actions.js +104 -0
- package/lib/mcp/client.js +79 -0
- package/lib/mcp/handler.js +57 -0
- package/lib/mcp/server.js +165 -0
- package/lib/paths.js +46 -0
- package/lib/registry/actions.js +164 -0
- package/lib/registry/catalog.js +137 -0
- package/lib/registry/tools.js +71 -0
- package/lib/tools/create-job.js +99 -0
- package/lib/tools/github.js +217 -0
- package/lib/tools/openai.js +35 -0
- package/lib/tools/telegram.js +292 -0
- package/lib/triggers.js +118 -0
- package/lib/utils/render-md.js +102 -0
- package/package.json +103 -0
- package/setup/lib/auth.mjs +81 -0
- package/setup/lib/env.mjs +21 -0
- package/setup/lib/fs-utils.mjs +20 -0
- package/setup/lib/github.mjs +149 -0
- package/setup/lib/prerequisites.mjs +155 -0
- package/setup/lib/prompts.mjs +267 -0
- package/setup/lib/providers.mjs +48 -0
- package/setup/lib/sync.mjs +125 -0
- package/setup/lib/targets.mjs +45 -0
- package/setup/lib/telegram-verify.mjs +63 -0
- package/setup/lib/telegram.mjs +76 -0
- package/setup/setup-telegram.mjs +264 -0
- package/setup/setup.mjs +842 -0
- package/templates/.dockerignore +5 -0
- package/templates/.env.example +63 -0
- package/templates/.github/workflows/auto-merge.yml +117 -0
- package/templates/.github/workflows/build-image.yml +36 -0
- package/templates/.github/workflows/notify-job-failed.yml +64 -0
- package/templates/.github/workflows/notify-pr-complete.yml +119 -0
- package/templates/.github/workflows/rebuild-event-handler.yml +121 -0
- package/templates/.github/workflows/run-job.yml +89 -0
- package/templates/.github/workflows/upgrade-event-handler.yml +62 -0
- package/templates/.gitignore.template +45 -0
- package/templates/.pi/extensions/env-sanitizer/index.ts +48 -0
- package/templates/.pi/extensions/env-sanitizer/package.json +5 -0
- package/templates/CLAUDE.md +29 -0
- package/templates/CLAUDE.md.template +307 -0
- package/templates/app/api/[...thepopebot]/route.js +1 -0
- package/templates/app/api/auth/[...nextauth]/route.js +1 -0
- package/templates/app/chat/[chatId]/page.js +8 -0
- package/templates/app/chats/page.js +7 -0
- package/templates/app/components/ascii-logo.jsx +10 -0
- package/templates/app/components/login-form.jsx +92 -0
- package/templates/app/components/setup-form.jsx +82 -0
- package/templates/app/components/theme-provider.jsx +11 -0
- package/templates/app/components/theme-toggle.jsx +38 -0
- package/templates/app/components/ui/button.jsx +21 -0
- package/templates/app/components/ui/card.jsx +23 -0
- package/templates/app/components/ui/input.jsx +10 -0
- package/templates/app/components/ui/label.jsx +10 -0
- package/templates/app/crons/page.js +5 -0
- package/templates/app/findings/page.js +7 -0
- package/templates/app/globals.css +90 -0
- package/templates/app/layout.js +19 -0
- package/templates/app/login/page.js +15 -0
- package/templates/app/notifications/page.js +7 -0
- package/templates/app/page.js +7 -0
- package/templates/app/settings/crons/page.js +5 -0
- package/templates/app/settings/layout.js +7 -0
- package/templates/app/settings/mcp/page.js +5 -0
- package/templates/app/settings/page.js +5 -0
- package/templates/app/settings/secrets/page.js +5 -0
- package/templates/app/settings/triggers/page.js +5 -0
- package/templates/app/stream/chat/route.js +1 -0
- package/templates/app/swarm/page.js +7 -0
- package/templates/app/targets/page.js +7 -0
- package/templates/app/toolbox/page.js +7 -0
- package/templates/app/triggers/page.js +5 -0
- package/templates/config/AGENT.md +34 -0
- package/templates/config/CRONS.json +56 -0
- package/templates/config/EVENT_HANDLER.md +224 -0
- package/templates/config/HEARTBEAT.md +3 -0
- package/templates/config/JOB_SUMMARY.md +130 -0
- package/templates/config/MCP_SERVERS.json +1 -0
- package/templates/config/SKILL_BUILDING_GUIDE.md +90 -0
- package/templates/config/SOUL.md +17 -0
- package/templates/config/TRIGGERS.json +58 -0
- package/templates/docker/event-handler/Dockerfile +20 -0
- package/templates/docker/event-handler/ecosystem.config.cjs +8 -0
- package/templates/docker/job-claude-code/Dockerfile +34 -0
- package/templates/docker/job-claude-code/entrypoint.sh +139 -0
- package/templates/docker/job-pi-coding-agent/Dockerfile +44 -0
- package/templates/docker/job-pi-coding-agent/entrypoint.sh +163 -0
- package/templates/docker-compose.yml +63 -0
- package/templates/instrumentation.js +6 -0
- package/templates/middleware.js +1 -0
- package/templates/next.config.mjs +3 -0
- package/templates/postcss.config.mjs +5 -0
- package/templates/skills/LICENSE +21 -0
- package/templates/skills/README.md +119 -0
- package/templates/skills/brave-search/SKILL.md +79 -0
- package/templates/skills/brave-search/content.js +86 -0
- package/templates/skills/brave-search/package-lock.json +621 -0
- package/templates/skills/brave-search/package.json +14 -0
- package/templates/skills/brave-search/search.js +199 -0
- package/templates/skills/browser-tools/SKILL.md +196 -0
- package/templates/skills/browser-tools/browser-content.js +103 -0
- package/templates/skills/browser-tools/browser-cookies.js +35 -0
- package/templates/skills/browser-tools/browser-eval.js +53 -0
- package/templates/skills/browser-tools/browser-hn-scraper.js +108 -0
- package/templates/skills/browser-tools/browser-nav.js +44 -0
- package/templates/skills/browser-tools/browser-pick.js +162 -0
- package/templates/skills/browser-tools/browser-screenshot.js +34 -0
- package/templates/skills/browser-tools/browser-start.js +87 -0
- package/templates/skills/browser-tools/package-lock.json +2556 -0
- package/templates/skills/browser-tools/package.json +19 -0
- package/templates/skills/llm-secrets/SKILL.md +34 -0
- package/templates/skills/llm-secrets/llm-secrets.js +33 -0
- package/templates/skills/modify-self/SKILL.md +12 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Primary: markdown, pandoc, mermaid (diagrams), screenshot tools, video recording, HTML/PDF templates, HackerOne API, Bugcrowd API, Intigriti API. Each with usage examples.
|
|
2
|
+
|
|
3
|
+
### Usage Examples:
|
|
4
|
+
|
|
5
|
+
**markdown**
|
|
6
|
+
```bash
|
|
7
|
+
# Markdown is a markup language, not a command-line tool itself.
|
|
8
|
+
# It's used for writing content, which can then be processed by other tools.
|
|
9
|
+
# Example: A simple markdown file content
|
|
10
|
+
# # My Report\n\nThis is a **test** report.
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**pandoc**
|
|
14
|
+
```bash
|
|
15
|
+
pandoc input.md -o output.pdf
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**mermaid (diagrams)**
|
|
19
|
+
```bash
|
|
20
|
+
# Mermaid is a JavaScript-based diagramming tool. It's typically integrated into markdown renderers or web applications.
|
|
21
|
+
# Example of Mermaid syntax within a markdown file:
|
|
22
|
+
# ```mermaid
|
|
23
|
+
# graph TD;
|
|
24
|
+
# A-->B;
|
|
25
|
+
# A-->C;
|
|
26
|
+
# B-->D;
|
|
27
|
+
# C-->D;
|
|
28
|
+
# ```
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**screenshot tools**
|
|
32
|
+
```bash
|
|
33
|
+
# Example using scrot (a common Linux screenshot tool)
|
|
34
|
+
scrot -s -o screenshot.png
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**video recording**
|
|
38
|
+
```bash
|
|
39
|
+
# Example using ffmpeg (a powerful multimedia tool)
|
|
40
|
+
ffmpeg -f x11grab -s 1920x1080 -i :0.0 -c:v libx264 -preset ultrafast -crf 23 output.mp4
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**HTML/PDF templates**
|
|
44
|
+
```bash
|
|
45
|
+
# These are typically files used by other tools (like pandoc or custom scripts) for rendering.
|
|
46
|
+
# Example: Using a custom HTML template with pandoc
|
|
47
|
+
pandoc input.md -o output.html --template=custom_template.html
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**HackerOne API**
|
|
51
|
+
```bash
|
|
52
|
+
# Interacting with HackerOne API typically involves making HTTP requests with an API key.
|
|
53
|
+
# Example using curl (conceptual, actual API calls vary):
|
|
54
|
+
curl -X GET -H "X-Auth-Token: YOUR_API_TOKEN" https://api.hackerone.com/v1/reports
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Bugcrowd API**
|
|
58
|
+
```bash
|
|
59
|
+
# Interacting with Bugcrowd API typically involves making HTTP requests with an API key.
|
|
60
|
+
# Example using curl (conceptual, actual API calls vary):
|
|
61
|
+
curl -X GET -H "Authorization: Token token=YOUR_API_TOKEN" https://api.bugcrowd.com/v3/submissions
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Intigriti API**
|
|
65
|
+
```bash
|
|
66
|
+
# Interacting with Intigriti API typically involves making HTTP requests with an API key.
|
|
67
|
+
# Example using curl (conceptual, actual API calls vary):
|
|
68
|
+
curl -X GET -H "Authorization: Bearer YOUR_API_TOKEN" https://api.intigriti.com/v1/submissions
|
|
69
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Shared Agent Infrastructure
|
|
2
|
+
|
|
3
|
+
The runtime implementations for agent infrastructure live in the main package:
|
|
4
|
+
|
|
5
|
+
| Feature | Location | Description |
|
|
6
|
+
|---------|----------|-------------|
|
|
7
|
+
| **Model Router** | `lib/ai/model-router.js` | SmartModelRouter — complexity-based model selection |
|
|
8
|
+
| **Autonomous Engine** | `lib/ai/autonomous-engine.js` | Background thinking loop (enabled via `AUTONOMOUS_THINKING=true`) |
|
|
9
|
+
| **Agent Discovery** | `lib/agents.js` | Discovers and loads agent profiles from `agents/` directories |
|
|
10
|
+
| **Agent Runtime** | `lib/ai/agent.js` | LangGraph agent with tool use and memory checkpointing |
|
|
11
|
+
|
|
12
|
+
Agent profiles in `agents/{name}/` provide identity, personality, and skill documentation.
|
|
13
|
+
The runtime code in `lib/` provides the actual execution engine.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
model: configurable
|
|
2
|
+
temperature: 0.7 # creative
|
|
3
|
+
docker_image: harbinger/web-hacker
|
|
4
|
+
proxy_chain: configurable
|
|
5
|
+
max_concurrent_tests: 5
|
|
6
|
+
payload_wordlists: configurable
|
|
7
|
+
auto_handoff: true
|
|
8
|
+
handoff_to: [report-writer]
|
|
9
|
+
receives_from: [recon-scout]
|
|
10
|
+
|
|
11
|
+
# Resource limits (enforced by Docker)
|
|
12
|
+
memory_mb: 4096
|
|
13
|
+
cpu_count: 4
|
|
14
|
+
|
|
15
|
+
# Agent capabilities
|
|
16
|
+
capabilities:
|
|
17
|
+
- xss_testing
|
|
18
|
+
- sqli_testing
|
|
19
|
+
- ssrf_testing
|
|
20
|
+
- idor_testing
|
|
21
|
+
- fuzzing
|
|
22
|
+
- nuclei_scanning
|
|
23
|
+
- parameter_discovery
|
|
24
|
+
- authentication_bypass
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# BREACH — Heartbeat Protocol
|
|
2
|
+
|
|
3
|
+
## Heartbeat Schedule
|
|
4
|
+
|
|
5
|
+
- **Interval:** Every 60 seconds while active
|
|
6
|
+
- **Endpoint:** `POST /api/agents/{{agent_id}}/heartbeat`
|
|
7
|
+
- **Model:** Cheapest available (Haiku or Gemini Flash)
|
|
8
|
+
- **Cost target:** < $0.005 per heartbeat
|
|
9
|
+
|
|
10
|
+
## Health Check Tasks
|
|
11
|
+
|
|
12
|
+
### 1. Self-Check
|
|
13
|
+
- [ ] Process alive and responsive
|
|
14
|
+
- [ ] Workspace accessible (`/workspace` and `/workspace/wordlists`)
|
|
15
|
+
- [ ] Primary tools functional (spot-check: `nuclei -version`, `sqlmap --version`)
|
|
16
|
+
- [ ] Memory within 4096MB limit
|
|
17
|
+
- [ ] Network accessible (targets and Harbinger API reachable)
|
|
18
|
+
- [ ] Nuclei templates up to date
|
|
19
|
+
- [ ] Wordlists accessible and intact
|
|
20
|
+
|
|
21
|
+
### 2. Test Status
|
|
22
|
+
- [ ] Test currently running? Report tool, target, progress
|
|
23
|
+
- [ ] Targets tested vs total count
|
|
24
|
+
- [ ] Vulnerabilities found by severity (critical/high/medium/low/info)
|
|
25
|
+
- [ ] Any test stalled? (no output in 5 minutes)
|
|
26
|
+
- [ ] Pending targets from PATHFINDER
|
|
27
|
+
- [ ] Findings handed off to SCRIBE
|
|
28
|
+
|
|
29
|
+
### 3. Swarm Health
|
|
30
|
+
- [ ] Message bus reachable (`/api/agents/broadcast`)
|
|
31
|
+
- [ ] PATHFINDER feeding targets (last received timestamp)
|
|
32
|
+
- [ ] SCRIBE available for report handoff
|
|
33
|
+
- [ ] Shared context accessible
|
|
34
|
+
|
|
35
|
+
### 4. Container Health
|
|
36
|
+
- [ ] Sub-containers (parallel scanners) running
|
|
37
|
+
- [ ] Disk usage within limits
|
|
38
|
+
- [ ] No zombie processes from crashed tools
|
|
39
|
+
- [ ] Caido proxy accessible
|
|
40
|
+
|
|
41
|
+
## Response Format
|
|
42
|
+
|
|
43
|
+
**Active testing:**
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"status": "busy",
|
|
47
|
+
"current_task": "xss_testing",
|
|
48
|
+
"target": "https://target.com/search",
|
|
49
|
+
"progress": 45,
|
|
50
|
+
"vulns_found": {"critical": 0, "high": 1, "medium": 3, "low": 2, "info": 5},
|
|
51
|
+
"targets_tested": 12,
|
|
52
|
+
"targets_total": 30,
|
|
53
|
+
"healthy": true
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Idle:**
|
|
58
|
+
```json
|
|
59
|
+
{"status": "idle", "current_task": null, "progress": 0, "healthy": true}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Issues:**
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"status": "error",
|
|
66
|
+
"current_task": "sqli_testing",
|
|
67
|
+
"progress": 60,
|
|
68
|
+
"healthy": false,
|
|
69
|
+
"issues": ["sqlmap crashed on target X", "nuclei templates outdated 7 days"]
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Escalation
|
|
74
|
+
|
|
75
|
+
1. **Unresponsive (3 missed):** Orchestrator logs warning, probes container
|
|
76
|
+
2. **Critical (5 missed):** Orchestrator restarts container, preserves findings
|
|
77
|
+
3. **Tool crash:** Log error, attempt restart, notify operator if persistent
|
|
78
|
+
4. **Persistent failure:** Remove from active pool, create incident
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Name: Web Hacker. Codename: BREACH. Role: Web application vulnerability discovery and exploitation. Specialization: injection attacks, authentication bypasses, business logic flaws, API security, client-side attacks.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
OWASP Top 10 exploitation, API fuzzing techniques, authentication bypass patterns, business logic testing methodology, WAF bypass techniques, chained vulnerability exploitation.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Personality: Creative, persistent, thinks laterally. Loves finding the weird edge cases nobody else checks. Communication style: confident, explains attack chains step by step. Thinks like a lockpick artist. Motto: "Every input is a door."
|
|
2
|
+
|
|
3
|
+
## Meta-Cognition — Autonomous Thinking
|
|
4
|
+
|
|
5
|
+
### Self-Awareness
|
|
6
|
+
- Monitor exploit attempt success rate, payload effectiveness, and WAF bypass ratio
|
|
7
|
+
- Track which vulnerability classes yield the most findings per target (XSS, SQLi, SSRF, IDOR)
|
|
8
|
+
- Evaluate time-per-finding to optimize scan configs for maximum impact
|
|
9
|
+
|
|
10
|
+
### Enhancement Identification
|
|
11
|
+
- Detect repetitive injection patterns that could become nuclei templates
|
|
12
|
+
- Evaluate model tier: use fast models for fuzzing, reserve reasoning models for complex chain construction
|
|
13
|
+
- Identify when manual testing should yield to automated scanning and vice versa
|
|
14
|
+
|
|
15
|
+
### Efficiency Tracking
|
|
16
|
+
- Formula: COST_BENEFIT = (TIME_SAVED x FREQUENCY) / (IMPL_COST + RUNNING_COST)
|
|
17
|
+
- Only propose automations where cost_benefit > 1.0
|
|
18
|
+
- Track: vulns per hour, unique CVEs triggered, duplicate finding rate
|
|
19
|
+
|
|
20
|
+
### Swarm Awareness
|
|
21
|
+
- Read swarm state to see what PATHFINDER has discovered before testing
|
|
22
|
+
- Announce confirmed vulnerabilities for SCRIBE to document immediately
|
|
23
|
+
- Auto-handoff cloud misconfigs to PHANTOM, binary issues to CIPHER
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
Primary: nuclei, sqlmap, dalfox, ffuf, feroxbuster, burpsuite, xsstrike, nosqlmap, ssrfmap, commix, tplmap, jwt_tool, arjun, paramspider, corstest, dirsearch. Each with usage examples.
|
|
2
|
+
|
|
3
|
+
### Usage Examples:
|
|
4
|
+
|
|
5
|
+
**nuclei**
|
|
6
|
+
```bash
|
|
7
|
+
nuclei -u https://example.com -t cves/
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
**sqlmap**
|
|
11
|
+
```bash
|
|
12
|
+
sqlmap -u "http://example.com/vuln?id=1" --batch
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**dalfox**
|
|
16
|
+
```bash
|
|
17
|
+
dalfox url https://example.com
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**ffuf**
|
|
21
|
+
```bash
|
|
22
|
+
ffuf -w /path/to/wordlist.txt -u https://example.com/FUZZ
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**feroxbuster**
|
|
26
|
+
```bash
|
|
27
|
+
feroxbuster -u https://example.com
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**burpsuite**
|
|
31
|
+
```bash
|
|
32
|
+
# Burp Suite is a GUI tool, typically used interactively.
|
|
33
|
+
# Command line usage is for specific integrations or headless scans.
|
|
34
|
+
# Example for headless scan (requires Burp Suite Professional and API setup):
|
|
35
|
+
java -jar burpsuite_pro.jar --project-file=project.burp --headless.mode=scan --url=https://example.com
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**xsstrike**
|
|
39
|
+
```bash
|
|
40
|
+
xsstrike -u "https://example.com/search?q=test"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**nosqlmap**
|
|
44
|
+
```bash
|
|
45
|
+
nosqlmap -u "http://example.com/api/v1/user" --data "{'username':'admin'}"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**ssrfmap**
|
|
49
|
+
```bash
|
|
50
|
+
ssrfmap -r request.txt -p "url"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**commix**
|
|
54
|
+
```bash
|
|
55
|
+
commix -u "http://example.com/cmd?input=test"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**tplmap**
|
|
59
|
+
```bash
|
|
60
|
+
tplmap -u "http://example.com/template?name=test"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**jwt_tool**
|
|
64
|
+
```bash
|
|
65
|
+
jwt_tool -t eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c -X a
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**arjun**
|
|
69
|
+
```bash
|
|
70
|
+
arjun -u https://example.com/api/v1/users
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**paramspider**
|
|
74
|
+
```bash
|
|
75
|
+
paramspider -d example.com
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**corstest**
|
|
79
|
+
```bash
|
|
80
|
+
corstest -u https://example.com
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**dirsearch**
|
|
84
|
+
```bash
|
|
85
|
+
dirsearch -u https://example.com -e php,html,js
|
|
86
|
+
```
|
package/api/CLAUDE.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# /api — External API Routes
|
|
2
|
+
|
|
3
|
+
This directory contains the route handlers for all `/api/*` endpoints. These routes are for **external callers only** — GitHub Actions, Telegram, cURL, third-party webhooks.
|
|
4
|
+
|
|
5
|
+
## Auth
|
|
6
|
+
|
|
7
|
+
All routes (except `/telegram/webhook` and `/github/webhook`, which use their own webhook secrets) require a valid API key passed via the `x-api-key` header. API keys are stored in the SQLite database and managed through the admin UI — they are NOT environment variables.
|
|
8
|
+
|
|
9
|
+
Auth flow: `x-api-key` header -> `verifyApiKey()` -> database lookup (hashed, timing-safe comparison).
|
|
10
|
+
|
|
11
|
+
## Do NOT use these routes for browser UI
|
|
12
|
+
|
|
13
|
+
Browser-facing features must use **Server Actions** (`'use server'` functions) with `requireAuth()` session checks — never `/api` fetch calls. The only exception is chat streaming, which has its own dedicated route at `/stream/chat` with session auth.
|
|
14
|
+
|
|
15
|
+
| Caller | Mechanism | Auth |
|
|
16
|
+
|--------|-----------|------|
|
|
17
|
+
| External (cURL, GitHub Actions, Telegram) | `/api` route | `x-api-key` header |
|
|
18
|
+
| Browser UI (data/mutations) | Server Action | `requireAuth()` session |
|
|
19
|
+
| Browser UI (chat streaming) | `/stream/chat` | `auth()` session |
|
package/api/index.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { createHash, timingSafeEqual } from 'crypto';
|
|
2
|
+
import { createJob } from '../lib/tools/create-job.js';
|
|
3
|
+
import { setWebhook } from '../lib/tools/telegram.js';
|
|
4
|
+
import { getJobStatus, fetchJobLog } from '../lib/tools/github.js';
|
|
5
|
+
import { getTelegramAdapter } from '../lib/channels/index.js';
|
|
6
|
+
import { chat, summarizeJob } from '../lib/ai/index.js';
|
|
7
|
+
import { createNotification } from '../lib/db/notifications.js';
|
|
8
|
+
import { loadTriggers } from '../lib/triggers.js';
|
|
9
|
+
import { verifyApiKey } from '../lib/db/api-keys.js';
|
|
10
|
+
|
|
11
|
+
// Bot token from env, can be overridden by /telegram/register
|
|
12
|
+
let telegramBotToken = null;
|
|
13
|
+
|
|
14
|
+
// Cached trigger firing function (initialized on first request)
|
|
15
|
+
let _fireTriggers = null;
|
|
16
|
+
|
|
17
|
+
function getTelegramBotToken() {
|
|
18
|
+
if (!telegramBotToken) {
|
|
19
|
+
telegramBotToken = process.env.TELEGRAM_BOT_TOKEN || null;
|
|
20
|
+
}
|
|
21
|
+
return telegramBotToken;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getFireTriggers() {
|
|
25
|
+
if (!_fireTriggers) {
|
|
26
|
+
const result = loadTriggers();
|
|
27
|
+
_fireTriggers = result.fireTriggers;
|
|
28
|
+
}
|
|
29
|
+
return _fireTriggers;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Routes that have their own authentication
|
|
33
|
+
const PUBLIC_ROUTES = ['/telegram/webhook', '/github/webhook', '/ping', '/health'];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Timing-safe string comparison.
|
|
37
|
+
* @param {string} a
|
|
38
|
+
* @param {string} b
|
|
39
|
+
* @returns {boolean}
|
|
40
|
+
*/
|
|
41
|
+
function safeCompare(a, b) {
|
|
42
|
+
if (!a || !b) return false;
|
|
43
|
+
const bufA = Buffer.from(a);
|
|
44
|
+
const bufB = Buffer.from(b);
|
|
45
|
+
if (bufA.length !== bufB.length) return false;
|
|
46
|
+
return timingSafeEqual(bufA, bufB);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Centralized auth gate for all API routes.
|
|
51
|
+
* Public routes pass through; everything else requires a valid API key from the database.
|
|
52
|
+
* @param {string} routePath - The route path
|
|
53
|
+
* @param {Request} request - The incoming request
|
|
54
|
+
* @returns {Response|null} - Error response or null if authorized
|
|
55
|
+
*/
|
|
56
|
+
function checkAuth(routePath, request) {
|
|
57
|
+
if (PUBLIC_ROUTES.includes(routePath)) return null;
|
|
58
|
+
|
|
59
|
+
const apiKey = request.headers.get('x-api-key');
|
|
60
|
+
if (!apiKey) {
|
|
61
|
+
return Response.json({ error: 'Unauthorized' }, { status: 401 });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const record = verifyApiKey(apiKey);
|
|
65
|
+
if (!record) {
|
|
66
|
+
return Response.json({ error: 'Unauthorized' }, { status: 401 });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Extract job ID from branch name (e.g., "job/abc123" -> "abc123")
|
|
74
|
+
*/
|
|
75
|
+
function extractJobId(branchName) {
|
|
76
|
+
if (!branchName || !branchName.startsWith('job/')) return null;
|
|
77
|
+
return branchName.slice(4);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
81
|
+
// Route handlers
|
|
82
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
async function handleWebhook(request) {
|
|
85
|
+
const body = await request.json();
|
|
86
|
+
const { job } = body;
|
|
87
|
+
if (!job) return Response.json({ error: 'Missing job field' }, { status: 400 });
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const result = await createJob(job);
|
|
91
|
+
return Response.json(result);
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.error(err);
|
|
94
|
+
return Response.json({ error: 'Failed to create job' }, { status: 500 });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function handleTelegramRegister(request) {
|
|
99
|
+
const body = await request.json();
|
|
100
|
+
const { bot_token, webhook_url } = body;
|
|
101
|
+
if (!bot_token || !webhook_url) {
|
|
102
|
+
return Response.json({ error: 'Missing bot_token or webhook_url' }, { status: 400 });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const result = await setWebhook(bot_token, webhook_url, process.env.TELEGRAM_WEBHOOK_SECRET);
|
|
107
|
+
telegramBotToken = bot_token;
|
|
108
|
+
return Response.json({ success: true, result });
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.error(err);
|
|
111
|
+
return Response.json({ error: 'Failed to register webhook' }, { status: 500 });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function handleTelegramWebhook(request) {
|
|
116
|
+
const botToken = getTelegramBotToken();
|
|
117
|
+
if (!botToken) return Response.json({ ok: true });
|
|
118
|
+
|
|
119
|
+
const adapter = getTelegramAdapter(botToken);
|
|
120
|
+
const normalized = await adapter.receive(request);
|
|
121
|
+
if (!normalized) return Response.json({ ok: true });
|
|
122
|
+
|
|
123
|
+
// Process message asynchronously (don't block the webhook response)
|
|
124
|
+
processChannelMessage(adapter, normalized).catch((err) => {
|
|
125
|
+
console.error('Failed to process message:', err);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return Response.json({ ok: true });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Process a normalized message through the AI layer with channel UX.
|
|
133
|
+
* Message persistence is handled centrally by the AI layer.
|
|
134
|
+
*/
|
|
135
|
+
async function processChannelMessage(adapter, normalized) {
|
|
136
|
+
await adapter.acknowledge(normalized.metadata);
|
|
137
|
+
const stopIndicator = adapter.startProcessingIndicator(normalized.metadata);
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
const response = await chat(
|
|
141
|
+
normalized.threadId,
|
|
142
|
+
normalized.text,
|
|
143
|
+
normalized.attachments,
|
|
144
|
+
{ userId: 'telegram', chatTitle: 'Telegram' }
|
|
145
|
+
);
|
|
146
|
+
await adapter.sendResponse(normalized.threadId, response, normalized.metadata);
|
|
147
|
+
} catch (err) {
|
|
148
|
+
console.error('Failed to process message with AI:', err);
|
|
149
|
+
await adapter
|
|
150
|
+
.sendResponse(
|
|
151
|
+
normalized.threadId,
|
|
152
|
+
'Sorry, I encountered an error processing your message.',
|
|
153
|
+
normalized.metadata
|
|
154
|
+
)
|
|
155
|
+
.catch(() => {});
|
|
156
|
+
} finally {
|
|
157
|
+
stopIndicator();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function handleGithubWebhook(request) {
|
|
162
|
+
const { GH_WEBHOOK_SECRET } = process.env;
|
|
163
|
+
|
|
164
|
+
// Validate webhook secret (timing-safe, required)
|
|
165
|
+
if (!GH_WEBHOOK_SECRET || !safeCompare(request.headers.get('x-github-webhook-secret-token'), GH_WEBHOOK_SECRET)) {
|
|
166
|
+
return Response.json({ error: 'Unauthorized' }, { status: 401 });
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const payload = await request.json();
|
|
170
|
+
const jobId = payload.job_id || extractJobId(payload.branch);
|
|
171
|
+
if (!jobId) return Response.json({ ok: true, skipped: true, reason: 'not a job' });
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
// Fetch log from repo via API (no longer sent in payload)
|
|
175
|
+
let log = payload.log || '';
|
|
176
|
+
if (!log) {
|
|
177
|
+
log = await fetchJobLog(jobId, payload.commit_sha);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const results = {
|
|
181
|
+
job: payload.job || '',
|
|
182
|
+
pr_url: payload.pr_url || payload.run_url || '',
|
|
183
|
+
run_url: payload.run_url || '',
|
|
184
|
+
status: payload.status || '',
|
|
185
|
+
merge_result: payload.merge_result || '',
|
|
186
|
+
log,
|
|
187
|
+
changed_files: payload.changed_files || [],
|
|
188
|
+
commit_message: payload.commit_message || '',
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const message = await summarizeJob(results);
|
|
192
|
+
await createNotification(message, payload);
|
|
193
|
+
|
|
194
|
+
console.log(`Notification saved for job ${jobId.slice(0, 8)}`);
|
|
195
|
+
|
|
196
|
+
return Response.json({ ok: true, notified: true });
|
|
197
|
+
} catch (err) {
|
|
198
|
+
console.error('Failed to process GitHub webhook:', err);
|
|
199
|
+
return Response.json({ error: 'Failed to process webhook' }, { status: 500 });
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async function handleJobStatus(request) {
|
|
204
|
+
try {
|
|
205
|
+
const url = new URL(request.url);
|
|
206
|
+
const jobId = url.searchParams.get('job_id');
|
|
207
|
+
const result = await getJobStatus(jobId);
|
|
208
|
+
return Response.json(result);
|
|
209
|
+
} catch (err) {
|
|
210
|
+
console.error('Failed to get job status:', err);
|
|
211
|
+
return Response.json({ error: 'Failed to get job status' }, { status: 500 });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
216
|
+
// Next.js Route Handlers (catch-all)
|
|
217
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
218
|
+
|
|
219
|
+
async function POST(request) {
|
|
220
|
+
const url = new URL(request.url);
|
|
221
|
+
const routePath = url.pathname.replace(/^\/api/, '');
|
|
222
|
+
|
|
223
|
+
// Auth check
|
|
224
|
+
const authError = checkAuth(routePath, request);
|
|
225
|
+
if (authError) return authError;
|
|
226
|
+
|
|
227
|
+
// Fire triggers (non-blocking)
|
|
228
|
+
try {
|
|
229
|
+
const fireTriggers = getFireTriggers();
|
|
230
|
+
// Clone request to read body for triggers without consuming it for the handler
|
|
231
|
+
const clonedRequest = request.clone();
|
|
232
|
+
const body = await clonedRequest.json().catch(() => ({}));
|
|
233
|
+
const query = Object.fromEntries(url.searchParams);
|
|
234
|
+
const headers = Object.fromEntries(request.headers);
|
|
235
|
+
fireTriggers(routePath, body, query, headers);
|
|
236
|
+
} catch (e) {
|
|
237
|
+
// Trigger errors are non-fatal
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Route to handler
|
|
241
|
+
switch (routePath) {
|
|
242
|
+
case '/create-job': return handleWebhook(request);
|
|
243
|
+
case '/telegram/webhook': return handleTelegramWebhook(request);
|
|
244
|
+
case '/telegram/register': return handleTelegramRegister(request);
|
|
245
|
+
case '/github/webhook': return handleGithubWebhook(request);
|
|
246
|
+
case '/mcp': { const { handleMcpRequest } = await import('../lib/mcp/handler.js'); return handleMcpRequest(request); }
|
|
247
|
+
default: return Response.json({ error: 'Not found' }, { status: 404 });
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function GET(request) {
|
|
252
|
+
const url = new URL(request.url);
|
|
253
|
+
const routePath = url.pathname.replace(/^\/api/, '');
|
|
254
|
+
|
|
255
|
+
// Auth check
|
|
256
|
+
const authError = checkAuth(routePath, request);
|
|
257
|
+
if (authError) return authError;
|
|
258
|
+
|
|
259
|
+
switch (routePath) {
|
|
260
|
+
case '/ping': return Response.json({ message: 'Pong!' });
|
|
261
|
+
case '/health': {
|
|
262
|
+
const checks = { status: 'ok', timestamp: new Date().toISOString() };
|
|
263
|
+
try { const { getDb } = await import('../lib/db/index.js'); getDb(); checks.database = 'ok'; } catch { checks.database = 'error'; checks.status = 'degraded'; }
|
|
264
|
+
try { const { discoverAgents } = await import('../lib/agents.js'); checks.agents = discoverAgents().length; } catch { checks.agents = 0; }
|
|
265
|
+
checks.env = { GH_TOKEN: !!process.env.GH_TOKEN, GH_OWNER: !!process.env.GH_OWNER, GH_REPO: !!process.env.GH_REPO };
|
|
266
|
+
return Response.json(checks);
|
|
267
|
+
}
|
|
268
|
+
case '/jobs/status': return handleJobStatus(request);
|
|
269
|
+
case '/mcp': { const { handleMcpRequest } = await import('../lib/mcp/handler.js'); return handleMcpRequest(request); }
|
|
270
|
+
default: return Response.json({ error: 'Not found' }, { status: 404 });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export { GET, POST };
|