@castlekit/castle 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -1
- package/bin/castle.js +94 -0
- package/install.sh +722 -0
- package/next.config.ts +7 -0
- package/package.json +54 -5
- package/postcss.config.mjs +7 -0
- package/src/app/api/avatars/[id]/route.ts +75 -0
- package/src/app/api/openclaw/agents/route.ts +107 -0
- package/src/app/api/openclaw/config/route.ts +94 -0
- package/src/app/api/openclaw/events/route.ts +96 -0
- package/src/app/api/openclaw/logs/route.ts +59 -0
- package/src/app/api/openclaw/ping/route.ts +68 -0
- package/src/app/api/openclaw/restart/route.ts +65 -0
- package/src/app/api/openclaw/sessions/route.ts +62 -0
- package/src/app/globals.css +286 -0
- package/src/app/icon.png +0 -0
- package/src/app/layout.tsx +42 -0
- package/src/app/page.tsx +269 -0
- package/src/app/ui-kit/page.tsx +684 -0
- package/src/cli/onboarding.ts +576 -0
- package/src/components/dashboard/agent-status.tsx +107 -0
- package/src/components/dashboard/glass-card.tsx +28 -0
- package/src/components/dashboard/goal-widget.tsx +174 -0
- package/src/components/dashboard/greeting-widget.tsx +78 -0
- package/src/components/dashboard/index.ts +7 -0
- package/src/components/dashboard/stat-widget.tsx +61 -0
- package/src/components/dashboard/stock-widget.tsx +164 -0
- package/src/components/dashboard/weather-widget.tsx +68 -0
- package/src/components/icons/castle-icon.tsx +21 -0
- package/src/components/kanban/index.ts +3 -0
- package/src/components/kanban/kanban-board.tsx +391 -0
- package/src/components/kanban/kanban-card.tsx +137 -0
- package/src/components/kanban/kanban-column.tsx +98 -0
- package/src/components/layout/index.ts +4 -0
- package/src/components/layout/page-header.tsx +20 -0
- package/src/components/layout/sidebar.tsx +128 -0
- package/src/components/layout/theme-toggle.tsx +59 -0
- package/src/components/layout/user-menu.tsx +72 -0
- package/src/components/ui/alert.tsx +72 -0
- package/src/components/ui/avatar.tsx +87 -0
- package/src/components/ui/badge.tsx +39 -0
- package/src/components/ui/button.tsx +43 -0
- package/src/components/ui/card.tsx +107 -0
- package/src/components/ui/checkbox.tsx +56 -0
- package/src/components/ui/clock.tsx +171 -0
- package/src/components/ui/dialog.tsx +105 -0
- package/src/components/ui/index.ts +34 -0
- package/src/components/ui/input.tsx +112 -0
- package/src/components/ui/option-card.tsx +151 -0
- package/src/components/ui/progress.tsx +103 -0
- package/src/components/ui/radio.tsx +109 -0
- package/src/components/ui/select.tsx +46 -0
- package/src/components/ui/slider.tsx +62 -0
- package/src/components/ui/tabs.tsx +132 -0
- package/src/components/ui/toggle-group.tsx +85 -0
- package/src/components/ui/toggle.tsx +78 -0
- package/src/components/ui/tooltip.tsx +145 -0
- package/src/components/ui/uptime.tsx +106 -0
- package/src/lib/config.ts +195 -0
- package/src/lib/gateway-connection.ts +391 -0
- package/src/lib/hooks/use-openclaw.ts +163 -0
- package/src/lib/utils.ts +6 -0
- package/tsconfig.json +34 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect, useCallback, useRef } from "react";
|
|
4
|
+
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// Types
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
export interface OpenClawAgent {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
description: string | null;
|
|
13
|
+
avatar: string | null;
|
|
14
|
+
emoji: string | null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface OpenClawStatus {
|
|
18
|
+
ok: boolean;
|
|
19
|
+
configured: boolean;
|
|
20
|
+
latency_ms?: number;
|
|
21
|
+
state?: string;
|
|
22
|
+
error?: string;
|
|
23
|
+
server?: {
|
|
24
|
+
version?: string;
|
|
25
|
+
connId?: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface GatewaySSEEvent {
|
|
30
|
+
event: string;
|
|
31
|
+
payload?: unknown;
|
|
32
|
+
seq?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Hook
|
|
37
|
+
// ============================================================================
|
|
38
|
+
|
|
39
|
+
export function useOpenClaw() {
|
|
40
|
+
const [status, setStatus] = useState<OpenClawStatus | null>(null);
|
|
41
|
+
const [agents, setAgents] = useState<OpenClawAgent[]>([]);
|
|
42
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
43
|
+
const [agentsLoading, setAgentsLoading] = useState(true);
|
|
44
|
+
const eventSourceRef = useRef<EventSource | null>(null);
|
|
45
|
+
|
|
46
|
+
// Fetch connection status
|
|
47
|
+
const fetchStatus = useCallback(async () => {
|
|
48
|
+
try {
|
|
49
|
+
const res = await fetch("/api/openclaw/ping", { method: "POST" });
|
|
50
|
+
const data: OpenClawStatus = await res.json();
|
|
51
|
+
setStatus(data);
|
|
52
|
+
return data;
|
|
53
|
+
} catch {
|
|
54
|
+
setStatus({ ok: false, configured: false, error: "Failed to reach Castle server" });
|
|
55
|
+
return null;
|
|
56
|
+
} finally {
|
|
57
|
+
setIsLoading(false);
|
|
58
|
+
}
|
|
59
|
+
}, []);
|
|
60
|
+
|
|
61
|
+
// Fetch agents
|
|
62
|
+
const fetchAgents = useCallback(async () => {
|
|
63
|
+
try {
|
|
64
|
+
setAgentsLoading(true);
|
|
65
|
+
const res = await fetch("/api/openclaw/agents");
|
|
66
|
+
if (!res.ok) {
|
|
67
|
+
setAgents([]);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const data = await res.json();
|
|
71
|
+
setAgents(data.agents || []);
|
|
72
|
+
} catch {
|
|
73
|
+
setAgents([]);
|
|
74
|
+
} finally {
|
|
75
|
+
setAgentsLoading(false);
|
|
76
|
+
}
|
|
77
|
+
}, []);
|
|
78
|
+
|
|
79
|
+
// Refresh everything
|
|
80
|
+
const refresh = useCallback(async () => {
|
|
81
|
+
const newStatus = await fetchStatus();
|
|
82
|
+
if (newStatus?.ok) {
|
|
83
|
+
await fetchAgents();
|
|
84
|
+
}
|
|
85
|
+
}, [fetchStatus, fetchAgents]);
|
|
86
|
+
|
|
87
|
+
// Initial data fetch
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
let cancelled = false;
|
|
90
|
+
|
|
91
|
+
async function init() {
|
|
92
|
+
const s = await fetchStatus();
|
|
93
|
+
if (!cancelled && s?.ok) {
|
|
94
|
+
await fetchAgents();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
init();
|
|
99
|
+
return () => { cancelled = true; };
|
|
100
|
+
}, [fetchStatus, fetchAgents]);
|
|
101
|
+
|
|
102
|
+
// SSE subscription for real-time events
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
const es = new EventSource("/api/openclaw/events");
|
|
105
|
+
eventSourceRef.current = es;
|
|
106
|
+
|
|
107
|
+
es.onmessage = (e) => {
|
|
108
|
+
try {
|
|
109
|
+
const evt: GatewaySSEEvent = JSON.parse(e.data);
|
|
110
|
+
|
|
111
|
+
// Handle Castle state changes
|
|
112
|
+
if (evt.event === "castle.state") {
|
|
113
|
+
const payload = evt.payload as { state: string; isConnected: boolean; server?: Record<string, unknown> };
|
|
114
|
+
setStatus((prev) => ({
|
|
115
|
+
ok: payload.isConnected,
|
|
116
|
+
configured: prev?.configured ?? true,
|
|
117
|
+
state: payload.state,
|
|
118
|
+
server: payload.server as OpenClawStatus["server"],
|
|
119
|
+
}));
|
|
120
|
+
|
|
121
|
+
// Re-fetch agents when connection state changes to connected
|
|
122
|
+
if (payload.isConnected) {
|
|
123
|
+
fetchAgents();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Handle agent-related events -- re-fetch agent list
|
|
128
|
+
if (evt.event?.startsWith("agent.")) {
|
|
129
|
+
fetchAgents();
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
// Ignore parse errors
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
es.onerror = () => {
|
|
137
|
+
// EventSource auto-reconnects, but update state
|
|
138
|
+
setStatus((prev) => prev ? { ...prev, ok: false, state: "disconnected" } : prev);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return () => {
|
|
142
|
+
es.close();
|
|
143
|
+
eventSourceRef.current = null;
|
|
144
|
+
};
|
|
145
|
+
}, [fetchAgents]);
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
// Status
|
|
149
|
+
status,
|
|
150
|
+
isLoading,
|
|
151
|
+
isConnected: status?.ok ?? false,
|
|
152
|
+
isConfigured: status?.configured ?? false,
|
|
153
|
+
latency: status?.latency_ms,
|
|
154
|
+
serverVersion: status?.server?.version,
|
|
155
|
+
|
|
156
|
+
// Agents
|
|
157
|
+
agents,
|
|
158
|
+
agentsLoading,
|
|
159
|
+
|
|
160
|
+
// Actions
|
|
161
|
+
refresh,
|
|
162
|
+
};
|
|
163
|
+
}
|
package/src/lib/utils.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [
|
|
17
|
+
{
|
|
18
|
+
"name": "next"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["./src/*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"include": [
|
|
26
|
+
"next-env.d.ts",
|
|
27
|
+
"**/*.ts",
|
|
28
|
+
"**/*.tsx",
|
|
29
|
+
".next/types/**/*.ts",
|
|
30
|
+
".next/dev/types/**/*.ts",
|
|
31
|
+
"**/*.mts"
|
|
32
|
+
],
|
|
33
|
+
"exclude": ["node_modules"]
|
|
34
|
+
}
|