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,193 +0,0 @@
1
- // /api/auth/openai/* — ChatGPT OAuth provider connection state.
2
- // /api/providers/test — model smoke-test.
3
- // /api/login — token-based browser login (sets the bz_token cookie).
4
-
5
- import { spawn } from 'node:child_process'
6
- import type { ProviderTestRequest, ProviderTestResponse } from '@bazilion/api-types'
7
- import { Hono } from 'hono'
8
- import { setCookie } from 'hono/cookie'
9
- import { isSetupComplete, mergeSecretsIntoEnv, providerStateRepo } from '../core/index.ts'
10
- import { isValidToken } from '../lib/auth.ts'
11
- import { getCtx } from '../lib/ctx.ts'
12
- import {
13
- clearOpenAICodexCredentials,
14
- createProviderRegistry,
15
- getOpenAICodexStatus,
16
- loadProviderConfigFromEnv,
17
- loginOpenAICodex,
18
- saveOpenAICodexLoginCredentials,
19
- } from '../runtime/index.ts'
20
-
21
- export const authRouter = new Hono()
22
-
23
- // ─── Auth probe ──────────────────────────────────────────────────────────
24
-
25
- /**
26
- * Cheap session validator. Web SSR middleware calls this once per request
27
- * to translate "is the cookie still good?" + "has setup been finished?"
28
- * into JSON-status pairs that the Astro middleware turns into redirects.
29
- *
30
- * Reaching this handler at all means auth passed (the daemon's own
31
- * middleware-auth would have 401'd otherwise). The body just exposes the
32
- * setup-complete bit so the web layer can route accordingly.
33
- */
34
- authRouter.get('/auth/me', (c) => {
35
- const { db } = getCtx()
36
- return c.json({ authed: true, setupComplete: isSetupComplete(db) })
37
- })
38
-
39
- // ─── ChatGPT OAuth ───────────────────────────────────────────────────────
40
-
41
- authRouter.get('/auth/openai', (c) => {
42
- const { db, authToken } = getCtx()
43
- return c.json(getOpenAICodexStatus(db, authToken))
44
- })
45
-
46
- authRouter.put('/auth/openai', async (c) => {
47
- const body = (await c.req.json().catch(() => null)) as {
48
- refresh?: unknown
49
- access?: unknown
50
- expires?: unknown
51
- } | null
52
- if (
53
- !body ||
54
- typeof body.refresh !== 'string' ||
55
- typeof body.access !== 'string' ||
56
- typeof body.expires !== 'number'
57
- ) {
58
- return c.json(
59
- { error: 'body must be { refresh: string, access: string, expires: number }' },
60
- 400,
61
- )
62
- }
63
- const { db, authToken } = getCtx()
64
- saveOpenAICodexLoginCredentials(db, authToken, {
65
- refresh: body.refresh,
66
- access: body.access,
67
- expires: body.expires,
68
- })
69
- return c.json(getOpenAICodexStatus(db, authToken))
70
- })
71
-
72
- authRouter.delete('/auth/openai', (c) => {
73
- const { db, authToken } = getCtx()
74
- clearOpenAICodexCredentials(db, authToken)
75
- return c.json({ connected: false, expiresAt: null, accountId: null })
76
- })
77
-
78
- authRouter.post('/auth/openai/login', async (c) => {
79
- const { db, authToken } = getCtx()
80
- try {
81
- const creds = await loginOpenAICodex({
82
- onAuth: ({ url }) => openBrowser(url),
83
- onPrompt: () =>
84
- Promise.reject(
85
- new Error(
86
- 'interactive paste not supported in the web flow — cancel and try again, or use `bazilion auth openai login`',
87
- ),
88
- ),
89
- onProgress: () => {
90
- // single blocking POST keeps the UI simple
91
- },
92
- })
93
- saveOpenAICodexLoginCredentials(db, authToken, creds)
94
- return c.json(getOpenAICodexStatus(db, authToken))
95
- } catch (err) {
96
- return c.json({ error: (err as Error).message }, 400)
97
- }
98
- })
99
-
100
- // ─── Provider model smoke-test ───────────────────────────────────────────
101
-
102
- authRouter.post('/providers/test', async (c) => {
103
- const body = (await c.req.json().catch(() => null)) as ProviderTestRequest | null
104
- if (!body || typeof body.model !== 'string' || !body.model) {
105
- return c.json({ error: 'model is required' }, 400)
106
- }
107
- const message = typeof body.message === 'string' && body.message ? body.message : 'say hi briefly'
108
- const { db, paths, authToken } = getCtx()
109
- const env = mergeSecretsIntoEnv(db, authToken)
110
- const reg = createProviderRegistry(loadProviderConfigFromEnv(env, { db, authToken }), {
111
- enabledSet: providerStateRepo.listEnabled(db),
112
- })
113
- try {
114
- const { provider, model } = reg.resolve(body.model)
115
- const res = await provider.chat({
116
- model,
117
- messages: [{ role: 'user', content: message }],
118
- maxTokens: 256,
119
- })
120
- const out: ProviderTestResponse = { content: res.content, usage: res.usage }
121
- return c.json(out)
122
- } catch (err) {
123
- return c.json({ error: (err as Error).message }, 400)
124
- }
125
- })
126
-
127
- // ─── Browser login ───────────────────────────────────────────────────────
128
-
129
- /**
130
- * Token-based login. Two body shapes accepted:
131
- * - `application/json`: `{ token: "<value>" }` → returns `{ ok: true }` on
132
- * success, sets the `bz_token` cookie. Used by clients (web pages, mobile)
133
- * that prefer JSON.
134
- * - `application/x-www-form-urlencoded`: `token=<value>` → 302 to `/` on
135
- * success or `/login?error=1` on failure. Used by the legacy `<form>` on
136
- * the Astro `/login` page; preserved for compatibility through Stage A.
137
- */
138
- authRouter.post('/login', async (c) => {
139
- const ct = c.req.header('content-type') ?? ''
140
- let token: string | null = null
141
-
142
- if (ct.startsWith('application/json')) {
143
- const body = (await c.req.json().catch(() => null)) as { token?: unknown } | null
144
- if (body && typeof body.token === 'string') token = body.token
145
- } else {
146
- const form = await c.req.formData().catch(() => null)
147
- const v = form?.get('token')
148
- if (typeof v === 'string') token = v
149
- }
150
-
151
- if (!token || !isValidToken(token)) {
152
- if (ct.startsWith('application/json')) {
153
- return c.json({ error: 'invalid token' }, 401)
154
- }
155
- return c.redirect('/login?error=1', 302)
156
- }
157
-
158
- setCookie(c, 'bz_token', token, {
159
- path: '/',
160
- httpOnly: true,
161
- sameSite: 'Lax',
162
- maxAge: 60 * 60 * 24 * 30,
163
- })
164
-
165
- if (ct.startsWith('application/json')) {
166
- return c.json({ ok: true })
167
- }
168
- return c.redirect('/', 302)
169
- })
170
-
171
- /**
172
- * Open `url` in the host's default browser. Only called by the OAuth flow
173
- * triggered from /config — the user is on the same machine as the daemon in
174
- * that scenario (loopback-only `bazilion serve`).
175
- */
176
- function openBrowser(url: string): void {
177
- const platform = process.platform
178
- const [cmd, ...args] =
179
- platform === 'darwin'
180
- ? ['open', url]
181
- : platform === 'win32'
182
- ? ['cmd', '/c', 'start', '""', url]
183
- : ['xdg-open', url]
184
- try {
185
- const child = spawn(cmd as string, args, { stdio: 'ignore', detached: true })
186
- child.unref()
187
- child.on('error', () => {
188
- // xdg-open missing on minimal installs — swallow so the flow still works
189
- })
190
- } catch {
191
- // spawn failed — user will still see the URL in the progress log
192
- }
193
- }
@@ -1,267 +0,0 @@
1
- // /api/config/* — provider matrix, services, per-provider enabled toggle and
2
- // curated models, and per-field config/secret writes.
3
-
4
- import type {
5
- ProviderConfigEntry,
6
- ProviderConfigResponse,
7
- ServiceCard,
8
- ServiceConfigResponse,
9
- ServiceFieldState,
10
- SetProviderModelsRequest,
11
- } from '@bazilion/api-types'
12
- import { Hono } from 'hono'
13
- import {
14
- ensureSetupSeeded,
15
- findFieldByEnvVar,
16
- groupAvailableModels,
17
- mergeSecretsIntoEnv,
18
- openConfig,
19
- openSecrets,
20
- providerModelRepo,
21
- providerStateRepo,
22
- type ServiceDef,
23
- servicesByCategory,
24
- } from '../core/index.ts'
25
- import { getCtx } from '../lib/ctx.ts'
26
- import {
27
- listAllProviders,
28
- listCatalogModels,
29
- listCatalogModelsSync,
30
- loadProviderConfigFromEnv,
31
- } from '../runtime/index.ts'
32
-
33
- export const configRouter = new Hono()
34
-
35
- // /api/config/providers
36
- configRouter.get('/providers', async (c) => {
37
- const { db, paths, authToken } = getCtx()
38
- const env = mergeSecretsIntoEnv(db, authToken)
39
- const registryProviders = listAllProviders(loadProviderConfigFromEnv(env, { db, authToken }))
40
- const registryByName = new Map(registryProviders.map((p) => [p.name, p]))
41
-
42
- const configValues = readAll(() => openConfig(db).getAll())
43
- const secretValues = readAll(() => openSecrets(db, authToken).getAll())
44
-
45
- const providerServices = servicesByCategory('provider')
46
- const enabledSet = providerStateRepo.listEnabled(db)
47
-
48
- const entries = await Promise.all(
49
- providerServices.map(async (svc): Promise<ProviderConfigEntry> => {
50
- const meta = registryByName.get(svc.id)
51
- const enabled = enabledSet.has(svc.id)
52
- const envHint = meta?.envHint ?? ''
53
- const ac = new AbortController()
54
- const t = setTimeout(() => ac.abort(), 5_000)
55
- try {
56
- const { catalog, live } = enabled
57
- ? await listCatalogModels(svc.id, env, ac.signal)
58
- : { catalog: listCatalogModelsSync(svc.id), live: undefined }
59
- return {
60
- id: svc.id,
61
- displayName: svc.displayName,
62
- ...(svc.hint ? { hint: svc.hint } : {}),
63
- enabled,
64
- envHint,
65
- fields: resolveFieldStates(svc, configValues, secretValues),
66
- catalog,
67
- ...(live ? { live } : {}),
68
- curated: providerModelRepo.list(db, svc.id),
69
- }
70
- } finally {
71
- clearTimeout(t)
72
- }
73
- }),
74
- )
75
-
76
- const body: ProviderConfigResponse = { providers: entries }
77
- return c.json(body)
78
- })
79
-
80
- // /api/config/services — non-provider service cards (e.g. SearXNG, Brave).
81
- configRouter.get('/services', (c) => {
82
- const { db, authToken } = getCtx()
83
- const configValues = readAll(() => openConfig(db).getAll())
84
- const secretValues = readAll(() => openSecrets(db, authToken).getAll())
85
-
86
- const services: ServiceCard[] = servicesByCategory('service').map((svc) => ({
87
- id: svc.id,
88
- displayName: svc.displayName,
89
- ...(svc.hint ? { hint: svc.hint } : {}),
90
- fields: resolveFieldStates(svc, configValues, secretValues),
91
- }))
92
-
93
- const body: ServiceConfigResponse = { services }
94
- return c.json(body)
95
- })
96
-
97
- // /api/config/providers/:name/enabled — flip the admin switch.
98
- configRouter.put('/providers/:name/enabled', async (c) => {
99
- const name = c.req.param('name')
100
- if (!knownProviderIds().has(name)) return c.json({ error: `unknown provider: ${name}` }, 404)
101
-
102
- const body = (await c.req.json().catch(() => null)) as { enabled?: unknown } | null
103
- if (!body || (typeof body.enabled !== 'boolean' && typeof body.enabled !== 'string')) {
104
- return c.json({ error: 'body must be {"enabled": boolean}' }, 400)
105
- }
106
- const enabled =
107
- typeof body.enabled === 'boolean' ? body.enabled : body.enabled.toLowerCase() === 'true'
108
-
109
- const { db, paths } = getCtx()
110
- providerStateRepo.setEnabled(db, name, enabled)
111
- ensureSetupSeeded(db, paths)
112
- return c.json({ name, enabled })
113
- })
114
-
115
- // /api/config/providers/:name/models — curated model list.
116
- configRouter.get('/providers/:name/models', (c) => {
117
- const name = c.req.param('name')
118
- if (!knownProviderRegistryNames().has(name))
119
- return c.json({ error: `unknown provider: ${name}` }, 404)
120
- const { db } = getCtx()
121
- return c.json({ models: providerModelRepo.list(db, name) })
122
- })
123
-
124
- configRouter.put('/providers/:name/models', async (c) => {
125
- const name = c.req.param('name')
126
- if (!knownProviderRegistryNames().has(name))
127
- return c.json({ error: `unknown provider: ${name}` }, 404)
128
- const body = (await c.req.json().catch(() => null)) as Partial<SetProviderModelsRequest> | null
129
- if (!body) return c.json({ error: 'invalid JSON body' }, 400)
130
-
131
- // Accept textarea-style newline-separated input from web forms in addition
132
- // to the CLI's array shape.
133
- let models: string[] = []
134
- if (Array.isArray(body.models)) {
135
- models = body.models.filter((m): m is string => typeof m === 'string')
136
- } else if (typeof (body as Record<string, unknown>).models === 'string') {
137
- models = ((body as Record<string, unknown>).models as string).split(/\r?\n/)
138
- } else {
139
- return c.json(
140
- { error: 'models must be an array of strings or a newline-separated string' },
141
- 400,
142
- )
143
- }
144
-
145
- const { db, paths } = getCtx()
146
- providerModelRepo.replace(db, name, models)
147
- ensureSetupSeeded(db, paths)
148
- return c.json({ models: providerModelRepo.list(db, name) })
149
- })
150
-
151
- // /api/config/fields/:envVar — write-through for any envVar the registry knows.
152
- configRouter.put('/fields/:envVar', async (c) => {
153
- const envVar = c.req.param('envVar')
154
- const found = findFieldByEnvVar(envVar)
155
- if (!found) return c.json({ error: `unknown envVar: ${envVar}` }, 404)
156
-
157
- const body = (await c.req.json().catch(() => null)) as { value?: unknown } | null
158
- if (!body || typeof body.value !== 'string') {
159
- return c.json({ error: 'body must be {"value": "<string>"}' }, 400)
160
- }
161
-
162
- const { db, authToken } = getCtx()
163
- if (found.field.kind === 'config') {
164
- const store = openConfig(db)
165
- if (body.value === '') store.remove(envVar)
166
- else store.set(envVar, body.value)
167
- } else {
168
- const store = openSecrets(db, authToken)
169
- if (body.value === '') store.remove(envVar)
170
- else store.set(envVar, body.value)
171
- }
172
-
173
- return c.json(readFieldState(db, authToken, envVar, found.field.kind))
174
- })
175
-
176
- // /api/config/available-models — provider-grouped curated models. Drives
177
- // the model dropdowns on the profile + agent spawn pages.
178
- configRouter.get('/available-models', (c) => {
179
- const { db } = getCtx()
180
- return c.json({ groups: groupAvailableModels(db) })
181
- })
182
-
183
- configRouter.delete('/fields/:envVar', (c) => {
184
- const envVar = c.req.param('envVar')
185
- const found = findFieldByEnvVar(envVar)
186
- if (!found) return c.json({ error: `unknown envVar: ${envVar}` }, 404)
187
-
188
- const { db, authToken } = getCtx()
189
- if (found.field.kind === 'config') {
190
- openConfig(db).remove(envVar)
191
- } else {
192
- openSecrets(db, authToken).remove(envVar)
193
- }
194
- return c.body(null, 204)
195
- })
196
-
197
- // ─── helpers ─────────────────────────────────────────────────────────────
198
-
199
- function mask(value: string): string {
200
- if (value.length === 0) return ''
201
- return value.length > 8 ? `${value.slice(0, 6)}…` : '***'
202
- }
203
-
204
- function resolveFieldStates(
205
- service: ServiceDef,
206
- configValues: Record<string, string>,
207
- secretValues: Record<string, string>,
208
- ): ServiceFieldState[] {
209
- return service.fields.map((f) => {
210
- const val = (f.kind === 'config' ? configValues[f.envVar] : secretValues[f.envVar]) ?? ''
211
- const state: ServiceFieldState = {
212
- envVar: f.envVar,
213
- kind: f.kind,
214
- label: f.label,
215
- set: val.length > 0,
216
- ...(f.placeholder ? { placeholder: f.placeholder } : {}),
217
- ...(f.description ? { description: f.description } : {}),
218
- }
219
- if (f.kind === 'config') {
220
- state.value = val
221
- } else if (val.length > 0) {
222
- state.preview = mask(val)
223
- }
224
- return state
225
- })
226
- }
227
-
228
- function readAll(read: () => Record<string, string>): Record<string, string> {
229
- try {
230
- return read()
231
- } catch {
232
- return {}
233
- }
234
- }
235
-
236
- interface FieldState {
237
- envVar: string
238
- kind: 'secret' | 'config'
239
- set: boolean
240
- value?: string
241
- preview?: string
242
- }
243
-
244
- function readFieldState(
245
- db: import('../core/index.ts').BazilionDb,
246
- authToken: string,
247
- envVar: string,
248
- kind: 'secret' | 'config',
249
- ): FieldState {
250
- if (kind === 'config') {
251
- const v = openConfig(db).get(envVar) ?? ''
252
- return { envVar, kind, set: v.length > 0, value: v }
253
- }
254
- const v = openSecrets(db, authToken).get(envVar) ?? ''
255
- return { envVar, kind, set: v.length > 0, ...(v.length > 0 ? { preview: mask(v) } : {}) }
256
- }
257
-
258
- function knownProviderIds(): Set<string> {
259
- return new Set(servicesByCategory('provider').map((s) => s.id))
260
- }
261
-
262
- function knownProviderRegistryNames(): Set<string> {
263
- const { db, authToken } = getCtx()
264
- return new Set(
265
- listAllProviders(loadProviderConfigFromEnv(process.env, { db, authToken })).map((p) => p.name),
266
- )
267
- }
@@ -1,133 +0,0 @@
1
- // /api/groups/* — group registry, per-group USER.md, per-group shared
2
- // memory. Memory is keyed by the group slug because the qmd index lives at
3
- // `<group.path>/memory/` and is shared by every agent in the group.
4
-
5
- import { join } from 'node:path'
6
- import type { RegisterGroupRequest, SetGroupUserMdRequest } from '@bazilion/api-types'
7
- import { Hono } from 'hono'
8
- import { deleteGroup, groupRepo, registerGroup } from '../core/index.ts'
9
- import { getCtx } from '../lib/ctx.ts'
10
- import { qmdBackend } from '../runtime/index.ts'
11
-
12
- // 12 KB cap matches OpenClaw's bootstrapMaxChars default — enough for a rich
13
- // USER.md, small enough that it can't silently blow out the system prompt.
14
- const USER_MD_MAX_BYTES = 12_000
15
-
16
- export const groupsRouter = new Hono()
17
-
18
- groupsRouter.get('/', (c) => {
19
- const { db, paths } = getCtx()
20
- return c.json(groupRepo.list(db, paths))
21
- })
22
-
23
- groupsRouter.post('/', async (c) => {
24
- const body = (await c.req.json().catch(() => null)) as RegisterGroupRequest | null
25
- if (!body || typeof body.id !== 'string') {
26
- return c.json({ error: 'id is required' }, 400)
27
- }
28
- const { db, paths } = getCtx()
29
- try {
30
- const g = registerGroup(db, { id: body.id, name: body.name, link: body.link }, paths)
31
- return c.json(g, 201)
32
- } catch (err) {
33
- return c.json({ error: (err as Error).message }, 400)
34
- }
35
- })
36
-
37
- groupsRouter.get('/:id', (c) => {
38
- const { db, paths } = getCtx()
39
- const g = groupRepo.get(db, c.req.param('id'), paths)
40
- if (!g) return c.json({ error: `group not found: ${c.req.param('id')}` }, 404)
41
- return c.json(g)
42
- })
43
-
44
- groupsRouter.delete('/:id', (c) => {
45
- const { db, paths } = getCtx()
46
- try {
47
- deleteGroup(db, paths, c.req.param('id'))
48
- return c.body(null, 204)
49
- } catch (err) {
50
- return c.json({ error: (err as Error).message }, 400)
51
- }
52
- })
53
-
54
- groupsRouter.put('/:id/user-md', async (c) => {
55
- const body = (await c.req.json().catch(() => null)) as SetGroupUserMdRequest | null
56
- if (!body || typeof body.userMd !== 'string') {
57
- return c.json({ error: 'userMd (string) is required' }, 400)
58
- }
59
- if (Buffer.byteLength(body.userMd, 'utf8') > USER_MD_MAX_BYTES) {
60
- return c.json({ error: `userMd exceeds ${USER_MD_MAX_BYTES}-byte cap` }, 413)
61
- }
62
- const { db, paths } = getCtx()
63
- const g = groupRepo.get(db, c.req.param('id'), paths)
64
- if (!g) return c.json({ error: `group not found: ${c.req.param('id')}` }, 404)
65
- groupRepo.setUserMd(db, c.req.param('id'), body.userMd)
66
- return c.json(groupRepo.get(db, c.req.param('id'), paths))
67
- })
68
-
69
- // ─── Memory (per-group, shared across all member agents) ──────────────────
70
-
71
- async function openMemory(rawId: string) {
72
- const { db, paths } = getCtx()
73
- const group = groupRepo.get(db, rawId, paths)
74
- if (!group) throw new Error(`group not found: ${rawId}`)
75
- const mem = qmdBackend(join(group.path, 'memory'))
76
- await mem.init()
77
- return { mem, group }
78
- }
79
-
80
- groupsRouter.get('/:id/memory', async (c) => {
81
- try {
82
- const { mem } = await openMemory(c.req.param('id'))
83
- return c.json(await mem.list())
84
- } catch (err) {
85
- return c.json({ error: (err as Error).message }, 404)
86
- }
87
- })
88
-
89
- groupsRouter.get('/:id/memory/search', async (c) => {
90
- const q = c.req.query('q')
91
- if (!q) return c.json({ error: 'q is required' }, 400)
92
- const limit = Number.parseInt(c.req.query('limit') ?? '10', 10)
93
- try {
94
- const { mem } = await openMemory(c.req.param('id'))
95
- return c.json(await mem.search(q, { limit }))
96
- } catch (err) {
97
- return c.json({ error: (err as Error).message }, 404)
98
- }
99
- })
100
-
101
- // `:key{.+}` matches multi-segment paths so memory keys with slashes (e.g.
102
- // `notes/2026-04-25.md`) survive the routing layer. Without the regex Hono
103
- // would only capture a single segment.
104
- groupsRouter.get('/:id/memory/:key{.+}', async (c) => {
105
- try {
106
- const { mem } = await openMemory(c.req.param('id'))
107
- return c.json(await mem.read(c.req.param('key')))
108
- } catch (err) {
109
- return c.json({ error: (err as Error).message }, 404)
110
- }
111
- })
112
-
113
- groupsRouter.put('/:id/memory/:key{.+}', async (c) => {
114
- const body = (await c.req.json().catch(() => null)) as { content?: string } | null
115
- if (!body || typeof body.content !== 'string')
116
- return c.json({ error: 'content is required' }, 400)
117
- try {
118
- const { mem } = await openMemory(c.req.param('id'))
119
- return c.json(await mem.write(c.req.param('key'), body.content))
120
- } catch (err) {
121
- return c.json({ error: (err as Error).message }, 500)
122
- }
123
- })
124
-
125
- groupsRouter.delete('/:id/memory/:key{.+}', async (c) => {
126
- try {
127
- const { mem } = await openMemory(c.req.param('id'))
128
- await mem.remove(c.req.param('key'))
129
- return c.body(null, 204)
130
- } catch (err) {
131
- return c.json({ error: (err as Error).message }, 500)
132
- }
133
- })
@@ -1,29 +0,0 @@
1
- // /api/messages/:id — fetch + mark-read for a single message. (Inbox listing
2
- // + send is per-agent at /api/agents/:id/messages.)
3
-
4
- import type { UpdateMessageRequest } from '@bazilion/api-types'
5
- import { Hono } from 'hono'
6
- import { messageRepo } from '../core/index.ts'
7
- import { getCtx } from '../lib/ctx.ts'
8
-
9
- export const messagesRouter = new Hono()
10
-
11
- messagesRouter.get('/:id', (c) => {
12
- const { db } = getCtx()
13
- const msg = messageRepo.get(db, c.req.param('id'))
14
- if (!msg) return c.json({ error: `message not found: ${c.req.param('id')}` }, 404)
15
- return c.json(msg)
16
- })
17
-
18
- messagesRouter.patch('/:id', async (c) => {
19
- const id = c.req.param('id')
20
- const body = (await c.req.json().catch(() => null)) as UpdateMessageRequest | null
21
- if (!body || body.read !== true) {
22
- return c.json({ error: 'body must be {read: true}' }, 400)
23
- }
24
- const { db } = getCtx()
25
- const existing = messageRepo.get(db, id)
26
- if (!existing) return c.json({ error: `message not found: ${id}` }, 404)
27
- messageRepo.markRead(db, id)
28
- return c.json(messageRepo.get(db, id))
29
- })