@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.
Files changed (63) hide show
  1. package/README.md +38 -1
  2. package/bin/castle.js +94 -0
  3. package/install.sh +722 -0
  4. package/next.config.ts +7 -0
  5. package/package.json +54 -5
  6. package/postcss.config.mjs +7 -0
  7. package/src/app/api/avatars/[id]/route.ts +75 -0
  8. package/src/app/api/openclaw/agents/route.ts +107 -0
  9. package/src/app/api/openclaw/config/route.ts +94 -0
  10. package/src/app/api/openclaw/events/route.ts +96 -0
  11. package/src/app/api/openclaw/logs/route.ts +59 -0
  12. package/src/app/api/openclaw/ping/route.ts +68 -0
  13. package/src/app/api/openclaw/restart/route.ts +65 -0
  14. package/src/app/api/openclaw/sessions/route.ts +62 -0
  15. package/src/app/globals.css +286 -0
  16. package/src/app/icon.png +0 -0
  17. package/src/app/layout.tsx +42 -0
  18. package/src/app/page.tsx +269 -0
  19. package/src/app/ui-kit/page.tsx +684 -0
  20. package/src/cli/onboarding.ts +576 -0
  21. package/src/components/dashboard/agent-status.tsx +107 -0
  22. package/src/components/dashboard/glass-card.tsx +28 -0
  23. package/src/components/dashboard/goal-widget.tsx +174 -0
  24. package/src/components/dashboard/greeting-widget.tsx +78 -0
  25. package/src/components/dashboard/index.ts +7 -0
  26. package/src/components/dashboard/stat-widget.tsx +61 -0
  27. package/src/components/dashboard/stock-widget.tsx +164 -0
  28. package/src/components/dashboard/weather-widget.tsx +68 -0
  29. package/src/components/icons/castle-icon.tsx +21 -0
  30. package/src/components/kanban/index.ts +3 -0
  31. package/src/components/kanban/kanban-board.tsx +391 -0
  32. package/src/components/kanban/kanban-card.tsx +137 -0
  33. package/src/components/kanban/kanban-column.tsx +98 -0
  34. package/src/components/layout/index.ts +4 -0
  35. package/src/components/layout/page-header.tsx +20 -0
  36. package/src/components/layout/sidebar.tsx +128 -0
  37. package/src/components/layout/theme-toggle.tsx +59 -0
  38. package/src/components/layout/user-menu.tsx +72 -0
  39. package/src/components/ui/alert.tsx +72 -0
  40. package/src/components/ui/avatar.tsx +87 -0
  41. package/src/components/ui/badge.tsx +39 -0
  42. package/src/components/ui/button.tsx +43 -0
  43. package/src/components/ui/card.tsx +107 -0
  44. package/src/components/ui/checkbox.tsx +56 -0
  45. package/src/components/ui/clock.tsx +171 -0
  46. package/src/components/ui/dialog.tsx +105 -0
  47. package/src/components/ui/index.ts +34 -0
  48. package/src/components/ui/input.tsx +112 -0
  49. package/src/components/ui/option-card.tsx +151 -0
  50. package/src/components/ui/progress.tsx +103 -0
  51. package/src/components/ui/radio.tsx +109 -0
  52. package/src/components/ui/select.tsx +46 -0
  53. package/src/components/ui/slider.tsx +62 -0
  54. package/src/components/ui/tabs.tsx +132 -0
  55. package/src/components/ui/toggle-group.tsx +85 -0
  56. package/src/components/ui/toggle.tsx +78 -0
  57. package/src/components/ui/tooltip.tsx +145 -0
  58. package/src/components/ui/uptime.tsx +106 -0
  59. package/src/lib/config.ts +195 -0
  60. package/src/lib/gateway-connection.ts +391 -0
  61. package/src/lib/hooks/use-openclaw.ts +163 -0
  62. package/src/lib/utils.ts +6 -0
  63. 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
+ }
@@ -0,0 +1,6 @@
1
+ import { type ClassValue, clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
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
+ }