@polderlabs/bizar 6.3.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/sessionend-recall.mjs +3 -3
- package/.claude/hooks/worker-suggest.mjs +110 -0
- package/.claude/settings.json +9 -0
- package/bizar-dash/dist/assets/{EnvVarsSection-B58aiJiE.js → EnvVarsSection-CW6fWKds.js} +3 -3
- package/bizar-dash/dist/assets/{EnvVarsSection-B58aiJiE.js.map → EnvVarsSection-CW6fWKds.js.map} +1 -1
- package/bizar-dash/dist/assets/MobileChat-D7zRhU9K.js +1 -0
- package/bizar-dash/dist/assets/{MobileChat-BJrqwVDd.js.map → MobileChat-D7zRhU9K.js.map} +1 -1
- package/bizar-dash/dist/assets/MobileSettings-K-sNsn_r.js +1 -0
- package/bizar-dash/dist/assets/{MobileSettings-CEQNJNLJ.js.map → MobileSettings-K-sNsn_r.js.map} +1 -1
- package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js → Toast-WTxc3m2g.js} +1 -1
- package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js.map → Toast-WTxc3m2g.js.map} +1 -1
- package/bizar-dash/dist/assets/flow-BpU0-gK2.js +1 -0
- package/bizar-dash/dist/assets/flow-BpU0-gK2.js.map +1 -0
- package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js +1 -0
- package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js.map +1 -0
- package/bizar-dash/dist/assets/{icons-Do5N2jmX.js → icons-B0AKnYI3.js} +98 -103
- package/bizar-dash/dist/assets/icons-B0AKnYI3.js.map +1 -0
- package/bizar-dash/dist/assets/main-C-Md3DaY.css +1 -0
- package/bizar-dash/dist/assets/main-CO8fIxQK.js +18 -0
- package/bizar-dash/dist/assets/main-CO8fIxQK.js.map +1 -0
- package/bizar-dash/dist/assets/markdown-w2bDDkAH.js +1 -0
- package/bizar-dash/dist/assets/{markdown-tOLaD6nm.js.map → markdown-w2bDDkAH.js.map} +1 -1
- package/bizar-dash/dist/assets/mobile-DXYCA0hC.js +1 -0
- package/bizar-dash/dist/assets/{mobile-DYCHcUpq.js.map → mobile-DXYCA0hC.js.map} +1 -1
- package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js +2 -0
- package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js.map +1 -0
- package/bizar-dash/dist/assets/react-vendor-BnuhLJ6X.css +1 -0
- package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js +46 -0
- package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js.map +1 -0
- package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js +2 -0
- package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js.map +1 -0
- package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js +45 -0
- package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js.map +1 -0
- package/bizar-dash/dist/index.html +12 -10
- package/bizar-dash/dist/mobile.html +7 -4
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/server/api.mjs +11 -0
- package/bizar-dash/src/server/memory-consolidator.mjs +218 -0
- package/bizar-dash/src/server/memory-distillation.mjs +296 -0
- package/bizar-dash/src/server/routes/distill.mjs +129 -0
- package/bizar-dash/src/server/routes/goal-planner.mjs +236 -0
- package/bizar-dash/src/web/App.tsx +4 -0
- package/bizar-dash/src/web/components/Tag.tsx +18 -5
- package/bizar-dash/src/web/components/Topbar.tsx +3 -0
- package/bizar-dash/src/web/components/agents/CommunicationLog.tsx +126 -0
- package/bizar-dash/src/web/components/agents/DependencyGraph.tsx +163 -0
- package/bizar-dash/src/web/components/agents/QualityGates.tsx +123 -0
- package/bizar-dash/src/web/components/agents/RealTimeEventLog.tsx +127 -0
- package/bizar-dash/src/web/components/agents/RoutingDecisions.test.tsx +148 -0
- package/bizar-dash/src/web/components/agents/RoutingDecisions.tsx +160 -0
- package/bizar-dash/src/web/components/goals/GoalInput.tsx +86 -0
- package/bizar-dash/src/web/components/goals/PlanVisualization.tsx +111 -0
- package/bizar-dash/src/web/lib/goapPlanner.ts +614 -0
- package/bizar-dash/src/web/lib/types.ts +25 -0
- package/bizar-dash/src/web/styles/agents-redesign.css +311 -0
- package/bizar-dash/src/web/styles/main.css +251 -0
- package/bizar-dash/src/web/styles/tasks-redesign.css +231 -0
- package/bizar-dash/src/web/ui/controls/Button.tsx +77 -0
- package/bizar-dash/src/web/ui/controls/Checkbox.tsx +95 -0
- package/bizar-dash/src/web/ui/controls/IconButton.tsx +66 -0
- package/bizar-dash/src/web/ui/controls/Kbd.tsx +24 -0
- package/bizar-dash/src/web/ui/controls/NumberInput.tsx +77 -0
- package/bizar-dash/src/web/ui/controls/RadioGroup.tsx +109 -0
- package/bizar-dash/src/web/ui/controls/SearchInput.tsx +91 -0
- package/bizar-dash/src/web/ui/controls/Select.tsx +92 -0
- package/bizar-dash/src/web/ui/controls/Slider.tsx +70 -0
- package/bizar-dash/src/web/ui/controls/TextInput.tsx +67 -0
- package/bizar-dash/src/web/ui/controls/Toggle.tsx +79 -0
- package/bizar-dash/src/web/ui/controls/controls.css +454 -0
- package/bizar-dash/src/web/ui/controls/index.ts +33 -0
- package/bizar-dash/src/web/ui/data/BarChart.tsx +60 -0
- package/bizar-dash/src/web/ui/data/DataTable.tsx +216 -0
- package/bizar-dash/src/web/ui/data/EmptyState.tsx +60 -0
- package/bizar-dash/src/web/ui/data/ErrorState.tsx +56 -0
- package/bizar-dash/src/web/ui/data/KeyValueList.tsx +106 -0
- package/bizar-dash/src/web/ui/data/LoadingState.tsx +65 -0
- package/bizar-dash/src/web/ui/data/Sparkline.tsx +87 -0
- package/bizar-dash/src/web/ui/data/StatTile.tsx +87 -0
- package/bizar-dash/src/web/ui/data/data.css +535 -0
- package/bizar-dash/src/web/ui/data/index.ts +31 -0
- package/bizar-dash/src/web/ui/feedback/Badge.tsx +49 -0
- package/bizar-dash/src/web/ui/feedback/Dialog.tsx +209 -0
- package/bizar-dash/src/web/ui/feedback/ProgressBar.tsx +69 -0
- package/bizar-dash/src/web/ui/feedback/StatusDot.tsx +50 -0
- package/bizar-dash/src/web/ui/feedback/Toast.tsx +200 -0
- package/bizar-dash/src/web/ui/feedback/Tooltip.tsx +126 -0
- package/bizar-dash/src/web/ui/feedback/feedback.css +314 -0
- package/bizar-dash/src/web/ui/feedback/index.ts +43 -0
- package/bizar-dash/src/web/ui/index.ts +56 -0
- package/bizar-dash/src/web/ui/layout/AppShell.tsx +51 -0
- package/bizar-dash/src/web/ui/layout/Breadcrumbs.tsx +97 -0
- package/bizar-dash/src/web/ui/layout/Panel.tsx +73 -0
- package/bizar-dash/src/web/ui/layout/PanelHeader.tsx +39 -0
- package/bizar-dash/src/web/ui/layout/Sidebar.tsx +131 -0
- package/bizar-dash/src/web/ui/layout/Tabs.tsx +133 -0
- package/bizar-dash/src/web/ui/layout/Topbar.tsx +42 -0
- package/bizar-dash/src/web/ui/layout/index.ts +33 -0
- package/bizar-dash/src/web/ui/layout/layout.css +413 -0
- package/bizar-dash/src/web/ui/navigation/CommandPalette.tsx +199 -0
- package/bizar-dash/src/web/ui/navigation/NavGroup.tsx +95 -0
- package/bizar-dash/src/web/ui/navigation/NavLink.tsx +93 -0
- package/bizar-dash/src/web/ui/navigation/index.ts +17 -0
- package/bizar-dash/src/web/ui/navigation/navigation.css +343 -0
- package/bizar-dash/src/web/ui/primitives/Box.tsx +91 -0
- package/bizar-dash/src/web/ui/primitives/Grid.tsx +49 -0
- package/bizar-dash/src/web/ui/primitives/Inline.tsx +55 -0
- package/bizar-dash/src/web/ui/primitives/Separator.tsx +46 -0
- package/bizar-dash/src/web/ui/primitives/Stack.tsx +54 -0
- package/bizar-dash/src/web/ui/primitives/VisuallyHidden.tsx +26 -0
- package/bizar-dash/src/web/ui/primitives/index.ts +23 -0
- package/bizar-dash/src/web/ui/primitives/primitives.css +183 -0
- package/bizar-dash/src/web/ui/styles/globals.css +86 -0
- package/bizar-dash/src/web/ui/styles/reset.css +125 -0
- package/bizar-dash/src/web/ui/styles/tokens.css +195 -0
- package/bizar-dash/src/web/ui/theme/ThemeProvider.tsx +142 -0
- package/bizar-dash/src/web/ui/theme/tokens.ts +131 -0
- package/bizar-dash/src/web/ui/theme/useTheme.ts +22 -0
- package/bizar-dash/src/web/ui/utils/cx.ts +42 -0
- package/bizar-dash/src/web/views/Agents.tsx +506 -266
- package/bizar-dash/src/web/views/GoalPlanner.tsx +158 -0
- package/bizar-dash/src/web/views/Overview.tsx +996 -448
- package/bizar-dash/src/web/views/Tasks.tsx +277 -273
- package/bizar-dash/tests/communication-log.test.tsx +67 -0
- package/bizar-dash/tests/dep-graph.test.tsx +40 -0
- package/bizar-dash/tests/event-log.test.tsx +61 -0
- package/bizar-dash/tests/goal-input.test.tsx +72 -0
- package/bizar-dash/tests/goap-planner.test.ts +68 -0
- package/bizar-dash/tests/quality-gates.test.tsx +59 -0
- package/bizar-dash/tests/setup.ts +31 -1
- package/bizar-dash/tests/ui/controls/Button.test.tsx +50 -0
- package/bizar-dash/tests/ui/controls/Checkbox.test.tsx +44 -0
- package/bizar-dash/tests/ui/controls/IconButton.test.tsx +37 -0
- package/bizar-dash/tests/ui/controls/Kbd.test.tsx +39 -0
- package/bizar-dash/tests/ui/controls/NumberInput.test.tsx +56 -0
- package/bizar-dash/tests/ui/controls/RadioGroup.test.tsx +58 -0
- package/bizar-dash/tests/ui/controls/SearchInput.test.tsx +52 -0
- package/bizar-dash/tests/ui/controls/Select.test.tsx +66 -0
- package/bizar-dash/tests/ui/controls/Slider.test.tsx +41 -0
- package/bizar-dash/tests/ui/controls/TextInput.test.tsx +44 -0
- package/bizar-dash/tests/ui/controls/Toggle.test.tsx +39 -0
- package/bizar-dash/tests/ui/data/BarChart.test.tsx +55 -0
- package/bizar-dash/tests/ui/data/DataTable.test.tsx +112 -0
- package/bizar-dash/tests/ui/data/EmptyState.test.tsx +57 -0
- package/bizar-dash/tests/ui/data/ErrorState.test.tsx +47 -0
- package/bizar-dash/tests/ui/data/KeyValueList.test.tsx +59 -0
- package/bizar-dash/tests/ui/data/LoadingState.test.tsx +37 -0
- package/bizar-dash/tests/ui/data/Sparkline.test.tsx +56 -0
- package/bizar-dash/tests/ui/data/StatTile.test.tsx +69 -0
- package/bizar-dash/tests/ui/feedback/Badge.test.tsx +41 -0
- package/bizar-dash/tests/ui/feedback/Dialog.test.tsx +99 -0
- package/bizar-dash/tests/ui/feedback/ProgressBar.test.tsx +66 -0
- package/bizar-dash/tests/ui/feedback/StatusDot.test.tsx +41 -0
- package/bizar-dash/tests/ui/feedback/Toast.test.tsx +124 -0
- package/bizar-dash/tests/ui/feedback/Tooltip.test.tsx +102 -0
- package/bizar-dash/tests/ui/layout/AppShell.test.tsx +50 -0
- package/bizar-dash/tests/ui/layout/Breadcrumbs.test.tsx +85 -0
- package/bizar-dash/tests/ui/layout/Panel.test.tsx +52 -0
- package/bizar-dash/tests/ui/layout/PanelHeader.test.tsx +32 -0
- package/bizar-dash/tests/ui/layout/Sidebar.test.tsx +95 -0
- package/bizar-dash/tests/ui/layout/Tabs.test.tsx +87 -0
- package/bizar-dash/tests/ui/layout/Topbar.test.tsx +41 -0
- package/bizar-dash/tests/ui/navigation/CommandPalette.test.tsx +105 -0
- package/bizar-dash/tests/ui/navigation/NavGroup.test.tsx +55 -0
- package/bizar-dash/tests/ui/navigation/NavLink.test.tsx +61 -0
- package/bizar-dash/tests/ui/primitives/Box.test.tsx +49 -0
- package/bizar-dash/tests/ui/primitives/Grid.test.tsx +37 -0
- package/bizar-dash/tests/ui/primitives/Inline.test.tsx +33 -0
- package/bizar-dash/tests/ui/primitives/Separator.test.tsx +34 -0
- package/bizar-dash/tests/ui/primitives/Stack.test.tsx +45 -0
- package/bizar-dash/tests/ui/primitives/VisuallyHidden.test.tsx +27 -0
- package/bizar-dash/tests/views/Agents.test.tsx +359 -0
- package/bizar-dash/tests/views/Overview.test.tsx +413 -0
- package/bizar-dash/tests/views/Tasks.test.tsx +250 -0
- package/bizar-dash/vitest.config.ts +3 -1
- package/cli/__tests__/cost-gate.test.mjs +301 -0
- package/cli/__tests__/feature-list-bridge.test.mjs +371 -0
- package/cli/bin.mjs +38 -0
- package/cli/commands/claim.mjs +282 -0
- package/cli/commands/cost.mjs +279 -0
- package/cli/cost-gate.mjs +501 -0
- package/cli/feature-list-bridge.mjs +400 -0
- package/cli/memory-constants.mjs +17 -0
- package/cli/worker-dispatcher.mjs +259 -0
- package/cli/worker-dispatcher.test.mjs +204 -0
- package/config/trigger-patterns.json +186 -0
- package/package.json +2 -2
- package/packages/sdk/package.json +1 -1
- package/packages/sdk/src/agent-registry.ts +304 -0
- package/packages/sdk/src/consensus/byzantine.ts +587 -0
- package/packages/sdk/src/consensus/index.ts +147 -0
- package/packages/sdk/src/consensus/queen.ts +173 -0
- package/packages/sdk/src/consensus/types.ts +199 -0
- package/packages/sdk/src/federation/audit.ts +156 -0
- package/packages/sdk/src/federation/budget.ts +269 -0
- package/packages/sdk/src/federation/envelope.ts +144 -0
- package/packages/sdk/src/federation/hmac.ts +160 -0
- package/packages/sdk/src/federation/index.ts +443 -0
- package/packages/sdk/src/federation/pii.ts +241 -0
- package/packages/sdk/src/federation/policy.ts +112 -0
- package/packages/sdk/src/federation/trust.ts +146 -0
- package/packages/sdk/src/index.ts +67 -0
- package/packages/sdk/src/mcp/server.ts +351 -1
- package/packages/sdk/src/router/codemod-intent.ts +125 -0
- package/packages/sdk/src/router/index.ts +247 -0
- package/packages/sdk/src/router/memory-distillation-shim.mjs +18 -0
- package/packages/sdk/src/router/memory-distillation.ts +249 -0
- package/packages/sdk/src/router/model-router.ts +235 -0
- package/packages/sdk/src/router/q-learning-router.ts +304 -0
- package/packages/sdk/src/swarm-topology.ts +279 -0
- package/packages/sdk/tests/agent-registry.test.ts +285 -0
- package/packages/sdk/tests/consensus.test.ts +376 -0
- package/packages/sdk/tests/federation/audit.test.ts +164 -0
- package/packages/sdk/tests/federation/budget.test.ts +189 -0
- package/packages/sdk/tests/federation/envelope.test.ts +120 -0
- package/packages/sdk/tests/federation/hmac.test.ts +194 -0
- package/packages/sdk/tests/federation/orchestrator.test.ts +176 -0
- package/packages/sdk/tests/federation/pii.test.ts +106 -0
- package/packages/sdk/tests/federation/policy.test.ts +140 -0
- package/packages/sdk/tests/federation/trust.test.ts +124 -0
- package/packages/sdk/tests/mcp-tools.test.ts +204 -0
- package/packages/sdk/tests/memory-distillation.test.mjs +186 -0
- package/packages/sdk/tests/model-router.test.mjs +108 -0
- package/packages/sdk/tests/q-learning-router.test.mjs +100 -0
- package/packages/sdk/tests/router-orchestrator.test.mjs +172 -0
- package/packages/sdk/tests/router.test.mjs +91 -0
- package/packages/sdk/tests/sdk.test.mjs +26 -2
- package/packages/sdk/tests/swarm-topology.test.ts +258 -0
- package/scripts/bh-full-e2e.mjs +11 -15
- package/bizar-dash/dist/assets/MobileChat-BJrqwVDd.js +0 -1
- package/bizar-dash/dist/assets/MobileSettings-CEQNJNLJ.js +0 -1
- package/bizar-dash/dist/assets/icons-Do5N2jmX.js.map +0 -1
- package/bizar-dash/dist/assets/main-IvfQAOfy.js +0 -18
- package/bizar-dash/dist/assets/main-IvfQAOfy.js.map +0 -1
- package/bizar-dash/dist/assets/main-ietCEg_R.css +0 -1
- package/bizar-dash/dist/assets/markdown-tOLaD6nm.js +0 -1
- package/bizar-dash/dist/assets/mobile-DYCHcUpq.js +0 -1
- package/bizar-dash/dist/assets/mobile-layout-CBHjpwsb.js +0 -2
- package/bizar-dash/dist/assets/mobile-layout-CBHjpwsb.js.map +0 -1
- package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js +0 -40
- package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js.map +0 -1
- package/bizar-dash/dist/assets/useSlashCommands-Bd7_FA6U.js +0 -2
- package/bizar-dash/dist/assets/useSlashCommands-Bd7_FA6U.js.map +0 -1
- package/bizar-dash/dist/assets/vendor-C843201K.js +0 -29
- package/bizar-dash/dist/assets/vendor-C843201K.js.map +0 -1
- package/packages/sdk/package-lock.json +0 -32
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* federation/policy.ts — PolicyEngine: enforces per-call envelope
|
|
3
|
+
* constraints (maxHops, action allowlist, peer blocklist).
|
|
4
|
+
*
|
|
5
|
+
* F-038 — ported from ruflo
|
|
6
|
+
* `v3/@claude-flow/plugin-agent-federation/src/application/policy-engine.ts`
|
|
7
|
+
* but stripped to the three checks the skeleton needs:
|
|
8
|
+
*
|
|
9
|
+
* 1. maxHops — envelope.hopCount must be < budget.maxHops
|
|
10
|
+
* (default ceiling = 3 hops).
|
|
11
|
+
* 2. message — envelope.messageType must be in the action
|
|
12
|
+
* allowlist.
|
|
13
|
+
* 3. peer — source node must NOT be in the blocklist.
|
|
14
|
+
*
|
|
15
|
+
* `enforce(envelope, budget)` returns a discriminated result so
|
|
16
|
+
* callers can map directly to an MCP error string.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
FEDERATION_MESSAGE_TYPES,
|
|
21
|
+
isFederationMessageType,
|
|
22
|
+
type EnvelopeBudget,
|
|
23
|
+
type FederationEnvelope,
|
|
24
|
+
type FederationMessageType,
|
|
25
|
+
} from "./envelope.js";
|
|
26
|
+
|
|
27
|
+
/** Hard ceiling on hops — matches the spec's "≤ 3" rule. */
|
|
28
|
+
export const DEFAULT_MAX_HOPS = 3;
|
|
29
|
+
|
|
30
|
+
export type PolicyDecision =
|
|
31
|
+
| { allowed: true }
|
|
32
|
+
| {
|
|
33
|
+
allowed: false;
|
|
34
|
+
denialReason:
|
|
35
|
+
| "max_hops_exceeded"
|
|
36
|
+
| "message_type_not_allowed"
|
|
37
|
+
| "peer_blocked"
|
|
38
|
+
| "budget_missing"
|
|
39
|
+
| "budget_invalid";
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export interface PolicyConfig {
|
|
43
|
+
/** Set of message kinds accepted by this node. Defaults to all
|
|
44
|
+
* 16 ruflo kinds — narrow via `allowedMessageTypes`. */
|
|
45
|
+
readonly allowedMessageTypes?: readonly FederationMessageType[];
|
|
46
|
+
/** Set of sourceNodeIds that are NEVER accepted (blocklist). */
|
|
47
|
+
readonly peerBlocklist?: readonly string[];
|
|
48
|
+
/** Override the default maxHops ceiling. */
|
|
49
|
+
readonly maxHops?: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class PolicyEngine {
|
|
53
|
+
private readonly allowed: Set<FederationMessageType>;
|
|
54
|
+
private readonly blocked: Set<string>;
|
|
55
|
+
private readonly maxHops: number;
|
|
56
|
+
|
|
57
|
+
constructor(cfg: PolicyConfig = {}) {
|
|
58
|
+
this.allowed = new Set(cfg.allowedMessageTypes ?? FEDERATION_MESSAGE_TYPES);
|
|
59
|
+
this.blocked = new Set((cfg.peerBlocklist ?? []).map((s) => String(s)));
|
|
60
|
+
this.maxHops = cfg.maxHops ?? DEFAULT_MAX_HOPS;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Runtime mutator — narrow the allowlist after construction. */
|
|
64
|
+
allowMessageType(t: FederationMessageType): void {
|
|
65
|
+
this.allowed.add(t);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Runtime mutator — narrow the allowlist after construction. */
|
|
69
|
+
denyMessageType(t: FederationMessageType): void {
|
|
70
|
+
this.allowed.delete(t);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Runtime mutator — block / unblock a peer at runtime. */
|
|
74
|
+
setBlocked(nodeId: string, blocked: boolean): void {
|
|
75
|
+
if (blocked) this.blocked.add(nodeId);
|
|
76
|
+
else this.blocked.delete(nodeId);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Admit or reject an envelope given its budget context. */
|
|
80
|
+
enforce(envelope: FederationEnvelope, budget: EnvelopeBudget | undefined): PolicyDecision {
|
|
81
|
+
// 0. The budget object must exist — without it we can't enforce
|
|
82
|
+
// the maxHops ceiling.
|
|
83
|
+
if (!budget) return { allowed: false, denialReason: "budget_missing" };
|
|
84
|
+
if (typeof budget.maxHops !== "number" || !Number.isFinite(budget.maxHops)) {
|
|
85
|
+
return { allowed: false, denialReason: "budget_invalid" };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 1. Peer blocklist
|
|
89
|
+
if (this.blocked.has(envelope.sourceNodeId)) {
|
|
90
|
+
return { allowed: false, denialReason: "peer_blocked" };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 2. Message type allowlist
|
|
94
|
+
if (!isFederationMessageType(envelope.messageType)) {
|
|
95
|
+
return { allowed: false, denialReason: "message_type_not_allowed" };
|
|
96
|
+
}
|
|
97
|
+
if (!this.allowed.has(envelope.messageType)) {
|
|
98
|
+
return { allowed: false, denialReason: "message_type_not_allowed" };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 3. maxHops — current hopCount must be strictly LESS than the
|
|
102
|
+
// ceiling. A freshly-origin envelope has hopCount=0 so a
|
|
103
|
+
// maxHops=3 budget admits it.
|
|
104
|
+
const hopCount = envelope.hopCount ?? 0;
|
|
105
|
+
const effectiveCeiling = Math.min(budget.maxHops, this.maxHops);
|
|
106
|
+
if (hopCount >= effectiveCeiling) {
|
|
107
|
+
return { allowed: false, denialReason: "max_hops_exceeded" };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { allowed: true };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* federation/trust.ts — TrustEvaluator: peer allowlist + recent fail
|
|
3
|
+
* rate + envelope age → trust score.
|
|
4
|
+
*
|
|
5
|
+
* F-038 — ported from ruflo
|
|
6
|
+
* `v3/@claude-flow/plugin-agent-federation/src/application/trust-evaluator.ts`
|
|
7
|
+
* (computeScore shape), stripped down for the skeleton:
|
|
8
|
+
*
|
|
9
|
+
* evaluate(envelope, peer) → { allowed, reason, score }
|
|
10
|
+
*
|
|
11
|
+
* Inputs:
|
|
12
|
+
* - peer (PeerState): { nodeId, allowlisted, recentFailRate, lastSeenMs }
|
|
13
|
+
* - envelope: FederationEnvelope
|
|
14
|
+
*
|
|
15
|
+
* Scoring (pure function):
|
|
16
|
+
* baseScore = peer.allowlisted ? 0.6 : 0.0
|
|
17
|
+
* freshness = clamp(1 - ageMs / MAX_AGE_MS, 0, 1) * 0.2
|
|
18
|
+
* reliability = clamp(1 - peer.recentFailRate, 0, 1) * 0.2
|
|
19
|
+
* score = baseScore + freshness + reliability
|
|
20
|
+
*
|
|
21
|
+
* Decision:
|
|
22
|
+
* allowed = peer.allowlisted AND ageMs <= MAX_AGE_MS AND score >= MIN_SCORE
|
|
23
|
+
*
|
|
24
|
+
* State — per-node recent fail rate + last-seen are tracked
|
|
25
|
+
* in a Map so repeated calls from the same peer update the
|
|
26
|
+
* picture. Failures can be recorded via `recordFailure(nodeId)`.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { envelopeAgeMs, type FederationEnvelope } from "./envelope.js";
|
|
30
|
+
|
|
31
|
+
/** Maximum envelope age we'll trust (5 minutes — matches the
|
|
32
|
+
* HMAC freshness window). Older envelopes fail freshness
|
|
33
|
+
* independently of HMAC verification. */
|
|
34
|
+
export const MAX_TRUST_AGE_MS = 5 * 60 * 1000;
|
|
35
|
+
|
|
36
|
+
/** Minimum composite trust score required to admit an envelope. */
|
|
37
|
+
export const MIN_TRUST_SCORE = 0.7;
|
|
38
|
+
|
|
39
|
+
/** Number of recent failures tracked per peer for fail-rate calc. */
|
|
40
|
+
const FAILURE_WINDOW = 20;
|
|
41
|
+
|
|
42
|
+
export interface PeerState {
|
|
43
|
+
readonly nodeId: string;
|
|
44
|
+
readonly allowlisted: boolean;
|
|
45
|
+
/** Failure rate over the last `FAILURE_WINDOW` calls (0..1). */
|
|
46
|
+
readonly recentFailRate: number;
|
|
47
|
+
/** Last activity timestamp (ms epoch). Used as a tiebreaker. */
|
|
48
|
+
readonly lastSeenMs?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type TrustDecision =
|
|
52
|
+
| { allowed: true; score: number; reason: string }
|
|
53
|
+
| { allowed: false; score: number; reason: string };
|
|
54
|
+
|
|
55
|
+
export class TrustEvaluator {
|
|
56
|
+
private readonly allowlist: Set<string>;
|
|
57
|
+
private readonly failHistory = new Map<string, { failures: boolean[]; lastSeenMs: number }>();
|
|
58
|
+
|
|
59
|
+
constructor(opts: { allowlist?: readonly string[] } = {}) {
|
|
60
|
+
this.allowlist = new Set((opts.allowlist ?? []).map((s) => String(s)));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Add or remove a node from the trust allowlist at runtime. */
|
|
64
|
+
setAllowlisted(nodeId: string, allowlisted: boolean): void {
|
|
65
|
+
if (allowlisted) this.allowlist.add(nodeId);
|
|
66
|
+
else this.allowlist.delete(nodeId);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
isAllowlisted(nodeId: string): boolean {
|
|
70
|
+
return this.allowlist.has(nodeId);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Snapshot the per-peer state seen by `evaluate()`. */
|
|
74
|
+
getPeerState(nodeId: string, _now: number = Date.now()): PeerState {
|
|
75
|
+
const rec = this.failHistory.get(nodeId);
|
|
76
|
+
const total = rec?.failures.length ?? 0;
|
|
77
|
+
const failures = rec?.failures.filter((b) => b).length ?? 0;
|
|
78
|
+
return {
|
|
79
|
+
nodeId,
|
|
80
|
+
allowlisted: this.allowlist.has(nodeId),
|
|
81
|
+
recentFailRate: total === 0 ? 0 : failures / total,
|
|
82
|
+
lastSeenMs: rec?.lastSeenMs,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Record that an exchange with `nodeId` succeeded/failed. Sliding
|
|
87
|
+
* window of `FAILURE_WINDOW` most-recent events. */
|
|
88
|
+
recordOutcome(nodeId: string, ok: boolean, now: number = Date.now()): void {
|
|
89
|
+
const rec = this.failHistory.get(nodeId) ?? { failures: [], lastSeenMs: now };
|
|
90
|
+
rec.failures.push(!ok);
|
|
91
|
+
if (rec.failures.length > FAILURE_WINDOW) rec.failures.shift();
|
|
92
|
+
rec.lastSeenMs = now;
|
|
93
|
+
this.failHistory.set(nodeId, rec);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Compute the trust score (0..1). Pure function — useful for tests
|
|
97
|
+
* and for the orchestrator's `status` tool.
|
|
98
|
+
*
|
|
99
|
+
* baseScore = 0.3 if allowlisted else 0.0 (allowlist is necessary, not sufficient)
|
|
100
|
+
* freshness = (1 - ageMs / MAX_TRUST_AGE_MS) * 0.3 (envelope must be fresh)
|
|
101
|
+
* reliability = (1 - peer.recentFailRate) * 0.4 (peer must be reliable)
|
|
102
|
+
*
|
|
103
|
+
* MIN_TRUST_SCORE = 0.5 — a peer needs AT LEAST 2 of the 3 axes
|
|
104
|
+
* in good standing to pass.
|
|
105
|
+
*/
|
|
106
|
+
computeScore(envelope: FederationEnvelope, peer: PeerState, now: number = Date.now()): number {
|
|
107
|
+
if (!peer.allowlisted) return 0;
|
|
108
|
+
const baseScore = 0.3;
|
|
109
|
+
const ageMs = envelopeAgeMs(envelope, now);
|
|
110
|
+
const freshness = Math.max(0, Math.min(1, 1 - ageMs / MAX_TRUST_AGE_MS)) * 0.3;
|
|
111
|
+
const reliability = Math.max(0, Math.min(1, 1 - peer.recentFailRate)) * 0.4;
|
|
112
|
+
return Math.max(0, Math.min(1, baseScore + freshness + reliability));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Admit or reject an envelope based on the per-peer trust state. */
|
|
116
|
+
evaluate(envelope: FederationEnvelope, peer: PeerState, now: number = Date.now()): TrustDecision {
|
|
117
|
+
if (!peer.allowlisted) {
|
|
118
|
+
return {
|
|
119
|
+
allowed: false,
|
|
120
|
+
score: 0,
|
|
121
|
+
reason: `peer_not_allowlisted: ${peer.nodeId}`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
const ageMs = envelopeAgeMs(envelope, now);
|
|
125
|
+
if (ageMs > MAX_TRUST_AGE_MS) {
|
|
126
|
+
return {
|
|
127
|
+
allowed: false,
|
|
128
|
+
score: 0,
|
|
129
|
+
reason: `envelope_too_old: ${ageMs}ms`,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const score = this.computeScore(envelope, peer, now);
|
|
133
|
+
if (score < MIN_TRUST_SCORE) {
|
|
134
|
+
return {
|
|
135
|
+
allowed: false,
|
|
136
|
+
score,
|
|
137
|
+
reason: `score_below_floor: ${score.toFixed(3)} < ${MIN_TRUST_SCORE}`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
allowed: true,
|
|
142
|
+
score,
|
|
143
|
+
reason: `score=${score.toFixed(3)} (peer_allowlisted=true, age=${ageMs}ms, fail_rate=${peer.recentFailRate.toFixed(3)})`,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -44,4 +44,71 @@ export {
|
|
|
44
44
|
} from "./mcp/server.js";
|
|
45
45
|
export type { SdkMcpToolDef, SdkMcpServerConfig } from "./mcp/server.js";
|
|
46
46
|
|
|
47
|
+
// F-032 — Swarm coordination primitives.
|
|
48
|
+
export {
|
|
49
|
+
BizarAgentRegistry,
|
|
50
|
+
bizarAgentRegistry,
|
|
51
|
+
} from "./agent-registry.js";
|
|
52
|
+
export type {
|
|
53
|
+
AgentRecord,
|
|
54
|
+
AgentStatus,
|
|
55
|
+
RegisterAgentInput,
|
|
56
|
+
RegisterAgentResult,
|
|
57
|
+
ListAgentsInput,
|
|
58
|
+
ListAgentsResult,
|
|
59
|
+
TerminateAgentInput,
|
|
60
|
+
TerminateAgentResult,
|
|
61
|
+
} from "./agent-registry.js";
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
SwarmTopologyRegistry,
|
|
65
|
+
swarmTopologyRegistry,
|
|
66
|
+
initSwarm,
|
|
67
|
+
getSwarm,
|
|
68
|
+
listSwarms,
|
|
69
|
+
recordAgentInSwarm,
|
|
70
|
+
decommissionSwarm,
|
|
71
|
+
SWARM_TOPOLOGIES,
|
|
72
|
+
DEFAULT_TOPOLOGY,
|
|
73
|
+
DEFAULT_MAX_AGENTS,
|
|
74
|
+
DEFAULT_SWARM_ID,
|
|
75
|
+
} from "./swarm-topology.js";
|
|
76
|
+
export type {
|
|
77
|
+
SwarmRecord,
|
|
78
|
+
SwarmTopology,
|
|
79
|
+
InitSwarmInput,
|
|
80
|
+
InitSwarmResult,
|
|
81
|
+
} from "./swarm-topology.js";
|
|
82
|
+
|
|
83
|
+
// F-039 — Byzantine fault-tolerant consensus (thin PBFT port).
|
|
84
|
+
export {
|
|
85
|
+
ByzantineConsensus,
|
|
86
|
+
type ByzantineConsensusOpts,
|
|
87
|
+
QueenCoordinator,
|
|
88
|
+
type QueenCoordinatorOpts,
|
|
89
|
+
createConsensus,
|
|
90
|
+
getSharedConsensus,
|
|
91
|
+
resetSharedConsensus,
|
|
92
|
+
type ConsensusHandle,
|
|
93
|
+
type CreateConsensusOpts,
|
|
94
|
+
PHASE_ORDER,
|
|
95
|
+
DEFAULT_QUORUM,
|
|
96
|
+
DEFAULT_PEER_COUNT,
|
|
97
|
+
DEFAULT_MAX_FAULTS,
|
|
98
|
+
} from "./consensus/index.js";
|
|
99
|
+
export type {
|
|
100
|
+
CommitResult,
|
|
101
|
+
ConsensusOpts,
|
|
102
|
+
ConsensusStatus,
|
|
103
|
+
Decision,
|
|
104
|
+
Phase,
|
|
105
|
+
ProposeResult,
|
|
106
|
+
Proposal,
|
|
107
|
+
ProposalSnapshot,
|
|
108
|
+
ProposalStatus,
|
|
109
|
+
Vote,
|
|
110
|
+
VoteResult,
|
|
111
|
+
ViewChangeResult,
|
|
112
|
+
} from "./consensus/types.js";
|
|
113
|
+
|
|
47
114
|
export { SDK_VERSION } from "./version.js";
|