bazilion 0.0.0 → 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 (265) hide show
  1. package/README.md +53 -152
  2. package/dist/cli.js +2730 -0
  3. package/dist/cli.js.map +1 -0
  4. package/dist/daemon.js +5888 -0
  5. package/dist/daemon.js.map +1 -0
  6. package/dist/worker.js +1830 -0
  7. package/dist/worker.js.map +1 -0
  8. package/package.json +57 -28
  9. package/.understand-anything/.understandignore +0 -25
  10. package/.understand-anything/fingerprints.json +0 -14267
  11. package/.understand-anything/knowledge-graph.json +0 -18128
  12. package/.understand-anything/meta.json +0 -6
  13. package/CLAUDE.md +0 -164
  14. package/apps/cli/package.json +0 -21
  15. package/apps/cli/src/auth-file.ts +0 -18
  16. package/apps/cli/src/client.ts +0 -37
  17. package/apps/cli/src/columnize.ts +0 -32
  18. package/apps/cli/src/commands/agent.ts +0 -574
  19. package/apps/cli/src/commands/auth.ts +0 -110
  20. package/apps/cli/src/commands/backup.ts +0 -135
  21. package/apps/cli/src/commands/completion.ts +0 -155
  22. package/apps/cli/src/commands/config.ts +0 -95
  23. package/apps/cli/src/commands/doctor.ts +0 -131
  24. package/apps/cli/src/commands/group.ts +0 -132
  25. package/apps/cli/src/commands/inbox.ts +0 -82
  26. package/apps/cli/src/commands/login.ts +0 -73
  27. package/apps/cli/src/commands/memory.ts +0 -106
  28. package/apps/cli/src/commands/profile.ts +0 -259
  29. package/apps/cli/src/commands/provider.ts +0 -170
  30. package/apps/cli/src/commands/send.ts +0 -24
  31. package/apps/cli/src/commands/serve.ts +0 -89
  32. package/apps/cli/src/commands/skill.ts +0 -120
  33. package/apps/cli/src/commands/token.ts +0 -148
  34. package/apps/cli/src/commands/trigger.ts +0 -129
  35. package/apps/cli/src/commands/uninstall.ts +0 -156
  36. package/apps/cli/src/index.ts +0 -196
  37. package/apps/cli/src/paths.ts +0 -12
  38. package/apps/cli/test/agent.test.ts +0 -213
  39. package/apps/cli/test/backup.test.ts +0 -95
  40. package/apps/cli/test/chat.test.ts +0 -539
  41. package/apps/cli/test/columnize.test.ts +0 -29
  42. package/apps/cli/test/completion.test.ts +0 -45
  43. package/apps/cli/test/config-page.test.ts +0 -151
  44. package/apps/cli/test/group.test.ts +0 -74
  45. package/apps/cli/test/helpers.ts +0 -70
  46. package/apps/cli/test/inbox-autodeliver.test.ts +0 -143
  47. package/apps/cli/test/inbox.test.ts +0 -147
  48. package/apps/cli/test/memory.test.ts +0 -69
  49. package/apps/cli/test/profile.test.ts +0 -110
  50. package/apps/cli/test/send.test.ts +0 -30
  51. package/apps/cli/test/server-fixture.ts +0 -212
  52. package/apps/cli/test/session-head.test.ts +0 -45
  53. package/apps/cli/test/skill.test.ts +0 -128
  54. package/apps/cli/test/token.test.ts +0 -109
  55. package/apps/cli/test/trigger.test.ts +0 -245
  56. package/apps/cli/tsconfig.json +0 -4
  57. package/apps/daemon/package.json +0 -31
  58. package/apps/daemon/src/app.ts +0 -41
  59. package/apps/daemon/src/core/agent/archive.ts +0 -8
  60. package/apps/daemon/src/core/agent/delete.ts +0 -30
  61. package/apps/daemon/src/core/agent/resolve.ts +0 -31
  62. package/apps/daemon/src/core/agent/spawn.ts +0 -95
  63. package/apps/daemon/src/core/agent/unarchive.ts +0 -11
  64. package/apps/daemon/src/core/availableModels.ts +0 -58
  65. package/apps/daemon/src/core/db/client.ts +0 -113
  66. package/apps/daemon/src/core/db/migrate.ts +0 -41
  67. package/apps/daemon/src/core/db/migrations/0001_init.sql +0 -179
  68. package/apps/daemon/src/core/group/delete.ts +0 -21
  69. package/apps/daemon/src/core/group/register.ts +0 -68
  70. package/apps/daemon/src/core/index.ts +0 -71
  71. package/apps/daemon/src/core/paths.ts +0 -56
  72. package/apps/daemon/src/core/profile/create.ts +0 -78
  73. package/apps/daemon/src/core/profile/delete.ts +0 -26
  74. package/apps/daemon/src/core/profile/identity.ts +0 -70
  75. package/apps/daemon/src/core/profile/load.ts +0 -45
  76. package/apps/daemon/src/core/profile/seed.ts +0 -74
  77. package/apps/daemon/src/core/profile/templates.ts +0 -60
  78. package/apps/daemon/src/core/profile/update.ts +0 -57
  79. package/apps/daemon/src/core/profile/validate.ts +0 -9
  80. package/apps/daemon/src/core/repos/agents.ts +0 -202
  81. package/apps/daemon/src/core/repos/config.ts +0 -78
  82. package/apps/daemon/src/core/repos/groups.ts +0 -55
  83. package/apps/daemon/src/core/repos/messages.ts +0 -127
  84. package/apps/daemon/src/core/repos/profiles.ts +0 -83
  85. package/apps/daemon/src/core/repos/providerModels.ts +0 -58
  86. package/apps/daemon/src/core/repos/providerState.ts +0 -37
  87. package/apps/daemon/src/core/repos/secrets.ts +0 -145
  88. package/apps/daemon/src/core/repos/skillMeta.ts +0 -49
  89. package/apps/daemon/src/core/repos/triggers.ts +0 -101
  90. package/apps/daemon/src/core/repos/webTokens.ts +0 -87
  91. package/apps/daemon/src/core/secrets.ts +0 -65
  92. package/apps/daemon/src/core/services.ts +0 -264
  93. package/apps/daemon/src/core/skills/discover.ts +0 -28
  94. package/apps/daemon/src/core/skills/import.ts +0 -136
  95. package/apps/daemon/src/core/skills/parse.ts +0 -52
  96. package/apps/daemon/src/core/skills/resolve.ts +0 -50
  97. package/apps/daemon/src/index.ts +0 -45
  98. package/apps/daemon/src/lib/agent-cancel.ts +0 -48
  99. package/apps/daemon/src/lib/agent-id.ts +0 -13
  100. package/apps/daemon/src/lib/agent-turn.ts +0 -56
  101. package/apps/daemon/src/lib/api-key.ts +0 -56
  102. package/apps/daemon/src/lib/auth.ts +0 -41
  103. package/apps/daemon/src/lib/cron.ts +0 -93
  104. package/apps/daemon/src/lib/ctx.ts +0 -80
  105. package/apps/daemon/src/lib/messaging-host.ts +0 -34
  106. package/apps/daemon/src/lib/middleware-auth.ts +0 -52
  107. package/apps/daemon/src/lib/scheduler.ts +0 -294
  108. package/apps/daemon/src/routes/agents.ts +0 -772
  109. package/apps/daemon/src/routes/auth-login.ts +0 -193
  110. package/apps/daemon/src/routes/config.ts +0 -267
  111. package/apps/daemon/src/routes/groups.ts +0 -133
  112. package/apps/daemon/src/routes/messages.ts +0 -29
  113. package/apps/daemon/src/routes/misc.ts +0 -239
  114. package/apps/daemon/src/routes/profiles.ts +0 -197
  115. package/apps/daemon/src/routes/skills.ts +0 -123
  116. package/apps/daemon/src/routes/triggers.ts +0 -29
  117. package/apps/daemon/src/runtime/auth/openai-codex.ts +0 -121
  118. package/apps/daemon/src/runtime/auto-reply/heartbeat.ts +0 -31
  119. package/apps/daemon/src/runtime/index.ts +0 -77
  120. package/apps/daemon/src/runtime/memory/files.ts +0 -103
  121. package/apps/daemon/src/runtime/memory/qmd.ts +0 -152
  122. package/apps/daemon/src/runtime/memory/types.ts +0 -16
  123. package/apps/daemon/src/runtime/pi/events.ts +0 -173
  124. package/apps/daemon/src/runtime/pi/session.ts +0 -536
  125. package/apps/daemon/src/runtime/pi/tools.ts +0 -85
  126. package/apps/daemon/src/runtime/providers/catalog.ts +0 -145
  127. package/apps/daemon/src/runtime/providers/pi-adapter.ts +0 -272
  128. package/apps/daemon/src/runtime/providers/registry.ts +0 -374
  129. package/apps/daemon/src/runtime/providers/retry.ts +0 -176
  130. package/apps/daemon/src/runtime/providers/types.ts +0 -33
  131. package/apps/daemon/src/runtime/session/prompt.ts +0 -83
  132. package/apps/daemon/src/runtime/tools/bootstrap.ts +0 -22
  133. package/apps/daemon/src/runtime/tools/home.ts +0 -114
  134. package/apps/daemon/src/runtime/tools/memory.ts +0 -81
  135. package/apps/daemon/src/runtime/tools/messaging.ts +0 -127
  136. package/apps/daemon/src/runtime/tools/registry.ts +0 -29
  137. package/apps/daemon/src/runtime/tools/types.ts +0 -13
  138. package/apps/daemon/src/runtime/tools/web-extract.ts +0 -110
  139. package/apps/daemon/src/runtime/tools/web-ssrf.ts +0 -245
  140. package/apps/daemon/src/runtime/tools/web.ts +0 -273
  141. package/apps/daemon/src/runtime/worker/entry.ts +0 -221
  142. package/apps/daemon/src/runtime/worker/ipc-protocol.ts +0 -75
  143. package/apps/daemon/src/runtime/worker/spawn.ts +0 -249
  144. package/apps/daemon/test/core/agents.test.ts +0 -319
  145. package/apps/daemon/test/core/available-models.test.ts +0 -63
  146. package/apps/daemon/test/core/config.test.ts +0 -99
  147. package/apps/daemon/test/core/groups.test.ts +0 -63
  148. package/apps/daemon/test/core/helpers.ts +0 -50
  149. package/apps/daemon/test/core/identity.test.ts +0 -85
  150. package/apps/daemon/test/core/migrations.test.ts +0 -83
  151. package/apps/daemon/test/core/profiles.test.ts +0 -182
  152. package/apps/daemon/test/core/provider-models.test.ts +0 -57
  153. package/apps/daemon/test/core/provider-state.test.ts +0 -36
  154. package/apps/daemon/test/core/skill-meta.test.ts +0 -45
  155. package/apps/daemon/test/core/skills.test.ts +0 -271
  156. package/apps/daemon/test/core/triggers.test.ts +0 -182
  157. package/apps/daemon/test/core/web-tokens.test.ts +0 -79
  158. package/apps/daemon/test/cron.test.ts +0 -90
  159. package/apps/daemon/test/runtime/heartbeat.test.ts +0 -34
  160. package/apps/daemon/test/runtime/memory-qmd.test.ts +0 -97
  161. package/apps/daemon/test/runtime/memory.test.ts +0 -78
  162. package/apps/daemon/test/runtime/messaging.test.ts +0 -213
  163. package/apps/daemon/test/runtime/mock-server.ts +0 -65
  164. package/apps/daemon/test/runtime/openai-codex-auth.test.ts +0 -116
  165. package/apps/daemon/test/runtime/providers.test.ts +0 -306
  166. package/apps/daemon/test/runtime/retry.test.ts +0 -191
  167. package/apps/daemon/test/runtime/session-head.test.ts +0 -90
  168. package/apps/daemon/test/runtime/tools-home.test.ts +0 -102
  169. package/apps/daemon/test/runtime/tools-web.test.ts +0 -206
  170. package/apps/daemon/tsconfig.json +0 -4
  171. package/apps/mobile/README.md +0 -60
  172. package/apps/mobile/app/_layout.tsx +0 -58
  173. package/apps/mobile/app/agents/[id]/chat.tsx +0 -486
  174. package/apps/mobile/app/agents/[id]/index.tsx +0 -166
  175. package/apps/mobile/app/agents/index.tsx +0 -212
  176. package/apps/mobile/app/index.tsx +0 -21
  177. package/apps/mobile/app/pair.tsx +0 -226
  178. package/apps/mobile/app/settings.tsx +0 -419
  179. package/apps/mobile/app.json +0 -49
  180. package/apps/mobile/assets/adaptive-icon.png +0 -0
  181. package/apps/mobile/assets/favicon.png +0 -0
  182. package/apps/mobile/assets/icon.png +0 -0
  183. package/apps/mobile/assets/splash-icon.png +0 -0
  184. package/apps/mobile/babel.config.js +0 -6
  185. package/apps/mobile/metro.config.js +0 -28
  186. package/apps/mobile/package.json +0 -44
  187. package/apps/mobile/src/auth.ts +0 -66
  188. package/apps/mobile/src/pair-url.ts +0 -48
  189. package/apps/mobile/src/theme-context.tsx +0 -88
  190. package/apps/mobile/src/theme.ts +0 -135
  191. package/apps/mobile/test/pair-url.test.ts +0 -46
  192. package/apps/mobile/tsconfig.json +0 -23
  193. package/apps/web/components.json +0 -25
  194. package/apps/web/package.json +0 -39
  195. package/apps/web/public/baziu.svg +0 -8
  196. package/apps/web/src/components/AgentTabs.tsx +0 -45
  197. package/apps/web/src/components/BaziuLogo.tsx +0 -21
  198. package/apps/web/src/components/ChatPane.tsx +0 -1033
  199. package/apps/web/src/components/ConfigTabs.tsx +0 -29
  200. package/apps/web/src/components/CopyButton.tsx +0 -68
  201. package/apps/web/src/components/CreateGroupDialog.tsx +0 -127
  202. package/apps/web/src/components/FieldRow.tsx +0 -94
  203. package/apps/web/src/components/Footer.tsx +0 -10
  204. package/apps/web/src/components/PawIcon.tsx +0 -15
  205. package/apps/web/src/components/Sidebar.tsx +0 -287
  206. package/apps/web/src/components/SpawnDialog.tsx +0 -129
  207. package/apps/web/src/components/ThemeToggle.tsx +0 -75
  208. package/apps/web/src/components/TopNav.tsx +0 -34
  209. package/apps/web/src/components/ui/button.tsx +0 -67
  210. package/apps/web/src/components/ui/card.tsx +0 -103
  211. package/apps/web/src/components/ui/checkbox.tsx +0 -31
  212. package/apps/web/src/components/ui/dialog.tsx +0 -168
  213. package/apps/web/src/components/ui/input.tsx +0 -19
  214. package/apps/web/src/components/ui/label.tsx +0 -22
  215. package/apps/web/src/components/ui/radio-group.tsx +0 -44
  216. package/apps/web/src/components/ui/select.tsx +0 -192
  217. package/apps/web/src/components/ui/separator.tsx +0 -26
  218. package/apps/web/src/components/ui/table.tsx +0 -116
  219. package/apps/web/src/components/ui/tabs.tsx +0 -88
  220. package/apps/web/src/components/ui/textarea.tsx +0 -18
  221. package/apps/web/src/lib/auth.ts +0 -50
  222. package/apps/web/src/lib/daemon-client.ts +0 -34
  223. package/apps/web/src/lib/md.ts +0 -45
  224. package/apps/web/src/lib/utils.ts +0 -6
  225. package/apps/web/src/lib/wire-constants.ts +0 -27
  226. package/apps/web/src/routeTree.gen.ts +0 -408
  227. package/apps/web/src/router.tsx +0 -20
  228. package/apps/web/src/routes/__root.tsx +0 -123
  229. package/apps/web/src/routes/agents/$id/inbox.tsx +0 -207
  230. package/apps/web/src/routes/agents/$id/index.tsx +0 -527
  231. package/apps/web/src/routes/agents/$id/triggers.tsx +0 -239
  232. package/apps/web/src/routes/agents/index.tsx +0 -265
  233. package/apps/web/src/routes/api/$.ts +0 -88
  234. package/apps/web/src/routes/config/index.tsx +0 -315
  235. package/apps/web/src/routes/config/services.tsx +0 -49
  236. package/apps/web/src/routes/config/tokens.tsx +0 -192
  237. package/apps/web/src/routes/groups/$id/index.tsx +0 -153
  238. package/apps/web/src/routes/groups/$id/memory.tsx +0 -321
  239. package/apps/web/src/routes/groups/index.tsx +0 -191
  240. package/apps/web/src/routes/index.tsx +0 -133
  241. package/apps/web/src/routes/login.tsx +0 -63
  242. package/apps/web/src/routes/profiles/$id.tsx +0 -549
  243. package/apps/web/src/routes/profiles/index.tsx +0 -458
  244. package/apps/web/src/routes/skills/index.tsx +0 -297
  245. package/apps/web/src/routes/welcome.tsx +0 -61
  246. package/apps/web/src/styles.css +0 -449
  247. package/apps/web/tsconfig.json +0 -25
  248. package/apps/web/vite.config.ts +0 -25
  249. package/biome.json +0 -23
  250. package/docs/agent-engine.md +0 -219
  251. package/docs/architecture.md +0 -627
  252. package/docs/backlog/README.md +0 -42
  253. package/docs/backlog/draft/BAZ-001-a2a-federation-spike.md +0 -125
  254. package/docs/openclaw-reference.md +0 -210
  255. package/packages/api-types/package.json +0 -11
  256. package/packages/api-types/src/entities.ts +0 -146
  257. package/packages/api-types/src/events.ts +0 -55
  258. package/packages/api-types/src/index.ts +0 -488
  259. package/packages/api-types/src/memory.ts +0 -15
  260. package/packages/client/package.json +0 -13
  261. package/packages/client/src/index.ts +0 -117
  262. package/pnpm-workspace.yaml +0 -3
  263. package/tsconfig.base.json +0 -23
  264. package/tsconfig.json +0 -11
  265. package/vitest.config.ts +0 -22
@@ -1,239 +0,0 @@
1
- import { ApiClientError } from '@bazilion/client'
2
- import type { AgentTrigger, ResolvedAgent } from '@bazilion/api-types'
3
- import { createFileRoute, redirect, useRouter } from '@tanstack/react-router'
4
- import { createServerFn } from '@tanstack/react-start'
5
- import { useState } from 'react'
6
- import { AgentTabs } from '../../../components/AgentTabs'
7
- import { daemonClient } from '../../../lib/daemon-client'
8
-
9
- interface TriggersView {
10
- resolved: ResolvedAgent
11
- triggers: AgentTrigger[]
12
- }
13
-
14
- const fetchTriggers = createServerFn({ method: 'POST' })
15
- .inputValidator((d: { id: string }) => d)
16
- .handler(async ({ data }): Promise<TriggersView | null> => {
17
- const c = daemonClient()
18
- let resolved: ResolvedAgent
19
- try {
20
- resolved = await c.get<ResolvedAgent>(`/api/agents/${encodeURIComponent(data.id)}`)
21
- } catch (err) {
22
- if (err instanceof ApiClientError && err.status === 404) return null
23
- throw err
24
- }
25
- const { triggers } = await c.get<{ triggers: AgentTrigger[] }>(
26
- `/api/agents/${encodeURIComponent(resolved.agent.id)}/triggers`,
27
- )
28
- return { resolved, triggers }
29
- })
30
-
31
- export const Route = createFileRoute('/agents/$id/triggers')({
32
- loader: async ({ params }) => {
33
- const data = await fetchTriggers({ data: { id: params.id } })
34
- if (!data) throw redirect({ to: '/agents' })
35
- return data
36
- },
37
- component: TriggersPage,
38
- })
39
-
40
- function TriggersPage() {
41
- const { resolved, triggers } = Route.useLoaderData()
42
- const router = useRouter()
43
-
44
- async function toggle(t: AgentTrigger) {
45
- await fetch(`/api/triggers/${t.id}`, {
46
- method: 'PATCH',
47
- headers: { 'content-type': 'application/json' },
48
- body: JSON.stringify({ enabled: !t.enabled }),
49
- })
50
- await router.invalidate()
51
- }
52
- async function del(id: string) {
53
- if (!confirm('delete this trigger?')) return
54
- await fetch(`/api/triggers/${id}`, { method: 'DELETE' })
55
- await router.invalidate()
56
- }
57
-
58
- return (
59
- <div>
60
- <header className="mb-6">
61
- <h1>{resolved.agent.name}</h1>
62
- </header>
63
- <AgentTabs
64
- agentId={resolved.agent.id}
65
- active="triggers"
66
- archived={resolved.agent.status === 'archived'}
67
- />
68
-
69
- <AddTriggerForm agentId={resolved.agent.id} onAdded={() => router.invalidate()} />
70
-
71
- <h3 className="mb-3 mt-6 font-body text-[0.85em] font-semibold uppercase tracking-wider text-mocha-light">
72
- Active triggers
73
- </h3>
74
-
75
- {triggers.length === 0 ? (
76
- <p className="muted">no triggers yet — add one above.</p>
77
- ) : (
78
- <table>
79
- <thead>
80
- <tr>
81
- <th>id</th>
82
- <th>kind</th>
83
- <th>spec</th>
84
- <th>message</th>
85
- <th>last fired</th>
86
- <th />
87
- </tr>
88
- </thead>
89
- <tbody>
90
- {triggers.map((t) => {
91
- const spec = t.kind === 'interval' ? `every ${t.intervalSec}s` : t.cronExpr
92
- const last = t.lastFiredAt ? new Date(t.lastFiredAt).toLocaleString() : '(never)'
93
- return (
94
- <tr key={t.id} className={t.enabled ? '' : 'opacity-60'}>
95
- <td>
96
- <code>{t.id.slice(0, 8)}…</code>
97
- </td>
98
- <td>
99
- <span className="inline-block rounded-sm border border-frost bg-ivory px-2 py-0.5 font-mono text-[0.8em] text-mocha">
100
- {t.kind}
101
- </span>
102
- </td>
103
- <td>
104
- <code>{spec}</code>
105
- </td>
106
- <td>
107
- {t.message.length > 60 ? `${t.message.slice(0, 60)}…` : t.message}
108
- </td>
109
- <td className="text-[0.82em] text-mocha-light">{last}</td>
110
- <td>
111
- <div className="flex gap-1.5">
112
- <button type="button" className="ghost-btn" onClick={() => toggle(t)}>
113
- {t.enabled ? 'disable' : 'enable'}
114
- </button>
115
- <button type="button" className="ghost-btn" onClick={() => del(t.id)}>
116
- delete
117
- </button>
118
- </div>
119
- </td>
120
- </tr>
121
- )
122
- })}
123
- </tbody>
124
- </table>
125
- )}
126
- </div>
127
- )
128
- }
129
-
130
- function AddTriggerForm({
131
- agentId,
132
- onAdded,
133
- }: {
134
- agentId: string
135
- onAdded: () => void
136
- }) {
137
- const [kind, setKind] = useState<'interval' | 'cron'>('interval')
138
- const [intervalSec, setIntervalSec] = useState(300)
139
- const [cronExpr, setCronExpr] = useState('')
140
- const [message, setMessage] = useState('')
141
- const [err, setErr] = useState<string | null>(null)
142
- const [submitting, setSubmitting] = useState(false)
143
-
144
- async function submit(e: React.FormEvent<HTMLFormElement>) {
145
- e.preventDefault()
146
- setErr(null)
147
- if (!message.trim()) {
148
- setErr('message is required')
149
- return
150
- }
151
- if (kind === 'interval' && (!Number.isFinite(intervalSec) || intervalSec <= 0)) {
152
- setErr('interval must be a positive number')
153
- return
154
- }
155
- if (kind === 'cron' && !cronExpr.trim()) {
156
- setErr('cron expression is required')
157
- return
158
- }
159
- setSubmitting(true)
160
- try {
161
- const body: Record<string, unknown> = { kind, message: message.trim() }
162
- if (kind === 'interval') body.intervalSec = intervalSec
163
- else body.cronExpr = cronExpr.trim()
164
- const res = await fetch(`/api/agents/${encodeURIComponent(agentId)}/triggers`, {
165
- method: 'POST',
166
- headers: { 'content-type': 'application/json' },
167
- body: JSON.stringify(body),
168
- })
169
- if (!res.ok) {
170
- const e2 = (await res.json().catch(() => null)) as { error?: string } | null
171
- throw new Error(e2?.error ?? res.statusText)
172
- }
173
- setMessage('')
174
- setCronExpr('')
175
- setIntervalSec(300)
176
- onAdded()
177
- } catch (e2) {
178
- setErr((e2 as Error).message)
179
- } finally {
180
- setSubmitting(false)
181
- }
182
- }
183
-
184
- return (
185
- <form className="card" onSubmit={submit}>
186
- <h3>Add trigger</h3>
187
- <div className="mb-3 flex gap-3">
188
- <label className="m-0 inline-flex cursor-pointer items-center gap-1">
189
- <input
190
- type="radio"
191
- checked={kind === 'interval'}
192
- onChange={() => setKind('interval')}
193
- />
194
- interval (every N seconds)
195
- </label>
196
- <label className="m-0 inline-flex cursor-pointer items-center gap-1">
197
- <input type="radio" checked={kind === 'cron'} onChange={() => setKind('cron')} />
198
- cron (5-field)
199
- </label>
200
- </div>
201
- {kind === 'interval' ? (
202
- <label>
203
- interval (seconds)
204
- <input
205
- type="number"
206
- min={1}
207
- value={intervalSec}
208
- onChange={(e) => setIntervalSec(Number(e.target.value))}
209
- />
210
- </label>
211
- ) : (
212
- <label>
213
- cron expression (minute hour dom month dow)
214
- <input
215
- type="text"
216
- placeholder="*/15 * * * *"
217
- value={cronExpr}
218
- onChange={(e) => setCronExpr(e.target.value)}
219
- />
220
- </label>
221
- )}
222
- <label>
223
- message
224
- <textarea
225
- placeholder="e.g. check your inbox and act on anything new"
226
- value={message}
227
- onChange={(e) => setMessage(e.target.value)}
228
- className="font-mono text-[0.9em] min-h-[80px]"
229
- />
230
- </label>
231
- <div className="mt-3 flex items-center gap-3">
232
- <button type="submit" disabled={submitting}>
233
- {submitting ? 'adding…' : 'add'}
234
- </button>
235
- {err && <span className="text-[0.85em] text-[#9B3D3D]">{err}</span>}
236
- </div>
237
- </form>
238
- )
239
- }
@@ -1,265 +0,0 @@
1
- import type { Agent, Group, Profile } from '@bazilion/api-types'
2
- import { createFileRoute, useRouter } from '@tanstack/react-router'
3
- import { createServerFn } from '@tanstack/react-start'
4
- import { useState } from 'react'
5
- import { daemonClient } from '../../lib/daemon-client'
6
-
7
- interface ModelGroup {
8
- provider: string
9
- models: string[]
10
- }
11
- interface AvailableModelsResponse {
12
- groups: ModelGroup[]
13
- }
14
-
15
- interface AgentsView {
16
- agents: Agent[]
17
- profiles: Profile[]
18
- groups: Group[]
19
- modelGroups: ModelGroup[]
20
- }
21
-
22
- const fetchAgents = createServerFn({ method: 'POST' })
23
- .inputValidator((d: { all: boolean }) => d)
24
- .handler(async ({ data }): Promise<AgentsView> => {
25
- const c = daemonClient()
26
- const [agents, profiles, groups, models] = await Promise.all([
27
- c.get<Agent[]>(`/api/agents?includeArchived=${data.all}`),
28
- c.get<Profile[]>('/api/profiles'),
29
- c.get<Group[]>('/api/groups'),
30
- c.get<AvailableModelsResponse>('/api/config/available-models'),
31
- ])
32
- return { agents, profiles, groups, modelGroups: models.groups }
33
- })
34
-
35
- export const Route = createFileRoute('/agents/')({
36
- validateSearch: (s: Record<string, unknown>): { all?: '1' } => ({
37
- all: s.all === '1' ? '1' : undefined,
38
- }),
39
- loaderDeps: ({ search }) => ({ all: search.all === '1' }),
40
- loader: ({ deps }) => fetchAgents({ data: { all: deps.all } }),
41
- component: AgentsPage,
42
- })
43
-
44
- function AgentsPage() {
45
- const { agents, profiles, groups, modelGroups } = Route.useLoaderData()
46
- const { all } = Route.useSearch()
47
- const showAll = all === '1'
48
- const router = useRouter()
49
-
50
- async function archive(id: string) {
51
- if (!confirm('archive this agent? (reversible)')) return
52
- await fetch(`/api/agents/${id}/archive`, { method: 'POST' })
53
- await router.invalidate()
54
- }
55
- async function unarchive(id: string) {
56
- await fetch(`/api/agents/${id}/unarchive`, { method: 'POST' })
57
- await router.invalidate()
58
- }
59
- async function del(id: string) {
60
- if (!confirm('permanently delete this agent and all its data?')) return
61
- await fetch(`/api/agents/${id}`, { method: 'DELETE' })
62
- await router.invalidate()
63
- }
64
-
65
- return (
66
- <div>
67
- <h1>agents</h1>
68
-
69
- <SpawnForm
70
- profiles={profiles}
71
- groups={groups}
72
- modelGroups={modelGroups}
73
- onSpawned={router.invalidate}
74
- />
75
-
76
- <p>
77
- <a href={showAll ? '/agents' : '/agents?all=1'}>
78
- {showAll ? 'hide archived' : 'show archived'}
79
- </a>
80
- </p>
81
-
82
- <table>
83
- <thead>
84
- <tr>
85
- <th>id</th>
86
- <th>name</th>
87
- <th>profile</th>
88
- <th>status</th>
89
- <th />
90
- </tr>
91
- </thead>
92
- <tbody>
93
- {agents.length === 0 && (
94
- <tr>
95
- <td colSpan={5} className="muted">
96
- no agents yet
97
- </td>
98
- </tr>
99
- )}
100
- {agents.map((a) => (
101
- <tr key={a.id}>
102
- <td>
103
- <a href={`/agents/${a.id}`} title={a.id}>
104
- <code>{a.id.slice(0, 8)}…</code>
105
- </a>
106
- </td>
107
- <td>{a.name}</td>
108
- <td>
109
- <code>{a.profileId}</code>
110
- </td>
111
- <td>{a.status}</td>
112
- <td>
113
- <div className="flex gap-1.5">
114
- {a.status !== 'archived' ? (
115
- <button type="button" className="ghost-btn" onClick={() => archive(a.id)}>
116
- archive
117
- </button>
118
- ) : (
119
- <button type="button" className="ghost-btn" onClick={() => unarchive(a.id)}>
120
- unarchive
121
- </button>
122
- )}
123
- <button
124
- type="button"
125
- className="ghost-btn"
126
- style={{ color: 'var(--color-rose-baziu)' }}
127
- onClick={() => del(a.id)}
128
- >
129
- delete
130
- </button>
131
- </div>
132
- </td>
133
- </tr>
134
- ))}
135
- </tbody>
136
- </table>
137
- </div>
138
- )
139
- }
140
-
141
- function SpawnForm({
142
- profiles,
143
- groups,
144
- modelGroups,
145
- onSpawned,
146
- }: {
147
- profiles: Profile[]
148
- groups: Group[]
149
- modelGroups: ModelGroup[]
150
- onSpawned: () => void
151
- }) {
152
- const [profileId, setProfileId] = useState('')
153
- const [name, setName] = useState('')
154
- const [model, setModel] = useState('')
155
- // Default to the seeded 'default' group when present so the form matches the
156
- // server-side fallback. Empty string means "let the daemon pick" — same end
157
- // result as picking 'default' explicitly.
158
- const [groupId, setGroupId] = useState(groups.find((g) => g.id === 'default')?.id ?? '')
159
- const [submitting, setSubmitting] = useState(false)
160
- const [err, setErr] = useState<string | null>(null)
161
-
162
- async function submit(e: React.FormEvent<HTMLFormElement>) {
163
- e.preventDefault()
164
- if (!profileId) {
165
- setErr('profile is required')
166
- return
167
- }
168
- setSubmitting(true)
169
- setErr(null)
170
- try {
171
- const body: Record<string, unknown> = { profile: profileId }
172
- if (name) body.name = name
173
- if (model) body.model = model
174
- if (groupId) body.groupId = groupId
175
- const res = await fetch('/api/agents', {
176
- method: 'POST',
177
- headers: { 'content-type': 'application/json' },
178
- body: JSON.stringify(body),
179
- })
180
- if (!res.ok) {
181
- const b = (await res.json().catch(() => null)) as { error?: string } | null
182
- throw new Error(b?.error ?? res.statusText)
183
- }
184
- // Reset on success.
185
- setName('')
186
- setModel('')
187
- onSpawned()
188
- } catch (e2) {
189
- setErr((e2 as Error).message)
190
- } finally {
191
- setSubmitting(false)
192
- }
193
- }
194
-
195
- return (
196
- <form className="card" onSubmit={submit}>
197
- <h3>spawn agent</h3>
198
- {err && <div className="err">{err}</div>}
199
- <p className="muted my-2 text-[0.85em]">
200
- Skills come from the profile's defaults at spawn time. Tweak per-agent skills after the
201
- fact from the agent detail page.
202
- </p>
203
- <div className="flex gap-4">
204
- <label className="flex-1">
205
- profile
206
- <select value={profileId} onChange={(e) => setProfileId(e.target.value)} required>
207
- <option value="">--</option>
208
- {profiles.map((p) => (
209
- <option key={p.id} value={p.id}>
210
- {p.id}
211
- </option>
212
- ))}
213
- </select>
214
- </label>
215
- <label className="flex-1">
216
- name
217
- <input value={name} onChange={(e) => setName(e.target.value)} />
218
- </label>
219
- </div>
220
- <label>
221
- model override
222
- {modelGroups.length === 0 ? (
223
- <input
224
- value=""
225
- disabled
226
- placeholder="(uses profile default — enable models on /config)"
227
- />
228
- ) : (
229
- <select value={model} onChange={(e) => setModel(e.target.value)}>
230
- <option value="">(uses profile default)</option>
231
- {modelGroups.map((g) => (
232
- <optgroup key={g.provider} label={g.provider}>
233
- {g.models.map((m) => (
234
- <option key={m} value={`${g.provider}:${m}`}>
235
- {`${g.provider}:${m}`}
236
- </option>
237
- ))}
238
- </optgroup>
239
- ))}
240
- </select>
241
- )}
242
- </label>
243
- <label>
244
- group
245
- {groups.length === 0 ? (
246
- <select disabled>
247
- <option>(no groups — register one on /groups)</option>
248
- </select>
249
- ) : (
250
- <select value={groupId} onChange={(e) => setGroupId(e.target.value)}>
251
- {groups.map((g) => (
252
- <option key={g.id} value={g.id}>
253
- {g.id} ({g.name})
254
- </option>
255
- ))}
256
- </select>
257
- )}
258
- </label>
259
-
260
- <button type="submit" disabled={submitting}>
261
- {submitting ? 'spawning…' : 'spawn'}
262
- </button>
263
- </form>
264
- )
265
- }
@@ -1,88 +0,0 @@
1
- // Catch-all reverse proxy: forwards every browser /api/* request to the
2
- // daemon. Browser scripts use relative URLs (/api/agents, /api/groups, …)
3
- // so the bz_token cookie auto-attaches; this proxy translates that cookie
4
- // into a Bearer header for the daemon, which lives on a different origin.
5
- //
6
- // Streams responses (chat NDJSON) and request bodies through unchanged.
7
-
8
- import { createFileRoute } from '@tanstack/react-router'
9
- import { getCookie } from '@tanstack/react-start/server'
10
- import { DAEMON_BASE_URL } from '../../lib/daemon-client'
11
-
12
- // Hop-by-hop headers per RFC 7230 §6.1, plus host (we're rewriting it) and
13
- // cookie (we translate cookie → bearer ourselves).
14
- const STRIP_REQUEST_HEADERS = new Set([
15
- 'host',
16
- 'connection',
17
- 'keep-alive',
18
- 'proxy-authenticate',
19
- 'proxy-authorization',
20
- 'te',
21
- 'trailer',
22
- 'transfer-encoding',
23
- 'upgrade',
24
- 'cookie',
25
- ])
26
-
27
- const STRIP_RESPONSE_HEADERS = new Set([
28
- 'connection',
29
- 'keep-alive',
30
- 'proxy-authenticate',
31
- 'proxy-authorization',
32
- 'te',
33
- 'trailer',
34
- 'transfer-encoding',
35
- 'upgrade',
36
- ])
37
-
38
- async function proxy(request: Request): Promise<Response> {
39
- const incoming = new URL(request.url)
40
- const target = `${DAEMON_BASE_URL}${incoming.pathname}${incoming.search}`
41
-
42
- const headers = new Headers()
43
- for (const [k, v] of request.headers) {
44
- if (!STRIP_REQUEST_HEADERS.has(k.toLowerCase())) headers.set(k, v)
45
- }
46
- // Browser sent the bz_token cookie; translate to Bearer for the daemon.
47
- // If the request already has an Authorization header (CLI/mobile via the
48
- // web origin — unusual but possible) leave it alone.
49
- if (!headers.has('authorization')) {
50
- const token = getCookie('bz_token')
51
- if (token) headers.set('authorization', `Bearer ${token}`)
52
- }
53
- // Stamp Origin so we stay symmetric with @bazilion/client and any future
54
- // origin checks the daemon adds keep working.
55
- headers.set('origin', DAEMON_BASE_URL)
56
-
57
- const init: RequestInit = { method: request.method, headers, redirect: 'manual' }
58
- if (request.method !== 'GET' && request.method !== 'HEAD') {
59
- init.body = request.body
60
- // @ts-expect-error — undici needs duplex:'half' for streaming bodies
61
- init.duplex = 'half'
62
- }
63
-
64
- const upstream = await fetch(target, init)
65
-
66
- const respHeaders = new Headers()
67
- for (const [k, v] of upstream.headers) {
68
- if (!STRIP_RESPONSE_HEADERS.has(k.toLowerCase())) respHeaders.set(k, v)
69
- }
70
-
71
- return new Response(upstream.body, {
72
- status: upstream.status,
73
- statusText: upstream.statusText,
74
- headers: respHeaders,
75
- })
76
- }
77
-
78
- export const Route = createFileRoute('/api/$')({
79
- server: {
80
- handlers: {
81
- GET: ({ request }) => proxy(request),
82
- POST: ({ request }) => proxy(request),
83
- PUT: ({ request }) => proxy(request),
84
- PATCH: ({ request }) => proxy(request),
85
- DELETE: ({ request }) => proxy(request),
86
- },
87
- },
88
- })