docs: keep only workflow testing and process guidance
This commit is contained in:
parent
88582fe050
commit
2447230ca7
6 changed files with 49 additions and 1731 deletions
|
|
@ -1,6 +1,8 @@
|
|||
# Documentation Index (Priority-Based)
|
||||
|
||||
This repo keeps documentation intentionally small to reduce stale AI context.
|
||||
Only workflow/testing/process documentation should be maintained.
|
||||
Project-intro and architecture explanation docs are intentionally omitted.
|
||||
|
||||
## P0 (Keep Fresh)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,433 +0,0 @@
|
|||
<mxfile host="app.diagrams.net" modified="2026-02-15T00:00:00.000Z" agent="Claude" version="24.0.0" type="device">
|
||||
<diagram id="multica-architecture" name="Architecture Overview">
|
||||
<mxGraphModel dx="2400" dy="1600" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="3300" pageHeight="2400" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- ==================== TITLE ==================== -->
|
||||
<mxCell id="title" value="Super Multica — Architecture & Module Map" style="text;html=1;fontSize=24;fontStyle=1;align=center;verticalAlign=middle;whiteSpace=wrap;fontFamily=Helvetica;fontColor=#1a1a2e;" vertex="1" parent="1">
|
||||
<mxGeometry x="400" y="20" width="800" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- ==================== APPS LAYER ==================== -->
|
||||
<mxCell id="apps-group" value="Apps Layer" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0f4ff;strokeColor=#4361ee;strokeWidth=2;fontSize=14;fontStyle=1;verticalAlign=top;align=left;spacingLeft=10;spacingTop=5;arcSize=8;fontColor=#4361ee;dashed=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="80" width="1530" height="260" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Desktop App -->
|
||||
<mxCell id="desktop" value="Desktop App" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#4361ee;strokeColor=#3a56d4;fontSize=13;fontStyle=1;fontColor=#ffffff;arcSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="120" width="340" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="desktop-main" value="Main Process (Electron)
├ IPC Handlers (14+ modules)
├ System Tray
└ Auto Updater" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e8edff;strokeColor=#4361ee;fontSize=11;align=left;spacingLeft=10;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="170" width="165" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="desktop-renderer" value="Renderer (React 19)
├ Zustand Stores (9)
├ Chat Interface
└ Settings / Dashboard" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e8edff;strokeColor=#4361ee;fontSize=11;align=left;spacingLeft=10;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="245" y="170" width="165" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="desktop-ipc-arrow" value="" style="endArrow=classic;startArrow=classic;html=1;strokeColor=#4361ee;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="desktop-main" target="desktop-renderer">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="desktop-ipc-label" value="IPC" style="edgeLabel;html=1;align=center;verticalAlign=middle;fontSize=9;fontColor=#4361ee;fontStyle=1;" vertex="1" connectable="0" parent="desktop-ipc-arrow">
|
||||
<mxGeometry x="-0.1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="desktop-tag" value="@multica/desktop · Electron + Vite" style="text;html=1;fontSize=9;fontColor=#888;align=center;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="255" width="340" height="16" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Gateway -->
|
||||
<mxCell id="gateway" value="Gateway" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#7209b7;strokeColor=#5a078f;fontSize=13;fontStyle=1;fontColor=#ffffff;arcSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="440" y="120" width="240" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="gateway-detail" value="NestJS WebSocket Server
├ Socket.io (port 3000)
├ Device Registration
├ RPC Message Routing
├ Heartbeat (25s ping)
└ Telegram Channel" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f3e8ff;strokeColor=#7209b7;fontSize=11;align=left;spacingLeft=10;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="440" y="170" width="240" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="gateway-tag" value="@multica/gateway · NestJS + Socket.io" style="text;html=1;fontSize=9;fontColor=#888;align=center;" vertex="1" parent="1">
|
||||
<mxGeometry x="440" y="275" width="240" height="16" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Web App -->
|
||||
<mxCell id="web" value="Web App" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f72585;strokeColor=#d01f6e;fontSize=13;fontStyle=1;fontColor=#ffffff;arcSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="710" y="120" width="200" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="web-detail" value="Next.js 16 + React 19
├ App Router
├ Gateway Client (SDK)
└ Zustand Store" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe0ef;strokeColor=#f72585;fontSize=11;align=left;spacingLeft=10;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="710" y="170" width="200" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="web-tag" value="@multica/web · Next.js 16" style="text;html=1;fontSize=9;fontColor=#888;align=center;" vertex="1" parent="1">
|
||||
<mxGeometry x="710" y="250" width="200" height="16" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- CLI -->
|
||||
<mxCell id="cli" value="CLI" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ff6d00;strokeColor=#e06200;fontSize=13;fontStyle=1;fontColor=#ffffff;arcSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="940" y="120" width="200" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cli-detail" value="Interactive & Non-interactive
├ run / chat / session
├ profile / skills / tools
├ credentials / cron / dev
└ Autocomplete + Help" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff3e0;strokeColor=#ff6d00;fontSize=11;align=left;spacingLeft=10;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="940" y="170" width="200" height="85" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cli-tag" value="@multica/cli · Node.js" style="text;html=1;fontSize=9;fontColor=#888;align=center;" vertex="1" parent="1">
|
||||
<mxGeometry x="940" y="260" width="200" height="16" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Mobile -->
|
||||
<mxCell id="mobile" value="Mobile" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#06d6a0;strokeColor=#05b88a;fontSize=13;fontStyle=1;fontColor=#ffffff;arcSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="1170" y="120" width="170" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mobile-detail" value="React Native
└ (In Development)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e0fff5;strokeColor=#06d6a0;fontSize=11;align=left;spacingLeft=10;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="1170" y="170" width="170" height="45" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mobile-tag" value="@multica/mobile · React Native" style="text;html=1;fontSize=9;fontColor=#888;align=center;" vertex="1" parent="1">
|
||||
<mxGeometry x="1170" y="220" width="170" height="16" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Server -->
|
||||
<mxCell id="server" value="Server" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#adb5bd;strokeColor=#868e96;fontSize=13;fontStyle=1;fontColor=#ffffff;arcSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="1370" y="120" width="170" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="server-detail" value="NestJS REST API
└ Port 4000 (Legacy)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f1f3f5;strokeColor=#adb5bd;fontSize=11;align=left;spacingLeft=10;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="1370" y="170" width="170" height="45" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- ==================== CONNECTION ARROWS (Apps → Core) ==================== -->
|
||||
<!-- Desktop → Hub (embedded) -->
|
||||
<mxCell id="arrow-desktop-hub" value="" style="endArrow=classic;html=1;strokeColor=#4361ee;strokeWidth=2;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.15;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="desktop-main" target="core-group">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="arrow-desktop-hub-label" value="Embedded Hub" style="edgeLabel;html=1;align=center;verticalAlign=middle;fontSize=10;fontColor=#4361ee;fontStyle=1;labelBackgroundColor=#ffffff;" vertex="1" connectable="0" parent="arrow-desktop-hub">
|
||||
<mxGeometry x="0.2" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Web → Gateway (Socket.io) -->
|
||||
<mxCell id="arrow-web-gateway" value="" style="endArrow=classic;startArrow=classic;html=1;strokeColor=#f72585;strokeWidth=2;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.3;entryDx=0;entryDy=0;" edge="1" parent="1" source="web-detail" target="gateway-detail">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="arrow-web-gateway-label" value="Socket.io" style="edgeLabel;html=1;align=center;verticalAlign=middle;fontSize=10;fontColor=#f72585;fontStyle=1;labelBackgroundColor=#ffffff;" vertex="1" connectable="0" parent="arrow-web-gateway">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Gateway → Hub -->
|
||||
<mxCell id="arrow-gateway-hub" value="" style="endArrow=classic;html=1;strokeColor=#7209b7;strokeWidth=2;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.35;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="gateway-detail" target="core-group">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="arrow-gateway-hub-label" value="RPC" style="edgeLabel;html=1;align=center;verticalAlign=middle;fontSize=10;fontColor=#7209b7;fontStyle=1;labelBackgroundColor=#ffffff;" vertex="1" connectable="0" parent="arrow-gateway-hub">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- CLI → Core -->
|
||||
<mxCell id="arrow-cli-core" value="" style="endArrow=classic;html=1;strokeColor=#ff6d00;strokeWidth=2;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.85;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="cli-detail" target="core-group">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="arrow-cli-core-label" value="Direct Import" style="edgeLabel;html=1;align=center;verticalAlign=middle;fontSize=10;fontColor=#ff6d00;fontStyle=1;labelBackgroundColor=#ffffff;" vertex="1" connectable="0" parent="arrow-cli-core">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- ==================== CORE PACKAGE ==================== -->
|
||||
<mxCell id="core-group" value="@multica/core — Core Engine" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff8f0;strokeColor=#e76f51;strokeWidth=2;fontSize=14;fontStyle=1;verticalAlign=top;align=left;spacingLeft=10;spacingTop=5;arcSize=6;fontColor=#e76f51;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="370" width="1530" height="590" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Hub -->
|
||||
<mxCell id="hub" value="Hub" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e76f51;strokeColor=#d05a3e;fontSize=13;fontStyle=1;fontColor=#ffffff;arcSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="410" width="350" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="hub-detail" value="Multi-Agent Coordination

