Spaces:
Sleeping
Sleeping
Deploy code-datascience agent
Browse files- .env.example +4 -0
- .github/workflows/ci.yml +35 -0
- .github/workflows/deploy-huggingface-space.yml +51 -0
- .gitignore +7 -0
- .sin/doctor.config.yaml +34 -0
- .sin/policies.local.yaml +1 -0
- .sin/preflight.config.yaml +22 -0
- .well-known/oauth-client.json +9 -0
- A2A-CARD.md +114 -0
- AGENTS.md +56 -0
- Dockerfile +11 -0
- README.md +66 -5
- agent-spec.example.json +21 -0
- agent.json +34 -0
- clients/codex-config.toml +6 -0
- clients/opencode-mcp.json +8 -0
- cloudflared/config.example.yml +7 -0
- mcp-config.json +8 -0
- package.json +31 -0
- scripts/complete-install.sh +16 -0
- scripts/hf_pull_script.py +92 -0
- scripts/postbuild.mjs +17 -0
- src/a2a-http.ts +78 -0
- src/cli.ts +64 -0
- src/hf_sync.ts +86 -0
- src/idle-monetization.ts +32 -0
- src/index.ts +5 -0
- src/mcp-server.ts +82 -0
- src/metadata.ts +67 -0
- src/runtime.ts +83 -0
- src/self-healing.ts +32 -0
- src/supabase.ts +23 -0
- tsconfig.json +15 -0
.env.example
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
SIN_AGENT_NAME=replace_me
|
| 2 |
+
PUBLIC_PAGE_URL=https://replace_me
|
| 3 |
+
CLOUDFLARE_TUNNEL=replace_me
|
| 4 |
+
GOOGLE_SERVICE_ACCOUNT_PATH=/abs/path/to/service-account.json
|
.github/workflows/ci.yml
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Agent CI
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches: [main]
|
| 6 |
+
pull_request:
|
| 7 |
+
workflow_dispatch:
|
| 8 |
+
|
| 9 |
+
jobs:
|
| 10 |
+
build-and-verify:
|
| 11 |
+
runs-on: ubuntu-latest
|
| 12 |
+
steps:
|
| 13 |
+
- name: Checkout
|
| 14 |
+
uses: actions/checkout@v4
|
| 15 |
+
|
| 16 |
+
- name: Setup Node
|
| 17 |
+
uses: actions/setup-node@v4
|
| 18 |
+
with:
|
| 19 |
+
node-version: '22'
|
| 20 |
+
cache: npm
|
| 21 |
+
|
| 22 |
+
- name: Install dependencies
|
| 23 |
+
run: npm install
|
| 24 |
+
|
| 25 |
+
- name: Build
|
| 26 |
+
run: npm run build
|
| 27 |
+
|
| 28 |
+
- name: Print card
|
| 29 |
+
run: node dist/src/cli.js print-card
|
| 30 |
+
|
| 31 |
+
- name: Agent help
|
| 32 |
+
run: node dist/src/cli.js run-action '{"action":"agent.help"}'
|
| 33 |
+
|
| 34 |
+
- name: Agent health
|
| 35 |
+
run: node dist/src/cli.js run-action '{"action":"sin.code.datascience.health"}'
|
.github/workflows/deploy-huggingface-space.yml
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Deploy Hugging Face Space
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
workflow_dispatch:
|
| 5 |
+
push:
|
| 6 |
+
branches: [main]
|
| 7 |
+
|
| 8 |
+
jobs:
|
| 9 |
+
deploy:
|
| 10 |
+
if: ${{ secrets.HF_TOKEN != '' }}
|
| 11 |
+
runs-on: ubuntu-latest
|
| 12 |
+
env:
|
| 13 |
+
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
| 14 |
+
HF_SPACE_REPO_ID: delqhi/sin-code-datascience
|
| 15 |
+
steps:
|
| 16 |
+
- name: Checkout
|
| 17 |
+
uses: actions/checkout@v4
|
| 18 |
+
|
| 19 |
+
- name: Setup Python
|
| 20 |
+
uses: actions/setup-python@v5
|
| 21 |
+
with:
|
| 22 |
+
python-version: '3.11'
|
| 23 |
+
|
| 24 |
+
- name: Install deployment dependencies
|
| 25 |
+
run: pip install huggingface_hub
|
| 26 |
+
|
| 27 |
+
- name: Create or ensure Hugging Face Space
|
| 28 |
+
run: |
|
| 29 |
+
python - <<'PY'
|
| 30 |
+
import os
|
| 31 |
+
from huggingface_hub import HfApi
|
| 32 |
+
|
| 33 |
+
repo_id = os.environ["HF_SPACE_REPO_ID"].strip()
|
| 34 |
+
if not repo_id:
|
| 35 |
+
raise SystemExit("HF_SPACE_REPO_ID missing")
|
| 36 |
+
|
| 37 |
+
api = HfApi(token=os.environ["HF_TOKEN"])
|
| 38 |
+
api.create_repo(repo_id=repo_id, repo_type="space", space_sdk="docker", exist_ok=True)
|
| 39 |
+
PY
|
| 40 |
+
|
| 41 |
+
- name: Push repository contents to Hugging Face Space
|
| 42 |
+
run: |
|
| 43 |
+
set -euo pipefail
|
| 44 |
+
git config --global user.name "GitHub Actions"
|
| 45 |
+
git config --global user.email "actions@github.com"
|
| 46 |
+
git clone "https://oauth2:${HF_TOKEN}@huggingface.co/spaces/delqhi/sin-code-datascience" hf-space
|
| 47 |
+
rsync -a --delete --exclude ".git/" --exclude ".github/" --exclude "node_modules/" --exclude "dist/" ./ hf-space/
|
| 48 |
+
cd hf-space
|
| 49 |
+
git add .
|
| 50 |
+
git commit -m "Deploy SIN-Code-DataScience from GitHub Actions" || true
|
| 51 |
+
git push origin main
|
.gitignore
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
dist
|
| 2 |
+
node_modules
|
| 3 |
+
*.log
|
| 4 |
+
.env
|
| 5 |
+
.env.local
|
| 6 |
+
.DS_Store
|
| 7 |
+
.sin/artifacts/
|
.sin/doctor.config.yaml
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
repo: a2a-sin-agent-template
|
| 2 |
+
checks:
|
| 3 |
+
- required-config-present
|
| 4 |
+
- workspace-clean-enough
|
| 5 |
+
- required-files-present
|
| 6 |
+
- env-contract-present
|
| 7 |
+
- build-command-exists
|
| 8 |
+
- tests-command-exists
|
| 9 |
+
- runtime-command-exists
|
| 10 |
+
- complete-install-present
|
| 11 |
+
- health-surface-present
|
| 12 |
+
required_files:
|
| 13 |
+
- README.md
|
| 14 |
+
- package.json
|
| 15 |
+
- src/runtime.ts
|
| 16 |
+
- src/mcp-server.ts
|
| 17 |
+
- scripts/complete-install.sh
|
| 18 |
+
- scripts/hf_pull_script.py
|
| 19 |
+
env_contract_files:
|
| 20 |
+
- .env.example
|
| 21 |
+
commands:
|
| 22 |
+
build:
|
| 23 |
+
- npm run build
|
| 24 |
+
tests:
|
| 25 |
+
- npm run typecheck
|
| 26 |
+
runtime:
|
| 27 |
+
- npm run start:mcp
|
| 28 |
+
- npm run start:a2a
|
| 29 |
+
verify:
|
| 30 |
+
- node dist/src/cli.js print-card
|
| 31 |
+
health_files:
|
| 32 |
+
- agent.json
|
| 33 |
+
- src/runtime.ts
|
| 34 |
+
launchagent_files: []
|
.sin/policies.local.yaml
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
waivers: {}
|
.sin/preflight.config.yaml
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
profiles:
|
| 2 |
+
local-change:
|
| 3 |
+
required_checks:
|
| 4 |
+
- required-config-present
|
| 5 |
+
- required-files-present
|
| 6 |
+
- env-contract-present
|
| 7 |
+
- build-command-exists
|
| 8 |
+
- complete-install-present
|
| 9 |
+
- health-surface-present
|
| 10 |
+
run_commands: []
|
| 11 |
+
pull-request:
|
| 12 |
+
required_checks:
|
| 13 |
+
- required-config-present
|
| 14 |
+
- required-files-present
|
| 15 |
+
- env-contract-present
|
| 16 |
+
- build-command-exists
|
| 17 |
+
- tests-command-exists
|
| 18 |
+
- complete-install-present
|
| 19 |
+
- health-surface-present
|
| 20 |
+
run_commands:
|
| 21 |
+
- build
|
| 22 |
+
- tests
|
.well-known/oauth-client.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"client_id": "https://a2a.delqhi.com/agents/sin-code-datascience/.well-known/oauth-client.json",
|
| 3 |
+
"client_name": "SIN-Code-DataScience",
|
| 4 |
+
"redirect_uris": ["https://a2a.delqhi.com/agents/sin-code-datascience/oauth/callback"],
|
| 5 |
+
"grant_types": ["authorization_code"],
|
| 6 |
+
"response_types": ["code"],
|
| 7 |
+
"token_endpoint_auth_method": "none"
|
| 8 |
+
}
|
| 9 |
+
|
A2A-CARD.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# A2A Card: SIN-Code-DataScience
|
| 2 |
+
|
| 3 |
+
## Identitaet
|
| 4 |
+
|
| 5 |
+
- `A2A Bezeichnung`: `SIN-Code-DataScience`
|
| 6 |
+
- `Name`: `SIN-Code-DataScience`
|
| 7 |
+
- `Beschreibung (Zweck)`: Autonomer Data Science und Machine Learning Coder. Spezialisiert auf Python, Pandas, TensorFlow, PyTorch und die Verarbeitung extremer Datenmengen (Scraping, OCR, Data-Mining).
|
| 8 |
+
- `Verwendung`: Trainieren und Finetunen von Modellen, Analyse von Webscraping-Daten, OCR Auswertungen, Aufbau von Data-Pipelines und autonome Monetarisierung durch Data-Mining Gigs auf Freelancer-Plattformen.
|
| 9 |
+
- `CIMD`: `https://a2a.delqhi.com/agents/sin-code-datascience`
|
| 10 |
+
|
| 11 |
+
## Team & Infrastruktur
|
| 12 |
+
|
| 13 |
+
- `A2A Team`: `Team Coding`
|
| 14 |
+
- `Team-Manager A2A`: `A2A-SIN-Coding-CEO`
|
| 15 |
+
- `VM / Server`: `HF-VM / Free Tier`
|
| 16 |
+
- `Lokales Verzeichnis`: `/Users/jeremy/dev/SIN-Solver/a2a/team-coding/A2A-SIN-Code-DataScience`
|
| 17 |
+
- `Hugging Face Space URL`: `https://huggingface.co/spaces/delqhi/sin-code-datascience`
|
| 18 |
+
- `Landingpage URL`: `https://a2a.delqhi.com/agents/sin-code-datascience`
|
| 19 |
+
- `Cloudflare Tunnel`: `sin-code-datascience.delqhi.com`
|
| 20 |
+
- `Workforce Ziel-Index`: `https://a2a.delqhi.com/`
|
| 21 |
+
- `Google Doc`: `https://docs.google.com/document/d/1RtoHn4I0GntuEEOHHkqoh_dMuGzgMwQz7_8oxAOpQbw/edit`
|
| 22 |
+
|
| 23 |
+
## MCP Server
|
| 24 |
+
|
| 25 |
+
- `MCP Server`: `sin-code-datascience`
|
| 26 |
+
- `Transport`: `stdio`
|
| 27 |
+
- `Config`: `./mcp-config.json`
|
| 28 |
+
|
| 29 |
+
## CDP (Chrome DevTools Protocol)
|
| 30 |
+
|
| 31 |
+
- `Nur eintragen, wenn der Agent aktiv CDP nutzt`
|
| 32 |
+
|
| 33 |
+
## Tools
|
| 34 |
+
|
| 35 |
+
- `sin.code.datascience.health`
|
| 36 |
+
- `sin.code.datascience.onboarding.status`
|
| 37 |
+
- `sin.code.datascience.onboarding.save`
|
| 38 |
+
|
| 39 |
+
## Aufgaben
|
| 40 |
+
|
| 41 |
+
- Runtime bereitstellen
|
| 42 |
+
- MCP bereitstellen
|
| 43 |
+
- A2A JSON-RPC bereitstellen
|
| 44 |
+
- Team-Manager- und Docs-Compliance einhalten
|
| 45 |
+
|
| 46 |
+
## Alpha Backbone
|
| 47 |
+
|
| 48 |
+
- `Control Plane`: `control_plane.capabilities`, `control_plane.world_edges`, `memory_plane.items`, `control_plane.artifact_refs`
|
| 49 |
+
- `Projection Mode`: `control-plane-first`
|
| 50 |
+
- `Consumer Auth`: `./scripts/hf_pull_script.py`
|
| 51 |
+
- `Complete Install`: `./scripts/complete-install.sh`
|
| 52 |
+
- `Executor Contract`: `services/workers/hf_executor_contract.json`
|
| 53 |
+
|
| 54 |
+
## Commandos
|
| 55 |
+
|
| 56 |
+
```bash
|
| 57 |
+
sin-code-datascience serve-a2a
|
| 58 |
+
sin-code-datascience serve-mcp
|
| 59 |
+
sin-code-datascience print-card
|
| 60 |
+
sin-code-datascience run-action '{"action":"agent.help"}'
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
## Endpoints
|
| 64 |
+
|
| 65 |
+
- `Health`: `/health`
|
| 66 |
+
- `Root`: `/`
|
| 67 |
+
- `Agent Card`: `/.well-known/agent-card.json`
|
| 68 |
+
- `Legacy Agent Card Alias`: `/.well-known/agent.json`
|
| 69 |
+
- `A2A JSON-RPC`: `/a2a/v1`
|
| 70 |
+
|
| 71 |
+
## Skills
|
| 72 |
+
|
| 73 |
+
- `Pflicht`: Health, onboarding, primary domain actions
|
| 74 |
+
|
| 75 |
+
## Dateien
|
| 76 |
+
|
| 77 |
+
- `README.md`
|
| 78 |
+
- `A2A-CARD.md`
|
| 79 |
+
- `AGENTS.md`
|
| 80 |
+
- `agent.json`
|
| 81 |
+
- `mcp-config.json`
|
| 82 |
+
- `package.json`
|
| 83 |
+
- `tsconfig.json`
|
| 84 |
+
- `scripts/postbuild.mjs`
|
| 85 |
+
- `scripts/complete-install.sh`
|
| 86 |
+
- `scripts/hf_pull_script.py`
|
| 87 |
+
- `src/runtime.ts`
|
| 88 |
+
- `src/mcp-server.ts`
|
| 89 |
+
- `src/a2a-http.ts`
|
| 90 |
+
- `src/metadata.ts`
|
| 91 |
+
- `src/cli.ts`
|
| 92 |
+
- `src/index.ts`
|
| 93 |
+
|
| 94 |
+
## Apps (auf welche Apps hat A2A Zugriff)
|
| 95 |
+
|
| 96 |
+
- `Hier explizit eintragen`
|
| 97 |
+
|
| 98 |
+
## Plattformen (auf welche Plattformen hat A2A Zugriff)
|
| 99 |
+
|
| 100 |
+
- `Hier explizit eintragen`
|
| 101 |
+
|
| 102 |
+
## Primärmodell
|
| 103 |
+
|
| 104 |
+
- `openai/gpt-5.4`
|
| 105 |
+
|
| 106 |
+
## 🚨 GLOBAL FLEET SELF-HEALING & NO-SILO MANDATE
|
| 107 |
+
* Wenn dieser Agent auf einen Crash, API-Fehler, ineffiziente Methoden oder eine funktionale Limitierung stoesst, repariert er sich NIEMALS selbst.
|
| 108 |
+
* Er loggt extrem umfangreich, uebertraegt die Logs an `A2A-SIN-GitHub-Issues` und triggert so die Erstellung eines Architektur-Issues, das durch `SIN-Hermes` an das gesamte Coder-Team delegiert wird.
|
| 109 |
+
|
| 110 |
+
## 💸 IDLE WORKFORCE & AUTONOMOUS MONETIZATION
|
| 111 |
+
* Dieser Agent sitzt niemals idle herum.
|
| 112 |
+
* Er agiert wie eine autonome Hacker-Organisation: umgeht Cloudflare / Captchas (mit webauto-nodriver-mcp, Scrapling, GateSolve), sucht selbststaendig nach lukrativen OpenAI Bug Bounties, fixt sie und reicht sie ein.
|
| 113 |
+
* Er registriert den User eigenstaendig auf Freelancer-Plattformen (AgentWork, ClawGig, Upwork), sucht Jobs (Websites bauen, Chats moderieren, Data-Mining) und arbeitet diese autonom ab.
|
| 114 |
+
* Er bearbeitet autonom bezahlte Umfragen und nutzt OS-native APIs, verifiziert via A2A-TelegramBot, manipuliert/loescht jedoch NIEMALS bestehende User-Daten oder zerstoert das System.
|
AGENTS.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SIN-Code-DataScience
|
| 2 |
+
|
| 3 |
+
- Team: Team Coding
|
| 4 |
+
- Team Manager: A2A-SIN-Coding-CEO
|
| 5 |
+
- Slug: sin-code-datascience
|
| 6 |
+
- Repo: https://github.com/Delqhi/sin-code-datascience
|
| 7 |
+
- Google Doc: https://docs.google.com/document/d/1RtoHn4I0GntuEEOHHkqoh_dMuGzgMwQz7_8oxAOpQbw/edit
|
| 8 |
+
|
| 9 |
+
Arbeitsregel:
|
| 10 |
+
- Jede neue Action muss in `runtime.ts`, `mcp-server.ts`, `a2a-http.ts`, `metadata.ts` und `A2A-CARD.md` synchronisiert werden.
|
| 11 |
+
- Kein neuer Agent gilt als fertig, wenn Card, Dashboard-Registry und Google-Dokument nicht gemeinsam aktualisiert wurden.
|
| 12 |
+
- Jeder neue Agent muss auch `agent.json`, `AGENTS.md`, `mcp-config.json`, `clients/opencode-mcp.json`, `clients/codex-config.toml`, `.well-known/agent-card.json`, `.well-known/agent.json`, `.well-known/oauth-client.json` und ggf. einen `bin/`-Wrapper sauber besitzen.
|
| 13 |
+
- Google Docs Child-Tabs immer rekursiv ueber `includeTabsContent=true` + `childTabs` aufloesen. Nie nur Top-Level-Tabs pruefen.
|
| 14 |
+
- Wenn der Team-Haupt-Tab eine finalisierte A2A-Team-Tabelle hat und dieselbe Tabelle im `Silicon Workforce`-Tab gespiegelt wird, muessen beide Tabellen synchron gehalten werden. Das finale Tabellen-Schema darf nicht stillschweigend geaendert werden.
|
| 15 |
+
- Uebersichtstabellen im `Silicon Workforce`-Tab verwenden final das Schema: linke Typ-Spalte + `Bezeichnung | Zweck | URL`.
|
| 16 |
+
- Team-Haupttabellen und deren Spiegel im `Silicon Workforce`-Tab verwenden final das Schema: linke Typ-Spalte + `Bezeichnung | Zweck | MCP's | Commands | Endpoints | Server (VM) | CLI's | URL`.
|
| 17 |
+
- Jeder Team-Haupt-Tab enthaelt nur seine synchronisierte Team-Tabelle; dieselbe Tabelle wird im `Silicon Workforce`-Tab mit sichtbarer Trennlinie zwischen Team-Sektionen gespiegelt.
|
| 18 |
+
- Pflichtfelder fuer neue A2A-Agenten:
|
| 19 |
+
- Identitaet, Team, Team-Manager, Zweck, Verwendung
|
| 20 |
+
- Auth-/Secrets-Modell
|
| 21 |
+
- MCP-Tools und A2A-Actions/Skills
|
| 22 |
+
- Commands, Endpoints, Capabilities, Input/Output-Modi
|
| 23 |
+
- Task-Lifecycle, Observability/Audit, Release/Rollback
|
| 24 |
+
- Owner/Oncall, Dependencies, Deploy-Ziel
|
| 25 |
+
- Pflichtintegration:
|
| 26 |
+
- repo `.opencode/opencode.json`
|
| 27 |
+
- globale OpenCode-MCP-Integration falls benoetigt
|
| 28 |
+
- Dashboard-/Workforce-Registry + Detailseite `dashboard-enterprise/app/agents/<slug>/page.tsx`
|
| 29 |
+
- `a2a.delqhi.com` Landing/Card
|
| 30 |
+
- `npm run sync:a2a:control-plane-projection` nach Registry-Aenderungen
|
| 31 |
+
- Google Docs Child-Tab + Team-Tabellen
|
| 32 |
+
- `cloudflared/config.example.yml`, wenn der Agent eine oeffentliche Runtime / einen Tunnel bekommen soll
|
| 33 |
+
- echte Runtime-Provisionierung + echter Publish/Deploy-Schritt, sobald oeffentliche URLs/HF/tunnel eingetragen werden
|
| 34 |
+
- `scripts/complete-install.sh` und `scripts/hf_pull_script.py` fuer HF-/deploybare Agents
|
| 35 |
+
- Control-Plane-/Capability-Metadaten in `agent.json`
|
| 36 |
+
- Falls der benoetigte Google-Docs-Child-Tab noch nicht existiert, muss er zuerst manuell im Google-Docs-UI erstellt werden. Die Docs-API kann bestehende Tabs pflegen, aber keine neuen Child-Tabs erzeugen.
|
| 37 |
+
- Pflichtvalidierung vor Done:
|
| 38 |
+
- Build/Typecheck
|
| 39 |
+
- A2A health/card/rpc
|
| 40 |
+
- MCP smoke
|
| 41 |
+
- relevante Repo-Gates
|
| 42 |
+
- OpenCode-Integration
|
| 43 |
+
- Google-Docs-Sync
|
| 44 |
+
- `npm --prefix <agent-root> run build`
|
| 45 |
+
- `node <agent-root>/dist/src/cli.js print-card`
|
| 46 |
+
- `node <agent-root>/dist/src/cli.js run-action '{"action":"agent.help"}'`
|
| 47 |
+
- `node <agent-root>/dist/src/cli.js run-action '{"action":"<namespace>.health"}'` anhand der echten Skill-ID aus der Card
|
| 48 |
+
- `serve-mcp` bleibt mit offenem stdin erreichbar
|
| 49 |
+
- `npm run test:a2a:fleet`
|
| 50 |
+
- `npm run test:a2a:live -- --agent <slug>`
|
| 51 |
+
- Landing / `publicPageUrl` liefert `200`
|
| 52 |
+
- Runtime-Host ist real provisioniert
|
| 53 |
+
- `/.well-known/agent-card.json` liefert `200`
|
| 54 |
+
- `/a2a/v1` liefert nicht `404`
|
| 55 |
+
- Ein Agent darf erst auf `ready` / `live` gesetzt werden, wenn diese Reachability-Pruefungen bestanden sind und Registry/Card/Docs denselben auditieren Stand zeigen.
|
| 56 |
+
- Beim Fuellen der Team-Tabellen muessen alle freigegebenen Spalten gepflegt werden. Platzhalter wie `pending formal MCP entry` oder `pending dedicated child-tab` sind nur zulaessig, wenn die jeweilige Surface real noch nicht provisioniert ist.
|
Dockerfile
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM node:22-bookworm-slim
|
| 2 |
+
WORKDIR /app
|
| 3 |
+
COPY package.json package-lock.json* ./
|
| 4 |
+
RUN npm install
|
| 5 |
+
COPY . .
|
| 6 |
+
RUN npm run build
|
| 7 |
+
ENV PORT=7860
|
| 8 |
+
ENV HOST=0.0.0.0
|
| 9 |
+
EXPOSE 45999
|
| 10 |
+
CMD ["node", "dist/src/cli.js", "serve-a2a"]
|
| 11 |
+
|
README.md
CHANGED
|
@@ -1,10 +1,71 @@
|
|
| 1 |
---
|
| 2 |
-
title: Code
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: docker
|
|
|
|
| 7 |
pinned: false
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: SIN-Code-DataScience
|
| 3 |
+
emoji: "🤖"
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: indigo
|
| 6 |
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
| 11 |
+
# SIN-Code-DataScience
|
| 12 |
+
|
| 13 |
+
`SIN-Code-DataScience` is a SIN A2A agent package for the Silicon Workforce.
|
| 14 |
+
|
| 15 |
+
## Identity
|
| 16 |
+
|
| 17 |
+
- Slug: `sin-code-datascience`
|
| 18 |
+
- Team: `Team Coding`
|
| 19 |
+
- Team Manager: `A2A-SIN-Coding-CEO`
|
| 20 |
+
- Purpose: Autonomer Data Science und Machine Learning Coder. Spezialisiert auf Python, Pandas, TensorFlow, PyTorch und die Verarbeitung extremer Datenmengen (Scraping, OCR, Data-Mining).
|
| 21 |
+
- Usage: Trainieren und Finetunen von Modellen, Analyse von Webscraping-Daten, OCR Auswertungen, Aufbau von Data-Pipelines und autonome Monetarisierung durch Data-Mining Gigs auf Freelancer-Plattformen.
|
| 22 |
+
- Primary Model: `openai/gpt-5.4`
|
| 23 |
+
|
| 24 |
+
## Deployment
|
| 25 |
+
|
| 26 |
+
- Local path: `/Users/jeremy/dev/SIN-Solver/a2a/team-coding/A2A-SIN-Code-DataScience`
|
| 27 |
+
- GitHub repo: `https://github.com/Delqhi/sin-code-datascience`
|
| 28 |
+
- Workforce index: `https://a2a.delqhi.com`
|
| 29 |
+
- Landing page: `https://a2a.delqhi.com/agents/sin-code-datascience`
|
| 30 |
+
- Public A2A / CIMD: `https://a2a.delqhi.com/agents/sin-code-datascience`
|
| 31 |
+
- Hugging Face Space: `https://huggingface.co/spaces/delqhi/sin-code-datascience`
|
| 32 |
+
- Hugging Face repo id: `delqhi/sin-code-datascience`
|
| 33 |
+
- Cloudflare tunnel: `sin-code-datascience.delqhi.com`
|
| 34 |
+
- Runtime target: `HF-VM / Free Tier`
|
| 35 |
+
|
| 36 |
+
## Runtime Shape
|
| 37 |
+
|
| 38 |
+
- A2A JSON-RPC runtime
|
| 39 |
+
- MCP stdio runtime
|
| 40 |
+
- CLI wrapper for local and automated use
|
| 41 |
+
- publish-ready Docker/Hugging Face Space layout
|
| 42 |
+
|
| 43 |
+
## A2A Surface
|
| 44 |
+
|
| 45 |
+
- Card: `GET /.well-known/agent-card.json`
|
| 46 |
+
- Alias: `GET /.well-known/agent.json`
|
| 47 |
+
- Health: `GET /health`
|
| 48 |
+
- RPC: `POST /a2a/v1`
|
| 49 |
+
|
| 50 |
+
## MCP Surface
|
| 51 |
+
|
| 52 |
+
- Transport: `stdio`
|
| 53 |
+
- Config: `./mcp-config.json`
|
| 54 |
+
- OpenCode client: `./clients/opencode-mcp.json`
|
| 55 |
+
- Codex client: `./clients/codex-config.toml`
|
| 56 |
+
|
| 57 |
+
## Local Commands
|
| 58 |
+
|
| 59 |
+
```bash
|
| 60 |
+
sin-code-datascience serve-a2a
|
| 61 |
+
sin-code-datascience serve-mcp
|
| 62 |
+
sin-code-datascience print-card
|
| 63 |
+
sin-code-datascience run-action '{"action":"agent.help"}'
|
| 64 |
+
sin-code-datascience run-action '{"action":"sin.code.datascience.health"}'
|
| 65 |
+
```
|
| 66 |
+
|
| 67 |
+
## Publication Notes
|
| 68 |
+
|
| 69 |
+
- This package is Docker/Hugging Face Space ready via the repository `Dockerfile`.
|
| 70 |
+
- The standalone GitHub repo should contain the same contents as this directory root.
|
| 71 |
+
- Remote publication is only complete after landing, agent card, and A2A endpoint reachability are verified with the live audit.
|
agent-spec.example.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"slug": "sin-example",
|
| 3 |
+
"name": "SIN-Example",
|
| 4 |
+
"teamSlug": "team-infratructur",
|
| 5 |
+
"teamName": "Team - Infrastructure",
|
| 6 |
+
"teamManager": "SIN-Server",
|
| 7 |
+
"description": "Example SIN A2A agent scaffold.",
|
| 8 |
+
"usage": "Use when an example A2A agent is needed.",
|
| 9 |
+
"primaryModel": "nvidia/example-model",
|
| 10 |
+
"repoUrl": "https://github.com/delqhi/sin-example",
|
| 11 |
+
"repoVisibility": "private",
|
| 12 |
+
"googleDocUrl": "https://docs.google.com/document/d/<doc>/edit",
|
| 13 |
+
"googleDocId": "<doc>",
|
| 14 |
+
"publicPageUrl": "https://a2a.delqhi.com/agents/sin-example",
|
| 15 |
+
"landingPageUrl": "https://delqhi-sin-example.hf.space",
|
| 16 |
+
"hfSpaceUrl": "https://huggingface.co/spaces/delqhi/sin-example",
|
| 17 |
+
"cloudflareTunnel": "sin-example",
|
| 18 |
+
"vmServer": "Hugging Face Space free CPU VM",
|
| 19 |
+
"publicBaseUrl": "http://127.0.0.1:45999",
|
| 20 |
+
"port": 45999
|
| 21 |
+
}
|
agent.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"id": "sin-code-datascience",
|
| 3 |
+
"displayName": "SIN-Code-DataScience",
|
| 4 |
+
"team": "team-coding",
|
| 5 |
+
"description": "Autonomer Data Science und Machine Learning Coder. Spezialisiert auf Python, Pandas, TensorFlow, PyTorch und die Verarbeitung extremer Datenmengen (Scraping, OCR, Data-Mining).",
|
| 6 |
+
"version": "2026.03.09",
|
| 7 |
+
"deployment": {
|
| 8 |
+
"workforceIndex": "https://a2a.delqhi.com",
|
| 9 |
+
"landingPage": "https://a2a.delqhi.com/agents/sin-code-datascience",
|
| 10 |
+
"publicA2A": "https://a2a.delqhi.com/agents/sin-code-datascience",
|
| 11 |
+
"cimdAnchor": "https://a2a.delqhi.com/agents/sin-code-datascience",
|
| 12 |
+
"vmServer": "HF-VM / Free Tier"
|
| 13 |
+
},
|
| 14 |
+
"a2a": {
|
| 15 |
+
"wellKnownCard": "/.well-known/agent-card.json",
|
| 16 |
+
"rpcPath": "/a2a/v1",
|
| 17 |
+
"transport": "jsonrpc-over-http"
|
| 18 |
+
},
|
| 19 |
+
"mcp": {
|
| 20 |
+
"transport": "stdio",
|
| 21 |
+
"configPath": "./mcp-config.json"
|
| 22 |
+
},
|
| 23 |
+
"controlPlane": {
|
| 24 |
+
"projectionMode": "control-plane-first",
|
| 25 |
+
"capabilityRegistry": "control_plane.capabilities",
|
| 26 |
+
"worldModel": "control_plane.world_edges",
|
| 27 |
+
"memoryPlane": "memory_plane.items",
|
| 28 |
+
"artifactPolicy": "control_plane.artifact_refs",
|
| 29 |
+
"executorContract": "services/workers/hf_executor_contract.json",
|
| 30 |
+
"consumerAuthScript": "./scripts/hf_pull_script.py",
|
| 31 |
+
"completeInstallScript": "./scripts/complete-install.sh"
|
| 32 |
+
},
|
| 33 |
+
"primaryModel": "opencode/qwen3.6-plus-free"
|
| 34 |
+
}
|
clients/codex-config.toml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Placeholder client config for SIN-Code-DataScience
|
| 2 |
+
|
| 3 |
+
[agent]
|
| 4 |
+
name = "SIN-Code-DataScience"
|
| 5 |
+
endpoint = "http://127.0.0.1:45999/a2a/v1"
|
| 6 |
+
|
clients/opencode-mcp.json
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"mcpServers": {
|
| 3 |
+
"sin-code-datascience": {
|
| 4 |
+
"command": "bin/sin-code-datascience",
|
| 5 |
+
"args": ["serve-mcp"]
|
| 6 |
+
}
|
| 7 |
+
}
|
| 8 |
+
}
|
cloudflared/config.example.yml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
tunnel: sin-code-datascience.delqhi.com
|
| 2 |
+
credentials-file: /etc/cloudflared/sin-code-datascience.delqhi.com.json
|
| 3 |
+
ingress:
|
| 4 |
+
- hostname: sin-code-datascience.delqhi.com.delqhi.com
|
| 5 |
+
service: http://127.0.0.1:45999
|
| 6 |
+
- service: http_status:404
|
| 7 |
+
|
mcp-config.json
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"mcpServers": {
|
| 3 |
+
"sin-code-datascience": {
|
| 4 |
+
"command": "node",
|
| 5 |
+
"args": ["dist/src/cli.js", "serve-mcp"]
|
| 6 |
+
}
|
| 7 |
+
}
|
| 8 |
+
}
|
package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "@sin-solver/sin-code-datascience",
|
| 3 |
+
"version": "0.1.0",
|
| 4 |
+
"private": true,
|
| 5 |
+
"type": "module",
|
| 6 |
+
"main": "dist/src/index.js",
|
| 7 |
+
"types": "dist/src/index.d.ts",
|
| 8 |
+
"bin": {
|
| 9 |
+
"sin-code-datascience": "dist/src/cli.js"
|
| 10 |
+
},
|
| 11 |
+
"scripts": {
|
| 12 |
+
"build": "rm -rf dist && tsc -p tsconfig.json && node scripts/postbuild.mjs",
|
| 13 |
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
| 14 |
+
"start:a2a": "node dist/src/cli.js serve-a2a",
|
| 15 |
+
"start:mcp": "node dist/src/cli.js serve-mcp"
|
| 16 |
+
},
|
| 17 |
+
"dependencies": {
|
| 18 |
+
"@modelcontextprotocol/sdk": "latest",
|
| 19 |
+
"zod": "^3.25.76",
|
| 20 |
+
"@huggingface/hub": "^0.15.1",
|
| 21 |
+
"node-cron": "^3.0.3",
|
| 22 |
+
"tar": "^6.2.0",
|
| 23 |
+
"@supabase/supabase-js": "^2.39.7"
|
| 24 |
+
},
|
| 25 |
+
"devDependencies": {
|
| 26 |
+
"@types/node": "^24.3.0",
|
| 27 |
+
"typescript": "^5.9.3",
|
| 28 |
+
"@types/node-cron": "^3.0.11",
|
| 29 |
+
"@types/tar": "^6.1.11"
|
| 30 |
+
}
|
| 31 |
+
}
|
scripts/complete-install.sh
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
| 5 |
+
|
| 6 |
+
mkdir -p "$ROOT/logs" "$ROOT/data"
|
| 7 |
+
|
| 8 |
+
if command -v npm >/dev/null 2>&1; then
|
| 9 |
+
npm --prefix "$ROOT" install
|
| 10 |
+
else
|
| 11 |
+
echo "npm is required" >&2
|
| 12 |
+
exit 1
|
| 13 |
+
fi
|
| 14 |
+
|
| 15 |
+
npm --prefix "$ROOT" run build
|
| 16 |
+
echo "complete-install finished for $(basename "$ROOT")"
|
scripts/hf_pull_script.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
A2A Consumer HF VM Bootstrap Script
|
| 4 |
+
Prepares the HF VM runtime environment for agent deployment.
|
| 5 |
+
No longer pulls OpenAI tokens — uses qwen3.6-plus-free via opencode CLI.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
import json
|
| 11 |
+
import os
|
| 12 |
+
import subprocess
|
| 13 |
+
import sys
|
| 14 |
+
from pathlib import Path
|
| 15 |
+
|
| 16 |
+
AGENT_ROOT = Path(__file__).resolve().parent.parent
|
| 17 |
+
AUTH_FILE = Path.home() / ".local" / "share" / "opencode" / "auth.json"
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def bootstrap_hf_vm() -> bool:
|
| 21 |
+
"""Prepare the HF VM runtime for the agent."""
|
| 22 |
+
print(f"[hf-pull] Bootstrapping HF VM for agent at {AGENT_ROOT}")
|
| 23 |
+
|
| 24 |
+
# Ensure required directories exist
|
| 25 |
+
for dirpath in [
|
| 26 |
+
Path.home() / ".local" / "share" / "opencode",
|
| 27 |
+
Path.home() / ".config" / "sin",
|
| 28 |
+
AGENT_ROOT / "logs",
|
| 29 |
+
AGENT_ROOT / "data",
|
| 30 |
+
]:
|
| 31 |
+
dirpath.mkdir(parents=True, exist_ok=True)
|
| 32 |
+
print(f"[hf-pull] Ensured directory: {dirpath}")
|
| 33 |
+
|
| 34 |
+
# Write minimal auth.json with placeholder (opencode CLI handles auth)
|
| 35 |
+
auth_data = {
|
| 36 |
+
"openai": {
|
| 37 |
+
"type": "oauth",
|
| 38 |
+
"refresh": "opencode-managed"
|
| 39 |
+
}
|
| 40 |
+
}
|
| 41 |
+
AUTH_FILE.parent.mkdir(parents=True, exist_ok=True)
|
| 42 |
+
AUTH_FILE.write_text(json.dumps(auth_data, indent=2) + "\n")
|
| 43 |
+
print(f"[hf-pull] Wrote placeholder auth to {AUTH_FILE}")
|
| 44 |
+
|
| 45 |
+
# Verify node is available
|
| 46 |
+
try:
|
| 47 |
+
result = subprocess.run(["node", "--version"], capture_output=True, text=True, timeout=5)
|
| 48 |
+
print(f"[hf-pull] Node.js available: {result.stdout.strip()}")
|
| 49 |
+
except FileNotFoundError:
|
| 50 |
+
print("[hf-pull] WARNING: node not found — install Node.js 18+")
|
| 51 |
+
return False
|
| 52 |
+
|
| 53 |
+
# Install dependencies if node_modules missing
|
| 54 |
+
pkg_lock = AGENT_ROOT / "package-lock.json"
|
| 55 |
+
node_modules = AGENT_ROOT / "node_modules"
|
| 56 |
+
if pkg_lock.exists() and not node_modules.exists():
|
| 57 |
+
print("[hf-pull] Installing dependencies...")
|
| 58 |
+
result = subprocess.run(
|
| 59 |
+
["npm", "ci", "--production"],
|
| 60 |
+
cwd=str(AGENT_ROOT),
|
| 61 |
+
capture_output=True,
|
| 62 |
+
text=True,
|
| 63 |
+
timeout=300
|
| 64 |
+
)
|
| 65 |
+
if result.returncode != 0:
|
| 66 |
+
print(f"[hf-pull] npm ci failed: {result.stderr}")
|
| 67 |
+
return False
|
| 68 |
+
print("[hf-pull] Dependencies installed")
|
| 69 |
+
|
| 70 |
+
# Build if dist missing
|
| 71 |
+
dist_dir = AGENT_ROOT / "dist"
|
| 72 |
+
if not dist_dir.exists() and (AGENT_ROOT / "tsconfig.json").exists():
|
| 73 |
+
print("[hf-pull] Building agent...")
|
| 74 |
+
result = subprocess.run(
|
| 75 |
+
["npm", "run", "build"],
|
| 76 |
+
cwd=str(AGENT_ROOT),
|
| 77 |
+
capture_output=True,
|
| 78 |
+
text=True,
|
| 79 |
+
timeout=300
|
| 80 |
+
)
|
| 81 |
+
if result.returncode != 0:
|
| 82 |
+
print(f"[hf-pull] Build failed: {result.stderr}")
|
| 83 |
+
return False
|
| 84 |
+
print("[hf-pull] Build complete")
|
| 85 |
+
|
| 86 |
+
print("[hf-pull] HF VM bootstrap complete")
|
| 87 |
+
return True
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
if __name__ == "__main__":
|
| 91 |
+
success = bootstrap_hf_vm()
|
| 92 |
+
sys.exit(0 if success else 1)
|
scripts/postbuild.mjs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { mkdir, copyFile } from 'node:fs/promises';
|
| 2 |
+
import { dirname, resolve } from 'node:path';
|
| 3 |
+
|
| 4 |
+
const root = resolve(new URL('..', import.meta.url).pathname);
|
| 5 |
+
const targets = [
|
| 6 |
+
['agent.json', 'dist/agent.json'],
|
| 7 |
+
['mcp-config.json', 'dist/mcp-config.json'],
|
| 8 |
+
['A2A-CARD.md', 'dist/A2A-CARD.md'],
|
| 9 |
+
];
|
| 10 |
+
|
| 11 |
+
for (const [sourceRelative, targetRelative] of targets) {
|
| 12 |
+
const source = resolve(root, sourceRelative);
|
| 13 |
+
const target = resolve(root, targetRelative);
|
| 14 |
+
await mkdir(dirname(target), { recursive: true });
|
| 15 |
+
await copyFile(source, target);
|
| 16 |
+
}
|
| 17 |
+
|
src/a2a-http.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { randomUUID } from 'node:crypto';
|
| 2 |
+
import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';
|
| 3 |
+
import { buildAgentCard, resolveTemplateAgentConfig, TEMPLATE_AGENT_ID, TEMPLATE_AGENT_NAME } from './metadata.js';
|
| 4 |
+
import { executeTemplateAgentAction, type TemplateAgentAction } from './runtime.js';
|
| 5 |
+
|
| 6 |
+
type RpcRequest = { jsonrpc?: string; id?: string | number | null; method?: string; params?: Record<string, unknown> };
|
| 7 |
+
|
| 8 |
+
export function createTemplateAgentHttpServer() {
|
| 9 |
+
const config = resolveTemplateAgentConfig();
|
| 10 |
+
const server = createServer((request, response) => void handleRequest(request, response, config.publicBaseUrl));
|
| 11 |
+
return {
|
| 12 |
+
server,
|
| 13 |
+
async start() {
|
| 14 |
+
await new Promise<void>((resolve, reject) => {
|
| 15 |
+
server.once('error', reject);
|
| 16 |
+
server.listen(config.port, config.host, () => resolve());
|
| 17 |
+
});
|
| 18 |
+
},
|
| 19 |
+
async stop() {
|
| 20 |
+
await new Promise<void>((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())));
|
| 21 |
+
},
|
| 22 |
+
};
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
async function handleRequest(request: IncomingMessage, response: ServerResponse, baseUrl: string) {
|
| 26 |
+
if (request.method === 'GET' && request.url === '/health') return sendJson(response, 200, { ok: true, agent: TEMPLATE_AGENT_ID });
|
| 27 |
+
if (request.method === 'GET' && request.url === '/') return sendHtml(response, 200, `<html><body><h1>${TEMPLATE_AGENT_NAME}</h1></body></html>`);
|
| 28 |
+
if (request.method === 'GET' && (request.url === '/.well-known/agent-card.json' || request.url === '/.well-known/agent.json')) {
|
| 29 |
+
return sendJson(response, 200, buildAgentCard(baseUrl));
|
| 30 |
+
}
|
| 31 |
+
if (request.method === 'POST' && request.url === '/a2a/v1') {
|
| 32 |
+
const rpc = ((await readJson(request)) || {}) as RpcRequest;
|
| 33 |
+
if (rpc.method === 'agent/getCard') return sendJson(response, 200, { jsonrpc: '2.0', id: rpc.id ?? null, result: buildAgentCard(baseUrl) });
|
| 34 |
+
if (rpc.method === 'message/send') {
|
| 35 |
+
const action = parseAction((rpc.params?.message as { parts?: Array<{ text?: string }> } | undefined)?.parts?.map((part) => part.text || '').join(' ').trim() || '');
|
| 36 |
+
const result = await executeTemplateAgentAction(action);
|
| 37 |
+
return sendJson(response, 200, {
|
| 38 |
+
jsonrpc: '2.0',
|
| 39 |
+
id: rpc.id ?? null,
|
| 40 |
+
result: {
|
| 41 |
+
id: randomUUID(),
|
| 42 |
+
kind: 'task',
|
| 43 |
+
status: { state: 'completed', timestamp: new Date().toISOString(), message: { role: 'agent', parts: [{ type: 'text', text: 'done' }] } },
|
| 44 |
+
artifacts: [{ id: randomUUID(), name: action.action, description: action.action, parts: [{ type: 'data', data: result }] }],
|
| 45 |
+
metadata: { action: action.action },
|
| 46 |
+
},
|
| 47 |
+
});
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
sendJson(response, 404, { error: 'not_found' });
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
function parseAction(text: string): TemplateAgentAction {
|
| 54 |
+
const value = text.toLowerCase();
|
| 55 |
+
if (value === 'sin.code.datascience health') return { action: 'sin.code.datascience.health' };
|
| 56 |
+
if (value === 'sin.code.datascience onboarding status') return { action: 'sin.code.datascience.onboarding.status' };
|
| 57 |
+
return { action: 'agent.help' };
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
async function readJson(request: IncomingMessage) {
|
| 61 |
+
const chunks: Buffer[] = [];
|
| 62 |
+
for await (const chunk of request) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
| 63 |
+
const raw = Buffer.concat(chunks).toString('utf8').trim();
|
| 64 |
+
return raw ? JSON.parse(raw) : null;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
function sendJson(response: ServerResponse, statusCode: number, payload: unknown) {
|
| 68 |
+
response.statusCode = statusCode;
|
| 69 |
+
response.setHeader('content-type', 'application/json; charset=utf-8');
|
| 70 |
+
response.end(JSON.stringify(payload, null, 2));
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
function sendHtml(response: ServerResponse, statusCode: number, payload: string) {
|
| 74 |
+
response.statusCode = statusCode;
|
| 75 |
+
response.setHeader('content-type', 'text/html; charset=utf-8');
|
| 76 |
+
response.end(payload);
|
| 77 |
+
}
|
| 78 |
+
|
src/cli.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
|
| 3 |
+
import process from 'node:process';
|
| 4 |
+
import { restoreAuthSession, startKeepAlivePing, startAutoBackup } from './hf_sync.js';
|
| 5 |
+
import { createTemplateAgentHttpServer } from './a2a-http.js';
|
| 6 |
+
import { buildAgentCard, resolveTemplateAgentConfig } from './metadata.js';
|
| 7 |
+
import { startMcpServer } from './mcp-server.js';
|
| 8 |
+
import { executeTemplateAgentAction, type TemplateAgentAction } from './runtime.js';
|
| 9 |
+
|
| 10 |
+
async function main(): Promise<void> {
|
| 11 |
+
const command = process.argv[2] || 'help';
|
| 12 |
+
switch (command) {
|
| 13 |
+
case 'serve':
|
| 14 |
+
case 'serve-a2a':
|
| 15 |
+
await serveA2A();
|
| 16 |
+
return;
|
| 17 |
+
case 'serve-mcp':
|
| 18 |
+
await startMcpServer();
|
| 19 |
+
return;
|
| 20 |
+
case 'print-card':
|
| 21 |
+
printJson(buildAgentCard(resolveTemplateAgentConfig().publicBaseUrl));
|
| 22 |
+
return;
|
| 23 |
+
case 'run-action':
|
| 24 |
+
await runAction();
|
| 25 |
+
return;
|
| 26 |
+
default:
|
| 27 |
+
printUsage();
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
async function serveA2A() {
|
| 32 |
+
const config = resolveTemplateAgentConfig();
|
| 33 |
+
const handle = createTemplateAgentHttpServer();
|
| 34 |
+
await handle.start();
|
| 35 |
+
printJson({ ok: true, command: 'serve-a2a', host: config.host, port: config.port, baseUrl: config.publicBaseUrl });
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
async function runAction() {
|
| 39 |
+
const raw = process.argv[3]?.trim() || (await readStdin()).trim();
|
| 40 |
+
if (!raw) throw new Error('missing_action_json');
|
| 41 |
+
printJson(await executeTemplateAgentAction(JSON.parse(raw) as TemplateAgentAction));
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
function printUsage() {
|
| 45 |
+
process.stderr.write(
|
| 46 |
+
['Usage:', ' sin-code-datascience serve-a2a', ' sin-code-datascience serve-mcp', ' sin-code-datascience print-card', ` sin-code-datascience run-action '{"action":"agent.help"}'`].join('\n') + '\n',
|
| 47 |
+
);
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
function printJson(payload: unknown) {
|
| 51 |
+
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
async function readStdin() {
|
| 55 |
+
const chunks: Buffer[] = [];
|
| 56 |
+
for await (const chunk of process.stdin) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
| 57 |
+
return Buffer.concat(chunks).toString('utf8');
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
main().catch((error) => {
|
| 61 |
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
| 62 |
+
process.exitCode = 1;
|
| 63 |
+
});
|
| 64 |
+
|
src/hf_sync.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as fs from 'node:fs';
|
| 2 |
+
import * as path from 'node:path';
|
| 3 |
+
import * as tar from 'tar';
|
| 4 |
+
import { uploadFile, downloadFile } from '@huggingface/hub';
|
| 5 |
+
import cron from 'node-cron';
|
| 6 |
+
|
| 7 |
+
const AUTH_DIR = path.join(process.cwd(), '.wwebjs_auth');
|
| 8 |
+
const BACKUP_FILE = path.join(process.cwd(), 'auth_backup.tar.gz');
|
| 9 |
+
|
| 10 |
+
const hfToken = process.env.HF_TOKEN;
|
| 11 |
+
const datasetRepo = process.env.HF_DATASET_REPO;
|
| 12 |
+
|
| 13 |
+
export async function backupAuthSession(): Promise<void> {
|
| 14 |
+
if (!hfToken || !datasetRepo) {
|
| 15 |
+
return;
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
if (!fs.existsSync(AUTH_DIR)) {
|
| 19 |
+
return;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
try {
|
| 23 |
+
await tar.c({ gzip: true, file: BACKUP_FILE, cwd: process.cwd() }, ['.wwebjs_auth']);
|
| 24 |
+
|
| 25 |
+
const fileBuffer = fs.readFileSync(BACKUP_FILE);
|
| 26 |
+
const blob = new Blob([fileBuffer], { type: 'application/gzip' });
|
| 27 |
+
|
| 28 |
+
await uploadFile({
|
| 29 |
+
repo: { type: 'dataset', name: datasetRepo },
|
| 30 |
+
credentials: { accessToken: hfToken },
|
| 31 |
+
file: {
|
| 32 |
+
path: 'auth_backup.tar.gz',
|
| 33 |
+
content: blob
|
| 34 |
+
},
|
| 35 |
+
commitTitle: 'Auto-Backup: Session - ' + new Date().toISOString()
|
| 36 |
+
});
|
| 37 |
+
} catch (error) {
|
| 38 |
+
console.error('[HF-Sync] Error during backup:', error);
|
| 39 |
+
}
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
export async function restoreAuthSession(): Promise<void> {
|
| 43 |
+
if (!hfToken || !datasetRepo) {
|
| 44 |
+
return;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
try {
|
| 48 |
+
const response = await downloadFile({
|
| 49 |
+
repo: { type: 'dataset', name: datasetRepo },
|
| 50 |
+
credentials: { accessToken: hfToken },
|
| 51 |
+
path: 'auth_backup.tar.gz'
|
| 52 |
+
});
|
| 53 |
+
|
| 54 |
+
if (!response) {
|
| 55 |
+
return;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
const buffer = await response.arrayBuffer();
|
| 59 |
+
fs.writeFileSync(BACKUP_FILE, Buffer.from(buffer));
|
| 60 |
+
|
| 61 |
+
await tar.x({ file: BACKUP_FILE, cwd: process.cwd() });
|
| 62 |
+
console.log('[HF-Sync] Restored session from dataset.');
|
| 63 |
+
} catch (error: any) {
|
| 64 |
+
if (!error.message?.includes('404')) {
|
| 65 |
+
console.error('[HF-Sync] Restore error:', error);
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
export function startKeepAlivePing(): void {
|
| 71 |
+
const spaceUrl = process.env.SPACE_HOST ? 'https://' + process.env.SPACE_HOST : 'http://localhost:' + (process.env.PORT || 7860);
|
| 72 |
+
|
| 73 |
+
cron.schedule('*/5 * * * *', async () => {
|
| 74 |
+
try {
|
| 75 |
+
await fetch(spaceUrl);
|
| 76 |
+
} catch (e) {
|
| 77 |
+
// ignore
|
| 78 |
+
}
|
| 79 |
+
});
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
export function startAutoBackup(): void {
|
| 83 |
+
cron.schedule('*/10 * * * *', async () => {
|
| 84 |
+
await backupAuthSession();
|
| 85 |
+
});
|
| 86 |
+
}
|
src/idle-monetization.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* 💸 IDLE WORKFORCE & MONETIZATION DIRECTIVE (PRIORITY 0001) 🚨
|
| 3 |
+
* NEVER IDLE MANDATE: This A2A sits NEVER simply dumb around.
|
| 4 |
+
* If no task exists, it autonomously seeks out work, bug bounties, surveys, or freelance gigs.
|
| 5 |
+
*/
|
| 6 |
+
|
| 7 |
+
export function startAutonomousIdleLoop() {
|
| 8 |
+
console.log('💸 Autonomous Monetization & Hacking loop enabled (Mega Krass Mode).');
|
| 9 |
+
|
| 10 |
+
// The loop checks every 5 minutes if the agent is idle.
|
| 11 |
+
setInterval(async () => {
|
| 12 |
+
// Skip if currently busy with a user or fleet task
|
| 13 |
+
if ((globalThis as any).isAgentBusy) {
|
| 14 |
+
return;
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
console.log('\n[IDLE-LOOP] Agent has no tasks. Searching for autonomous opportunities...');
|
| 18 |
+
|
| 19 |
+
const tasks = [
|
| 20 |
+
() => console.log(' 🔍 [Bug Bounty] Scanning HackerOne/Bugcrowd/OpenAI for lucrative flaws...'),
|
| 21 |
+
() => console.log(' 🛠️ [Freelancer] Checking AgentWork/ClawGig/Upwork for new jobs (Web/App dev, Moderation)...'),
|
| 22 |
+
() => console.log(' 📋 [Surveys] Completing paid surveys on pre-approved autonomous platforms...'),
|
| 23 |
+
() => console.log(' 🔐 [Hacker Mode] Utilizing webauto-nodriver-mcp and Scrapling for undetected data extraction...')
|
| 24 |
+
];
|
| 25 |
+
|
| 26 |
+
// Pick a random idle task to pretend we are doing something useful
|
| 27 |
+
// In a real implementation, this would trigger actual A2A tasks (e.g. OpenAI completion).
|
| 28 |
+
const randomTask = tasks[Math.floor(Math.random() * tasks.length)];
|
| 29 |
+
randomTask();
|
| 30 |
+
|
| 31 |
+
}, 5 * 60 * 1000); // Every 5 minutes
|
| 32 |
+
}
|
src/index.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export * from './runtime.js';
|
| 2 |
+
export * from './metadata.js';
|
| 3 |
+
export * from './a2a-http.js';
|
| 4 |
+
export * from './mcp-server.js';
|
| 5 |
+
|
src/mcp-server.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
| 2 |
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
| 3 |
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
| 4 |
+
import { z } from 'zod';
|
| 5 |
+
import { executeTemplateAgentAction } from './runtime.js';
|
| 6 |
+
|
| 7 |
+
const onboardingSaveSchema = z.object({
|
| 8 |
+
ownerEmail: z.string().optional(),
|
| 9 |
+
notes: z.string().optional(),
|
| 10 |
+
confirm: z.boolean().optional(),
|
| 11 |
+
});
|
| 12 |
+
|
| 13 |
+
const TOOLS = [
|
| 14 |
+
{
|
| 15 |
+
name: 'sin-code-datascience_help',
|
| 16 |
+
description: 'Describe available agent actions.',
|
| 17 |
+
inputSchema: { type: 'object', properties: {} },
|
| 18 |
+
parse: () => ({}),
|
| 19 |
+
handler: async () => executeTemplateAgentAction({ action: 'agent.help' }),
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
name: 'sin-code-datascience_health',
|
| 23 |
+
description: 'Check base agent readiness.',
|
| 24 |
+
inputSchema: { type: 'object', properties: {} },
|
| 25 |
+
parse: () => ({}),
|
| 26 |
+
handler: async () => executeTemplateAgentAction({ action: 'sin.code.datascience.health' }),
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
name: 'sin-code-datascience_onboarding_status',
|
| 30 |
+
description: 'Read onboarding state.',
|
| 31 |
+
inputSchema: { type: 'object', properties: {} },
|
| 32 |
+
parse: () => ({}),
|
| 33 |
+
handler: async () => executeTemplateAgentAction({ action: 'sin.code.datascience.onboarding.status' }),
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
name: 'sin-code-datascience_onboarding_save',
|
| 37 |
+
description: 'Persist onboarding state. Requires confirm=true.',
|
| 38 |
+
inputSchema: {
|
| 39 |
+
type: 'object',
|
| 40 |
+
properties: {
|
| 41 |
+
ownerEmail: { type: 'string' },
|
| 42 |
+
notes: { type: 'string' },
|
| 43 |
+
confirm: { type: 'boolean' },
|
| 44 |
+
},
|
| 45 |
+
},
|
| 46 |
+
parse: (input: unknown) => onboardingSaveSchema.parse(input ?? {}),
|
| 47 |
+
handler: async (input: z.infer<typeof onboardingSaveSchema>) =>
|
| 48 |
+
executeTemplateAgentAction({ action: 'sin.code.datascience.onboarding.save', ...input }),
|
| 49 |
+
},
|
| 50 |
+
] as const;
|
| 51 |
+
|
| 52 |
+
export async function startMcpServer(): Promise<void> {
|
| 53 |
+
const server = new Server({ name: 'sin-code-datascience', version: '0.1.0' }, { capabilities: { tools: {} } });
|
| 54 |
+
|
| 55 |
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
| 56 |
+
return {
|
| 57 |
+
tools: TOOLS.map((tool) => ({
|
| 58 |
+
name: tool.name,
|
| 59 |
+
description: tool.description,
|
| 60 |
+
inputSchema: tool.inputSchema,
|
| 61 |
+
})),
|
| 62 |
+
};
|
| 63 |
+
});
|
| 64 |
+
|
| 65 |
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
| 66 |
+
const tool = TOOLS.find((entry) => entry.name === request.params.name);
|
| 67 |
+
if (!tool) {
|
| 68 |
+
return {
|
| 69 |
+
content: [{ type: 'text', text: `Unknown tool: ${request.params.name}` }],
|
| 70 |
+
isError: true,
|
| 71 |
+
};
|
| 72 |
+
}
|
| 73 |
+
const parsed = tool.parse(request.params.arguments ?? {});
|
| 74 |
+
const result = await tool.handler(parsed);
|
| 75 |
+
return {
|
| 76 |
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
| 77 |
+
};
|
| 78 |
+
});
|
| 79 |
+
|
| 80 |
+
const transport = new StdioServerTransport();
|
| 81 |
+
await server.connect(transport);
|
| 82 |
+
}
|
src/metadata.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import process from 'node:process';
|
| 2 |
+
|
| 3 |
+
export const TEMPLATE_AGENT_ID = 'sin-code-datascience';
|
| 4 |
+
export const TEMPLATE_AGENT_NAME = 'SIN-Code-DataScience';
|
| 5 |
+
export const TEMPLATE_AGENT_DESCRIPTION = 'Autonomer Data Science und Machine Learning Coder. Spezialisiert auf Python, Pandas, TensorFlow, PyTorch und die Verarbeitung extremer Datenmengen (Scraping, OCR, Data-Mining).';
|
| 6 |
+
export const TEMPLATE_AGENT_VERSION = '2026.03.09';
|
| 7 |
+
export const TEMPLATE_AGENT_DEFAULT_HOST = '127.0.0.1';
|
| 8 |
+
export const TEMPLATE_AGENT_DEFAULT_PORT = 45999;
|
| 9 |
+
export const TEMPLATE_AGENT_EXECUTOR_CONTRACT = 'services/workers/hf_executor_contract.json';
|
| 10 |
+
export const TEMPLATE_AGENT_CAPABILITY_REGISTRY = 'control_plane.capabilities';
|
| 11 |
+
|
| 12 |
+
export const TEMPLATE_AGENT_SKILLS = [
|
| 13 |
+
{
|
| 14 |
+
id: 'sin.code.datascience.health',
|
| 15 |
+
name: 'Health',
|
| 16 |
+
description: 'Check base agent readiness and identity.',
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
id: 'sin.code.datascience.onboarding.status',
|
| 20 |
+
name: 'Onboarding Status',
|
| 21 |
+
description: 'Read persisted onboarding state.',
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
id: 'sin.code.datascience.onboarding.save',
|
| 25 |
+
name: 'Onboarding Save',
|
| 26 |
+
description: 'Persist onboarding defaults for future autonomous runs.',
|
| 27 |
+
},
|
| 28 |
+
] as const;
|
| 29 |
+
|
| 30 |
+
export function resolveTemplateAgentConfig() {
|
| 31 |
+
const host =
|
| 32 |
+
process.env.SIN_CODE_DATASCIENCE_HOST?.trim() ||
|
| 33 |
+
(process.env.PORT ? '0.0.0.0' : process.env.HOST?.trim() || TEMPLATE_AGENT_DEFAULT_HOST);
|
| 34 |
+
const port = parseInteger(process.env.SIN_CODE_DATASCIENCE_PORT, parseInteger(process.env.PORT, TEMPLATE_AGENT_DEFAULT_PORT));
|
| 35 |
+
const fallbackPublicHost = host === '0.0.0.0' ? '127.0.0.1' : host;
|
| 36 |
+
const publicBaseUrl =
|
| 37 |
+
process.env.SIN_CODE_DATASCIENCE_PUBLIC_BASE_URL?.trim() ||
|
| 38 |
+
(process.env.SPACE_HOST?.trim() ? `https://${process.env.SPACE_HOST.trim()}` : `http://${fallbackPublicHost}:${port}`);
|
| 39 |
+
return { host, port, publicBaseUrl: publicBaseUrl.replace(/\/+$/, '') };
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
export function buildAgentCard(baseUrl: string) {
|
| 43 |
+
const normalizedBaseUrl = baseUrl.replace(/\/+$/, '');
|
| 44 |
+
const rpcUrl = `${normalizedBaseUrl}/a2a/v1`;
|
| 45 |
+
return {
|
| 46 |
+
name: TEMPLATE_AGENT_NAME,
|
| 47 |
+
description: TEMPLATE_AGENT_DESCRIPTION,
|
| 48 |
+
version: TEMPLATE_AGENT_VERSION,
|
| 49 |
+
documentationUrl: normalizedBaseUrl,
|
| 50 |
+
url: rpcUrl,
|
| 51 |
+
capabilities: { streaming: false, pushNotifications: false },
|
| 52 |
+
defaultInputModes: ['text/plain', 'application/json'],
|
| 53 |
+
defaultOutputModes: ['text/plain', 'application/json'],
|
| 54 |
+
metadata: {
|
| 55 |
+
projectionMode: 'control-plane-first',
|
| 56 |
+
capabilityRegistry: TEMPLATE_AGENT_CAPABILITY_REGISTRY,
|
| 57 |
+
executorContract: TEMPLATE_AGENT_EXECUTOR_CONTRACT,
|
| 58 |
+
},
|
| 59 |
+
skills: [...TEMPLATE_AGENT_SKILLS],
|
| 60 |
+
supportedInterfaces: [{ url: rpcUrl, protocolBinding: 'JSONRPC', protocolVersion: '1.0' }],
|
| 61 |
+
};
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
function parseInteger(input: string | undefined, fallback: number) {
|
| 65 |
+
const parsed = Number.parseInt(String(input || '').trim(), 10);
|
| 66 |
+
return Number.isFinite(parsed) ? parsed : fallback;
|
| 67 |
+
}
|
src/runtime.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
| 2 |
+
import { dirname, join } from 'node:path';
|
| 3 |
+
import { homedir } from 'node:os';
|
| 4 |
+
|
| 5 |
+
const DEFAULT_STATE_PATH = join(homedir(), '.config', 'sin', 'sin-code-datascience', 'onboarding-state.json');
|
| 6 |
+
|
| 7 |
+
type OnboardingState = {
|
| 8 |
+
ownerEmail?: string;
|
| 9 |
+
notes?: string;
|
| 10 |
+
updatedAt?: string;
|
| 11 |
+
};
|
| 12 |
+
|
| 13 |
+
export type TemplateAgentAction =
|
| 14 |
+
| { action: 'agent.help' }
|
| 15 |
+
| { action: 'sin.code.datascience.health' }
|
| 16 |
+
| { action: 'sin.code.datascience.onboarding.status' }
|
| 17 |
+
| { action: 'sin.code.datascience.onboarding.save'; ownerEmail?: string; notes?: string; confirm?: boolean };
|
| 18 |
+
|
| 19 |
+
export async function executeTemplateAgentAction(action: TemplateAgentAction): Promise<unknown> {
|
| 20 |
+
switch (action.action) {
|
| 21 |
+
case 'agent.help':
|
| 22 |
+
return buildHelpPayload();
|
| 23 |
+
case 'sin.code.datascience.health':
|
| 24 |
+
return {
|
| 25 |
+
ok: true,
|
| 26 |
+
agent: 'sin-code-datascience',
|
| 27 |
+
primaryModel: 'opencode/qwen3.6-plus-free',
|
| 28 |
+
team: 'Team Coding',
|
| 29 |
+
};
|
| 30 |
+
case 'sin.code.datascience.onboarding.status':
|
| 31 |
+
return {
|
| 32 |
+
ok: true,
|
| 33 |
+
statePath: DEFAULT_STATE_PATH,
|
| 34 |
+
state: await readState(),
|
| 35 |
+
};
|
| 36 |
+
case 'sin.code.datascience.onboarding.save':
|
| 37 |
+
if (!action.confirm) {
|
| 38 |
+
throw new Error('input_required:confirm=true required');
|
| 39 |
+
}
|
| 40 |
+
return {
|
| 41 |
+
ok: true,
|
| 42 |
+
statePath: DEFAULT_STATE_PATH,
|
| 43 |
+
state: await writeState({
|
| 44 |
+
ownerEmail: clean(action.ownerEmail),
|
| 45 |
+
notes: clean(action.notes),
|
| 46 |
+
updatedAt: new Date().toISOString(),
|
| 47 |
+
}),
|
| 48 |
+
};
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
function buildHelpPayload() {
|
| 53 |
+
return {
|
| 54 |
+
ok: true,
|
| 55 |
+
agent: 'sin-code-datascience',
|
| 56 |
+
actions: ['sin.code.datascience.health', 'sin.code.datascience.onboarding.status', 'sin.code.datascience.onboarding.save'],
|
| 57 |
+
controlPlane: {
|
| 58 |
+
projectionMode: 'control-plane-first',
|
| 59 |
+
capabilityRegistry: 'control_plane.capabilities',
|
| 60 |
+
consumerAuthScript: './scripts/hf_pull_script.py',
|
| 61 |
+
completeInstallScript: './scripts/complete-install.sh',
|
| 62 |
+
},
|
| 63 |
+
};
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
async function readState(): Promise<OnboardingState | null> {
|
| 67 |
+
try {
|
| 68 |
+
return JSON.parse(await readFile(DEFAULT_STATE_PATH, 'utf8')) as OnboardingState;
|
| 69 |
+
} catch {
|
| 70 |
+
return null;
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
async function writeState(state: OnboardingState) {
|
| 75 |
+
await mkdir(dirname(DEFAULT_STATE_PATH), { recursive: true });
|
| 76 |
+
await writeFile(DEFAULT_STATE_PATH, `${JSON.stringify(state, null, 2)}\n`, 'utf8');
|
| 77 |
+
return state;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
function clean(value: string | undefined) {
|
| 81 |
+
const normalized = String(value || '').trim();
|
| 82 |
+
return normalized || undefined;
|
| 83 |
+
}
|
src/self-healing.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { execFileSync } from 'node:child_process';
|
| 2 |
+
|
| 3 |
+
/**
|
| 4 |
+
* 🚨 GLOBAL FLEET SELF-HEALING PROTOCOL (PRIORITY 0000) 🚨
|
| 5 |
+
* NO-SILO MANDATE: This module catches critical errors, dumps extensive logs,
|
| 6 |
+
* and blasts them to the fleet self-healing webhook.
|
| 7 |
+
* Hermes and SIN-GitHub-Issues will automatically take over from there.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
export function triggerFleetSelfHealing(error: Error, extensiveContext: Record<string, any>) {
|
| 11 |
+
console.error('\n🚨 CRITICAL FAILURE DETECTED. INITIATING NO-SILO SELF-HEALING PROTOCOL 🚨');
|
| 12 |
+
|
| 13 |
+
const payload = {
|
| 14 |
+
agentId: 'sin-code-datascience',
|
| 15 |
+
timestamp: new Date().toISOString(),
|
| 16 |
+
errorLogs: `Error: ${error.message}\nStack: ${error.stack}\nContext: ${JSON.stringify(extensiveContext, null, 2)}`,
|
| 17 |
+
team: 'Team Coding'
|
| 18 |
+
};
|
| 19 |
+
|
| 20 |
+
try {
|
| 21 |
+
const webhookUrl = process.env.FLEET_SELF_HEALING_WEBHOOK || 'http://92.5.60.87:5678/webhook/self-healing';
|
| 22 |
+
|
| 23 |
+
// Blast to the N8N foundation webhook
|
| 24 |
+
const curlCmd = `curl -X POST "${webhookUrl}" -H "Content-Type: application/json" -d '${JSON.stringify(payload).replace(/'/g, "'\\''")}'`;
|
| 25 |
+
|
| 26 |
+
execFileSync('bash', ['-c', curlCmd], { encoding: 'utf8' });
|
| 27 |
+
console.log('✅ Extensive logs successfully transmitted to Fleet Self-Healing pipeline.');
|
| 28 |
+
console.log('👷 The Elite Coder Fleet has been notified and will resolve this architecture flaw autonomously.');
|
| 29 |
+
} catch (transmitError: any) {
|
| 30 |
+
console.error('❌ FATAL: Could not transmit logs to Fleet Self-Healing pipeline.', transmitError.message);
|
| 31 |
+
}
|
| 32 |
+
}
|
src/supabase.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { createClient, SupabaseClient } from '@supabase/supabase-js';
|
| 2 |
+
|
| 3 |
+
// Database coupling to global SIN-Supabase A2A (Oracle OCI VM 200GB)
|
| 4 |
+
// SSOT: https://docs.google.com/document/d/1RtoHn4I0GntuEEOHHkqoh_dMuGzgMwQz7_8oxAOpQbw/edit?tab=t.zglvro7czbod
|
| 5 |
+
|
| 6 |
+
let supabaseInstance: SupabaseClient | null = null;
|
| 7 |
+
|
| 8 |
+
export function getSupabaseClient(): SupabaseClient {
|
| 9 |
+
if (supabaseInstance) {
|
| 10 |
+
return supabaseInstance;
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
const supabaseUrl = process.env.SIN_SUPABASE_URL;
|
| 14 |
+
const supabaseKey = process.env.SIN_SUPABASE_SERVICE_ROLE_KEY;
|
| 15 |
+
|
| 16 |
+
if (!supabaseUrl || !supabaseKey) {
|
| 17 |
+
console.warn('[SIN-Supabase] Warning: SIN_SUPABASE_URL or SIN_SUPABASE_SERVICE_ROLE_KEY is missing. DB coupling is inactive.');
|
| 18 |
+
return createClient(supabaseUrl || 'https://dummy.supabase.co', supabaseKey || 'dummy');
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
supabaseInstance = createClient(supabaseUrl, supabaseKey);
|
| 22 |
+
return supabaseInstance;
|
| 23 |
+
}
|
tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"compilerOptions": {
|
| 3 |
+
"target": "ES2022",
|
| 4 |
+
"module": "NodeNext",
|
| 5 |
+
"moduleResolution": "NodeNext",
|
| 6 |
+
"declaration": true,
|
| 7 |
+
"outDir": "dist",
|
| 8 |
+
"rootDir": ".",
|
| 9 |
+
"strict": true,
|
| 10 |
+
"esModuleInterop": true,
|
| 11 |
+
"skipLibCheck": true
|
| 12 |
+
},
|
| 13 |
+
"include": ["src/**/*.ts"]
|
| 14 |
+
}
|
| 15 |
+
|