botschat 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 (88) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +213 -0
  3. package/migrations/0001_initial.sql +88 -0
  4. package/migrations/0002_rename_projects_to_channels.sql +53 -0
  5. package/migrations/0003_messages.sql +14 -0
  6. package/migrations/0004_jobs.sql +15 -0
  7. package/migrations/0005_deleted_cron_jobs.sql +6 -0
  8. package/migrations/0006_tasks_add_model.sql +2 -0
  9. package/migrations/0007_sessions.sql +25 -0
  10. package/migrations/0008_remove_openclaw_fields.sql +8 -0
  11. package/package.json +53 -0
  12. package/packages/api/package.json +17 -0
  13. package/packages/api/src/do/connection-do.ts +929 -0
  14. package/packages/api/src/env.ts +8 -0
  15. package/packages/api/src/index.ts +297 -0
  16. package/packages/api/src/routes/agents.ts +68 -0
  17. package/packages/api/src/routes/auth.ts +105 -0
  18. package/packages/api/src/routes/channels.ts +185 -0
  19. package/packages/api/src/routes/jobs.ts +65 -0
  20. package/packages/api/src/routes/models.ts +22 -0
  21. package/packages/api/src/routes/pairing.ts +76 -0
  22. package/packages/api/src/routes/projects.ts +177 -0
  23. package/packages/api/src/routes/sessions.ts +171 -0
  24. package/packages/api/src/routes/tasks.ts +375 -0
  25. package/packages/api/src/routes/upload.ts +52 -0
  26. package/packages/api/src/utils/auth.ts +101 -0
  27. package/packages/api/src/utils/id.ts +19 -0
  28. package/packages/api/tsconfig.json +18 -0
  29. package/packages/plugin/dist/index.d.ts +19 -0
  30. package/packages/plugin/dist/index.d.ts.map +1 -0
  31. package/packages/plugin/dist/index.js +17 -0
  32. package/packages/plugin/dist/index.js.map +1 -0
  33. package/packages/plugin/dist/src/accounts.d.ts +12 -0
  34. package/packages/plugin/dist/src/accounts.d.ts.map +1 -0
  35. package/packages/plugin/dist/src/accounts.js +103 -0
  36. package/packages/plugin/dist/src/accounts.js.map +1 -0
  37. package/packages/plugin/dist/src/channel.d.ts +206 -0
  38. package/packages/plugin/dist/src/channel.d.ts.map +1 -0
  39. package/packages/plugin/dist/src/channel.js +1248 -0
  40. package/packages/plugin/dist/src/channel.js.map +1 -0
  41. package/packages/plugin/dist/src/runtime.d.ts +3 -0
  42. package/packages/plugin/dist/src/runtime.d.ts.map +1 -0
  43. package/packages/plugin/dist/src/runtime.js +18 -0
  44. package/packages/plugin/dist/src/runtime.js.map +1 -0
  45. package/packages/plugin/dist/src/types.d.ts +179 -0
  46. package/packages/plugin/dist/src/types.d.ts.map +1 -0
  47. package/packages/plugin/dist/src/types.js +6 -0
  48. package/packages/plugin/dist/src/types.js.map +1 -0
  49. package/packages/plugin/dist/src/ws-client.d.ts +51 -0
  50. package/packages/plugin/dist/src/ws-client.d.ts.map +1 -0
  51. package/packages/plugin/dist/src/ws-client.js +170 -0
  52. package/packages/plugin/dist/src/ws-client.js.map +1 -0
  53. package/packages/plugin/openclaw.plugin.json +11 -0
  54. package/packages/plugin/package.json +39 -0
  55. package/packages/plugin/tsconfig.json +20 -0
  56. package/packages/web/dist/assets/index-C-wI8eHy.css +1 -0
  57. package/packages/web/dist/assets/index-CbPEKHLG.js +93 -0
  58. package/packages/web/dist/index.html +17 -0
  59. package/packages/web/index.html +16 -0
  60. package/packages/web/package.json +29 -0
  61. package/packages/web/postcss.config.js +6 -0
  62. package/packages/web/src/App.tsx +827 -0
  63. package/packages/web/src/api.ts +242 -0
  64. package/packages/web/src/components/ChatWindow.tsx +864 -0
  65. package/packages/web/src/components/CronDetail.tsx +943 -0
  66. package/packages/web/src/components/CronSidebar.tsx +123 -0
  67. package/packages/web/src/components/DebugLogPanel.tsx +258 -0
  68. package/packages/web/src/components/IconRail.tsx +163 -0
  69. package/packages/web/src/components/JobList.tsx +120 -0
  70. package/packages/web/src/components/LoginPage.tsx +178 -0
  71. package/packages/web/src/components/MessageContent.tsx +1082 -0
  72. package/packages/web/src/components/ModelSelect.tsx +87 -0
  73. package/packages/web/src/components/ScheduleEditor.tsx +403 -0
  74. package/packages/web/src/components/SessionTabs.tsx +246 -0
  75. package/packages/web/src/components/Sidebar.tsx +331 -0
  76. package/packages/web/src/components/TaskBar.tsx +413 -0
  77. package/packages/web/src/components/ThreadPanel.tsx +212 -0
  78. package/packages/web/src/debug-log.ts +58 -0
  79. package/packages/web/src/index.css +170 -0
  80. package/packages/web/src/main.tsx +10 -0
  81. package/packages/web/src/store.ts +492 -0
  82. package/packages/web/src/ws.ts +99 -0
  83. package/packages/web/tailwind.config.js +65 -0
  84. package/packages/web/tsconfig.json +18 -0
  85. package/packages/web/vite.config.ts +20 -0
  86. package/scripts/dev.sh +122 -0
  87. package/tsconfig.json +18 -0
  88. package/wrangler.toml +40 -0