├ Agent Manager — create / delete / list agents
├ RPC Dispatcher — 12+ handlers for remote ops
├ Gateway Client — Socket.io ↔ remote devices
├ Agent Store — persistent agent list (JSON)
├ Device Store — device metadata
├ Auth Store — Hub authentication tokens
├ Exec Approval Manager — tool approval flow
├ Message Aggregator — message coalescing
└ Block Chunker — large payload chunking" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fef0eb;strokeColor=#e76f51;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="455" width="350" height="180" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Agent Engine -->
|
||||
<mxCell id="agent-engine" value="Agent Engine" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#264653;strokeColor=#1d3740;fontSize=13;fontStyle=1;fontColor=#ffffff;arcSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="450" y="410" width="530" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="agent-runner" value="Agent Runner
├ Agent (sync orchestrator)
├ AsyncAgent (event-driven)
├ SyncAgent (blocking)
├ pi-agent-core integration
└ Run Log (JSONL debug)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e8f4f0;strokeColor=#264653;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="450" y="455" width="165" height="105" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="agent-session" value="Session Manager
├ JSONL Persistence
├ Compaction (3 modes)
│ ├ Count-based
│ ├ Token-aware
│ └ Summary (LLM)
├ File Repair
├ Write Lock
└ UUIDv7 IDs" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e8f4f0;strokeColor=#264653;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="625" y="455" width="165" height="150" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="agent-ctx" value="Context Window Guard
├ Token Estimation
├ Budget Enforcement
├ LLM Summarization
├ Tool Result Pruning
└ Compaction Metadata" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e8f4f0;strokeColor=#264653;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="800" y="455" width="175" height="105" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- System Prompt -->
|
||||
<mxCell id="agent-prompt" value="System Prompt Builder
├ Dynamic Construction
├ Sections (tools, skills,
│ memory, channels)
├ Constitution (safety)
└ Runtime Info" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e8f4f0;strokeColor=#264653;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="450" y="570" width="165" height="105" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Providers -->
|
||||
<mxCell id="providers" value="LLM Providers" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#264653;strokeColor=#1d3740;fontSize=13;fontStyle=1;fontColor=#ffffff;arcSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="1010" y="410" width="230" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="providers-detail" value="Multi-Provider Registry

├ Anthropic (Claude)
├ OpenAI (GPT / o-series)
├ Google (Gemini)
├ DeepSeek
├ Kimi (Moonshot)
├ Groq
├ Mistral
├ Together
├ OpenRouter
└ xAI (Grok)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e8f4f0;strokeColor=#264653;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="1010" y="455" width="145" height="185" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Auth Profiles -->
|
||||
<mxCell id="auth-profiles" value="Auth Profiles
├ Multi-credential store
├ Rotation on error
├ Cooldown mechanism
├ OAuth support
└ API key resolution" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e8f4f0;strokeColor=#264653;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="1165" y="455" width="155" height="105" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Tools -->
|
||||
<mxCell id="tools" value="Tools" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#2a9d8f;strokeColor=#218778;fontSize=13;fontStyle=1;fontColor=#ffffff;arcSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="650" width="350" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="tools-detail" value="Tool Registry & Execution

├ Exec (shell commands)
│ ├ Safety Classification
│ ├ Approval Callbacks
│ └ Command Allowlist
├ Web Fetch & Web Search
│ ├ SSRF Protection
│ └ Response Cache
├ File Glob
├ Memory Search
├ Sessions Spawn / List (subagents)
├ Cron Tool
├ Data / Finance APIs
├ Send File & Image Resize
├ Process Management
└ Policy Engine
 ├ Allow / Deny Lists
 ├ Provider Overrides
 └ Group Patterns (web:*, fs:*)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e8f8f5;strokeColor=#2a9d8f;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="695" width="350" height="245" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Skills System -->
