botschat 0.1.20 → 0.1.21

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 (52) hide show
  1. package/package.json +1 -1
  2. package/packages/api/src/do/connection-do.ts +186 -382
  3. package/packages/api/src/index.ts +50 -67
  4. package/packages/api/src/routes/agents.ts +3 -3
  5. package/packages/api/src/routes/auth.ts +1 -0
  6. package/packages/api/src/routes/channels.ts +11 -11
  7. package/packages/api/src/routes/demo.ts +156 -0
  8. package/packages/api/src/routes/sessions.ts +5 -5
  9. package/packages/api/src/routes/tasks.ts +33 -33
  10. package/packages/plugin/dist/src/channel.js +50 -0
  11. package/packages/plugin/dist/src/channel.js.map +1 -1
  12. package/packages/plugin/package.json +18 -2
  13. package/packages/web/dist/assets/index-BtPyCBCl.css +1 -0
  14. package/packages/web/dist/assets/index-BtpsFe4Z.js +2 -0
  15. package/packages/web/dist/assets/index-CQbIYr6_.js +2 -0
  16. package/packages/web/dist/assets/{index-CYQMu_-c.js → index-C_GamcQc.js} +1 -1
  17. package/packages/web/dist/assets/index-LiBjPMg2.js +1 -0
  18. package/packages/web/dist/assets/{index-DYCO-ry1.js → index-MyoWvQAH.js} +1 -1
  19. package/packages/web/dist/assets/index-STIPTMK8.js +1516 -0
  20. package/packages/web/dist/assets/{index.esm-CvOpngZM.js → index.esm-BpQAwtdR.js} +1 -1
  21. package/packages/web/dist/assets/{web-D3LMODYp.js → web-BbTzVNLt.js} +1 -1
  22. package/packages/web/dist/assets/{web-1cdhq2RW.js → web-cnzjgNfD.js} +1 -1
  23. package/packages/web/dist/index.html +2 -2
  24. package/packages/web/src/App.tsx +9 -56
  25. package/packages/web/src/api.ts +5 -61
  26. package/packages/web/src/components/ChatWindow.tsx +9 -9
  27. package/packages/web/src/components/CronDetail.tsx +1 -1
  28. package/packages/web/src/components/ImageLightbox.tsx +96 -0
  29. package/packages/web/src/components/LoginPage.tsx +59 -1
  30. package/packages/web/src/components/MessageContent.tsx +17 -2
  31. package/packages/web/src/components/SessionTabs.tsx +1 -1
  32. package/packages/web/src/components/Sidebar.tsx +1 -3
  33. package/packages/web/src/hooks/useIMEComposition.ts +14 -9
  34. package/packages/web/src/store.ts +7 -39
  35. package/packages/web/src/ws.ts +0 -1
  36. package/scripts/dev.sh +0 -53
  37. package/migrations/0013_agents_table.sql +0 -29
  38. package/migrations/0014_agent_sessions.sql +0 -19
  39. package/migrations/0015_message_traces.sql +0 -27
  40. package/migrations/0016_multi_agent_channels_messages.sql +0 -9
  41. package/migrations/0017_rename_cron_job_id.sql +0 -2
  42. package/packages/api/src/protocol-v2.ts +0 -154
  43. package/packages/api/src/routes/agents-v2.ts +0 -192
  44. package/packages/api/src/routes/history-v2.ts +0 -221
  45. package/packages/api/src/routes/migrate-v2.ts +0 -110
  46. package/packages/web/dist/assets/index-BARPtt0v.css +0 -1
  47. package/packages/web/dist/assets/index-Bf-XL3te.js +0 -2
  48. package/packages/web/dist/assets/index-CYlvfpX9.js +0 -1519
  49. package/packages/web/dist/assets/index-CxcpA4Qo.js +0 -1
  50. package/packages/web/dist/assets/index-QebPVqwj.js +0 -2
  51. package/packages/web/src/components/AgentSettings.tsx +0 -328
  52. package/scripts/mock-openclaw-v2.mjs +0 -486
