@praveencs/agent 0.9.29 → 0.10.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 (268) hide show
  1. package/README.md +55 -9
  2. package/ROADMAP.md +42 -50
  3. package/agent-skills/README.md +192 -0
  4. package/agent-skills/plugins/aws/plugin.json +22 -0
  5. package/agent-skills/plugins/aws/skills/aws-manager.md +17 -0
  6. package/agent-skills/plugins/aws/tools/aws.js +152 -0
  7. package/agent-skills/plugins/discord/plugin.json +22 -0
  8. package/agent-skills/plugins/discord/skills/discord-manager.md +15 -0
  9. package/agent-skills/plugins/discord/tools/discord.js +150 -0
  10. package/agent-skills/plugins/docker/plugin.json +21 -0
  11. package/agent-skills/plugins/docker/skills/docker-manager.md +15 -0
  12. package/agent-skills/plugins/docker/tools/docker.js +135 -0
  13. package/agent-skills/plugins/firebase/plugin.json +22 -0
  14. package/agent-skills/plugins/firebase/skills/firebase-manager.md +14 -0
  15. package/agent-skills/plugins/firebase/tools/firebase.js +157 -0
  16. package/agent-skills/plugins/github/plugin.json +23 -0
  17. package/agent-skills/plugins/github/skills/github-manager.md +15 -0
  18. package/agent-skills/plugins/github/tools/github.js +133 -0
  19. package/agent-skills/plugins/huggingface/plugin.json +22 -0
  20. package/agent-skills/plugins/huggingface/skills/huggingface-manager.md +16 -0
  21. package/agent-skills/plugins/huggingface/tools/huggingface.js +149 -0
  22. package/agent-skills/plugins/linear/plugin.json +22 -0
  23. package/agent-skills/plugins/linear/skills/linear-manager.md +16 -0
  24. package/agent-skills/plugins/linear/tools/linear.js +199 -0
  25. package/agent-skills/plugins/mongodb/plugin.json +21 -0
  26. package/agent-skills/plugins/mongodb/skills/mongodb-manager.md +14 -0
  27. package/agent-skills/plugins/mongodb/tools/mongodb.js +123 -0
  28. package/agent-skills/plugins/notion/plugin.json +22 -0
  29. package/agent-skills/plugins/notion/skills/notion-manager.md +16 -0
  30. package/agent-skills/plugins/notion/tools/notion.js +158 -0
  31. package/agent-skills/plugins/openai/plugin.json +23 -0
  32. package/agent-skills/plugins/openai/skills/openai-manager.md +15 -0
  33. package/agent-skills/plugins/openai/tools/openai.js +137 -0
  34. package/agent-skills/plugins/resend/plugin.json +21 -0
  35. package/agent-skills/plugins/resend/skills/resend-manager.md +15 -0
  36. package/agent-skills/plugins/resend/tools/resend.js +102 -0
  37. package/agent-skills/plugins/slack/plugin.json +22 -0
  38. package/agent-skills/plugins/slack/skills/slack-manager.md +15 -0
  39. package/agent-skills/plugins/slack/tools/slack.js +168 -0
  40. package/agent-skills/plugins/stripe/plugin.json +22 -0
  41. package/agent-skills/plugins/stripe/skills/stripe-manager.md +16 -0
  42. package/agent-skills/plugins/stripe/tools/stripe.js +174 -0
  43. package/agent-skills/plugins/supabase/plugin.json +22 -0
  44. package/agent-skills/plugins/supabase/skills/supabase-manager.md +16 -0
  45. package/agent-skills/plugins/supabase/tools/supabase.js +153 -0
  46. package/agent-skills/plugins/telegram/plugin.json +21 -0
  47. package/agent-skills/plugins/telegram/skills/telegram-manager.md +14 -0
  48. package/agent-skills/plugins/telegram/tools/telegram.js +131 -0
  49. package/agent-skills/plugins/vercel/plugin.json +22 -0
  50. package/agent-skills/plugins/vercel/skills/vercel-manager.md +15 -0
  51. package/agent-skills/plugins/vercel/tools/vercel.js +145 -0
  52. package/agent-skills/registry.json +675 -0
  53. package/agent-skills/skills/api-tester/prompt.md +27 -0
  54. package/agent-skills/skills/api-tester/skill.json +16 -0
  55. package/agent-skills/skills/backup/prompt.md +12 -0
  56. package/agent-skills/skills/backup/skill.json +1 -0
  57. package/agent-skills/skills/code-review/prompt.md +29 -0
  58. package/agent-skills/skills/code-review/skill.json +18 -0
  59. package/agent-skills/skills/create-note/prompt.md +21 -0
  60. package/agent-skills/skills/create-note/skill.json +15 -0
  61. package/agent-skills/skills/cron-scheduler/prompt.md +25 -0
  62. package/agent-skills/skills/cron-scheduler/skill.json +1 -0
  63. package/agent-skills/skills/db-query/prompt.md +12 -0
  64. package/agent-skills/skills/db-query/skill.json +1 -0
  65. package/agent-skills/skills/docker-deploy/prompt.md +21 -0
  66. package/agent-skills/skills/docker-deploy/skill.json +16 -0
  67. package/agent-skills/skills/file-organizer/prompt.md +32 -0
  68. package/agent-skills/skills/file-organizer/skill.json +19 -0
  69. package/agent-skills/skills/git-commit/prompt.md +21 -0
  70. package/agent-skills/skills/git-commit/skill.json +17 -0
  71. package/agent-skills/skills/log-analyzer/prompt.md +16 -0
  72. package/agent-skills/skills/log-analyzer/skill.json +1 -0
  73. package/agent-skills/skills/npm-publish/prompt.md +24 -0
  74. package/agent-skills/skills/npm-publish/skill.json +20 -0
  75. package/agent-skills/skills/open-vscode/prompt.md +8 -0
  76. package/agent-skills/skills/open-vscode/skill.json +15 -0
  77. package/agent-skills/skills/project-scaffold/prompt.md +43 -0
  78. package/agent-skills/skills/project-scaffold/skill.json +17 -0
  79. package/agent-skills/skills/send-email/prompt.md +19 -0
  80. package/agent-skills/skills/send-email/send.js +60 -0
  81. package/agent-skills/skills/send-email/skill.json +16 -0
  82. package/agent-skills/skills/system-monitor/prompt.md +27 -0
  83. package/agent-skills/skills/system-monitor/skill.json +15 -0
  84. package/agent-skills/skills/web-search/prompt.md +26 -0
  85. package/agent-skills/skills/web-search/skill.json +16 -0
  86. package/dist/src/cli/commands/desktop.d.ts +3 -0
  87. package/dist/src/cli/commands/desktop.d.ts.map +1 -0
  88. package/dist/src/cli/commands/desktop.js +80 -0
  89. package/dist/src/cli/commands/desktop.js.map +1 -0
  90. package/dist/src/cli/commands/multimodal.d.ts +3 -0
  91. package/dist/src/cli/commands/multimodal.d.ts.map +1 -0
  92. package/dist/src/cli/commands/multimodal.js +78 -0
  93. package/dist/src/cli/commands/multimodal.js.map +1 -0
  94. package/dist/src/cli/commands/plugins.d.ts.map +1 -1
  95. package/dist/src/cli/commands/plugins.js +63 -12
  96. package/dist/src/cli/commands/plugins.js.map +1 -1
  97. package/dist/src/cli/commands/sandbox.d.ts +3 -0
  98. package/dist/src/cli/commands/sandbox.d.ts.map +1 -0
  99. package/dist/src/cli/commands/sandbox.js +89 -0
  100. package/dist/src/cli/commands/sandbox.js.map +1 -0
  101. package/dist/src/cli/commands/skills.d.ts.map +1 -1
  102. package/dist/src/cli/commands/skills.js +52 -121
  103. package/dist/src/cli/commands/skills.js.map +1 -1
  104. package/dist/src/cli/commands/swarm.d.ts +3 -0
  105. package/dist/src/cli/commands/swarm.d.ts.map +1 -0
  106. package/dist/src/cli/commands/swarm.js +120 -0
  107. package/dist/src/cli/commands/swarm.js.map +1 -0
  108. package/dist/src/cli/index.d.ts.map +1 -1
  109. package/dist/src/cli/index.js +8 -0
  110. package/dist/src/cli/index.js.map +1 -1
  111. package/dist/src/config/defaults.d.ts.map +1 -1
  112. package/dist/src/config/defaults.js +42 -0
  113. package/dist/src/config/defaults.js.map +1 -1
  114. package/dist/src/config/loader.d.ts +4 -0
  115. package/dist/src/config/loader.d.ts.map +1 -1
  116. package/dist/src/config/loader.js +27 -6
  117. package/dist/src/config/loader.js.map +1 -1
  118. package/dist/src/config/schema.d.ts +261 -0
  119. package/dist/src/config/schema.d.ts.map +1 -1
  120. package/dist/src/config/schema.js +58 -0
  121. package/dist/src/config/schema.js.map +1 -1
  122. package/dist/src/desktop/engine.d.ts +42 -0
  123. package/dist/src/desktop/engine.d.ts.map +1 -0
  124. package/dist/src/desktop/engine.js +77 -0
  125. package/dist/src/desktop/engine.js.map +1 -0
  126. package/dist/src/desktop/index.d.ts +6 -0
  127. package/dist/src/desktop/index.d.ts.map +1 -0
  128. package/dist/src/desktop/index.js +6 -0
  129. package/dist/src/desktop/index.js.map +1 -0
  130. package/dist/src/desktop/input.d.ts +20 -0
  131. package/dist/src/desktop/input.d.ts.map +1 -0
  132. package/dist/src/desktop/input.js +160 -0
  133. package/dist/src/desktop/input.js.map +1 -0
  134. package/dist/src/desktop/screen.d.ts +17 -0
  135. package/dist/src/desktop/screen.d.ts.map +1 -0
  136. package/dist/src/desktop/screen.js +120 -0
  137. package/dist/src/desktop/screen.js.map +1 -0
  138. package/dist/src/desktop/types.d.ts +50 -0
  139. package/dist/src/desktop/types.d.ts.map +1 -0
  140. package/dist/src/desktop/types.js +10 -0
  141. package/dist/src/desktop/types.js.map +1 -0
  142. package/dist/src/hub/lockfile.d.ts +29 -0
  143. package/dist/src/hub/lockfile.d.ts.map +1 -0
  144. package/dist/src/hub/lockfile.js +72 -0
  145. package/dist/src/hub/lockfile.js.map +1 -0
  146. package/dist/src/hub/publisher.d.ts +13 -0
  147. package/dist/src/hub/publisher.d.ts.map +1 -0
  148. package/dist/src/hub/publisher.js +159 -0
  149. package/dist/src/hub/publisher.js.map +1 -0
  150. package/dist/src/hub/registry.d.ts +40 -0
  151. package/dist/src/hub/registry.d.ts.map +1 -0
  152. package/dist/src/hub/registry.js +123 -0
  153. package/dist/src/hub/registry.js.map +1 -0
  154. package/dist/src/multimodal/engine.d.ts +33 -0
  155. package/dist/src/multimodal/engine.d.ts.map +1 -0
  156. package/dist/src/multimodal/engine.js +63 -0
  157. package/dist/src/multimodal/engine.js.map +1 -0
  158. package/dist/src/multimodal/index.d.ts +7 -0
  159. package/dist/src/multimodal/index.d.ts.map +1 -0
  160. package/dist/src/multimodal/index.js +7 -0
  161. package/dist/src/multimodal/index.js.map +1 -0
  162. package/dist/src/multimodal/tts.d.ts +11 -0
  163. package/dist/src/multimodal/tts.d.ts.map +1 -0
  164. package/dist/src/multimodal/tts.js +48 -0
  165. package/dist/src/multimodal/tts.js.map +1 -0
  166. package/dist/src/multimodal/types.d.ts +55 -0
  167. package/dist/src/multimodal/types.d.ts.map +1 -0
  168. package/dist/src/multimodal/types.js +20 -0
  169. package/dist/src/multimodal/types.js.map +1 -0
  170. package/dist/src/multimodal/vision.d.ts +15 -0
  171. package/dist/src/multimodal/vision.d.ts.map +1 -0
  172. package/dist/src/multimodal/vision.js +98 -0
  173. package/dist/src/multimodal/vision.js.map +1 -0
  174. package/dist/src/multimodal/voice.d.ts +11 -0
  175. package/dist/src/multimodal/voice.d.ts.map +1 -0
  176. package/dist/src/multimodal/voice.js +43 -0
  177. package/dist/src/multimodal/voice.js.map +1 -0
  178. package/dist/src/plans/types.d.ts +18 -18
  179. package/dist/src/plugins/loader.d.ts.map +1 -1
  180. package/dist/src/plugins/loader.js +10 -0
  181. package/dist/src/plugins/loader.js.map +1 -1
  182. package/dist/src/sandbox/docker.d.ts +42 -0
  183. package/dist/src/sandbox/docker.d.ts.map +1 -0
  184. package/dist/src/sandbox/docker.js +131 -0
  185. package/dist/src/sandbox/docker.js.map +1 -0
  186. package/dist/src/sandbox/engine.d.ts +50 -0
  187. package/dist/src/sandbox/engine.d.ts.map +1 -0
  188. package/dist/src/sandbox/engine.js +133 -0
  189. package/dist/src/sandbox/engine.js.map +1 -0
  190. package/dist/src/sandbox/index.d.ts +5 -0
  191. package/dist/src/sandbox/index.d.ts.map +1 -0
  192. package/dist/src/sandbox/index.js +5 -0
  193. package/dist/src/sandbox/index.js.map +1 -0
  194. package/dist/src/sandbox/types.d.ts +41 -0
  195. package/dist/src/sandbox/types.d.ts.map +1 -0
  196. package/dist/src/sandbox/types.js +12 -0
  197. package/dist/src/sandbox/types.js.map +1 -0
  198. package/dist/src/scripts/types.d.ts +2 -2
  199. package/dist/src/server/app.d.ts.map +1 -1
  200. package/dist/src/server/app.js +133 -0
  201. package/dist/src/server/app.js.map +1 -1
  202. package/dist/src/skills/loader.d.ts.map +1 -1
  203. package/dist/src/skills/loader.js +10 -0
  204. package/dist/src/skills/loader.js.map +1 -1
  205. package/dist/src/swarm/bus.d.ts +27 -0
  206. package/dist/src/swarm/bus.d.ts.map +1 -0
  207. package/dist/src/swarm/bus.js +64 -0
  208. package/dist/src/swarm/bus.js.map +1 -0
  209. package/dist/src/swarm/index.d.ts +6 -0
  210. package/dist/src/swarm/index.d.ts.map +1 -0
  211. package/dist/src/swarm/index.js +6 -0
  212. package/dist/src/swarm/index.js.map +1 -0
  213. package/dist/src/swarm/orchestrator.d.ts +79 -0
  214. package/dist/src/swarm/orchestrator.d.ts.map +1 -0
  215. package/dist/src/swarm/orchestrator.js +271 -0
  216. package/dist/src/swarm/orchestrator.js.map +1 -0
  217. package/dist/src/swarm/roles.d.ts +18 -0
  218. package/dist/src/swarm/roles.d.ts.map +1 -0
  219. package/dist/src/swarm/roles.js +83 -0
  220. package/dist/src/swarm/roles.js.map +1 -0
  221. package/dist/src/swarm/types.d.ts +58 -0
  222. package/dist/src/swarm/types.d.ts.map +1 -0
  223. package/dist/src/swarm/types.js +10 -0
  224. package/dist/src/swarm/types.js.map +1 -0
  225. package/dist/src/tools/core/cmd.d.ts.map +1 -1
  226. package/dist/src/tools/core/cmd.js +28 -0
  227. package/dist/src/tools/core/cmd.js.map +1 -1
  228. package/dist/src/utils/paths.d.ts +4 -4
  229. package/dist/src/utils/paths.d.ts.map +1 -1
  230. package/dist/src/utils/paths.js +8 -8
  231. package/dist/src/utils/paths.js.map +1 -1
  232. package/docs/DOCUMENTATION.md +137 -0
  233. package/package.json +4 -2
  234. package/studio/README.md +73 -0
  235. package/studio/eslint.config.js +23 -0
  236. package/studio/index.html +13 -0
  237. package/studio/package-lock.json +4350 -0
  238. package/studio/package.json +44 -0
  239. package/studio/postcss.config.js +6 -0
  240. package/studio/public/vite.svg +1 -0
  241. package/studio/src/App.tsx +243 -0
  242. package/studio/src/assets/react.svg +1 -0
  243. package/studio/src/components/Capabilities.tsx +80 -0
  244. package/studio/src/components/CommandsManager.tsx +94 -0
  245. package/studio/src/components/CostDashboard.tsx +182 -0
  246. package/studio/src/components/CredentialCapture.tsx +196 -0
  247. package/studio/src/components/CredentialsManager.tsx +257 -0
  248. package/studio/src/components/DaemonPanel.tsx +91 -0
  249. package/studio/src/components/DesktopPanel.tsx +118 -0
  250. package/studio/src/components/GoalTemplates.tsx +190 -0
  251. package/studio/src/components/GoalsPanel.tsx +235 -0
  252. package/studio/src/components/MemoryExplorer.tsx +152 -0
  253. package/studio/src/components/MultimodalPanel.tsx +150 -0
  254. package/studio/src/components/NotificationsPanel.tsx +175 -0
  255. package/studio/src/components/PluginsManager.tsx +60 -0
  256. package/studio/src/components/SandboxPanel.tsx +118 -0
  257. package/studio/src/components/ScriptsManager.tsx +269 -0
  258. package/studio/src/components/SkillsManager.tsx +123 -0
  259. package/studio/src/components/SwarmPanel.tsx +149 -0
  260. package/studio/src/components/TaskStreaming.tsx +189 -0
  261. package/studio/src/components/Terminal.tsx +200 -0
  262. package/studio/src/index.css +51 -0
  263. package/studio/src/main.tsx +13 -0
  264. package/studio/tailwind.config.js +47 -0
  265. package/studio/tsconfig.app.json +28 -0
  266. package/studio/tsconfig.json +7 -0
  267. package/studio/tsconfig.node.json +26 -0
  268. package/studio/vite.config.ts +7 -0