@@ -0,0 +1,99 @@
1
+ /** WebSocket client for connecting to the BotsChat ConnectionDO. */
2
+
3
+ import { dlog } from "./debug-log";
4
+
5
+ export type WSMessage = {
6
+ type: string;
7
+ [key: string]: unknown;
8
+ };
9
+
10
+ export type WSClientOptions = {
11
+ userId: string;
12
+ sessionId: string;
13
+ token: string;
14
+ onMessage: (msg: WSMessage) => void;
15
+ onStatusChange: (connected: boolean) => void;
16
+ };
17
+
18
+ export class BotsChatWSClient {
19
+ private ws: WebSocket | null = null;
20
+ private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
21
+ private backoffMs = 1000;
22
+ private intentionalClose = false;
23
+ private _connected = false;
24
+
25
+ constructor(private opts: WSClientOptions) {}
26
+
27
+ get connected(): boolean {
28
+ return this._connected;
29
+ }
30
+
31
+ connect(): void {
32
+ this.intentionalClose = false;
33
+ const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
34
+ const url = `${protocol}//${window.location.host}/api/ws/${this.opts.userId}/${this.opts.sessionId}`;
35
+
36
+ dlog.info("WS", `Connecting to ${url}`);
37
+ this.ws = new WebSocket(url);
38
+
39
+ this.ws.onopen = () => {
40
+ dlog.info("WS", "Socket opened, sending auth");
41
+ // Authenticate with the ConnectionDO
42
+ this.ws!.send(JSON.stringify({ type: "auth", token: this.opts.token }));
43
+ };
44
+
45
+ this.ws.onmessage = (evt) => {
46
+ try {
47
+ const msg = JSON.parse(evt.data) as WSMessage;
48
+ if (msg.type === "auth.ok") {
49
+ dlog.info("WS", "Auth OK — connected");
50
+ this.backoffMs = 1000;
51
+ this._connected = true;
52
+ this.opts.onStatusChange(true);
53
+ } else {
54
+ this.opts.onMessage(msg);
55
+ }
56
+ } catch {
57
+ dlog.warn("WS", "Failed to parse incoming message", evt.data);
58
+ }
59
+ };
60
+
61
+ this.ws.onclose = (evt) => {
62
+ this._connected = false;
63
+ this.opts.onStatusChange(false);
64
+ if (!this.intentionalClose) {
65
+ dlog.warn("WS", `Connection closed (code=${evt.code}), reconnecting in ${this.backoffMs}ms`);
66
+ this.reconnectTimer = setTimeout(() => {
67
+ this.backoffMs = Math.min(this.backoffMs * 2, 30000);
68
+ this.connect();
69
+ }, this.backoffMs);
70
+ } else {
71
+ dlog.info("WS", "Connection closed (intentional)");
72
+ }
73
+ };
74
+
75
+ this.ws.onerror = () => {
76
+ dlog.error("WS", "WebSocket error (close event will follow)");
77
+ };
78
+ }
79
+
80
+ send(msg: WSMessage): void {
81
+ if (this.ws?.readyState === WebSocket.OPEN) {
82
+ this.ws.send(JSON.stringify(msg));
83
+ } else {
84
+ dlog.warn("WS", `Cannot send — socket not open (readyState=${this.ws?.readyState})`, msg);
85
+ }
86
+ }
87
+
88
+ disconnect(): void {
89
+ this.intentionalClose = true;
90
+ if (this.reconnectTimer) {
91
+ clearTimeout(this.reconnectTimer);
92
+ this.reconnectTimer = null;
93
+ }
94
+ this.ws?.close();
95
+ this.ws = null;
96
+ this._connected = false;
97
+ this.opts.onStatusChange(false);
98
+ }
99
+ }
@@ -0,0 +1,65 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: ["./index.html", "./src/**/*.{ts,tsx}"],
4
+ theme: {
5
+ extend: {
6
+ colors: {
7
+ brand: {
8
+ 50: "#f0f7ff",
9
+ 100: "#e0efff",
10
+ 500: "#1264A3",
11
+ 600: "#1164A3",
12
+ 700: "#0d5289",
13
+ },
14
+ surface: "var(--bg-surface)",
15
+ "bg-primary": "var(--bg-primary)",
16
+ "bg-secondary": "var(--bg-secondary)",
17
+ "bg-hover": "var(--bg-hover)",
18
+ "bg-active": "var(--bg-active)",
19
+ "text-primary": "var(--text-primary)",
20
+ "text-secondary": "var(--text-secondary)",
21
+ "text-muted": "var(--text-muted)",
22
+ "text-link": "var(--text-link)",
23
+ "text-sidebar": "var(--text-sidebar)",
24
+ "text-sidebar-active": "var(--text-sidebar-active)",
25
+ "accent-green": "var(--accent-green)",
26
+ "accent-yellow": "var(--accent-yellow)",
27
+ "accent-red": "var(--accent-red)",
28
+ border: "var(--border)",
29
+ },
30
+ fontFamily: {
31
+ sans: ["Lato", "Noto Sans SC", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Helvetica", "Arial", "sans-serif"],
32
+ mono: ["SF Mono", "Consolas", "Monaco", "monospace"],
33
+ },
34
+ fontSize: {
35
+ h1: ["18px", { lineHeight: "1.33", fontWeight: "700" }],
36
+ h2: ["15px", { lineHeight: "1.46", fontWeight: "700" }],
37
+ body: ["15px", { lineHeight: "1.46", fontWeight: "400" }],
38
+ caption: ["13px", { lineHeight: "1.38", fontWeight: "400" }],
39
+ tiny: ["11px", { lineHeight: "1.27", fontWeight: "500" }],
40
+ },
41
+ spacing: {
42
+ "space-1": "4px",
43
+ "space-2": "8px",
44
+ "space-3": "12px",
45
+ "space-4": "16px",
46
+ "space-5": "20px",
47
+ "space-6": "24px",
48
+ },
49
+ borderRadius: {
50
+ sm: "4px",
51
+ md: "8px",
52
+ lg: "12px",
53
+ },
54
+ boxShadow: {
55
+ sm: "var(--shadow-sm)",
56
+ md: "var(--shadow-md)",
57
+ lg: "var(--shadow-lg)",
58
+ },
59
+ maxWidth: {
60
+ message: "700px",
61
+ },
62
+ },
63
+ },
64
+ plugins: [require("@tailwindcss/typography")],
65
+ };
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "resolveJsonModule": true,
11
+ "jsx": "react-jsx",
12
+ "outDir": "dist",
13
+ "rootDir": "src",
14
+ "lib": ["ES2022", "DOM", "DOM.Iterable"]
15
+ },
16
+ "include": ["src/**/*.ts", "src/**/*.tsx"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }
@@ -0,0 +1,20 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+
4
+ export default defineConfig({
5
+ plugins: [react()],
6
+ build: {
7
+ outDir: "dist",
8
+ emptyOutDir: true,
9
+ },
10
+ server: {
11
+ port: 3000,
12
+ proxy: {
13
+ "/api": {
14
+ target: "https://botschat-api.auxtenwpc.workers.dev",
15
+ changeOrigin: true,
16
+ ws: true,
17
+ },
18
+ },
19
+ },
20
+ });
package/scripts/dev.sh ADDED
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env bash
2
+ # BotsChat local dev startup script
3
+ # Usage:
4
+ # ./scripts/dev.sh — build web + migrate + start server
5
+ # ./scripts/dev.sh reset — nuke local DB, re-migrate, then start
6
+ # ./scripts/dev.sh migrate — only run D1 migrations (no server)
7
+ # ./scripts/dev.sh build — only build web frontend (no server)
8
+ # ./scripts/dev.sh sync — sync plugin to mini.local + rebuild + restart gateway
9
+ # ./scripts/dev.sh logs — tail gateway logs on mini.local
10
+ set -euo pipefail
11
+
12
+ cd "$(dirname "$0")/.."
13
+ ROOT="$(pwd)"
14
+
15
+ # ── Colours ──────────────────────────────────────────────────────────
16
+ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[0;33m'; CYAN='\033[0;36m'; NC='\033[0m'
17
+ info() { echo -e "${CYAN}▸${NC} $*"; }
18
+ ok() { echo -e "${GREEN}✔${NC} $*"; }
19
+ warn() { echo -e "${YELLOW}▲${NC} $*"; }
20
+ fail() { echo -e "${RED}✖${NC} $*"; exit 1; }
21
+
22
+ # ── Helpers ──────────────────────────────────────────────────────────
23
+
24
+ kill_port() {
25
+ local port=${1:-8787}
26
+ local pids
27
+ pids=$(lsof -ti:"$port" 2>/dev/null || true)
28
+ if [[ -n "$pids" ]]; then
29
+ warn "Killing process(es) on port $port: $pids"
30
+ echo "$pids" | xargs kill -9 2>/dev/null || true
31
+ sleep 1
32
+ fi
33
+ }
34
+
35
+ do_migrate() {
36
+ info "Applying D1 migrations (local)…"
37
+ npx wrangler d1 migrations apply botschat-db --local
38
+ ok "Migrations applied"
39
+ }
40
+
41
+ do_reset() {
42
+ warn "Nuking local D1 database…"
43
+ rm -rf "$ROOT/.wrangler/state"
44
+ ok "Local DB wiped"
45
+ do_migrate
46
+ }
47
+
48
+ do_build_web() {
49
+ info "Building web frontend…"
50
+ npm run build -w packages/web
51
+ ok "Web build complete (packages/web/dist)"
52
+ }
53
+
54
+ do_start() {
55
+ kill_port 8787
56
+ info "Starting wrangler dev on 0.0.0.0:8787…"
57
+ exec npx wrangler dev --config wrangler.toml --ip 0.0.0.0
58
+ }
59
+
60
+ do_sync_plugin() {
61
+ local REMOTE="YinTong@mini.local"
62
+ local REMOTE_DIR="~/Projects/botsChat/packages/plugin"
63
+
64
+ info "Syncing plugin to $REMOTE…"
65
+ rsync -avz --exclude node_modules --exclude .git --exclude dist --exclude .wrangler \
66
+ packages/plugin/ "$REMOTE:$REMOTE_DIR/"
67
+ ok "Plugin files synced"
68
+
69
+ info "Building plugin + restarting gateway on mini.local…"
70
+ ssh "$REMOTE" "$(cat <<'REMOTE_SCRIPT'
71
+ export PATH="/opt/homebrew/bin:$PATH"
72
+ cd ~/Projects/botsChat/packages/plugin
73
+ npm run build
74
+ echo "--- Plugin build OK ---"
75
+ pkill -9 -f openclaw-gateway 2>/dev/null || true
76
+ sleep 3
77
+ nohup openclaw gateway run --bind loopback --port 18789 --force \
78
+ > /tmp/openclaw-gateway.log 2>&1 &
79
+ echo "Gateway restarted (PID=$!)"
80
+ REMOTE_SCRIPT
81
+ )"
82
+ ok "Plugin synced and gateway restarted"
83
+
84
+ sleep 4
85
+ info "Checking connection…"
86
+ ssh "$REMOTE" 'tail -5 /tmp/openclaw-gateway.log | grep -i "authenticated\|error\|Task scan"'
87
+ }
88
+
89
+ do_logs() {
90
+ info "Tailing gateway logs on mini.local…"
91
+ ssh YinTong@mini.local 'tail -f /tmp/openclaw-gateway.log'
92
+ }
93
+
94
+ # ── Main ─────────────────────────────────────────────────────────────
95
+
96
+ cmd="${1:-}"
97
+
98
+ case "$cmd" in
99
+ reset)
100
+ do_reset
101
+ do_build_web
102
+ do_start
103
+ ;;
104
+ migrate)
105
+ do_migrate
106
+ ;;
107
+ build)
108
+ do_build_web
109
+ ;;
110
+ sync)
111
+ do_sync_plugin
112
+ ;;
113
+ logs)
114
+ do_logs
115
+ ;;
116
+ *)
117
+ # Default: build + migrate + start
118
+ do_build_web
119
+ do_migrate
120
+ do_start
121
+ ;;
122
+ esac
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "resolveJsonModule": true,
11
+ "declaration": true,
12
+ "declarationMap": true,
13
+ "sourceMap": true,
14
+ "outDir": "dist",
15
+ "lib": ["ES2022"]
16
+ },
17
+ "exclude": ["node_modules", "dist"]
18
+ }
package/wrangler.toml ADDED
@@ -0,0 +1,40 @@
1
+ name = "botschat-api"
2
+ main = "packages/api/src/index.ts"
3
+ compatibility_date = "2025-01-01"
4
+ compatibility_flags = ["nodejs_compat"]
5
+
6
+ # --- Static Assets (React SPA) ---
7
+ [assets]
8
+ directory = "packages/web/dist"
9
+ binding = "ASSETS"
10
+ not_found_handling = "single-page-application"
11
+
12
+ # --- D1 Database ---
13
+ [[d1_databases]]
14
+ binding = "DB"
15
+ database_name = "botschat-db"
16
+ database_id = "aa8dc50d-c839-44c2-a019-5818f0487be4"
17
+ migrations_dir = "migrations"
18
+
19
+ # --- R2 Bucket ---
20
+ [[r2_buckets]]
21
+ binding = "MEDIA"
22
+ bucket_name = "botschat-media"
23
+
24
+ # --- Durable Objects ---
25
+ [durable_objects]
26
+ bindings = [
27
+ { name = "CONNECTION_DO", class_name = "ConnectionDO" },
28
+ ]
29
+
30
+ [[migrations]]
31
+ tag = "v1"
32
+ new_sqlite_classes = ["ConnectionDO"]
33
+
34
+ # --- Environment Variables ---
35
+ [vars]
36
+ ENVIRONMENT = "development"
37
+
38
+ # --- Dev settings ---
39
+ [dev]
40
+ port = 8787