@@ -1 +0,0 @@
1
- import{r as i}from"./index-CYlvfpX9.js";const t=i("PushNotifications",{});export{t as PushNotifications};
@@ -1,2 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/web-D3LMODYp.js","assets/index-CYlvfpX9.js","assets/index-BARPtt0v.css"])))=>i.map(i=>d[i]);
2
- import{r as o,f as t}from"./index-CYlvfpX9.js";const n=o("SocialLogin",{web:()=>t(()=>import("./web-D3LMODYp.js"),__vite__mapDeps([0,1,2])).then(e=>new e.SocialLoginWeb)});export{n as SocialLogin};
@@ -1,328 +0,0 @@
1
- import React, { useState, useEffect, useCallback } from "react";
2
- import { agentsV2Api, type AgentV2 } from "../api";
3
- import { useAppState, useAppDispatch } from "../store";
4
-
5
- const AGENT_TYPES = [
6
- { value: "openclaw", label: "OpenClaw", color: "#2BAC76" },
7
- { value: "cursor_cli", label: "Cursor CLI", color: "#3B82F6" },
8
- { value: "cursor_cloud", label: "Cursor Cloud", color: "#6366F1" },
9
- { value: "claude_code", label: "Claude Code", color: "#F59E0B" },
10
- { value: "mock", label: "Mock", color: "#9CA3AF" },
11
- ] as const;
12
-
13
- const ROLES = [
14
- { value: "general", label: "General" },
15
- { value: "product_manager", label: "Product Manager" },
16
- { value: "developer", label: "Developer" },
17
- { value: "qa", label: "QA / Tester" },
18
- { value: "devops", label: "DevOps" },
19
- ] as const;
20
-
21
- function AgentTypeIcon({ type, size = 20 }: { type: string; size?: number }) {
22
- const agentType = AGENT_TYPES.find((t) => t.value === type);
23
- const color = agentType?.color ?? "#9CA3AF";
24
- return (
25
- <div
26
- className="shrink-0 rounded-full flex items-center justify-center font-bold"
27
- style={{ width: size, height: size, background: color, color: "#fff", fontSize: size * 0.45 }}
28
- >
29
- {(agentType?.label ?? "?")[0]}
30
- </div>
31
- );
32
- }
33
-
34
- function StatusDot({ connected }: { connected: boolean }) {
35
- return (
36
- <span
37
- className="inline-block rounded-full"
38
- style={{
39
- width: 8,
40
- height: 8,
41
- background: connected ? "#2BAC76" : "var(--text-tertiary)",
42
- }}
43
- />
44
- );
45
- }
46
-
47
- export function AgentSettings({ onClose }: { onClose: () => void }) {
48
- const state = useAppState();
49
- const dispatch = useAppDispatch();
50
- const [agents, setAgents] = useState<AgentV2[]>([]);
51
- const [loading, setLoading] = useState(true);
52
- const [editingAgent, setEditingAgent] = useState<AgentV2 | null>(null);
53
- const [showCreate, setShowCreate] = useState(false);
54
-
55
- const loadAgents = useCallback(async () => {
56
- setLoading(true);
57
- try {
58
- const data = await agentsV2Api.list();
59
- setAgents(data.agents);
60
- dispatch({ type: "SET_V2_AGENTS", agents: data.agents });
61
- } catch (err) {
62
- console.error("Failed to load agents:", err);
63
- } finally {
64
- setLoading(false);
65
- }
66
- }, [dispatch]);
67
-
68
- useEffect(() => { loadAgents(); }, [loadAgents]);
69
-
70
- const handleDelete = async (id: string, name: string) => {
71
- if (!confirm(`Delete agent "${name}"? This cannot be undone.`)) return;
72
- try {
73
- await agentsV2Api.delete(id);
74
- await loadAgents();
75
- } catch (err) {
76
- alert(`Failed to delete: ${err}`);
77
- }
78
- };
79
-
80
- return (
81
- <div className="fixed inset-0 z-50 flex items-center justify-center" style={{ background: "rgba(0,0,0,0.5)" }}>
82
- <div
83
- className="w-full max-w-2xl max-h-[80vh] overflow-y-auto rounded-xl shadow-lg"
84
- style={{ background: "var(--bg-primary)", border: "1px solid var(--border)" }}
85
- >
86
- <div className="flex items-center justify-between px-6 py-4" style={{ borderBottom: "1px solid var(--border)" }}>
87
- <h2 className="text-body font-semibold" style={{ color: "var(--text-primary)" }}>Agent Management</h2>
88
- <button onClick={onClose} className="text-caption" style={{ color: "var(--text-secondary)" }}>Close</button>
89
- </div>
90
-
91
- <div className="px-6 py-4">
92
- {loading ? (
93
- <p className="text-caption" style={{ color: "var(--text-secondary)" }}>Loading agents...</p>
94
- ) : (
95
- <>
96
- <div className="space-y-2">
97
- {agents.map((agent) => (
98
- <div
99
- key={agent.id}
100
- className="flex items-center gap-3 px-4 py-3 rounded-lg"
101
- style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)" }}
102
- >
103
- <AgentTypeIcon type={agent.type} />
104
- <div className="flex-1 min-w-0">
105
- <div className="flex items-center gap-2">
106
- <span className="text-caption font-medium" style={{ color: "var(--text-primary)" }}>
107
- {agent.name}
108
- </span>
109
- <StatusDot connected={agent.status === "connected"} />
110
- <span
111
- className="text-tiny px-1.5 py-0.5 rounded"
112
- style={{ background: "var(--bg-hover)", color: "var(--text-secondary)" }}
113
- >
114
- {ROLES.find((r) => r.value === agent.role)?.label ?? agent.role}
115
- </span>
116
- </div>
117
- <div className="text-tiny" style={{ color: "var(--text-tertiary)" }}>
118
- {AGENT_TYPES.find((t) => t.value === agent.type)?.label ?? agent.type}
119
- {agent.skills.length > 0 && ` · ${agent.skills.map((s) => s.name).join(", ")}`}
120
- </div>
121
- </div>
122
- <div className="flex gap-1.5">
123
- <button
124
- onClick={() => setEditingAgent(agent)}
125
- className="px-2.5 py-1 text-tiny rounded-sm"
126
- style={{ background: "var(--bg-hover)", color: "var(--text-secondary)" }}
127
- >
128
- Edit
129
- </button>
130
- <button
131
- onClick={() => handleDelete(agent.id, agent.name)}
132
- className="px-2.5 py-1 text-tiny rounded-sm"
133
- style={{ background: "var(--bg-hover)", color: "var(--accent-red)" }}
134
- >
135
- Delete
136
- </button>
137
- </div>
138
- </div>
139
- ))}
140
- </div>
141
-
142
- <button
143
- onClick={() => setShowCreate(true)}
144
- className="mt-4 w-full py-2.5 text-caption font-medium rounded-lg transition-colors"
145
- style={{ background: "var(--accent-blue)", color: "#fff" }}
146
- >
147
- + Add Agent
148
- </button>
149
- </>
150
- )}
151
- </div>
152
-
153
- {(showCreate || editingAgent) && (
154
- <AgentForm
155
- agent={editingAgent}
156
- onSave={async () => {
157
- setShowCreate(false);
158
- setEditingAgent(null);
159
- await loadAgents();
160
- }}
161
- onCancel={() => { setShowCreate(false); setEditingAgent(null); }}
162
- />
163
- )}
164
- </div>
165
- </div>
166
- );
167
- }
168
-
169
- function AgentForm({
170
- agent,
171
- onSave,
172
- onCancel,
173
- }: {
174
- agent: AgentV2 | null;
175
- onSave: () => void;
176
- onCancel: () => void;
177
- }) {
178
- const isEdit = !!agent;
179
- const [name, setName] = useState(agent?.name ?? "");
180
- const [type, setType] = useState(agent?.type ?? "openclaw");
181
- const [role, setRole] = useState(agent?.role ?? "general");
182
- const [systemPrompt, setSystemPrompt] = useState(agent?.systemPrompt ?? "");
183
- const [skillsText, setSkillsText] = useState(
184
- agent?.skills.map((s) => `${s.name}: ${s.description}`).join("\n") ?? "",
185
- );
186
- const [pairingToken, setPairingToken] = useState("");
187
- const [saving, setSaving] = useState(false);
188
- const [error, setError] = useState("");
189
-
190
- const handleSubmit = async (e: React.FormEvent) => {
191
- e.preventDefault();
192
- setSaving(true);
193
- setError("");
194
-
195
- const skills = skillsText
196
- .split("\n")
197
- .map((line) => line.trim())
198
- .filter(Boolean)
199
- .map((line) => {
200
- const colonIdx = line.indexOf(":");
201
- return colonIdx > 0
202
- ? { name: line.slice(0, colonIdx).trim(), description: line.slice(colonIdx + 1).trim() }
203
- : { name: line, description: "" };
204
- });
205
-
206
- try {
207
- if (isEdit) {
208
- await agentsV2Api.update(agent!.id, { name, role, systemPrompt, skills });
209
- } else {
210
- await agentsV2Api.create({
211
- name,
212
- type,
213
- role,
214
- systemPrompt,
215
- skills,
216
- pairingToken: pairingToken || undefined,
217
- });
218
- }
219
- onSave();
220
- } catch (err) {
221
- setError(String(err));
222
- } finally {
223
- setSaving(false);
224
- }
225
- };
226
-
227
- return (
228
- <div className="px-6 py-4" style={{ borderTop: "1px solid var(--border)" }}>
229
- <h3 className="text-caption font-semibold mb-3" style={{ color: "var(--text-primary)" }}>
230
- {isEdit ? `Edit ${agent!.name}` : "Add New Agent"}
231
- </h3>
232
- <form onSubmit={handleSubmit} className="space-y-3">
233
- <div className="flex gap-3">
234
- <label className="flex-1">
235
- <span className="text-tiny block mb-1" style={{ color: "var(--text-secondary)" }}>Name</span>
236
- <input
237
- value={name}
238
- onChange={(e) => setName(e.target.value)}
239
- className="w-full px-3 py-2 text-caption rounded-md"
240
- style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)", color: "var(--text-primary)" }}
241
- required
242
- />
243
- </label>
244
- {!isEdit && (
245
- <label className="w-40">
246
- <span className="text-tiny block mb-1" style={{ color: "var(--text-secondary)" }}>Type</span>
247
- <select
248
- value={type}
249
- onChange={(e) => setType(e.target.value as AgentV2["type"])}
250
- className="w-full px-3 py-2 text-caption rounded-md"
251
- style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)", color: "var(--text-primary)" }}
252
- >
253
- {AGENT_TYPES.map((t) => (
254
- <option key={t.value} value={t.value}>{t.label}</option>
255
- ))}
256
- </select>
257
- </label>
258
- )}
259
- <label className="w-40">
260
- <span className="text-tiny block mb-1" style={{ color: "var(--text-secondary)" }}>Role</span>
261
- <select
262
- value={role}
263
- onChange={(e) => setRole(e.target.value)}
264
- className="w-full px-3 py-2 text-caption rounded-md"
265
- style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)", color: "var(--text-primary)" }}
266
- >
267
- {ROLES.map((r) => (
268
- <option key={r.value} value={r.value}>{r.label}</option>
269
- ))}
270
- </select>
271
- </label>
272
- </div>
273
-
274
- <label>
275
- <span className="text-tiny block mb-1" style={{ color: "var(--text-secondary)" }}>System Prompt</span>
276
- <textarea
277
- value={systemPrompt}
278
- onChange={(e) => setSystemPrompt(e.target.value)}
279
- rows={3}
280
- className="w-full px-3 py-2 text-caption rounded-md resize-y"
281
- style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)", color: "var(--text-primary)" }}
282
- placeholder="You are a product manager who excels at..."
283
- />
284
- </label>
285
-
286
- <label>
287
- <span className="text-tiny block mb-1" style={{ color: "var(--text-secondary)" }}>Skills (one per line, format: name: description)</span>
288
- <textarea
289
- value={skillsText}
290
- onChange={(e) => setSkillsText(e.target.value)}
291
- rows={3}
292
- className="w-full px-3 py-2 text-caption rounded-md resize-y font-mono"
293
- style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)", color: "var(--text-primary)" }}
294
- placeholder={"Code Review: Review code for quality and security\nRefactoring: Improve code structure"}
295
- />
296
- </label>
297
-
298
- {!isEdit && type === "openclaw" && (
299
- <label>
300
- <span className="text-tiny block mb-1" style={{ color: "var(--text-secondary)" }}>Pairing Token (optional)</span>
301
- <input
302
- value={pairingToken}
303
- onChange={(e) => setPairingToken(e.target.value)}
304
- className="w-full px-3 py-2 text-caption rounded-md font-mono"
305
- style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)", color: "var(--text-primary)" }}
306
- placeholder="bc_pat_..."
307
- />
308
- </label>
309
- )}
310
-
311
- {error && (
312
- <p className="text-tiny" style={{ color: "var(--accent-red)" }}>{error}</p>
313
- )}
314
-
315
- <div className="flex justify-end gap-2 pt-1">
316
- <button type="button" onClick={onCancel} className="px-4 py-2 text-caption rounded-md"
317
- style={{ background: "var(--bg-hover)", color: "var(--text-secondary)" }}>
318
- Cancel
319
- </button>
320
- <button type="submit" disabled={saving} className="px-4 py-2 text-caption font-medium rounded-md"
321
- style={{ background: "var(--accent-blue)", color: "#fff", opacity: saving ? 0.6 : 1 }}>
322
- {saving ? "Saving..." : isEdit ? "Update" : "Create"}
323
- </button>
324
- </div>
325
- </form>
326
- </div>
327
- );
328
- }