@@ -0,0 +1,189 @@
1
+ import { useState, useEffect, useRef } from 'react';
2
+ import { Activity, CheckCircle2, XCircle, Loader2, Play, Clock } from 'lucide-react';
3
+ import { io, Socket } from 'socket.io-client';
4
+
5
+ interface TaskEvent {
6
+ id: string;
7
+ type: 'start' | 'complete' | 'failed' | 'progress';
8
+ taskId: number;
9
+ title: string;
10
+ goalId?: number;
11
+ output?: string;
12
+ error?: string;
13
+ timestamp: Date;
14
+ }
15
+
16
+ let socket: Socket | null = null;
17
+
18
+ function getSocket(): Socket {
19
+ if (!socket) {
20
+ socket = io(window.location.origin);
21
+ }
22
+ return socket;
23
+ }
24
+
25
+ export default function TaskStreaming() {
26
+ const [events, setEvents] = useState<TaskEvent[]>([]);
27
+ const [connected, setConnected] = useState(false);
28
+ const scrollRef = useRef<HTMLDivElement>(null);
29
+
30
+ useEffect(() => {
31
+ const s = getSocket();
32
+
33
+ const addEvent = (type: TaskEvent['type'], data: any) => {
34
+ setEvents(prev => [...prev.slice(-100), {
35
+ id: `${type}-${data.taskId}-${Date.now()}`,
36
+ type,
37
+ taskId: data.taskId,
38
+ title: data.title,
39
+ goalId: data.goalId,
40
+ output: data.output,
41
+ error: data.error,
42
+ timestamp: new Date(),
43
+ }]);
44
+ };
45
+
46
+ s.on('connect', () => setConnected(true));
47
+ s.on('disconnect', () => setConnected(false));
48
+ s.on('task:start', (d: any) => addEvent('start', d));
49
+ s.on('task:complete', (d: any) => addEvent('complete', d));
50
+ s.on('task:failed', (d: any) => addEvent('failed', d));
51
+ s.on('task:progress', (d: any) => addEvent('progress', d));
52
+
53
+ setConnected(s.connected);
54
+
55
+ return () => {
56
+ s.off('task:start');
57
+ s.off('task:complete');
58
+ s.off('task:failed');
59
+ s.off('task:progress');
60
+ };
61
+ }, []);
62
+
63
+ // Auto-scroll
64
+ useEffect(() => {
65
+ scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: 'smooth' });
66
+ }, [events]);
67
+
68
+ const getIcon = (type: TaskEvent['type']) => {
69
+ switch (type) {
70
+ case 'start': return <Play size={14} color="#6366f1" />;
71
+ case 'complete': return <CheckCircle2 size={14} color="#22c55e" />;
72
+ case 'failed': return <XCircle size={14} color="#ef4444" />;
73
+ case 'progress': return <Loader2 size={14} color="#f5a623" className="animate-spin" />;
74
+ }
75
+ };
76
+
77
+ const getBorderColor = (type: TaskEvent['type']) => {
78
+ switch (type) {
79
+ case 'start': return '#6366f130';
80
+ case 'complete': return '#22c55e30';
81
+ case 'failed': return '#ef444430';
82
+ case 'progress': return '#f5a62330';
83
+ }
84
+ };
85
+
86
+ const getLabel = (type: TaskEvent['type']) => {
87
+ switch (type) {
88
+ case 'start': return 'STARTED';
89
+ case 'complete': return 'COMPLETED';
90
+ case 'failed': return 'FAILED';
91
+ case 'progress': return 'PROGRESS';
92
+ }
93
+ };
94
+
95
+ return (
96
+ <div style={{ padding: 32, maxWidth: 900, height: '100%', display: 'flex', flexDirection: 'column' }}>
97
+ {/* Header */}
98
+ <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 24 }}>
99
+ <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
100
+ <Activity size={24} color="#6366f1" />
101
+ <h2 style={{ margin: 0, color: '#fff', fontSize: 22 }}>Live Task Stream</h2>
102
+ <div style={{
103
+ width: 8, height: 8, borderRadius: '50%',
104
+ background: connected ? '#22c55e' : '#ef4444',
105
+ boxShadow: connected ? '0 0 8px #22c55e' : '0 0 8px #ef4444',
106
+ }} />
107
+ <span style={{ color: '#888', fontSize: 12 }}>{connected ? 'Connected' : 'Disconnected'}</span>
108
+ </div>
109
+ {events.length > 0 && (
110
+ <button
111
+ onClick={() => setEvents([])}
112
+ style={{
113
+ padding: '6px 14px', background: 'transparent', border: '1px solid #555',
114
+ borderRadius: 8, color: '#aaa', cursor: 'pointer', fontSize: 12,
115
+ }}
116
+ >Clear</button>
117
+ )}
118
+ </div>
119
+
120
+ {/* Stream */}
121
+ <div
122
+ ref={scrollRef}
123
+ style={{
124
+ flex: 1, overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 8,
125
+ paddingRight: 8,
126
+ }}
127
+ >
128
+ {events.length === 0 ? (
129
+ <div style={{
130
+ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center',
131
+ flexDirection: 'column', gap: 12, color: '#555',
132
+ }}>
133
+ <Activity size={40} style={{ opacity: 0.3 }} />
134
+ <div style={{ fontSize: 14 }}>Waiting for task events...</div>
135
+ <div style={{ fontSize: 12, color: '#444' }}>
136
+ Events will appear here as the daemon processes tasks
137
+ </div>
138
+ </div>
139
+ ) : events.map((event) => (
140
+ <div
141
+ key={event.id}
142
+ style={{
143
+ padding: '12px 16px', background: '#1a1a2e',
144
+ border: `1px solid ${getBorderColor(event.type)}`,
145
+ borderRadius: 10, animation: 'fadeIn 0.3s ease-in',
146
+ }}
147
+ >
148
+ <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: event.output || event.error ? 8 : 0 }}>
149
+ {getIcon(event.type)}
150
+ <span style={{
151
+ fontSize: 10, fontWeight: 700, letterSpacing: 1,
152
+ color: event.type === 'complete' ? '#22c55e' :
153
+ event.type === 'failed' ? '#ef4444' :
154
+ event.type === 'start' ? '#6366f1' : '#f5a623',
155
+ }}>
156
+ {getLabel(event.type)}
157
+ </span>
158
+ <span style={{ color: '#ddd', fontSize: 13, fontWeight: 600, flex: 1 }}>
159
+ Task #{event.taskId}: {event.title}
160
+ </span>
161
+ <span style={{ color: '#555', fontSize: 11, display: 'flex', alignItems: 'center', gap: 4 }}>
162
+ <Clock size={10} />
163
+ {event.timestamp.toLocaleTimeString()}
164
+ </span>
165
+ </div>
166
+ {event.output && (
167
+ <pre style={{
168
+ margin: 0, padding: '8px 12px', background: '#0d0d1a', borderRadius: 8,
169
+ color: '#aaa', fontSize: 12, fontFamily: 'monospace', whiteSpace: 'pre-wrap',
170
+ maxHeight: 120, overflow: 'auto',
171
+ }}>
172
+ {event.output}
173
+ </pre>
174
+ )}
175
+ {event.error && (
176
+ <pre style={{
177
+ margin: 0, padding: '8px 12px', background: '#1a0d0d', borderRadius: 8,
178
+ color: '#ef4444', fontSize: 12, fontFamily: 'monospace', whiteSpace: 'pre-wrap',
179
+ maxHeight: 120, overflow: 'auto',
180
+ }}>
181
+ {event.error}
182
+ </pre>
183
+ )}
184
+ </div>
185
+ ))}
186
+ </div>
187
+ </div>
188
+ );
189
+ }
@@ -0,0 +1,200 @@
1
+ import { useState, useEffect, useRef } from 'react';
2
+ import type { FormEvent } from 'react';
3
+ import { useParams } from 'react-router-dom';
4
+ import { Terminal as TerminalIcon, Send, Copy, Check } from 'lucide-react';
5
+ import { io, Socket } from 'socket.io-client';
6
+
7
+ export function Terminal() {
8
+ const { id } = useParams<{ id: string }>();
9
+ const [logs, setLogs] = useState<{ id: string, text: string, type: 'info' | 'error' | 'warn' | 'user' | 'system' | 'result' }[]>([]);
10
+ const [input, setInput] = useState('');
11
+ const [socket, setSocket] = useState<Socket | null>(null);
12
+ const endRef = useRef<HTMLDivElement>(null);
13
+ const [copied, setCopied] = useState<string | null>(null);
14
+ const [approval, setApproval] = useState<any | null>(null);
15
+
16
+ useEffect(() => {
17
+ // Initialize Socket.io connection to the local Agent Studio server
18
+ const newSocket = io('http://localhost:3333');
19
+ setSocket(newSocket);
20
+
21
+ setLogs([
22
+ { id: 'init-1', text: `Connected to autonomous environment: ${id}`, type: 'info' },
23
+ { id: 'init-2', text: `Listening for system events...`, type: 'warn' },
24
+ ]);
25
+
26
+ newSocket.on('connect', () => {
27
+ // We can emit a join room event if we implement multi-tenancy later
28
+ newSocket.emit('subscribe', id);
29
+ });
30
+
31
+ // Listen for log streams from the backend
32
+ newSocket.on('agent:log', (data: { instanceId: string, text: string, type: any }) => {
33
+ if (data.instanceId === id || data.instanceId === 'all') {
34
+ setLogs(prev => [...prev, { id: Math.random().toString(), text: data.text, type: data.type || 'system' }]);
35
+ }
36
+ });
37
+
38
+ newSocket.on('agent:approval:request', (data: { instanceId: string, action: any }) => {
39
+ if (data.instanceId === id || data.instanceId === 'all') {
40
+ setApproval(data.action);
41
+ setLogs(prev => [...prev, { id: Math.random().toString(), text: `⚠ Action requires approval: ${data.action.description} (${data.action.tool})`, type: 'warn' }]);
42
+ }
43
+ });
44
+
45
+ return () => {
46
+ newSocket.disconnect();
47
+ };
48
+ }, [id]);
49
+
50
+ useEffect(() => {
51
+ endRef.current?.scrollIntoView({ behavior: 'smooth' });
52
+ }, [logs]);
53
+
54
+ const handleSubmit = (e: FormEvent) => {
55
+ e.preventDefault();
56
+ if (!input.trim() || !socket) return;
57
+
58
+ const cmdId = Math.random().toString();
59
+ setLogs(prev => [...prev, { id: cmdId, text: input, type: 'user' }]);
60
+
61
+ // Emit the command via socket to the backend which writes to the repl/daemon stdin
62
+ socket.emit('agent:command', { instanceId: id, command: input });
63
+
64
+ setInput('');
65
+ };
66
+
67
+ const handleCopy = (text: string, id: string) => {
68
+ navigator.clipboard.writeText(text);
69
+ setCopied(id);
70
+ setTimeout(() => setCopied(null), 2000);
71
+ };
72
+
73
+ const handleApprovalResponse = (approved: boolean) => {
74
+ if (!approval || !socket) return;
75
+ setLogs(prev => [...prev, { id: Math.random().toString(), text: approved ? `✔ Approved Action: ${approval.tool}` : `✖ Denied Action: ${approval.tool}`, type: approved ? 'result' : 'error' }]);
76
+ socket.emit('agent:approval:response', { instanceId: id, tool: approval.tool, approved });
77
+ setApproval(null);
78
+ };
79
+
80
+ return (
81
+ <div className="flex flex-col h-full bg-[#0a0a0a] relative w-full font-mono">
82
+ {/* Header */}
83
+ <div className="h-12 border-b border-white/10 bg-neutral-900/60 flex items-center justify-between px-4 shrink-0 shadow-sm z-10">
84
+ <div className="flex items-center">
85
+ <div className="p-1.5 bg-blue-500/10 rounded-md border border-blue-500/20 mr-3">
86
+ <TerminalIcon size={14} className="text-blue-400" />
87
+ </div>
88
+ <span className="text-sm font-medium text-neutral-200 tracking-wide">Agent TTY</span>
89
+ <span className="mx-3 text-neutral-600">|</span>
90
+ <span className="text-xs text-neutral-500">{id}</span>
91
+ </div>
92
+ <div className="flex items-center gap-2">
93
+ <span className="flex h-2 w-2 relative">
94
+ <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
95
+ <span className="relative inline-flex rounded-full h-2 w-2 bg-emerald-500"></span>
96
+ </span>
97
+ <span className="text-xs text-emerald-500 font-medium">Live</span>
98
+ </div>
99
+ </div>
100
+
101
+ {/* Log Output Area */}
102
+ <div className="flex-1 overflow-y-auto p-4 space-y-3 text-sm max-w-full custom-scrollbar pb-24">
103
+ {logs.map((log) => (
104
+ <div
105
+ key={log.id}
106
+ className={`group relative flex gap-3 leading-relaxed p-2 rounded-lg transition-colors
107
+ ${log.type === 'user' ? 'bg-indigo-500/5 border border-indigo-500/10' : 'hover:bg-white/[0.02]'}
108
+ `}
109
+ >
110
+ {/* Status Icon Indicator */}
111
+ <span className="shrink-0 mt-0.5 select-none w-5 text-center">
112
+ {log.type === 'user' && <span className="text-indigo-400">❯</span>}
113
+ {log.type === 'info' && <span className="text-blue-400 opacity-70">ℹ</span>}
114
+ {log.type === 'warn' && <span className="text-amber-400 opacity-70">⚠</span>}
115
+ {log.type === 'error' && <span className="text-red-400">✖</span>}
116
+ {log.type === 'result' && <span className="text-emerald-400">✔</span>}
117
+ {log.type === 'system' && <span className="text-neutral-500">·</span>}
118
+ </span>
119
+
120
+ {/* Text Content */}
121
+ <div className={`break-words w-full whitespace-pre-wrap flex-1
122
+ ${log.type === 'user' ? 'text-indigo-200' :
123
+ log.type === 'error' ? 'text-red-300' :
124
+ log.type === 'warn' ? 'text-amber-200' :
125
+ log.type === 'result' ? 'text-emerald-200 font-medium' :
126
+ 'text-neutral-300'}
127
+ `}>
128
+ {log.text}
129
+ </div>
130
+
131
+ {/* Hover Actions (Copy) */}
132
+ <button
133
+ onClick={() => handleCopy(log.text, log.id)}
134
+ className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity p-1.5 rounded-md hover:bg-white/10 text-neutral-500 hover:text-neutral-300"
135
+ title="Copy output"
136
+ >
137
+ {copied === log.id ? <Check size={14} className="text-emerald-400" /> : <Copy size={14} />}
138
+ </button>
139
+ </div>
140
+ ))}
141
+ <div ref={endRef} />
142
+ </div>
143
+
144
+ {/* Input Form & Approval Banner */}
145
+ <div className="absolute bottom-6 left-1/2 -translate-x-1/2 w-[calc(100%-3rem)] max-w-4xl flex flex-col gap-3">
146
+ {approval && (
147
+ <div className="p-4 border border-amber-500/20 bg-amber-500/10 backdrop-blur-xl shadow-2xl rounded-xl flex items-center justify-between gap-4 w-full">
148
+ <div className="flex-1">
149
+ <h4 className="text-amber-200 font-medium mb-1 flex items-center gap-2"><div className="w-2 h-2 rounded-full bg-amber-400 animate-pulse"></div> Approval Required: {approval.tool}</h4>
150
+ <p className="text-amber-200/70 text-sm whitespace-pre-wrap">{approval.description}</p>
151
+ {approval.riskLevel && (
152
+ <div className="mt-2 text-xs font-mono bg-black/20 rounded px-2 py-1 inline-block text-amber-500">Risk: {approval.riskLevel.toUpperCase()}</div>
153
+ )}
154
+ </div>
155
+ <div className="flex items-center gap-2 shrink-0">
156
+ <button
157
+ onClick={() => handleApprovalResponse(false)}
158
+ className="px-4 py-2 bg-red-500/20 text-red-300 hover:bg-red-500/30 font-medium rounded-lg text-sm border border-red-500/20 transition-colors"
159
+ >
160
+ Deny
161
+ </button>
162
+ <button
163
+ onClick={() => handleApprovalResponse(true)}
164
+ className="px-4 py-2 bg-emerald-500/20 text-emerald-300 hover:bg-emerald-500/30 font-medium rounded-lg text-sm border border-emerald-500/20 transition-colors shadow-[0_0_15px_rgba(16,185,129,0.15)] focus:ring-2 focus:ring-emerald-500"
165
+ >
166
+ Approve
167
+ </button>
168
+ </div>
169
+ </div>
170
+ )}
171
+
172
+ <form
173
+ onSubmit={handleSubmit}
174
+ className="p-1 px-4 border border-white/10 bg-neutral-900/90 backdrop-blur-xl shadow-2xl rounded-xl flex items-center gap-3 ring-1 ring-black/5 hover:border-white/20 transition-colors focus-within:border-indigo-500/50 focus-within:ring-2 focus-within:ring-indigo-500/20"
175
+ >
176
+ <span className="text-indigo-500 font-bold select-none">❯</span>
177
+ <input
178
+ type="text"
179
+ value={input}
180
+ onChange={e => setInput(e.target.value)}
181
+ placeholder={approval ? "Waiting for approval..." : "Send a natural language command..."}
182
+ autoFocus
183
+ disabled={!!approval}
184
+ className="flex-1 bg-transparent py-3 text-sm text-neutral-200 outline-none placeholder-neutral-500 w-full disabled:opacity-50"
185
+ />
186
+ <div className="flex items-center gap-2">
187
+ <span className="text-[10px] text-neutral-500 font-sans tracking-wide uppercase px-2 hidden sm:inline-block border-r border-white/10 mr-1">Enter</span>
188
+ <button
189
+ type="submit"
190
+ disabled={!input.trim() || !!approval}
191
+ className="p-2 text-white transition-all bg-indigo-500 rounded-lg hover:bg-indigo-400 disabled:opacity-50 disabled:bg-white/5 disabled:text-neutral-500 hover:shadow-lg hover:shadow-indigo-500/20"
192
+ >
193
+ <Send size={15} className={input.trim() && !approval ? "translate-x-0.5 -translate-y-0.5" : ""} />
194
+ </button>
195
+ </div>
196
+ </form>
197
+ </div>
198
+ </div>
199
+ );
200
+ }
@@ -0,0 +1,51 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @layer base {
6
+ :root {
7
+ --background: 222.2 84% 4.9%;
8
+ --foreground: 210 40% 98%;
9
+ --card: 222.2 84% 4.9%;
10
+ --card-foreground: 210 40% 98%;
11
+ --popover: 222.2 84% 4.9%;
12
+ --popover-foreground: 210 40% 98%;
13
+ --primary: 210 40% 98%;
14
+ --primary-foreground: 222.2 47.4% 11.2%;
15
+ --secondary: 217.2 32.6% 17.5%;
16
+ --secondary-foreground: 210 40% 98%;
17
+ --muted: 217.2 32.6% 17.5%;
18
+ --muted-foreground: 215 20.2% 65.1%;
19
+ --accent: 217.2 32.6% 17.5%;
20
+ --accent-foreground: 210 40% 98%;
21
+ --destructive: 0 62.8% 30.6%;
22
+ --destructive-foreground: 210 40% 98%;
23
+ --border: 217.2 32.6% 17.5%;
24
+ --input: 217.2 32.6% 17.5%;
25
+ --ring: 212.7 26.8% 83.9%;
26
+ }
27
+ }
28
+
29
+ @layer base {
30
+ * {
31
+ @apply border-border;
32
+ }
33
+ body {
34
+ @apply bg-background text-foreground font-sans antialiased;
35
+ }
36
+ }
37
+
38
+ /* Scrollbar tweaks */
39
+ ::-webkit-scrollbar {
40
+ width: 8px;
41
+ height: 8px;
42
+ }
43
+ ::-webkit-scrollbar-track {
44
+ background: transparent;
45
+ }
46
+ ::-webkit-scrollbar-thumb {
47
+ @apply bg-muted-foreground/30 rounded-full cursor-pointer;
48
+ }
49
+ ::-webkit-scrollbar-thumb:hover {
50
+ @apply bg-muted-foreground/50;
51
+ }
@@ -0,0 +1,13 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import { BrowserRouter } from 'react-router-dom'
4
+ import './index.css'
5
+ import App from './App.tsx'
6
+
7
+ createRoot(document.getElementById('root')!).render(
8
+ <StrictMode>
9
+ <BrowserRouter>
10
+ <App />
11
+ </BrowserRouter>
12
+ </StrictMode>,
13
+ )
@@ -0,0 +1,47 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: [
4
+ "./index.html",
5
+ "./src/**/*.{js,ts,jsx,tsx}",
6
+ ],
7
+ theme: {
8
+ extend: {
9
+ colors: {
10
+ border: "hsl(var(--border))",
11
+ input: "hsl(var(--input))",
12
+ ring: "hsl(var(--ring))",
13
+ background: "hsl(var(--background))",
14
+ foreground: "hsl(var(--foreground))",
15
+ primary: {
16
+ DEFAULT: "hsl(var(--primary))",
17
+ foreground: "hsl(var(--primary-foreground))",
18
+ },
19
+ secondary: {
20
+ DEFAULT: "hsl(var(--secondary))",
21
+ foreground: "hsl(var(--secondary-foreground))",
22
+ },
23
+ destructive: {
24
+ DEFAULT: "hsl(var(--destructive))",
25
+ foreground: "hsl(var(--destructive-foreground))",
26
+ },
27
+ muted: {
28
+ DEFAULT: "hsl(var(--muted))",
29
+ foreground: "hsl(var(--muted-foreground))",
30
+ },
31
+ accent: {
32
+ DEFAULT: "hsl(var(--accent))",
33
+ foreground: "hsl(var(--accent-foreground))",
34
+ },
35
+ popover: {
36
+ DEFAULT: "hsl(var(--popover))",
37
+ foreground: "hsl(var(--popover-foreground))",
38
+ },
39
+ card: {
40
+ DEFAULT: "hsl(var(--card))",
41
+ foreground: "hsl(var(--card-foreground))",
42
+ },
43
+ },
44
+ },
45
+ },
46
+ plugins: [],
47
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
+ "target": "ES2022",
5
+ "useDefineForClassFields": true,
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "module": "ESNext",
8
+ "types": ["vite/client"],
9
+ "skipLibCheck": true,
10
+
11
+ /* Bundler mode */
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "moduleDetection": "force",
16
+ "noEmit": true,
17
+ "jsx": "react-jsx",
18
+
19
+ /* Linting */
20
+ "strict": true,
21
+ "noUnusedLocals": true,
22
+ "noUnusedParameters": true,
23
+ "erasableSyntaxOnly": true,
24
+ "noFallthroughCasesInSwitch": true,
25
+ "noUncheckedSideEffectImports": true
26
+ },
27
+ "include": ["src"]
28
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "types": ["node"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "erasableSyntaxOnly": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "noUncheckedSideEffectImports": true
24
+ },
25
+ "include": ["vite.config.ts"]
26
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+
4
+ // https://vite.dev/config/
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ })