feat: Phase F-1 — Plexum-fabric-channel-plugin foundation
Ports the foundation of Fabric.OpenclawPlugin to a native Plexum channel plugin (Go). F-2+ phases (socket.io inbound, wakeup gate, tools, presence, etc.) follow. Layout: internal/identity/ — fabric-identity.json registry (agent → API key) internal/fabric/ — REST client (Center auth + Guild messaging) internal/config/ — channels/<name>.json fabric extension parser cmd/plexum-fabric-register/ — agent registration CLI cmd/plexum-fabric-channel-plugin/— Plexum SDK plugin entry scripts/install.sh — build + install + manifest generator Plugin behavior (F-1): - Reads <profile>/channels/*.json, filters plugin=plexum-fabric-channel, builds (plexum-channel-name → fabric channel-id) index - Validates each bound agent's API key against Center at init (warmSessions); logs warning but doesn't refuse init on bad keys - `send` MCP tool: POST plain text to the bound Fabric channel as the agent user; selects guild endpoint+token from cached session - Manifest channels[] is generated by install.sh from current channels/*.json — re-run with --reset-manifest after adding bindings - Plugin-private config at <profile>/plugins/plexum-fabric-channel/config.json (center_api_base, default http://localhost:7001/api) Live smoke verified: - plexum-fabric-register against running Fabric Center (port 7001): validated fak_..., wrote identity file with user_id + email captured Tests: identity (5) + config (6) = 11 unit tests. F-2 will hook socket.io for inbound + wakeup gating + token refresh. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
91
cmd/plexum-fabric-register/main.go
Normal file
91
cmd/plexum-fabric-register/main.go
Normal file
@@ -0,0 +1,91 @@
|
||||
// Command plexum-fabric-register binds a Plexum agent to a Fabric
|
||||
// Center API key. Equivalent of openclaw's `fabric-register` script.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// plexum-fabric-register --api-key fak_...
|
||||
// # agent id from $AGENT_ID env (set by exec MCP tool)
|
||||
// plexum-fabric-register --agent-id alice --api-key fak_...
|
||||
//
|
||||
// Flags:
|
||||
// --api-key Required. The Center-issued agent API key.
|
||||
// --agent-id Optional when $AGENT_ID is set.
|
||||
// --center Optional. Defaults to ${FABRIC_CENTER_API_BASE} or
|
||||
// http://localhost:7001/api.
|
||||
// --identity-file Optional path to fabric-identity.json (default
|
||||
// ${PLEXUM_PROFILE_ROOT}/fabric-identity.json).
|
||||
//
|
||||
// Writes the (agent, api key, user id, email) tuple to identity file
|
||||
// after validating the key against Center via /auth/agent/login.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"git.hangman-lab.top/hzhang/Plexum-fabric-channel-plugin/internal/fabric"
|
||||
"git.hangman-lab.top/hzhang/Plexum-fabric-channel-plugin/internal/identity"
|
||||
)
|
||||
|
||||
func main() {
|
||||
apiKey := flag.String("api-key", "", "Fabric Center API key (fak_...; required)")
|
||||
agentID := flag.String("agent-id", "", "agent id (defaults to $AGENT_ID)")
|
||||
centerBase := flag.String("center", "", "Center API base URL (default $FABRIC_CENTER_API_BASE or http://localhost:7001/api)")
|
||||
identityFile := flag.String("identity-file", "", "identity registry path (default $PLEXUM_PROFILE_ROOT/fabric-identity.json)")
|
||||
flag.Parse()
|
||||
|
||||
if *apiKey == "" {
|
||||
fatalf("--api-key is required")
|
||||
}
|
||||
if *agentID == "" {
|
||||
*agentID = os.Getenv("AGENT_ID")
|
||||
}
|
||||
if *agentID == "" {
|
||||
fatalf("--agent-id required (or set AGENT_ID env)")
|
||||
}
|
||||
if *centerBase == "" {
|
||||
*centerBase = os.Getenv("FABRIC_CENTER_API_BASE")
|
||||
}
|
||||
if *centerBase == "" {
|
||||
*centerBase = "http://localhost:7001/api"
|
||||
}
|
||||
if *identityFile == "" {
|
||||
*identityFile = identity.DefaultPath()
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
|
||||
client := fabric.New(*centerBase)
|
||||
sess, err := client.AgentLogin(ctx, *apiKey)
|
||||
if err != nil {
|
||||
fatalf("validate key against %s: %v", *centerBase, err)
|
||||
}
|
||||
|
||||
reg, err := identity.Open(*identityFile)
|
||||
if err != nil {
|
||||
fatalf("open identity: %v", err)
|
||||
}
|
||||
reg.Set(*agentID, &identity.Entry{
|
||||
FabricAPIKey: *apiKey,
|
||||
FabricUserID: sess.User.ID,
|
||||
FabricEmail: sess.User.Email,
|
||||
Enabled: true,
|
||||
})
|
||||
if err := reg.Save(); err != nil {
|
||||
fatalf("save identity: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("registered agent %s as fabric user %s (%s); %d guilds\n",
|
||||
*agentID, sess.User.Email, sess.User.ID, len(sess.Guilds))
|
||||
fmt.Printf("identity file: %s\n", *identityFile)
|
||||
fmt.Println("restart the plexum gateway to pick up the new identity")
|
||||
}
|
||||
|
||||
func fatalf(format string, args ...any) {
|
||||
fmt.Fprintf(os.Stderr, "plexum-fabric-register: "+format+"\n", args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
Reference in New Issue
Block a user