|
||||
<mxCell id="skills-sys" value="Skills System" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e9c46a;strokeColor=#d4a843;fontSize=13;fontStyle=1;fontColor=#333;arcSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="450" y="690" width="170" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="skills-detail" value="Modular Skill Loader
├ YAML Frontmatter
├ Eligibility Filtering
│ (OS, binaries, configs)
├ Hot-Reload Watcher
├ GitHub Install
└ OpenClaw Compatible" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fdf6e3;strokeColor=#e9c46a;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="450" y="735" width="170" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Profile System -->
|
||||
<mxCell id="profile-sys" value="Profile System" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e9c46a;strokeColor=#d4a843;fontSize=13;fontStyle=1;fontColor=#333;arcSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="640" y="690" width="170" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="profile-detail" value="Agent Identity & Config
├ Soul (personality)
├ User info
├ Workspace context
├ Memory (long-term)
├ Heartbeat prompt
└ Config (YAML)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fdf6e3;strokeColor=#e9c46a;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="640" y="735" width="170" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Subagent System -->
|
||||
<mxCell id="subagent-sys" value="Subagent System" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e9c46a;strokeColor=#d4a843;fontSize=13;fontStyle=1;fontColor=#333;arcSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="840" y="690" width="180" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="subagent-detail" value="Child Agent Orchestration
├ Registry (lifecycle)
├ JSONL Persistence
├ Result Announcement
├ Coalesced Batching
├ Command Queue
└ Lane-based Concurrency" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fdf6e3;strokeColor=#e9c46a;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="840" y="735" width="180" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Cron System -->
|
||||
<mxCell id="cron-sys" value="Cron" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e9c46a;strokeColor=#d4a843;fontSize=13;fontStyle=1;fontColor=#333;arcSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="1050" y="690" width="130" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cron-detail" value="Scheduled Tasks
├ Cron Expressions
├ Job Execution
└ JSONL Storage" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fdf6e3;strokeColor=#e9c46a;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="1050" y="735" width="130" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Heartbeat -->
|
||||
<mxCell id="heartbeat-sys" value="Heartbeat" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e9c46a;strokeColor=#d4a843;fontSize=13;fontStyle=1;fontColor=#333;arcSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="1200" y="690" width="130" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="heartbeat-detail" value="Always-On Agent
├ Periodic Runner
├ Wake-from-sleep
└ System Events" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fdf6e3;strokeColor=#e9c46a;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="1200" y="735" width="130" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Channels -->
|
||||
<mxCell id="channels-sys" value="Channels" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e9c46a;strokeColor=#d4a843;fontSize=13;fontStyle=1;fontColor=#333;arcSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="1350" y="690" width="190" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="channels-detail" value="Messaging Integrations
├ Channel Manager
├ Plugin Registry
├ Inbound Debouncer
└ Telegram (via Gateway)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fdf6e3;strokeColor=#e9c46a;fontSize=11;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="1350" y="735" width="190" height="90" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Media -->
|
||||
<mxCell id="media-sys" value="Media" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e9c46a;strokeColor=#d4a843;fontSize=11;fontStyle=1;fontColor=#333;arcSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="1350" y="835" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="media-detail" value="Image / Video / Audio
├ describe-image (LLM)
├ describe-video (frames)
└ transcribe (Whisper)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fdf6e3;strokeColor=#e9c46a;fontSize=10;align=left;spacingLeft=10;arcSize=6;fontColor=#333;verticalAlign=top;spacingTop=4;" vertex="1" parent="1">
|
||||
<mxGeometry x="1350" y="870" width="190" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Hub → Agent Engine arrow -->
|
||||
<mxCell id="hub-agent-arrow" value="" style="endArrow=classic;startArrow=classic;html=1;strokeColor=#264653;strokeWidth=1.5;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="hub" target="agent-engine">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="hub-agent-label" value="manages" style="edgeLabel;html=1;align=center;verticalAlign=middle;fontSize=9;fontColor=#264653;fontStyle=2;" vertex="1" connectable="0" parent="hub-agent-arrow">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- ==================== SHARED PACKAGES ==================== -->
|
||||
<mxCell id="shared-group" value="Shared Packages" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0fff4;strokeColor=#38b000;strokeWidth=2;fontSize=14;fontStyle=1;verticalAlign=top;align=left;spacingLeft=10;spacingTop=5;arcSize=6;fontColor=#38b000;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="990" width="1080" height="130" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="pkg-sdk" value="SDK
@multica/sdk
Gateway Client
Socket.io" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d4edda;strokeColor=#38b000;fontSize=11;align=center;arcSize=8;fontColor=#333;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="60" y="1025" width="130" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="pkg-ui" value="UI
@multica/ui
Shadcn + Radix
Tailwind v4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d4edda;strokeColor=#38b000;fontSize=11;align=center;arcSize=8;fontColor=#333;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="210" y="1025" width="130" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="pkg-store" value="Store
@multica/store
Zustand" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d4edda;strokeColor=#38b000;fontSize=11;align=center;arcSize=8;fontColor=#333;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="1025" width="130" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="pkg-hooks" value="Hooks
@multica/hooks
React Hooks" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d4edda;strokeColor=#38b000;fontSize=11;align=center;arcSize=8;fontColor=#333;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="510" y="1025" width="130" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="pkg-types" value="Types
@multica/types
Shared TypeScript
Zero-dep" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d4edda;strokeColor=#38b000;fontSize=11;align=center;arcSize=8;fontColor=#333;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="1025" width="130" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="pkg-utils" value="Utils
@multica/utils
Paths, Retry
Errors, Device ID" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d4edda;strokeColor=#38b000;fontSize=11;align=center;arcSize=8;fontColor=#333;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="810" y="1025" width="140" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="pkg-utils2" value="Credentials
@multica/core
credentials.json5
skills.env.json5" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d4edda;strokeColor=#38b000;fontSize=11;align=center;arcSize=8;fontColor=#333;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="970" y="1025" width="130" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- ==================== SKILLS LAYER ==================== -->
|
||||
<mxCell id="skills-group" value="Bundled Skills" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fffde7;strokeColor=#f9a825;strokeWidth=2;fontSize=14;fontStyle=1;verticalAlign=top;align=left;spacingLeft=10;spacingTop=5;arcSize=6;fontColor=#f9a825;" vertex="1" parent="1">
|
||||
<mxGeometry x="1150" y="990" width="420" height="130" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="skill-pdf" value="pdf" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff9c4;strokeColor=#f9a825;fontSize=10;align=center;arcSize=10;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="1170" y="1025" width="55" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="skill-pptx" value="pptx" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff9c4;strokeColor=#f9a825;fontSize=10;align=center;arcSize=10;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="1235" y="1025" width="55" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="skill-docx" value="docx" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff9c4;strokeColor=#f9a825;fontSize=10;align=center;arcSize=10;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="1300" y="1025" width="55" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="skill-xlsx" value="xlsx" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff9c4;strokeColor=#f9a825;fontSize=10;align=center;arcSize=10;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="1365" y="1025" width="55" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="skill-whisper" value="whisper" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff9c4;strokeColor=#f9a825;fontSize=10;align=center;arcSize=10;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="1430" y="1025" width="55" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="skill-finance" value="finance-
research" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff9c4;strokeColor=#f9a825;fontSize=10;align=center;arcSize=10;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="1495" y="1025" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="skill-profile" value="profile-
setup" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff9c4;strokeColor=#f9a825;fontSize=10;align=center;arcSize=10;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="1170" y="1065" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="skill-creator" value="skill-
creator" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff9c4;strokeColor=#f9a825;fontSize=10;align=center;arcSize=10;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="1240" y="1065" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="skill-earnings" value="earnings-
analysis" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff9c4;strokeColor=#f9a825;fontSize=10;align=center;arcSize=10;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="1310" y="1065" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="skill-dcf" value="dcf-
valuation" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff9c4;strokeColor=#f9a825;fontSize=10;align=center;arcSize=10;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="1380" y="1065" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- ==================== DATA LAYER ==================== -->
|
||||
<mxCell id="data-group" value="Persistent Storage (~/.super-multica/)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666;strokeWidth=2;fontSize=14;fontStyle=1;verticalAlign=top;align=left;spacingLeft=10;spacingTop=5;arcSize=6;fontColor=#666;dashed=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="1150" width="1530" height="90" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="data-sessions" value="sessions/
{id}.jsonl" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eee;strokeColor=#999;fontSize=10;align=center;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="1185" width="100" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="data-profiles" value="agent-profiles/
{id}/*.md" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eee;strokeColor=#999;fontSize=10;align=center;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="190" y="1185" width="110" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="data-creds" value="credentials
.json5" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eee;strokeColor=#999;fontSize=10;align=center;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="1185" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="data-agents" value="agents
.json" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eee;strokeColor=#999;fontSize=10;align=center;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="430" y="1185" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="data-subagents" value="subagents
.jsonl" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eee;strokeColor=#999;fontSize=10;align=center;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="530" y="1185" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="data-cron" value="cron-jobs
.jsonl" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eee;strokeColor=#999;fontSize=10;align=center;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="640" y="1185" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="data-skills-env" value="skills.env
.json5" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eee;strokeColor=#999;fontSize=10;align=center;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="740" y="1185" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="data-runlog" value="run-log
.jsonl" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eee;strokeColor=#999;fontSize=10;align=center;arcSize=8;fontColor=#333;" vertex="1" parent="1">
|
||||
<mxGeometry x="840" y="1185" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- ==================== EXTERNAL DEPS ==================== -->
|
||||
<mxCell id="ext-group" value="External Dependencies" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fafafa;strokeColor=#aaa;strokeWidth=1;fontSize=12;fontStyle=1;verticalAlign=top;align=left;spacingLeft=10;spacingTop=5;arcSize=6;fontColor=#888;dashed=1;dashPattern=5 5;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="1270" width="1530" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ext-piagent" value="pi-agent-core" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8f8f8;strokeColor=#ccc;fontSize=10;align=center;arcSize=8;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="1295" width="100" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ext-electron" value="Electron 33+" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8f8f8;strokeColor=#ccc;fontSize=10;align=center;arcSize=8;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="185" y="1295" width="100" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ext-nestjs" value="NestJS 11" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8f8f8;strokeColor=#ccc;fontSize=10;align=center;arcSize=8;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="300" y="1295" width="80" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ext-nextjs" value="Next.js 16" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8f8f8;strokeColor=#ccc;fontSize=10;align=center;arcSize=8;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="395" y="1295" width="80" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ext-react" value="React 19" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8f8f8;strokeColor=#ccc;fontSize=10;align=center;arcSize=8;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="490" y="1295" width="70" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ext-socketio" value="Socket.io" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8f8f8;strokeColor=#ccc;fontSize=10;align=center;arcSize=8;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="575" y="1295" width="70" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ext-zustand" value="Zustand" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8f8f8;strokeColor=#ccc;fontSize=10;align=center;arcSize=8;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="1295" width="70" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ext-turborepo" value="Turborepo" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8f8f8;strokeColor=#ccc;fontSize=10;align=center;arcSize=8;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="745" y="1295" width="70" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ext-pnpm" value="pnpm 10" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8f8f8;strokeColor=#ccc;fontSize=10;align=center;arcSize=8;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="830" y="1295" width="70" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ext-vitest" value="Vitest" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8f8f8;strokeColor=#ccc;fontSize=10;align=center;arcSize=8;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="915" y="1295" width="60" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ext-tailwind" value="Tailwind v4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8f8f8;strokeColor=#ccc;fontSize=10;align=center;arcSize=8;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="990" y="1295" width="80" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ext-shadcn" value="Shadcn/UI" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8f8f8;strokeColor=#ccc;fontSize=10;align=center;arcSize=8;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="1085" y="1295" width="75" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- ==================== LEGEND ==================== -->
|
||||
<mxCell id="legend-box" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#ddd;strokeWidth=1;arcSize=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="1200" y="1270" width="370" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-title" value="Legend" style="text;html=1;fontSize=11;fontStyle=1;align=left;fontColor=#666;" vertex="1" parent="1">
|
||||
<mxGeometry x="1210" y="1273" width="50" height="16" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-1" value="" style="rounded=1;fillColor=#4361ee;strokeColor=none;fontSize=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="1210" y="1295" width="12" height="12" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-1t" value="Apps" style="text;fontSize=9;fontColor=#666;align=left;" vertex="1" parent="1">
|
||||
<mxGeometry x="1226" y="1293" width="35" height="16" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-2" value="" style="rounded=1;fillColor=#264653;strokeColor=none;fontSize=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="1270" y="1295" width="12" height="12" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-2t" value="Engine" style="text;fontSize=9;fontColor=#666;align=left;" vertex="1" parent="1">
|
||||
<mxGeometry x="1286" y="1293" width="40" height="16" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-3" value="" style="rounded=1;fillColor=#e76f51;strokeColor=none;fontSize=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="1335" y="1295" width="12" height="12" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-3t" value="Hub" style="text;fontSize=9;fontColor=#666;align=left;" vertex="1" parent="1">
|
||||
<mxGeometry x="1351" y="1293" width="30" height="16" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-4" value="" style="rounded=1;fillColor=#2a9d8f;strokeColor=none;fontSize=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="1390" y="1295" width="12" height="12" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-4t" value="Tools" style="text;fontSize=9;fontColor=#666;align=left;" vertex="1" parent="1">
|
||||
<mxGeometry x="1406" y="1293" width="35" height="16" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-5" value="" style="rounded=1;fillColor=#e9c46a;strokeColor=none;fontSize=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="1450" y="1295" width="12" height="12" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-5t" value="Systems" style="text;fontSize=9;fontColor=#666;align=left;" vertex="1" parent="1">
|
||||
<mxGeometry x="1466" y="1293" width="50" height="16" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-6" value="" style="rounded=1;fillColor=#38b000;strokeColor=none;fontSize=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="1520" y="1295" width="12" height="12" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="legend-6t" value="Shared" style="text;fontSize=9;fontColor=#666;align=left;" vertex="1" parent="1">
|
||||
<mxGeometry x="1536" y="1293" width="40" height="16" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
|
@ -1,347 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Super Multica 代码贡献统计</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #0b0d10;
|
||||
--panel: #14181d;
|
||||
--panel-2: #1a2027;
|
||||
--line: #2a3440;
|
||||
--text: #e8edf3;
|
||||
--muted: #98a7b7;
|
||||
--ok: #2fbf71;
|
||||
--danger: #ef4444;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial;
|
||||
background: radial-gradient(circle at 20% -10%, #1a2430 0%, #0b0d10 45%) fixed;
|
||||
color: var(--text);
|
||||
line-height: 1.4;
|
||||
}
|
||||
.wrap { max-width: 1200px; margin: 0 auto; padding: 24px; }
|
||||
h1 { margin: 0 0 8px; font-size: 28px; }
|
||||
.sub { color: var(--muted); margin-bottom: 20px; }
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.card {
|
||||
background: linear-gradient(180deg, var(--panel) 0%, var(--panel-2) 100%);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 10px;
|
||||
padding: 12px;
|
||||
}
|
||||
.k { color: var(--muted); font-size: 12px; margin-bottom: 8px; }
|
||||
.v { font-size: 24px; font-weight: 700; letter-spacing: 0.3px; }
|
||||
.section { margin-top: 14px; }
|
||||
.section h2 { margin: 0 0 10px; font-size: 16px; color: #d4dde7; }
|
||||
.panel {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
table { width: 100%; border-collapse: collapse; }
|
||||
th, td { padding: 9px 10px; border-bottom: 1px solid var(--line); font-size: 13px; }
|
||||
th { background: #11161c; text-align: left; color: #c5d0db; position: sticky; top: 0; }
|
||||
tr:last-child td { border-bottom: 0; }
|
||||
.num { text-align: right; font-variant-numeric: tabular-nums; }
|
||||
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
||||
.bar-wrap { background: #0f1318; border-radius: 999px; height: 8px; width: 180px; border: 1px solid #273241; }
|
||||
.bar { height: 100%; border-radius: 999px; background: linear-gradient(90deg, #3f7ef7, #58a6ff); }
|
||||
.ok { color: var(--ok); }
|
||||
.danger { color: var(--danger); }
|
||||
.foot { margin-top: 16px; color: var(--muted); font-size: 12px; }
|
||||
.scroll { max-height: 420px; overflow: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<h1>Super Multica 代码贡献统计</h1>
|
||||
<div class="sub" id="subtitle"></div>
|
||||
|
||||
<div class="grid" id="summary"></div>
|
||||
|
||||
<div class="section">
|
||||
<h2>代码量分布(按扩展名)</h2>
|
||||
<div class="panel scroll"><table id="extTable"></table></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>人员贡献(人工口径)</h2>
|
||||
<div class="panel scroll"><table id="authorTable"></table></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>每日贡献(人工口径)</h2>
|
||||
<div class="panel scroll"><table id="dayTable"></table></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>小时段贡献(人工口径)</h2>
|
||||
<div class="panel scroll"><table id="hourTable"></table></div>
|
||||
</div>
|
||||
|
||||
<div class="foot">数据来源:git log --numstat 与当前工作树文件统计。人工口径排除 checkpointer / dependabot。</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const RAW = {
|
||||
locTotals: String.raw`
|
||||
files 669
|
||||
lines 137510
|
||||
source_files 500
|
||||
source_lines 75894
|
||||
doc_files 47
|
||||
doc_lines 11701
|
||||
config_files 82
|
||||
config_lines 42562
|
||||
`,
|
||||
locByExt: String.raw`
|
||||
mjs 3 25
|
||||
js 8 357
|
||||
production 1 11
|
||||
dockerignore 1 45
|
||||
xml 5 15
|
||||
gitignore 4 126
|
||||
tsx 109 12206
|
||||
ts 337 55198
|
||||
json 38 1025
|
||||
yaml 2 21654
|
||||
yml 2 66
|
||||
css 4 412
|
||||
sh 5 259
|
||||
icns 1 1992
|
||||
example 2 115
|
||||
json5 1 87
|
||||
svg 1 75
|
||||
sql 1 17
|
||||
html 5 2363
|
||||
md 47 11701
|
||||
development 1 10
|
||||
npmrc 1 1
|
||||
xsd 39 19730
|
||||
ico 2 315
|
||||
[noext] 1 44
|
||||
cjs 1 19
|
||||
py 28 5055
|
||||
png 18 4154
|
||||
drawio 1 433
|
||||
`,
|
||||
authorHuman: String.raw`
|
||||
Jiayuan Zhang <forrestchang7@gmail.com> 233 110606 55597 55009 49.11% 27.67%
|
||||
Naiyuan Qing <145280634+NevilleQingNY@users.noreply.github.com> 253 61422 24246 37176 27.27% 30.05%
|
||||
Jiang Bohan <bhjiang@outlook.com> 203 30764 4944 25820 13.66% 24.11%
|
||||
yushen <ldnvnbl@gmail.com> 128 21171 2185 18986 9.40% 15.20%
|
||||
yushen <linyushen@proton.me> 25 1279 341 938 0.57% 2.97%
|
||||
`,
|
||||
dayHuman: String.raw`
|
||||
2026-01-28 4 3403 13 3390 14 17
|
||||
2026-01-29 2 9990 676 9314 16 16
|
||||
2026-01-30 173 39220 4907 34313 01 23
|
||||
2026-01-31 28 3353 1117 2236 01 21
|
||||
2026-02-01 17 4093 539 3554 02 23
|
||||
2026-02-02 42 3993 2331 1662 00 17
|
||||
2026-02-03 52 22784 6410 16374 02 21
|
||||
2026-02-04 64 8893 1733 7160 03 20
|
||||
2026-02-05 78 12776 5203 7573 02 22
|
||||
2026-02-06 42 6074 521 5553 12 22
|
||||
2026-02-09 44 4458 941 3517 07 19
|
||||
2026-02-10 50 9474 4410 5064 02 23
|
||||
2026-02-11 58 7069 3222 3847 00 20
|
||||
2026-02-12 60 79852 4003 75849 09 23
|
||||
2026-02-13 66 6194 1427 4767 01 23
|
||||
2026-02-14 30 1479 1049 430 00 23
|
||||
2026-02-15 32 2137 48811 -46674 00 04
|
||||
`,
|
||||
hourHuman: String.raw`
|
||||
00 18 1236 248 988
|
||||
01 32 5718 45407 -39689
|
||||
02 34 4449 2948 1501
|
||||
03 27 3861 3587 274
|
||||
04 24 4591 1047 3544
|
||||
05 7 2752 69 2683
|
||||
06 0 0 0 0
|
||||
07 7 809 54 755
|
||||
08 17 3605 2099 1506
|
||||
09 19 5612 1801 3811
|
||||
10 17 2907 1784 1123
|
||||
11 22 1673 530 1143
|
||||
12 12 1974 72 1902
|
||||
13 49 8470 1911 6559
|
||||
14 67 8581 2303 6278
|
||||
15 64 10866 2467 8399
|
||||
16 84 35691 6756 28935
|
||||
17 111 97435 7908 89527
|
||||
18 73 8936 2276 6660
|
||||
19 36 2716 723 1993
|
||||
20 22 3916 1223 2693
|
||||
21 24 2296 497 1799
|
||||
22 48 3545 1016 2529
|
||||
23 28 3603 587 3016
|
||||
`,
|
||||
dayPeak: String.raw`
|
||||
2026-01-28 16 1 2237 5
|
||||
2026-01-29 16 2 9990 676
|
||||
2026-01-30 13 16 4675 55
|
||||
2026-01-31 02 9 1277 144
|
||||
2026-02-01 23 7 3036 270
|
||||
2026-02-02 16 13 1218 280
|
||||
2026-02-03 16 7 14253 4890
|
||||
2026-02-04 17 10 2766 143
|
||||
2026-02-05 17 17 4345 1657
|
||||
2026-02-06 17 8 2300 120
|
||||
2026-02-09 19 3 1095 335
|
||||
2026-02-10 17 5 5778 3625
|
||||
2026-02-11 17 17 2520 1018
|
||||
2026-02-12 17 13 73452 132
|
||||
2026-02-13 12 7 1378 56
|
||||
2026-02-14 00 8 601 212
|
||||
2026-02-15 04 4 657 364
|
||||
`
|
||||
};
|
||||
|
||||
const fmt = (n) => Number(n).toLocaleString("en-US");
|
||||
const tsv = (txt) => txt.trim().split(/\n+/).map((line) => line.split("\t"));
|
||||
const toNum = (v) => Number(v || 0);
|
||||
|
||||
const locTotalsRows = tsv(RAW.locTotals);
|
||||
const locTotals = Object.fromEntries(locTotalsRows.map(([k, v]) => [k, toNum(v)]));
|
||||
|
||||
const extRows = tsv(RAW.locByExt).map(([ext, files, lines]) => ({
|
||||
ext,
|
||||
files: toNum(files),
|
||||
lines: toNum(lines),
|
||||
})).sort((a, b) => b.lines - a.lines);
|
||||
|
||||
const authors = tsv(RAW.authorHuman).map(([name, commits, add, del, net, addPct, commitPct]) => ({
|
||||
name,
|
||||
commits: toNum(commits),
|
||||
add: toNum(add),
|
||||
del: toNum(del),
|
||||
net: toNum(net),
|
||||
addPct,
|
||||
commitPct,
|
||||
})).sort((a, b) => b.add - a.add);
|
||||
|
||||
const dayPeaks = Object.fromEntries(tsv(RAW.dayPeak).map(([d, h, c, a, del]) => [d, {
|
||||
hour: h,
|
||||
commits: toNum(c),
|
||||
add: toNum(a),
|
||||
del: toNum(del),
|
||||
}]));
|
||||
|
||||
const days = tsv(RAW.dayHuman).map(([date, commits, add, del, net, startHour, endHour]) => ({
|
||||
date,
|
||||
commits: toNum(commits),
|
||||
add: toNum(add),
|
||||
del: toNum(del),
|
||||
net: toNum(net),
|
||||
startHour,
|
||||
endHour,
|
||||
peak: dayPeaks[date] || null,
|
||||
})).sort((a, b) => a.date.localeCompare(b.date));
|
||||
|
||||
const hours = tsv(RAW.hourHuman).map(([hour, commits, add, del, net]) => ({
|
||||
hour,
|
||||
commits: toNum(commits),
|
||||
add: toNum(add),
|
||||
del: toNum(del),
|
||||
net: toNum(net),
|
||||
})).sort((a, b) => a.hour.localeCompare(b.hour));
|
||||
|
||||
const totalHumanCommits = authors.reduce((sum, x) => sum + x.commits, 0);
|
||||
const totalHumanAdd = authors.reduce((sum, x) => sum + x.add, 0);
|
||||
const totalHumanDel = authors.reduce((sum, x) => sum + x.del, 0);
|
||||
const topHour = [...hours].sort((a, b) => b.add - a.add)[0] || { hour: "--", add: 0 };
|
||||
const startDate = days[0]?.date || "--";
|
||||
const endDate = days[days.length - 1]?.date || "--";
|
||||
|
||||
document.getElementById("subtitle").textContent = `${startDate} ~ ${endDate}`;
|
||||
|
||||
const summaryItems = [
|
||||
["总文件数", fmt(locTotals.files || 0)],
|
||||
["总行数", fmt(locTotals.lines || 0)],
|
||||
["源码行数", fmt(locTotals.source_lines || 0)],
|
||||
["贡献人数", fmt(authors.length)],
|
||||
["人工提交数", fmt(totalHumanCommits)],
|
||||
["人工新增", fmt(totalHumanAdd)],
|
||||
["人工删除", fmt(totalHumanDel)],
|
||||
["最高产小时", `${topHour.hour}:00 (${fmt(topHour.add)})`],
|
||||
];
|
||||
|
||||
document.getElementById("summary").innerHTML = summaryItems.map(([k, v]) => (
|
||||
`<div class="card"><div class="k">${k}</div><div class="v">${v}</div></div>`
|
||||
)).join("");
|
||||
|
||||
const maxExtLines = Math.max(...extRows.map((x) => x.lines), 1);
|
||||
document.getElementById("extTable").innerHTML = `
|
||||
<thead><tr><th>扩展名</th><th class="num">文件数</th><th class="num">行数</th><th>占比</th><th>可视化</th></tr></thead>
|
||||
<tbody>
|
||||
${extRows.map((r) => {
|
||||
const pct = ((r.lines / (locTotals.lines || 1)) * 100).toFixed(2);
|
||||
const w = ((r.lines / maxExtLines) * 100).toFixed(1);
|
||||
return `<tr>
|
||||
<td class="mono">${r.ext}</td>
|
||||
<td class="num">${fmt(r.files)}</td>
|
||||
<td class="num">${fmt(r.lines)}</td>
|
||||
<td class="num">${pct}%</td>
|
||||
<td><div class="bar-wrap"><div class="bar" style="width:${w}%"></div></div></td>
|
||||
</tr>`;
|
||||
}).join("")}
|
||||
</tbody>`;
|
||||
|
||||
document.getElementById("authorTable").innerHTML = `
|
||||
<thead><tr><th>作者</th><th class="num">提交</th><th class="num">新增</th><th class="num">删除</th><th class="num">净新增</th><th class="num">新增占比</th><th class="num">提交占比</th></tr></thead>
|
||||
<tbody>
|
||||
${authors.map((a) => `<tr>
|
||||
<td>${a.name}</td>
|
||||
<td class="num">${fmt(a.commits)}</td>
|
||||
<td class="num">${fmt(a.add)}</td>
|
||||
<td class="num">${fmt(a.del)}</td>
|
||||
<td class="num ${a.net >= 0 ? "ok" : "danger"}">${fmt(a.net)}</td>
|
||||
<td class="num">${a.addPct}</td>
|
||||
<td class="num">${a.commitPct}</td>
|
||||
</tr>`).join("")}
|
||||
</tbody>`;
|
||||
|
||||
document.getElementById("dayTable").innerHTML = `
|
||||
<thead><tr><th>日期</th><th class="num">提交</th><th class="num">新增</th><th class="num">删除</th><th class="num">净新增</th><th>活跃时段</th><th>峰值小时</th></tr></thead>
|
||||
<tbody>
|
||||
${days.map((d) => `<tr>
|
||||
<td class="mono">${d.date}</td>
|
||||
<td class="num">${fmt(d.commits)}</td>
|
||||
<td class="num">${fmt(d.add)}</td>
|
||||
<td class="num">${fmt(d.del)}</td>
|
||||
<td class="num ${d.net >= 0 ? "ok" : "danger"}">${fmt(d.net)}</td>
|
||||
<td class="mono">${d.startHour}:00 - ${d.endHour}:59</td>
|
||||
<td class="mono">${d.peak ? `${d.peak.hour}:00 (${fmt(d.peak.add)})` : "--"}</td>
|
||||
</tr>`).join("")}
|
||||
</tbody>`;
|
||||
|
||||
const maxHourAdd = Math.max(...hours.map((h) => h.add), 1);
|
||||
document.getElementById("hourTable").innerHTML = `
|
||||
<thead><tr><th>小时</th><th class="num">提交</th><th class="num">新增</th><th class="num">删除</th><th class="num">净新增</th><th>可视化</th></tr></thead>
|
||||
<tbody>
|
||||
${hours.map((h) => {
|
||||
const w = ((h.add / maxHourAdd) * 100).toFixed(1);
|
||||
return `<tr>
|
||||
<td class="mono">${h.hour}:00</td>
|
||||
<td class="num">${fmt(h.commits)}</td>
|
||||
<td class="num">${fmt(h.add)}</td>
|
||||
<td class="num">${fmt(h.del)}</td>
|
||||
<td class="num ${h.net >= 0 ? "ok" : "danger"}">${fmt(h.net)}</td>
|
||||
<td><div class="bar-wrap"><div class="bar" style="width:${w}%"></div></div></td>
|
||||
</tr>`;
|
||||
}).join("")}
|
||||
</tbody>`;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,884 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Subagent Orchestration Architecture</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #0d1117;
|
||||
--surface: #161b22;
|
||||
--border: #30363d;
|
||||
--text: #e6edf3;
|
||||
--text-muted: #8b949e;
|
||||
--accent: #58a6ff;
|
||||
--green: #3fb950;
|
||||
--orange: #d29922;
|
||||
--red: #f85149;
|
||||
--purple: #bc8cff;
|
||||
--cyan: #39d2c0;
|
||||
--pink: #f778ba;
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
padding: 40px 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 28px;
|
||||
margin-bottom: 8px;
|
||||
background: linear-gradient(135deg, var(--accent), var(--purple));
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
text-align: center;
|
||||
color: var(--text-muted);
|
||||
font-size: 14px;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
margin: 48px 0 24px;
|
||||
color: var(--accent);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
h2::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 4px;
|
||||
height: 20px;
|
||||
background: var(--accent);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* ── Architecture Diagram ── */
|
||||
.arch-diagram {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.arch-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.arch-box {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 20px 24px;
|
||||
min-width: 200px;
|
||||
max-width: 320px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.arch-box.wide { min-width: 500px; }
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.arch-box.wide { min-width: 100%; }
|
||||
}
|
||||
|
||||
.arch-box .title {
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
margin-bottom: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.arch-box .desc {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.arch-box .file {
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
font-family: 'SF Mono', Consolas, monospace;
|
||||
margin-top: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.badge-blue { background: rgba(88,166,255,0.15); color: var(--accent); }
|
||||
.badge-green { background: rgba(63,185,80,0.15); color: var(--green); }
|
||||
.badge-purple { background: rgba(188,140,255,0.15); color: var(--purple); }
|
||||
.badge-orange { background: rgba(210,153,34,0.15); color: var(--orange); }
|
||||
.badge-cyan { background: rgba(57,210,192,0.15); color: var(--cyan); }
|
||||
.badge-pink { background: rgba(247,120,186,0.15); color: var(--pink); }
|
||||
|
||||
/* ── SVG Arrows ── */
|
||||
.arrow-section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.arrow-section svg {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* ── Call Chain ── */
|
||||
.call-chain {
|
||||
position: relative;
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
.call-chain::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
background: linear-gradient(to bottom, var(--accent), var(--purple), var(--green));
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.chain-step {
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
padding: 16px 20px;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.chain-step:hover {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.chain-step::before {
|
||||
content: attr(data-step);
|
||||
position: absolute;
|
||||
left: -32px;
|
||||
top: 16px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
color: var(--bg);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: translateX(-4px);
|
||||
}
|
||||
|
||||
.chain-step.phase-spawn::before { background: var(--accent); }
|
||||
.chain-step.phase-watch::before { background: var(--purple); }
|
||||
.chain-step.phase-complete::before { background: var(--green); }
|
||||
.chain-step.phase-cleanup::before { background: var(--orange); }
|
||||
|
||||
.chain-step .step-title {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.chain-step .step-detail {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.chain-step code {
|
||||
background: rgba(88,166,255,0.1);
|
||||
color: var(--accent);
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-family: 'SF Mono', Consolas, monospace;
|
||||
}
|
||||
|
||||
.chain-step .arrow-label {
|
||||
font-size: 11px;
|
||||
color: var(--cyan);
|
||||
font-family: 'SF Mono', Consolas, monospace;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
/* ── Sequence Diagram ── */
|
||||
.sequence-container {
|
||||
overflow-x: auto;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.sequence-diagram {
|
||||
min-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* ── Module Map ── */
|
||||
.module-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.module-card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
.module-card .mod-name {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
font-family: 'SF Mono', Consolas, monospace;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.module-card .mod-desc {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.module-card .mod-exports {
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
font-family: 'SF Mono', Consolas, monospace;
|
||||
}
|
||||
|
||||
.module-card .mod-exports span {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
/* ── State Machine ── */
|
||||
.state-diagram {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.state-node {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 18px;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.state-arrow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
.state-arrow svg { margin: 0 4px; }
|
||||
|
||||
.legend {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 16px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.legend-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
||||
<h1>Subagent Orchestration Architecture</h1>
|
||||
<p class="subtitle">Super Multica — Parent-child agent spawning, lifecycle management, and result announcement</p>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════════ -->
|
||||
<h2>System Architecture</h2>
|
||||
<!-- ══════════════════════════════════════════════════════ -->
|
||||
|
||||
<div class="arch-diagram">
|
||||
|
||||
<!-- Row 1: Parent Agent -->
|
||||
<div class="arch-row">
|
||||
<div class="arch-box wide" style="border-color: var(--accent);">
|
||||
<div class="title">
|
||||
<span class="badge badge-blue">Agent</span>
|
||||
Parent Agent (Interactive Session)
|
||||
</div>
|
||||
<div class="desc">
|
||||
User-facing agent with full tool access. Can spawn child agents via <code>sessions_spawn</code> tool.
|
||||
Receives announcement messages when child agents complete.
|
||||
</div>
|
||||
<div class="file">src/agent/runner.ts → tools: sessions_spawn, exec, glob, web_fetch, ...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Arrow -->
|
||||
<div class="arrow-section">
|
||||
<svg width="400" height="48">
|
||||
<defs>
|
||||
<marker id="arrow1" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#58a6ff"/>
|
||||
</marker>
|
||||
<marker id="arrow2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#3fb950"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<!-- spawn arrow (down-left) -->
|
||||
<line x1="140" y1="4" x2="80" y2="40" stroke="#58a6ff" stroke-width="2" marker-end="url(#arrow1)"/>
|
||||
<text x="70" y="24" fill="#58a6ff" font-size="11" font-family="monospace">spawn</text>
|
||||
<!-- announce arrow (up-right) -->
|
||||
<line x1="320" y1="40" x2="260" y2="4" stroke="#3fb950" stroke-width="2" stroke-dasharray="6 3" marker-end="url(#arrow2)"/>
|
||||
<text x="282" y="24" fill="#3fb950" font-size="11" font-family="monospace">announce</text>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- Row 2: Hub + Registry -->
|
||||
<div class="arch-row">
|
||||
<div class="arch-box" style="border-color: var(--purple);">
|
||||
<div class="title">
|
||||
<span class="badge badge-purple">Singleton</span>
|
||||
Hub
|
||||
</div>
|
||||
<div class="desc">
|
||||
Central coordinator. Creates & manages all agents. Provides <code>createSubagent()</code>,
|
||||
<code>getAgent()</code>, <code>closeAgent()</code>. Calls registry init on startup, shutdown on exit.
|
||||
</div>
|
||||
<div class="file">src/hub/hub.ts + hub-singleton.ts</div>
|
||||
</div>
|
||||
|
||||
<div class="arch-box" style="border-color: var(--orange);">
|
||||
<div class="title">
|
||||
<span class="badge badge-orange">Module</span>
|
||||
Subagent Registry
|
||||
</div>
|
||||
<div class="desc">
|
||||
In-memory Map + JSON persistence. Tracks run lifecycle (created → started → ended).
|
||||
Archive sweeper cleans old runs every 60s. Handles crash recovery on restart.
|
||||
</div>
|
||||
<div class="file">src/agent/subagent/registry.ts</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Arrow -->
|
||||
<div class="arrow-section">
|
||||
<svg width="400" height="48">
|
||||
<defs>
|
||||
<marker id="arrow3" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#bc8cff"/>
|
||||
</marker>
|
||||
<marker id="arrow4" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#d29922"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<line x1="120" y1="4" x2="120" y2="40" stroke="#bc8cff" stroke-width="2" marker-end="url(#arrow3)"/>
|
||||
<text x="132" y="26" fill="#bc8cff" font-size="11" font-family="monospace">createSubagent()</text>
|
||||
<line x1="280" y1="4" x2="280" y2="40" stroke="#d29922" stroke-width="2" stroke-dasharray="6 3" marker-end="url(#arrow4)"/>
|
||||
<text x="292" y="26" fill="#d29922" font-size="11" font-family="monospace">watchChildAgent()</text>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- Row 3: Child Agent + Announce + Store -->
|
||||
<div class="arch-row">
|
||||
<div class="arch-box" style="border-color: var(--cyan);">
|
||||
<div class="title">
|
||||
<span class="badge badge-cyan">Agent</span>
|
||||
Child AsyncAgent
|
||||
</div>
|
||||
<div class="desc">
|
||||
Isolated agent with <code>isSubagent: true</code>. Restricted tools (no <code>sessions_spawn</code>).
|
||||
Custom system prompt: stay focused, no user messaging, no nested spawning.
|
||||
</div>
|
||||
<div class="file">src/agent/async-agent.ts</div>
|
||||
</div>
|
||||
|
||||
<div class="arch-box" style="border-color: var(--green);">
|
||||
<div class="title">
|
||||
<span class="badge badge-green">Flow</span>
|
||||
Announce Module
|
||||
</div>
|
||||
<div class="desc">
|
||||
Reads child's last assistant reply from session JSONL. Formats announcement message with findings, duration, status.
|
||||
Delivers to parent via <code>parentAgent.write()</code>.
|
||||
</div>
|
||||
<div class="file">src/agent/subagent/announce.ts</div>
|
||||
</div>
|
||||
|
||||
<div class="arch-box" style="border-color: var(--text-muted);">
|
||||
<div class="title">
|
||||
<span class="badge" style="background:rgba(139,148,158,0.15);color:var(--text-muted);">Store</span>
|
||||
Registry Store
|
||||
</div>
|
||||
<div class="desc">
|
||||
JSON file persistence at <code>~/.super-multica/subagents/runs.json</code>.
|
||||
Schema: <code>{ version: 1, runs: {...} }</code>. Survives process restarts.
|
||||
</div>
|
||||
<div class="file">src/agent/subagent/registry-store.ts</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════════ -->
|
||||
<h2>Call Chain — Spawn & Lifecycle</h2>
|
||||
<!-- ══════════════════════════════════════════════════════ -->
|
||||
|
||||
<div class="call-chain">
|
||||
|
||||
<div class="chain-step phase-spawn" data-step="1">
|
||||
<div class="step-title">Parent Agent invokes <code>sessions_spawn</code> tool</div>
|
||||
<div class="step-detail">
|
||||
Agent calls tool with <code>{ task, label?, model?, cleanup?, timeoutSeconds? }</code>.
|
||||
Guard rejects if <code>isSubagent === true</code>.
|
||||
</div>
|
||||
<div class="arrow-label">sessions-spawn.ts → execute()</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-step phase-spawn" data-step="2">
|
||||
<div class="step-title">Generate IDs & build system prompt</div>
|
||||
<div class="step-detail">
|
||||
<code>runId</code> = UUIDv7, <code>childSessionId</code> = UUIDv7.
|
||||
<code>buildSubagentSystemPrompt()</code> creates prompt with task context, rules (no nested spawn, stay focused).
|
||||
</div>
|
||||
<div class="arrow-label">announce.ts → buildSubagentSystemPrompt()</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-step phase-spawn" data-step="3">
|
||||
<div class="step-title">Hub creates child AsyncAgent</div>
|
||||
<div class="step-detail">
|
||||
<code>hub.createSubagent(childSessionId, { systemPrompt, model })</code>
|
||||
creates an <code>AsyncAgent</code> with <code>isSubagent: true</code>. Not persisted to agent store (ephemeral).
|
||||
</div>
|
||||
<div class="arrow-label">hub.ts → createSubagent()</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-step phase-watch" data-step="4">
|
||||
<div class="step-title">Write task to child (non-blocking)</div>
|
||||
<div class="step-detail">
|
||||
<code>childAgent.write(task)</code> enqueues the task to the serial queue.
|
||||
This happens before registration so <code>waitForIdle()</code> observes queued work.
|
||||
</div>
|
||||
<div class="arrow-label">async-agent.ts → write() (enqueues to serial queue)</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-step phase-spawn" data-step="5">
|
||||
<div class="step-title">Register run in registry</div>
|
||||
<div class="step-detail">
|
||||
<code>registerSubagentRun()</code> saves record to in-memory Map + JSON file.
|
||||
Sets <code>createdAt</code>, starts archive sweeper.
|
||||
</div>
|
||||
<div class="arrow-label">registry.ts → registerSubagentRun()</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-step phase-watch" data-step="6">
|
||||
<div class="step-title">Start lifecycle watcher & return to parent</div>
|
||||
<div class="step-detail">
|
||||
<code>watchChildAgent()</code> sets <code>startedAt</code>.
|
||||
Attaches <code>childAgent.waitForIdle()</code> (promise resolves when task queue drained)
|
||||
and <code>childAgent.onClose()</code> callback. Optionally sets timeout timer.
|
||||
Tool returns <code>{ status: "accepted", childSessionId, runId }</code> immediately.
|
||||
</div>
|
||||
<div class="arrow-label">registry.ts → watchChildAgent() → AsyncAgent.waitForIdle() + onClose()</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-step phase-watch" data-step="7">
|
||||
<div class="step-title">Child agent processes task autonomously</div>
|
||||
<div class="step-detail">
|
||||
Child runs LLM inference with restricted tools. Uses its own session.
|
||||
May call <code>exec</code>, <code>glob</code>, <code>web_fetch</code> etc. but NOT <code>sessions_spawn</code>.
|
||||
</div>
|
||||
<div class="arrow-label">runner.ts → Agent.run() (within AsyncAgent queue)</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-step phase-complete" data-step="8">
|
||||
<div class="step-title">Child completes → <code>waitForIdle()</code> resolves</div>
|
||||
<div class="step-detail">
|
||||
Task queue drains. Watcher's cleanup callback fires: sets <code>endedAt</code>, <code>outcome: { status: "ok" }</code>.
|
||||
Persists updated record to JSON.
|
||||
</div>
|
||||
<div class="arrow-label">registry.ts → cleanup() → handleRunCompletion()</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-step phase-complete" data-step="9">
|
||||
<div class="step-title">Announce flow: read child reply & deliver to parent</div>
|
||||
<div class="step-detail">
|
||||
<code>readLatestAssistantReply(childSessionId)</code> reads session JSONL, extracts last assistant text.
|
||||
<code>formatAnnouncementMessage()</code> builds summary with task, status, findings, runtime.
|
||||
<code>parentAgent.write(message)</code> delivers to parent.
|
||||
</div>
|
||||
<div class="arrow-label">announce.ts → runSubagentAnnounceFlow() → hub.getAgent(parentId).write()</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-step phase-cleanup" data-step="10">
|
||||
<div class="step-title">Session cleanup & archive</div>
|
||||
<div class="step-detail">
|
||||
If <code>cleanup === "delete"</code>: removes child session directory + closes agent in Hub.
|
||||
Schedules archive at <code>now + 60min</code>. Sweeper removes from registry after TTL.
|
||||
</div>
|
||||
<div class="arrow-label">registry.ts → deleteChildSession() + sweep()</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════════ -->
|
||||
<h2>Sequence Diagram</h2>
|
||||
<!-- ══════════════════════════════════════════════════════ -->
|
||||
|
||||
<div class="sequence-container">
|
||||
<svg class="sequence-diagram" viewBox="0 0 920 620" width="920" height="620">
|
||||
<style>
|
||||
.seq-text { font-family: -apple-system, sans-serif; font-size: 12px; fill: #e6edf3; }
|
||||
.seq-mono { font-family: 'SF Mono', Consolas, monospace; font-size: 11px; }
|
||||
.seq-label { font-size: 13px; font-weight: 600; }
|
||||
.seq-line { stroke: #30363d; stroke-width: 1; }
|
||||
.seq-lifeline { stroke: #30363d; stroke-width: 1; stroke-dasharray: 6 4; }
|
||||
</style>
|
||||
|
||||
<!-- Column headers -->
|
||||
<rect x="40" y="10" width="130" height="36" rx="6" fill="#161b22" stroke="#58a6ff"/>
|
||||
<text x="105" y="33" text-anchor="middle" class="seq-text seq-label" fill="#58a6ff">Parent Agent</text>
|
||||
|
||||
<rect x="230" y="10" width="130" height="36" rx="6" fill="#161b22" stroke="#d29922"/>
|
||||
<text x="295" y="33" text-anchor="middle" class="seq-text seq-label" fill="#d29922">sessions_spawn</text>
|
||||
|
||||
<rect x="420" y="10" width="100" height="36" rx="6" fill="#161b22" stroke="#bc8cff"/>
|
||||
<text x="470" y="33" text-anchor="middle" class="seq-text seq-label" fill="#bc8cff">Hub</text>
|
||||
|
||||
<rect x="580" y="10" width="120" height="36" rx="6" fill="#161b22" stroke="#d29922"/>
|
||||
<text x="640" y="33" text-anchor="middle" class="seq-text seq-label" fill="#d29922">Registry</text>
|
||||
|
||||
<rect x="760" y="10" width="120" height="36" rx="6" fill="#161b22" stroke="#39d2c0"/>
|
||||
<text x="820" y="33" text-anchor="middle" class="seq-text seq-label" fill="#39d2c0">Child Agent</text>
|
||||
|
||||
<!-- Lifelines -->
|
||||
<line x1="105" y1="46" x2="105" y2="610" class="seq-lifeline"/>
|
||||
<line x1="295" y1="46" x2="295" y2="610" class="seq-lifeline"/>
|
||||
<line x1="470" y1="46" x2="470" y2="610" class="seq-lifeline"/>
|
||||
<line x1="640" y1="46" x2="640" y2="610" class="seq-lifeline"/>
|
||||
<line x1="820" y1="46" x2="820" y2="610" class="seq-lifeline"/>
|
||||
|
||||
<!-- 1. Parent → Tool: call sessions_spawn -->
|
||||
<line x1="105" y1="80" x2="290" y2="80" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#seq-arrow-blue)"/>
|
||||
<text x="198" y="74" text-anchor="middle" class="seq-text seq-mono" fill="#58a6ff">execute({ task, label })</text>
|
||||
|
||||
<!-- 2. Tool → Hub: createSubagent -->
|
||||
<line x1="295" y1="115" x2="465" y2="115" stroke="#bc8cff" stroke-width="1.5" marker-end="url(#seq-arrow-purple)"/>
|
||||
<text x="380" y="109" text-anchor="middle" class="seq-text seq-mono" fill="#bc8cff">createSubagent(id, opts)</text>
|
||||
|
||||
<!-- 3. Hub → Child: new AsyncAgent -->
|
||||
<line x1="470" y1="150" x2="815" y2="150" stroke="#39d2c0" stroke-width="1.5" marker-end="url(#seq-arrow-cyan)"/>
|
||||
<text x="640" y="144" text-anchor="middle" class="seq-text seq-mono" fill="#39d2c0">new AsyncAgent({ isSubagent: true })</text>
|
||||
|
||||
<!-- 4. Tool → Child: write(task) -->
|
||||
<line x1="295" y1="190" x2="815" y2="190" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#seq-arrow-blue)"/>
|
||||
<text x="555" y="184" text-anchor="middle" class="seq-text seq-mono" fill="#58a6ff">childAgent.write(task)</text>
|
||||
|
||||
<!-- 5. Tool → Registry: registerSubagentRun -->
|
||||
<line x1="295" y1="225" x2="635" y2="225" stroke="#d29922" stroke-width="1.5" marker-end="url(#seq-arrow-orange)"/>
|
||||
<text x="465" y="219" text-anchor="middle" class="seq-text seq-mono" fill="#d29922">registerSubagentRun(params)</text>
|
||||
|
||||
<!-- 6. Registry → Child: watchChildAgent (waitForIdle) -->
|
||||
<line x1="640" y1="260" x2="815" y2="260" stroke="#d29922" stroke-width="1.5" stroke-dasharray="6 3" marker-end="url(#seq-arrow-orange)"/>
|
||||
<text x="727" y="254" text-anchor="middle" class="seq-text seq-mono" fill="#d29922">waitForIdle() + onClose()</text>
|
||||
|
||||
<!-- 7. Tool → Parent: return accepted -->
|
||||
<line x1="290" y1="295" x2="110" y2="295" stroke="#3fb950" stroke-width="1.5" marker-end="url(#seq-arrow-green)"/>
|
||||
<text x="200" y="289" text-anchor="middle" class="seq-text seq-mono" fill="#3fb950">{ status: "accepted", runId }</text>
|
||||
|
||||
<!-- Async boundary -->
|
||||
<line x1="20" y1="330" x2="900" y2="330" stroke="#30363d" stroke-width="1" stroke-dasharray="3 3"/>
|
||||
<rect x="390" y="320" width="140" height="20" rx="4" fill="#161b22" stroke="#30363d"/>
|
||||
<text x="460" y="335" text-anchor="middle" class="seq-text" fill="#8b949e" style="font-size:11px">async (non-blocking)</text>
|
||||
|
||||
<!-- 8. Child processes task -->
|
||||
<rect x="790" y="355" width="60" height="60" rx="4" fill="rgba(57,210,192,0.1)" stroke="#39d2c0" stroke-dasharray="4 2"/>
|
||||
<text x="820" y="380" text-anchor="middle" class="seq-text" fill="#39d2c0" style="font-size:10px">LLM</text>
|
||||
<text x="820" y="395" text-anchor="middle" class="seq-text" fill="#39d2c0" style="font-size:10px">inference</text>
|
||||
|
||||
<!-- 9. Child → Registry: waitForIdle resolves -->
|
||||
<line x1="815" y1="440" x2="645" y2="440" stroke="#3fb950" stroke-width="1.5" stroke-dasharray="6 3" marker-end="url(#seq-arrow-green)"/>
|
||||
<text x="730" y="434" text-anchor="middle" class="seq-text seq-mono" fill="#3fb950">idle (resolved)</text>
|
||||
|
||||
<!-- 10. Registry: handleRunCompletion -->
|
||||
<rect x="610" y="460" width="60" height="30" rx="4" fill="rgba(210,153,34,0.1)" stroke="#d29922" stroke-dasharray="4 2"/>
|
||||
<text x="640" y="480" text-anchor="middle" class="seq-text" fill="#d29922" style="font-size:10px">announce</text>
|
||||
|
||||
<!-- 11. Registry → Parent: announcement -->
|
||||
<line x1="635" y1="510" x2="110" y2="510" stroke="#3fb950" stroke-width="1.5" marker-end="url(#seq-arrow-green)"/>
|
||||
<text x="372" y="504" text-anchor="middle" class="seq-text seq-mono" fill="#3fb950">parentAgent.write(announcement)</text>
|
||||
|
||||
<!-- 12. Registry: cleanup -->
|
||||
<line x1="640" y1="545" x2="815" y2="545" stroke="#f85149" stroke-width="1.5" marker-end="url(#seq-arrow-red)"/>
|
||||
<text x="727" y="539" text-anchor="middle" class="seq-text seq-mono" fill="#f85149">deleteChildSession()</text>
|
||||
|
||||
<!-- 13. Registry: schedule archive -->
|
||||
<rect x="610" y="565" width="60" height="25" rx="4" fill="rgba(210,153,34,0.1)" stroke="#d29922" stroke-dasharray="4 2"/>
|
||||
<text x="640" y="582" text-anchor="middle" class="seq-text" fill="#d29922" style="font-size:9px">archive 60m</text>
|
||||
|
||||
<!-- Arrow markers -->
|
||||
<defs>
|
||||
<marker id="seq-arrow-blue" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#58a6ff"/>
|
||||
</marker>
|
||||
<marker id="seq-arrow-green" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#3fb950"/>
|
||||
</marker>
|
||||
<marker id="seq-arrow-purple" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#bc8cff"/>
|
||||
</marker>
|
||||
<marker id="seq-arrow-orange" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#d29922"/>
|
||||
</marker>
|
||||
<marker id="seq-arrow-cyan" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#39d2c0"/>
|
||||
</marker>
|
||||
<marker id="seq-arrow-red" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#f85149"/>
|
||||
</marker>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════════ -->
|
||||
<h2>Run State Machine</h2>
|
||||
<!-- ══════════════════════════════════════════════════════ -->
|
||||
|
||||
<div class="state-diagram" style="flex-wrap: wrap; gap: 12px;">
|
||||
<div class="state-node" style="background:rgba(88,166,255,0.12); border:1px solid var(--accent);">
|
||||
<svg width="10" height="10"><circle cx="5" cy="5" r="5" fill="#58a6ff"/></svg>
|
||||
created
|
||||
</div>
|
||||
<div class="state-arrow">
|
||||
<svg width="24" height="12">
|
||||
<defs>
|
||||
<marker id="sm-arrow-1" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto">
|
||||
<path d="M0 0 L10 5 L0 10z" fill="#8b949e"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<path d="M0 6 L20 6" stroke="#8b949e" stroke-width="1.5" marker-end="url(#sm-arrow-1)"/>
|
||||
</svg>
|
||||
startedAt
|
||||
</div>
|
||||
<div class="state-node" style="background:rgba(188,140,255,0.12); border:1px solid var(--purple);">
|
||||
<svg width="10" height="10"><circle cx="5" cy="5" r="5" fill="#bc8cff"/></svg>
|
||||
started
|
||||
</div>
|
||||
<div class="state-arrow">
|
||||
<svg width="24" height="12">
|
||||
<defs>
|
||||
<marker id="sm-arrow-2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto">
|
||||
<path d="M0 0 L10 5 L0 10z" fill="#8b949e"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<path d="M0 6 L20 6" stroke="#8b949e" stroke-width="1.5" marker-end="url(#sm-arrow-2)"/>
|
||||
</svg>
|
||||
endedAt
|
||||
</div>
|
||||
<div class="state-node" style="background:rgba(63,185,80,0.12); border:1px solid var(--green);">
|
||||
<svg width="10" height="10"><circle cx="5" cy="5" r="5" fill="#3fb950"/></svg>
|
||||
ended
|
||||
</div>
|
||||
<div class="state-arrow">
|
||||
<svg width="24" height="12">
|
||||
<defs>
|
||||
<marker id="sm-arrow-3" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto">
|
||||
<path d="M0 0 L10 5 L0 10z" fill="#8b949e"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<path d="M0 6 L20 6" stroke="#8b949e" stroke-width="1.5" marker-end="url(#sm-arrow-3)"/>
|
||||
</svg>
|
||||
announce
|
||||
</div>
|
||||
<div class="state-node" style="background:rgba(210,153,34,0.12); border:1px solid var(--orange);">
|
||||
<svg width="10" height="10"><circle cx="5" cy="5" r="5" fill="#d29922"/></svg>
|
||||
cleanup done
|
||||
</div>
|
||||
<div class="state-arrow">
|
||||
<svg width="24" height="12">
|
||||
<defs>
|
||||
<marker id="sm-arrow-4" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto">
|
||||
<path d="M0 0 L10 5 L0 10z" fill="#8b949e"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<path d="M0 6 L20 6" stroke="#8b949e" stroke-width="1.5" marker-end="url(#sm-arrow-4)"/>
|
||||
</svg>
|
||||
60 min
|
||||
</div>
|
||||
<div class="state-node" style="background:rgba(139,148,158,0.12); border:1px solid var(--text-muted);">
|
||||
<svg width="10" height="10"><circle cx="5" cy="5" r="5" fill="#8b949e"/></svg>
|
||||
archived
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px; padding: 16px 20px; background: var(--surface); border: 1px solid var(--border); border-radius: 10px;">
|
||||
<div style="font-size: 13px; font-weight: 600; margin-bottom: 8px;">Outcome Status Values</div>
|
||||
<div style="display: flex; gap: 24px; flex-wrap: wrap; font-size: 12px;">
|
||||
<span><code style="color:var(--green)">ok</code> — Task completed normally (waitForIdle resolved)</span>
|
||||
<span><code style="color:var(--red)">error</code> — Child agent threw an error</span>
|
||||
<span><code style="color:var(--orange)">timeout</code> — Exceeded timeoutSeconds limit</span>
|
||||
<span><code style="color:var(--text-muted)">unknown</code> — Process crash or Hub shutdown</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════════ -->
|
||||
<h2>Module Map</h2>
|
||||
<!-- ══════════════════════════════════════════════════════ -->
|
||||
|
||||
<div class="module-grid">
|
||||
<div class="module-card" style="border-left: 3px solid var(--cyan);">
|
||||
<div class="mod-name">src/agent/subagent/types.ts</div>
|
||||
<div class="mod-desc">Core type definitions</div>
|
||||
<div class="mod-exports">
|
||||
<span>export</span> SubagentRunOutcome<br>
|
||||
<span>export</span> SubagentRunRecord<br>
|
||||
<span>export</span> RegisterSubagentRunParams<br>
|
||||
<span>export</span> SubagentAnnounceParams<br>
|
||||
<span>export</span> SubagentSystemPromptParams
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="module-card" style="border-left: 3px solid var(--orange);">
|
||||
<div class="mod-name">src/agent/subagent/registry.ts</div>
|
||||
<div class="mod-desc">In-memory registry + lifecycle watcher</div>
|
||||
<div class="mod-exports">
|
||||
<span>export</span> initSubagentRegistry()<br>
|
||||
<span>export</span> registerSubagentRun()<br>
|
||||
<span>export</span> listSubagentRuns()<br>
|
||||
<span>export</span> releaseSubagentRun()<br>
|
||||
<span>export</span> getSubagentRun()<br>
|
||||
<span>export</span> shutdownSubagentRegistry()
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="module-card" style="border-left: 3px solid var(--text-muted);">
|
||||
<div class="mod-name">src/agent/subagent/registry-store.ts</div>
|
||||
<div class="mod-desc">JSON file persistence</div>
|
||||
<div class="mod-exports">
|
||||
<span>export</span> loadSubagentRuns()<br>
|
||||
<span>export</span> saveSubagentRuns()<br>
|
||||
<span>export</span> getSubagentStorePath()
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="module-card" style="border-left: 3px solid var(--green);">
|
||||
<div class="mod-name">src/agent/subagent/announce.ts</div>
|
||||
<div class="mod-desc">Result propagation child → parent</div>
|
||||
<div class="mod-exports">
|
||||
<span>export</span> buildSubagentSystemPrompt()<br>
|
||||
<span>export</span> readLatestAssistantReply()<br>
|
||||
<span>export</span> formatAnnouncementMessage()<br>
|
||||
<span>export</span> runSubagentAnnounceFlow()
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="module-card" style="border-left: 3px solid var(--accent);">
|
||||
<div class="mod-name">src/agent/tools/sessions-spawn.ts</div>
|
||||
<div class="mod-desc">Tool definition for parent agents</div>
|
||||
<div class="mod-exports">
|
||||
<span>export</span> createSessionsSpawnTool()<br>
|
||||
schema: { task, label?, model?,<br>
|
||||
cleanup?, timeoutSeconds? }
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="module-card" style="border-left: 3px solid var(--purple);">
|
||||
<div class="mod-name">src/hub/hub-singleton.ts</div>
|
||||
<div class="mod-desc">Global Hub access for tools & registry</div>
|
||||
<div class="mod-exports">
|
||||
<span>export</span> setHub(hub)<br>
|
||||
<span>export</span> getHub()<br>
|
||||
<span>export</span> isHubInitialized()
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════════ -->
|
||||
<h2>Key Design Decisions</h2>
|
||||
<!-- ══════════════════════════════════════════════════════ -->
|
||||
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 16px;">
|
||||
<div class="module-card">
|
||||
<div class="mod-name" style="color: var(--accent); font-family: inherit;">waitForIdle() vs stream consumption</div>
|
||||
<div class="mod-desc" style="font-size: 13px; margin-top: 8px;">
|
||||
Channel is single-reader. <code>Hub.consumeAgent()</code> already reads the stream for forwarding events.
|
||||
Registry uses <code>waitForIdle()</code> (promise on internal task queue) to detect completion without competing for the stream.
|
||||
</div>
|
||||
</div>
|
||||
<div class="module-card">
|
||||
<div class="mod-name" style="color: var(--accent); font-family: inherit;">Singleton Hub access</div>
|
||||
<div class="mod-desc" style="font-size: 13px; margin-top: 8px;">
|
||||
Tools and registry modules cannot receive Hub via constructor injection (tools are created before Hub exists).
|
||||
A module-level singleton (<code>setHub</code>/<code>getHub</code>) bridges this gap, with <code>isHubInitialized()</code> guard for test safety.
|
||||
</div>
|
||||
</div>
|
||||
<div class="module-card">
|
||||
<div class="mod-name" style="color: var(--accent); font-family: inherit;">Crash recovery</div>
|
||||
<div class="mod-desc" style="font-size: 13px; margin-top: 8px;">
|
||||
Runs are persisted to JSON after every state change. On restart, <code>initSubagentRegistry()</code>
|
||||
loads persisted runs: completed-but-unannounced runs trigger announce flow; unfinished runs are marked as
|
||||
<code>status: "unknown"</code>.
|
||||
</div>
|
||||
</div>
|
||||
<div class="module-card">
|
||||
<div class="mod-name" style="color: var(--accent); font-family: inherit;">Subagent isolation</div>
|
||||
<div class="mod-desc" style="font-size: 13px; margin-top: 8px;">
|
||||
Child agents have <code>isSubagent: true</code> which applies tool deny-list (blocks <code>sessions_spawn</code>).
|
||||
System prompt explicitly forbids nested spawning, direct user communication, and off-topic work.
|
||||
Sessions are ephemeral — deleted after announce unless <code>cleanup: "keep"</code>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; color: var(--text-muted); font-size: 12px; margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--border);">
|
||||
Super Multica — Subagent Orchestration System — Branch: subagent-orchestration
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue